source: molecuilder/src/tesselation.cpp@ 1f2e46

Last change on this file since 1f2e46 was 1f2e46, checked in by Frederik Heber <heber@…>, 15 years ago

Huge change: Log() << Verbose(.) --> DoLog(.) && (Log() << Verbose(.) << ...);

Most of the files are affected, but this is necessary as if DoLog() says verbosity is not enough, all the stream operators won"t get executed which saves substantial amount of computation time.

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

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