source: src/tesselation.cpp@ 5417c5

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 5417c5 was 29812d, checked in by Saskia Metzler <metzler@…>, 16 years ago

Ticket 11: use templates and/or traits to fix Malloc/ReAlloc-Free warnings in a clean manner

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