source: src/tesselation.cpp@ 89c8b2

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 89c8b2 was 34e0592, checked in by Frederik Heber <heber@…>, 15 years ago

Merge branch 'ConcaveHull' of ssh://stud64d-02/home/metzler/workspace/espack into Ticket14

Conflicts:

molecuilder/src/boundary.cpp
molecuilder/src/tesselation.cpp

  • Property mode set to 100644
File size: 131.6 KB
Line 
1/*
2 * tesselation.cpp
3 *
4 * Created on: Aug 3, 2009
5 * Author: heber
6 */
7
8#include "tesselation.hpp"
9
10// ======================================== Points on Boundary =================================
11
12/** Constructor of BoundaryPointSet.
13 */
14BoundaryPointSet::BoundaryPointSet()
15{
16 LinesCount = 0;
17 Nr = -1;
18 value = 0.;
19};
20
21/** Constructor of BoundaryPointSet with Tesselpoint.
22 * \param *Walker TesselPoint this boundary point represents
23 */
24BoundaryPointSet::BoundaryPointSet(TesselPoint *Walker)
25{
26 node = Walker;
27 LinesCount = 0;
28 Nr = Walker->nr;
29 value = 0.;
30};
31
32/** Destructor of BoundaryPointSet.
33 * Sets node to NULL to avoid removing the original, represented TesselPoint.
34 * \note When removing point from a class Tesselation, use RemoveTesselationPoint()
35 */
36BoundaryPointSet::~BoundaryPointSet()
37{
38 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
39 if (!lines.empty())
40 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some lines." << endl;
41 node = NULL;
42};
43
44/** Add a line to the LineMap of this point.
45 * \param *line line to add
46 */
47void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
48{
49 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "."
50 << endl;
51 if (line->endpoints[0] == this)
52 {
53 lines.insert(LinePair(line->endpoints[1]->Nr, line));
54 }
55 else
56 {
57 lines.insert(LinePair(line->endpoints[0]->Nr, line));
58 }
59 LinesCount++;
60};
61
62/** output operator for BoundaryPointSet.
63 * \param &ost output stream
64 * \param &a boundary point
65 */
66ostream & operator <<(ostream &ost, BoundaryPointSet &a)
67{
68 ost << "[" << a.Nr << "|" << a.node->Name << "]";
69 return ost;
70}
71;
72
73// ======================================== Lines on Boundary =================================
74
75/** Constructor of BoundaryLineSet.
76 */
77BoundaryLineSet::BoundaryLineSet()
78{
79 for (int i = 0; i < 2; i++)
80 endpoints[i] = NULL;
81 Nr = -1;
82};
83
84/** Constructor of BoundaryLineSet with two endpoints.
85 * Adds line automatically to each endpoints' LineMap
86 * \param *Point[2] array of two boundary points
87 * \param number number of the list
88 */
89BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
90{
91 // set number
92 Nr = number;
93 // set endpoints in ascending order
94 SetEndpointsOrdered(endpoints, Point[0], Point[1]);
95 // add this line to the hash maps of both endpoints
96 Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.
97 Point[1]->AddLine(this); //
98 // clear triangles list
99 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
100};
101
102/** Destructor for BoundaryLineSet.
103 * Removes itself from each endpoints' LineMap, calling RemoveTrianglePoint() when point not connected anymore.
104 * \note When removing lines from a class Tesselation, use RemoveTesselationLine()
105 */
106BoundaryLineSet::~BoundaryLineSet()
107{
108 int Numbers[2];
109
110 // get other endpoint number of finding copies of same line
111 if (endpoints[1] != NULL)
112 Numbers[0] = endpoints[1]->Nr;
113 else
114 Numbers[0] = -1;
115 if (endpoints[0] != NULL)
116 Numbers[1] = endpoints[0]->Nr;
117 else
118 Numbers[1] = -1;
119
120 for (int i = 0; i < 2; i++) {
121 if (endpoints[i] != NULL) {
122 if (Numbers[i] != -1) { // as there may be multiple lines with same endpoints, we have to go through each and find in the endpoint's line list this line set
123 pair<LineMap::iterator, LineMap::iterator> erasor = endpoints[i]->lines.equal_range(Numbers[i]);
124 for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
125 if ((*Runner).second == this) {
126 cout << Verbose(5) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
127 endpoints[i]->lines.erase(Runner);
128 break;
129 }
130 } else { // there's just a single line left
131 if (endpoints[i]->lines.erase(Nr))
132 cout << Verbose(5) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
133 }
134 if (endpoints[i]->lines.empty()) {
135 cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
136 if (endpoints[i] != NULL) {
137 delete(endpoints[i]);
138 endpoints[i] = NULL;
139 }
140 }
141 }
142 }
143 if (!triangles.empty())
144 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some triangles." << endl;
145};
146
147/** Add triangle to TriangleMap of this boundary line.
148 * \param *triangle to add
149 */
150void BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
151{
152 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "." << endl;
153 triangles.insert(TrianglePair(triangle->Nr, triangle));
154};
155
156/** Checks whether we have a common endpoint with given \a *line.
157 * \param *line other line to test
158 * \return true - common endpoint present, false - not connected
159 */
160bool BoundaryLineSet::IsConnectedTo(class BoundaryLineSet *line)
161{
162 if ((endpoints[0] == line->endpoints[0]) || (endpoints[1] == line->endpoints[0]) || (endpoints[0] == line->endpoints[1]) || (endpoints[1] == line->endpoints[1]))
163 return true;
164 else
165 return false;
166};
167
168/** Checks whether the adjacent triangles of a baseline are convex or not.
169 * We sum the two angles of each normal vector with a ficticious normnal vector from this baselinbe pointing outwards.
170 * If greater/equal M_PI than we are convex.
171 * \param *out output stream for debugging
172 * \return true - triangles are convex, false - concave or less than two triangles connected
173 */
174bool BoundaryLineSet::CheckConvexityCriterion(ofstream *out)
175{
176 Vector BaseLineCenter, BaseLineNormal, BaseLine, helper[2], NormalCheck;
177 // get the two triangles
178 if (triangles.size() != 2) {
179 *out << Verbose(1) << "ERROR: Baseline " << *this << " is connect to less than two triangles, Tesselation incomplete!" << endl;
180 return true;
181 }
182 // check normal vectors
183 // have a normal vector on the base line pointing outwards
184 //*out << Verbose(3) << "INFO: " << *this << " has vectors at " << *(endpoints[0]->node->node) << " and at " << *(endpoints[1]->node->node) << "." << endl;
185 BaseLineCenter.CopyVector(endpoints[0]->node->node);
186 BaseLineCenter.AddVector(endpoints[1]->node->node);
187 BaseLineCenter.Scale(1./2.);
188 BaseLine.CopyVector(endpoints[0]->node->node);
189 BaseLine.SubtractVector(endpoints[1]->node->node);
190 //*out << Verbose(3) << "INFO: Baseline is " << BaseLine << " and its center is at " << BaseLineCenter << "." << endl;
191
192 BaseLineNormal.Zero();
193 NormalCheck.Zero();
194 double sign = -1.;
195 int i=0;
196 class BoundaryPointSet *node = NULL;
197 for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++) {
198 //*out << Verbose(3) << "INFO: NormalVector of " << *(runner->second) << " is " << runner->second->NormalVector << "." << endl;
199 NormalCheck.AddVector(&runner->second->NormalVector);
200 NormalCheck.Scale(sign);
201 sign = -sign;
202 BaseLineNormal.SubtractVector(&runner->second->NormalVector); // we subtract as BaseLineNormal has to point inward in direction of [pi,2pi]
203 node = runner->second->GetThirdEndpoint(this);
204 if (node != NULL) {
205 //*out << Verbose(3) << "INFO: Third node for triangle " << *(runner->second) << " is " << *node << " at " << *(node->node->node) << "." << endl;
206 helper[i].CopyVector(node->node->node);
207 helper[i].SubtractVector(&BaseLineCenter);
208 helper[i].MakeNormalVector(&BaseLine); // we want to compare the triangle's heights' angles!
209 //*out << Verbose(4) << "INFO: Height vector with respect to baseline is " << helper[i] << "." << endl;
210 i++;
211 } else {
212 //*out << Verbose(2) << "WARNING: I cannot find third node in triangle, something's wrong." << endl;
213 return true;
214 }
215 }
216 //*out << Verbose(3) << "INFO: BaselineNormal is " << BaseLineNormal << "." << endl;
217 if (NormalCheck.NormSquared() < MYEPSILON) {
218 *out << Verbose(2) << "ACCEPT: Normalvectors of both triangles are the same: convex." << endl;
219 return true;
220 }
221 double angle = GetAngle(helper[0], helper[1], BaseLineNormal);
222 if ((angle - M_PI) > -MYEPSILON) {
223 *out << Verbose(2) << "ACCEPT: Angle is greater than pi: convex." << endl;
224 return true;
225 } else {
226 *out << Verbose(2) << "REJECT: Angle is less than pi: concave." << endl;
227 return false;
228 }
229}
230
231/** Checks whether point is any of the two endpoints this line contains.
232 * \param *point point to test
233 * \return true - point is of the line, false - is not
234 */
235bool BoundaryLineSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
236{
237 for(int i=0;i<2;i++)
238 if (point == endpoints[i])
239 return true;
240 return false;
241};
242
243/** Returns other endpoint of the line.
244 * \param *point other endpoint
245 * \return NULL - if endpoint not contained in BoundaryLineSet, or pointer to BoundaryPointSet otherwise
246 */
247class BoundaryPointSet *BoundaryLineSet::GetOtherEndpoint(class BoundaryPointSet *point)
248{
249 if (endpoints[0] == point)
250 return endpoints[1];
251 else if (endpoints[1] == point)
252 return endpoints[0];
253 else
254 return NULL;
255};
256
257/** output operator for BoundaryLineSet.
258 * \param &ost output stream
259 * \param &a boundary line
260 */
261ostream & operator <<(ostream &ost, BoundaryLineSet &a)
262{
263 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "]";
264 return ost;
265};
266
267// ======================================== Triangles on Boundary =================================
268
269/** Constructor for BoundaryTriangleSet.
270 */
271BoundaryTriangleSet::BoundaryTriangleSet()
272{
273 for (int i = 0; i < 3; i++)
274 {
275 endpoints[i] = NULL;
276 lines[i] = NULL;
277 }
278 Nr = -1;
279};
280
281/** Constructor for BoundaryTriangleSet with three lines.
282 * \param *line[3] lines that make up the triangle
283 * \param number number of triangle
284 */
285BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number)
286{
287 // set number
288 Nr = number;
289 // set lines
290 cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
291 for (int i = 0; i < 3; i++)
292 {
293 lines[i] = line[i];
294 lines[i]->AddTriangle(this);
295 }
296 // get ascending order of endpoints
297 map<int, class BoundaryPointSet *> OrderMap;
298 for (int i = 0; i < 3; i++)
299 // for all three lines
300 for (int j = 0; j < 2; j++)
301 { // for both endpoints
302 OrderMap.insert(pair<int, class BoundaryPointSet *> (
303 line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));
304 // and we don't care whether insertion fails
305 }
306 // set endpoints
307 int Counter = 0;
308 cout << Verbose(6) << " with end points ";
309 for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner
310 != OrderMap.end(); runner++)
311 {
312 endpoints[Counter] = runner->second;
313 cout << " " << *endpoints[Counter];
314 Counter++;
315 }
316 if (Counter < 3)
317 {
318 cerr << "ERROR! We have a triangle with only two distinct endpoints!"
319 << endl;
320 //exit(1);
321 }
322 cout << "." << endl;
323};
324
325/** Destructor of BoundaryTriangleSet.
326 * Removes itself from each of its lines' LineMap and removes them if necessary.
327 * \note When removing triangles from a class Tesselation, use RemoveTesselationTriangle()
328 */
329BoundaryTriangleSet::~BoundaryTriangleSet()
330{
331 for (int i = 0; i < 3; i++) {
332 if (lines[i] != NULL) {
333 if (lines[i]->triangles.erase(Nr))
334 cout << Verbose(5) << "Triangle Nr." << Nr << " erased in line " << *lines[i] << "." << endl;
335 if (lines[i]->triangles.empty()) {
336 cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
337 delete (lines[i]);
338 lines[i] = NULL;
339 }
340 }
341 }
342 cout << Verbose(5) << "Erasing triangle Nr." << Nr << " itself." << endl;
343};
344
345/** Calculates the normal vector for this triangle.
346 * Is made unique by comparison with \a OtherVector to point in the other direction.
347 * \param &OtherVector direction vector to make normal vector unique.
348 */
349void BoundaryTriangleSet::GetNormalVector(Vector &OtherVector)
350{
351 // get normal vector
352 NormalVector.MakeNormalVector(endpoints[0]->node->node, endpoints[1]->node->node, endpoints[2]->node->node);
353
354 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
355 if (NormalVector.ScalarProduct(&OtherVector) > 0.)
356 NormalVector.Scale(-1.);
357};
358
359/** Finds the point on the triangle \a *BTS the line defined by \a *MolCenter and \a *x crosses through.
360 * We call Vector::GetIntersectionWithPlane() to receive the intersection point with the plane
361 * This we test if it's really on the plane and whether it's inside the triangle on the plane or not.
362 * The latter is done as follows: if it's really outside, then for any endpoint of the triangle and it's opposite
363 * base line, the intersection between the line from endpoint to intersection and the base line will have a Vector::NormSquared()
364 * smaller than the first line.
365 * \param *out output stream for debugging
366 * \param *MolCenter offset vector of line
367 * \param *x second endpoint of line, minus \a *MolCenter is directional vector of line
368 * \param *Intersection intersection on plane on return
369 * \return true - \a *Intersection contains intersection on plane defined by triangle, false - zero vector if outside of triangle.
370 */
371bool BoundaryTriangleSet::GetIntersectionInsideTriangle(ofstream *out, Vector *MolCenter, Vector *x, Vector *Intersection)
372{
373 Vector CrossPoint;
374 Vector helper;
375
376 if (!Intersection->GetIntersectionWithPlane(out, &NormalVector, endpoints[0]->node->node, MolCenter, x)) {
377 *out << Verbose(1) << "Alas! Intersection with plane failed - at least numerically - the intersection is not on the plane!" << endl;
378 return false;
379 }
380
381 // Calculate cross point between one baseline and the line from the third endpoint to intersection
382 int i=0;
383 do {
384 if (CrossPoint.GetIntersectionOfTwoLinesOnPlane(out, endpoints[i%3]->node->node, endpoints[(i+1)%3]->node->node, endpoints[(i+2)%3]->node->node, Intersection, &NormalVector)) {
385 helper.CopyVector(endpoints[(i+1)%3]->node->node);
386 helper.SubtractVector(endpoints[i%3]->node->node);
387 } else
388 i++;
389 if (i>2)
390 break;
391 } while (CrossPoint.NormSquared() < MYEPSILON);
392 if (i==3) {
393 *out << Verbose(1) << "ERROR: Could not find any cross points, something's utterly wrong here!" << endl;
394 exit(255);
395 }
396 CrossPoint.SubtractVector(endpoints[i%3]->node->node);
397
398 // check whether intersection is inside or not by comparing length of intersection and length of cross point
399 if ((CrossPoint.NormSquared() - helper.NormSquared()) > -MYEPSILON) { // inside
400 return true;
401 } else { // outside!
402 Intersection->Zero();
403 return false;
404 }
405};
406
407/** Checks whether lines is any of the three boundary lines this triangle contains.
408 * \param *line line to test
409 * \return true - line is of the triangle, false - is not
410 */
411bool BoundaryTriangleSet::ContainsBoundaryLine(class BoundaryLineSet *line)
412{
413 for(int i=0;i<3;i++)
414 if (line == lines[i])
415 return true;
416 return false;
417};
418
419/** Checks whether point is any of the three endpoints this triangle contains.
420 * \param *point point to test
421 * \return true - point is of the triangle, false - is not
422 */
423bool BoundaryTriangleSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
424{
425 for(int i=0;i<3;i++)
426 if (point == endpoints[i])
427 return true;
428 return false;
429};
430
431/** Checks whether three given \a *Points coincide with triangle's endpoints.
432 * \param *Points[3] pointer to BoundaryPointSet
433 * \return true - is the very triangle, false - is not
434 */
435bool BoundaryTriangleSet::IsPresentTupel(class BoundaryPointSet *Points[3])
436{
437 return (((endpoints[0] == Points[0])
438 || (endpoints[0] == Points[1])
439 || (endpoints[0] == Points[2])
440 ) && (
441 (endpoints[1] == Points[0])
442 || (endpoints[1] == Points[1])
443 || (endpoints[1] == Points[2])
444 ) && (
445 (endpoints[2] == Points[0])
446 || (endpoints[2] == Points[1])
447 || (endpoints[2] == Points[2])
448
449 ));
450};
451
452/** Returns the endpoint which is not contained in the given \a *line.
453 * \param *line baseline defining two endpoints
454 * \return pointer third endpoint or NULL if line does not belong to triangle.
455 */
456class BoundaryPointSet *BoundaryTriangleSet::GetThirdEndpoint(class BoundaryLineSet *line)
457{
458 // sanity check
459 if (!ContainsBoundaryLine(line))
460 return NULL;
461 for(int i=0;i<3;i++)
462 if (!line->ContainsBoundaryPoint(endpoints[i]))
463 return endpoints[i];
464 // actually, that' impossible :)
465 return NULL;
466};
467
468/** Calculates the center point of the triangle.
469 * Is third of the sum of all endpoints.
470 * \param *center central point on return.
471 */
472void BoundaryTriangleSet::GetCenter(Vector *center)
473{
474 center->Zero();
475 for(int i=0;i<3;i++)
476 center->AddVector(endpoints[i]->node->node);
477 center->Scale(1./3.);
478}
479
480/** output operator for BoundaryTriangleSet.
481 * \param &ost output stream
482 * \param &a boundary triangle
483 */
484ostream &operator <<(ostream &ost, BoundaryTriangleSet &a)
485{
486 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
487 << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
488 return ost;
489};
490
491// =========================================================== class TESSELPOINT ===========================================
492
493/** Constructor of class TesselPoint.
494 */
495TesselPoint::TesselPoint()
496{
497 node = NULL;
498 nr = -1;
499 Name = NULL;
500};
501
502/** Destructor for class TesselPoint.
503 */
504TesselPoint::~TesselPoint()
505{
506 Free((void **)&Name, "TesselPoint::~TesselPoint: *Name");
507};
508
509/** Prints LCNode to screen.
510 */
511ostream & operator << (ostream &ost, const TesselPoint &a)
512{
513 ost << "[" << (a.Name) << "|" << &a << "]";
514 return ost;
515};
516
517/** Prints LCNode to screen.
518 */
519ostream & TesselPoint::operator << (ostream &ost)
520{
521 ost << "[" << (Name) << "|" << this << "]";
522 return ost;
523};
524
525
526// =========================================================== class POINTCLOUD ============================================
527
528/** Constructor of class PointCloud.
529 */
530PointCloud::PointCloud()
531{
532
533};
534
535/** Destructor for class PointCloud.
536 */
537PointCloud::~PointCloud()
538{
539
540};
541
542// ============================ CandidateForTesselation =============================
543
544/** Constructor of class CandidateForTesselation.
545 */
546CandidateForTesselation::CandidateForTesselation(TesselPoint *candidate, BoundaryLineSet* line, Vector OptCandidateCenter, Vector OtherOptCandidateCenter) {
547 point = candidate;
548 BaseLine = line;
549 OptCenter.CopyVector(&OptCandidateCenter);
550 OtherOptCenter.CopyVector(&OtherOptCandidateCenter);
551};
552
553/** Destructor for class CandidateForTesselation.
554 */
555CandidateForTesselation::~CandidateForTesselation() {
556 point = NULL;
557 BaseLine = NULL;
558};
559
560// =========================================================== class TESSELATION ===========================================
561
562/** Constructor of class Tesselation.
563 */
564Tesselation::Tesselation()
565{
566 PointsOnBoundaryCount = 0;
567 LinesOnBoundaryCount = 0;
568 TrianglesOnBoundaryCount = 0;
569 InternalPointer = PointsOnBoundary.begin();
570}
571;
572
573/** Destructor of class Tesselation.
574 * We have to free all points, lines and triangles.
575 */
576Tesselation::~Tesselation()
577{
578 cout << Verbose(1) << "Free'ing TesselStruct ... " << endl;
579 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
580 if (runner->second != NULL) {
581 delete (runner->second);
582 runner->second = NULL;
583 } else
584 cerr << "ERROR: The triangle " << runner->first << " has already been free'd." << endl;
585 }
586}
587;
588
589/** PointCloud implementation of GetCenter
590 * Uses PointsOnBoundary and STL stuff.
591 */
592Vector * Tesselation::GetCenter(ofstream *out)
593{
594 Vector *Center = new Vector(0.,0.,0.);
595 int num=0;
596 for (GoToFirst(); (!IsEnd()); GoToNext()) {
597 Center->AddVector(GetPoint()->node);
598 num++;
599 }
600 Center->Scale(1./num);
601 return Center;
602};
603
604/** PointCloud implementation of GoPoint
605 * Uses PointsOnBoundary and STL stuff.
606 */
607TesselPoint * Tesselation::GetPoint()
608{
609 return (InternalPointer->second->node);
610};
611
612/** PointCloud implementation of GetTerminalPoint.
613 * Uses PointsOnBoundary and STL stuff.
614 */
615TesselPoint * Tesselation::GetTerminalPoint()
616{
617 PointMap::iterator Runner = PointsOnBoundary.end();
618 Runner--;
619 return (Runner->second->node);
620};
621
622/** PointCloud implementation of GoToNext.
623 * Uses PointsOnBoundary and STL stuff.
624 */
625void Tesselation::GoToNext()
626{
627 if (InternalPointer != PointsOnBoundary.end())
628 InternalPointer++;
629};
630
631/** PointCloud implementation of GoToPrevious.
632 * Uses PointsOnBoundary and STL stuff.
633 */
634void Tesselation::GoToPrevious()
635{
636 if (InternalPointer != PointsOnBoundary.begin())
637 InternalPointer--;
638};
639
640/** PointCloud implementation of GoToFirst.
641 * Uses PointsOnBoundary and STL stuff.
642 */
643void Tesselation::GoToFirst()
644{
645 InternalPointer = PointsOnBoundary.begin();
646};
647
648/** PointCloud implementation of GoToLast.
649 * Uses PointsOnBoundary and STL stuff.
650 */
651void Tesselation::GoToLast()
652{
653 InternalPointer = PointsOnBoundary.end();
654 InternalPointer--;
655};
656
657/** PointCloud implementation of IsEmpty.
658 * Uses PointsOnBoundary and STL stuff.
659 */
660bool Tesselation::IsEmpty()
661{
662 return (PointsOnBoundary.empty());
663};
664
665/** PointCloud implementation of IsLast.
666 * Uses PointsOnBoundary and STL stuff.
667 */
668bool Tesselation::IsEnd()
669{
670 return (InternalPointer == PointsOnBoundary.end());
671};
672
673
674/** Gueses first starting triangle of the convex envelope.
675 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
676 * \param *out output stream for debugging
677 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
678 */
679void
680Tesselation::GuessStartingTriangle(ofstream *out)
681{
682 // 4b. create a starting triangle
683 // 4b1. create all distances
684 DistanceMultiMap DistanceMMap;
685 double distance, tmp;
686 Vector PlaneVector, TrialVector;
687 PointMap::iterator A, B, C; // three nodes of the first triangle
688 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
689
690 // with A chosen, take each pair B,C and sort
691 if (A != PointsOnBoundary.end())
692 {
693 B = A;
694 B++;
695 for (; B != PointsOnBoundary.end(); B++)
696 {
697 C = B;
698 C++;
699 for (; C != PointsOnBoundary.end(); C++)
700 {
701 tmp = A->second->node->node->DistanceSquared(B->second->node->node);
702 distance = tmp * tmp;
703 tmp = A->second->node->node->DistanceSquared(C->second->node->node);
704 distance += tmp * tmp;
705 tmp = B->second->node->node->DistanceSquared(C->second->node->node);
706 distance += tmp * tmp;
707 DistanceMMap.insert(DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator> (B, C)));
708 }
709 }
710 }
711 // // listing distances
712 // *out << Verbose(1) << "Listing DistanceMMap:";
713 // for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
714 // *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
715 // }
716 // *out << endl;
717 // 4b2. pick three baselines forming a triangle
718 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
719 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
720 for (; baseline != DistanceMMap.end(); baseline++)
721 {
722 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
723 // 2. next, we have to check whether all points reside on only one side of the triangle
724 // 3. construct plane vector
725 PlaneVector.MakeNormalVector(A->second->node->node,
726 baseline->second.first->second->node->node,
727 baseline->second.second->second->node->node);
728 *out << Verbose(2) << "Plane vector of candidate triangle is ";
729 PlaneVector.Output(out);
730 *out << endl;
731 // 4. loop over all points
732 double sign = 0.;
733 PointMap::iterator checker = PointsOnBoundary.begin();
734 for (; checker != PointsOnBoundary.end(); checker++)
735 {
736 // (neglecting A,B,C)
737 if ((checker == A) || (checker == baseline->second.first) || (checker
738 == baseline->second.second))
739 continue;
740 // 4a. project onto plane vector
741 TrialVector.CopyVector(checker->second->node->node);
742 TrialVector.SubtractVector(A->second->node->node);
743 distance = TrialVector.ScalarProduct(&PlaneVector);
744 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
745 continue;
746 *out << Verbose(3) << "Projection of " << checker->second->node->Name
747 << " yields distance of " << distance << "." << endl;
748 tmp = distance / fabs(distance);
749 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
750 if ((sign != 0) && (tmp != sign))
751 {
752 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
753 *out << Verbose(2) << "Current candidates: "
754 << A->second->node->Name << ","
755 << baseline->second.first->second->node->Name << ","
756 << baseline->second.second->second->node->Name << " leaves "
757 << checker->second->node->Name << " outside the convex hull."
758 << endl;
759 break;
760 }
761 else
762 { // note the sign for later
763 *out << Verbose(2) << "Current candidates: "
764 << A->second->node->Name << ","
765 << baseline->second.first->second->node->Name << ","
766 << baseline->second.second->second->node->Name << " leave "
767 << checker->second->node->Name << " inside the convex hull."
768 << endl;
769 sign = tmp;
770 }
771 // 4d. Check whether the point is inside the triangle (check distance to each node
772 tmp = checker->second->node->node->DistanceSquared(A->second->node->node);
773 int innerpoint = 0;
774 if ((tmp < A->second->node->node->DistanceSquared(
775 baseline->second.first->second->node->node)) && (tmp
776 < A->second->node->node->DistanceSquared(
777 baseline->second.second->second->node->node)))
778 innerpoint++;
779 tmp = checker->second->node->node->DistanceSquared(
780 baseline->second.first->second->node->node);
781 if ((tmp < baseline->second.first->second->node->node->DistanceSquared(
782 A->second->node->node)) && (tmp
783 < baseline->second.first->second->node->node->DistanceSquared(
784 baseline->second.second->second->node->node)))
785 innerpoint++;
786 tmp = checker->second->node->node->DistanceSquared(
787 baseline->second.second->second->node->node);
788 if ((tmp < baseline->second.second->second->node->node->DistanceSquared(
789 baseline->second.first->second->node->node)) && (tmp
790 < baseline->second.second->second->node->node->DistanceSquared(
791 A->second->node->node)))
792 innerpoint++;
793 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
794 if (innerpoint == 3)
795 break;
796 }
797 // 5. come this far, all on same side? Then break 1. loop and construct triangle
798 if (checker == PointsOnBoundary.end())
799 {
800 *out << "Looks like we have a candidate!" << endl;
801 break;
802 }
803 }
804 if (baseline != DistanceMMap.end())
805 {
806 BPS[0] = baseline->second.first->second;
807 BPS[1] = baseline->second.second->second;
808 BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
809 BPS[0] = A->second;
810 BPS[1] = baseline->second.second->second;
811 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
812 BPS[0] = baseline->second.first->second;
813 BPS[1] = A->second;
814 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
815
816 // 4b3. insert created triangle
817 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
818 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
819 TrianglesOnBoundaryCount++;
820 for (int i = 0; i < NDIM; i++)
821 {
822 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));
823 LinesOnBoundaryCount++;
824 }
825
826 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
827 }
828 else
829 {
830 *out << Verbose(1) << "No starting triangle found." << endl;
831 exit(255);
832 }
833}
834;
835
836/** Tesselates the convex envelope of a cluster from a single starting triangle.
837 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
838 * 2 triangles. Hence, we go through all current lines:
839 * -# if the lines contains to only one triangle
840 * -# We search all points in the boundary
841 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
842 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
843 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors)
844 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
845 * \param *out output stream for debugging
846 * \param *configuration for IsAngstroem
847 * \param *cloud cluster of points
848 */
849void Tesselation::TesselateOnBoundary(ofstream *out, PointCloud *cloud)
850{
851 bool flag;
852 PointMap::iterator winner;
853 class BoundaryPointSet *peak = NULL;
854 double SmallestAngle, TempAngle;
855 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, helper, PropagationVector, *Center = NULL;
856 LineMap::iterator LineChecker[2];
857
858 Center = cloud->GetCenter(out);
859 // create a first tesselation with the given BoundaryPoints
860 do {
861 flag = false;
862 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
863 if (baseline->second->triangles.size() == 1) {
864 // 5a. go through each boundary point if not _both_ edges between either endpoint of the current line and this point exist (and belong to 2 triangles)
865 SmallestAngle = M_PI;
866
867 // get peak point with respect to this base line's only triangle
868 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
869 *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl;
870 for (int i = 0; i < 3; i++)
871 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
872 peak = BTS->endpoints[i];
873 *out << Verbose(3) << " and has peak " << *peak << "." << endl;
874
875 // prepare some auxiliary vectors
876 Vector BaseLineCenter, BaseLine;
877 BaseLineCenter.CopyVector(baseline->second->endpoints[0]->node->node);
878 BaseLineCenter.AddVector(baseline->second->endpoints[1]->node->node);
879 BaseLineCenter.Scale(1. / 2.); // points now to center of base line
880 BaseLine.CopyVector(baseline->second->endpoints[0]->node->node);
881 BaseLine.SubtractVector(baseline->second->endpoints[1]->node->node);
882
883 // offset to center of triangle
884 CenterVector.Zero();
885 for (int i = 0; i < 3; i++)
886 CenterVector.AddVector(BTS->endpoints[i]->node->node);
887 CenterVector.Scale(1. / 3.);
888 *out << Verbose(4) << "CenterVector of base triangle is " << CenterVector << endl;
889
890 // normal vector of triangle
891 NormalVector.CopyVector(Center);
892 NormalVector.SubtractVector(&CenterVector);
893 BTS->GetNormalVector(NormalVector);
894 NormalVector.CopyVector(&BTS->NormalVector);
895 *out << Verbose(4) << "NormalVector of base triangle is " << NormalVector << endl;
896
897 // vector in propagation direction (out of triangle)
898 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
899 PropagationVector.MakeNormalVector(&BaseLine, &NormalVector);
900 TempVector.CopyVector(&CenterVector);
901 TempVector.SubtractVector(baseline->second->endpoints[0]->node->node); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
902 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
903 if (PropagationVector.ScalarProduct(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
904 PropagationVector.Scale(-1.);
905 *out << Verbose(4) << "PropagationVector of base triangle is " << PropagationVector << endl;
906 winner = PointsOnBoundary.end();
907
908 // loop over all points and calculate angle between normal vector of new and present triangle
909 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) {
910 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
911 *out << Verbose(3) << "Target point is " << *(target->second) << ":" << endl;
912
913 // first check direction, so that triangles don't intersect
914 VirtualNormalVector.CopyVector(target->second->node->node);
915 VirtualNormalVector.SubtractVector(&BaseLineCenter); // points from center of base line to target
916 VirtualNormalVector.ProjectOntoPlane(&NormalVector);
917 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
918 *out << Verbose(4) << "VirtualNormalVector is " << VirtualNormalVector << " and PropagationVector is " << PropagationVector << "." << endl;
919 if (TempAngle > (M_PI/2.)) { // no bends bigger than Pi/2 (90 degrees)
920 *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
921 continue;
922 } else
923 *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
924
925 // check first and second endpoint (if any connecting line goes to target has at least not more than 1 triangle)
926 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
927 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
928 if (((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[0]->second->triangles.size() == 2))) {
929 *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->triangles.size() << " triangles." << endl;
930 continue;
931 }
932 if (((LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (LineChecker[1]->second->triangles.size() == 2))) {
933 *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->triangles.size() << " triangles." << endl;
934 continue;
935 }
936
937 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
938 if ((((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak)))) {
939 *out << Verbose(4) << "Current target is peak!" << endl;
940 continue;
941 }
942
943 // check for linear dependence
944 TempVector.CopyVector(baseline->second->endpoints[0]->node->node);
945 TempVector.SubtractVector(target->second->node->node);
946 helper.CopyVector(baseline->second->endpoints[1]->node->node);
947 helper.SubtractVector(target->second->node->node);
948 helper.ProjectOntoPlane(&TempVector);
949 if (fabs(helper.NormSquared()) < MYEPSILON) {
950 *out << Verbose(4) << "Chosen set of vectors is linear dependent." << endl;
951 continue;
952 }
953
954 // in case NOT both were found, create virtually this triangle, get its normal vector, calculate angle
955 flag = true;
956 VirtualNormalVector.MakeNormalVector(baseline->second->endpoints[0]->node->node, baseline->second->endpoints[1]->node->node, target->second->node->node);
957 TempVector.CopyVector(baseline->second->endpoints[0]->node->node);
958 TempVector.AddVector(baseline->second->endpoints[1]->node->node);
959 TempVector.AddVector(target->second->node->node);
960 TempVector.Scale(1./3.);
961 TempVector.SubtractVector(Center);
962 // make it always point outward
963 if (VirtualNormalVector.ScalarProduct(&TempVector) < 0)
964 VirtualNormalVector.Scale(-1.);
965 // calculate angle
966 TempAngle = NormalVector.Angle(&VirtualNormalVector);
967 *out << Verbose(4) << "NormalVector is " << VirtualNormalVector << " and the angle is " << TempAngle << "." << endl;
968 if ((SmallestAngle - TempAngle) > MYEPSILON) { // set to new possible winner
969 SmallestAngle = TempAngle;
970 winner = target;
971 *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
972 } else if (fabs(SmallestAngle - TempAngle) < MYEPSILON) { // check the angle to propagation, both possible targets are in one plane! (their normals have same angle)
973 // hence, check the angles to some normal direction from our base line but in this common plane of both targets...
974 helper.CopyVector(target->second->node->node);
975 helper.SubtractVector(&BaseLineCenter);
976 helper.ProjectOntoPlane(&BaseLine);
977 // ...the one with the smaller angle is the better candidate
978 TempVector.CopyVector(target->second->node->node);
979 TempVector.SubtractVector(&BaseLineCenter);
980 TempVector.ProjectOntoPlane(&VirtualNormalVector);
981 TempAngle = TempVector.Angle(&helper);
982 TempVector.CopyVector(winner->second->node->node);
983 TempVector.SubtractVector(&BaseLineCenter);
984 TempVector.ProjectOntoPlane(&VirtualNormalVector);
985 if (TempAngle < TempVector.Angle(&helper)) {
986 TempAngle = NormalVector.Angle(&VirtualNormalVector);
987 SmallestAngle = TempAngle;
988 winner = target;
989 *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle " << TempAngle << " to propagation direction." << endl;
990 } else
991 *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle to propagation direction." << endl;
992 } else
993 *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
994 }
995 } // end of loop over all boundary points
996
997 // 5b. The point of the above whose triangle has the greatest angle with the triangle the current line belongs to (it only belongs to one, remember!): New triangle
998 if (winner != PointsOnBoundary.end()) {
999 *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
1000 // create the lins of not yet present
1001 BLS[0] = baseline->second;
1002 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
1003 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
1004 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
1005 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
1006 BPS[0] = baseline->second->endpoints[0];
1007 BPS[1] = winner->second;
1008 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1009 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[1]));
1010 LinesOnBoundaryCount++;
1011 } else
1012 BLS[1] = LineChecker[0]->second;
1013 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
1014 BPS[0] = baseline->second->endpoints[1];
1015 BPS[1] = winner->second;
1016 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1017 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[2]));
1018 LinesOnBoundaryCount++;
1019 } else
1020 BLS[2] = LineChecker[1]->second;
1021 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1022 BTS->GetCenter(&helper);
1023 helper.SubtractVector(Center);
1024 helper.Scale(-1);
1025 BTS->GetNormalVector(helper);
1026 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1027 TrianglesOnBoundaryCount++;
1028 } else {
1029 *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
1030 }
1031
1032 // 5d. If the set of lines is not yet empty, go to 5. and continue
1033 } else
1034 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->triangles.size() << "." << endl;
1035 } while (flag);
1036
1037 // exit
1038 delete(Center);
1039};
1040
1041/** Inserts all points outside of the tesselated surface into it by adding new triangles.
1042 * \param *out output stream for debugging
1043 * \param *cloud cluster of points
1044 * \param *LC LinkedCell structure to find nearest point quickly
1045 * \return true - all straddling points insert, false - something went wrong
1046 */
1047bool Tesselation::InsertStraddlingPoints(ofstream *out, PointCloud *cloud, LinkedCell *LC)
1048{
1049 Vector Intersection, Normal;
1050 TesselPoint *Walker = NULL;
1051 Vector *Center = cloud->GetCenter(out);
1052 list<BoundaryTriangleSet*> *triangles = NULL;
1053
1054 *out << Verbose(1) << "Begin of InsertStraddlingPoints" << endl;
1055
1056 cloud->GoToFirst();
1057 while (!cloud->IsEnd()) { // we only have to go once through all points, as boundary can become only bigger
1058 LinkedCell BoundaryPoints(this, 5.);
1059 Walker = cloud->GetPoint();
1060 *out << Verbose(2) << "Current point is " << *Walker << "." << endl;
1061 // get the next triangle
1062 triangles = FindClosestTrianglesToPoint(out, Walker->node, &BoundaryPoints);
1063 if (triangles == NULL) {
1064 *out << Verbose(1) << "No triangles found, probably a tesselation point itself." << endl;
1065 cloud->GoToNext();
1066 continue;
1067 } else {
1068 BTS = triangles->front();
1069 }
1070 *out << Verbose(2) << "Closest triangle is " << *BTS << "." << endl;
1071 // get the intersection point
1072 if (BTS->GetIntersectionInsideTriangle(out, Center, Walker->node, &Intersection)) {
1073 *out << Verbose(2) << "We have an intersection at " << Intersection << "." << endl;
1074 // we have the intersection, check whether in- or outside of boundary
1075 if ((Center->DistanceSquared(Walker->node) - Center->DistanceSquared(&Intersection)) < -MYEPSILON) {
1076 // inside, next!
1077 *out << Verbose(2) << *Walker << " is inside wrt triangle " << *BTS << "." << endl;
1078 } else {
1079 // outside!
1080 *out << Verbose(2) << *Walker << " is outside wrt triangle " << *BTS << "." << endl;
1081 class BoundaryLineSet *OldLines[3], *NewLines[3];
1082 class BoundaryPointSet *OldPoints[3], *NewPoint;
1083 // store the three old lines and old points
1084 for (int i=0;i<3;i++) {
1085 OldLines[i] = BTS->lines[i];
1086 OldPoints[i] = BTS->endpoints[i];
1087 }
1088 Normal.CopyVector(&BTS->NormalVector);
1089 // add Walker to boundary points
1090 *out << Verbose(2) << "Adding " << *Walker << " to BoundaryPoints." << endl;
1091 if (AddBoundaryPoint(Walker,0))
1092 NewPoint = BPS[0];
1093 else
1094 continue;
1095 // remove triangle
1096 *out << Verbose(2) << "Erasing triangle " << *BTS << "." << endl;
1097 TrianglesOnBoundary.erase(BTS->Nr);
1098 delete(BTS);
1099 // create three new boundary lines
1100 for (int i=0;i<3;i++) {
1101 BPS[0] = NewPoint;
1102 BPS[1] = OldPoints[i];
1103 NewLines[i] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1104 *out << Verbose(3) << "Creating new line " << *NewLines[i] << "." << endl;
1105 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, NewLines[i])); // no need for check for unique insertion as BPS[0] is definitely a new one
1106 LinesOnBoundaryCount++;
1107 }
1108 // create three new triangle with new point
1109 for (int i=0;i<3;i++) { // find all baselines
1110 BLS[0] = OldLines[i];
1111 int n = 1;
1112 for (int j=0;j<3;j++) {
1113 if (NewLines[j]->IsConnectedTo(BLS[0])) {
1114 if (n>2) {
1115 *out << Verbose(1) << "ERROR: " << BLS[0] << " connects to all of the new lines?!" << endl;
1116 return false;
1117 } else
1118 BLS[n++] = NewLines[j];
1119 }
1120 }
1121 // create the triangle
1122 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1123 Normal.Scale(-1.);
1124 BTS->GetNormalVector(Normal);
1125 Normal.Scale(-1.);
1126 *out << Verbose(2) << "Created new triangle " << *BTS << "." << endl;
1127 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1128 TrianglesOnBoundaryCount++;
1129 }
1130 }
1131 } else { // something is wrong with FindClosestTriangleToPoint!
1132 *out << Verbose(1) << "ERROR: The closest triangle did not produce an intersection!" << endl;
1133 return false;
1134 }
1135 cloud->GoToNext();
1136 }
1137
1138 // exit
1139 delete(Center);
1140 *out << Verbose(1) << "End of InsertStraddlingPoints" << endl;
1141 return true;
1142};
1143
1144/** Adds a point to the tesselation::PointsOnBoundary list.
1145 * \param *Walker point to add
1146 * \param n TesselStruct::BPS index to put pointer into
1147 * \return true - new point was added, false - point already present
1148 */
1149bool
1150Tesselation::AddBoundaryPoint(TesselPoint *Walker, int n)
1151{
1152 PointTestPair InsertUnique;
1153 BPS[n] = new class BoundaryPointSet(Walker);
1154 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[n]));
1155 if (InsertUnique.second) { // if new point was not present before, increase counter
1156 PointsOnBoundaryCount++;
1157 return true;
1158 } else {
1159 delete(BPS[n]);
1160 BPS[n] = InsertUnique.first->second;
1161 return false;
1162 }
1163}
1164;
1165
1166/** Adds point to Tesselation::PointsOnBoundary if not yet present.
1167 * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
1168 * @param Candidate point to add
1169 * @param n index for this point in Tesselation::TPS array
1170 */
1171void
1172Tesselation::AddTesselationPoint(TesselPoint* Candidate, int n)
1173{
1174 PointTestPair InsertUnique;
1175 TPS[n] = new class BoundaryPointSet(Candidate);
1176 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
1177 if (InsertUnique.second) { // if new point was not present before, increase counter
1178 PointsOnBoundaryCount++;
1179 } else {
1180 delete TPS[n];
1181 cout << Verbose(3) << "Node " << *((InsertUnique.first)->second->node) << " is already present in PointsOnBoundary." << endl;
1182 TPS[n] = (InsertUnique.first)->second;
1183 }
1184}
1185;
1186
1187/** Function tries to add line from current Points in BPS to BoundaryLineSet.
1188 * If successful it raises the line count and inserts the new line into the BLS,
1189 * if unsuccessful, it writes the line which had been present into the BLS, deleting the new constructed one.
1190 * @param *a first endpoint
1191 * @param *b second endpoint
1192 * @param n index of Tesselation::BLS giving the line with both endpoints
1193 */
1194void Tesselation::AddTesselationLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n) {
1195 bool insertNewLine = true;
1196
1197 if (a->lines.find(b->node->nr) != a->lines.end()) {
1198 LineMap::iterator FindLine;
1199 pair<LineMap::iterator,LineMap::iterator> FindPair;
1200 FindPair = a->lines.equal_range(b->node->nr);
1201
1202 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
1203 // If there is a line with less than two attached triangles, we don't need a new line.
1204 if (FindLine->second->triangles.size() < 2) {
1205 insertNewLine = false;
1206 cout << Verbose(3) << "Using existing line " << *FindLine->second << endl;
1207
1208 BPS[0] = FindLine->second->endpoints[0];
1209 BPS[1] = FindLine->second->endpoints[1];
1210 BLS[n] = FindLine->second;
1211
1212 break;
1213 }
1214 }
1215 }
1216
1217 if (insertNewLine) {
1218 AlwaysAddTesselationTriangleLine(a, b, n);
1219 }
1220}
1221;
1222
1223/**
1224 * Adds lines from each of the current points in the BPS to BoundaryLineSet.
1225 * Raises the line count and inserts the new line into the BLS.
1226 *
1227 * @param *a first endpoint
1228 * @param *b second endpoint
1229 * @param n index of Tesselation::BLS giving the line with both endpoints
1230 */
1231void Tesselation::AlwaysAddTesselationTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n)
1232{
1233 cout << Verbose(3) << "Adding line between " << *(a->node) << " and " << *(b->node) << "." << endl;
1234 BPS[0] = a;
1235 BPS[1] = b;
1236 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); // this also adds the line to the local maps
1237 // add line to global map
1238 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
1239 // increase counter
1240 LinesOnBoundaryCount++;
1241};
1242
1243/** Function tries to add Triangle just created to Triangle and remarks if already existent (Failure of algorithm).
1244 * Furthermore it adds the triangle to all of its lines, in order to recognize those which are saturated later.
1245 */
1246void Tesselation::AddTesselationTriangle()
1247{
1248 cout << Verbose(1) << "Adding triangle to global TrianglesOnBoundary map." << endl;
1249
1250 // add triangle to global map
1251 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1252 TrianglesOnBoundaryCount++;
1253
1254 // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
1255};
1256
1257/** Removes a triangle from the tesselation.
1258 * Removes itself from the TriangleMap's of its lines, calls for them RemoveTriangleLine() if they are no more connected.
1259 * Removes itself from memory.
1260 * \param *triangle to remove
1261 */
1262void Tesselation::RemoveTesselationTriangle(class BoundaryTriangleSet *triangle)
1263{
1264 if (triangle == NULL)
1265 return;
1266 for (int i = 0; i < 3; i++) {
1267 if (triangle->lines[i] != NULL) {
1268 cout << Verbose(5) << "Removing triangle Nr." << triangle->Nr << " in line " << *triangle->lines[i] << "." << endl;
1269 triangle->lines[i]->triangles.erase(triangle->Nr);
1270 if (triangle->lines[i]->triangles.empty()) {
1271 cout << Verbose(5) << *triangle->lines[i] << " is no more attached to any triangle, erasing." << endl;
1272 RemoveTesselationLine(triangle->lines[i]);
1273 triangle->lines[i] = NULL;
1274 } else
1275 cout << Verbose(5) << *triangle->lines[i] << " is still attached to another triangle." << endl;
1276 } else
1277 cerr << "ERROR: This line " << i << " has already been free'd." << endl;
1278 }
1279
1280 if (TrianglesOnBoundary.erase(triangle->Nr))
1281 cout << Verbose(5) << "Removing triangle Nr. " << triangle->Nr << "." << endl;
1282 delete(triangle);
1283};
1284
1285/** Removes a line from the tesselation.
1286 * Removes itself from each endpoints' LineMap, then removes itself from global LinesOnBoundary list and free's the line.
1287 * \param *line line to remove
1288 */
1289void Tesselation::RemoveTesselationLine(class BoundaryLineSet *line)
1290{
1291 int Numbers[2];
1292
1293 if (line == NULL)
1294 return;
1295 // get other endpoint number of finding copies of same line
1296 if (line->endpoints[1] != NULL)
1297 Numbers[0] = line->endpoints[1]->Nr;
1298 else
1299 Numbers[0] = -1;
1300 if (line->endpoints[0] != NULL)
1301 Numbers[1] = line->endpoints[0]->Nr;
1302 else
1303 Numbers[1] = -1;
1304
1305 for (int i = 0; i < 2; i++) {
1306 if (line->endpoints[i] != NULL) {
1307 if (Numbers[i] != -1) { // as there may be multiple lines with same endpoints, we have to go through each and find in the endpoint's line list this line set
1308 pair<LineMap::iterator, LineMap::iterator> erasor = line->endpoints[i]->lines.equal_range(Numbers[i]);
1309 for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
1310 if ((*Runner).second == line) {
1311 cout << Verbose(5) << "Removing Line Nr. " << line->Nr << " in boundary point " << *line->endpoints[i] << "." << endl;
1312 line->endpoints[i]->lines.erase(Runner);
1313 break;
1314 }
1315 } else { // there's just a single line left
1316 if (line->endpoints[i]->lines.erase(line->Nr))
1317 cout << Verbose(5) << "Removing Line Nr. " << line->Nr << " in boundary point " << *line->endpoints[i] << "." << endl;
1318 }
1319 if (line->endpoints[i]->lines.empty()) {
1320 cout << Verbose(5) << *line->endpoints[i] << " has no more lines it's attached to, erasing." << endl;
1321 RemoveTesselationPoint(line->endpoints[i]);
1322 line->endpoints[i] = NULL;
1323 } else
1324 cout << Verbose(5) << *line->endpoints[i] << " has still lines it's attached to." << endl;
1325 } else
1326 cerr << "ERROR: Endpoint " << i << " has already been free'd." << endl;
1327 }
1328 if (!line->triangles.empty())
1329 cerr << "WARNING: Memory Leak! I " << *line << " am still connected to some triangles." << endl;
1330
1331 if (LinesOnBoundary.erase(line->Nr))
1332 cout << Verbose(5) << "Removing line Nr. " << line->Nr << "." << endl;
1333 delete(line);
1334};
1335
1336/** Removes a point from the tesselation.
1337 * Checks whether there are still lines connected, removes from global PointsOnBoundary list, then free's the point.
1338 * \note If a point should be removed, while keep the tesselated surface intact (i.e. closed), use RemovePointFromTesselatedSurface()
1339 * \param *point point to remove
1340 */
1341void Tesselation::RemoveTesselationPoint(class BoundaryPointSet *point)
1342{
1343 if (point == NULL)
1344 return;
1345 if (PointsOnBoundary.erase(point->Nr))
1346 cout << Verbose(5) << "Removing point Nr. " << point->Nr << "." << endl;
1347 delete(point);
1348};
1349
1350/** Checks whether the triangle consisting of the three points is already present.
1351 * Searches for the points in Tesselation::PointsOnBoundary and checks their
1352 * lines. If any of the three edges already has two triangles attached, false is
1353 * returned.
1354 * \param *out output stream for debugging
1355 * \param *Candidates endpoints of the triangle candidate
1356 * \return integer 0 if no triangle exists, 1 if one triangle exists, 2 if two
1357 * triangles exist which is the maximum for three points
1358 */
1359int Tesselation::CheckPresenceOfTriangle(ofstream *out, TesselPoint *Candidates[3]) {
1360 int adjacentTriangleCount = 0;
1361 class BoundaryPointSet *Points[3];
1362
1363 *out << Verbose(2) << "Begin of CheckPresenceOfTriangle" << endl;
1364 // builds a triangle point set (Points) of the end points
1365 for (int i = 0; i < 3; i++) {
1366 PointMap::iterator FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
1367 if (FindPoint != PointsOnBoundary.end()) {
1368 Points[i] = FindPoint->second;
1369 } else {
1370 Points[i] = NULL;
1371 }
1372 }
1373
1374 // checks lines between the points in the Points for their adjacent triangles
1375 for (int i = 0; i < 3; i++) {
1376 if (Points[i] != NULL) {
1377 for (int j = i; j < 3; j++) {
1378 if (Points[j] != NULL) {
1379 LineMap::iterator FindLine = Points[i]->lines.find(Points[j]->node->nr);
1380 for (; (FindLine != Points[i]->lines.end()) && (FindLine->first == Points[j]->node->nr); FindLine++) {
1381 TriangleMap *triangles = &FindLine->second->triangles;
1382 *out << Verbose(3) << "Current line is " << FindLine->first << ": " << *(FindLine->second) << " with triangles " << triangles << "." << endl;
1383 for (TriangleMap::iterator FindTriangle = triangles->begin(); FindTriangle != triangles->end(); FindTriangle++) {
1384 if (FindTriangle->second->IsPresentTupel(Points)) {
1385 adjacentTriangleCount++;
1386 }
1387 }
1388 *out << Verbose(3) << "end." << endl;
1389 }
1390 // Only one of the triangle lines must be considered for the triangle count.
1391 *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1392 return adjacentTriangleCount;
1393 }
1394 }
1395 }
1396 }
1397
1398 *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1399 *out << Verbose(2) << "End of CheckPresenceOfTriangle" << endl;
1400 return adjacentTriangleCount;
1401};
1402
1403
1404/** Finds the starting triangle for FindNonConvexBorder().
1405 * Looks at the outermost point per axis, then FindSecondPointForTesselation()
1406 * for the second and FindNextSuitablePointViaAngleOfSphere() for the third
1407 * point are called.
1408 * \param *out output stream for debugging
1409 * \param RADIUS radius of virtual rolling sphere
1410 * \param *LC LinkedCell structure with neighbouring TesselPoint's
1411 */
1412void Tesselation::FindStartingTriangle(ofstream *out, const double RADIUS, LinkedCell *LC)
1413{
1414 cout << Verbose(1) << "Begin of FindStartingTriangle\n";
1415 int i = 0;
1416 LinkedNodes *List = NULL;
1417 TesselPoint* FirstPoint = NULL;
1418 TesselPoint* SecondPoint = NULL;
1419 TesselPoint* MaxPoint[NDIM];
1420 double maxCoordinate[NDIM];
1421 Vector Oben;
1422 Vector helper;
1423 Vector Chord;
1424 Vector SearchDirection;
1425
1426 Oben.Zero();
1427
1428 for (i = 0; i < 3; i++) {
1429 MaxPoint[i] = NULL;
1430 maxCoordinate[i] = -1;
1431 }
1432
1433 // 1. searching topmost point with respect to each axis
1434 for (int i=0;i<NDIM;i++) { // each axis
1435 LC->n[i] = LC->N[i]-1; // current axis is topmost cell
1436 for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++)
1437 for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) {
1438 List = LC->GetCurrentCell();
1439 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1440 if (List != NULL) {
1441 for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
1442 if ((*Runner)->node->x[i] > maxCoordinate[i]) {
1443 cout << Verbose(2) << "New maximal for axis " << i << " node is " << *(*Runner) << " at " << *(*Runner)->node << "." << endl;
1444 maxCoordinate[i] = (*Runner)->node->x[i];
1445 MaxPoint[i] = (*Runner);
1446 }
1447 }
1448 } else {
1449 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
1450 }
1451 }
1452 }
1453
1454 cout << Verbose(2) << "Found maximum coordinates: ";
1455 for (int i=0;i<NDIM;i++)
1456 cout << i << ": " << *MaxPoint[i] << "\t";
1457 cout << endl;
1458
1459 BTS = NULL;
1460 CandidateList *OptCandidates = new CandidateList();
1461 for (int k=0;k<NDIM;k++) {
1462 Oben.x[k] = 1.;
1463 FirstPoint = MaxPoint[k];
1464 cout << Verbose(1) << "Coordinates of start node at " << *FirstPoint->node << "." << endl;
1465
1466 double ShortestAngle;
1467 TesselPoint* OptCandidate = NULL;
1468 ShortestAngle = 999999.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant.
1469
1470 FindSecondPointForTesselation(FirstPoint, NULL, Oben, OptCandidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
1471 SecondPoint = OptCandidate;
1472 if (SecondPoint == NULL) // have we found a second point?
1473 continue;
1474 else
1475 cout << Verbose(1) << "Found second point is at " << *SecondPoint->node << ".\n";
1476
1477 helper.CopyVector(FirstPoint->node);
1478 helper.SubtractVector(SecondPoint->node);
1479 helper.Normalize();
1480 Oben.ProjectOntoPlane(&helper);
1481 Oben.Normalize();
1482 helper.VectorProduct(&Oben);
1483 ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1484
1485 Chord.CopyVector(FirstPoint->node); // bring into calling function
1486 Chord.SubtractVector(SecondPoint->node);
1487 double radius = Chord.ScalarProduct(&Chord);
1488 double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.);
1489 helper.CopyVector(&Oben);
1490 helper.Scale(CircleRadius);
1491 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized)
1492
1493 // look in one direction of baseline for initial candidate
1494 SearchDirection.MakeNormalVector(&Chord, &Oben); // whether we look "left" first or "right" first is not important ...
1495
1496 // adding point 1 and point 2 and add the line between them
1497 AddTesselationPoint(FirstPoint, 0);
1498 AddTesselationPoint(SecondPoint, 1);
1499 AddTesselationLine(TPS[0], TPS[1], 0);
1500
1501 //cout << Verbose(2) << "INFO: OldSphereCenter is at " << helper << ".\n";
1502 FindThirdPointForTesselation(
1503 Oben, SearchDirection, helper, BLS[0], NULL, *&OptCandidates, &ShortestAngle, RADIUS, LC
1504 );
1505 cout << Verbose(1) << "List of third Points is ";
1506 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1507 cout << " " << *(*it)->point;
1508 }
1509 cout << endl;
1510
1511 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1512 // add third triangle point
1513 AddTesselationPoint((*it)->point, 2);
1514 // add the second and third line
1515 AddTesselationLine(TPS[1], TPS[2], 1);
1516 AddTesselationLine(TPS[0], TPS[2], 2);
1517 // ... and triangles to the Maps of the Tesselation class
1518 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1519 AddTesselationTriangle();
1520 // ... and calculate its normal vector (with correct orientation)
1521 (*it)->OptCenter.Scale(-1.);
1522 cout << Verbose(2) << "Anti-Oben is currently " << (*it)->OptCenter << "." << endl;
1523 BTS->GetNormalVector((*it)->OptCenter); // vector to compare with should point inwards
1524 cout << Verbose(0) << "==> Found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and "
1525 << *(*it)->point << " with normal vector " << BTS->NormalVector << ".\n";
1526
1527 // if we do not reach the end with the next step of iteration, we need to setup a new first line
1528 if (it != OptCandidates->end()--) {
1529 FirstPoint = (*it)->BaseLine->endpoints[0]->node;
1530 SecondPoint = (*it)->point;
1531 // adding point 1 and point 2 and the line between them
1532 AddTesselationPoint(FirstPoint, 0);
1533 AddTesselationPoint(SecondPoint, 1);
1534 AddTesselationLine(TPS[0], TPS[1], 0);
1535 }
1536 cout << Verbose(2) << "Projection is " << BTS->NormalVector.ScalarProduct(&Oben) << "." << endl;
1537 }
1538 if (BTS != NULL) // we have created one starting triangle
1539 break;
1540 else {
1541 // remove all candidates from the list and then the list itself
1542 class CandidateForTesselation *remover = NULL;
1543 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1544 remover = *it;
1545 delete(remover);
1546 }
1547 OptCandidates->clear();
1548 }
1549 }
1550
1551 // remove all candidates from the list and then the list itself
1552 class CandidateForTesselation *remover = NULL;
1553 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1554 remover = *it;
1555 delete(remover);
1556 }
1557 delete(OptCandidates);
1558 cout << Verbose(1) << "End of FindStartingTriangle\n";
1559};
1560
1561
1562/** This function finds a triangle to a line, adjacent to an existing one.
1563 * @param out output stream for debugging
1564 * @param Line current baseline to search from
1565 * @param T current triangle which \a Line is edge of
1566 * @param RADIUS radius of the rolling ball
1567 * @param N number of found triangles
1568 * @param *LC LinkedCell structure with neighbouring points
1569 */
1570bool Tesselation::FindNextSuitableTriangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, int N, LinkedCell *LC)
1571{
1572 cout << Verbose(0) << "Begin of FindNextSuitableTriangle\n";
1573 bool result = true;
1574 CandidateList *OptCandidates = new CandidateList();
1575
1576 Vector CircleCenter;
1577 Vector CirclePlaneNormal;
1578 Vector OldSphereCenter;
1579 Vector SearchDirection;
1580 Vector helper;
1581 TesselPoint *ThirdNode = NULL;
1582 LineMap::iterator testline;
1583 double ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1584 double radius, CircleRadius;
1585
1586 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl;
1587 for (int i=0;i<3;i++)
1588 if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node))
1589 ThirdNode = T.endpoints[i]->node;
1590
1591 // construct center of circle
1592 CircleCenter.CopyVector(Line.endpoints[0]->node->node);
1593 CircleCenter.AddVector(Line.endpoints[1]->node->node);
1594 CircleCenter.Scale(0.5);
1595
1596 // construct normal vector of circle
1597 CirclePlaneNormal.CopyVector(Line.endpoints[0]->node->node);
1598 CirclePlaneNormal.SubtractVector(Line.endpoints[1]->node->node);
1599
1600 // calculate squared radius of circle
1601 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
1602 if (radius/4. < RADIUS*RADIUS) {
1603 CircleRadius = RADIUS*RADIUS - radius/4.;
1604 CirclePlaneNormal.Normalize();
1605 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
1606
1607 // construct old center
1608 GetCenterofCircumcircle(&OldSphereCenter, T.endpoints[0]->node->node, T.endpoints[1]->node->node, T.endpoints[2]->node->node);
1609 helper.CopyVector(&T.NormalVector); // normal vector ensures that this is correct center of the two possible ones
1610 radius = Line.endpoints[0]->node->node->DistanceSquared(&OldSphereCenter);
1611 helper.Scale(sqrt(RADIUS*RADIUS - radius));
1612 OldSphereCenter.AddVector(&helper);
1613 OldSphereCenter.SubtractVector(&CircleCenter);
1614 //cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
1615
1616 // construct SearchDirection
1617 SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal);
1618 helper.CopyVector(Line.endpoints[0]->node->node);
1619 helper.SubtractVector(ThirdNode->node);
1620 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
1621 SearchDirection.Scale(-1.);
1622 SearchDirection.ProjectOntoPlane(&OldSphereCenter);
1623 SearchDirection.Normalize();
1624 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
1625 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
1626 // rotated the wrong way!
1627 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
1628 }
1629
1630 // add third point
1631 FindThirdPointForTesselation(
1632 T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, OptCandidates,
1633 &ShortestAngle, RADIUS, LC
1634 );
1635
1636 } else {
1637 cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl;
1638 }
1639
1640 if (OptCandidates->begin() == OptCandidates->end()) {
1641 cerr << "WARNING: Could not find a suitable candidate." << endl;
1642 return false;
1643 }
1644 cout << Verbose(1) << "Third Points are ";
1645 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1646 cout << " " << *(*it)->point;
1647 }
1648 cout << endl;
1649
1650 BoundaryLineSet *BaseRay = &Line;
1651 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1652 cout << Verbose(1) << " Third point candidate is " << *(*it)->point
1653 << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
1654 cout << Verbose(1) << " Baseline is " << *BaseRay << endl;
1655
1656 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
1657 TesselPoint *PointCandidates[3];
1658 PointCandidates[0] = (*it)->point;
1659 PointCandidates[1] = BaseRay->endpoints[0]->node;
1660 PointCandidates[2] = BaseRay->endpoints[1]->node;
1661 int existentTrianglesCount = CheckPresenceOfTriangle(out, PointCandidates);
1662
1663 BTS = NULL;
1664 // If there is no triangle, add it regularly.
1665 if (existentTrianglesCount == 0) {
1666 AddTesselationPoint((*it)->point, 0);
1667 AddTesselationPoint(BaseRay->endpoints[0]->node, 1);
1668 AddTesselationPoint(BaseRay->endpoints[1]->node, 2);
1669
1670 if (CheckLineCriteriaForDegeneratedTriangle(TPS)) {
1671 AddTesselationLine(TPS[0], TPS[1], 0);
1672 AddTesselationLine(TPS[0], TPS[2], 1);
1673 AddTesselationLine(TPS[1], TPS[2], 2);
1674
1675 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1676 AddTesselationTriangle();
1677 (*it)->OptCenter.Scale(-1.);
1678 BTS->GetNormalVector((*it)->OptCenter);
1679 (*it)->OptCenter.Scale(-1.);
1680
1681 cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector
1682 << " for this triangle ... " << endl;
1683 //cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << *BaseRay << "." << endl;
1684 } else {
1685 cout << Verbose(1) << "WARNING: This triangle consisting of ";
1686 cout << *(*it)->point << ", ";
1687 cout << *BaseRay->endpoints[0]->node << " and ";
1688 cout << *BaseRay->endpoints[1]->node << " ";
1689 cout << "exists and is not added, as it does not seem helpful!" << endl;
1690 result = false;
1691 }
1692 } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time.
1693 AddTesselationPoint((*it)->point, 0);
1694 AddTesselationPoint(BaseRay->endpoints[0]->node, 1);
1695 AddTesselationPoint(BaseRay->endpoints[1]->node, 2);
1696
1697 // We demand that at most one new degenerate line is created and that this line also already exists (which has to be the case due to existentTrianglesCount == 1)
1698 // i.e. at least one of the three lines must be present with TriangleCount <= 1
1699 if (CheckLineCriteriaForDegeneratedTriangle(TPS)) {
1700 AddTesselationLine(TPS[0], TPS[1], 0);
1701 AddTesselationLine(TPS[0], TPS[2], 1);
1702 AddTesselationLine(TPS[1], TPS[2], 2);
1703
1704 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1705 AddTesselationTriangle(); // add to global map
1706
1707 (*it)->OtherOptCenter.Scale(-1.);
1708 BTS->GetNormalVector((*it)->OtherOptCenter);
1709 (*it)->OtherOptCenter.Scale(-1.);
1710
1711 cout << "--> WARNING: Special new triangle with " << *BTS << " and normal vector " << BTS->NormalVector
1712 << " for this triangle ... " << endl;
1713 cout << Verbose(1) << "We have "<< BaseRay->triangles.size() << " for line " << BaseRay << "." << endl;
1714 } else {
1715 cout << Verbose(1) << "WARNING: This triangle consisting of ";
1716 cout << *(*it)->point << ", ";
1717 cout << *BaseRay->endpoints[0]->node << " and ";
1718 cout << *BaseRay->endpoints[1]->node << " ";
1719 cout << "exists and is not added, as it does not seem helpful!" << endl;
1720 result = false;
1721 }
1722 } else {
1723 cout << Verbose(1) << "This triangle consisting of ";
1724 cout << *(*it)->point << ", ";
1725 cout << *BaseRay->endpoints[0]->node << " and ";
1726 cout << *BaseRay->endpoints[1]->node << " ";
1727 cout << "is invalid!" << endl;
1728 result = false;
1729 }
1730
1731 // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
1732 BaseRay = BLS[0];
1733 }
1734
1735 // remove all candidates from the list and then the list itself
1736 class CandidateForTesselation *remover = NULL;
1737 for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
1738 remover = *it;
1739 delete(remover);
1740 }
1741 delete(OptCandidates);
1742 cout << Verbose(0) << "End of FindNextSuitableTriangle\n";
1743 return result;
1744};
1745
1746/** Checks whether the quadragon of the two triangles connect to \a *Base is convex.
1747 * We look whether the closest point on \a *Base with respect to the other baseline is outside
1748 * of the segment formed by both endpoints (concave) or not (convex).
1749 * \param *out output stream for debugging
1750 * \param *Base line to be flipped
1751 * \return NULL - concave, otherwise endpoint that makes it concave
1752 */
1753class BoundaryPointSet *Tesselation::IsConvexRectangle(ofstream *out, class BoundaryLineSet *Base)
1754{
1755 class BoundaryPointSet *Spot = NULL;
1756 class BoundaryLineSet *OtherBase;
1757 Vector *ClosestPoint;
1758
1759 int m=0;
1760 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1761 for (int j=0;j<3;j++) // all of their endpoints and baselines
1762 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) // and neither of its endpoints
1763 BPS[m++] = runner->second->endpoints[j];
1764 OtherBase = new class BoundaryLineSet(BPS,-1);
1765
1766 *out << Verbose(3) << "INFO: Current base line is " << *Base << "." << endl;
1767 *out << Verbose(3) << "INFO: Other base line is " << *OtherBase << "." << endl;
1768
1769 // get the closest point on each line to the other line
1770 ClosestPoint = GetClosestPointBetweenLine(out, Base, OtherBase);
1771
1772 // delete the temporary other base line
1773 delete(OtherBase);
1774
1775 // get the distance vector from Base line to OtherBase line
1776 Vector DistanceToIntersection[2], BaseLine;
1777 double distance[2];
1778 BaseLine.CopyVector(Base->endpoints[1]->node->node);
1779 BaseLine.SubtractVector(Base->endpoints[0]->node->node);
1780 for (int i=0;i<2;i++) {
1781 DistanceToIntersection[i].CopyVector(ClosestPoint);
1782 DistanceToIntersection[i].SubtractVector(Base->endpoints[i]->node->node);
1783 distance[i] = BaseLine.ScalarProduct(&DistanceToIntersection[i]);
1784 }
1785 delete(ClosestPoint);
1786 if ((distance[0] * distance[1]) > 0) { // have same sign?
1787 *out << Verbose(3) << "REJECT: Both SKPs have same sign: " << distance[0] << " and " << distance[1] << ". " << *Base << "' rectangle is concave." << endl;
1788 if (distance[0] < distance[1]) {
1789 Spot = Base->endpoints[0];
1790 } else {
1791 Spot = Base->endpoints[1];
1792 }
1793 return Spot;
1794 } else { // different sign, i.e. we are in between
1795 *out << Verbose(3) << "ACCEPT: Rectangle of triangles of base line " << *Base << " is convex." << endl;
1796 return NULL;
1797 }
1798
1799};
1800
1801void Tesselation::PrintAllBoundaryPoints(ofstream *out)
1802{
1803 // print all lines
1804 *out << Verbose(1) << "Printing all boundary points for debugging:" << endl;
1805 for (PointMap::iterator PointRunner = PointsOnBoundary.begin();PointRunner != PointsOnBoundary.end(); PointRunner++)
1806 *out << Verbose(2) << *(PointRunner->second) << endl;
1807};
1808
1809void Tesselation::PrintAllBoundaryLines(ofstream *out)
1810{
1811 // print all lines
1812 *out << Verbose(1) << "Printing all boundary lines for debugging:" << endl;
1813 for (LineMap::iterator LineRunner = LinesOnBoundary.begin(); LineRunner != LinesOnBoundary.end(); LineRunner++)
1814 *out << Verbose(2) << *(LineRunner->second) << endl;
1815};
1816
1817void Tesselation::PrintAllBoundaryTriangles(ofstream *out)
1818{
1819 // print all triangles
1820 *out << Verbose(1) << "Printing all boundary triangles for debugging:" << endl;
1821 for (TriangleMap::iterator TriangleRunner = TrianglesOnBoundary.begin(); TriangleRunner != TrianglesOnBoundary.end(); TriangleRunner++)
1822 *out << Verbose(2) << *(TriangleRunner->second) << endl;
1823};
1824
1825/** For a given boundary line \a *Base and its two triangles, picks the central baseline that is "higher".
1826 * \param *out output stream for debugging
1827 * \param *Base line to be flipped
1828 * \return true - line was changed, false - same line as before
1829 */
1830bool Tesselation::PickFarthestofTwoBaselines(ofstream *out, class BoundaryLineSet *Base)
1831{
1832 class BoundaryLineSet *OtherBase;
1833 Vector *ClosestPoint[2];
1834
1835 int m=0;
1836 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1837 for (int j=0;j<3;j++) // all of their endpoints and baselines
1838 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) // and neither of its endpoints
1839 BPS[m++] = runner->second->endpoints[j];
1840 OtherBase = new class BoundaryLineSet(BPS,-1);
1841
1842 *out << Verbose(3) << "INFO: Current base line is " << *Base << "." << endl;
1843 *out << Verbose(3) << "INFO: Other base line is " << *OtherBase << "." << endl;
1844
1845 // get the closest point on each line to the other line
1846 ClosestPoint[0] = GetClosestPointBetweenLine(out, Base, OtherBase);
1847 ClosestPoint[1] = GetClosestPointBetweenLine(out, OtherBase, Base);
1848
1849 // get the distance vector from Base line to OtherBase line
1850 Vector Distance;
1851 Distance.CopyVector(ClosestPoint[1]);
1852 Distance.SubtractVector(ClosestPoint[0]);
1853
1854 // delete the temporary other base line and the closest points
1855 delete(ClosestPoint[0]);
1856 delete(ClosestPoint[1]);
1857 delete(OtherBase);
1858
1859 if (Distance.NormSquared() < MYEPSILON) { // check for intersection
1860 *out << Verbose(3) << "REJECT: Both lines have an intersection: Nothing to do." << endl;
1861 return false;
1862 } else { // check for sign against BaseLineNormal
1863 Vector BaseLineNormal;
1864 BaseLineNormal.Zero();
1865 if (Base->triangles.size() < 2) {
1866 *out << Verbose(2) << "ERROR: Less than two triangles are attached to this baseline!" << endl;
1867 return false;
1868 }
1869 for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
1870 *out << Verbose(4) << "INFO: Adding NormalVector " << runner->second->NormalVector << " of triangle " << *(runner->second) << "." << endl;
1871 BaseLineNormal.AddVector(&(runner->second->NormalVector));
1872 }
1873 BaseLineNormal.Scale(1./2.);
1874
1875 if (Distance.ScalarProduct(&BaseLineNormal) > MYEPSILON) { // Distance points outwards, hence OtherBase higher than Base -> flip
1876 *out << Verbose(2) << "ACCEPT: Other base line would be higher: Flipping baseline." << endl;
1877 FlipBaseline(out, Base);
1878 return true;
1879 } else { // Base higher than OtherBase -> do nothing
1880 *out << Verbose(2) << "REJECT: Base line is higher: Nothing to do." << endl;
1881 return false;
1882 }
1883 }
1884};
1885
1886/** Returns the closest point on \a *Base with respect to \a *OtherBase.
1887 * \param *out output stream for debugging
1888 * \param *Base reference line
1889 * \param *OtherBase other base line
1890 * \return Vector on reference line that has closest distance
1891 */
1892Vector * GetClosestPointBetweenLine(ofstream *out, class BoundaryLineSet *Base, class BoundaryLineSet *OtherBase)
1893{
1894 // construct the plane of the two baselines (i.e. take both their directional vectors)
1895 Vector Normal;
1896 Vector Baseline, OtherBaseline;
1897 Baseline.CopyVector(Base->endpoints[1]->node->node);
1898 Baseline.SubtractVector(Base->endpoints[0]->node->node);
1899 OtherBaseline.CopyVector(OtherBase->endpoints[1]->node->node);
1900 OtherBaseline.SubtractVector(OtherBase->endpoints[0]->node->node);
1901 Normal.CopyVector(&Baseline);
1902 Normal.VectorProduct(&OtherBaseline);
1903 Normal.Normalize();
1904 *out << Verbose(4) << "First direction is " << Baseline << ", second direction is " << OtherBaseline << ", normal of intersection plane is " << Normal << "." << endl;
1905
1906 // project one offset point of OtherBase onto this plane (and add plane offset vector)
1907 Vector NewOffset;
1908 NewOffset.CopyVector(OtherBase->endpoints[0]->node->node);
1909 NewOffset.SubtractVector(Base->endpoints[0]->node->node);
1910 NewOffset.ProjectOntoPlane(&Normal);
1911 NewOffset.AddVector(Base->endpoints[0]->node->node);
1912 Vector NewDirection;
1913 NewDirection.CopyVector(&NewOffset);
1914 NewDirection.AddVector(&OtherBaseline);
1915
1916 // calculate the intersection between this projected baseline and Base
1917 Vector *Intersection = new Vector;
1918 Intersection->GetIntersectionOfTwoLinesOnPlane(out, Base->endpoints[0]->node->node, Base->endpoints[1]->node->node, &NewOffset, &NewDirection, &Normal);
1919 Normal.CopyVector(Intersection);
1920 Normal.SubtractVector(Base->endpoints[0]->node->node);
1921 *out << Verbose(3) << "Found closest point on " << *Base << " at " << *Intersection << ", factor in line is " << fabs(Normal.ScalarProduct(&Baseline)/Baseline.NormSquared()) << "." << endl;
1922
1923 return Intersection;
1924};
1925
1926/** For a given baseline and its two connected triangles, flips the baseline.
1927 * I.e. we create the new baseline between the other two endpoints of these four
1928 * endpoints and reconstruct the two triangles accordingly.
1929 * \param *out output stream for debugging
1930 * \param *Base line to be flipped
1931 * \return true - flipping successful, false - something went awry
1932 */
1933bool Tesselation::FlipBaseline(ofstream *out, class BoundaryLineSet *Base)
1934{
1935 class BoundaryLineSet *OldLines[4], *NewLine;
1936 class BoundaryPointSet *OldPoints[2];
1937 Vector BaseLineNormal;
1938 int OldTriangleNrs[2], OldBaseLineNr;
1939 int i,m;
1940
1941 *out << Verbose(1) << "Begin of FlipBaseline" << endl;
1942
1943 // calculate NormalVector for later use
1944 BaseLineNormal.Zero();
1945 if (Base->triangles.size() < 2) {
1946 *out << Verbose(2) << "ERROR: Less than two triangles are attached to this baseline!" << endl;
1947 return false;
1948 }
1949 for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
1950 *out << Verbose(4) << "INFO: Adding NormalVector " << runner->second->NormalVector << " of triangle " << *(runner->second) << "." << endl;
1951 BaseLineNormal.AddVector(&(runner->second->NormalVector));
1952 }
1953 BaseLineNormal.Scale(-1./2.); // has to point inside for BoundaryTriangleSet::GetNormalVector()
1954
1955 // get the two triangles
1956 // gather four endpoints and four lines
1957 for (int j=0;j<4;j++)
1958 OldLines[j] = NULL;
1959 for (int j=0;j<2;j++)
1960 OldPoints[j] = NULL;
1961 i=0;
1962 m=0;
1963 *out << Verbose(3) << "The four old lines are: ";
1964 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1965 for (int j=0;j<3;j++) // all of their endpoints and baselines
1966 if (runner->second->lines[j] != Base) { // pick not the central baseline
1967 OldLines[i++] = runner->second->lines[j];
1968 *out << *runner->second->lines[j] << "\t";
1969 }
1970 *out << endl;
1971 *out << Verbose(3) << "The two old points are: ";
1972 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1973 for (int j=0;j<3;j++) // all of their endpoints and baselines
1974 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) { // and neither of its endpoints
1975 OldPoints[m++] = runner->second->endpoints[j];
1976 *out << *runner->second->endpoints[j] << "\t";
1977 }
1978 *out << endl;
1979
1980 // check whether everything is in place to create new lines and triangles
1981 if (i<4) {
1982 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
1983 return false;
1984 }
1985 for (int j=0;j<4;j++)
1986 if (OldLines[j] == NULL) {
1987 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
1988 return false;
1989 }
1990 for (int j=0;j<2;j++)
1991 if (OldPoints[j] == NULL) {
1992 *out << Verbose(1) << "ERROR: We have not gathered enough endpoints!" << endl;
1993 return false;
1994 }
1995
1996 // remove triangles and baseline removes itself
1997 *out << Verbose(3) << "INFO: Deleting baseline " << *Base << " from global list." << endl;
1998 OldBaseLineNr = Base->Nr;
1999 m=0;
2000 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
2001 *out << Verbose(3) << "INFO: Deleting triangle " << *(runner->second) << "." << endl;
2002 OldTriangleNrs[m++] = runner->second->Nr;
2003 RemoveTesselationTriangle(runner->second);
2004 }
2005
2006 // construct new baseline (with same number as old one)
2007 BPS[0] = OldPoints[0];
2008 BPS[1] = OldPoints[1];
2009 NewLine = new class BoundaryLineSet(BPS, OldBaseLineNr);
2010 LinesOnBoundary.insert(LinePair(OldBaseLineNr, NewLine)); // no need for check for unique insertion as NewLine is definitely a new one
2011 *out << Verbose(3) << "INFO: Created new baseline " << *NewLine << "." << endl;
2012
2013 // construct new triangles with flipped baseline
2014 i=-1;
2015 if (OldLines[0]->IsConnectedTo(OldLines[2]))
2016 i=2;
2017 if (OldLines[0]->IsConnectedTo(OldLines[3]))
2018 i=3;
2019 if (i!=-1) {
2020 BLS[0] = OldLines[0];
2021 BLS[1] = OldLines[i];
2022 BLS[2] = NewLine;
2023 BTS = new class BoundaryTriangleSet(BLS, OldTriangleNrs[0]);
2024 BTS->GetNormalVector(BaseLineNormal);
2025 TrianglesOnBoundary.insert(TrianglePair(OldTriangleNrs[0], BTS));
2026 *out << Verbose(3) << "INFO: Created new triangle " << *BTS << "." << endl;
2027
2028 BLS[0] = (i==2 ? OldLines[3] : OldLines[2]);
2029 BLS[1] = OldLines[1];
2030 BLS[2] = NewLine;
2031 BTS = new class BoundaryTriangleSet(BLS, OldTriangleNrs[1]);
2032 BTS->GetNormalVector(BaseLineNormal);
2033 TrianglesOnBoundary.insert(TrianglePair(OldTriangleNrs[1], BTS));
2034 *out << Verbose(3) << "INFO: Created new triangle " << *BTS << "." << endl;
2035 } else {
2036 *out << Verbose(1) << "The four old lines do not connect, something's utterly wrong here!" << endl;
2037 return false;
2038 }
2039
2040 *out << Verbose(1) << "End of FlipBaseline" << endl;
2041 return true;
2042};
2043
2044
2045/** Finds the second point of starting triangle.
2046 * \param *a first node
2047 * \param *Candidate pointer to candidate node on return
2048 * \param Oben vector indicating the outside
2049 * \param OptCandidate reference to recommended candidate on return
2050 * \param Storage[3] array storing angles and other candidate information
2051 * \param RADIUS radius of virtual sphere
2052 * \param *LC LinkedCell structure with neighbouring points
2053 */
2054void Tesselation::FindSecondPointForTesselation(TesselPoint* a, TesselPoint* Candidate, Vector Oben, TesselPoint*& OptCandidate, double Storage[3], double RADIUS, LinkedCell *LC)
2055{
2056 cout << Verbose(2) << "Begin of FindSecondPointForTesselation" << endl;
2057 Vector AngleCheck;
2058 double norm = -1., angle;
2059 LinkedNodes *List = NULL;
2060 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2061
2062 if (LC->SetIndexToNode(a)) { // get cell for the starting point
2063 for(int i=0;i<NDIM;i++) // store indices of this cell
2064 N[i] = LC->n[i];
2065 } else {
2066 cerr << "ERROR: Point " << *a << " is not found in cell " << LC->index << "." << endl;
2067 return;
2068 }
2069 // then go through the current and all neighbouring cells and check the contained points for possible candidates
2070 cout << Verbose(3) << "LC Intervals from [";
2071 for (int i=0;i<NDIM;i++) {
2072 cout << " " << N[i] << "<->" << LC->N[i];
2073 }
2074 cout << "] :";
2075 for (int i=0;i<NDIM;i++) {
2076 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
2077 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
2078 cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
2079 }
2080 cout << endl;
2081
2082
2083 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2084 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2085 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2086 List = LC->GetCurrentCell();
2087 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
2088 if (List != NULL) {
2089 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2090 Candidate = (*Runner);
2091 // check if we only have one unique point yet ...
2092 if (a != Candidate) {
2093 // Calculate center of the circle with radius RADIUS through points a and Candidate
2094 Vector OrthogonalizedOben, aCandidate, Center;
2095 double distance, scaleFactor;
2096
2097 OrthogonalizedOben.CopyVector(&Oben);
2098 aCandidate.CopyVector(a->node);
2099 aCandidate.SubtractVector(Candidate->node);
2100 OrthogonalizedOben.ProjectOntoPlane(&aCandidate);
2101 OrthogonalizedOben.Normalize();
2102 distance = 0.5 * aCandidate.Norm();
2103 scaleFactor = sqrt(((RADIUS * RADIUS) - (distance * distance)));
2104 OrthogonalizedOben.Scale(scaleFactor);
2105
2106 Center.CopyVector(Candidate->node);
2107 Center.AddVector(a->node);
2108 Center.Scale(0.5);
2109 Center.AddVector(&OrthogonalizedOben);
2110
2111 AngleCheck.CopyVector(&Center);
2112 AngleCheck.SubtractVector(a->node);
2113 norm = aCandidate.Norm();
2114 // second point shall have smallest angle with respect to Oben vector
2115 if (norm < RADIUS*2.) {
2116 angle = AngleCheck.Angle(&Oben);
2117 if (angle < Storage[0]) {
2118 //cout << Verbose(3) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
2119 cout << Verbose(3) << "Current candidate is " << *Candidate << ": Is a better candidate with distance " << norm << " and angle " << angle << " to oben " << Oben << ".\n";
2120 OptCandidate = Candidate;
2121 Storage[0] = angle;
2122 //cout << Verbose(3) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
2123 } else {
2124 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Looses with angle " << angle << " to a better candidate " << *OptCandidate << endl;
2125 }
2126 } else {
2127 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Refused due to Radius " << norm << endl;
2128 }
2129 } else {
2130 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Candidate is equal to first endpoint." << *a << "." << endl;
2131 }
2132 }
2133 } else {
2134 cout << Verbose(3) << "Linked cell list is empty." << endl;
2135 }
2136 }
2137 cout << Verbose(2) << "End of FindSecondPointForTesselation" << endl;
2138};
2139
2140
2141/** This recursive function finds a third point, to form a triangle with two given ones.
2142 * Note that this function is for the starting triangle.
2143 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points
2144 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then
2145 * the center of the sphere is still fixed up to a single parameter. The band of possible values
2146 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives
2147 * us the "null" on this circle, the new center of the candidate point will be some way along this
2148 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given
2149 * by the normal vector of the base triangle that always points outwards by construction.
2150 * Hence, we construct a Center of this circle which sits right in the middle of the current base line.
2151 * We construct the normal vector that defines the plane this circle lies in, it is just in the
2152 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest
2153 * with respect to the length of the baseline and the sphere's fixed \a RADIUS.
2154 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center
2155 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check
2156 * both.
2157 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check
2158 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check
2159 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal
2160 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality
2161 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether
2162 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI).
2163 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa FindStartingTriangle())
2164 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine
2165 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle
2166 * @param BaseLine BoundaryLineSet with the current base line
2167 * @param ThirdNode third point to avoid in search
2168 * @param candidates list of equally good candidates to return
2169 * @param ShortestAngle the current path length on this circle band for the current OptCandidate
2170 * @param RADIUS radius of sphere
2171 * @param *LC LinkedCell structure with neighbouring points
2172 */
2173void Tesselation::FindThirdPointForTesselation(Vector NormalVector, Vector SearchDirection, Vector OldSphereCenter, class BoundaryLineSet *BaseLine, class TesselPoint *ThirdNode, CandidateList* &candidates, double *ShortestAngle, const double RADIUS, LinkedCell *LC)
2174{
2175 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers
2176 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
2177 Vector SphereCenter;
2178 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility
2179 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility
2180 Vector NewNormalVector; // normal vector of the Candidate's triangle
2181 Vector helper, OptCandidateCenter, OtherOptCandidateCenter;
2182 LinkedNodes *List = NULL;
2183 double CircleRadius; // radius of this circle
2184 double radius;
2185 double alpha, Otheralpha; // angles (i.e. parameter for the circle).
2186 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2187 TesselPoint *Candidate = NULL;
2188 CandidateForTesselation *optCandidate = NULL;
2189
2190 cout << Verbose(1) << "Begin of FindThirdPointForTesselation" << endl;
2191
2192 //cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
2193
2194 // construct center of circle
2195 CircleCenter.CopyVector(BaseLine->endpoints[0]->node->node);
2196 CircleCenter.AddVector(BaseLine->endpoints[1]->node->node);
2197 CircleCenter.Scale(0.5);
2198
2199 // construct normal vector of circle
2200 CirclePlaneNormal.CopyVector(BaseLine->endpoints[0]->node->node);
2201 CirclePlaneNormal.SubtractVector(BaseLine->endpoints[1]->node->node);
2202
2203 // calculate squared radius TesselPoint *ThirdNode,f circle
2204 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
2205 if (radius/4. < RADIUS*RADIUS) {
2206 CircleRadius = RADIUS*RADIUS - radius/4.;
2207 CirclePlaneNormal.Normalize();
2208 //cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
2209
2210 // test whether old center is on the band's plane
2211 if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
2212 cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
2213 OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal);
2214 }
2215 radius = OldSphereCenter.ScalarProduct(&OldSphereCenter);
2216 if (fabs(radius - CircleRadius) < HULLEPSILON) {
2217
2218 // check SearchDirection
2219 //cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
2220 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way!
2221 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl;
2222 }
2223
2224 // get cell for the starting point
2225 if (LC->SetIndexToVector(&CircleCenter)) {
2226 for(int i=0;i<NDIM;i++) // store indices of this cell
2227 N[i] = LC->n[i];
2228 //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2229 } else {
2230 cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl;
2231 return;
2232 }
2233 // then go through the current and all neighbouring cells and check the contained points for possible candidates
2234 //cout << Verbose(2) << "LC Intervals:";
2235 for (int i=0;i<NDIM;i++) {
2236 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
2237 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
2238 //cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
2239 }
2240 //cout << endl;
2241 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2242 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2243 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2244 List = LC->GetCurrentCell();
2245 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
2246 if (List != NULL) {
2247 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2248 Candidate = (*Runner);
2249
2250 // check for three unique points
2251 //cout << Verbose(2) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->node << "." << endl;
2252 if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) ){
2253
2254 // construct both new centers
2255 GetCenterofCircumcircle(&NewSphereCenter, BaseLine->endpoints[0]->node->node, BaseLine->endpoints[1]->node->node, Candidate->node);
2256 OtherNewSphereCenter.CopyVector(&NewSphereCenter);
2257
2258 if ((NewNormalVector.MakeNormalVector(BaseLine->endpoints[0]->node->node, BaseLine->endpoints[1]->node->node, Candidate->node))
2259 && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)
2260 ) {
2261 helper.CopyVector(&NewNormalVector);
2262 //cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl;
2263 radius = BaseLine->endpoints[0]->node->node->DistanceSquared(&NewSphereCenter);
2264 if (radius < RADIUS*RADIUS) {
2265 helper.Scale(sqrt(RADIUS*RADIUS - radius));
2266 //cout << Verbose(2) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << " with sphere radius " << RADIUS << "." << endl;
2267 NewSphereCenter.AddVector(&helper);
2268 NewSphereCenter.SubtractVector(&CircleCenter);
2269 //cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl;
2270
2271 // OtherNewSphereCenter is created by the same vector just in the other direction
2272 helper.Scale(-1.);
2273 OtherNewSphereCenter.AddVector(&helper);
2274 OtherNewSphereCenter.SubtractVector(&CircleCenter);
2275 //cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl;
2276
2277 alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
2278 Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
2279 alpha = min(alpha, Otheralpha);
2280 // if there is a better candidate, drop the current list and add the new candidate
2281 // otherwise ignore the new candidate and keep the list
2282 if (*ShortestAngle > (alpha - HULLEPSILON)) {
2283 optCandidate = new CandidateForTesselation(Candidate, BaseLine, OptCandidateCenter, OtherOptCandidateCenter);
2284 if (fabs(alpha - Otheralpha) > MYEPSILON) {
2285 optCandidate->OptCenter.CopyVector(&NewSphereCenter);
2286 optCandidate->OtherOptCenter.CopyVector(&OtherNewSphereCenter);
2287 } else {
2288 optCandidate->OptCenter.CopyVector(&OtherNewSphereCenter);
2289 optCandidate->OtherOptCenter.CopyVector(&NewSphereCenter);
2290 }
2291 // if there is an equal candidate, add it to the list without clearing the list
2292 if ((*ShortestAngle - HULLEPSILON) < alpha) {
2293 candidates->push_back(optCandidate);
2294 cout << Verbose(2) << "ACCEPT: We have found an equally good candidate: " << *(optCandidate->point) << " with "
2295 << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
2296 } else {
2297 // remove all candidates from the list and then the list itself
2298 class CandidateForTesselation *remover = NULL;
2299 for (CandidateList::iterator it = candidates->begin(); it != candidates->end(); ++it) {
2300 remover = *it;
2301 delete(remover);
2302 }
2303 candidates->clear();
2304 candidates->push_back(optCandidate);
2305 cout << Verbose(2) << "ACCEPT: We have found a better candidate: " << *(optCandidate->point) << " with "
2306 << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
2307 }
2308 *ShortestAngle = alpha;
2309 //cout << Verbose(2) << "INFO: There are " << candidates->size() << " candidates in the list now." << endl;
2310 } else {
2311 if ((optCandidate != NULL) && (optCandidate->point != NULL)) {
2312 //cout << Verbose(2) << "REJECT: Old candidate " << *(optCandidate->point) << " with " << *ShortestAngle << " is better than new one " << *Candidate << " with " << alpha << " ." << endl;
2313 } else {
2314 //cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl;
2315 }
2316 }
2317
2318 } else {
2319 //cout << Verbose(2) << "REJECT: NewSphereCenter " << NewSphereCenter << " for " << *Candidate << " is too far away: " << radius << "." << endl;
2320 }
2321 } else {
2322 //cout << Verbose(2) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl;
2323 }
2324 } else {
2325 if (ThirdNode != NULL) {
2326 //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl;
2327 } else {
2328 //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl;
2329 }
2330 }
2331 }
2332 }
2333 }
2334 } else {
2335 cerr << Verbose(2) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
2336 }
2337 } else {
2338 if (ThirdNode != NULL)
2339 cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl;
2340 else
2341 cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl;
2342 }
2343
2344 //cout << Verbose(2) << "INFO: Sorting candidate list ..." << endl;
2345 if (candidates->size() > 1) {
2346 candidates->unique();
2347 candidates->sort(SortCandidates);
2348 }
2349
2350 cout << Verbose(1) << "End of FindThirdPointForTesselation" << endl;
2351};
2352
2353/** Finds the endpoint two lines are sharing.
2354 * \param *line1 first line
2355 * \param *line2 second line
2356 * \return point which is shared or NULL if none
2357 */
2358class BoundaryPointSet *Tesselation::GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
2359{
2360 class BoundaryLineSet * lines[2] =
2361 { line1, line2 };
2362 class BoundaryPointSet *node = NULL;
2363 map<int, class BoundaryPointSet *> OrderMap;
2364 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
2365 for (int i = 0; i < 2; i++)
2366 // for both lines
2367 for (int j = 0; j < 2; j++)
2368 { // for both endpoints
2369 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
2370 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
2371 if (!OrderTest.second)
2372 { // if insertion fails, we have common endpoint
2373 node = OrderTest.first->second;
2374 cout << Verbose(5) << "Common endpoint of lines " << *line1
2375 << " and " << *line2 << " is: " << *node << "." << endl;
2376 j = 2;
2377 i = 2;
2378 break;
2379 }
2380 }
2381 return node;
2382};
2383
2384/** Finds the triangle that is closest to a given Vector \a *x.
2385 * \param *out output stream for debugging
2386 * \param *x Vector to look from
2387 * \return list of BoundaryTriangleSet of nearest triangles or NULL in degenerate case.
2388 */
2389list<BoundaryTriangleSet*> * Tesselation::FindClosestTrianglesToPoint(ofstream *out, Vector *x, LinkedCell* LC)
2390{
2391 TesselPoint *trianglePoints[3];
2392 TesselPoint *SecondPoint = NULL;
2393
2394 if (LinesOnBoundary.empty()) {
2395 *out << Verbose(0) << "Error: There is no tesselation structure to compare the point with, please create one first.";
2396 return NULL;
2397 }
2398
2399 trianglePoints[0] = FindClosestPoint(x, SecondPoint, LC);
2400
2401 // check whether closest point is "too close" :), then it's inside
2402 if (trianglePoints[0] == NULL) {
2403 *out << Verbose(1) << "Is the only point, no one else is closeby." << endl;
2404 return NULL;
2405 }
2406 if (trianglePoints[0]->node->DistanceSquared(x) < MYEPSILON) {
2407 *out << Verbose(1) << "Point is right on a tesselation point, no nearest triangle." << endl;
2408 return NULL;
2409 }
2410 list<TesselPoint*> *connectedPoints = GetCircleOfConnectedPoints(out, trianglePoints[0]);
2411 list<TesselPoint*> *connectedClosestPoints = GetNeighboursOnCircleOfConnectedPoints(out, connectedPoints, trianglePoints[0], x);
2412 delete(connectedPoints);
2413 trianglePoints[1] = connectedClosestPoints->front();
2414 trianglePoints[2] = connectedClosestPoints->back();
2415 for (int i=0;i<3;i++) {
2416 if (trianglePoints[i] == NULL) {
2417 *out << Verbose(1) << "IsInnerPoint encounters serious error, point " << i << " not found." << endl;
2418 }
2419 //*out << Verbose(1) << "List of possible points:" << endl;
2420 //*out << Verbose(2) << *trianglePoints[i] << endl;
2421 }
2422
2423 list<BoundaryTriangleSet*> *triangles = FindTriangles(trianglePoints);
2424
2425 delete(connectedClosestPoints);
2426
2427 if (triangles->empty()) {
2428 *out << Verbose(0) << "Error: There is no nearest triangle. Please check the tesselation structure.";
2429 return NULL;
2430 } else
2431 return triangles;
2432};
2433
2434/** Finds closest triangle to a point.
2435 * This basically just takes care of the degenerate case, which is not handled in FindClosestTrianglesToPoint().
2436 * \param *out output stream for debugging
2437 * \param *x Vector to look from
2438 * \return list of BoundaryTriangleSet of nearest triangles or NULL.
2439 */
2440class BoundaryTriangleSet * Tesselation::FindClosestTriangleToPoint(ofstream *out, Vector *x, LinkedCell* LC)
2441{
2442 class BoundaryTriangleSet *result = NULL;
2443 list<BoundaryTriangleSet*> *triangles = FindClosestTrianglesToPoint(out, x, LC);
2444
2445 if (triangles == NULL)
2446 return NULL;
2447
2448 if (x->ScalarProduct(&triangles->front()->NormalVector) < 0)
2449 result = triangles->back();
2450 else
2451 result = triangles->front();
2452
2453 delete(triangles);
2454 return result;
2455};
2456
2457/** Checks whether the provided Vector is within the tesselation structure.
2458 *
2459 * @param point of which to check the position
2460 * @param *LC LinkedCell structure
2461 *
2462 * @return true if the point is inside the tesselation structure, false otherwise
2463 */
2464bool Tesselation::IsInnerPoint(ofstream *out, Vector Point, LinkedCell* LC)
2465{
2466 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, &Point, LC);
2467 if (result == NULL)
2468 return true;
2469 if (Point.ScalarProduct(&result->NormalVector) < 0)
2470 return true;
2471 else
2472 return false;
2473}
2474
2475/** Checks whether the provided TesselPoint is within the tesselation structure.
2476 *
2477 * @param *Point of which to check the position
2478 * @param *LC Linked Cell structure
2479 *
2480 * @return true if the point is inside the tesselation structure, false otherwise
2481 */
2482bool Tesselation::IsInnerPoint(ofstream *out, TesselPoint *Point, LinkedCell* LC)
2483{
2484 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, Point->node, LC);
2485 if (result == NULL)
2486 return true;
2487 if (Point->node->ScalarProduct(&result->NormalVector) < 0)
2488 return true;
2489 else
2490 return false;
2491}
2492
2493/** Gets all points connected to the provided point by triangulation lines.
2494 *
2495 * @param *Point of which get all connected points
2496 *
2497 * @return list of the all points linked to the provided one
2498 */
2499list<TesselPoint*> * Tesselation::GetCircleOfConnectedPoints(ofstream *out, TesselPoint* Point)
2500{
2501 list<TesselPoint*> *connectedPoints = new list<TesselPoint*>;
2502 class BoundaryPointSet *ReferencePoint = NULL;
2503 TesselPoint* current;
2504 bool takePoint = false;
2505
2506 // find the respective boundary point
2507 PointMap::iterator PointRunner = PointsOnBoundary.find(Point->nr);
2508 if (PointRunner != PointsOnBoundary.end()) {
2509 ReferencePoint = PointRunner->second;
2510 } else {
2511 *out << Verbose(2) << "getCircleOfConnectedPoints() could not find the BoundaryPoint belonging to " << *Point << "." << endl;
2512 ReferencePoint = NULL;
2513 }
2514
2515 // little trick so that we look just through lines connect to the BoundaryPoint
2516 // OR fall-back to look through all lines if there is no such BoundaryPoint
2517 LineMap *Lines = &LinesOnBoundary;
2518 if (ReferencePoint != NULL)
2519 Lines = &(ReferencePoint->lines);
2520 LineMap::iterator findLines = Lines->begin();
2521 while (findLines != Lines->end()) {
2522 takePoint = false;
2523
2524 if (findLines->second->endpoints[0]->Nr == Point->nr) {
2525 takePoint = true;
2526 current = findLines->second->endpoints[1]->node;
2527 } else if (findLines->second->endpoints[1]->Nr == Point->nr) {
2528 takePoint = true;
2529 current = findLines->second->endpoints[0]->node;
2530 }
2531
2532 if (takePoint) {
2533 *out << Verbose(3) << "INFO: Endpoint " << *current << " of line " << *(findLines->second) << " is taken into the circle." << endl;
2534 connectedPoints->push_back(current);
2535 }
2536
2537 findLines++;
2538 }
2539
2540 if (connectedPoints->size() == 0) { // if have not found any points
2541 *out << Verbose(1) << "ERROR: We have not found any connected points to " << *Point<< "." << endl;
2542 return NULL;
2543 }
2544 return connectedPoints;
2545}
2546
2547/** Gets the two neighbouring points with respect to a reference line to the provided point.
2548 * Maps them down onto the plane designated by the axis \a *Point and \a *Reference. The center of all points
2549 * connected in the tesselation to \a *Point is mapped to spherical coordinates with the zero angle being given
2550 * by the mapped down \a *Reference. Hence, the biggest and the smallest angles are those of the two shanks of the
2551 * triangle we are looking for.
2552 *
2553 * @param *out output stream for debugging
2554 * @param *connectedPoints list of connected points to the central \a *Point
2555 * @param *Point of which get all connected points
2556 * @param *Reference Vector to be checked whether it is an inner point
2557 *
2558 * @return list of the two points linked to the provided one and closest to the point to be checked,
2559 */
2560list<TesselPoint*> * Tesselation::GetNeighboursOnCircleOfConnectedPoints(ofstream *out, list<TesselPoint*> *connectedPoints, TesselPoint* Point, Vector* Reference)
2561{
2562 map<double, TesselPoint*> anglesOfPoints;
2563 map<double, TesselPoint*>::iterator runner;
2564 ;
2565 Vector center, PlaneNormal, OrthogonalVector, helper, AngleZero;
2566
2567 if (connectedPoints->size() == 0) { // if have not found any points
2568 *out << Verbose(1) << "ERROR: We have not found any connected points to " << *Point<< "." << endl;
2569 return NULL;
2570 }
2571
2572 // calculate central point
2573 for (list<TesselPoint*>::iterator TesselRunner = connectedPoints->begin(); TesselRunner != connectedPoints->end(); TesselRunner++)
2574 center.AddVector((*TesselRunner)->node);
2575 //*out << "Summed vectors " << center << "; number of points " << connectedPoints.size()
2576 // << "; scale factor " << 1.0/connectedPoints.size();
2577 center.Scale(1.0/connectedPoints->size());
2578 *out << Verbose(4) << "INFO: Calculated center of all circle points is " << center << "." << endl;
2579
2580 // projection plane of the circle is at the closes Point and normal is pointing away from center of all circle points
2581 PlaneNormal.CopyVector(Point->node);
2582 PlaneNormal.SubtractVector(&center);
2583 PlaneNormal.Normalize();
2584 *out << Verbose(4) << "INFO: Calculated plane normal of circle is " << PlaneNormal << "." << endl;
2585
2586 // construct one orthogonal vector
2587 AngleZero.CopyVector(Reference);
2588 AngleZero.SubtractVector(Point->node);
2589 AngleZero.ProjectOntoPlane(&PlaneNormal);
2590 *out << Verbose(4) << "INFO: Reference vector on this plane representing angle 0 is " << AngleZero << "." << endl;
2591 OrthogonalVector.MakeNormalVector(&PlaneNormal, &AngleZero);
2592 *out << Verbose(4) << "INFO: OrthogonalVector on plane is " << OrthogonalVector << "." << endl;
2593
2594 // go through all connected points and calculate angle
2595 for (list<TesselPoint*>::iterator listRunner = connectedPoints->begin(); listRunner != connectedPoints->end(); listRunner++) {
2596 helper.CopyVector((*listRunner)->node);
2597 helper.SubtractVector(Point->node);
2598 helper.ProjectOntoPlane(&PlaneNormal);
2599 double angle = GetAngle(helper, AngleZero, OrthogonalVector);
2600 *out << Verbose(2) << "INFO: Calculated angle is " << angle << " for point " << **listRunner << "." << endl;
2601 anglesOfPoints.insert(pair<double, TesselPoint*>(angle, (*listRunner)));
2602 }
2603
2604 list<TesselPoint*> *result = new list<TesselPoint*>;
2605 runner = anglesOfPoints.begin();
2606 result->push_back(runner->second);
2607 runner = anglesOfPoints.end();
2608 runner--;
2609 result->push_back(runner->second);
2610
2611 *out << Verbose(2) << "List of closest points has " << result->size() << " elements, which are "
2612 << *(result->front()) << " and " << *(result->back()) << endl;
2613
2614 return result;
2615}
2616
2617/** Removes a boundary point from the envelope while keeping it closed.
2618 * We create new triangles and remove the old ones connected to the point.
2619 * \param *out output stream for debugging
2620 * \param *point point to be removed
2621 * \return volume added to the volume inside the tesselated surface by the removal
2622 */
2623double Tesselation::RemovePointFromTesselatedSurface(ofstream *out, class BoundaryPointSet *point) {
2624 class BoundaryLineSet *line = NULL;
2625 class BoundaryTriangleSet *triangle = NULL;
2626 Vector OldPoint, TetraederVector[3];
2627 double volume = 0;
2628 int *numbers = NULL;
2629 int count = 0;
2630 int i;
2631
2632 if (point == NULL) {
2633 *out << Verbose(1) << "ERROR: Cannot remove the point " << point << ", it's NULL!" << endl;
2634 return 0.;
2635 } else
2636 *out << Verbose(2) << "Removing point " << *point << " from tesselated boundary ..." << endl;
2637
2638 // copy old location for the volume
2639 OldPoint.CopyVector(point->node->node);
2640
2641 // get list of connected points
2642 if (point->lines.empty()) {
2643 *out << Verbose(1) << "ERROR: Cannot remove the point " << *point << ", it's connected to no lines!" << endl;
2644 return 0.;
2645 }
2646 list<TesselPoint*> *CircleofPoints = GetCircleOfConnectedPoints(out, point->node);
2647
2648 // remove all triangles
2649 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++)
2650 count+=LineRunner->second->triangles.size();
2651 numbers = new int[count];
2652 class BoundaryTriangleSet **Candidates = new BoundaryTriangleSet*[count];
2653 i=0;
2654 for (LineMap::iterator LineRunner = point->lines.begin(); (point != NULL) && (LineRunner != point->lines.end()); LineRunner++) {
2655 line = LineRunner->second;
2656 for (TriangleMap::iterator TriangleRunner = line->triangles.begin(); TriangleRunner != line->triangles.end(); TriangleRunner++) {
2657 triangle = TriangleRunner->second;
2658 Candidates[i] = triangle;
2659 numbers[i++] = triangle->Nr;
2660 }
2661 }
2662 for (int j=0;j<i;j++) {
2663 RemoveTesselationTriangle(Candidates[j]);
2664 }
2665 delete[](Candidates);
2666 *out << Verbose(1) << i << " triangles were removed." << endl;
2667
2668 // re-create all triangles by going through connected points list
2669 list<TesselPoint*>::iterator CircleRunner = CircleofPoints->begin();
2670 list<TesselPoint*>::iterator OtherCircleRunner = CircleofPoints->begin();
2671 class TesselPoint *CentralNode = *CircleRunner;
2672 // advance two with CircleRunner and one with OtherCircleRunner
2673 CircleRunner++;
2674 CircleRunner++;
2675 OtherCircleRunner++;
2676 i=0;
2677 cout << Verbose(2) << "INFO: CentralNode is " << *CentralNode << "." << endl;
2678 for (; (OtherCircleRunner != CircleofPoints->end()) && (CircleRunner != CircleofPoints->end()); (CircleRunner++), (OtherCircleRunner++)) {
2679 cout << Verbose(3) << "INFO: CircleRunner's node is " << **CircleRunner << "." << endl;
2680 cout << Verbose(3) << "INFO: OtherCircleRunner's node is " << **OtherCircleRunner << "." << endl;
2681 *out << Verbose(4) << "Adding new triangle points."<< endl;
2682 AddTesselationPoint(CentralNode, 0);
2683 AddTesselationPoint(*OtherCircleRunner, 1);
2684 AddTesselationPoint(*CircleRunner, 2);
2685 *out << Verbose(4) << "Adding new triangle lines."<< endl;
2686 AddTesselationLine(TPS[0], TPS[1], 0);
2687 AddTesselationLine(TPS[0], TPS[2], 1);
2688 AddTesselationLine(TPS[1], TPS[2], 2);
2689 BTS = new class BoundaryTriangleSet(BLS, numbers[i]);
2690 TrianglesOnBoundary.insert(TrianglePair(numbers[i], BTS));
2691 *out << Verbose(4) << "Created triangle " << *BTS << "." << endl;
2692 // calculate volume summand as a general tetraeder
2693 for (int j=0;j<3;j++) {
2694 TetraederVector[j].CopyVector(TPS[j]->node->node);
2695 TetraederVector[j].SubtractVector(&OldPoint);
2696 }
2697 OldPoint.CopyVector(&TetraederVector[0]);
2698 OldPoint.VectorProduct(&TetraederVector[1]);
2699 volume += 1./6. * fabs(OldPoint.ScalarProduct(&TetraederVector[2]));
2700 // advance number
2701 i++;
2702 if (i >= count)
2703 *out << Verbose(2) << "WARNING: Maximum of numbers reached!" << endl;
2704 }
2705 *out << Verbose(1) << i << " triangles were created." << endl;
2706
2707 delete[](numbers);
2708
2709 return volume;
2710};
2711
2712/** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
2713 * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
2714 * make it bigger (i.e. closing one (the baseline) and opening two new ones).
2715 * \param TPS[3] nodes of the triangle
2716 * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
2717 */
2718bool CheckLineCriteriaForDegeneratedTriangle(class BoundaryPointSet *nodes[3])
2719{
2720 bool result = false;
2721 int counter = 0;
2722
2723 // check all three points
2724 for (int i=0;i<3;i++)
2725 for (int j=i+1; j<3; j++) {
2726 if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) { // there already is a line
2727 LineMap::iterator FindLine;
2728 pair<LineMap::iterator,LineMap::iterator> FindPair;
2729 FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
2730 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
2731 // If there is a line with less than two attached triangles, we don't need a new line.
2732 if (FindLine->second->triangles.size() < 2) {
2733 counter++;
2734 break; // increase counter only once per edge
2735 }
2736 }
2737 } else { // no line
2738 cout << Verbose(1) << "The line between " << nodes[i] << " and " << nodes[j] << " is not yet present, hence no need for a degenerate triangle." << endl;
2739 result = true;
2740 }
2741 }
2742 if (counter > 1) {
2743 cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
2744 result = true;
2745 }
2746 return result;
2747};
2748
2749
2750/** Sort function for the candidate list.
2751 */
2752bool SortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2)
2753{
2754 Vector BaseLineVector, OrthogonalVector, helper;
2755 if (candidate1->BaseLine != candidate2->BaseLine) { // sanity check
2756 cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
2757 //return false;
2758 exit(1);
2759 }
2760 // create baseline vector
2761 BaseLineVector.CopyVector(candidate1->BaseLine->endpoints[1]->node->node);
2762 BaseLineVector.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2763 BaseLineVector.Normalize();
2764
2765 // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!)
2766 helper.CopyVector(candidate1->BaseLine->endpoints[0]->node->node);
2767 helper.SubtractVector(candidate1->point->node);
2768 OrthogonalVector.CopyVector(&helper);
2769 helper.VectorProduct(&BaseLineVector);
2770 OrthogonalVector.SubtractVector(&helper);
2771 OrthogonalVector.Normalize();
2772
2773 // calculate both angles and correct with in-plane vector
2774 helper.CopyVector(candidate1->point->node);
2775 helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2776 double phi = BaseLineVector.Angle(&helper);
2777 if (OrthogonalVector.ScalarProduct(&helper) > 0) {
2778 phi = 2.*M_PI - phi;
2779 }
2780 helper.CopyVector(candidate2->point->node);
2781 helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2782 double psi = BaseLineVector.Angle(&helper);
2783 if (OrthogonalVector.ScalarProduct(&helper) > 0) {
2784 psi = 2.*M_PI - psi;
2785 }
2786
2787 cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
2788 cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
2789
2790 // return comparison
2791 return phi < psi;
2792};
2793
2794/**
2795 * Finds the point which is second closest to the provided one.
2796 *
2797 * @param Point to which to find the second closest other point
2798 * @param linked cell structure
2799 *
2800 * @return point which is second closest to the provided one
2801 */
2802TesselPoint* FindSecondClosestPoint(const Vector* Point, LinkedCell* LC)
2803{
2804 LinkedNodes *List = NULL;
2805 TesselPoint* closestPoint = NULL;
2806 TesselPoint* secondClosestPoint = NULL;
2807 double distance = 1e16;
2808 double secondDistance = 1e16;
2809 Vector helper;
2810 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2811
2812 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
2813 for(int i=0;i<NDIM;i++) // store indices of this cell
2814 N[i] = LC->n[i];
2815 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2816
2817 LC->GetNeighbourBounds(Nlower, Nupper);
2818 //cout << endl;
2819 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2820 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2821 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2822 List = LC->GetCurrentCell();
2823 cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
2824 if (List != NULL) {
2825 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2826 helper.CopyVector(Point);
2827 helper.SubtractVector((*Runner)->node);
2828 double currentNorm = helper. Norm();
2829 if (currentNorm < distance) {
2830 // remember second point
2831 secondDistance = distance;
2832 secondClosestPoint = closestPoint;
2833 // mark down new closest point
2834 distance = currentNorm;
2835 closestPoint = (*Runner);
2836 cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
2837 }
2838 }
2839 } else {
2840 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
2841 << LC->n[2] << " is invalid!" << endl;
2842 }
2843 }
2844
2845 return secondClosestPoint;
2846};
2847
2848/**
2849 * Finds the point which is closest to the provided one.
2850 *
2851 * @param Point to which to find the closest other point
2852 * @param SecondPoint the second closest other point on return, NULL if none found
2853 * @param linked cell structure
2854 *
2855 * @return point which is closest to the provided one, NULL if none found
2856 */
2857TesselPoint* FindClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC)
2858{
2859 LinkedNodes *List = NULL;
2860 TesselPoint* closestPoint = NULL;
2861 SecondPoint = NULL;
2862 double distance = 1e16;
2863 double secondDistance = 1e16;
2864 Vector helper;
2865 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2866
2867 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
2868 for(int i=0;i<NDIM;i++) // store indices of this cell
2869 N[i] = LC->n[i];
2870 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2871
2872 LC->GetNeighbourBounds(Nlower, Nupper);
2873 //cout << endl;
2874 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2875 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2876 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2877 List = LC->GetCurrentCell();
2878 cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
2879 if (List != NULL) {
2880 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2881 helper.CopyVector(Point);
2882 helper.SubtractVector((*Runner)->node);
2883 double currentNorm = helper. Norm();
2884 if (currentNorm < distance) {
2885 secondDistance = distance;
2886 SecondPoint = closestPoint;
2887 distance = currentNorm;
2888 closestPoint = (*Runner);
2889 cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
2890 } else if (currentNorm < secondDistance) {
2891 secondDistance = currentNorm;
2892 SecondPoint = (*Runner);
2893 cout << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
2894 }
2895 }
2896 } else {
2897 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
2898 << LC->n[2] << " is invalid!" << endl;
2899 }
2900 }
2901
2902 return closestPoint;
2903};
2904
2905/**
2906 * Finds triangles belonging to the three provided points.
2907 *
2908 * @param *Points[3] list, is expected to contain three points
2909 *
2910 * @return triangles which belong to the provided points, will be empty if there are none,
2911 * will usually be one, in case of degeneration, there will be two
2912 */
2913list<BoundaryTriangleSet*> *Tesselation::FindTriangles(TesselPoint* Points[3])
2914{
2915 list<BoundaryTriangleSet*> *result = new list<BoundaryTriangleSet*>;
2916 LineMap::iterator FindLine;
2917 PointMap::iterator FindPoint;
2918 TriangleMap::iterator FindTriangle;
2919 class BoundaryPointSet *TrianglePoints[3];
2920
2921 for (int i = 0; i < 3; i++) {
2922 FindPoint = PointsOnBoundary.find(Points[i]->nr);
2923 if (FindPoint != PointsOnBoundary.end()) {
2924 TrianglePoints[i] = FindPoint->second;
2925 } else {
2926 TrianglePoints[i] = NULL;
2927 }
2928 }
2929
2930 // checks lines between the points in the Points for their adjacent triangles
2931 for (int i = 0; i < 3; i++) {
2932 if (TrianglePoints[i] != NULL) {
2933 for (int j = i; j < 3; j++) {
2934 if (TrianglePoints[j] != NULL) {
2935 FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr);
2936 if (FindLine != TrianglePoints[i]->lines.end()) {
2937 for (; FindLine->first == TrianglePoints[j]->node->nr; FindLine++) {
2938 FindTriangle = FindLine->second->triangles.begin();
2939 for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
2940 if ((
2941 (FindTriangle->second->endpoints[0] == TrianglePoints[0])
2942 || (FindTriangle->second->endpoints[0] == TrianglePoints[1])
2943 || (FindTriangle->second->endpoints[0] == TrianglePoints[2])
2944 ) && (
2945 (FindTriangle->second->endpoints[1] == TrianglePoints[0])
2946 || (FindTriangle->second->endpoints[1] == TrianglePoints[1])
2947 || (FindTriangle->second->endpoints[1] == TrianglePoints[2])
2948 ) && (
2949 (FindTriangle->second->endpoints[2] == TrianglePoints[0])
2950 || (FindTriangle->second->endpoints[2] == TrianglePoints[1])
2951 || (FindTriangle->second->endpoints[2] == TrianglePoints[2])
2952 )
2953 ) {
2954 result->push_back(FindTriangle->second);
2955 }
2956 }
2957 }
2958 // Is it sufficient to consider one of the triangle lines for this.
2959 return result;
2960
2961 }
2962 }
2963 }
2964 }
2965 }
2966
2967 return result;
2968}
2969
2970/**
2971 * Finds all degenerated triangles within the tesselation structure.
2972 *
2973 * @return map of keys of degenerated triangle pairs, each triangle occurs twice
2974 * in the list, once as key and once as value
2975 */
2976map<int, int> Tesselation::FindAllDegeneratedTriangles()
2977{
2978 map<int, int> DegeneratedTriangles;
2979
2980 // sanity check
2981 if (LinesOnBoundary.empty()) {
2982 cout << Verbose(1) << "Warning: FindAllDegeneratedTriangles() was called without any tesselation structure.";
2983 return DegeneratedTriangles;
2984 }
2985
2986 LineMap::iterator LineRunner1, LineRunner2;
2987
2988 for (LineRunner1 = LinesOnBoundary.begin(); LineRunner1 != LinesOnBoundary.end(); ++LineRunner1) {
2989 for (LineRunner2 = LinesOnBoundary.begin(); LineRunner2 != LinesOnBoundary.end(); ++LineRunner2) {
2990 if ((LineRunner1->second != LineRunner2->second)
2991 && (LineRunner1->second->endpoints[0] == LineRunner2->second->endpoints[0])
2992 && (LineRunner1->second->endpoints[1] == LineRunner2->second->endpoints[1])
2993 ) {
2994 TriangleMap::iterator TriangleRunner1 = LineRunner1->second->triangles.begin(),
2995 TriangleRunner2 = LineRunner2->second->triangles.begin();
2996
2997 for (; TriangleRunner1 != LineRunner1->second->triangles.end(); ++TriangleRunner1) {
2998 for (; TriangleRunner2 != LineRunner2->second->triangles.end(); ++TriangleRunner2) {
2999 if ((TriangleRunner1->second != TriangleRunner2->second)
3000 && (TriangleRunner1->second->endpoints[0] == TriangleRunner2->second->endpoints[0])
3001 && (TriangleRunner1->second->endpoints[1] == TriangleRunner2->second->endpoints[1])
3002 && (TriangleRunner1->second->endpoints[2] == TriangleRunner2->second->endpoints[2])
3003 ) {
3004 DegeneratedTriangles[TriangleRunner1->second->Nr] = TriangleRunner2->second->Nr;
3005 DegeneratedTriangles[TriangleRunner2->second->Nr] = TriangleRunner1->second->Nr;
3006 }
3007 }
3008 }
3009 }
3010 }
3011 }
3012
3013 cout << Verbose(1) << "FindAllDegeneratedTriangles() found " << DegeneratedTriangles.size() << " triangles." << endl;
3014 map<int,int>::iterator it;
3015 for (it = DegeneratedTriangles.begin(); it != DegeneratedTriangles.end(); it++)
3016 cout << Verbose(2) << (*it).first << " => " << (*it).second << endl;
3017
3018 return DegeneratedTriangles;
3019}
3020
3021/**
3022 * Purges degenerated triangles from the tesselation structure if they are not
3023 * necessary to keep a single point within the structure.
3024 */
3025void Tesselation::RemoveDegeneratedTriangles()
3026{
3027 map<int, int> DegeneratedTriangles = FindAllDegeneratedTriangles();
3028
3029 for (map<int, int>::iterator TriangleKeyRunner = DegeneratedTriangles.begin();
3030 TriangleKeyRunner != DegeneratedTriangles.end(); ++TriangleKeyRunner
3031 ) {
3032 BoundaryTriangleSet *triangle = TrianglesOnBoundary.find(TriangleKeyRunner->first)->second,
3033 *partnerTriangle = TrianglesOnBoundary.find(TriangleKeyRunner->second)->second;
3034
3035 bool trianglesShareLine = false;
3036 for (int i = 0; i < 3; ++i)
3037 for (int j = 0; j < 3; ++j)
3038 trianglesShareLine = trianglesShareLine || triangle->lines[i] == partnerTriangle->lines[j];
3039
3040 if (trianglesShareLine
3041 && (triangle->endpoints[1]->LinesCount > 2)
3042 && (triangle->endpoints[2]->LinesCount > 2)
3043 && (triangle->endpoints[0]->LinesCount > 2)
3044 ) {
3045 cout << Verbose(1) << "RemoveDegeneratedTriangles() removes triangle " << *triangle << "." << endl;
3046 RemoveTesselationTriangle(triangle);
3047 cout << Verbose(1) << "RemoveDegeneratedTriangles() removes triangle " << *partnerTriangle << "." << endl;
3048 RemoveTesselationTriangle(partnerTriangle);
3049 DegeneratedTriangles.erase(DegeneratedTriangles.find(partnerTriangle->Nr));
3050 } else {
3051 cout << Verbose(1) << "RemoveDegeneratedTriangles() does not remove triangle " << *triangle
3052 << " and its partner " << *partnerTriangle << " because it is essential for at"
3053 << " least one of the endpoints to be kept in the tesselation structure." << endl;
3054 }
3055 }
3056}
3057
3058/** Gets the angle between a point and a reference relative to the provided center.
3059 * We have two shanks point and reference between which the angle is calculated
3060 * and by scalar product with OrthogonalVector we decide the interval.
3061 * @param point to calculate the angle for
3062 * @param reference to which to calculate the angle
3063 * @param OrthogonalVector points in direction of [pi,2pi] interval
3064 *
3065 * @return angle between point and reference
3066 */
3067double GetAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector)
3068{
3069 if (reference.IsZero())
3070 return M_PI;
3071
3072 // calculate both angles and correct with in-plane vector
3073 if (point.IsZero())
3074 return M_PI;
3075 double phi = point.Angle(&reference);
3076 if (OrthogonalVector.ScalarProduct(&point) > 0) {
3077 phi = 2.*M_PI - phi;
3078 }
3079
3080 cout << Verbose(3) << "INFO: " << point << " has angle " << phi << " with respect to reference " << reference << "." << endl;
3081
3082 return phi;
3083}
3084
Note: See TracBrowser for help on using the repository browser.