source: src/tesselation.cpp@ 71b20e

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 Candidate_v1.7.0 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 71b20e was 71b20e, checked in by Frederik Heber <heber@…>, 16 years ago

Attempt to fix the embedding.

Basically it would be working, but there was some failures with the FindClosestTriangleToPoint() routines.
We get triangles wrong if we start looking for the closest point. Actually, we should really look at each
triangle and check the distance. Now, we look at least at each line, but code is unfinished and crashes at the end
unexplainedly.

  • Property mode set to 100644
File size: 201.8 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 "info.hpp"
12#include "linkedcell.hpp"
13#include "log.hpp"
14#include "tesselation.hpp"
15#include "tesselationhelpers.hpp"
16#include "vector.hpp"
17#include "verbose.hpp"
18
19class molecule;
20
21// ======================================== Points on Boundary =================================
22
23/** Constructor of BoundaryPointSet.
24 */
25BoundaryPointSet::BoundaryPointSet() :
26 LinesCount(0),
27 value(0.),
28 Nr(-1)
29{
30 Info FunctionInfo(__func__);
31 Log() << Verbose(1) << "Adding noname." << endl;
32};
33
34/** Constructor of BoundaryPointSet with Tesselpoint.
35 * \param *Walker TesselPoint this boundary point represents
36 */
37BoundaryPointSet::BoundaryPointSet(TesselPoint * Walker) :
38 LinesCount(0),
39 node(Walker),
40 value(0.),
41 Nr(Walker->nr)
42{
43 Info FunctionInfo(__func__);
44 Log() << Verbose(1) << "Adding Node " << *Walker << endl;
45};
46
47/** Destructor of BoundaryPointSet.
48 * Sets node to NULL to avoid removing the original, represented TesselPoint.
49 * \note When removing point from a class Tesselation, use RemoveTesselationPoint()
50 */
51BoundaryPointSet::~BoundaryPointSet()
52{
53 Info FunctionInfo(__func__);
54 //Log() << Verbose(0) << "Erasing point nr. " << Nr << "." << endl;
55 if (!lines.empty())
56 eLog() << Verbose(2) << "Memory Leak! I " << *this << " am still connected to some lines." << endl;
57 node = NULL;
58};
59
60/** Add a line to the LineMap of this point.
61 * \param *line line to add
62 */
63void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
64{
65 Info FunctionInfo(__func__);
66 Log() << Verbose(1) << "Adding " << *this << " to line " << *line << "."
67 << endl;
68 if (line->endpoints[0] == this)
69 {
70 lines.insert(LinePair(line->endpoints[1]->Nr, line));
71 }
72 else
73 {
74 lines.insert(LinePair(line->endpoints[0]->Nr, line));
75 }
76 LinesCount++;
77};
78
79/** output operator for BoundaryPointSet.
80 * \param &ost output stream
81 * \param &a boundary point
82 */
83ostream & operator <<(ostream &ost, const BoundaryPointSet &a)
84{
85 ost << "[" << a.Nr << "|" << a.node->Name << " at " << *a.node->node << "]";
86 return ost;
87}
88;
89
90// ======================================== Lines on Boundary =================================
91
92/** Constructor of BoundaryLineSet.
93 */
94BoundaryLineSet::BoundaryLineSet() :
95 Nr(-1)
96{
97 Info FunctionInfo(__func__);
98 for (int i = 0; i < 2; i++)
99 endpoints[i] = NULL;
100};
101
102/** Constructor of BoundaryLineSet with two endpoints.
103 * Adds line automatically to each endpoints' LineMap
104 * \param *Point[2] array of two boundary points
105 * \param number number of the list
106 */
107BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], const int number)
108{
109 Info FunctionInfo(__func__);
110 // set number
111 Nr = number;
112 // set endpoints in ascending order
113 SetEndpointsOrdered(endpoints, Point[0], Point[1]);
114 // add this line to the hash maps of both endpoints
115 Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.
116 Point[1]->AddLine(this); //
117 // set skipped to false
118 skipped = false;
119 // clear triangles list
120 Log() << Verbose(0) << "New Line with endpoints " << *this << "." << endl;
121};
122
123/** Destructor for BoundaryLineSet.
124 * Removes itself from each endpoints' LineMap, calling RemoveTrianglePoint() when point not connected anymore.
125 * \note When removing lines from a class Tesselation, use RemoveTesselationLine()
126 */
127BoundaryLineSet::~BoundaryLineSet()
128{
129 Info FunctionInfo(__func__);
130 int Numbers[2];
131
132 // get other endpoint number of finding copies of same line
133 if (endpoints[1] != NULL)
134 Numbers[0] = endpoints[1]->Nr;
135 else
136 Numbers[0] = -1;
137 if (endpoints[0] != NULL)
138 Numbers[1] = endpoints[0]->Nr;
139 else
140 Numbers[1] = -1;
141
142 for (int i = 0; i < 2; i++) {
143 if (endpoints[i] != NULL) {
144 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
145 pair<LineMap::iterator, LineMap::iterator> erasor = endpoints[i]->lines.equal_range(Numbers[i]);
146 for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
147 if ((*Runner).second == this) {
148 //Log() << Verbose(0) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
149 endpoints[i]->lines.erase(Runner);
150 break;
151 }
152 } else { // there's just a single line left
153 if (endpoints[i]->lines.erase(Nr)) {
154 //Log() << Verbose(0) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
155 }
156 }
157 if (endpoints[i]->lines.empty()) {
158 //Log() << Verbose(0) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
159 if (endpoints[i] != NULL) {
160 delete(endpoints[i]);
161 endpoints[i] = NULL;
162 }
163 }
164 }
165 }
166 if (!triangles.empty())
167 eLog() << Verbose(2) << "Memory Leak! I " << *this << " am still connected to some triangles." << endl;
168};
169
170/** Add triangle to TriangleMap of this boundary line.
171 * \param *triangle to add
172 */
173void BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
174{
175 Info FunctionInfo(__func__);
176 Log() << Verbose(0) << "Add " << triangle->Nr << " to line " << *this << "." << endl;
177 triangles.insert(TrianglePair(triangle->Nr, triangle));
178};
179
180/** Checks whether we have a common endpoint with given \a *line.
181 * \param *line other line to test
182 * \return true - common endpoint present, false - not connected
183 */
184bool BoundaryLineSet::IsConnectedTo(class BoundaryLineSet *line)
185{
186 Info FunctionInfo(__func__);
187 if ((endpoints[0] == line->endpoints[0]) || (endpoints[1] == line->endpoints[0]) || (endpoints[0] == line->endpoints[1]) || (endpoints[1] == line->endpoints[1]))
188 return true;
189 else
190 return false;
191};
192
193/** Checks whether the adjacent triangles of a baseline are convex or not.
194 * We sum the two angles of each height vector with respect to the center of the baseline.
195 * If greater/equal M_PI than we are convex.
196 * \param *out output stream for debugging
197 * \return true - triangles are convex, false - concave or less than two triangles connected
198 */
199bool BoundaryLineSet::CheckConvexityCriterion()
200{
201 Info FunctionInfo(__func__);
202 Vector BaseLineCenter, BaseLineNormal, BaseLine, helper[2], NormalCheck;
203 // get the two triangles
204 if (triangles.size() != 2) {
205 eLog() << Verbose(0) << "Baseline " << *this << " is connected to less than two triangles, Tesselation incomplete!" << endl;
206 return true;
207 }
208 // check normal vectors
209 // have a normal vector on the base line pointing outwards
210 //Log() << Verbose(0) << "INFO: " << *this << " has vectors at " << *(endpoints[0]->node->node) << " and at " << *(endpoints[1]->node->node) << "." << endl;
211 BaseLineCenter.CopyVector(endpoints[0]->node->node);
212 BaseLineCenter.AddVector(endpoints[1]->node->node);
213 BaseLineCenter.Scale(1./2.);
214 BaseLine.CopyVector(endpoints[0]->node->node);
215 BaseLine.SubtractVector(endpoints[1]->node->node);
216 //Log() << Verbose(0) << "INFO: Baseline is " << BaseLine << " and its center is at " << BaseLineCenter << "." << endl;
217
218 BaseLineNormal.Zero();
219 NormalCheck.Zero();
220 double sign = -1.;
221 int i=0;
222 class BoundaryPointSet *node = NULL;
223 for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++) {
224 //Log() << Verbose(0) << "INFO: NormalVector of " << *(runner->second) << " is " << runner->second->NormalVector << "." << endl;
225 NormalCheck.AddVector(&runner->second->NormalVector);
226 NormalCheck.Scale(sign);
227 sign = -sign;
228 if (runner->second->NormalVector.NormSquared() > MYEPSILON)
229 BaseLineNormal.CopyVector(&runner->second->NormalVector); // yes, copy second on top of first
230 else {
231 eLog() << Verbose(0) << "Triangle " << *runner->second << " has zero normal vector!" << endl;
232 }
233 node = runner->second->GetThirdEndpoint(this);
234 if (node != NULL) {
235 //Log() << Verbose(0) << "INFO: Third node for triangle " << *(runner->second) << " is " << *node << " at " << *(node->node->node) << "." << endl;
236 helper[i].CopyVector(node->node->node);
237 helper[i].SubtractVector(&BaseLineCenter);
238 helper[i].MakeNormalVector(&BaseLine); // we want to compare the triangle's heights' angles!
239 //Log() << Verbose(0) << "INFO: Height vector with respect to baseline is " << helper[i] << "." << endl;
240 i++;
241 } else {
242 eLog() << Verbose(1) << "I cannot find third node in triangle, something's wrong." << endl;
243 return true;
244 }
245 }
246 //Log() << Verbose(0) << "INFO: BaselineNormal is " << BaseLineNormal << "." << endl;
247 if (NormalCheck.NormSquared() < MYEPSILON) {
248 Log() << Verbose(0) << "ACCEPT: Normalvectors of both triangles are the same: convex." << endl;
249 return true;
250 }
251 BaseLineNormal.Scale(-1.);
252 double angle = GetAngle(helper[0], helper[1], BaseLineNormal);
253 if ((angle - M_PI) > -MYEPSILON) {
254 Log() << Verbose(0) << "ACCEPT: Angle is greater than pi: convex." << endl;
255 return true;
256 } else {
257 Log() << Verbose(0) << "REJECT: Angle is less than pi: concave." << endl;
258 return false;
259 }
260}
261
262/** Checks whether point is any of the two endpoints this line contains.
263 * \param *point point to test
264 * \return true - point is of the line, false - is not
265 */
266bool BoundaryLineSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
267{
268 Info FunctionInfo(__func__);
269 for(int i=0;i<2;i++)
270 if (point == endpoints[i])
271 return true;
272 return false;
273};
274
275/** Returns other endpoint of the line.
276 * \param *point other endpoint
277 * \return NULL - if endpoint not contained in BoundaryLineSet, or pointer to BoundaryPointSet otherwise
278 */
279class BoundaryPointSet *BoundaryLineSet::GetOtherEndpoint(class BoundaryPointSet *point)
280{
281 Info FunctionInfo(__func__);
282 if (endpoints[0] == point)
283 return endpoints[1];
284 else if (endpoints[1] == point)
285 return endpoints[0];
286 else
287 return NULL;
288};
289
290/** output operator for BoundaryLineSet.
291 * \param &ost output stream
292 * \param &a boundary line
293 */
294ostream & operator <<(ostream &ost, const BoundaryLineSet &a)
295{
296 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 << "]";
297 return ost;
298};
299
300// ======================================== Triangles on Boundary =================================
301
302/** Constructor for BoundaryTriangleSet.
303 */
304BoundaryTriangleSet::BoundaryTriangleSet() :
305 Nr(-1)
306{
307 Info FunctionInfo(__func__);
308 for (int i = 0; i < 3; i++)
309 {
310 endpoints[i] = NULL;
311 lines[i] = NULL;
312 }
313};
314
315/** Constructor for BoundaryTriangleSet with three lines.
316 * \param *line[3] lines that make up the triangle
317 * \param number number of triangle
318 */
319BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number) :
320 Nr(number)
321{
322 Info FunctionInfo(__func__);
323 // set number
324 // set lines
325 for (int i = 0; i < 3; i++) {
326 lines[i] = line[i];
327 lines[i]->AddTriangle(this);
328 }
329 // get ascending order of endpoints
330 PointMap OrderMap;
331 for (int i = 0; i < 3; i++)
332 // for all three lines
333 for (int j = 0; j < 2; j++) { // for both endpoints
334 OrderMap.insert(pair<int, class BoundaryPointSet *> (
335 line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));
336 // and we don't care whether insertion fails
337 }
338 // set endpoints
339 int Counter = 0;
340 Log() << Verbose(0) << "New triangle " << Nr << " with end points: " << endl;
341 for (PointMap::iterator runner = OrderMap.begin(); runner != OrderMap.end(); runner++) {
342 endpoints[Counter] = runner->second;
343 Log() << Verbose(0) << " " << *endpoints[Counter] << endl;
344 Counter++;
345 }
346 if (Counter < 3) {
347 eLog() << Verbose(0) << "We have a triangle with only two distinct endpoints!" << endl;
348 performCriticalExit();
349 }
350};
351
352/** Destructor of BoundaryTriangleSet.
353 * Removes itself from each of its lines' LineMap and removes them if necessary.
354 * \note When removing triangles from a class Tesselation, use RemoveTesselationTriangle()
355 */
356BoundaryTriangleSet::~BoundaryTriangleSet()
357{
358 Info FunctionInfo(__func__);
359 for (int i = 0; i < 3; i++) {
360 if (lines[i] != NULL) {
361 if (lines[i]->triangles.erase(Nr)) {
362 //Log() << Verbose(0) << "Triangle Nr." << Nr << " erased in line " << *lines[i] << "." << endl;
363 }
364 if (lines[i]->triangles.empty()) {
365 //Log() << Verbose(0) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
366 delete (lines[i]);
367 lines[i] = NULL;
368 }
369 }
370 }
371 //Log() << Verbose(0) << "Erasing triangle Nr." << Nr << " itself." << endl;
372};
373
374/** Calculates the normal vector for this triangle.
375 * Is made unique by comparison with \a OtherVector to point in the other direction.
376 * \param &OtherVector direction vector to make normal vector unique.
377 */
378void BoundaryTriangleSet::GetNormalVector(Vector &OtherVector)
379{
380 Info FunctionInfo(__func__);
381 // get normal vector
382 NormalVector.MakeNormalVector(endpoints[0]->node->node, endpoints[1]->node->node, endpoints[2]->node->node);
383
384 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
385 if (NormalVector.ScalarProduct(&OtherVector) > 0.)
386 NormalVector.Scale(-1.);
387 Log() << Verbose(1) << "Normal Vector is " << NormalVector << "." << endl;
388};
389
390/** Finds the point on the triangle \a *BTS the line defined by \a *MolCenter and \a *x crosses through.
391 * We call Vector::GetIntersectionWithPlane() to receive the intersection point with the plane
392 * This we test if it's really on the plane and whether it's inside the triangle on the plane or not.
393 * The latter is done as follows: We calculate the cross point of one of the triangle's baseline with the line
394 * given by the intersection and the third basepoint. Then, we check whether it's on the baseline (i.e. between
395 * the first two basepoints) or not.
396 * \param *out output stream for debugging
397 * \param *MolCenter offset vector of line
398 * \param *x second endpoint of line, minus \a *MolCenter is directional vector of line
399 * \param *Intersection intersection on plane on return
400 * \return true - \a *Intersection contains intersection on plane defined by triangle, false - zero vector if outside of triangle.
401 */
402bool BoundaryTriangleSet::GetIntersectionInsideTriangle(Vector *MolCenter, Vector *x, Vector *Intersection)
403{
404 Info FunctionInfo(__func__);
405 Vector CrossPoint;
406 Vector helper;
407
408 if (!Intersection->GetIntersectionWithPlane(&NormalVector, endpoints[0]->node->node, MolCenter, x)) {
409 eLog() << Verbose(1) << "Alas! Intersection with plane failed - at least numerically - the intersection is not on the plane!" << endl;
410 return false;
411 }
412
413 // Calculate cross point between one baseline and the line from the third endpoint to intersection
414 int i=0;
415 do {
416 if (CrossPoint.GetIntersectionOfTwoLinesOnPlane(endpoints[i%3]->node->node, endpoints[(i+1)%3]->node->node, endpoints[(i+2)%3]->node->node, Intersection, &NormalVector)) {
417 helper.CopyVector(endpoints[(i+1)%3]->node->node);
418 helper.SubtractVector(endpoints[i%3]->node->node);
419 } else
420 i++;
421 if (i>2)
422 break;
423 } while (CrossPoint.NormSquared() < MYEPSILON);
424 if (i==3) {
425 eLog() << Verbose(0) << "Could not find any cross points, something's utterly wrong here!" << endl;
426 }
427 CrossPoint.SubtractVector(endpoints[i%3]->node->node); // cross point was returned as absolute vector
428
429 // check whether intersection is inside or not by comparing length of intersection and length of cross point
430 if ((CrossPoint.NormSquared() - helper.NormSquared()) < MYEPSILON) { // inside
431 return true;
432 } else { // outside!
433 Intersection->Zero();
434 return false;
435 }
436};
437
438/** Checks whether lines is any of the three boundary lines this triangle contains.
439 * \param *line line to test
440 * \return true - line is of the triangle, false - is not
441 */
442bool BoundaryTriangleSet::ContainsBoundaryLine(class BoundaryLineSet *line)
443{
444 Info FunctionInfo(__func__);
445 for(int i=0;i<3;i++)
446 if (line == lines[i])
447 return true;
448 return false;
449};
450
451/** Checks whether point is any of the three endpoints this triangle contains.
452 * \param *point point to test
453 * \return true - point is of the triangle, false - is not
454 */
455bool BoundaryTriangleSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
456{
457 Info FunctionInfo(__func__);
458 for(int i=0;i<3;i++)
459 if (point == endpoints[i])
460 return true;
461 return false;
462};
463
464/** Checks whether point is any of the three endpoints this triangle contains.
465 * \param *point TesselPoint to test
466 * \return true - point is of the triangle, false - is not
467 */
468bool BoundaryTriangleSet::ContainsBoundaryPoint(class TesselPoint *point)
469{
470 Info FunctionInfo(__func__);
471 for(int i=0;i<3;i++)
472 if (point == endpoints[i]->node)
473 return true;
474 return false;
475};
476
477/** Checks whether three given \a *Points coincide with triangle's endpoints.
478 * \param *Points[3] pointer to BoundaryPointSet
479 * \return true - is the very triangle, false - is not
480 */
481bool BoundaryTriangleSet::IsPresentTupel(class BoundaryPointSet *Points[3])
482{
483 Info FunctionInfo(__func__);
484 Log() << Verbose(1) << "INFO: Checking " << Points[0] << "," << Points[1] << "," << Points[2] << " against " << endpoints[0] << "," << endpoints[1] << "," << endpoints[2] << "." << endl;
485 return (((endpoints[0] == Points[0])
486 || (endpoints[0] == Points[1])
487 || (endpoints[0] == Points[2])
488 ) && (
489 (endpoints[1] == Points[0])
490 || (endpoints[1] == Points[1])
491 || (endpoints[1] == Points[2])
492 ) && (
493 (endpoints[2] == Points[0])
494 || (endpoints[2] == Points[1])
495 || (endpoints[2] == Points[2])
496
497 ));
498};
499
500/** Checks whether three given \a *Points coincide with triangle's endpoints.
501 * \param *Points[3] pointer to BoundaryPointSet
502 * \return true - is the very triangle, false - is not
503 */
504bool BoundaryTriangleSet::IsPresentTupel(class BoundaryTriangleSet *T)
505{
506 Info FunctionInfo(__func__);
507 return (((endpoints[0] == T->endpoints[0])
508 || (endpoints[0] == T->endpoints[1])
509 || (endpoints[0] == T->endpoints[2])
510 ) && (
511 (endpoints[1] == T->endpoints[0])
512 || (endpoints[1] == T->endpoints[1])
513 || (endpoints[1] == T->endpoints[2])
514 ) && (
515 (endpoints[2] == T->endpoints[0])
516 || (endpoints[2] == T->endpoints[1])
517 || (endpoints[2] == T->endpoints[2])
518
519 ));
520};
521
522/** Returns the endpoint which is not contained in the given \a *line.
523 * \param *line baseline defining two endpoints
524 * \return pointer third endpoint or NULL if line does not belong to triangle.
525 */
526class BoundaryPointSet *BoundaryTriangleSet::GetThirdEndpoint(class BoundaryLineSet *line)
527{
528 Info FunctionInfo(__func__);
529 // sanity check
530 if (!ContainsBoundaryLine(line))
531 return NULL;
532 for(int i=0;i<3;i++)
533 if (!line->ContainsBoundaryPoint(endpoints[i]))
534 return endpoints[i];
535 // actually, that' impossible :)
536 return NULL;
537};
538
539/** Calculates the center point of the triangle.
540 * Is third of the sum of all endpoints.
541 * \param *center central point on return.
542 */
543void BoundaryTriangleSet::GetCenter(Vector *center)
544{
545 Info FunctionInfo(__func__);
546 center->Zero();
547 for(int i=0;i<3;i++)
548 center->AddVector(endpoints[i]->node->node);
549 center->Scale(1./3.);
550}
551
552/** output operator for BoundaryTriangleSet.
553 * \param &ost output stream
554 * \param &a boundary triangle
555 */
556ostream &operator <<(ostream &ost, const BoundaryTriangleSet &a)
557{
558 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
559// ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << " at " << *a.endpoints[0]->node->node << ","
560// << a.endpoints[1]->node->Name << " at " << *a.endpoints[1]->node->node << "," << a.endpoints[2]->node->Name << " at " << *a.endpoints[2]->node->node << "]";
561 return ost;
562};
563
564// ======================================== Polygons on Boundary =================================
565
566/** Constructor for BoundaryPolygonSet.
567 */
568BoundaryPolygonSet::BoundaryPolygonSet() :
569 Nr(-1)
570{
571 Info FunctionInfo(__func__);
572};
573
574/** Destructor of BoundaryPolygonSet.
575 * Just clears endpoints.
576 * \note When removing triangles from a class Tesselation, use RemoveTesselationTriangle()
577 */
578BoundaryPolygonSet::~BoundaryPolygonSet()
579{
580 Info FunctionInfo(__func__);
581 endpoints.clear();
582 Log() << Verbose(1) << "Erasing polygon Nr." << Nr << " itself." << endl;
583};
584
585/** Calculates the normal vector for this triangle.
586 * Is made unique by comparison with \a OtherVector to point in the other direction.
587 * \param &OtherVector direction vector to make normal vector unique.
588 * \return allocated vector in normal direction
589 */
590Vector * BoundaryPolygonSet::GetNormalVector(const Vector &OtherVector) const
591{
592 Info FunctionInfo(__func__);
593 // get normal vector
594 Vector TemporaryNormal;
595 Vector *TotalNormal = new Vector;
596 PointSet::const_iterator Runner[3];
597 for (int i=0;i<3; i++) {
598 Runner[i] = endpoints.begin();
599 for (int j = 0; j<i; j++) { // go as much further
600 Runner[i]++;
601 if (Runner[i] == endpoints.end()) {
602 eLog() << Verbose(0) << "There are less than three endpoints in the polygon!" << endl;
603 performCriticalExit();
604 }
605 }
606 }
607 TotalNormal->Zero();
608 int counter=0;
609 for (; Runner[2] != endpoints.end(); ) {
610 TemporaryNormal.MakeNormalVector((*Runner[0])->node->node, (*Runner[1])->node->node, (*Runner[2])->node->node);
611 for (int i=0;i<3;i++) // increase each of them
612 Runner[i]++;
613 TotalNormal->AddVector(&TemporaryNormal);
614 }
615 TotalNormal->Scale(1./(double)counter);
616
617 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
618 if (TotalNormal->ScalarProduct(&OtherVector) > 0.)
619 TotalNormal->Scale(-1.);
620 Log() << Verbose(1) << "Normal Vector is " << *TotalNormal << "." << endl;
621
622 return TotalNormal;
623};
624
625/** Calculates the center point of the triangle.
626 * Is third of the sum of all endpoints.
627 * \param *center central point on return.
628 */
629void BoundaryPolygonSet::GetCenter(Vector * const center) const
630{
631 Info FunctionInfo(__func__);
632 center->Zero();
633 int counter = 0;
634 for(PointSet::const_iterator Runner = endpoints.begin(); Runner != endpoints.end(); Runner++) {
635 center->AddVector((*Runner)->node->node);
636 counter++;
637 }
638 center->Scale(1./(double)counter);
639 Log() << Verbose(1) << "Center is at " << *center << "." << endl;
640}
641
642/** Checks whether the polygons contains all three endpoints of the triangle.
643 * \param *triangle triangle to test
644 * \return true - triangle is contained polygon, false - is not
645 */
646bool BoundaryPolygonSet::ContainsBoundaryTriangle(const BoundaryTriangleSet * const triangle) const
647{
648 Info FunctionInfo(__func__);
649 return ContainsPresentTupel(triangle->endpoints, 3);
650};
651
652/** Checks whether the polygons contains both endpoints of the line.
653 * \param *line line to test
654 * \return true - line is of the triangle, false - is not
655 */
656bool BoundaryPolygonSet::ContainsBoundaryLine(const BoundaryLineSet * const line) const
657{
658 Info FunctionInfo(__func__);
659 return ContainsPresentTupel(line->endpoints, 2);
660};
661
662/** Checks whether point is any of the three endpoints this triangle contains.
663 * \param *point point to test
664 * \return true - point is of the triangle, false - is not
665 */
666bool BoundaryPolygonSet::ContainsBoundaryPoint(const BoundaryPointSet * const point) const
667{
668 Info FunctionInfo(__func__);
669 for(PointSet::const_iterator Runner = endpoints.begin(); Runner != endpoints.end(); Runner++) {
670 Log() << Verbose(0) << "Checking against " << **Runner << endl;
671 if (point == (*Runner)) {
672 Log() << Verbose(0) << " Contained." << endl;
673 return true;
674 }
675 }
676 Log() << Verbose(0) << " Not contained." << endl;
677 return false;
678};
679
680/** Checks whether point is any of the three endpoints this triangle contains.
681 * \param *point TesselPoint to test
682 * \return true - point is of the triangle, false - is not
683 */
684bool BoundaryPolygonSet::ContainsBoundaryPoint(const TesselPoint * const point) const
685{
686 Info FunctionInfo(__func__);
687 for(PointSet::const_iterator Runner = endpoints.begin(); Runner != endpoints.end(); Runner++)
688 if (point == (*Runner)->node) {
689 Log() << Verbose(0) << " Contained." << endl;
690 return true;
691 }
692 Log() << Verbose(0) << " Not contained." << endl;
693 return false;
694};
695
696/** Checks whether given array of \a *Points coincide with polygons's endpoints.
697 * \param **Points pointer to an array of BoundaryPointSet
698 * \param dim dimension of array
699 * \return true - set of points is contained in polygon, false - is not
700 */
701bool BoundaryPolygonSet::ContainsPresentTupel(const BoundaryPointSet * const * Points, const int dim) const
702{
703 Info FunctionInfo(__func__);
704 int counter = 0;
705 Log() << Verbose(1) << "Polygon is " << *this << endl;
706 for(int i=0;i<dim;i++) {
707 Log() << Verbose(1) << " Testing endpoint " << *Points[i] << endl;
708 if (ContainsBoundaryPoint(Points[i])) {
709 counter++;
710 }
711 }
712
713 if (counter == dim)
714 return true;
715 else
716 return false;
717};
718
719/** Checks whether given PointList coincide with polygons's endpoints.
720 * \param &endpoints PointList
721 * \return true - set of points is contained in polygon, false - is not
722 */
723bool BoundaryPolygonSet::ContainsPresentTupel(const PointSet &endpoints) const
724{
725 Info FunctionInfo(__func__);
726 size_t counter = 0;
727 Log() << Verbose(1) << "Polygon is " << *this << endl;
728 for(PointSet::const_iterator Runner = endpoints.begin(); Runner != endpoints.end(); Runner++) {
729 Log() << Verbose(1) << " Testing endpoint " << **Runner << endl;
730 if (ContainsBoundaryPoint(*Runner))
731 counter++;
732 }
733
734 if (counter == endpoints.size())
735 return true;
736 else
737 return false;
738};
739
740/** Checks whether given set of \a *Points coincide with polygons's endpoints.
741 * \param *P pointer to BoundaryPolygonSet
742 * \return true - is the very triangle, false - is not
743 */
744bool BoundaryPolygonSet::ContainsPresentTupel(const BoundaryPolygonSet * const P) const
745{
746 return ContainsPresentTupel((const PointSet)P->endpoints);
747};
748
749/** Gathers all the endpoints' triangles in a unique set.
750 * \return set of all triangles
751 */
752TriangleSet * BoundaryPolygonSet::GetAllContainedTrianglesFromEndpoints() const
753{
754 Info FunctionInfo(__func__);
755 pair <TriangleSet::iterator, bool> Tester;
756 TriangleSet *triangles = new TriangleSet;
757
758 for(PointSet::const_iterator Runner = endpoints.begin(); Runner != endpoints.end(); Runner++)
759 for(LineMap::const_iterator Walker = (*Runner)->lines.begin(); Walker != (*Runner)->lines.end(); Walker++)
760 for(TriangleMap::const_iterator Sprinter = (Walker->second)->triangles.begin(); Sprinter != (Walker->second)->triangles.end(); Sprinter++) {
761 //Log() << Verbose(0) << " Testing triangle " << *(Sprinter->second) << endl;
762 if (ContainsBoundaryTriangle(Sprinter->second)) {
763 Tester = triangles->insert(Sprinter->second);
764 if (Tester.second)
765 Log() << Verbose(0) << "Adding triangle " << *(Sprinter->second) << endl;
766 }
767 }
768
769 Log() << Verbose(1) << "The Polygon of " << endpoints.size() << " endpoints has " << triangles->size() << " unique triangles in total." << endl;
770 return triangles;
771};
772
773/** Fills the endpoints of this polygon from the triangles attached to \a *line.
774 * \param *line lines with triangles attached
775 * \return true - polygon contains endpoints, false - line was NULL
776 */
777bool BoundaryPolygonSet::FillPolygonFromTrianglesOfLine(const BoundaryLineSet * const line)
778{
779 Info FunctionInfo(__func__);
780 pair <PointSet::iterator, bool> Tester;
781 if (line == NULL)
782 return false;
783 Log() << Verbose(1) << "Filling polygon from line " << *line << endl;
784 for(TriangleMap::const_iterator Runner = line->triangles.begin(); Runner != line->triangles.end(); Runner++) {
785 for (int i=0;i<3;i++) {
786 Tester = endpoints.insert((Runner->second)->endpoints[i]);
787 if (Tester.second)
788 Log() << Verbose(1) << " Inserting endpoint " << *((Runner->second)->endpoints[i]) << endl;
789 }
790 }
791
792 return true;
793};
794
795/** output operator for BoundaryPolygonSet.
796 * \param &ost output stream
797 * \param &a boundary polygon
798 */
799ostream &operator <<(ostream &ost, const BoundaryPolygonSet &a)
800{
801 ost << "[" << a.Nr << "|";
802 for(PointSet::const_iterator Runner = a.endpoints.begin(); Runner != a.endpoints.end();) {
803 ost << (*Runner)->node->Name;
804 Runner++;
805 if (Runner != a.endpoints.end())
806 ost << ",";
807 }
808 ost<< "]";
809 return ost;
810};
811
812// =========================================================== class TESSELPOINT ===========================================
813
814/** Constructor of class TesselPoint.
815 */
816TesselPoint::TesselPoint()
817{
818 Info FunctionInfo(__func__);
819 node = NULL;
820 nr = -1;
821 Name = NULL;
822};
823
824/** Destructor for class TesselPoint.
825 */
826TesselPoint::~TesselPoint()
827{
828 Info FunctionInfo(__func__);
829};
830
831/** Prints LCNode to screen.
832 */
833ostream & operator << (ostream &ost, const TesselPoint &a)
834{
835 ost << "[" << (a.Name) << "|" << a.Name << " at " << *a.node << "]";
836 return ost;
837};
838
839/** Prints LCNode to screen.
840 */
841ostream & TesselPoint::operator << (ostream &ost)
842{
843 Info FunctionInfo(__func__);
844 ost << "[" << (nr) << "|" << this << "]";
845 return ost;
846};
847
848
849// =========================================================== class POINTCLOUD ============================================
850
851/** Constructor of class PointCloud.
852 */
853PointCloud::PointCloud()
854{
855 Info FunctionInfo(__func__);
856};
857
858/** Destructor for class PointCloud.
859 */
860PointCloud::~PointCloud()
861{
862 Info FunctionInfo(__func__);
863};
864
865// ============================ CandidateForTesselation =============================
866
867/** Constructor of class CandidateForTesselation.
868 */
869CandidateForTesselation::CandidateForTesselation (BoundaryLineSet* line) :
870 BaseLine(line),
871 ShortestAngle(2.*M_PI),
872 OtherShortestAngle(2.*M_PI)
873{
874 Info FunctionInfo(__func__);
875};
876
877
878/** Constructor of class CandidateForTesselation.
879 */
880CandidateForTesselation::CandidateForTesselation (TesselPoint *candidate, BoundaryLineSet* line, Vector OptCandidateCenter, Vector OtherOptCandidateCenter) :
881 BaseLine(line),
882 ShortestAngle(2.*M_PI),
883 OtherShortestAngle(2.*M_PI)
884{
885 Info FunctionInfo(__func__);
886 OptCenter.CopyVector(&OptCandidateCenter);
887 OtherOptCenter.CopyVector(&OtherOptCandidateCenter);
888};
889
890/** Destructor for class CandidateForTesselation.
891 */
892CandidateForTesselation::~CandidateForTesselation() {
893 BaseLine = NULL;
894};
895
896/** output operator for CandidateForTesselation.
897 * \param &ost output stream
898 * \param &a boundary line
899 */
900ostream & operator <<(ostream &ost, const CandidateForTesselation &a)
901{
902 ost << "[" << a.BaseLine->Nr << "|" << a.BaseLine->endpoints[0]->node->Name << "," << a.BaseLine->endpoints[1]->node->Name << "] with ";
903 if (a.pointlist.empty())
904 ost << "no candidate.";
905 else {
906 ost << "candidate";
907 if (a.pointlist.size() != 1)
908 ost << "s ";
909 else
910 ost << " ";
911 for (TesselPointList::const_iterator Runner = a.pointlist.begin(); Runner != a.pointlist.end(); Runner++)
912 ost << *(*Runner) << " ";
913 ost << " at angle " << (a.ShortestAngle)<< ".";
914 }
915
916 return ost;
917};
918
919
920// =========================================================== class TESSELATION ===========================================
921
922/** Constructor of class Tesselation.
923 */
924Tesselation::Tesselation() :
925 PointsOnBoundaryCount(0),
926 LinesOnBoundaryCount(0),
927 TrianglesOnBoundaryCount(0),
928 LastTriangle(NULL),
929 TriangleFilesWritten(0),
930 InternalPointer(PointsOnBoundary.begin())
931{
932 Info FunctionInfo(__func__);
933}
934;
935
936/** Destructor of class Tesselation.
937 * We have to free all points, lines and triangles.
938 */
939Tesselation::~Tesselation()
940{
941 Info FunctionInfo(__func__);
942 Log() << Verbose(0) << "Free'ing TesselStruct ... " << endl;
943 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
944 if (runner->second != NULL) {
945 delete (runner->second);
946 runner->second = NULL;
947 } else
948 eLog() << Verbose(1) << "The triangle " << runner->first << " has already been free'd." << endl;
949 }
950 Log() << Verbose(0) << "This envelope was written to file " << TriangleFilesWritten << " times(s)." << endl;
951}
952;
953
954/** PointCloud implementation of GetCenter
955 * Uses PointsOnBoundary and STL stuff.
956 */
957Vector * Tesselation::GetCenter(ofstream *out) const
958{
959 Info FunctionInfo(__func__);
960 Vector *Center = new Vector(0.,0.,0.);
961 int num=0;
962 for (GoToFirst(); (!IsEnd()); GoToNext()) {
963 Center->AddVector(GetPoint()->node);
964 num++;
965 }
966 Center->Scale(1./num);
967 return Center;
968};
969
970/** PointCloud implementation of GoPoint
971 * Uses PointsOnBoundary and STL stuff.
972 */
973TesselPoint * Tesselation::GetPoint() const
974{
975 Info FunctionInfo(__func__);
976 return (InternalPointer->second->node);
977};
978
979/** PointCloud implementation of GetTerminalPoint.
980 * Uses PointsOnBoundary and STL stuff.
981 */
982TesselPoint * Tesselation::GetTerminalPoint() const
983{
984 Info FunctionInfo(__func__);
985 PointMap::const_iterator Runner = PointsOnBoundary.end();
986 Runner--;
987 return (Runner->second->node);
988};
989
990/** PointCloud implementation of GoToNext.
991 * Uses PointsOnBoundary and STL stuff.
992 */
993void Tesselation::GoToNext() const
994{
995 Info FunctionInfo(__func__);
996 if (InternalPointer != PointsOnBoundary.end())
997 InternalPointer++;
998};
999
1000/** PointCloud implementation of GoToPrevious.
1001 * Uses PointsOnBoundary and STL stuff.
1002 */
1003void Tesselation::GoToPrevious() const
1004{
1005 Info FunctionInfo(__func__);
1006 if (InternalPointer != PointsOnBoundary.begin())
1007 InternalPointer--;
1008};
1009
1010/** PointCloud implementation of GoToFirst.
1011 * Uses PointsOnBoundary and STL stuff.
1012 */
1013void Tesselation::GoToFirst() const
1014{
1015 Info FunctionInfo(__func__);
1016 InternalPointer = PointsOnBoundary.begin();
1017};
1018
1019/** PointCloud implementation of GoToLast.
1020 * Uses PointsOnBoundary and STL stuff.
1021 */
1022void Tesselation::GoToLast() const
1023{
1024 Info FunctionInfo(__func__);
1025 InternalPointer = PointsOnBoundary.end();
1026 InternalPointer--;
1027};
1028
1029/** PointCloud implementation of IsEmpty.
1030 * Uses PointsOnBoundary and STL stuff.
1031 */
1032bool Tesselation::IsEmpty() const
1033{
1034 Info FunctionInfo(__func__);
1035 return (PointsOnBoundary.empty());
1036};
1037
1038/** PointCloud implementation of IsLast.
1039 * Uses PointsOnBoundary and STL stuff.
1040 */
1041bool Tesselation::IsEnd() const
1042{
1043 Info FunctionInfo(__func__);
1044 return (InternalPointer == PointsOnBoundary.end());
1045};
1046
1047
1048/** Gueses first starting triangle of the convex envelope.
1049 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
1050 * \param *out output stream for debugging
1051 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
1052 */
1053void
1054Tesselation::GuessStartingTriangle()
1055{
1056 Info FunctionInfo(__func__);
1057 // 4b. create a starting triangle
1058 // 4b1. create all distances
1059 DistanceMultiMap DistanceMMap;
1060 double distance, tmp;
1061 Vector PlaneVector, TrialVector;
1062 PointMap::iterator A, B, C; // three nodes of the first triangle
1063 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
1064
1065 // with A chosen, take each pair B,C and sort
1066 if (A != PointsOnBoundary.end())
1067 {
1068 B = A;
1069 B++;
1070 for (; B != PointsOnBoundary.end(); B++)
1071 {
1072 C = B;
1073 C++;
1074 for (; C != PointsOnBoundary.end(); C++)
1075 {
1076 tmp = A->second->node->node->DistanceSquared(B->second->node->node);
1077 distance = tmp * tmp;
1078 tmp = A->second->node->node->DistanceSquared(C->second->node->node);
1079 distance += tmp * tmp;
1080 tmp = B->second->node->node->DistanceSquared(C->second->node->node);
1081 distance += tmp * tmp;
1082 DistanceMMap.insert(DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator> (B, C)));
1083 }
1084 }
1085 }
1086 // // listing distances
1087 // Log() << Verbose(1) << "Listing DistanceMMap:";
1088 // for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
1089 // Log() << Verbose(0) << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
1090 // }
1091 // Log() << Verbose(0) << endl;
1092 // 4b2. pick three baselines forming a triangle
1093 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
1094 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
1095 for (; baseline != DistanceMMap.end(); baseline++)
1096 {
1097 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
1098 // 2. next, we have to check whether all points reside on only one side of the triangle
1099 // 3. construct plane vector
1100 PlaneVector.MakeNormalVector(A->second->node->node,
1101 baseline->second.first->second->node->node,
1102 baseline->second.second->second->node->node);
1103 Log() << Verbose(2) << "Plane vector of candidate triangle is " << PlaneVector << endl;
1104 // 4. loop over all points
1105 double sign = 0.;
1106 PointMap::iterator checker = PointsOnBoundary.begin();
1107 for (; checker != PointsOnBoundary.end(); checker++)
1108 {
1109 // (neglecting A,B,C)
1110 if ((checker == A) || (checker == baseline->second.first) || (checker
1111 == baseline->second.second))
1112 continue;
1113 // 4a. project onto plane vector
1114 TrialVector.CopyVector(checker->second->node->node);
1115 TrialVector.SubtractVector(A->second->node->node);
1116 distance = TrialVector.ScalarProduct(&PlaneVector);
1117 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
1118 continue;
1119 Log() << Verbose(2) << "Projection of " << checker->second->node->Name << " yields distance of " << distance << "." << endl;
1120 tmp = distance / fabs(distance);
1121 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
1122 if ((sign != 0) && (tmp != sign))
1123 {
1124 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
1125 Log() << Verbose(2) << "Current candidates: "
1126 << A->second->node->Name << ","
1127 << baseline->second.first->second->node->Name << ","
1128 << baseline->second.second->second->node->Name << " leaves "
1129 << checker->second->node->Name << " outside the convex hull."
1130 << endl;
1131 break;
1132 }
1133 else
1134 { // note the sign for later
1135 Log() << Verbose(2) << "Current candidates: "
1136 << A->second->node->Name << ","
1137 << baseline->second.first->second->node->Name << ","
1138 << baseline->second.second->second->node->Name << " leave "
1139 << checker->second->node->Name << " inside the convex hull."
1140 << endl;
1141 sign = tmp;
1142 }
1143 // 4d. Check whether the point is inside the triangle (check distance to each node
1144 tmp = checker->second->node->node->DistanceSquared(A->second->node->node);
1145 int innerpoint = 0;
1146 if ((tmp < A->second->node->node->DistanceSquared(
1147 baseline->second.first->second->node->node)) && (tmp
1148 < A->second->node->node->DistanceSquared(
1149 baseline->second.second->second->node->node)))
1150 innerpoint++;
1151 tmp = checker->second->node->node->DistanceSquared(
1152 baseline->second.first->second->node->node);
1153 if ((tmp < baseline->second.first->second->node->node->DistanceSquared(
1154 A->second->node->node)) && (tmp
1155 < baseline->second.first->second->node->node->DistanceSquared(
1156 baseline->second.second->second->node->node)))
1157 innerpoint++;
1158 tmp = checker->second->node->node->DistanceSquared(
1159 baseline->second.second->second->node->node);
1160 if ((tmp < baseline->second.second->second->node->node->DistanceSquared(
1161 baseline->second.first->second->node->node)) && (tmp
1162 < baseline->second.second->second->node->node->DistanceSquared(
1163 A->second->node->node)))
1164 innerpoint++;
1165 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
1166 if (innerpoint == 3)
1167 break;
1168 }
1169 // 5. come this far, all on same side? Then break 1. loop and construct triangle
1170 if (checker == PointsOnBoundary.end())
1171 {
1172 Log() << Verbose(2) << "Looks like we have a candidate!" << endl;
1173 break;
1174 }
1175 }
1176 if (baseline != DistanceMMap.end())
1177 {
1178 BPS[0] = baseline->second.first->second;
1179 BPS[1] = baseline->second.second->second;
1180 BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1181 BPS[0] = A->second;
1182 BPS[1] = baseline->second.second->second;
1183 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1184 BPS[0] = baseline->second.first->second;
1185 BPS[1] = A->second;
1186 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1187
1188 // 4b3. insert created triangle
1189 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1190 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1191 TrianglesOnBoundaryCount++;
1192 for (int i = 0; i < NDIM; i++)
1193 {
1194 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));
1195 LinesOnBoundaryCount++;
1196 }
1197
1198 Log() << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
1199 }
1200 else
1201 {
1202 eLog() << Verbose(0) << "No starting triangle found." << endl;
1203 }
1204}
1205;
1206
1207/** Tesselates the convex envelope of a cluster from a single starting triangle.
1208 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
1209 * 2 triangles. Hence, we go through all current lines:
1210 * -# if the lines contains to only one triangle
1211 * -# We search all points in the boundary
1212 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
1213 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
1214 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors)
1215 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
1216 * \param *out output stream for debugging
1217 * \param *configuration for IsAngstroem
1218 * \param *cloud cluster of points
1219 */
1220void Tesselation::TesselateOnBoundary(const PointCloud * const cloud)
1221{
1222 Info FunctionInfo(__func__);
1223 bool flag;
1224 PointMap::iterator winner;
1225 class BoundaryPointSet *peak = NULL;
1226 double SmallestAngle, TempAngle;
1227 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, helper, PropagationVector, *Center = NULL;
1228 LineMap::iterator LineChecker[2];
1229
1230 Center = cloud->GetCenter();
1231 // create a first tesselation with the given BoundaryPoints
1232 do {
1233 flag = false;
1234 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
1235 if (baseline->second->triangles.size() == 1) {
1236 // 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)
1237 SmallestAngle = M_PI;
1238
1239 // get peak point with respect to this base line's only triangle
1240 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
1241 Log() << Verbose(0) << "Current baseline is between " << *(baseline->second) << "." << endl;
1242 for (int i = 0; i < 3; i++)
1243 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
1244 peak = BTS->endpoints[i];
1245 Log() << Verbose(1) << " and has peak " << *peak << "." << endl;
1246
1247 // prepare some auxiliary vectors
1248 Vector BaseLineCenter, BaseLine;
1249 BaseLineCenter.CopyVector(baseline->second->endpoints[0]->node->node);
1250 BaseLineCenter.AddVector(baseline->second->endpoints[1]->node->node);
1251 BaseLineCenter.Scale(1. / 2.); // points now to center of base line
1252 BaseLine.CopyVector(baseline->second->endpoints[0]->node->node);
1253 BaseLine.SubtractVector(baseline->second->endpoints[1]->node->node);
1254
1255 // offset to center of triangle
1256 CenterVector.Zero();
1257 for (int i = 0; i < 3; i++)
1258 CenterVector.AddVector(BTS->endpoints[i]->node->node);
1259 CenterVector.Scale(1. / 3.);
1260 Log() << Verbose(2) << "CenterVector of base triangle is " << CenterVector << endl;
1261
1262 // normal vector of triangle
1263 NormalVector.CopyVector(Center);
1264 NormalVector.SubtractVector(&CenterVector);
1265 BTS->GetNormalVector(NormalVector);
1266 NormalVector.CopyVector(&BTS->NormalVector);
1267 Log() << Verbose(2) << "NormalVector of base triangle is " << NormalVector << endl;
1268
1269 // vector in propagation direction (out of triangle)
1270 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
1271 PropagationVector.MakeNormalVector(&BaseLine, &NormalVector);
1272 TempVector.CopyVector(&CenterVector);
1273 TempVector.SubtractVector(baseline->second->endpoints[0]->node->node); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
1274 //Log() << Verbose(0) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
1275 if (PropagationVector.ScalarProduct(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
1276 PropagationVector.Scale(-1.);
1277 Log() << Verbose(2) << "PropagationVector of base triangle is " << PropagationVector << endl;
1278 winner = PointsOnBoundary.end();
1279
1280 // loop over all points and calculate angle between normal vector of new and present triangle
1281 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) {
1282 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
1283 Log() << Verbose(1) << "Target point is " << *(target->second) << ":" << endl;
1284
1285 // first check direction, so that triangles don't intersect
1286 VirtualNormalVector.CopyVector(target->second->node->node);
1287 VirtualNormalVector.SubtractVector(&BaseLineCenter); // points from center of base line to target
1288 VirtualNormalVector.ProjectOntoPlane(&NormalVector);
1289 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
1290 Log() << Verbose(2) << "VirtualNormalVector is " << VirtualNormalVector << " and PropagationVector is " << PropagationVector << "." << endl;
1291 if (TempAngle > (M_PI/2.)) { // no bends bigger than Pi/2 (90 degrees)
1292 Log() << Verbose(2) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
1293 continue;
1294 } else
1295 Log() << Verbose(2) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
1296
1297 // check first and second endpoint (if any connecting line goes to target has at least not more than 1 triangle)
1298 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
1299 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
1300 if (((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[0]->second->triangles.size() == 2))) {
1301 Log() << Verbose(2) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->triangles.size() << " triangles." << endl;
1302 continue;
1303 }
1304 if (((LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (LineChecker[1]->second->triangles.size() == 2))) {
1305 Log() << Verbose(2) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->triangles.size() << " triangles." << endl;
1306 continue;
1307 }
1308
1309 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
1310 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)))) {
1311 Log() << Verbose(4) << "Current target is peak!" << endl;
1312 continue;
1313 }
1314
1315 // check for linear dependence
1316 TempVector.CopyVector(baseline->second->endpoints[0]->node->node);
1317 TempVector.SubtractVector(target->second->node->node);
1318 helper.CopyVector(baseline->second->endpoints[1]->node->node);
1319 helper.SubtractVector(target->second->node->node);
1320 helper.ProjectOntoPlane(&TempVector);
1321 if (fabs(helper.NormSquared()) < MYEPSILON) {
1322 Log() << Verbose(2) << "Chosen set of vectors is linear dependent." << endl;
1323 continue;
1324 }
1325
1326 // in case NOT both were found, create virtually this triangle, get its normal vector, calculate angle
1327 flag = true;
1328 VirtualNormalVector.MakeNormalVector(baseline->second->endpoints[0]->node->node, baseline->second->endpoints[1]->node->node, target->second->node->node);
1329 TempVector.CopyVector(baseline->second->endpoints[0]->node->node);
1330 TempVector.AddVector(baseline->second->endpoints[1]->node->node);
1331 TempVector.AddVector(target->second->node->node);
1332 TempVector.Scale(1./3.);
1333 TempVector.SubtractVector(Center);
1334 // make it always point outward
1335 if (VirtualNormalVector.ScalarProduct(&TempVector) < 0)
1336 VirtualNormalVector.Scale(-1.);
1337 // calculate angle
1338 TempAngle = NormalVector.Angle(&VirtualNormalVector);
1339 Log() << Verbose(2) << "NormalVector is " << VirtualNormalVector << " and the angle is " << TempAngle << "." << endl;
1340 if ((SmallestAngle - TempAngle) > MYEPSILON) { // set to new possible winner
1341 SmallestAngle = TempAngle;
1342 winner = target;
1343 Log() << Verbose(2) << "New winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
1344 } else if (fabs(SmallestAngle - TempAngle) < MYEPSILON) { // check the angle to propagation, both possible targets are in one plane! (their normals have same angle)
1345 // hence, check the angles to some normal direction from our base line but in this common plane of both targets...
1346 helper.CopyVector(target->second->node->node);
1347 helper.SubtractVector(&BaseLineCenter);
1348 helper.ProjectOntoPlane(&BaseLine);
1349 // ...the one with the smaller angle is the better candidate
1350 TempVector.CopyVector(target->second->node->node);
1351 TempVector.SubtractVector(&BaseLineCenter);
1352 TempVector.ProjectOntoPlane(&VirtualNormalVector);
1353 TempAngle = TempVector.Angle(&helper);
1354 TempVector.CopyVector(winner->second->node->node);
1355 TempVector.SubtractVector(&BaseLineCenter);
1356 TempVector.ProjectOntoPlane(&VirtualNormalVector);
1357 if (TempAngle < TempVector.Angle(&helper)) {
1358 TempAngle = NormalVector.Angle(&VirtualNormalVector);
1359 SmallestAngle = TempAngle;
1360 winner = target;
1361 Log() << Verbose(2) << "New winner " << *winner->second->node << " due to smaller angle " << TempAngle << " to propagation direction." << endl;
1362 } else
1363 Log() << Verbose(2) << "Keeping old winner " << *winner->second->node << " due to smaller angle to propagation direction." << endl;
1364 } else
1365 Log() << Verbose(2) << "Keeping old winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
1366 }
1367 } // end of loop over all boundary points
1368
1369 // 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
1370 if (winner != PointsOnBoundary.end()) {
1371 Log() << Verbose(0) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
1372 // create the lins of not yet present
1373 BLS[0] = baseline->second;
1374 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
1375 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
1376 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
1377 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
1378 BPS[0] = baseline->second->endpoints[0];
1379 BPS[1] = winner->second;
1380 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1381 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[1]));
1382 LinesOnBoundaryCount++;
1383 } else
1384 BLS[1] = LineChecker[0]->second;
1385 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
1386 BPS[0] = baseline->second->endpoints[1];
1387 BPS[1] = winner->second;
1388 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1389 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[2]));
1390 LinesOnBoundaryCount++;
1391 } else
1392 BLS[2] = LineChecker[1]->second;
1393 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1394 BTS->GetCenter(&helper);
1395 helper.SubtractVector(Center);
1396 helper.Scale(-1);
1397 BTS->GetNormalVector(helper);
1398 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1399 TrianglesOnBoundaryCount++;
1400 } else {
1401 eLog() << Verbose(2) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
1402 }
1403
1404 // 5d. If the set of lines is not yet empty, go to 5. and continue
1405 } else
1406 Log() << Verbose(0) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->triangles.size() << "." << endl;
1407 } while (flag);
1408
1409 // exit
1410 delete(Center);
1411};
1412
1413/** Inserts all points outside of the tesselated surface into it by adding new triangles.
1414 * \param *out output stream for debugging
1415 * \param *cloud cluster of points
1416 * \param *LC LinkedCell structure to find nearest point quickly
1417 * \return true - all straddling points insert, false - something went wrong
1418 */
1419bool Tesselation::InsertStraddlingPoints(const PointCloud *cloud, const LinkedCell *LC)
1420{
1421 Info FunctionInfo(__func__);
1422 Vector Intersection, Normal;
1423 TesselPoint *Walker = NULL;
1424 Vector *Center = cloud->GetCenter();
1425 list<BoundaryTriangleSet*> *triangles = NULL;
1426 bool AddFlag = false;
1427 LinkedCell *BoundaryPoints = NULL;
1428
1429 cloud->GoToFirst();
1430 BoundaryPoints = new LinkedCell(this, 5.);
1431 while (!cloud->IsEnd()) { // we only have to go once through all points, as boundary can become only bigger
1432 if (AddFlag) {
1433 delete(BoundaryPoints);
1434 BoundaryPoints = new LinkedCell(this, 5.);
1435 AddFlag = false;
1436 }
1437 Walker = cloud->GetPoint();
1438 Log() << Verbose(0) << "Current point is " << *Walker << "." << endl;
1439 // get the next triangle
1440 triangles = FindClosestTrianglesToPoint(Walker->node, BoundaryPoints);
1441 BTS = triangles->front();
1442 if ((triangles == NULL) || (BTS->ContainsBoundaryPoint(Walker))) {
1443 Log() << Verbose(0) << "No triangles found, probably a tesselation point itself." << endl;
1444 cloud->GoToNext();
1445 continue;
1446 } else {
1447 }
1448 Log() << Verbose(0) << "Closest triangle is " << *BTS << "." << endl;
1449 // get the intersection point
1450 if (BTS->GetIntersectionInsideTriangle(Center, Walker->node, &Intersection)) {
1451 Log() << Verbose(0) << "We have an intersection at " << Intersection << "." << endl;
1452 // we have the intersection, check whether in- or outside of boundary
1453 if ((Center->DistanceSquared(Walker->node) - Center->DistanceSquared(&Intersection)) < -MYEPSILON) {
1454 // inside, next!
1455 Log() << Verbose(0) << *Walker << " is inside wrt triangle " << *BTS << "." << endl;
1456 } else {
1457 // outside!
1458 Log() << Verbose(0) << *Walker << " is outside wrt triangle " << *BTS << "." << endl;
1459 class BoundaryLineSet *OldLines[3], *NewLines[3];
1460 class BoundaryPointSet *OldPoints[3], *NewPoint;
1461 // store the three old lines and old points
1462 for (int i=0;i<3;i++) {
1463 OldLines[i] = BTS->lines[i];
1464 OldPoints[i] = BTS->endpoints[i];
1465 }
1466 Normal.CopyVector(&BTS->NormalVector);
1467 // add Walker to boundary points
1468 Log() << Verbose(0) << "Adding " << *Walker << " to BoundaryPoints." << endl;
1469 AddFlag = true;
1470 if (AddBoundaryPoint(Walker,0))
1471 NewPoint = BPS[0];
1472 else
1473 continue;
1474 // remove triangle
1475 Log() << Verbose(0) << "Erasing triangle " << *BTS << "." << endl;
1476 TrianglesOnBoundary.erase(BTS->Nr);
1477 delete(BTS);
1478 // create three new boundary lines
1479 for (int i=0;i<3;i++) {
1480 BPS[0] = NewPoint;
1481 BPS[1] = OldPoints[i];
1482 NewLines[i] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1483 Log() << Verbose(1) << "Creating new line " << *NewLines[i] << "." << endl;
1484 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, NewLines[i])); // no need for check for unique insertion as BPS[0] is definitely a new one
1485 LinesOnBoundaryCount++;
1486 }
1487 // create three new triangle with new point
1488 for (int i=0;i<3;i++) { // find all baselines
1489 BLS[0] = OldLines[i];
1490 int n = 1;
1491 for (int j=0;j<3;j++) {
1492 if (NewLines[j]->IsConnectedTo(BLS[0])) {
1493 if (n>2) {
1494 eLog() << Verbose(2) << BLS[0] << " connects to all of the new lines?!" << endl;
1495 return false;
1496 } else
1497 BLS[n++] = NewLines[j];
1498 }
1499 }
1500 // create the triangle
1501 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1502 Normal.Scale(-1.);
1503 BTS->GetNormalVector(Normal);
1504 Normal.Scale(-1.);
1505 Log() << Verbose(0) << "Created new triangle " << *BTS << "." << endl;
1506 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1507 TrianglesOnBoundaryCount++;
1508 }
1509 }
1510 } else { // something is wrong with FindClosestTriangleToPoint!
1511 eLog() << Verbose(1) << "The closest triangle did not produce an intersection!" << endl;
1512 return false;
1513 }
1514 cloud->GoToNext();
1515 }
1516
1517 // exit
1518 delete(Center);
1519 return true;
1520};
1521
1522/** Adds a point to the tesselation::PointsOnBoundary list.
1523 * \param *Walker point to add
1524 * \param n TesselStruct::BPS index to put pointer into
1525 * \return true - new point was added, false - point already present
1526 */
1527bool Tesselation::AddBoundaryPoint(TesselPoint * Walker, const int n)
1528{
1529 Info FunctionInfo(__func__);
1530 PointTestPair InsertUnique;
1531 BPS[n] = new class BoundaryPointSet(Walker);
1532 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[n]));
1533 if (InsertUnique.second) { // if new point was not present before, increase counter
1534 PointsOnBoundaryCount++;
1535 return true;
1536 } else {
1537 delete(BPS[n]);
1538 BPS[n] = InsertUnique.first->second;
1539 return false;
1540 }
1541}
1542;
1543
1544/** Adds point to Tesselation::PointsOnBoundary if not yet present.
1545 * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
1546 * @param Candidate point to add
1547 * @param n index for this point in Tesselation::TPS array
1548 */
1549void Tesselation::AddTesselationPoint(TesselPoint* Candidate, const int n)
1550{
1551 Info FunctionInfo(__func__);
1552 PointTestPair InsertUnique;
1553 TPS[n] = new class BoundaryPointSet(Candidate);
1554 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
1555 if (InsertUnique.second) { // if new point was not present before, increase counter
1556 PointsOnBoundaryCount++;
1557 } else {
1558 delete TPS[n];
1559 Log() << Verbose(0) << "Node " << *((InsertUnique.first)->second->node) << " is already present in PointsOnBoundary." << endl;
1560 TPS[n] = (InsertUnique.first)->second;
1561 }
1562}
1563;
1564
1565/** Sets point to a present Tesselation::PointsOnBoundary.
1566 * Tesselation::TPS is set to the existing one or NULL if not found.
1567 * @param Candidate point to set to
1568 * @param n index for this point in Tesselation::TPS array
1569 */
1570void Tesselation::SetTesselationPoint(TesselPoint* Candidate, const int n) const
1571{
1572 Info FunctionInfo(__func__);
1573 PointMap::const_iterator FindPoint = PointsOnBoundary.find(Candidate->nr);
1574 if (FindPoint != PointsOnBoundary.end())
1575 TPS[n] = FindPoint->second;
1576 else
1577 TPS[n] = NULL;
1578};
1579
1580/** Function tries to add line from current Points in BPS to BoundaryLineSet.
1581 * If successful it raises the line count and inserts the new line into the BLS,
1582 * if unsuccessful, it writes the line which had been present into the BLS, deleting the new constructed one.
1583 * @param *a first endpoint
1584 * @param *b second endpoint
1585 * @param n index of Tesselation::BLS giving the line with both endpoints
1586 */
1587void Tesselation::AddTesselationLine(class BoundaryPointSet *a, class BoundaryPointSet *b, const int n) {
1588 bool insertNewLine = true;
1589
1590 LineMap::iterator FindLine = a->lines.find(b->node->nr);
1591 if (FindLine != a->lines.end()) {
1592 Log() << Verbose(1) << "INFO: There is at least one line between " << *a << " and " << *b << ": " << *(FindLine->second) << "." << endl;
1593
1594 pair<LineMap::iterator,LineMap::iterator> FindPair;
1595 FindPair = a->lines.equal_range(b->node->nr);
1596
1597 for (FindLine = FindPair.first; FindLine != FindPair.second; FindLine++) {
1598 // If there is a line with less than two attached triangles, we don't need a new line.
1599 if (FindLine->second->triangles.size() < 2) {
1600 insertNewLine = false;
1601 Log() << Verbose(0) << "Using existing line " << *FindLine->second << endl;
1602
1603 BPS[0] = FindLine->second->endpoints[0];
1604 BPS[1] = FindLine->second->endpoints[1];
1605 BLS[n] = FindLine->second;
1606
1607 // remove existing line from OpenLines
1608 CandidateMap::iterator CandidateLine = OpenLines.find(BLS[n]);
1609 if (CandidateLine != OpenLines.end()) {
1610 Log() << Verbose(1) << " Removing line from OpenLines." << endl;
1611 delete(CandidateLine->second);
1612 OpenLines.erase(CandidateLine);
1613 } else {
1614 eLog() << Verbose(1) << "Line exists and is attached to less than two triangles, but not in OpenLines!" << endl;
1615 }
1616
1617 break;
1618 }
1619 }
1620 }
1621
1622 if (insertNewLine) {
1623 AlwaysAddTesselationTriangleLine(a, b, n);
1624 }
1625}
1626;
1627
1628/**
1629 * Adds lines from each of the current points in the BPS to BoundaryLineSet.
1630 * Raises the line count and inserts the new line into the BLS.
1631 *
1632 * @param *a first endpoint
1633 * @param *b second endpoint
1634 * @param n index of Tesselation::BLS giving the line with both endpoints
1635 */
1636void Tesselation::AlwaysAddTesselationTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, const int n)
1637{
1638 Info FunctionInfo(__func__);
1639 Log() << Verbose(0) << "Adding open line [" << LinesOnBoundaryCount << "|" << *(a->node) << " and " << *(b->node) << "." << endl;
1640 BPS[0] = a;
1641 BPS[1] = b;
1642 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); // this also adds the line to the local maps
1643 // add line to global map
1644 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
1645 // increase counter
1646 LinesOnBoundaryCount++;
1647 // also add to open lines
1648 CandidateForTesselation *CFT = new CandidateForTesselation(BLS[n]);
1649 OpenLines.insert(pair< BoundaryLineSet *, CandidateForTesselation *> (BLS[n], CFT));
1650};
1651
1652/** Function adds triangle to global list.
1653 * Furthermore, the triangle receives the next free id and id counter \a TrianglesOnBoundaryCount is increased.
1654 */
1655void Tesselation::AddTesselationTriangle()
1656{
1657 Info FunctionInfo(__func__);
1658 Log() << Verbose(1) << "Adding triangle to global TrianglesOnBoundary map." << endl;
1659
1660 // add triangle to global map
1661 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1662 TrianglesOnBoundaryCount++;
1663
1664 // set as last new triangle
1665 LastTriangle = BTS;
1666
1667 // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
1668};
1669
1670/** Function adds triangle to global list.
1671 * Furthermore, the triangle number is set to \a nr.
1672 * \param nr triangle number
1673 */
1674void Tesselation::AddTesselationTriangle(const int nr)
1675{
1676 Info FunctionInfo(__func__);
1677 Log() << Verbose(0) << "Adding triangle to global TrianglesOnBoundary map." << endl;
1678
1679 // add triangle to global map
1680 TrianglesOnBoundary.insert(TrianglePair(nr, BTS));
1681
1682 // set as last new triangle
1683 LastTriangle = BTS;
1684
1685 // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
1686};
1687
1688/** Removes a triangle from the tesselation.
1689 * Removes itself from the TriangleMap's of its lines, calls for them RemoveTriangleLine() if they are no more connected.
1690 * Removes itself from memory.
1691 * \param *triangle to remove
1692 */
1693void Tesselation::RemoveTesselationTriangle(class BoundaryTriangleSet *triangle)
1694{
1695 Info FunctionInfo(__func__);
1696 if (triangle == NULL)
1697 return;
1698 for (int i = 0; i < 3; i++) {
1699 if (triangle->lines[i] != NULL) {
1700 Log() << Verbose(0) << "Removing triangle Nr." << triangle->Nr << " in line " << *triangle->lines[i] << "." << endl;
1701 triangle->lines[i]->triangles.erase(triangle->Nr);
1702 if (triangle->lines[i]->triangles.empty()) {
1703 Log() << Verbose(0) << *triangle->lines[i] << " is no more attached to any triangle, erasing." << endl;
1704 RemoveTesselationLine(triangle->lines[i]);
1705 } else {
1706 Log() << Verbose(0) << *triangle->lines[i] << " is still attached to another triangle: ";
1707 OpenLines.insert(pair< BoundaryLineSet *, CandidateForTesselation *> (triangle->lines[i], NULL));
1708 for(TriangleMap::iterator TriangleRunner = triangle->lines[i]->triangles.begin(); TriangleRunner != triangle->lines[i]->triangles.end(); TriangleRunner++)
1709 Log() << Verbose(0) << "[" << (TriangleRunner->second)->Nr << "|" << *((TriangleRunner->second)->endpoints[0]) << ", " << *((TriangleRunner->second)->endpoints[1]) << ", " << *((TriangleRunner->second)->endpoints[2]) << "] \t";
1710 Log() << Verbose(0) << endl;
1711// for (int j=0;j<2;j++) {
1712// Log() << Verbose(0) << "Lines of endpoint " << *(triangle->lines[i]->endpoints[j]) << ": ";
1713// for(LineMap::iterator LineRunner = triangle->lines[i]->endpoints[j]->lines.begin(); LineRunner != triangle->lines[i]->endpoints[j]->lines.end(); LineRunner++)
1714// Log() << Verbose(0) << "[" << *(LineRunner->second) << "] \t";
1715// Log() << Verbose(0) << endl;
1716// }
1717 }
1718 triangle->lines[i] = NULL; // free'd or not: disconnect
1719 } else
1720 eLog() << Verbose(1) << "This line " << i << " has already been free'd." << endl;
1721 }
1722
1723 if (TrianglesOnBoundary.erase(triangle->Nr))
1724 Log() << Verbose(0) << "Removing triangle Nr. " << triangle->Nr << "." << endl;
1725 delete(triangle);
1726};
1727
1728/** Removes a line from the tesselation.
1729 * Removes itself from each endpoints' LineMap, then removes itself from global LinesOnBoundary list and free's the line.
1730 * \param *line line to remove
1731 */
1732void Tesselation::RemoveTesselationLine(class BoundaryLineSet *line)
1733{
1734 Info FunctionInfo(__func__);
1735 int Numbers[2];
1736
1737 if (line == NULL)
1738 return;
1739 // get other endpoint number for finding copies of same line
1740 if (line->endpoints[1] != NULL)
1741 Numbers[0] = line->endpoints[1]->Nr;
1742 else
1743 Numbers[0] = -1;
1744 if (line->endpoints[0] != NULL)
1745 Numbers[1] = line->endpoints[0]->Nr;
1746 else
1747 Numbers[1] = -1;
1748
1749 for (int i = 0; i < 2; i++) {
1750 if (line->endpoints[i] != NULL) {
1751 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
1752 pair<LineMap::iterator, LineMap::iterator> erasor = line->endpoints[i]->lines.equal_range(Numbers[i]);
1753 for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
1754 if ((*Runner).second == line) {
1755 Log() << Verbose(0) << "Removing Line Nr. " << line->Nr << " in boundary point " << *line->endpoints[i] << "." << endl;
1756 line->endpoints[i]->lines.erase(Runner);
1757 break;
1758 }
1759 } else { // there's just a single line left
1760 if (line->endpoints[i]->lines.erase(line->Nr))
1761 Log() << Verbose(0) << "Removing Line Nr. " << line->Nr << " in boundary point " << *line->endpoints[i] << "." << endl;
1762 }
1763 if (line->endpoints[i]->lines.empty()) {
1764 Log() << Verbose(0) << *line->endpoints[i] << " has no more lines it's attached to, erasing." << endl;
1765 RemoveTesselationPoint(line->endpoints[i]);
1766 } else {
1767 Log() << Verbose(0) << *line->endpoints[i] << " has still lines it's attached to: ";
1768 for(LineMap::iterator LineRunner = line->endpoints[i]->lines.begin(); LineRunner != line->endpoints[i]->lines.end(); LineRunner++)
1769 Log() << Verbose(0) << "[" << *(LineRunner->second) << "] \t";
1770 Log() << Verbose(0) << endl;
1771 }
1772 line->endpoints[i] = NULL; // free'd or not: disconnect
1773 } else
1774 eLog() << Verbose(1) << "Endpoint " << i << " has already been free'd." << endl;
1775 }
1776 if (!line->triangles.empty())
1777 eLog() << Verbose(2) << "Memory Leak! I " << *line << " am still connected to some triangles." << endl;
1778
1779 if (LinesOnBoundary.erase(line->Nr))
1780 Log() << Verbose(0) << "Removing line Nr. " << line->Nr << "." << endl;
1781 delete(line);
1782};
1783
1784/** Removes a point from the tesselation.
1785 * Checks whether there are still lines connected, removes from global PointsOnBoundary list, then free's the point.
1786 * \note If a point should be removed, while keep the tesselated surface intact (i.e. closed), use RemovePointFromTesselatedSurface()
1787 * \param *point point to remove
1788 */
1789void Tesselation::RemoveTesselationPoint(class BoundaryPointSet *point)
1790{
1791 Info FunctionInfo(__func__);
1792 if (point == NULL)
1793 return;
1794 if (PointsOnBoundary.erase(point->Nr))
1795 Log() << Verbose(0) << "Removing point Nr. " << point->Nr << "." << endl;
1796 delete(point);
1797};
1798
1799/** Checks whether the triangle consisting of the three points is already present.
1800 * Searches for the points in Tesselation::PointsOnBoundary and checks their
1801 * lines. If any of the three edges already has two triangles attached, false is
1802 * returned.
1803 * \param *out output stream for debugging
1804 * \param *Candidates endpoints of the triangle candidate
1805 * \return integer 0 if no triangle exists, 1 if one triangle exists, 2 if two
1806 * triangles exist which is the maximum for three points
1807 */
1808int Tesselation::CheckPresenceOfTriangle(TesselPoint *Candidates[3]) const
1809{
1810 Info FunctionInfo(__func__);
1811 int adjacentTriangleCount = 0;
1812 class BoundaryPointSet *Points[3];
1813
1814 // builds a triangle point set (Points) of the end points
1815 for (int i = 0; i < 3; i++) {
1816 PointMap::const_iterator FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
1817 if (FindPoint != PointsOnBoundary.end()) {
1818 Points[i] = FindPoint->second;
1819 } else {
1820 Points[i] = NULL;
1821 }
1822 }
1823
1824 // checks lines between the points in the Points for their adjacent triangles
1825 for (int i = 0; i < 3; i++) {
1826 if (Points[i] != NULL) {
1827 for (int j = i; j < 3; j++) {
1828 if (Points[j] != NULL) {
1829 LineMap::const_iterator FindLine = Points[i]->lines.find(Points[j]->node->nr);
1830 for (; (FindLine != Points[i]->lines.end()) && (FindLine->first == Points[j]->node->nr); FindLine++) {
1831 TriangleMap *triangles = &FindLine->second->triangles;
1832 Log() << Verbose(1) << "Current line is " << FindLine->first << ": " << *(FindLine->second) << " with triangles " << triangles << "." << endl;
1833 for (TriangleMap::const_iterator FindTriangle = triangles->begin(); FindTriangle != triangles->end(); FindTriangle++) {
1834 if (FindTriangle->second->IsPresentTupel(Points)) {
1835 adjacentTriangleCount++;
1836 }
1837 }
1838 Log() << Verbose(1) << "end." << endl;
1839 }
1840 // Only one of the triangle lines must be considered for the triangle count.
1841 //Log() << Verbose(0) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1842 //return adjacentTriangleCount;
1843 }
1844 }
1845 }
1846 }
1847
1848 Log() << Verbose(0) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1849 return adjacentTriangleCount;
1850};
1851
1852/** Checks whether the triangle consisting of the three points is already present.
1853 * Searches for the points in Tesselation::PointsOnBoundary and checks their
1854 * lines. If any of the three edges already has two triangles attached, false is
1855 * returned.
1856 * \param *out output stream for debugging
1857 * \param *Candidates endpoints of the triangle candidate
1858 * \return NULL - none found or pointer to triangle
1859 */
1860class BoundaryTriangleSet * Tesselation::GetPresentTriangle(TesselPoint *Candidates[3])
1861{
1862 Info FunctionInfo(__func__);
1863 class BoundaryTriangleSet *triangle = NULL;
1864 class BoundaryPointSet *Points[3];
1865
1866 // builds a triangle point set (Points) of the end points
1867 for (int i = 0; i < 3; i++) {
1868 PointMap::iterator FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
1869 if (FindPoint != PointsOnBoundary.end()) {
1870 Points[i] = FindPoint->second;
1871 } else {
1872 Points[i] = NULL;
1873 }
1874 }
1875
1876 // checks lines between the points in the Points for their adjacent triangles
1877 for (int i = 0; i < 3; i++) {
1878 if (Points[i] != NULL) {
1879 for (int j = i; j < 3; j++) {
1880 if (Points[j] != NULL) {
1881 LineMap::iterator FindLine = Points[i]->lines.find(Points[j]->node->nr);
1882 for (; (FindLine != Points[i]->lines.end()) && (FindLine->first == Points[j]->node->nr); FindLine++) {
1883 TriangleMap *triangles = &FindLine->second->triangles;
1884 for (TriangleMap::iterator FindTriangle = triangles->begin(); FindTriangle != triangles->end(); FindTriangle++) {
1885 if (FindTriangle->second->IsPresentTupel(Points)) {
1886 if ((triangle == NULL) || (triangle->Nr > FindTriangle->second->Nr))
1887 triangle = FindTriangle->second;
1888 }
1889 }
1890 }
1891 // Only one of the triangle lines must be considered for the triangle count.
1892 //Log() << Verbose(0) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1893 //return adjacentTriangleCount;
1894 }
1895 }
1896 }
1897 }
1898
1899 return triangle;
1900};
1901
1902
1903/** Finds the starting triangle for FindNonConvexBorder().
1904 * Looks at the outermost point per axis, then FindSecondPointForTesselation()
1905 * for the second and FindNextSuitablePointViaAngleOfSphere() for the third
1906 * point are called.
1907 * \param *out output stream for debugging
1908 * \param RADIUS radius of virtual rolling sphere
1909 * \param *LC LinkedCell structure with neighbouring TesselPoint's
1910 */
1911void Tesselation::FindStartingTriangle(const double RADIUS, const LinkedCell *LC)
1912{
1913 Info FunctionInfo(__func__);
1914 int i = 0;
1915 TesselPoint* MaxPoint[NDIM];
1916 TesselPoint* Temporary;
1917 double maxCoordinate[NDIM];
1918 BoundaryLineSet BaseLine;
1919 Vector helper;
1920 Vector Chord;
1921 Vector SearchDirection;
1922 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers
1923 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
1924 Vector SphereCenter;
1925 Vector NormalVector;
1926
1927 NormalVector.Zero();
1928
1929 for (i = 0; i < 3; i++) {
1930 MaxPoint[i] = NULL;
1931 maxCoordinate[i] = -1;
1932 }
1933
1934 // 1. searching topmost point with respect to each axis
1935 for (int i=0;i<NDIM;i++) { // each axis
1936 LC->n[i] = LC->N[i]-1; // current axis is topmost cell
1937 for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++)
1938 for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) {
1939 const LinkedNodes *List = LC->GetCurrentCell();
1940 //Log() << Verbose(1) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1941 if (List != NULL) {
1942 for (LinkedNodes::const_iterator Runner = List->begin();Runner != List->end();Runner++) {
1943 if ((*Runner)->node->x[i] > maxCoordinate[i]) {
1944 Log() << Verbose(1) << "New maximal for axis " << i << " node is " << *(*Runner) << " at " << *(*Runner)->node << "." << endl;
1945 maxCoordinate[i] = (*Runner)->node->x[i];
1946 MaxPoint[i] = (*Runner);
1947 }
1948 }
1949 } else {
1950 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
1951 }
1952 }
1953 }
1954
1955 Log() << Verbose(1) << "Found maximum coordinates: ";
1956 for (int i=0;i<NDIM;i++)
1957 Log() << Verbose(0) << i << ": " << *MaxPoint[i] << "\t";
1958 Log() << Verbose(0) << endl;
1959
1960 BTS = NULL;
1961 for (int k=0;k<NDIM;k++) {
1962 NormalVector.Zero();
1963 NormalVector.x[k] = 1.;
1964 BaseLine.endpoints[0] = new BoundaryPointSet(MaxPoint[k]);
1965 Log() << Verbose(0) << "Coordinates of start node at " << *BaseLine.endpoints[0]->node << "." << endl;
1966
1967 double ShortestAngle;
1968 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.
1969
1970 FindSecondPointForTesselation(BaseLine.endpoints[0]->node, NormalVector, Temporary, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
1971 if (Temporary == NULL) // have we found a second point?
1972 continue;
1973 BaseLine.endpoints[1] = new BoundaryPointSet(Temporary);
1974
1975 // construct center of circle
1976 CircleCenter.CopyVector(BaseLine.endpoints[0]->node->node);
1977 CircleCenter.AddVector(BaseLine.endpoints[1]->node->node);
1978 CircleCenter.Scale(0.5);
1979
1980 // construct normal vector of circle
1981 CirclePlaneNormal.CopyVector(BaseLine.endpoints[0]->node->node);
1982 CirclePlaneNormal.SubtractVector(BaseLine.endpoints[1]->node->node);
1983
1984 double radius = CirclePlaneNormal.NormSquared();
1985 double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.);
1986
1987 NormalVector.ProjectOntoPlane(&CirclePlaneNormal);
1988 NormalVector.Normalize();
1989 ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1990
1991 SphereCenter.CopyVector(&NormalVector);
1992 SphereCenter.Scale(CircleRadius);
1993 SphereCenter.AddVector(&CircleCenter);
1994 // Now, NormalVector and SphereCenter are two orthonormalized vectors in the plane defined by CirclePlaneNormal (not normalized)
1995
1996 // look in one direction of baseline for initial candidate
1997 SearchDirection.MakeNormalVector(&CirclePlaneNormal, &NormalVector); // whether we look "left" first or "right" first is not important ...
1998
1999 // adding point 1 and point 2 and add the line between them
2000 Log() << Verbose(0) << "Coordinates of start node at " << *BaseLine.endpoints[0]->node << "." << endl;
2001 Log() << Verbose(0) << "Found second point is at " << *BaseLine.endpoints[1]->node << ".\n";
2002
2003 //Log() << Verbose(1) << "INFO: OldSphereCenter is at " << helper << ".\n";
2004 CandidateForTesselation OptCandidates(&BaseLine);
2005 FindThirdPointForTesselation(NormalVector, SearchDirection, SphereCenter, OptCandidates, NULL, RADIUS, LC);
2006 Log() << Verbose(0) << "List of third Points is:" << endl;
2007 for (TesselPointList::iterator it = OptCandidates.pointlist.begin(); it != OptCandidates.pointlist.end(); it++) {
2008 Log() << Verbose(0) << " " << *(*it) << endl;
2009 }
2010
2011 BTS = NULL;
2012 AddCandidateTriangle(OptCandidates);
2013// delete(BaseLine.endpoints[0]);
2014// delete(BaseLine.endpoints[1]);
2015
2016 if (BTS != NULL) // we have created one starting triangle
2017 break;
2018 else {
2019 // remove all candidates from the list and then the list itself
2020 OptCandidates.pointlist.clear();
2021 }
2022 }
2023};
2024
2025/** Checks for a given baseline and a third point candidate whether baselines of the found triangle don't have even better candidates.
2026 * This is supposed to prevent early closing of the tesselation.
2027 * \param CandidateLine CandidateForTesselation with baseline and shortestangle , i.e. not \a *OptCandidate
2028 * \param *ThirdNode third point in triangle, not in BoundaryLineSet::endpoints
2029 * \param RADIUS radius of sphere
2030 * \param *LC LinkedCell structure
2031 * \return true - there is a better candidate (smaller angle than \a ShortestAngle), false - no better TesselPoint candidate found
2032 */
2033//bool Tesselation::HasOtherBaselineBetterCandidate(CandidateForTesselation &CandidateLine, const TesselPoint * const ThirdNode, double RADIUS, const LinkedCell * const LC) const
2034//{
2035// Info FunctionInfo(__func__);
2036// bool result = false;
2037// Vector CircleCenter;
2038// Vector CirclePlaneNormal;
2039// Vector OldSphereCenter;
2040// Vector SearchDirection;
2041// Vector helper;
2042// TesselPoint *OtherOptCandidate = NULL;
2043// double OtherShortestAngle = 2.*M_PI; // This will indicate the quadrant.
2044// double radius, CircleRadius;
2045// BoundaryLineSet *Line = NULL;
2046// BoundaryTriangleSet *T = NULL;
2047//
2048// // check both other lines
2049// PointMap::const_iterator FindPoint = PointsOnBoundary.find(ThirdNode->nr);
2050// if (FindPoint != PointsOnBoundary.end()) {
2051// for (int i=0;i<2;i++) {
2052// LineMap::const_iterator FindLine = (FindPoint->second)->lines.find(BaseRay->endpoints[0]->node->nr);
2053// if (FindLine != (FindPoint->second)->lines.end()) {
2054// Line = FindLine->second;
2055// Log() << Verbose(0) << "Found line " << *Line << "." << endl;
2056// if (Line->triangles.size() == 1) {
2057// T = Line->triangles.begin()->second;
2058// // construct center of circle
2059// CircleCenter.CopyVector(Line->endpoints[0]->node->node);
2060// CircleCenter.AddVector(Line->endpoints[1]->node->node);
2061// CircleCenter.Scale(0.5);
2062//
2063// // construct normal vector of circle
2064// CirclePlaneNormal.CopyVector(Line->endpoints[0]->node->node);
2065// CirclePlaneNormal.SubtractVector(Line->endpoints[1]->node->node);
2066//
2067// // calculate squared radius of circle
2068// radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
2069// if (radius/4. < RADIUS*RADIUS) {
2070// CircleRadius = RADIUS*RADIUS - radius/4.;
2071// CirclePlaneNormal.Normalize();
2072// //Log() << Verbose(1) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
2073//
2074// // construct old center
2075// GetCenterofCircumcircle(&OldSphereCenter, *T->endpoints[0]->node->node, *T->endpoints[1]->node->node, *T->endpoints[2]->node->node);
2076// helper.CopyVector(&T->NormalVector); // normal vector ensures that this is correct center of the two possible ones
2077// radius = Line->endpoints[0]->node->node->DistanceSquared(&OldSphereCenter);
2078// helper.Scale(sqrt(RADIUS*RADIUS - radius));
2079// OldSphereCenter.AddVector(&helper);
2080// OldSphereCenter.SubtractVector(&CircleCenter);
2081// //Log() << Verbose(1) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
2082//
2083// // construct SearchDirection
2084// SearchDirection.MakeNormalVector(&T->NormalVector, &CirclePlaneNormal);
2085// helper.CopyVector(Line->endpoints[0]->node->node);
2086// helper.SubtractVector(ThirdNode->node);
2087// if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
2088// SearchDirection.Scale(-1.);
2089// SearchDirection.ProjectOntoPlane(&OldSphereCenter);
2090// SearchDirection.Normalize();
2091// Log() << Verbose(1) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
2092// if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
2093// // rotated the wrong way!
2094// eLog() << Verbose(1) << "SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
2095// }
2096//
2097// // add third point
2098// FindThirdPointForTesselation(T->NormalVector, SearchDirection, OldSphereCenter, OptCandidates, ThirdNode, RADIUS, LC);
2099// for (TesselPointList::iterator it = OptCandidates.pointlist.begin(); it != OptCandidates.pointlist.end(); ++it) {
2100// if (((*it) == BaseRay->endpoints[0]->node) || ((*it) == BaseRay->endpoints[1]->node)) // skip if it's the same triangle than suggested
2101// continue;
2102// Log() << Verbose(0) << " Third point candidate is " << (*it)
2103// << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
2104// Log() << Verbose(0) << " Baseline is " << *BaseRay << endl;
2105//
2106// // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
2107// TesselPoint *PointCandidates[3];
2108// PointCandidates[0] = (*it);
2109// PointCandidates[1] = BaseRay->endpoints[0]->node;
2110// PointCandidates[2] = BaseRay->endpoints[1]->node;
2111// bool check=false;
2112// int existentTrianglesCount = CheckPresenceOfTriangle(PointCandidates);
2113// // If there is no triangle, add it regularly.
2114// if (existentTrianglesCount == 0) {
2115// SetTesselationPoint((*it), 0);
2116// SetTesselationPoint(BaseRay->endpoints[0]->node, 1);
2117// SetTesselationPoint(BaseRay->endpoints[1]->node, 2);
2118//
2119// if (CheckLineCriteriaForDegeneratedTriangle((const BoundaryPointSet ** const )TPS)) {
2120// OtherOptCandidate = (*it);
2121// check = true;
2122// }
2123// } else if ((existentTrianglesCount >= 1) && (existentTrianglesCount <= 3)) { // If there is a planar region within the structure, we need this triangle a second time.
2124// SetTesselationPoint((*it), 0);
2125// SetTesselationPoint(BaseRay->endpoints[0]->node, 1);
2126// SetTesselationPoint(BaseRay->endpoints[1]->node, 2);
2127//
2128// // 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)
2129// // i.e. at least one of the three lines must be present with TriangleCount <= 1
2130// if (CheckLineCriteriaForDegeneratedTriangle((const BoundaryPointSet ** const)TPS)) {
2131// OtherOptCandidate = (*it);
2132// check = true;
2133// }
2134// }
2135//
2136// if (check) {
2137// if (ShortestAngle > OtherShortestAngle) {
2138// Log() << Verbose(0) << "There is a better candidate than " << *ThirdNode << " with " << ShortestAngle << " from baseline " << *Line << ": " << *OtherOptCandidate << " with " << OtherShortestAngle << "." << endl;
2139// result = true;
2140// break;
2141// }
2142// }
2143// }
2144// delete(OptCandidates);
2145// if (result)
2146// break;
2147// } else {
2148// Log() << Verbose(0) << "Circumcircle for base line " << *Line << " and base triangle " << T << " is too big!" << endl;
2149// }
2150// } else {
2151// eLog() << Verbose(2) << "Baseline is connected to two triangles already?" << endl;
2152// }
2153// } else {
2154// Log() << Verbose(1) << "No present baseline between " << BaseRay->endpoints[0] << " and candidate " << *ThirdNode << "." << endl;
2155// }
2156// }
2157// } else {
2158// eLog() << Verbose(1) << "Could not find the TesselPoint " << *ThirdNode << "." << endl;
2159// }
2160//
2161// return result;
2162//};
2163
2164/** This function finds a triangle to a line, adjacent to an existing one.
2165 * @param out output stream for debugging
2166 * @param CandidateLine current cadndiate baseline to search from
2167 * @param T current triangle which \a Line is edge of
2168 * @param RADIUS radius of the rolling ball
2169 * @param N number of found triangles
2170 * @param *LC LinkedCell structure with neighbouring points
2171 */
2172bool Tesselation::FindNextSuitableTriangle(CandidateForTesselation &CandidateLine, BoundaryTriangleSet &T, const double& RADIUS, const LinkedCell *LC)
2173{
2174 Info FunctionInfo(__func__);
2175 bool result = true;
2176
2177 Vector CircleCenter;
2178 Vector CirclePlaneNormal;
2179 Vector RelativeSphereCenter;
2180 Vector SearchDirection;
2181 Vector helper;
2182 TesselPoint *ThirdNode = NULL;
2183 LineMap::iterator testline;
2184 double radius, CircleRadius;
2185
2186 for (int i=0;i<3;i++)
2187 if ((T.endpoints[i]->node != CandidateLine.BaseLine->endpoints[0]->node) && (T.endpoints[i]->node != CandidateLine.BaseLine->endpoints[1]->node)) {
2188 ThirdNode = T.endpoints[i]->node;
2189 break;
2190 }
2191 Log() << Verbose(0) << "Current baseline is " << *CandidateLine.BaseLine << " with ThirdNode " << *ThirdNode << " of triangle " << T << "." << endl;
2192
2193 // construct center of circle
2194 CircleCenter.CopyVector(CandidateLine.BaseLine->endpoints[0]->node->node);
2195 CircleCenter.AddVector(CandidateLine.BaseLine->endpoints[1]->node->node);
2196 CircleCenter.Scale(0.5);
2197
2198 // construct normal vector of circle
2199 CirclePlaneNormal.CopyVector(CandidateLine.BaseLine->endpoints[0]->node->node);
2200 CirclePlaneNormal.SubtractVector(CandidateLine.BaseLine->endpoints[1]->node->node);
2201
2202 // calculate squared radius of circle
2203 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
2204 if (radius/4. < RADIUS*RADIUS) {
2205 // construct relative sphere center with now known CircleCenter
2206 RelativeSphereCenter.CopyVector(&T.SphereCenter);
2207 RelativeSphereCenter.SubtractVector(&CircleCenter);
2208
2209 CircleRadius = RADIUS*RADIUS - radius/4.;
2210 CirclePlaneNormal.Normalize();
2211 Log() << Verbose(1) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
2212
2213 Log() << Verbose(1) << "INFO: OldSphereCenter is at " << T.SphereCenter << "." << endl;
2214
2215 // construct SearchDirection and an "outward pointer"
2216 SearchDirection.MakeNormalVector(&RelativeSphereCenter, &CirclePlaneNormal);
2217 helper.CopyVector(&CircleCenter);
2218 helper.SubtractVector(ThirdNode->node);
2219 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
2220 SearchDirection.Scale(-1.);
2221 Log() << Verbose(1) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
2222 if (fabs(RelativeSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
2223 // rotated the wrong way!
2224 eLog() << Verbose(1) << "SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
2225 }
2226
2227 // add third point
2228 FindThirdPointForTesselation(T.NormalVector, SearchDirection, T.SphereCenter, CandidateLine, ThirdNode, RADIUS, LC);
2229
2230 } else {
2231 Log() << Verbose(0) << "Circumcircle for base line " << *CandidateLine.BaseLine << " and base triangle " << T << " is too big!" << endl;
2232 }
2233
2234 if (CandidateLine.pointlist.empty()) {
2235 eLog() << Verbose(2) << "Could not find a suitable candidate." << endl;
2236 return false;
2237 }
2238 Log() << Verbose(0) << "Third Points are: " << endl;
2239 for (TesselPointList::iterator it = CandidateLine.pointlist.begin(); it != CandidateLine.pointlist.end(); ++it) {
2240 Log() << Verbose(0) << " " << *(*it) << endl;
2241 }
2242
2243 return true;
2244
2245// BoundaryLineSet *BaseRay = CandidateLine.BaseLine;
2246// for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
2247// Log() << Verbose(0) << "Third point candidate is " << *(*it)->point
2248// << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
2249// Log() << Verbose(0) << "Baseline is " << *BaseRay << endl;
2250//
2251// // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
2252// TesselPoint *PointCandidates[3];
2253// PointCandidates[0] = (*it)->point;
2254// PointCandidates[1] = BaseRay->endpoints[0]->node;
2255// PointCandidates[2] = BaseRay->endpoints[1]->node;
2256// int existentTrianglesCount = CheckPresenceOfTriangle(PointCandidates);
2257//
2258// BTS = NULL;
2259// // check for present edges and whether we reach better candidates from them
2260// //if (HasOtherBaselineBetterCandidate(BaseRay, (*it)->point, ShortestAngle, RADIUS, LC) ) {
2261// if (0) {
2262// result = false;
2263// break;
2264// } else {
2265// // If there is no triangle, add it regularly.
2266// if (existentTrianglesCount == 0) {
2267// AddTesselationPoint((*it)->point, 0);
2268// AddTesselationPoint(BaseRay->endpoints[0]->node, 1);
2269// AddTesselationPoint(BaseRay->endpoints[1]->node, 2);
2270//
2271// if (CheckLineCriteriaForDegeneratedTriangle((const BoundaryPointSet ** const )TPS)) {
2272// CandidateLine.point = (*it)->point;
2273// CandidateLine.OptCenter.CopyVector(&((*it)->OptCenter));
2274// CandidateLine.OtherOptCenter.CopyVector(&((*it)->OtherOptCenter));
2275// CandidateLine.ShortestAngle = ShortestAngle;
2276// } else {
2277//// eLog() << Verbose(1) << "This triangle consisting of ";
2278//// Log() << Verbose(0) << *(*it)->point << ", ";
2279//// Log() << Verbose(0) << *BaseRay->endpoints[0]->node << " and ";
2280//// Log() << Verbose(0) << *BaseRay->endpoints[1]->node << " ";
2281//// Log() << Verbose(0) << "exists and is not added, as it 0x80000000006fc150(does not seem helpful!" << endl;
2282// result = false;
2283// }
2284// } else if ((existentTrianglesCount >= 1) && (existentTrianglesCount <= 3)) { // If there is a planar region within the structure, we need this triangle a second time.
2285// AddTesselationPoint((*it)->point, 0);
2286// AddTesselationPoint(BaseRay->endpoints[0]->node, 1);
2287// AddTesselationPoint(BaseRay->endpoints[1]->node, 2);
2288//
2289// // 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)
2290// // i.e. at least one of the three lines must be present with TriangleCount <= 1
2291// if (CheckLineCriteriaForDegeneratedTriangle((const BoundaryPointSet ** const)TPS) || CandidateLine.BaseLine->skipped) {
2292// CandidateLine.point = (*it)->point;
2293// CandidateLine.OptCenter.CopyVector(&(*it)->OptCenter);
2294// CandidateLine.OtherOptCenter.CopyVector(&(*it)->OtherOptCenter);
2295// CandidateLine.ShortestAngle = ShortestAngle+2.*M_PI;
2296//
2297// } else {
2298//// eLog() << Verbose(1) << "This triangle consisting of " << *(*it)->point << ", " << *BaseRay->endpoints[0]->node << " and " << *BaseRay->endpoints[1]->node << " " << "exists and is not added, as it does not seem helpful!" << endl;
2299// result = false;
2300// }
2301// } else {
2302//// Log() << Verbose(1) << "This triangle consisting of ";
2303//// Log() << Verbose(0) << *(*it)->point << ", ";
2304//// Log() << Verbose(0) << *BaseRay->endpoints[0]->node << " and ";
2305//// Log() << Verbose(0) << *BaseRay->endpoints[1]->node << " ";
2306//// Log() << Verbose(0) << "is invalid!" << endl;
2307// result = false;
2308// }
2309// }
2310//
2311// // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
2312// BaseRay = BLS[0];
2313// if ((BTS != NULL) && (BTS->NormalVector.NormSquared() < MYEPSILON)) {
2314// eLog() << Verbose(1) << "Triangle " << *BTS << " has zero normal vector!" << endl;
2315// exit(255);
2316// }
2317//
2318// }
2319//
2320// // remove all candidates from the list and then the list itself
2321// class CandidateForTesselation *remover = NULL;
2322// for (CandidateList::iterator it = OptCandidates->begin(); it != OptCandidates->end(); ++it) {
2323// remover = *it;
2324// delete(remover);
2325// }
2326// delete(OptCandidates);
2327 return result;
2328};
2329
2330/** Adds the present line and candidate point from \a &CandidateLine to the Tesselation.
2331 * \param CandidateLine triangle to add
2332 * \NOTE we need the copy operator here as the original CandidateForTesselation is removed in AddTesselationLine()
2333 */
2334void Tesselation::AddCandidateTriangle(CandidateForTesselation CandidateLine)
2335{
2336 Info FunctionInfo(__func__);
2337 Vector Center;
2338 TesselPoint * const TurningPoint = CandidateLine.BaseLine->endpoints[0]->node;
2339
2340 // fill the set of neighbours
2341 Center.CopyVector(CandidateLine.BaseLine->endpoints[1]->node->node);
2342 Center.SubtractVector(TurningPoint->node);
2343 set<TesselPoint*> SetOfNeighbours;
2344 SetOfNeighbours.insert(CandidateLine.BaseLine->endpoints[1]->node);
2345 for (TesselPointList::iterator Runner = CandidateLine.pointlist.begin(); Runner != CandidateLine.pointlist.end(); Runner++)
2346 SetOfNeighbours.insert(*Runner);
2347 TesselPointList *connectedClosestPoints = GetCircleOfSetOfPoints(&SetOfNeighbours, TurningPoint, &Center);
2348
2349 // go through all angle-sorted candidates (in degenerate n-nodes case we may have to add multiple triangles)
2350 TesselPointList::iterator Runner = connectedClosestPoints->begin();
2351 TesselPointList::iterator Sprinter = Runner;
2352 Sprinter++;
2353 while(Sprinter != connectedClosestPoints->end()) {
2354 // add the points
2355 AddTesselationPoint(TurningPoint, 0);
2356 AddTesselationPoint((*Runner), 1);
2357 AddTesselationPoint((*Sprinter), 2);
2358
2359
2360 // add the lines
2361 AddTesselationLine(TPS[0], TPS[1], 0);
2362 AddTesselationLine(TPS[0], TPS[2], 1);
2363 AddTesselationLine(TPS[1], TPS[2], 2);
2364
2365 // add the triangles
2366 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
2367 AddTesselationTriangle();
2368 BTS->GetCenter(&Center);
2369 Center.SubtractVector(&CandidateLine.OptCenter);
2370 BTS->SphereCenter.CopyVector(&CandidateLine.OptCenter);
2371 BTS->GetNormalVector(Center);
2372
2373 Log() << Verbose(0) << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector << "." << endl;
2374 Runner = Sprinter;
2375 Sprinter++;
2376 }
2377 delete(connectedClosestPoints);
2378};
2379
2380/** Checks whether the quadragon of the two triangles connect to \a *Base is convex.
2381 * We look whether the closest point on \a *Base with respect to the other baseline is outside
2382 * of the segment formed by both endpoints (concave) or not (convex).
2383 * \param *out output stream for debugging
2384 * \param *Base line to be flipped
2385 * \return NULL - convex, otherwise endpoint that makes it concave
2386 */
2387class BoundaryPointSet *Tesselation::IsConvexRectangle(class BoundaryLineSet *Base)
2388{
2389 Info FunctionInfo(__func__);
2390 class BoundaryPointSet *Spot = NULL;
2391 class BoundaryLineSet *OtherBase;
2392 Vector *ClosestPoint;
2393
2394 int m=0;
2395 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
2396 for (int j=0;j<3;j++) // all of their endpoints and baselines
2397 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) // and neither of its endpoints
2398 BPS[m++] = runner->second->endpoints[j];
2399 OtherBase = new class BoundaryLineSet(BPS,-1);
2400
2401 Log() << Verbose(1) << "INFO: Current base line is " << *Base << "." << endl;
2402 Log() << Verbose(1) << "INFO: Other base line is " << *OtherBase << "." << endl;
2403
2404 // get the closest point on each line to the other line
2405 ClosestPoint = GetClosestPointBetweenLine(Base, OtherBase);
2406
2407 // delete the temporary other base line
2408 delete(OtherBase);
2409
2410 // get the distance vector from Base line to OtherBase line
2411 Vector DistanceToIntersection[2], BaseLine;
2412 double distance[2];
2413 BaseLine.CopyVector(Base->endpoints[1]->node->node);
2414 BaseLine.SubtractVector(Base->endpoints[0]->node->node);
2415 for (int i=0;i<2;i++) {
2416 DistanceToIntersection[i].CopyVector(ClosestPoint);
2417 DistanceToIntersection[i].SubtractVector(Base->endpoints[i]->node->node);
2418 distance[i] = BaseLine.ScalarProduct(&DistanceToIntersection[i]);
2419 }
2420 delete(ClosestPoint);
2421 if ((distance[0] * distance[1]) > 0) { // have same sign?
2422 Log() << Verbose(1) << "REJECT: Both SKPs have same sign: " << distance[0] << " and " << distance[1] << ". " << *Base << "' rectangle is concave." << endl;
2423 if (distance[0] < distance[1]) {
2424 Spot = Base->endpoints[0];
2425 } else {
2426 Spot = Base->endpoints[1];
2427 }
2428 return Spot;
2429 } else { // different sign, i.e. we are in between
2430 Log() << Verbose(0) << "ACCEPT: Rectangle of triangles of base line " << *Base << " is convex." << endl;
2431 return NULL;
2432 }
2433
2434};
2435
2436void Tesselation::PrintAllBoundaryPoints(ofstream *out) const
2437{
2438 Info FunctionInfo(__func__);
2439 // print all lines
2440 Log() << Verbose(0) << "Printing all boundary points for debugging:" << endl;
2441 for (PointMap::const_iterator PointRunner = PointsOnBoundary.begin();PointRunner != PointsOnBoundary.end(); PointRunner++)
2442 Log() << Verbose(0) << *(PointRunner->second) << endl;
2443};
2444
2445void Tesselation::PrintAllBoundaryLines(ofstream *out) const
2446{
2447 Info FunctionInfo(__func__);
2448 // print all lines
2449 Log() << Verbose(0) << "Printing all boundary lines for debugging:" << endl;
2450 for (LineMap::const_iterator LineRunner = LinesOnBoundary.begin(); LineRunner != LinesOnBoundary.end(); LineRunner++)
2451 Log() << Verbose(0) << *(LineRunner->second) << endl;
2452};
2453
2454void Tesselation::PrintAllBoundaryTriangles(ofstream *out) const
2455{
2456 Info FunctionInfo(__func__);
2457 // print all triangles
2458 Log() << Verbose(0) << "Printing all boundary triangles for debugging:" << endl;
2459 for (TriangleMap::const_iterator TriangleRunner = TrianglesOnBoundary.begin(); TriangleRunner != TrianglesOnBoundary.end(); TriangleRunner++)
2460 Log() << Verbose(0) << *(TriangleRunner->second) << endl;
2461};
2462
2463/** For a given boundary line \a *Base and its two triangles, picks the central baseline that is "higher".
2464 * \param *out output stream for debugging
2465 * \param *Base line to be flipped
2466 * \return volume change due to flipping (0 - then no flipped occured)
2467 */
2468double Tesselation::PickFarthestofTwoBaselines(class BoundaryLineSet *Base)
2469{
2470 Info FunctionInfo(__func__);
2471 class BoundaryLineSet *OtherBase;
2472 Vector *ClosestPoint[2];
2473 double volume;
2474
2475 int m=0;
2476 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
2477 for (int j=0;j<3;j++) // all of their endpoints and baselines
2478 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) // and neither of its endpoints
2479 BPS[m++] = runner->second->endpoints[j];
2480 OtherBase = new class BoundaryLineSet(BPS,-1);
2481
2482 Log() << Verbose(0) << "INFO: Current base line is " << *Base << "." << endl;
2483 Log() << Verbose(0) << "INFO: Other base line is " << *OtherBase << "." << endl;
2484
2485 // get the closest point on each line to the other line
2486 ClosestPoint[0] = GetClosestPointBetweenLine(Base, OtherBase);
2487 ClosestPoint[1] = GetClosestPointBetweenLine(OtherBase, Base);
2488
2489 // get the distance vector from Base line to OtherBase line
2490 Vector Distance;
2491 Distance.CopyVector(ClosestPoint[1]);
2492 Distance.SubtractVector(ClosestPoint[0]);
2493
2494 // calculate volume
2495 volume = CalculateVolumeofGeneralTetraeder(*Base->endpoints[1]->node->node, *OtherBase->endpoints[0]->node->node, *OtherBase->endpoints[1]->node->node, *Base->endpoints[0]->node->node);
2496
2497 // delete the temporary other base line and the closest points
2498 delete(ClosestPoint[0]);
2499 delete(ClosestPoint[1]);
2500 delete(OtherBase);
2501
2502 if (Distance.NormSquared() < MYEPSILON) { // check for intersection
2503 Log() << Verbose(0) << "REJECT: Both lines have an intersection: Nothing to do." << endl;
2504 return false;
2505 } else { // check for sign against BaseLineNormal
2506 Vector BaseLineNormal;
2507 BaseLineNormal.Zero();
2508 if (Base->triangles.size() < 2) {
2509 eLog() << Verbose(1) << "Less than two triangles are attached to this baseline!" << endl;
2510 return 0.;
2511 }
2512 for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
2513 Log() << Verbose(1) << "INFO: Adding NormalVector " << runner->second->NormalVector << " of triangle " << *(runner->second) << "." << endl;
2514 BaseLineNormal.AddVector(&(runner->second->NormalVector));
2515 }
2516 BaseLineNormal.Scale(1./2.);
2517
2518 if (Distance.ScalarProduct(&BaseLineNormal) > MYEPSILON) { // Distance points outwards, hence OtherBase higher than Base -> flip
2519 Log() << Verbose(0) << "ACCEPT: Other base line would be higher: Flipping baseline." << endl;
2520 // calculate volume summand as a general tetraeder
2521 return volume;
2522 } else { // Base higher than OtherBase -> do nothing
2523 Log() << Verbose(0) << "REJECT: Base line is higher: Nothing to do." << endl;
2524 return 0.;
2525 }
2526 }
2527};
2528
2529/** For a given baseline and its two connected triangles, flips the baseline.
2530 * I.e. we create the new baseline between the other two endpoints of these four
2531 * endpoints and reconstruct the two triangles accordingly.
2532 * \param *out output stream for debugging
2533 * \param *Base line to be flipped
2534 * \return pointer to allocated new baseline - flipping successful, NULL - something went awry
2535 */
2536class BoundaryLineSet * Tesselation::FlipBaseline(class BoundaryLineSet *Base)
2537{
2538 Info FunctionInfo(__func__);
2539 class BoundaryLineSet *OldLines[4], *NewLine;
2540 class BoundaryPointSet *OldPoints[2];
2541 Vector BaseLineNormal;
2542 int OldTriangleNrs[2], OldBaseLineNr;
2543 int i,m;
2544
2545 // calculate NormalVector for later use
2546 BaseLineNormal.Zero();
2547 if (Base->triangles.size() < 2) {
2548 eLog() << Verbose(1) << "Less than two triangles are attached to this baseline!" << endl;
2549 return NULL;
2550 }
2551 for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
2552 Log() << Verbose(1) << "INFO: Adding NormalVector " << runner->second->NormalVector << " of triangle " << *(runner->second) << "." << endl;
2553 BaseLineNormal.AddVector(&(runner->second->NormalVector));
2554 }
2555 BaseLineNormal.Scale(-1./2.); // has to point inside for BoundaryTriangleSet::GetNormalVector()
2556
2557 // get the two triangles
2558 // gather four endpoints and four lines
2559 for (int j=0;j<4;j++)
2560 OldLines[j] = NULL;
2561 for (int j=0;j<2;j++)
2562 OldPoints[j] = NULL;
2563 i=0;
2564 m=0;
2565 Log() << Verbose(0) << "The four old lines are: ";
2566 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
2567 for (int j=0;j<3;j++) // all of their endpoints and baselines
2568 if (runner->second->lines[j] != Base) { // pick not the central baseline
2569 OldLines[i++] = runner->second->lines[j];
2570 Log() << Verbose(0) << *runner->second->lines[j] << "\t";
2571 }
2572 Log() << Verbose(0) << endl;
2573 Log() << Verbose(0) << "The two old points are: ";
2574 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
2575 for (int j=0;j<3;j++) // all of their endpoints and baselines
2576 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) { // and neither of its endpoints
2577 OldPoints[m++] = runner->second->endpoints[j];
2578 Log() << Verbose(0) << *runner->second->endpoints[j] << "\t";
2579 }
2580 Log() << Verbose(0) << endl;
2581
2582 // check whether everything is in place to create new lines and triangles
2583 if (i<4) {
2584 eLog() << Verbose(1) << "We have not gathered enough baselines!" << endl;
2585 return NULL;
2586 }
2587 for (int j=0;j<4;j++)
2588 if (OldLines[j] == NULL) {
2589 eLog() << Verbose(1) << "We have not gathered enough baselines!" << endl;
2590 return NULL;
2591 }
2592 for (int j=0;j<2;j++)
2593 if (OldPoints[j] == NULL) {
2594 eLog() << Verbose(1) << "We have not gathered enough endpoints!" << endl;
2595 return NULL;
2596 }
2597
2598 // remove triangles and baseline removes itself
2599 Log() << Verbose(0) << "INFO: Deleting baseline " << *Base << " from global list." << endl;
2600 OldBaseLineNr = Base->Nr;
2601 m=0;
2602 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
2603 Log() << Verbose(0) << "INFO: Deleting triangle " << *(runner->second) << "." << endl;
2604 OldTriangleNrs[m++] = runner->second->Nr;
2605 RemoveTesselationTriangle(runner->second);
2606 }
2607
2608 // construct new baseline (with same number as old one)
2609 BPS[0] = OldPoints[0];
2610 BPS[1] = OldPoints[1];
2611 NewLine = new class BoundaryLineSet(BPS, OldBaseLineNr);
2612 LinesOnBoundary.insert(LinePair(OldBaseLineNr, NewLine)); // no need for check for unique insertion as NewLine is definitely a new one
2613 Log() << Verbose(0) << "INFO: Created new baseline " << *NewLine << "." << endl;
2614
2615 // construct new triangles with flipped baseline
2616 i=-1;
2617 if (OldLines[0]->IsConnectedTo(OldLines[2]))
2618 i=2;
2619 if (OldLines[0]->IsConnectedTo(OldLines[3]))
2620 i=3;
2621 if (i!=-1) {
2622 BLS[0] = OldLines[0];
2623 BLS[1] = OldLines[i];
2624 BLS[2] = NewLine;
2625 BTS = new class BoundaryTriangleSet(BLS, OldTriangleNrs[0]);
2626 BTS->GetNormalVector(BaseLineNormal);
2627 AddTesselationTriangle(OldTriangleNrs[0]);
2628 Log() << Verbose(0) << "INFO: Created new triangle " << *BTS << "." << endl;
2629
2630 BLS[0] = (i==2 ? OldLines[3] : OldLines[2]);
2631 BLS[1] = OldLines[1];
2632 BLS[2] = NewLine;
2633 BTS = new class BoundaryTriangleSet(BLS, OldTriangleNrs[1]);
2634 BTS->GetNormalVector(BaseLineNormal);
2635 AddTesselationTriangle(OldTriangleNrs[1]);
2636 Log() << Verbose(0) << "INFO: Created new triangle " << *BTS << "." << endl;
2637 } else {
2638 eLog() << Verbose(0) << "The four old lines do not connect, something's utterly wrong here!" << endl;
2639 return NULL;
2640 }
2641
2642 return NewLine;
2643};
2644
2645
2646/** Finds the second point of starting triangle.
2647 * \param *a first node
2648 * \param Oben vector indicating the outside
2649 * \param OptCandidate reference to recommended candidate on return
2650 * \param Storage[3] array storing angles and other candidate information
2651 * \param RADIUS radius of virtual sphere
2652 * \param *LC LinkedCell structure with neighbouring points
2653 */
2654void Tesselation::FindSecondPointForTesselation(TesselPoint* a, Vector Oben, TesselPoint*& OptCandidate, double Storage[3], double RADIUS, const LinkedCell *LC)
2655{
2656 Info FunctionInfo(__func__);
2657 Vector AngleCheck;
2658 class TesselPoint* Candidate = NULL;
2659 double norm = -1.;
2660 double angle = 0.;
2661 int N[NDIM];
2662 int Nlower[NDIM];
2663 int Nupper[NDIM];
2664
2665 if (LC->SetIndexToNode(a)) { // get cell for the starting point
2666 for(int i=0;i<NDIM;i++) // store indices of this cell
2667 N[i] = LC->n[i];
2668 } else {
2669 eLog() << Verbose(1) << "Point " << *a << " is not found in cell " << LC->index << "." << endl;
2670 return;
2671 }
2672 // then go through the current and all neighbouring cells and check the contained points for possible candidates
2673 for (int i=0;i<NDIM;i++) {
2674 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
2675 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
2676 }
2677 Log() << Verbose(0) << "LC Intervals from [" << N[0] << "<->" << LC->N[0] << ", " << N[1] << "<->" << LC->N[1] << ", " << N[2] << "<->" << LC->N[2] << "] :"
2678 << " [" << Nlower[0] << "," << Nupper[0] << "], " << " [" << Nlower[1] << "," << Nupper[1] << "], " << " [" << Nlower[2] << "," << Nupper[2] << "], " << endl;
2679
2680 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2681 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2682 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2683 const LinkedNodes *List = LC->GetCurrentCell();
2684 //Log() << Verbose(1) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
2685 if (List != NULL) {
2686 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2687 Candidate = (*Runner);
2688 // check if we only have one unique point yet ...
2689 if (a != Candidate) {
2690 // Calculate center of the circle with radius RADIUS through points a and Candidate
2691 Vector OrthogonalizedOben, aCandidate, Center;
2692 double distance, scaleFactor;
2693
2694 OrthogonalizedOben.CopyVector(&Oben);
2695 aCandidate.CopyVector(a->node);
2696 aCandidate.SubtractVector(Candidate->node);
2697 OrthogonalizedOben.ProjectOntoPlane(&aCandidate);
2698 OrthogonalizedOben.Normalize();
2699 distance = 0.5 * aCandidate.Norm();
2700 scaleFactor = sqrt(((RADIUS * RADIUS) - (distance * distance)));
2701 OrthogonalizedOben.Scale(scaleFactor);
2702
2703 Center.CopyVector(Candidate->node);
2704 Center.AddVector(a->node);
2705 Center.Scale(0.5);
2706 Center.AddVector(&OrthogonalizedOben);
2707
2708 AngleCheck.CopyVector(&Center);
2709 AngleCheck.SubtractVector(a->node);
2710 norm = aCandidate.Norm();
2711 // second point shall have smallest angle with respect to Oben vector
2712 if (norm < RADIUS*2.) {
2713 angle = AngleCheck.Angle(&Oben);
2714 if (angle < Storage[0]) {
2715 //Log() << Verbose(1) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
2716 Log() << Verbose(1) << "Current candidate is " << *Candidate << ": Is a better candidate with distance " << norm << " and angle " << angle << " to oben " << Oben << ".\n";
2717 OptCandidate = Candidate;
2718 Storage[0] = angle;
2719 //Log() << Verbose(1) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
2720 } else {
2721 //Log() << Verbose(1) << "Current candidate is " << *Candidate << ": Looses with angle " << angle << " to a better candidate " << *OptCandidate << endl;
2722 }
2723 } else {
2724 //Log() << Verbose(1) << "Current candidate is " << *Candidate << ": Refused due to Radius " << norm << endl;
2725 }
2726 } else {
2727 //Log() << Verbose(1) << "Current candidate is " << *Candidate << ": Candidate is equal to first endpoint." << *a << "." << endl;
2728 }
2729 }
2730 } else {
2731 Log() << Verbose(0) << "Linked cell list is empty." << endl;
2732 }
2733 }
2734};
2735
2736
2737/** This recursive function finds a third point, to form a triangle with two given ones.
2738 * Note that this function is for the starting triangle.
2739 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points
2740 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then
2741 * the center of the sphere is still fixed up to a single parameter. The band of possible values
2742 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives
2743 * us the "null" on this circle, the new center of the candidate point will be some way along this
2744 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given
2745 * by the normal vector of the base triangle that always points outwards by construction.
2746 * Hence, we construct a Center of this circle which sits right in the middle of the current base line.
2747 * We construct the normal vector that defines the plane this circle lies in, it is just in the
2748 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest
2749 * with respect to the length of the baseline and the sphere's fixed \a RADIUS.
2750 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center
2751 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check
2752 * both.
2753 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check
2754 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check
2755 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal
2756 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality
2757 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether
2758 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI).
2759 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa FindStartingTriangle())
2760 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine
2761 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle
2762 * @param CandidateLine CandidateForTesselation with the current base line and list of candidates and ShortestAngle
2763 * @param ThirdNode third point to avoid in search
2764 * @param RADIUS radius of sphere
2765 * @param *LC LinkedCell structure with neighbouring points
2766 */
2767void Tesselation::FindThirdPointForTesselation(Vector &NormalVector, Vector &SearchDirection, Vector &OldSphereCenter, CandidateForTesselation &CandidateLine, const class TesselPoint * const ThirdNode, const double RADIUS, const LinkedCell *LC) const
2768{
2769 Info FunctionInfo(__func__);
2770 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers
2771 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
2772 Vector SphereCenter;
2773 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility
2774 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility
2775 Vector NewNormalVector; // normal vector of the Candidate's triangle
2776 Vector helper, OptCandidateCenter, OtherOptCandidateCenter;
2777 Vector RelativeOldSphereCenter;
2778 Vector NewPlaneCenter;
2779 double CircleRadius; // radius of this circle
2780 double radius;
2781 double otherradius;
2782 double alpha, Otheralpha; // angles (i.e. parameter for the circle).
2783 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2784 TesselPoint *Candidate = NULL;
2785
2786 Log() << Verbose(1) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
2787
2788 // construct center of circle
2789 CircleCenter.CopyVector(CandidateLine.BaseLine->endpoints[0]->node->node);
2790 CircleCenter.AddVector(CandidateLine.BaseLine->endpoints[1]->node->node);
2791 CircleCenter.Scale(0.5);
2792
2793 // construct normal vector of circle
2794 CirclePlaneNormal.CopyVector(CandidateLine.BaseLine->endpoints[0]->node->node);
2795 CirclePlaneNormal.SubtractVector(CandidateLine.BaseLine->endpoints[1]->node->node);
2796
2797 RelativeOldSphereCenter.CopyVector(&OldSphereCenter);
2798 RelativeOldSphereCenter.SubtractVector(&CircleCenter);
2799
2800 // calculate squared radius TesselPoint *ThirdNode,f circle
2801 radius = CirclePlaneNormal.NormSquared()/4.;
2802 if (radius < RADIUS*RADIUS) {
2803 CircleRadius = RADIUS*RADIUS - radius;
2804 CirclePlaneNormal.Normalize();
2805 Log() << Verbose(1) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
2806
2807 // test whether old center is on the band's plane
2808 if (fabs(RelativeOldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
2809 eLog() << Verbose(1) << "Something's very wrong here: RelativeOldSphereCenter is not on the band's plane as desired by " << fabs(RelativeOldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
2810 RelativeOldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal);
2811 }
2812 radius = RelativeOldSphereCenter.NormSquared();
2813 if (fabs(radius - CircleRadius) < HULLEPSILON) {
2814 Log() << Verbose(1) << "INFO: RelativeOldSphereCenter is at " << RelativeOldSphereCenter << "." << endl;
2815
2816 // check SearchDirection
2817 Log() << Verbose(1) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
2818 if (fabs(RelativeOldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way!
2819 eLog() << Verbose(1) << "SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl;
2820 }
2821
2822 // get cell for the starting point
2823 if (LC->SetIndexToVector(&CircleCenter)) {
2824 for(int i=0;i<NDIM;i++) // store indices of this cell
2825 N[i] = LC->n[i];
2826 //Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2827 } else {
2828 eLog() << Verbose(1) << "Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl;
2829 return;
2830 }
2831 // then go through the current and all neighbouring cells and check the contained points for possible candidates
2832 //Log() << Verbose(1) << "LC Intervals:";
2833 for (int i=0;i<NDIM;i++) {
2834 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
2835 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
2836 //Log() << Verbose(0) << " [" << Nlower[i] << "," << Nupper[i] << "] ";
2837 }
2838 //Log() << Verbose(0) << endl;
2839 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2840 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2841 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2842 const LinkedNodes *List = LC->GetCurrentCell();
2843 //Log() << Verbose(1) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
2844 if (List != NULL) {
2845 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2846 Candidate = (*Runner);
2847
2848 // check for three unique points
2849 Log() << Verbose(2) << "INFO: Current Candidate is " << *Candidate << " for BaseLine " << *CandidateLine.BaseLine << " with OldSphereCenter " << OldSphereCenter << "." << endl;
2850 if ((Candidate != CandidateLine.BaseLine->endpoints[0]->node) && (Candidate != CandidateLine.BaseLine->endpoints[1]->node) ){
2851
2852 // find center on the plane
2853 GetCenterofCircumcircle(&NewPlaneCenter, *CandidateLine.BaseLine->endpoints[0]->node->node, *CandidateLine.BaseLine->endpoints[1]->node->node, *Candidate->node);
2854 Log() << Verbose(1) << "INFO: NewPlaneCenter is " << NewPlaneCenter << "." << endl;
2855
2856 if (NewNormalVector.MakeNormalVector(CandidateLine.BaseLine->endpoints[0]->node->node, CandidateLine.BaseLine->endpoints[1]->node->node, Candidate->node)
2857 && (fabs(NewNormalVector.NormSquared()) > HULLEPSILON)
2858 ) {
2859 Log() << Verbose(1) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl;
2860 radius = CandidateLine.BaseLine->endpoints[0]->node->node->DistanceSquared(&NewPlaneCenter);
2861 Log() << Verbose(1) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
2862 Log() << Verbose(1) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
2863 Log() << Verbose(1) << "INFO: Radius of CircumCenterCircle is " << radius << "." << endl;
2864 if (radius < RADIUS*RADIUS) {
2865 otherradius = CandidateLine.BaseLine->endpoints[1]->node->node->DistanceSquared(&NewPlaneCenter);
2866 if (fabs(radius - otherradius) > HULLEPSILON) {
2867 eLog() << Verbose(1) << "Distance to center of circumcircle is not the same from each corner of the triangle: " << fabs(radius-otherradius) << endl;
2868 }
2869 // construct both new centers
2870 NewSphereCenter.CopyVector(&NewPlaneCenter);
2871 OtherNewSphereCenter.CopyVector(&NewPlaneCenter);
2872 helper.CopyVector(&NewNormalVector);
2873 helper.Scale(sqrt(RADIUS*RADIUS - radius));
2874 Log() << Verbose(2) << "INFO: Distance of NewPlaneCenter " << NewPlaneCenter << " to either NewSphereCenter is " << helper.Norm() << " of vector " << helper << " with sphere radius " << RADIUS << "." << endl;
2875 NewSphereCenter.AddVector(&helper);
2876 Log() << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl;
2877 // OtherNewSphereCenter is created by the same vector just in the other direction
2878 helper.Scale(-1.);
2879 OtherNewSphereCenter.AddVector(&helper);
2880 Log() << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl;
2881
2882 alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
2883 Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
2884 alpha = min(alpha, Otheralpha);
2885
2886 // if there is a better candidate, drop the current list and add the new candidate
2887 // otherwise ignore the new candidate and keep the list
2888 if (CandidateLine.ShortestAngle > (alpha - HULLEPSILON)) {
2889 if (fabs(alpha - Otheralpha) > MYEPSILON) {
2890 CandidateLine.OptCenter.CopyVector(&NewSphereCenter);
2891 CandidateLine.OtherOptCenter.CopyVector(&OtherNewSphereCenter);
2892 } else {
2893 CandidateLine.OptCenter.CopyVector(&OtherNewSphereCenter);
2894 CandidateLine.OtherOptCenter.CopyVector(&NewSphereCenter);
2895 }
2896 // if there is an equal candidate, add it to the list without clearing the list
2897 if ((CandidateLine.ShortestAngle - HULLEPSILON) < alpha) {
2898 CandidateLine.pointlist.push_back(Candidate);
2899 Log() << Verbose(0) << "ACCEPT: We have found an equally good candidate: " << *(Candidate) << " with "
2900 << alpha << " and circumsphere's center at " << CandidateLine.OptCenter << "." << endl;
2901 } else {
2902 // remove all candidates from the list and then the list itself
2903 CandidateLine.pointlist.clear();
2904 CandidateLine.pointlist.push_back(Candidate);
2905 Log() << Verbose(0) << "ACCEPT: We have found a better candidate: " << *(Candidate) << " with "
2906 << alpha << " and circumsphere's center at " << CandidateLine.OptCenter << "." << endl;
2907 }
2908 CandidateLine.ShortestAngle = alpha;
2909 Log() << Verbose(0) << "INFO: There are " << CandidateLine.pointlist.size() << " candidates in the list now." << endl;
2910 } else {
2911 if ((Candidate != NULL) && (CandidateLine.pointlist.begin() != CandidateLine.pointlist.end())) {
2912 Log() << Verbose(1) << "REJECT: Old candidate " << *(Candidate) << " with " << CandidateLine.ShortestAngle << " is better than new one " << *Candidate << " with " << alpha << " ." << endl;
2913 } else {
2914 Log() << Verbose(1) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl;
2915 }
2916 }
2917 } else {
2918 Log() << Verbose(1) << "REJECT: NewSphereCenter " << NewSphereCenter << " for " << *Candidate << " is too far away: " << radius << "." << endl;
2919 }
2920 } else {
2921 Log() << Verbose(1) << "REJECT: Three points from " << *CandidateLine.BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl;
2922 }
2923 } else {
2924 if (ThirdNode != NULL) {
2925 Log() << Verbose(1) << "REJECT: Base triangle " << *CandidateLine.BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl;
2926 } else {
2927 Log() << Verbose(1) << "REJECT: Base triangle " << *CandidateLine.BaseLine << " contains Candidate " << *Candidate << "." << endl;
2928 }
2929 }
2930 }
2931 }
2932 }
2933 } else {
2934 eLog() << Verbose(1) << "The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
2935 }
2936 } else {
2937 if (ThirdNode != NULL)
2938 Log() << Verbose(1) << "Circumcircle for base line " << *CandidateLine.BaseLine << " and third node " << *ThirdNode << " is too big!" << endl;
2939 else
2940 Log() << Verbose(1) << "Circumcircle for base line " << *CandidateLine.BaseLine << " is too big!" << endl;
2941 }
2942
2943 Log() << Verbose(1) << "INFO: Sorting candidate list ..." << endl;
2944 if (CandidateLine.pointlist.size() > 1) {
2945 CandidateLine.pointlist.unique();
2946 CandidateLine.pointlist.sort(); //SortCandidates);
2947 }
2948};
2949
2950/** Finds the endpoint two lines are sharing.
2951 * \param *line1 first line
2952 * \param *line2 second line
2953 * \return point which is shared or NULL if none
2954 */
2955class BoundaryPointSet *Tesselation::GetCommonEndpoint(const BoundaryLineSet * line1, const BoundaryLineSet * line2) const
2956{
2957 Info FunctionInfo(__func__);
2958 const BoundaryLineSet * lines[2] = { line1, line2 };
2959 class BoundaryPointSet *node = NULL;
2960 map<int, class BoundaryPointSet *> OrderMap;
2961 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
2962 for (int i = 0; i < 2; i++)
2963 // for both lines
2964 for (int j = 0; j < 2; j++)
2965 { // for both endpoints
2966 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
2967 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
2968 if (!OrderTest.second)
2969 { // if insertion fails, we have common endpoint
2970 node = OrderTest.first->second;
2971 Log() << Verbose(1) << "Common endpoint of lines " << *line1
2972 << " and " << *line2 << " is: " << *node << "." << endl;
2973 j = 2;
2974 i = 2;
2975 break;
2976 }
2977 }
2978 return node;
2979};
2980
2981/** Finds the triangle that is closest to a given Vector \a *x.
2982 * \param *out output stream for debugging
2983 * \param *x Vector to look from
2984 * \return list of BoundaryTriangleSet of nearest triangles or NULL in degenerate case.
2985 */
2986list<BoundaryTriangleSet*> * Tesselation::FindClosestTrianglesToPoint(const Vector *x, const LinkedCell* LC) const
2987{
2988 Info FunctionInfo(__func__);
2989 PointMap::const_iterator FindPoint;
2990 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2991
2992 if (LinesOnBoundary.empty()) {
2993 eLog() << Verbose(1) << "There is no tesselation structure to compare the point with, please create one first." << endl;
2994 return NULL;
2995 }
2996
2997 // gather all points close to the desired one
2998 LC->SetIndexToVector(x); // ignore status as we calculate bounds below sensibly
2999 for(int i=0;i<NDIM;i++) // store indices of this cell
3000 N[i] = LC->n[i];
3001 Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
3002
3003 set<BoundaryPointSet *> points;
3004 LC->GetNeighbourBounds(Nlower, Nupper);
3005 //Log() << Verbose(1) << endl;
3006 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
3007 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
3008 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
3009 const LinkedNodes *List = LC->GetCurrentCell();
3010 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
3011 if (List != NULL) {
3012 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
3013 FindPoint = PointsOnBoundary.find((*Runner)->nr);
3014 if (FindPoint != PointsOnBoundary.end())
3015 points.insert(FindPoint->second);
3016 }
3017 } else {
3018 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
3019 }
3020 }
3021
3022 // check whether we found some points
3023 if (points.empty()) {
3024 Log() << Verbose(1) << "There is no nearest triangle, too far away from the surface." << endl;
3025 return NULL;
3026 }
3027
3028 // for each point, check its lines, remember closest
3029 Log() << Verbose(1) << "Finding closest BoundaryLine to " << *x << " ... " << endl;
3030 BoundaryLineSet *ClosestLine = NULL;
3031 double MinDistance = -1.;
3032 Vector helper;
3033 Vector Center;
3034 Vector BaseLine;
3035 for (set<BoundaryPointSet *>::iterator Runner = points.begin(); Runner != points.end(); Runner++) {
3036 for (LineMap::iterator LineRunner = (*Runner)->lines.begin(); LineRunner != (*Runner)->lines.end(); LineRunner++) {
3037 // calculate closest point on line to desired point
3038 helper.CopyVector((LineRunner->second)->endpoints[0]->node->node);
3039 helper.AddVector((LineRunner->second)->endpoints[1]->node->node);
3040 helper.Scale(0.5);
3041 Center.CopyVector(x);
3042 Center.SubtractVector(&helper);
3043 BaseLine.CopyVector((LineRunner->second)->endpoints[0]->node->node);
3044 BaseLine.SubtractVector((LineRunner->second)->endpoints[1]->node->node);
3045 Center.ProjectOntoPlane(&BaseLine);
3046 const double distance = Center.NormSquared();
3047 if ((ClosestLine == NULL) || (distance < MinDistance)) {
3048 // additionally calculate intersection on line (whether it's on the line section or not)
3049 helper.CopyVector(x);
3050 helper.SubtractVector((LineRunner->second)->endpoints[0]->node->node);
3051 helper.SubtractVector(&Center);
3052 const double lengthA = helper.ScalarProduct(&BaseLine);
3053 helper.CopyVector(x);
3054 helper.SubtractVector((LineRunner->second)->endpoints[1]->node->node);
3055 helper.SubtractVector(&Center);
3056 const double lengthB = helper.ScalarProduct(&BaseLine);
3057 if (lengthB*lengthA < 0) { // if have different sign
3058 ClosestLine = LineRunner->second;
3059 MinDistance = distance;
3060 Log() << Verbose(1) << "ACCEPT: New closest line is " << *ClosestLine << " with projected distance " << MinDistance << "." << endl;
3061 } else {
3062 Log() << Verbose(1) << "REJECT: Intersection is outside of the line section: " << lengthA << " and " << lengthB << "." << endl;
3063 }
3064 } else {
3065 Log() << Verbose(1) << "REJECT: Point is too further away than present line: " << distance << " >> " << MinDistance << "." << endl;
3066 }
3067 }
3068 }
3069 // check whether closest line is "too close" :), then it's inside
3070 if (ClosestLine == NULL) {
3071 Log() << Verbose(0) << "Is the only point, no one else is closeby." << endl;
3072 return NULL;
3073 }
3074 list<BoundaryTriangleSet*> *triangles = new list<BoundaryTriangleSet*>;
3075 for (TriangleMap::iterator Runner = ClosestLine->triangles.begin(); Runner != ClosestLine->triangles.end(); Runner++) {
3076 triangles->push_back(Runner->second);
3077 }
3078 return triangles;
3079};
3080
3081/** Finds closest triangle to a point.
3082 * This basically just takes care of the degenerate case, which is not handled in FindClosestTrianglesToPoint().
3083 * \param *out output stream for debugging
3084 * \param *x Vector to look from
3085 * \return list of BoundaryTriangleSet of nearest triangles or NULL.
3086 */
3087class BoundaryTriangleSet * Tesselation::FindClosestTriangleToPoint(const Vector *x, const LinkedCell* LC) const
3088{
3089 Info FunctionInfo(__func__);
3090 class BoundaryTriangleSet *result = NULL;
3091 list<BoundaryTriangleSet*> *triangles = FindClosestTrianglesToPoint(x, LC);
3092 list<BoundaryTriangleSet*> candidates;
3093 Vector Center;
3094 Vector helper;
3095
3096 if ((triangles == NULL) || (triangles->empty()))
3097 return NULL;
3098
3099 // reject all which are not closest
3100 double MinDistance = -1.;
3101 for (list<BoundaryTriangleSet*>::iterator Runner = triangles->begin(); Runner != triangles->end(); Runner++) {
3102 (*Runner)->GetCenter(&Center);
3103 helper.CopyVector(x);
3104 helper.SubtractVector(&Center);
3105 helper.ProjectOntoPlane(&(*Runner)->NormalVector);
3106 const double distance = helper.NormSquared();
3107 if (fabs(distance - MinDistance) < MYEPSILON) { // degenerate case, keep both
3108 candidates.push_back(*Runner);
3109 } else if (distance < MinDistance) {
3110 candidates.clear();
3111 candidates.push_back(*Runner);
3112 MinDistance = distance;
3113 }
3114 }
3115 delete(triangles);
3116 if (!candidates.empty()) {
3117 if (candidates.size() == 1) { // there is no degenerate case
3118 result = candidates.front();
3119 Log() << Verbose(1) << "Normal Vector of this triangle is " << result->NormalVector << "." << endl;
3120 } else {
3121 result = candidates.front();
3122 result->GetCenter(&Center);
3123 Center.SubtractVector(x);
3124 Log() << Verbose(1) << "Normal Vector of this front side is " << result->NormalVector << "." << endl;
3125 if (Center.ScalarProduct(&result->NormalVector) < 0) {
3126 result = candidates.back();
3127 Log() << Verbose(1) << "Normal Vector of this back side is " << result->NormalVector << "." << endl;
3128 if (Center.ScalarProduct(&result->NormalVector) < 0) {
3129 eLog() << Verbose(1) << "Front and back side yield NormalVector in wrong direction!" << endl;
3130 }
3131 }
3132 }
3133 } else {
3134 result = NULL;
3135 Log() << Verbose(0) << "No closest triangle found." << endl;
3136 }
3137 return result;
3138};
3139
3140/** Checks whether the provided Vector is within the tesselation structure.
3141 *
3142 * @param point of which to check the position
3143 * @param *LC LinkedCell structure
3144 * @param epsilon Distance of \a &Point to Center of triangle (of point outwards) is tested less against this value (standard: -MYEPSILON)
3145 *
3146 * @return true if the point is inside the tesselation structure, false otherwise
3147 */
3148bool Tesselation::IsInnerPoint(const Vector &Point, const LinkedCell* const LC, const double epsilon) const
3149{
3150 Info FunctionInfo(__func__);
3151 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(&Point, LC);
3152 Vector Center;
3153 Vector helper;
3154
3155 if (result == NULL) {// is boundary point or only point in point cloud?
3156 Log() << Verbose(1) << Point << " is the only point in vicinity." << endl;
3157 return false;
3158 } else {
3159 Log() << Verbose(1) << "INFO: Closest triangle found is " << *result << "." << endl;
3160 }
3161
3162 result->GetCenter(&Center);
3163 Log() << Verbose(2) << "INFO: Central point of the triangle is " << Center << "." << endl;
3164 Center.SubtractVector(&Point);
3165 Log() << Verbose(2) << "INFO: Vector from point to test to center is " << Center << "." << endl;
3166 if (Center.ScalarProduct(&result->NormalVector) > -MYEPSILON) {
3167 Log() << Verbose(1) << Point << " is an inner point." << endl;
3168 return true;
3169 } else {
3170 for (int i=0;i<3;i++) {
3171 helper.CopyVector(result->endpoints[i]->node->node);
3172 helper.SubtractVector(&Point);
3173 if (Center.NormSquared() > helper.NormSquared())
3174 Center.CopyVector(&helper);
3175 }
3176 if (Center.NormSquared() < epsilon*epsilon) {
3177 Log() << Verbose(1) << Point << " is inner point, being sufficiently close (wrt " << epsilon << ") to boundary." << endl;
3178 return true;
3179 }
3180 Log() << Verbose(1) << Point << " is NOT an inner point." << endl;
3181 return false;
3182 }
3183}
3184
3185/** Checks whether the provided TesselPoint is within the tesselation structure.
3186 *
3187 * @param *Point of which to check the position
3188 * @param *LC Linked Cell structure
3189 * @param epsilon Distance of \a &Point to Center of triangle is tested greater against this value (standard: -MYEPSILON)
3190 *
3191 * @return true if the point is inside the tesselation structure, false otherwise
3192 */
3193bool Tesselation::IsInnerPoint(const TesselPoint * const Point, const LinkedCell* const LC, const double epsilon) const
3194{
3195 Info FunctionInfo(__func__);
3196 return IsInnerPoint(*(Point->node), LC, epsilon);
3197}
3198
3199/**
3200 * Finds the point which is second closest to the provided one.
3201 *
3202 * @param Point to which to find the second closest other point
3203 * @param linked cell structure
3204 *
3205 * @return point which is second closest to the provided one
3206 * @TODO Optimize me! These finds are unnecessary if we have a LC list of BoundaryPoints only!
3207 */
3208TesselPoint* Tesselation::FindSecondClosestBoundaryPoint(const Vector* Point, const LinkedCell* const LC) const
3209{
3210 Info FunctionInfo(__func__);
3211 TesselPoint* closestPoint = NULL;
3212 TesselPoint* secondClosestPoint = NULL;
3213 double distance = 1e16;
3214 double secondDistance = 1e16;
3215 Vector helper;
3216 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
3217
3218 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
3219 for(int i=0;i<NDIM;i++) // store indices of this cell
3220 N[i] = LC->n[i];
3221 Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
3222
3223 LC->GetNeighbourBounds(Nlower, Nupper);
3224 //Log() << Verbose(1) << endl;
3225 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
3226 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
3227 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
3228 const LinkedNodes *List = LC->GetCurrentCell();
3229 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
3230 if (List != NULL) {
3231 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
3232 helper.CopyVector(Point);
3233 helper.SubtractVector((*Runner)->node);
3234 double currentNorm = helper. Norm();
3235 if (PointsOnBoundary.find((*Runner)->nr) != PointsOnBoundary.end()) {
3236 if (currentNorm < distance) {
3237 // remember second point
3238 secondDistance = distance;
3239 secondClosestPoint = closestPoint;
3240 // mark down new closest point
3241 distance = currentNorm;
3242 closestPoint = (*Runner);
3243 //Log() << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *secondClosestPoint << "." << endl;
3244 }
3245 }
3246 }
3247 } else {
3248 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << ","
3249 << LC->n[2] << " is invalid!" << endl;
3250 }
3251 }
3252
3253 return secondClosestPoint;
3254};
3255
3256/**
3257 * Finds the point which is closest to the provided one.
3258 *
3259 * @param Point to which to find the closest other point
3260 * @param SecondPoint the second closest other point on return, NULL if none found
3261 * @param linked cell structure
3262 *
3263 * @return point which is closest to the provided one, NULL if none found
3264 * @TODO Optimize me! These finds are unnecessary if we have a LC list of BoundaryPoints only!
3265 */
3266TesselPoint* Tesselation::FindClosestBoundaryPoint(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC) const
3267{
3268 Info FunctionInfo(__func__);
3269 TesselPoint* closestPoint = NULL;
3270 SecondPoint = NULL;
3271 double distance = 1e16;
3272 double secondDistance = 1e16;
3273 Vector helper;
3274 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
3275
3276 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
3277 for(int i=0;i<NDIM;i++) // store indices of this cell
3278 N[i] = LC->n[i];
3279 Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
3280
3281 LC->GetNeighbourBounds(Nlower, Nupper);
3282 //Log() << Verbose(1) << endl;
3283 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
3284 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
3285 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
3286 const LinkedNodes *List = LC->GetCurrentCell();
3287 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
3288 if (List != NULL) {
3289 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
3290 helper.CopyVector(Point);
3291 helper.SubtractVector((*Runner)->node);
3292 double currentNorm = helper.NormSquared();
3293 if (PointsOnBoundary.find((*Runner)->nr) != PointsOnBoundary.end()) {
3294 if (currentNorm < distance) {
3295 secondDistance = distance;
3296 SecondPoint = closestPoint;
3297 distance = currentNorm;
3298 closestPoint = (*Runner);
3299 //Log() << Verbose(1) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
3300 } else if (currentNorm < secondDistance) {
3301 secondDistance = currentNorm;
3302 SecondPoint = (*Runner);
3303 //Log() << Verbose(1) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
3304 }
3305 }
3306 }
3307 } else {
3308 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
3309 }
3310 }
3311 // output
3312 if ((closestPoint != NULL) && (SecondPoint != NULL)) {
3313 Log() << Verbose(1) << "Closest point is " << *closestPoint << " and second closest is " << *SecondPoint << "." << endl;
3314 } else if (closestPoint != NULL) {
3315 Log() << Verbose(1) << "Closest point is " << *closestPoint << " and second closest is " << SecondPoint << "." << endl;
3316 } else {
3317 Log() << Verbose(1) << "No closest point has been found, only " << closestPoint << " and " << SecondPoint << "." << endl;
3318 }
3319 return closestPoint;
3320};
3321
3322
3323/** Gets all points connected to the provided point by triangulation lines.
3324 *
3325 * @param *Point of which get all connected points
3326 *
3327 * @return set of the all points linked to the provided one
3328 */
3329set<TesselPoint*> * Tesselation::GetAllConnectedPoints(const TesselPoint* const Point) const
3330{
3331 Info FunctionInfo(__func__);
3332 set<TesselPoint*> *connectedPoints = new set<TesselPoint*>;
3333 class BoundaryPointSet *ReferencePoint = NULL;
3334 TesselPoint* current;
3335 bool takePoint = false;
3336
3337 // find the respective boundary point
3338 PointMap::const_iterator PointRunner = PointsOnBoundary.find(Point->nr);
3339 if (PointRunner != PointsOnBoundary.end()) {
3340 ReferencePoint = PointRunner->second;
3341 } else {
3342 eLog() << Verbose(2) << "GetAllConnectedPoints() could not find the BoundaryPoint belonging to " << *Point << "." << endl;
3343 ReferencePoint = NULL;
3344 }
3345
3346 // little trick so that we look just through lines connect to the BoundaryPoint
3347 // OR fall-back to look through all lines if there is no such BoundaryPoint
3348 const LineMap *Lines;;
3349 if (ReferencePoint != NULL)
3350 Lines = &(ReferencePoint->lines);
3351 else
3352 Lines = &LinesOnBoundary;
3353 LineMap::const_iterator findLines = Lines->begin();
3354 while (findLines != Lines->end()) {
3355 takePoint = false;
3356
3357 if (findLines->second->endpoints[0]->Nr == Point->nr) {
3358 takePoint = true;
3359 current = findLines->second->endpoints[1]->node;
3360 } else if (findLines->second->endpoints[1]->Nr == Point->nr) {
3361 takePoint = true;
3362 current = findLines->second->endpoints[0]->node;
3363 }
3364
3365 if (takePoint) {
3366 Log() << Verbose(1) << "INFO: Endpoint " << *current << " of line " << *(findLines->second) << " is enlisted." << endl;
3367 connectedPoints->insert(current);
3368 }
3369
3370 findLines++;
3371 }
3372
3373 if (connectedPoints->empty()) { // if have not found any points
3374 eLog() << Verbose(1) << "We have not found any connected points to " << *Point<< "." << endl;
3375 return NULL;
3376 }
3377
3378 return connectedPoints;
3379};
3380
3381
3382/** Gets all points connected to the provided point by triangulation lines, ordered such that we have the circle round the point.
3383 * Maps them down onto the plane designated by the axis \a *Point and \a *Reference. The center of all points
3384 * connected in the tesselation to \a *Point is mapped to spherical coordinates with the zero angle being given
3385 * by the mapped down \a *Reference. Hence, the biggest and the smallest angles are those of the two shanks of the
3386 * triangle we are looking for.
3387 *
3388 * @param *out output stream for debugging
3389 * @param *SetOfNeighbours all points for which the angle should be calculated
3390 * @param *Point of which get all connected points
3391 * @param *Reference Reference vector for zero angle or NULL for no preference
3392 * @return list of the all points linked to the provided one
3393 */
3394list<TesselPoint*> * Tesselation::GetCircleOfConnectedTriangles(set<TesselPoint*> *SetOfNeighbours, const TesselPoint* const Point, const Vector * const Reference) const
3395{
3396 Info FunctionInfo(__func__);
3397 map<double, TesselPoint*> anglesOfPoints;
3398 list<TesselPoint*> *connectedCircle = new list<TesselPoint*>;
3399 Vector PlaneNormal;
3400 Vector AngleZero;
3401 Vector OrthogonalVector;
3402 Vector helper;
3403 const TesselPoint * const TrianglePoints[3] = {Point, NULL, NULL};
3404 list<BoundaryTriangleSet*> *triangles = NULL;
3405
3406 if (SetOfNeighbours == NULL) {
3407 eLog() << Verbose(2) << "Could not find any connected points!" << endl;
3408 delete(connectedCircle);
3409 return NULL;
3410 }
3411
3412 // calculate central point
3413 triangles = FindTriangles(TrianglePoints);
3414 if ((triangles != NULL) && (!triangles->empty())) {
3415 for (list<BoundaryTriangleSet*>::iterator Runner = triangles->begin(); Runner != triangles->end(); Runner++)
3416 PlaneNormal.AddVector(&(*Runner)->NormalVector);
3417 } else {
3418 eLog() << Verbose(0) << "Could not find any triangles for point " << *Point << "." << endl;
3419 performCriticalExit();
3420 }
3421 PlaneNormal.Scale(1.0/triangles->size());
3422 Log() << Verbose(1) << "INFO: Calculated PlaneNormal of all circle points is " << PlaneNormal << "." << endl;
3423 PlaneNormal.Normalize();
3424
3425 // construct one orthogonal vector
3426 if (Reference != NULL) {
3427 AngleZero.CopyVector(Reference);
3428 AngleZero.SubtractVector(Point->node);
3429 AngleZero.ProjectOntoPlane(&PlaneNormal);
3430 }
3431 if ((Reference == NULL) || (AngleZero.NormSquared() < MYEPSILON )) {
3432 Log() << Verbose(1) << "Using alternatively " << *(*SetOfNeighbours->begin())->node << " as angle 0 referencer." << endl;
3433 AngleZero.CopyVector((*SetOfNeighbours->begin())->node);
3434 AngleZero.SubtractVector(Point->node);
3435 AngleZero.ProjectOntoPlane(&PlaneNormal);
3436 if (AngleZero.NormSquared() < MYEPSILON) {
3437 eLog() << Verbose(0) << "CRITIAL: AngleZero is 0 even with alternative reference. The algorithm has to be changed here!" << endl;
3438 performCriticalExit();
3439 }
3440 }
3441 Log() << Verbose(1) << "INFO: Reference vector on this plane representing angle 0 is " << AngleZero << "." << endl;
3442 if (AngleZero.NormSquared() > MYEPSILON)
3443 OrthogonalVector.MakeNormalVector(&PlaneNormal, &AngleZero);
3444 else
3445 OrthogonalVector.MakeNormalVector(&PlaneNormal);
3446 Log() << Verbose(1) << "INFO: OrthogonalVector on plane is " << OrthogonalVector << "." << endl;
3447
3448 // go through all connected points and calculate angle
3449 for (set<TesselPoint*>::iterator listRunner = SetOfNeighbours->begin(); listRunner != SetOfNeighbours->end(); listRunner++) {
3450 helper.CopyVector((*listRunner)->node);
3451 helper.SubtractVector(Point->node);
3452 helper.ProjectOntoPlane(&PlaneNormal);
3453 double angle = GetAngle(helper, AngleZero, OrthogonalVector);
3454 Log() << Verbose(0) << "INFO: Calculated angle is " << angle << " for point " << **listRunner << "." << endl;
3455 anglesOfPoints.insert(pair<double, TesselPoint*>(angle, (*listRunner)));
3456 }
3457
3458 for(map<double, TesselPoint*>::iterator AngleRunner = anglesOfPoints.begin(); AngleRunner != anglesOfPoints.end(); AngleRunner++) {
3459 connectedCircle->push_back(AngleRunner->second);
3460 }
3461
3462 return connectedCircle;
3463}
3464
3465/** Gets all points connected to the provided point by triangulation lines, ordered such that we have the circle round the point.
3466 * Maps them down onto the plane designated by the axis \a *Point and \a *Reference. The center of all points
3467 * connected in the tesselation to \a *Point is mapped to spherical coordinates with the zero angle being given
3468 * by the mapped down \a *Reference. Hence, the biggest and the smallest angles are those of the two shanks of the
3469 * triangle we are looking for.
3470 *
3471 * @param *out output stream for debugging
3472 * @param *SetOfNeighbours all points for which the angle should be calculated
3473 * @param *Point of which get all connected points
3474 * @param *Reference Reference vector for zero angle or NULL for no preference
3475 * @return list of the all points linked to the provided one
3476 */
3477list<TesselPoint*> * Tesselation::GetCircleOfSetOfPoints(set<TesselPoint*> *SetOfNeighbours, const TesselPoint* const Point, const Vector * const Reference) const
3478{
3479 Info FunctionInfo(__func__);
3480 map<double, TesselPoint*> anglesOfPoints;
3481 list<TesselPoint*> *connectedCircle = new list<TesselPoint*>;
3482 Vector center;
3483 Vector PlaneNormal;
3484 Vector AngleZero;
3485 Vector OrthogonalVector;
3486 Vector helper;
3487
3488 if (SetOfNeighbours == NULL) {
3489 eLog() << Verbose(2) << "Could not find any connected points!" << endl;
3490 delete(connectedCircle);
3491 return NULL;
3492 }
3493
3494 // calculate central point
3495 for (set<TesselPoint*>::const_iterator TesselRunner = SetOfNeighbours->begin(); TesselRunner != SetOfNeighbours->end(); TesselRunner++)
3496 center.AddVector((*TesselRunner)->node);
3497 //Log() << Verbose(0) << "Summed vectors " << center << "; number of points " << connectedPoints.size()
3498 // << "; scale factor " << 1.0/connectedPoints.size();
3499 center.Scale(1.0/SetOfNeighbours->size());
3500 Log() << Verbose(1) << "INFO: Calculated center of all circle points is " << center << "." << endl;
3501
3502 // projection plane of the circle is at the closes Point and normal is pointing away from center of all circle points
3503 PlaneNormal.CopyVector(Point->node);
3504 PlaneNormal.SubtractVector(&center);
3505 PlaneNormal.Normalize();
3506 Log() << Verbose(1) << "INFO: Calculated plane normal of circle is " << PlaneNormal << "." << endl;
3507
3508 // construct one orthogonal vector
3509 if (Reference != NULL) {
3510 AngleZero.CopyVector(Reference);
3511 AngleZero.SubtractVector(Point->node);
3512 AngleZero.ProjectOntoPlane(&PlaneNormal);
3513 }
3514 if ((Reference == NULL) || (AngleZero.NormSquared() < MYEPSILON )) {
3515 Log() << Verbose(1) << "Using alternatively " << *(*SetOfNeighbours->begin())->node << " as angle 0 referencer." << endl;
3516 AngleZero.CopyVector((*SetOfNeighbours->begin())->node);
3517 AngleZero.SubtractVector(Point->node);
3518 AngleZero.ProjectOntoPlane(&PlaneNormal);
3519 if (AngleZero.NormSquared() < MYEPSILON) {
3520 eLog() << Verbose(0) << "CRITIAL: AngleZero is 0 even with alternative reference. The algorithm has to be changed here!" << endl;
3521 performCriticalExit();
3522 }
3523 }
3524 Log() << Verbose(1) << "INFO: Reference vector on this plane representing angle 0 is " << AngleZero << "." << endl;
3525 if (AngleZero.NormSquared() > MYEPSILON)
3526 OrthogonalVector.MakeNormalVector(&PlaneNormal, &AngleZero);
3527 else
3528 OrthogonalVector.MakeNormalVector(&PlaneNormal);
3529 Log() << Verbose(1) << "INFO: OrthogonalVector on plane is " << OrthogonalVector << "." << endl;
3530
3531 // go through all connected points and calculate angle
3532 for (set<TesselPoint*>::iterator listRunner = SetOfNeighbours->begin(); listRunner != SetOfNeighbours->end(); listRunner++) {
3533 helper.CopyVector((*listRunner)->node);
3534 helper.SubtractVector(Point->node);
3535 helper.ProjectOntoPlane(&PlaneNormal);
3536 double angle = GetAngle(helper, AngleZero, OrthogonalVector);
3537 Log() << Verbose(0) << "INFO: Calculated angle is " << angle << " for point " << **listRunner << "." << endl;
3538 anglesOfPoints.insert(pair<double, TesselPoint*>(angle, (*listRunner)));
3539 }
3540
3541 for(map<double, TesselPoint*>::iterator AngleRunner = anglesOfPoints.begin(); AngleRunner != anglesOfPoints.end(); AngleRunner++) {
3542 connectedCircle->push_back(AngleRunner->second);
3543 }
3544
3545 return connectedCircle;
3546}
3547
3548/** Gets all points connected to the provided point by triangulation lines, ordered such that we walk along a closed path.
3549 *
3550 * @param *out output stream for debugging
3551 * @param *Point of which get all connected points
3552 * @return list of the all points linked to the provided one
3553 */
3554list<list<TesselPoint*> *> * Tesselation::GetPathsOfConnectedPoints(const TesselPoint* const Point) const
3555{
3556 Info FunctionInfo(__func__);
3557 map<double, TesselPoint*> anglesOfPoints;
3558 list<list<TesselPoint*> *> *ListOfPaths = new list<list<TesselPoint*> *>;
3559 list<TesselPoint*> *connectedPath = NULL;
3560 Vector center;
3561 Vector PlaneNormal;
3562 Vector AngleZero;
3563 Vector OrthogonalVector;
3564 Vector helper;
3565 class BoundaryPointSet *ReferencePoint = NULL;
3566 class BoundaryPointSet *CurrentPoint = NULL;
3567 class BoundaryTriangleSet *triangle = NULL;
3568 class BoundaryLineSet *CurrentLine = NULL;
3569 class BoundaryLineSet *StartLine = NULL;
3570
3571 // find the respective boundary point
3572 PointMap::const_iterator PointRunner = PointsOnBoundary.find(Point->nr);
3573 if (PointRunner != PointsOnBoundary.end()) {
3574 ReferencePoint = PointRunner->second;
3575 } else {
3576 eLog() << Verbose(1) << "GetPathOfConnectedPoints() could not find the BoundaryPoint belonging to " << *Point << "." << endl;
3577 return NULL;
3578 }
3579
3580 map <class BoundaryLineSet *, bool> TouchedLine;
3581 map <class BoundaryTriangleSet *, bool> TouchedTriangle;
3582 map <class BoundaryLineSet *, bool>::iterator LineRunner;
3583 map <class BoundaryTriangleSet *, bool>::iterator TriangleRunner;
3584 for (LineMap::iterator Runner = ReferencePoint->lines.begin(); Runner != ReferencePoint->lines.end(); Runner++) {
3585 TouchedLine.insert( pair <class BoundaryLineSet *, bool>(Runner->second, false) );
3586 for (TriangleMap::iterator Sprinter = Runner->second->triangles.begin(); Sprinter != Runner->second->triangles.end(); Sprinter++)
3587 TouchedTriangle.insert( pair <class BoundaryTriangleSet *, bool>(Sprinter->second, false) );
3588 }
3589 if (!ReferencePoint->lines.empty()) {
3590 for (LineMap::iterator runner = ReferencePoint->lines.begin(); runner != ReferencePoint->lines.end(); runner++) {
3591 LineRunner = TouchedLine.find(runner->second);
3592 if (LineRunner == TouchedLine.end()) {
3593 eLog() << Verbose(1) << "I could not find " << *runner->second << " in the touched list." << endl;
3594 } else if (!LineRunner->second) {
3595 LineRunner->second = true;
3596 connectedPath = new list<TesselPoint*>;
3597 triangle = NULL;
3598 CurrentLine = runner->second;
3599 StartLine = CurrentLine;
3600 CurrentPoint = CurrentLine->GetOtherEndpoint(ReferencePoint);
3601 Log() << Verbose(1)<< "INFO: Beginning path retrieval at " << *CurrentPoint << " of line " << *CurrentLine << "." << endl;
3602 do {
3603 // push current one
3604 Log() << Verbose(1) << "INFO: Putting " << *CurrentPoint << " at end of path." << endl;
3605 connectedPath->push_back(CurrentPoint->node);
3606
3607 // find next triangle
3608 for (TriangleMap::iterator Runner = CurrentLine->triangles.begin(); Runner != CurrentLine->triangles.end(); Runner++) {
3609 Log() << Verbose(1) << "INFO: Inspecting triangle " << *Runner->second << "." << endl;
3610 if ((Runner->second != triangle)) { // look for first triangle not equal to old one
3611 triangle = Runner->second;
3612 TriangleRunner = TouchedTriangle.find(triangle);
3613 if (TriangleRunner != TouchedTriangle.end()) {
3614 if (!TriangleRunner->second) {
3615 TriangleRunner->second = true;
3616 Log() << Verbose(1) << "INFO: Connecting triangle is " << *triangle << "." << endl;
3617 break;
3618 } else {
3619 Log() << Verbose(1) << "INFO: Skipping " << *triangle << ", as we have already visited it." << endl;
3620 triangle = NULL;
3621 }
3622 } else {
3623 eLog() << Verbose(1) << "I could not find " << *triangle << " in the touched list." << endl;
3624 triangle = NULL;
3625 }
3626 }
3627 }
3628 if (triangle == NULL)
3629 break;
3630 // find next line
3631 for (int i=0;i<3;i++) {
3632 if ((triangle->lines[i] != CurrentLine) && (triangle->lines[i]->ContainsBoundaryPoint(ReferencePoint))) { // not the current line and still containing Point
3633 CurrentLine = triangle->lines[i];
3634 Log() << Verbose(1) << "INFO: Connecting line is " << *CurrentLine << "." << endl;
3635 break;
3636 }
3637 }
3638 LineRunner = TouchedLine.find(CurrentLine);
3639 if (LineRunner == TouchedLine.end())
3640 eLog() << Verbose(1) << "I could not find " << *CurrentLine << " in the touched list." << endl;
3641 else
3642 LineRunner->second = true;
3643 // find next point
3644 CurrentPoint = CurrentLine->GetOtherEndpoint(ReferencePoint);
3645
3646 } while (CurrentLine != StartLine);
3647 // last point is missing, as it's on start line
3648 Log() << Verbose(1) << "INFO: Putting " << *CurrentPoint << " at end of path." << endl;
3649 if (StartLine->GetOtherEndpoint(ReferencePoint)->node != connectedPath->back())
3650 connectedPath->push_back(StartLine->GetOtherEndpoint(ReferencePoint)->node);
3651
3652 ListOfPaths->push_back(connectedPath);
3653 } else {
3654 Log() << Verbose(1) << "INFO: Skipping " << *runner->second << ", as we have already visited it." << endl;
3655 }
3656 }
3657 } else {
3658 eLog() << Verbose(1) << "There are no lines attached to " << *ReferencePoint << "." << endl;
3659 }
3660
3661 return ListOfPaths;
3662}
3663
3664/** Gets all closed paths on the circle of points connected to the provided point by triangulation lines, if this very point is removed.
3665 * From GetPathsOfConnectedPoints() extracts all single loops of intracrossing paths in the list of closed paths.
3666 * @param *out output stream for debugging
3667 * @param *Point of which get all connected points
3668 * @return list of the closed paths
3669 */
3670list<list<TesselPoint*> *> * Tesselation::GetClosedPathsOfConnectedPoints(const TesselPoint* const Point) const
3671{
3672 Info FunctionInfo(__func__);
3673 list<list<TesselPoint*> *> *ListofPaths = GetPathsOfConnectedPoints(Point);
3674 list<list<TesselPoint*> *> *ListofClosedPaths = new list<list<TesselPoint*> *>;
3675 list<TesselPoint*> *connectedPath = NULL;
3676 list<TesselPoint*> *newPath = NULL;
3677 int count = 0;
3678
3679
3680 list<TesselPoint*>::iterator CircleRunner;
3681 list<TesselPoint*>::iterator CircleStart;
3682
3683 for(list<list<TesselPoint*> *>::iterator ListRunner = ListofPaths->begin(); ListRunner != ListofPaths->end(); ListRunner++) {
3684 connectedPath = *ListRunner;
3685
3686 Log() << Verbose(1) << "INFO: Current path is " << connectedPath << "." << endl;
3687
3688 // go through list, look for reappearance of starting Point and count
3689 CircleStart = connectedPath->begin();
3690
3691 // go through list, look for reappearance of starting Point and create list
3692 list<TesselPoint*>::iterator Marker = CircleStart;
3693 for (CircleRunner = CircleStart; CircleRunner != connectedPath->end(); CircleRunner++) {
3694 if ((*CircleRunner == *CircleStart) && (CircleRunner != CircleStart)) { // is not the very first point
3695 // we have a closed circle from Marker to new Marker
3696 Log() << Verbose(1) << count+1 << ". closed path consists of: ";
3697 newPath = new list<TesselPoint*>;
3698 list<TesselPoint*>::iterator CircleSprinter = Marker;
3699 for (; CircleSprinter != CircleRunner; CircleSprinter++) {
3700 newPath->push_back(*CircleSprinter);
3701 Log() << Verbose(0) << (**CircleSprinter) << " <-> ";
3702 }
3703 Log() << Verbose(0) << ".." << endl;
3704 count++;
3705 Marker = CircleRunner;
3706
3707 // add to list
3708 ListofClosedPaths->push_back(newPath);
3709 }
3710 }
3711 }
3712 Log() << Verbose(1) << "INFO: " << count << " closed additional path(s) have been created." << endl;
3713
3714 // delete list of paths
3715 while (!ListofPaths->empty()) {
3716 connectedPath = *(ListofPaths->begin());
3717 ListofPaths->remove(connectedPath);
3718 delete(connectedPath);
3719 }
3720 delete(ListofPaths);
3721
3722 // exit
3723 return ListofClosedPaths;
3724};
3725
3726
3727/** Gets all belonging triangles for a given BoundaryPointSet.
3728 * \param *out output stream for debugging
3729 * \param *Point BoundaryPoint
3730 * \return pointer to allocated list of triangles
3731 */
3732set<BoundaryTriangleSet*> *Tesselation::GetAllTriangles(const BoundaryPointSet * const Point) const
3733{
3734 Info FunctionInfo(__func__);
3735 set<BoundaryTriangleSet*> *connectedTriangles = new set<BoundaryTriangleSet*>;
3736
3737 if (Point == NULL) {
3738 eLog() << Verbose(1) << "Point given is NULL." << endl;
3739 } else {
3740 // go through its lines and insert all triangles
3741 for (LineMap::const_iterator LineRunner = Point->lines.begin(); LineRunner != Point->lines.end(); LineRunner++)
3742 for (TriangleMap::iterator TriangleRunner = (LineRunner->second)->triangles.begin(); TriangleRunner != (LineRunner->second)->triangles.end(); TriangleRunner++) {
3743 connectedTriangles->insert(TriangleRunner->second);
3744 }
3745 }
3746
3747 return connectedTriangles;
3748};
3749
3750
3751/** Removes a boundary point from the envelope while keeping it closed.
3752 * We remove the old triangles connected to the point and re-create new triangles to close the surface following this ansatz:
3753 * -# a closed path(s) of boundary points surrounding the point to be removed is constructed
3754 * -# on each closed path, we pick three adjacent points, create a triangle with them and subtract the middle point from the path
3755 * -# we advance two points (i.e. the next triangle will start at the ending point of the last triangle) and continue as before
3756 * -# the surface is closed, when the path is empty
3757 * Thereby, we (hopefully) make sure that the removed points remains beneath the surface (this is checked via IsInnerPoint eventually).
3758 * \param *out output stream for debugging
3759 * \param *point point to be removed
3760 * \return volume added to the volume inside the tesselated surface by the removal
3761 */
3762double Tesselation::RemovePointFromTesselatedSurface(class BoundaryPointSet *point) {
3763 class BoundaryLineSet *line = NULL;
3764 class BoundaryTriangleSet *triangle = NULL;
3765 Vector OldPoint, NormalVector;
3766 double volume = 0;
3767 int count = 0;
3768
3769 if (point == NULL) {
3770 eLog() << Verbose(1) << "Cannot remove the point " << point << ", it's NULL!" << endl;
3771 return 0.;
3772 } else
3773 Log() << Verbose(0) << "Removing point " << *point << " from tesselated boundary ..." << endl;
3774
3775 // copy old location for the volume
3776 OldPoint.CopyVector(point->node->node);
3777
3778 // get list of connected points
3779 if (point->lines.empty()) {
3780 eLog() << Verbose(1) << "Cannot remove the point " << *point << ", it's connected to no lines!" << endl;
3781 return 0.;
3782 }
3783
3784 list<list<TesselPoint*> *> *ListOfClosedPaths = GetClosedPathsOfConnectedPoints(point->node);
3785 list<TesselPoint*> *connectedPath = NULL;
3786
3787 // gather all triangles
3788 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++)
3789 count+=LineRunner->second->triangles.size();
3790 map<class BoundaryTriangleSet *, int> Candidates;
3791 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
3792 line = LineRunner->second;
3793 for (TriangleMap::iterator TriangleRunner = line->triangles.begin(); TriangleRunner != line->triangles.end(); TriangleRunner++) {
3794 triangle = TriangleRunner->second;
3795 Candidates.insert( pair<class BoundaryTriangleSet *, int> (triangle, triangle->Nr) );
3796 }
3797 }
3798
3799 // remove all triangles
3800 count=0;
3801 NormalVector.Zero();
3802 for (map<class BoundaryTriangleSet *, int>::iterator Runner = Candidates.begin(); Runner != Candidates.end(); Runner++) {
3803 Log() << Verbose(1) << "INFO: Removing triangle " << *(Runner->first) << "." << endl;
3804 NormalVector.SubtractVector(&Runner->first->NormalVector); // has to point inward
3805 RemoveTesselationTriangle(Runner->first);
3806 count++;
3807 }
3808 Log() << Verbose(1) << count << " triangles were removed." << endl;
3809
3810 list<list<TesselPoint*> *>::iterator ListAdvance = ListOfClosedPaths->begin();
3811 list<list<TesselPoint*> *>::iterator ListRunner = ListAdvance;
3812 map<class BoundaryTriangleSet *, int>::iterator NumberRunner = Candidates.begin();
3813 list<TesselPoint*>::iterator StartNode, MiddleNode, EndNode;
3814 double angle;
3815 double smallestangle;
3816 Vector Point, Reference, OrthogonalVector;
3817 if (count > 2) { // less than three triangles, then nothing will be created
3818 class TesselPoint *TriangleCandidates[3];
3819 count = 0;
3820 for ( ; ListRunner != ListOfClosedPaths->end(); ListRunner = ListAdvance) { // go through all closed paths
3821 if (ListAdvance != ListOfClosedPaths->end())
3822 ListAdvance++;
3823
3824 connectedPath = *ListRunner;
3825
3826 // re-create all triangles by going through connected points list
3827 list<class BoundaryLineSet *> NewLines;
3828 for (;!connectedPath->empty();) {
3829 // search middle node with widest angle to next neighbours
3830 EndNode = connectedPath->end();
3831 smallestangle = 0.;
3832 for (MiddleNode = connectedPath->begin(); MiddleNode != connectedPath->end(); MiddleNode++) {
3833 Log() << Verbose(1) << "INFO: MiddleNode is " << **MiddleNode << "." << endl;
3834 // construct vectors to next and previous neighbour
3835 StartNode = MiddleNode;
3836 if (StartNode == connectedPath->begin())
3837 StartNode = connectedPath->end();
3838 StartNode--;
3839 //Log() << Verbose(3) << "INFO: StartNode is " << **StartNode << "." << endl;
3840 Point.CopyVector((*StartNode)->node);
3841 Point.SubtractVector((*MiddleNode)->node);
3842 StartNode = MiddleNode;
3843 StartNode++;
3844 if (StartNode == connectedPath->end())
3845 StartNode = connectedPath->begin();
3846 //Log() << Verbose(3) << "INFO: EndNode is " << **StartNode << "." << endl;
3847 Reference.CopyVector((*StartNode)->node);
3848 Reference.SubtractVector((*MiddleNode)->node);
3849 OrthogonalVector.CopyVector((*MiddleNode)->node);
3850 OrthogonalVector.SubtractVector(&OldPoint);
3851 OrthogonalVector.MakeNormalVector(&Reference);
3852 angle = GetAngle(Point, Reference, OrthogonalVector);
3853 //if (angle < M_PI) // no wrong-sided triangles, please?
3854 if(fabs(angle - M_PI) < fabs(smallestangle - M_PI)) { // get straightest angle (i.e. construct those triangles with smallest area first)
3855 smallestangle = angle;
3856 EndNode = MiddleNode;
3857 }
3858 }
3859 MiddleNode = EndNode;
3860 if (MiddleNode == connectedPath->end()) {
3861 eLog() << Verbose(0) << "CRITICAL: Could not find a smallest angle!" << endl;
3862 performCriticalExit();
3863 }
3864 StartNode = MiddleNode;
3865 if (StartNode == connectedPath->begin())
3866 StartNode = connectedPath->end();
3867 StartNode--;
3868 EndNode++;
3869 if (EndNode == connectedPath->end())
3870 EndNode = connectedPath->begin();
3871 Log() << Verbose(2) << "INFO: StartNode is " << **StartNode << "." << endl;
3872 Log() << Verbose(2) << "INFO: MiddleNode is " << **MiddleNode << "." << endl;
3873 Log() << Verbose(2) << "INFO: EndNode is " << **EndNode << "." << endl;
3874 Log() << Verbose(1) << "INFO: Attempting to create triangle " << (*StartNode)->Name << ", " << (*MiddleNode)->Name << " and " << (*EndNode)->Name << "." << endl;
3875 TriangleCandidates[0] = *StartNode;
3876 TriangleCandidates[1] = *MiddleNode;
3877 TriangleCandidates[2] = *EndNode;
3878 triangle = GetPresentTriangle(TriangleCandidates);
3879 if (triangle != NULL) {
3880 eLog() << Verbose(0) << "New triangle already present, skipping!" << endl;
3881 StartNode++;
3882 MiddleNode++;
3883 EndNode++;
3884 if (StartNode == connectedPath->end())
3885 StartNode = connectedPath->begin();
3886 if (MiddleNode == connectedPath->end())
3887 MiddleNode = connectedPath->begin();
3888 if (EndNode == connectedPath->end())
3889 EndNode = connectedPath->begin();
3890 continue;
3891 }
3892 Log() << Verbose(3) << "Adding new triangle points."<< endl;
3893 AddTesselationPoint(*StartNode, 0);
3894 AddTesselationPoint(*MiddleNode, 1);
3895 AddTesselationPoint(*EndNode, 2);
3896 Log() << Verbose(3) << "Adding new triangle lines."<< endl;
3897 AddTesselationLine(TPS[0], TPS[1], 0);
3898 AddTesselationLine(TPS[0], TPS[2], 1);
3899 NewLines.push_back(BLS[1]);
3900 AddTesselationLine(TPS[1], TPS[2], 2);
3901 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
3902 BTS->GetNormalVector(NormalVector);
3903 AddTesselationTriangle();
3904 // calculate volume summand as a general tetraeder
3905 volume += CalculateVolumeofGeneralTetraeder(*TPS[0]->node->node, *TPS[1]->node->node, *TPS[2]->node->node, OldPoint);
3906 // advance number
3907 count++;
3908
3909 // prepare nodes for next triangle
3910 StartNode = EndNode;
3911 Log() << Verbose(2) << "Removing " << **MiddleNode << " from closed path, remaining points: " << connectedPath->size() << "." << endl;
3912 connectedPath->remove(*MiddleNode); // remove the middle node (it is surrounded by triangles)
3913 if (connectedPath->size() == 2) { // we are done
3914 connectedPath->remove(*StartNode); // remove the start node
3915 connectedPath->remove(*EndNode); // remove the end node
3916 break;
3917 } else if (connectedPath->size() < 2) { // something's gone wrong!
3918 eLog() << Verbose(0) << "CRITICAL: There are only two endpoints left!" << endl;
3919 performCriticalExit();
3920 } else {
3921 MiddleNode = StartNode;
3922 MiddleNode++;
3923 if (MiddleNode == connectedPath->end())
3924 MiddleNode = connectedPath->begin();
3925 EndNode = MiddleNode;
3926 EndNode++;
3927 if (EndNode == connectedPath->end())
3928 EndNode = connectedPath->begin();
3929 }
3930 }
3931 // maximize the inner lines (we preferentially created lines with a huge angle, which is for the tesselation not wanted though useful for the closing)
3932 if (NewLines.size() > 1) {
3933 list<class BoundaryLineSet *>::iterator Candidate;
3934 class BoundaryLineSet *OtherBase = NULL;
3935 double tmp, maxgain;
3936 do {
3937 maxgain = 0;
3938 for(list<class BoundaryLineSet *>::iterator Runner = NewLines.begin(); Runner != NewLines.end(); Runner++) {
3939 tmp = PickFarthestofTwoBaselines(*Runner);
3940 if (maxgain < tmp) {
3941 maxgain = tmp;
3942 Candidate = Runner;
3943 }
3944 }
3945 if (maxgain != 0) {
3946 volume += maxgain;
3947 Log() << Verbose(1) << "Flipping baseline with highest volume" << **Candidate << "." << endl;
3948 OtherBase = FlipBaseline(*Candidate);
3949 NewLines.erase(Candidate);
3950 NewLines.push_back(OtherBase);
3951 }
3952 } while (maxgain != 0.);
3953 }
3954
3955 ListOfClosedPaths->remove(connectedPath);
3956 delete(connectedPath);
3957 }
3958 Log() << Verbose(0) << count << " triangles were created." << endl;
3959 } else {
3960 while (!ListOfClosedPaths->empty()) {
3961 ListRunner = ListOfClosedPaths->begin();
3962 connectedPath = *ListRunner;
3963 ListOfClosedPaths->remove(connectedPath);
3964 delete(connectedPath);
3965 }
3966 Log() << Verbose(0) << "No need to create any triangles." << endl;
3967 }
3968 delete(ListOfClosedPaths);
3969
3970 Log() << Verbose(0) << "Removed volume is " << volume << "." << endl;
3971
3972 return volume;
3973};
3974
3975
3976
3977/**
3978 * Finds triangles belonging to the three provided points.
3979 *
3980 * @param *Points[3] list, is expected to contain three points (NULL means wildcard)
3981 *
3982 * @return triangles which belong to the provided points, will be empty if there are none,
3983 * will usually be one, in case of degeneration, there will be two
3984 */
3985list<BoundaryTriangleSet*> *Tesselation::FindTriangles(const TesselPoint* const Points[3]) const
3986{
3987 Info FunctionInfo(__func__);
3988 list<BoundaryTriangleSet*> *result = new list<BoundaryTriangleSet*>;
3989 LineMap::const_iterator FindLine;
3990 TriangleMap::const_iterator FindTriangle;
3991 class BoundaryPointSet *TrianglePoints[3];
3992 size_t NoOfWildcards = 0;
3993
3994 for (int i = 0; i < 3; i++) {
3995 if (Points[i] == NULL) {
3996 NoOfWildcards++;
3997 TrianglePoints[i] = NULL;
3998 } else {
3999 PointMap::const_iterator FindPoint = PointsOnBoundary.find(Points[i]->nr);
4000 if (FindPoint != PointsOnBoundary.end()) {
4001 TrianglePoints[i] = FindPoint->second;
4002 } else {
4003 TrianglePoints[i] = NULL;
4004 }
4005 }
4006 }
4007
4008 switch (NoOfWildcards) {
4009 case 0: // checks lines between the points in the Points for their adjacent triangles
4010 for (int i = 0; i < 3; i++) {
4011 if (TrianglePoints[i] != NULL) {
4012 for (int j = i+1; j < 3; j++) {
4013 if (TrianglePoints[j] != NULL) {
4014 for (FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr); // is a multimap!
4015 (FindLine != TrianglePoints[i]->lines.end()) && (FindLine->first == TrianglePoints[j]->node->nr);
4016 FindLine++) {
4017 for (FindTriangle = FindLine->second->triangles.begin();
4018 FindTriangle != FindLine->second->triangles.end();
4019 FindTriangle++) {
4020 if (FindTriangle->second->IsPresentTupel(TrianglePoints)) {
4021 result->push_back(FindTriangle->second);
4022 }
4023 }
4024 }
4025 // Is it sufficient to consider one of the triangle lines for this.
4026 return result;
4027 }
4028 }
4029 }
4030 }
4031 break;
4032 case 1: // copy all triangles of the respective line
4033 {
4034 int i=0;
4035 for (; i < 3; i++)
4036 if (TrianglePoints[i] == NULL)
4037 break;
4038 for (FindLine = TrianglePoints[(i+1)%3]->lines.find(TrianglePoints[(i+2)%3]->node->nr); // is a multimap!
4039 (FindLine != TrianglePoints[(i+1)%3]->lines.end()) && (FindLine->first == TrianglePoints[(i+2)%3]->node->nr);
4040 FindLine++) {
4041 for (FindTriangle = FindLine->second->triangles.begin();
4042 FindTriangle != FindLine->second->triangles.end();
4043 FindTriangle++) {
4044 if (FindTriangle->second->IsPresentTupel(TrianglePoints)) {
4045 result->push_back(FindTriangle->second);
4046 }
4047 }
4048 }
4049 break;
4050 }
4051 case 2: // copy all triangles of the respective point
4052 {
4053 int i=0;
4054 for (; i < 3; i++)
4055 if (TrianglePoints[i] != NULL)
4056 break;
4057 for (LineMap::const_iterator line = TrianglePoints[i]->lines.begin(); line != TrianglePoints[i]->lines.end(); line++)
4058 for (TriangleMap::const_iterator triangle = line->second->triangles.begin(); triangle != line->second->triangles.end(); triangle++)
4059 result->push_back(triangle->second);
4060 result->sort();
4061 result->unique();
4062 break;
4063 }
4064 case 3: // copy all triangles
4065 {
4066 for (TriangleMap::const_iterator triangle = TrianglesOnBoundary.begin(); triangle != TrianglesOnBoundary.end(); triangle++)
4067 result->push_back(triangle->second);
4068 break;
4069 }
4070 default:
4071 eLog() << Verbose(0) << "Number of wildcards is greater than 3, cannot happen!" << endl;
4072 performCriticalExit();
4073 break;
4074 }
4075
4076 return result;
4077}
4078
4079struct BoundaryLineSetCompare {
4080 bool operator() (const BoundaryLineSet * const a, const BoundaryLineSet * const b) {
4081 int lowerNra = -1;
4082 int lowerNrb = -1;
4083
4084 if (a->endpoints[0] < a->endpoints[1])
4085 lowerNra = 0;
4086 else
4087 lowerNra = 1;
4088
4089 if (b->endpoints[0] < b->endpoints[1])
4090 lowerNrb = 0;
4091 else
4092 lowerNrb = 1;
4093
4094 if (a->endpoints[lowerNra] < b->endpoints[lowerNrb])
4095 return true;
4096 else if (a->endpoints[lowerNra] > b->endpoints[lowerNrb])
4097 return false;
4098 else { // both lower-numbered endpoints are the same ...
4099 if (a->endpoints[(lowerNra+1)%2] < b->endpoints[(lowerNrb+1)%2])
4100 return true;
4101 else if (a->endpoints[(lowerNra+1)%2] > b->endpoints[(lowerNrb+1)%2])
4102 return false;
4103 }
4104 return false;
4105 };
4106};
4107
4108#define UniqueLines set < class BoundaryLineSet *, BoundaryLineSetCompare>
4109
4110/**
4111 * Finds all degenerated lines within the tesselation structure.
4112 *
4113 * @return map of keys of degenerated line pairs, each line occurs twice
4114 * in the list, once as key and once as value
4115 */
4116map<int, int> * Tesselation::FindAllDegeneratedLines()
4117{
4118 Info FunctionInfo(__func__);
4119 UniqueLines AllLines;
4120 map<int, int> * DegeneratedLines = new map<int, int>;
4121
4122 // sanity check
4123 if (LinesOnBoundary.empty()) {
4124 eLog() << Verbose(2) << "FindAllDegeneratedTriangles() was called without any tesselation structure.";
4125 return DegeneratedLines;
4126 }
4127
4128 LineMap::iterator LineRunner1;
4129 pair< UniqueLines::iterator, bool> tester;
4130 for (LineRunner1 = LinesOnBoundary.begin(); LineRunner1 != LinesOnBoundary.end(); ++LineRunner1) {
4131 tester = AllLines.insert( LineRunner1->second );
4132 if (!tester.second) { // found degenerated line
4133 DegeneratedLines->insert ( pair<int, int> (LineRunner1->second->Nr, (*tester.first)->Nr) );
4134 DegeneratedLines->insert ( pair<int, int> ((*tester.first)->Nr, LineRunner1->second->Nr) );
4135 }
4136 }
4137
4138 AllLines.clear();
4139
4140 Log() << Verbose(0) << "FindAllDegeneratedLines() found " << DegeneratedLines->size() << " lines." << endl;
4141 map<int,int>::iterator it;
4142 for (it = DegeneratedLines->begin(); it != DegeneratedLines->end(); it++) {
4143 const LineMap::const_iterator Line1 = LinesOnBoundary.find((*it).first);
4144 const LineMap::const_iterator Line2 = LinesOnBoundary.find((*it).second);
4145 if (Line1 != LinesOnBoundary.end() && Line2 != LinesOnBoundary.end())
4146 Log() << Verbose(0) << *Line1->second << " => " << *Line2->second << endl;
4147 else
4148 eLog() << Verbose(1) << "Either " << (*it).first << " or " << (*it).second << " are not in LinesOnBoundary!" << endl;
4149 }
4150
4151 return DegeneratedLines;
4152}
4153
4154/**
4155 * Finds all degenerated triangles within the tesselation structure.
4156 *
4157 * @return map of keys of degenerated triangle pairs, each triangle occurs twice
4158 * in the list, once as key and once as value
4159 */
4160map<int, int> * Tesselation::FindAllDegeneratedTriangles()
4161{
4162 Info FunctionInfo(__func__);
4163 map<int, int> * DegeneratedLines = FindAllDegeneratedLines();
4164 map<int, int> * DegeneratedTriangles = new map<int, int>;
4165
4166 TriangleMap::iterator TriangleRunner1, TriangleRunner2;
4167 LineMap::iterator Liner;
4168 class BoundaryLineSet *line1 = NULL, *line2 = NULL;
4169
4170 for (map<int, int>::iterator LineRunner = DegeneratedLines->begin(); LineRunner != DegeneratedLines->end(); ++LineRunner) {
4171 // run over both lines' triangles
4172 Liner = LinesOnBoundary.find(LineRunner->first);
4173 if (Liner != LinesOnBoundary.end())
4174 line1 = Liner->second;
4175 Liner = LinesOnBoundary.find(LineRunner->second);
4176 if (Liner != LinesOnBoundary.end())
4177 line2 = Liner->second;
4178 for (TriangleRunner1 = line1->triangles.begin(); TriangleRunner1 != line1->triangles.end(); ++TriangleRunner1) {
4179 for (TriangleRunner2 = line2->triangles.begin(); TriangleRunner2 != line2->triangles.end(); ++TriangleRunner2) {
4180 if ((TriangleRunner1->second != TriangleRunner2->second)
4181 && (TriangleRunner1->second->IsPresentTupel(TriangleRunner2->second))) {
4182 DegeneratedTriangles->insert( pair<int, int> (TriangleRunner1->second->Nr, TriangleRunner2->second->Nr) );
4183 DegeneratedTriangles->insert( pair<int, int> (TriangleRunner2->second->Nr, TriangleRunner1->second->Nr) );
4184 }
4185 }
4186 }
4187 }
4188 delete(DegeneratedLines);
4189
4190 Log() << Verbose(0) << "FindAllDegeneratedTriangles() found " << DegeneratedTriangles->size() << " triangles:" << endl;
4191 map<int,int>::iterator it;
4192 for (it = DegeneratedTriangles->begin(); it != DegeneratedTriangles->end(); it++)
4193 Log() << Verbose(0) << (*it).first << " => " << (*it).second << endl;
4194
4195 return DegeneratedTriangles;
4196}
4197
4198/**
4199 * Purges degenerated triangles from the tesselation structure if they are not
4200 * necessary to keep a single point within the structure.
4201 */
4202void Tesselation::RemoveDegeneratedTriangles()
4203{
4204 Info FunctionInfo(__func__);
4205 map<int, int> * DegeneratedTriangles = FindAllDegeneratedTriangles();
4206 TriangleMap::iterator finder;
4207 BoundaryTriangleSet *triangle = NULL, *partnerTriangle = NULL;
4208 int count = 0;
4209
4210 for (map<int, int>::iterator TriangleKeyRunner = DegeneratedTriangles->begin();
4211 TriangleKeyRunner != DegeneratedTriangles->end(); ++TriangleKeyRunner
4212 ) {
4213 finder = TrianglesOnBoundary.find(TriangleKeyRunner->first);
4214 if (finder != TrianglesOnBoundary.end())
4215 triangle = finder->second;
4216 else
4217 break;
4218 finder = TrianglesOnBoundary.find(TriangleKeyRunner->second);
4219 if (finder != TrianglesOnBoundary.end())
4220 partnerTriangle = finder->second;
4221 else
4222 break;
4223
4224 bool trianglesShareLine = false;
4225 for (int i = 0; i < 3; ++i)
4226 for (int j = 0; j < 3; ++j)
4227 trianglesShareLine = trianglesShareLine || triangle->lines[i] == partnerTriangle->lines[j];
4228
4229 if (trianglesShareLine
4230 && (triangle->endpoints[1]->LinesCount > 2)
4231 && (triangle->endpoints[2]->LinesCount > 2)
4232 && (triangle->endpoints[0]->LinesCount > 2)
4233 ) {
4234 // check whether we have to fix lines
4235 BoundaryTriangleSet *Othertriangle = NULL;
4236 BoundaryTriangleSet *OtherpartnerTriangle = NULL;
4237 TriangleMap::iterator TriangleRunner;
4238 for (int i = 0; i < 3; ++i)
4239 for (int j = 0; j < 3; ++j)
4240 if (triangle->lines[i] != partnerTriangle->lines[j]) {
4241 // get the other two triangles
4242 for (TriangleRunner = triangle->lines[i]->triangles.begin(); TriangleRunner != triangle->lines[i]->triangles.end(); ++TriangleRunner)
4243 if (TriangleRunner->second != triangle) {
4244 Othertriangle = TriangleRunner->second;
4245 }
4246 for (TriangleRunner = partnerTriangle->lines[i]->triangles.begin(); TriangleRunner != partnerTriangle->lines[i]->triangles.end(); ++TriangleRunner)
4247 if (TriangleRunner->second != partnerTriangle) {
4248 OtherpartnerTriangle = TriangleRunner->second;
4249 }
4250 /// interchanges their lines so that triangle->lines[i] == partnerTriangle->lines[j]
4251 // the line of triangle receives the degenerated ones
4252 triangle->lines[i]->triangles.erase(Othertriangle->Nr);
4253 triangle->lines[i]->triangles.insert( TrianglePair( partnerTriangle->Nr, partnerTriangle) );
4254 for (int k=0;k<3;k++)
4255 if (triangle->lines[i] == Othertriangle->lines[k]) {
4256 Othertriangle->lines[k] = partnerTriangle->lines[j];
4257 break;
4258 }
4259 // the line of partnerTriangle receives the non-degenerated ones
4260 partnerTriangle->lines[j]->triangles.erase( partnerTriangle->Nr);
4261 partnerTriangle->lines[j]->triangles.insert( TrianglePair( Othertriangle->Nr, Othertriangle) );
4262 partnerTriangle->lines[j] = triangle->lines[i];
4263 }
4264
4265 // erase the pair
4266 count += (int) DegeneratedTriangles->erase(triangle->Nr);
4267 Log() << Verbose(0) << "RemoveDegeneratedTriangles() removes triangle " << *triangle << "." << endl;
4268 RemoveTesselationTriangle(triangle);
4269 count += (int) DegeneratedTriangles->erase(partnerTriangle->Nr);
4270 Log() << Verbose(0) << "RemoveDegeneratedTriangles() removes triangle " << *partnerTriangle << "." << endl;
4271 RemoveTesselationTriangle(partnerTriangle);
4272 } else {
4273 Log() << Verbose(0) << "RemoveDegeneratedTriangles() does not remove triangle " << *triangle
4274 << " and its partner " << *partnerTriangle << " because it is essential for at"
4275 << " least one of the endpoints to be kept in the tesselation structure." << endl;
4276 }
4277 }
4278 delete(DegeneratedTriangles);
4279 if (count > 0)
4280 LastTriangle = NULL;
4281
4282 Log() << Verbose(0) << "RemoveDegeneratedTriangles() removed " << count << " triangles:" << endl;
4283}
4284
4285/** Adds an outside Tesselpoint to the envelope via (two) degenerated triangles.
4286 * We look for the closest point on the boundary, we look through its connected boundary lines and
4287 * seek the one with the minimum angle between its center point and the new point and this base line.
4288 * We open up the line by adding a degenerated triangle, whose other side closes the base line again.
4289 * \param *out output stream for debugging
4290 * \param *point point to add
4291 * \param *LC Linked Cell structure to find nearest point
4292 */
4293void Tesselation::AddBoundaryPointByDegeneratedTriangle(class TesselPoint *point, LinkedCell *LC)
4294{
4295 Info FunctionInfo(__func__);
4296 // find nearest boundary point
4297 class TesselPoint *BackupPoint = NULL;
4298 class TesselPoint *NearestPoint = FindClosestTesselPoint(point->node, BackupPoint, LC);
4299 class BoundaryPointSet *NearestBoundaryPoint = NULL;
4300 PointMap::iterator PointRunner;
4301
4302 if (NearestPoint == point)
4303 NearestPoint = BackupPoint;
4304 PointRunner = PointsOnBoundary.find(NearestPoint->nr);
4305 if (PointRunner != PointsOnBoundary.end()) {
4306 NearestBoundaryPoint = PointRunner->second;
4307 } else {
4308 eLog() << Verbose(1) << "I cannot find the boundary point." << endl;
4309 return;
4310 }
4311 Log() << Verbose(0) << "Nearest point on boundary is " << NearestPoint->Name << "." << endl;
4312
4313 // go through its lines and find the best one to split
4314 Vector CenterToPoint;
4315 Vector BaseLine;
4316 double angle, BestAngle = 0.;
4317 class BoundaryLineSet *BestLine = NULL;
4318 for (LineMap::iterator Runner = NearestBoundaryPoint->lines.begin(); Runner != NearestBoundaryPoint->lines.end(); Runner++) {
4319 BaseLine.CopyVector(Runner->second->endpoints[0]->node->node);
4320 BaseLine.SubtractVector(Runner->second->endpoints[1]->node->node);
4321 CenterToPoint.CopyVector(Runner->second->endpoints[0]->node->node);
4322 CenterToPoint.AddVector(Runner->second->endpoints[1]->node->node);
4323 CenterToPoint.Scale(0.5);
4324 CenterToPoint.SubtractVector(point->node);
4325 angle = CenterToPoint.Angle(&BaseLine);
4326 if (fabs(angle - M_PI/2.) < fabs(BestAngle - M_PI/2.)) {
4327 BestAngle = angle;
4328 BestLine = Runner->second;
4329 }
4330 }
4331
4332 // remove one triangle from the chosen line
4333 class BoundaryTriangleSet *TempTriangle = (BestLine->triangles.begin())->second;
4334 BestLine->triangles.erase(TempTriangle->Nr);
4335 int nr = -1;
4336 for (int i=0;i<3; i++) {
4337 if (TempTriangle->lines[i] == BestLine) {
4338 nr = i;
4339 break;
4340 }
4341 }
4342
4343 // create new triangle to connect point (connects automatically with the missing spot of the chosen line)
4344 Log() << Verbose(2) << "Adding new triangle points."<< endl;
4345 AddTesselationPoint((BestLine->endpoints[0]->node), 0);
4346 AddTesselationPoint((BestLine->endpoints[1]->node), 1);
4347 AddTesselationPoint(point, 2);
4348 Log() << Verbose(2) << "Adding new triangle lines."<< endl;
4349 AddTesselationLine(TPS[0], TPS[1], 0);
4350 AddTesselationLine(TPS[0], TPS[2], 1);
4351 AddTesselationLine(TPS[1], TPS[2], 2);
4352 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
4353 BTS->GetNormalVector(TempTriangle->NormalVector);
4354 BTS->NormalVector.Scale(-1.);
4355 Log() << Verbose(1) << "INFO: NormalVector of new triangle is " << BTS->NormalVector << "." << endl;
4356 AddTesselationTriangle();
4357
4358 // create other side of this triangle and close both new sides of the first created triangle
4359 Log() << Verbose(2) << "Adding new triangle points."<< endl;
4360 AddTesselationPoint((BestLine->endpoints[0]->node), 0);
4361 AddTesselationPoint((BestLine->endpoints[1]->node), 1);
4362 AddTesselationPoint(point, 2);
4363 Log() << Verbose(2) << "Adding new triangle lines."<< endl;
4364 AddTesselationLine(TPS[0], TPS[1], 0);
4365 AddTesselationLine(TPS[0], TPS[2], 1);
4366 AddTesselationLine(TPS[1], TPS[2], 2);
4367 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
4368 BTS->GetNormalVector(TempTriangle->NormalVector);
4369 Log() << Verbose(1) << "INFO: NormalVector of other new triangle is " << BTS->NormalVector << "." << endl;
4370 AddTesselationTriangle();
4371
4372 // add removed triangle to the last open line of the second triangle
4373 for (int i=0;i<3;i++) { // look for the same line as BestLine (only it's its degenerated companion)
4374 if ((BTS->lines[i]->ContainsBoundaryPoint(BestLine->endpoints[0])) && (BTS->lines[i]->ContainsBoundaryPoint(BestLine->endpoints[1]))) {
4375 if (BestLine == BTS->lines[i]){
4376 eLog() << Verbose(0) << "BestLine is same as found line, something's wrong here!" << endl;
4377 performCriticalExit();
4378 }
4379 BTS->lines[i]->triangles.insert( pair<int, class BoundaryTriangleSet *> (TempTriangle->Nr, TempTriangle) );
4380 TempTriangle->lines[nr] = BTS->lines[i];
4381 break;
4382 }
4383 }
4384};
4385
4386/** Writes the envelope to file.
4387 * \param *out otuput stream for debugging
4388 * \param *filename basename of output file
4389 * \param *cloud PointCloud structure with all nodes
4390 */
4391void Tesselation::Output(const char *filename, const PointCloud * const cloud)
4392{
4393 Info FunctionInfo(__func__);
4394 ofstream *tempstream = NULL;
4395 string NameofTempFile;
4396 char NumberName[255];
4397
4398 if (LastTriangle != NULL) {
4399 sprintf(NumberName, "-%04d-%s_%s_%s", (int)TrianglesOnBoundary.size(), LastTriangle->endpoints[0]->node->Name, LastTriangle->endpoints[1]->node->Name, LastTriangle->endpoints[2]->node->Name);
4400 if (DoTecplotOutput) {
4401 string NameofTempFile(filename);
4402 NameofTempFile.append(NumberName);
4403 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
4404 NameofTempFile.erase(npos, 1);
4405 NameofTempFile.append(TecplotSuffix);
4406 Log() << Verbose(0) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
4407 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
4408 WriteTecplotFile(tempstream, this, cloud, TriangleFilesWritten);
4409 tempstream->close();
4410 tempstream->flush();
4411 delete(tempstream);
4412 }
4413
4414 if (DoRaster3DOutput) {
4415 string NameofTempFile(filename);
4416 NameofTempFile.append(NumberName);
4417 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
4418 NameofTempFile.erase(npos, 1);
4419 NameofTempFile.append(Raster3DSuffix);
4420 Log() << Verbose(0) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
4421 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
4422 WriteRaster3dFile(tempstream, this, cloud);
4423 IncludeSphereinRaster3D(tempstream, this, cloud);
4424 tempstream->close();
4425 tempstream->flush();
4426 delete(tempstream);
4427 }
4428 }
4429 if (DoTecplotOutput || DoRaster3DOutput)
4430 TriangleFilesWritten++;
4431};
4432
4433struct BoundaryPolygonSetCompare {
4434 bool operator()(const BoundaryPolygonSet * s1, const BoundaryPolygonSet * s2) const {
4435 if (s1->endpoints.size() < s2->endpoints.size())
4436 return true;
4437 else if (s1->endpoints.size() > s2->endpoints.size())
4438 return false;
4439 else { // equality of number of endpoints
4440 PointSet::const_iterator Walker1 = s1->endpoints.begin();
4441 PointSet::const_iterator Walker2 = s2->endpoints.begin();
4442 while ((Walker1 != s1->endpoints.end()) || (Walker2 != s2->endpoints.end())) {
4443 if ((*Walker1)->Nr < (*Walker2)->Nr)
4444 return true;
4445 else if ((*Walker1)->Nr > (*Walker2)->Nr)
4446 return false;
4447 Walker1++;
4448 Walker2++;
4449 }
4450 return false;
4451 }
4452 }
4453};
4454
4455#define UniquePolygonSet set < BoundaryPolygonSet *, BoundaryPolygonSetCompare>
4456
4457/** Finds all degenerated polygons and calls ReTesselateDegeneratedPolygon()/
4458 * \return number of polygons found
4459 */
4460int Tesselation::CorrectAllDegeneratedPolygons()
4461{
4462 Info FunctionInfo(__func__);
4463
4464 /// 2. Go through all BoundaryPointSet's, check their triangles' NormalVector
4465 map <int, int> *DegeneratedTriangles = FindAllDegeneratedTriangles();
4466 set < BoundaryPointSet *> EndpointCandidateList;
4467 pair < set < BoundaryPointSet *>::iterator, bool > InsertionTester;
4468 pair < map < int, Vector *>::iterator, bool > TriangleInsertionTester;
4469 for (PointMap::const_iterator Runner = PointsOnBoundary.begin(); Runner != PointsOnBoundary.end(); Runner++) {
4470 Log() << Verbose(0) << "Current point is " << *Runner->second << "." << endl;
4471 map < int, Vector *> TriangleVectors;
4472 // gather all NormalVectors
4473 Log() << Verbose(1) << "Gathering triangles ..." << endl;
4474 for (LineMap::const_iterator LineRunner = (Runner->second)->lines.begin(); LineRunner != (Runner->second)->lines.end(); LineRunner++)
4475 for (TriangleMap::const_iterator TriangleRunner = (LineRunner->second)->triangles.begin(); TriangleRunner != (LineRunner->second)->triangles.end(); TriangleRunner++) {
4476 if (DegeneratedTriangles->find(TriangleRunner->second->Nr) == DegeneratedTriangles->end()) {
4477 TriangleInsertionTester = TriangleVectors.insert( pair< int, Vector *> ((TriangleRunner->second)->Nr, &((TriangleRunner->second)->NormalVector)) );
4478 if (TriangleInsertionTester.second)
4479 Log() << Verbose(1) << " Adding triangle " << *(TriangleRunner->second) << " to triangles to check-list." << endl;
4480 } else {
4481 Log() << Verbose(1) << " NOT adding triangle " << *(TriangleRunner->second) << " as it's a simply degenerated one." << endl;
4482 }
4483 }
4484 // check whether there are two that are parallel
4485 Log() << Verbose(1) << "Finding two parallel triangles ..." << endl;
4486 for (map < int, Vector *>::iterator VectorWalker = TriangleVectors.begin(); VectorWalker != TriangleVectors.end(); VectorWalker++)
4487 for (map < int, Vector *>::iterator VectorRunner = VectorWalker; VectorRunner != TriangleVectors.end(); VectorRunner++)
4488 if (VectorWalker != VectorRunner) { // skip equals
4489 const double SCP = VectorWalker->second->ScalarProduct(VectorRunner->second); // ScalarProduct should result in -1. for degenerated triangles
4490 Log() << Verbose(1) << "Checking " << *VectorWalker->second<< " against " << *VectorRunner->second << ": " << SCP << endl;
4491 if (fabs(SCP + 1.) < ParallelEpsilon) {
4492 InsertionTester = EndpointCandidateList.insert((Runner->second));
4493 if (InsertionTester.second)
4494 Log() << Verbose(0) << " Adding " << *Runner->second << " to endpoint candidate list." << endl;
4495 // and break out of both loops
4496 VectorWalker = TriangleVectors.end();
4497 VectorRunner = TriangleVectors.end();
4498 break;
4499 }
4500 }
4501 }
4502
4503 /// 3. Find connected endpoint candidates and put them into a polygon
4504 UniquePolygonSet ListofDegeneratedPolygons;
4505 BoundaryPointSet *Walker = NULL;
4506 BoundaryPointSet *OtherWalker = NULL;
4507 BoundaryPolygonSet *Current = NULL;
4508 stack <BoundaryPointSet*> ToCheckConnecteds;
4509 while (!EndpointCandidateList.empty()) {
4510 Walker = *(EndpointCandidateList.begin());
4511 if (Current == NULL) { // create a new polygon with current candidate
4512 Log() << Verbose(0) << "Starting new polygon set at point " << *Walker << endl;
4513 Current = new BoundaryPolygonSet;
4514 Current->endpoints.insert(Walker);
4515 EndpointCandidateList.erase(Walker);
4516 ToCheckConnecteds.push(Walker);
4517 }
4518
4519 // go through to-check stack
4520 while (!ToCheckConnecteds.empty()) {
4521 Walker = ToCheckConnecteds.top(); // fetch ...
4522 ToCheckConnecteds.pop(); // ... and remove
4523 for (LineMap::const_iterator LineWalker = Walker->lines.begin(); LineWalker != Walker->lines.end(); LineWalker++) {
4524 OtherWalker = (LineWalker->second)->GetOtherEndpoint(Walker);
4525 Log() << Verbose(1) << "Checking " << *OtherWalker << endl;
4526 set < BoundaryPointSet *>::iterator Finder = EndpointCandidateList.find(OtherWalker);
4527 if (Finder != EndpointCandidateList.end()) { // found a connected partner
4528 Log() << Verbose(1) << " Adding to polygon." << endl;
4529 Current->endpoints.insert(OtherWalker);
4530 EndpointCandidateList.erase(Finder); // remove from candidates
4531 ToCheckConnecteds.push(OtherWalker); // but check its partners too
4532 } else {
4533 Log() << Verbose(1) << " is not connected to " << *Walker << endl;
4534 }
4535 }
4536 }
4537
4538 Log() << Verbose(0) << "Final polygon is " << *Current << endl;
4539 ListofDegeneratedPolygons.insert(Current);
4540 Current = NULL;
4541 }
4542
4543 const int counter = ListofDegeneratedPolygons.size();
4544
4545 Log() << Verbose(0) << "The following " << counter << " degenerated polygons have been found: " << endl;
4546 for (UniquePolygonSet::iterator PolygonRunner = ListofDegeneratedPolygons.begin(); PolygonRunner != ListofDegeneratedPolygons.end(); PolygonRunner++)
4547 Log() << Verbose(0) << " " << **PolygonRunner << endl;
4548
4549 /// 4. Go through all these degenerated polygons
4550 for (UniquePolygonSet::iterator PolygonRunner = ListofDegeneratedPolygons.begin(); PolygonRunner != ListofDegeneratedPolygons.end(); PolygonRunner++) {
4551 stack <int> TriangleNrs;
4552 Vector NormalVector;
4553 /// 4a. Gather all triangles of this polygon
4554 TriangleSet *T = (*PolygonRunner)->GetAllContainedTrianglesFromEndpoints();
4555
4556 // check whether number is bigger than 2, otherwise it's just a simply degenerated one and nothing to do.
4557 if (T->size() == 2) {
4558 Log() << Verbose(1) << " Skipping degenerated polygon, is just a (already simply degenerated) triangle." << endl;
4559 delete(T);
4560 continue;
4561 }
4562
4563 // check whether number is even
4564 // If this case occurs, we have to think about it!
4565 // The Problem is probably due to two degenerated polygons being connected by a bridging, non-degenerated polygon, as somehow one node has
4566 // connections to either polygon ...
4567 if (T->size() % 2 != 0) {
4568 eLog() << Verbose(0) << " degenerated polygon contains an odd number of triangles, probably contains bridging non-degenerated ones, too!" << endl;
4569 performCriticalExit();
4570 }
4571
4572 TriangleSet::iterator TriangleWalker = T->begin(); // is the inner iterator
4573 /// 4a. Get NormalVector for one side (this is "front")
4574 NormalVector.CopyVector(&(*TriangleWalker)->NormalVector);
4575 Log() << Verbose(1) << "\"front\" defining triangle is " << **TriangleWalker << " and Normal vector of \"front\" side is " << NormalVector << endl;
4576 TriangleWalker++;
4577 TriangleSet::iterator TriangleSprinter = TriangleWalker; // is the inner advanced iterator
4578 /// 4b. Remove all triangles whose NormalVector is in opposite direction (i.e. "back")
4579 BoundaryTriangleSet *triangle = NULL;
4580 while (TriangleSprinter != T->end()) {
4581 TriangleWalker = TriangleSprinter;
4582 triangle = *TriangleWalker;
4583 TriangleSprinter++;
4584 Log() << Verbose(1) << "Current triangle to test for removal: " << *triangle << endl;
4585 if (triangle->NormalVector.ScalarProduct(&NormalVector) < 0) { // if from other side, then delete and remove from list
4586 Log() << Verbose(1) << " Removing ... " << endl;
4587 TriangleNrs.push(triangle->Nr);
4588 T->erase(TriangleWalker);
4589 RemoveTesselationTriangle(triangle);
4590 } else
4591 Log() << Verbose(1) << " Keeping ... " << endl;
4592 }
4593 /// 4c. Copy all "front" triangles but with inverse NormalVector
4594 TriangleWalker = T->begin();
4595 while (TriangleWalker != T->end()) { // go through all front triangles
4596 Log() << Verbose(1) << " Re-creating triangle " << **TriangleWalker << " with NormalVector " << (*TriangleWalker)->NormalVector << endl;
4597 for (int i = 0; i < 3; i++)
4598 AddTesselationPoint((*TriangleWalker)->endpoints[i]->node, i);
4599 AddTesselationLine(TPS[0], TPS[1], 0);
4600 AddTesselationLine(TPS[0], TPS[2], 1);
4601 AddTesselationLine(TPS[1], TPS[2], 2);
4602 if (TriangleNrs.empty())
4603 eLog() << Verbose(0) << "No more free triangle numbers!" << endl;
4604 BTS = new BoundaryTriangleSet(BLS, TriangleNrs.top()); // copy triangle ...
4605 AddTesselationTriangle(); // ... and add
4606 TriangleNrs.pop();
4607 BTS->NormalVector.CopyVector(&(*TriangleWalker)->NormalVector);
4608 BTS->NormalVector.Scale(-1.);
4609 TriangleWalker++;
4610 }
4611 if (!TriangleNrs.empty()) {
4612 eLog() << Verbose(0) << "There have been less triangles created than removed!" << endl;
4613 }
4614 delete(T); // remove the triangleset
4615 }
4616
4617 map<int, int> * SimplyDegeneratedTriangles = FindAllDegeneratedTriangles();
4618 Log() << Verbose(0) << "Final list of simply degenerated triangles found, containing " << SimplyDegeneratedTriangles->size() << " triangles:" << endl;
4619 map<int,int>::iterator it;
4620 for (it = SimplyDegeneratedTriangles->begin(); it != SimplyDegeneratedTriangles->end(); it++)
4621 Log() << Verbose(0) << (*it).first << " => " << (*it).second << endl;
4622 delete(SimplyDegeneratedTriangles);
4623
4624 /// 5. exit
4625 UniquePolygonSet::iterator PolygonRunner;
4626 while (!ListofDegeneratedPolygons.empty()) {
4627 PolygonRunner = ListofDegeneratedPolygons.begin();
4628 delete(*PolygonRunner);
4629 ListofDegeneratedPolygons.erase(PolygonRunner);
4630 }
4631
4632 return counter;
4633};
Note: See TracBrowser for help on using the repository browser.