OOFEM  2.4
OOFEM.org - Object Oriented Finite Element Solver
delaunay.C
Go to the documentation of this file.
1 /*
2  *
3  * ##### ##### ###### ###### ### ###
4  * ## ## ## ## ## ## ## ### ##
5  * ## ## ## ## #### #### ## # ##
6  * ## ## ## ## ## ## ## ##
7  * ## ## ## ## ## ## ## ##
8  * ##### ##### ## ###### ## ##
9  *
10  *
11  * OOFEM : Object Oriented Finite Element Code
12  *
13  * Copyright (C) 1993 - 2013 Borek Patzak
14  *
15  *
16  *
17  * Czech Technical University, Faculty of Civil Engineering,
18  * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19  *
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33  */
34 
35 #include "delaunay.h"
36 #include "floatarray.h"
37 #include "intarray.h"
38 #include "geometry.h"
39 #include "node.h"
40 #include "mathfem.h"
41 
42 #include <cstdlib>
43 #include <map>
44 #include <algorithm>
45 
46 namespace oofem {
47 bool Delaunay :: colinear(const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iP3) const
48 {
49  double dist = iP1.at(1) * ( iP2.at(2) - iP3.at(2) ) + iP2.at(1) * ( iP3.at(2) - iP1.at(2) ) +
50  iP3.at(1) * ( iP1.at(2) - iP2.at(2) );
51 
52  if ( dist < mTol && dist > -mTol ) {
53  return true;
54  } else {
55  return false;
56  }
57 }
58 
59 void Delaunay :: printTriangles(std :: vector< Triangle > &triangles)
60 {
61  for ( auto &tri: triangles ) {
62  tri.printYourself();
63  }
64 }
65 
66 bool Delaunay :: isInsideCC(const FloatArray &iP, const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iP3) const
67 {
68  Triangle tr(iP1, iP2, iP3);
69  double r = tr.getRadiusOfCircumCircle();
70  FloatArray circumCenter;
71  tr.computeCenterOfCircumCircle(circumCenter);
72  double distance = circumCenter.distance(iP);
73  if ( distance < r ) {
74  return true;
75  } else {
76  return false;
77  }
78 }
79 
80 void Delaunay :: triangulate(const std :: vector< FloatArray > &iVertices, std :: vector< Triangle > &oTriangles) const
81 {
82  // 4th order algorithm - four loops, only for testing purposes
83 
84  if ( iVertices.size() == 4 ) {
85  // Check if the points approximately form a rectangle
86  // and treat that case separately .
87  // The purpose is to avoid annyoing round-off effects for
88  // this quite common case. /ES
89 
90  const double relTol2 = 1.0e-6;
91 
92  std :: vector< double >dist_square = {
93  iVertices [ 0 ].distance_square(iVertices [ 1 ]),
94  iVertices [ 0 ].distance_square(iVertices [ 2 ]),
95  iVertices [ 0 ].distance_square(iVertices [ 3 ])
96  };
97 
98  std :: sort( dist_square.begin(), dist_square.end() );
99 
100  // This expression is zero for a rectangle according to the Pythagorean theorem
101  if ( fabs(dist_square [ 2 ] - dist_square [ 1 ] - dist_square [ 0 ]) < relTol2 * dist_square [ 2 ] ) {
102  // We found a rectangle
103 
104  double maxDist_square = iVertices [ 0 ].distance_square(iVertices [ 1 ]);
105  int maxDistInd = 1;
106 
107  if ( iVertices [ 0 ].distance_square(iVertices [ 2 ]) > maxDist_square ) {
108  maxDist_square = iVertices [ 0 ].distance_square(iVertices [ 2 ]);
109  maxDistInd = 2;
110  }
111 
112  if ( iVertices [ 0 ].distance_square(iVertices [ 3 ]) > maxDist_square ) {
113  maxDist_square = iVertices [ 0 ].distance_square(iVertices [ 3 ]);
114  maxDistInd = 3;
115  }
116 
117 
118  int remainingInd1 = -1, remainingInd2 = -1;
119 
120  switch ( maxDistInd ) {
121  case 1:
122  remainingInd1 = 2;
123  remainingInd2 = 3;
124  break;
125 
126  case 2:
127  remainingInd1 = 1;
128  remainingInd2 = 3;
129  break;
130 
131  case 3:
132  remainingInd1 = 1;
133  remainingInd2 = 2;
134  break;
135  default:
136  OOFEM_ERROR("Case not handled in switch.")
137  break;
138  }
139 
140 
141  Triangle tri1(iVertices [ 0 ], iVertices [ remainingInd1 ], iVertices [ maxDistInd ]);
142  if ( !tri1.isOrientedAnticlockwise() ) {
143  tri1.changeToAnticlockwise();
144  }
145 
146  oTriangles.push_back(tri1);
147 
148 
149  Triangle tri2(iVertices [ 0 ], iVertices [ remainingInd2 ], iVertices [ maxDistInd ]);
150  if ( !tri2.isOrientedAnticlockwise() ) {
151  tri2.changeToAnticlockwise();
152  }
153 
154  oTriangles.push_back(tri2);
155 
156  return;
157  }
158  }
159 
160 
161  int n = iVertices.size();
162 
163  // copy of vertices, since they will be shifted
164  std :: vector< FloatArray >vertices(iVertices);
165 
166  // small shift of vertices
167  const double shift = 1.0e-12;
168  for ( int i = 1; i <= n; i++ ) {
169  vertices [ i - 1 ].at(1) += vertices [ i - 1 ].at(1) * shift * double ( rand() ) / RAND_MAX;
170  vertices [ i - 1 ].at(2) += vertices [ i - 1 ].at(2) * shift * double ( rand() ) / RAND_MAX;
171  }
172 
173  for ( int i = 1; i <= n; i++ ) {
174  for ( int j = i + 1; j <= n; j++ ) {
175  for ( int k = j + 1; k <= n; k++ ) {
176  bool isTriangle = true;
177  if ( colinear(vertices [ i - 1 ], vertices [ j - 1 ], vertices [ k - 1 ]) ) {
178  isTriangle = false;
179  } else {
180  for ( int a = 1; a <= n; a++ ) {
181  if ( a != i && a != j && a != k ) {
182  // checks whether a point a is inside a circumcircle of a triangle ijk
183  if ( isInsideCC(vertices [ a - 1 ], vertices [ i - 1 ], vertices [ j - 1 ],
184  vertices [ k - 1 ]) ) {
185  isTriangle = false;
186  break;
187  }
188  }
189  }
190  }
191 
192  if ( isTriangle ) {
193  // here we switch to old vertices
194  Triangle tri(iVertices [ i - 1 ], iVertices [ j - 1 ], iVertices [ k - 1 ]);
195  if ( !tri.isOrientedAnticlockwise() ) {
196  tri.changeToAnticlockwise();
197  }
198 
199  oTriangles.push_back(tri);
200  }
201  }
202  }
203  }
204 }
205 } // end namespace oofem
const double mTol
Definition: delaunay.h:64
double & at(int i)
Coefficient access function.
Definition: floatarray.h:131
void sort(IntArray &arry, operation op)
Sorts the receiver using quicksort algorithm.
Definition: intarray.h:416
double distance(const FloatArray &x) const
Computes the distance between position represented by receiver and position given as parameter...
Definition: floatarray.C:489
void triangulate(const std::vector< FloatArray > &iVertices, std::vector< Triangle > &oTriangles) const
Definition: delaunay.C:80
#define OOFEM_ERROR(...)
Definition: error.h:61
void changeToAnticlockwise()
Definition: geometry.C:486
void printTriangles(std::vector< Triangle > &triangles)
Definition: delaunay.C:59
bool isInsideCC(const FloatArray &iP, const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iP3) const
Definition: delaunay.C:66
Class representing vector of real numbers.
Definition: floatarray.h:82
bool isOrientedAnticlockwise()
Definition: geometry.C:469
double getRadiusOfCircumCircle()
Definition: geometry.C:423
bool colinear(const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iP3) const
Definition: delaunay.C:47
the oofem namespace is to define a context or scope in which all oofem names are defined.
void computeCenterOfCircumCircle(FloatArray &answer) const
Definition: geometry.C:447

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Tue Jan 2 2018 20:07:28 for OOFEM by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2011