source: src/tesselation.cpp@ f7f7a4

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 f7f7a4 was 065e82, checked in by Frederik Heber <heber@…>, 16 years ago

FIX: Tesselation::RemovePointFromTesselatedSurface() is working correctly now, heptan is de-tesselated without any memory leaks.

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