source: molecuilder/src/tesselation.cpp@ 086db0

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

Rewrite of tesselation procedure: treatment of degenerated triangles.

The central idea is that when matching open lines are present, then we have to check whether candidate matches desired ThirdPoint and that the calculated OptCenter matches as well. The latter is essential for degenerated triangles, that can only be decerned by their (Other)OptCenter.

Asparagine is now tesselated correctly from radius 1.5 up to 25.

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