source: src/tesselation.cpp@ 70ff32

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 70ff32 was 6b919f8, checked in by Frederik Heber <heber@…>, 15 years ago

Refactored atom.cpp into multiple files.

After the class atom was refactored into multiple base classes that are inherited, these base classes are also all put into separate files. This is basically a preparatory step for the like-wise refactoring of class molecule into inherited base classes and splitting up (that is there done already). Finally, we will also separate the relations, i.e. not have "atom.hpp" included everywhere and use class atom, but rather the subclasses such as TrajectoryParticle and its header files only.
Signed-off-by: Frederik Heber <heber@…>

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