source: src/tesselation.cpp@ bdaacd

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 bdaacd was accebe, checked in by Frederik Heber <heber@…>, 15 years ago

Fix of PrepareClustersInWater (at least it does not stumble over memory issues).

  • note: this was just done to make check test Filling/2 work again (which only runs and does not check the output)
  • GetBoundaryPoints() - using now left and right to have a good runner even if it is discarded/deleted, flag check when loop is through
  • PrepareClustersinWater() - LCList is now a pointer and removed after FindConvexBorder()
  • DOCUFIX: Tesselation::RemoveTesselationTriangle() - triangles attached to lines are printed starting on next line, not current
  • BUGFIX: Tesselation::FlipBaseline() - as we remove the two connected triangles, the baseline who they are attached to will be deleted and removed, hence the loop over the line's triangles does not work. Now, we first put all into a list, then delete the triangles.

This was the last test to fail. All unit tests (33), all testsuite cases (45) and all tesselation tests (15) work.

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

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