source: src/tesselation.cpp@ 7b36fe

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

FillWithMolecule() is now working correctly.

  • FillWithMolecule() was almost working except for some positions very much outside. The problem was that a single closest point was found and its first line seen as shortest, despite all other connected lines were equally short due the point always being the one with shortest distance. This kept triangles better aligned from being excluded as they not necessarily belong to the first line
  • This was fixed by introducing a LineSet ClosestLines in Tesselation::FindClosestTrianglesToVector().
    • If a candidate has equal distance, he is added to the list.
    • If a candidate has smaller distance, the list is cleared beforehand.
    • As only the adjacent triangles of the found lines are returned, depending routines don't notice the change.

Signed-off-by: Frederik Heber <heber@…>

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