source: src/tesselation.cpp@ 5c7bf8

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

BUGFIXes to Find_convex_... and Find_non_convex_... algorithms

  • Find_non_convex_border() - very first baseline of starting triangle is skipped as it is the most outward.
  • BoundaryLineSet::TrianglesCount is removed and replaced by triangles.size(), as it is redundant and we made mistakes in not reducing TrianglesCount on triangle erase.
  • BoundaryLineSet::CheckConvexityCriterion() - extra check when NormalVector point in the very same directions,
  • BoundaryTriangleSet::GetIntersectionInsideTriangle() - CrossPoint return value is checked, i===3 checked not >3!
  • new stream operator for TesselPoint with single argument.
  • class Tesselation inherits PointCloud and implements all functions (including virtual destructor) in order to have PointsOnBoundary parsable by LinkedCell.
  • Tesselation::InsertStraddlingPoints() - LinkedCell is created for every atom just from the BoundaryPoints and not for all (so that only BoundaryPoints can be found), old triangle is now really deleted, lots of verbosity added and fixed.
  • Tesselation::GetCommonEndpoint() - connectedClosestPoint is deleted lateron, SecondPoint argument but not used.
  • Tesselation::FindClosestPoint() - returns second second closest point in new second argument.
  • Tesselation::getCircleOfConnectedPoints() - we find the BoundaryPoint if possible and just look through its lines if found, plane is centered at closest point and normal is between it and the center of all on circle, getAngle() corrections incorporated and vector is always projected onto circle plane.
  • new function Tesselation findSecondClosestPoint().
  • getAngle() - just receives third vector with which it dedices between [0,pi) and [pi,2pi), the vectors are assumed to be relative to one common center already.
  • Property mode set to 100644
File size: 109.3 KB
Line 
1/*
2 * tesselation.cpp
3 *
4 * Created on: Aug 3, 2009
5 * Author: heber
6 */
7
8#include "tesselation.hpp"
9
10// ======================================== Points on Boundary =================================
11
12BoundaryPointSet::BoundaryPointSet()
13{
14 LinesCount = 0;
15 Nr = -1;
16}
17;
18
19BoundaryPointSet::BoundaryPointSet(TesselPoint *Walker)
20{
21 node = Walker;
22 LinesCount = 0;
23 Nr = Walker->nr;
24}
25;
26
27BoundaryPointSet::~BoundaryPointSet()
28{
29 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
30 if (!lines.empty())
31 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some lines." << endl;
32 node = NULL;
33}
34;
35
36void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
37{
38 cout << Verbose(6) << "Adding " << *this << " to line " << *line << "."
39 << endl;
40 if (line->endpoints[0] == this)
41 {
42 lines.insert(LinePair(line->endpoints[1]->Nr, line));
43 }
44 else
45 {
46 lines.insert(LinePair(line->endpoints[0]->Nr, line));
47 }
48 LinesCount++;
49}
50;
51
52ostream &
53operator <<(ostream &ost, BoundaryPointSet &a)
54{
55 ost << "[" << a.Nr << "|" << a.node->Name << "]";
56 return ost;
57}
58;
59
60// ======================================== Lines on Boundary =================================
61
62BoundaryLineSet::BoundaryLineSet()
63{
64 for (int i = 0; i < 2; i++)
65 endpoints[i] = NULL;
66 Nr = -1;
67}
68;
69
70BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
71{
72 // set number
73 Nr = number;
74 // set endpoints in ascending order
75 SetEndpointsOrdered(endpoints, Point[0], Point[1]);
76 // add this line to the hash maps of both endpoints
77 Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.
78 Point[1]->AddLine(this); //
79 // clear triangles list
80 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
81}
82;
83
84BoundaryLineSet::~BoundaryLineSet()
85{
86 int Numbers[2];
87 Numbers[0] = endpoints[1]->Nr;
88 Numbers[1] = endpoints[0]->Nr;
89 for (int i = 0; i < 2; i++) {
90 cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
91 // 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
92 pair<LineMap::iterator, LineMap::iterator> erasor = endpoints[i]->lines.equal_range(Numbers[i]);
93 for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
94 if ((*Runner).second == this) {
95 endpoints[i]->lines.erase(Runner);
96 break;
97 }
98 if (endpoints[i]->lines.empty()) {
99 cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
100 if (endpoints[i] != NULL) {
101 delete(endpoints[i]);
102 endpoints[i] = NULL;
103 } else
104 cerr << "ERROR: Endpoint " << i << " has already been free'd." << endl;
105 } else
106 cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl;
107 }
108 if (!triangles.empty())
109 cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some triangles." << endl;
110}
111;
112
113void
114BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
115{
116 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "."
117 << endl;
118 triangles.insert(TrianglePair(triangle->Nr, triangle));
119}
120;
121
122/** Checks whether we have a common endpoint with given \a *line.
123 * \param *line other line to test
124 * \return true - common endpoint present, false - not connected
125 */
126bool BoundaryLineSet::IsConnectedTo(class BoundaryLineSet *line)
127{
128 if ((endpoints[0] == line->endpoints[0]) || (endpoints[1] == line->endpoints[0]) || (endpoints[0] == line->endpoints[1]) || (endpoints[1] == line->endpoints[1]))
129 return true;
130 else
131 return false;
132};
133
134/** Checks whether the adjacent triangles of a baseline are convex or not.
135 * We sum the two angles of each normal vector with a ficticious normnal vector from this baselinbe pointing outwards.
136 * If greater/equal M_PI than we are convex.
137 * \param *out output stream for debugging
138 * \return true - triangles are convex, false - concave or less than two triangles connected
139 */
140bool BoundaryLineSet::CheckConvexityCriterion(ofstream *out)
141{
142 Vector BaseLineCenter, BaseLineNormal, BaseLine, helper[2], NormalCheck;
143 // get the two triangles
144 if (triangles.size() != 2) {
145 *out << Verbose(1) << "ERROR: Baseline " << *this << " is connect to less than two triangles, Tesselation incomplete!" << endl;
146 return false;
147 }
148 // check normal vectors
149 // have a normal vector on the base line pointing outwards
150 *out << Verbose(3) << "INFO: " << *this << " has vectors at " << *(endpoints[0]->node->node) << " and at " << *(endpoints[1]->node->node) << "." << endl;
151 BaseLineCenter.CopyVector(endpoints[0]->node->node);
152 BaseLineCenter.AddVector(endpoints[1]->node->node);
153 BaseLineCenter.Scale(1./2.);
154 BaseLine.CopyVector(endpoints[0]->node->node);
155 BaseLine.SubtractVector(endpoints[1]->node->node);
156 *out << Verbose(3) << "INFO: Baseline is " << BaseLine << " and its center is at " << BaseLineCenter << "." << endl;
157
158 BaseLineNormal.Zero();
159 NormalCheck.Zero();
160 double sign = -1.;
161 int i=0;
162 class BoundaryPointSet *node = NULL;
163 for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++) {
164 *out << Verbose(3) << "INFO: NormalVector of " << *(runner->second) << " is " << runner->second->NormalVector << "." << endl;
165 NormalCheck.AddVector(&runner->second->NormalVector);
166 NormalCheck.Scale(sign);
167 sign = -sign;
168 BaseLineNormal.SubtractVector(&runner->second->NormalVector); // we subtract as BaseLineNormal has to point inward in direction of [pi,2pi]
169 node = runner->second->GetThirdEndpoint(this);
170 if (node != NULL) {
171 *out << Verbose(3) << "INFO: Third node for triangle " << *(runner->second) << " is " << *node << " at " << *(node->node->node) << "." << endl;
172 helper[i].CopyVector(node->node->node);
173 helper[i].SubtractVector(&BaseLineCenter);
174 helper[i].MakeNormalVector(&BaseLine); // we want to compare the triangle's heights' angles!
175 *out << Verbose(4) << "INFO: Height vector with respect to baseline is " << helper[i] << "." << endl;
176 i++;
177 } else {
178 *out << Verbose(2) << "WARNING: I cannot find third node in triangle, something's wrong." << endl;
179 return true;
180 }
181 }
182 *out << Verbose(3) << "INFO: BaselineNormal is " << BaseLineNormal << "." << endl;
183 if (NormalCheck.NormSquared() < MYEPSILON) {
184 *out << Verbose(3) << "Normalvectors of both triangles are the same: convex." << endl;
185 return true;
186 }
187 double angle = getAngle(helper[0], helper[1], BaseLineNormal);
188 if ((angle - M_PI) > -MYEPSILON)
189 return true;
190 else
191 return false;
192}
193
194/** Checks whether point is any of the two endpoints this line contains.
195 * \param *point point to test
196 * \return true - point is of the line, false - is not
197 */
198bool BoundaryLineSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
199{
200 for(int i=0;i<2;i++)
201 if (point == endpoints[i])
202 return true;
203 return false;
204};
205
206/** Returns other endpoint of the line.
207 * \param *point other endpoint
208 * \return NULL - if endpoint not contained in BoundaryLineSet, or pointer to BoundaryPointSet otherwise
209 */
210inline class BoundaryPointSet *BoundaryLineSet::GetOtherEndpoint(class BoundaryPointSet *point)
211{
212 if (endpoints[0] == point)
213 return endpoints[1];
214 else if (endpoints[1] == point)
215 return endpoints[0];
216 else
217 return NULL;
218};
219
220
221ostream &
222operator <<(ostream &ost, BoundaryLineSet &a)
223{
224 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "]";
225 return ost;
226}
227;
228
229// ======================================== Triangles on Boundary =================================
230
231
232BoundaryTriangleSet::BoundaryTriangleSet()
233{
234 for (int i = 0; i < 3; i++)
235 {
236 endpoints[i] = NULL;
237 lines[i] = NULL;
238 }
239 Nr = -1;
240}
241;
242
243BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number)
244{
245 // set number
246 Nr = number;
247 // set lines
248 cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
249 for (int i = 0; i < 3; i++)
250 {
251 lines[i] = line[i];
252 lines[i]->AddTriangle(this);
253 }
254 // get ascending order of endpoints
255 map<int, class BoundaryPointSet *> OrderMap;
256 for (int i = 0; i < 3; i++)
257 // for all three lines
258 for (int j = 0; j < 2; j++)
259 { // for both endpoints
260 OrderMap.insert(pair<int, class BoundaryPointSet *> (
261 line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));
262 // and we don't care whether insertion fails
263 }
264 // set endpoints
265 int Counter = 0;
266 cout << Verbose(6) << " with end points ";
267 for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner
268 != OrderMap.end(); runner++)
269 {
270 endpoints[Counter] = runner->second;
271 cout << " " << *endpoints[Counter];
272 Counter++;
273 }
274 if (Counter < 3)
275 {
276 cerr << "ERROR! We have a triangle with only two distinct endpoints!"
277 << endl;
278 //exit(1);
279 }
280 cout << "." << endl;
281}
282;
283
284BoundaryTriangleSet::~BoundaryTriangleSet()
285{
286 for (int i = 0; i < 3; i++) {
287 cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl;
288 lines[i]->triangles.erase(Nr);
289 if (lines[i]->triangles.empty()) {
290 if (lines[i] != NULL) {
291 cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
292 delete (lines[i]);
293 lines[i] = NULL;
294 } else
295 cerr << "ERROR: This line " << i << " has already been free'd." << endl;
296 } else
297 cout << Verbose(5) << *lines[i] << " is still attached to another triangle." << endl;
298 }
299}
300;
301
302/** Calculates the normal vector for this triangle.
303 * Is made unique by comparison with \a OtherVector to point in the other direction.
304 * \param &OtherVector direction vector to make normal vector unique.
305 */
306void BoundaryTriangleSet::GetNormalVector(Vector &OtherVector)
307{
308 // get normal vector
309 NormalVector.MakeNormalVector(endpoints[0]->node->node, endpoints[1]->node->node, endpoints[2]->node->node);
310
311 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
312 if (NormalVector.Projection(&OtherVector) > 0)
313 NormalVector.Scale(-1.);
314};
315
316/** Finds the point on the triangle \a *BTS the line defined by \a *MolCenter and \a *x crosses through.
317 * We call Vector::GetIntersectionWithPlane() to receive the intersection point with the plane
318 * This we test if it's really on the plane and whether it's inside the triangle on the plane or not.
319 * The latter is done as follows: if it's really outside, then for any endpoint of the triangle and it's opposite
320 * base line, the intersection between the line from endpoint to intersection and the base line will have a Vector::NormSquared()
321 * smaller than the first line.
322 * \param *out output stream for debugging
323 * \param *MolCenter offset vector of line
324 * \param *x second endpoint of line, minus \a *MolCenter is directional vector of line
325 * \param *Intersection intersection on plane on return
326 * \return true - \a *Intersection contains intersection on plane defined by triangle, false - zero vector if outside of triangle.
327 */
328bool BoundaryTriangleSet::GetIntersectionInsideTriangle(ofstream *out, Vector *MolCenter, Vector *x, Vector *Intersection)
329{
330 Vector CrossPoint;
331 Vector helper;
332
333 if (!Intersection->GetIntersectionWithPlane(out, &NormalVector, endpoints[0]->node->node, MolCenter, x)) {
334 *out << Verbose(1) << "Alas! Intersection with plane failed - at least numerically - the intersection is not on the plane!" << endl;
335 return false;
336 }
337
338 // Calculate cross point between one baseline and the line from the third endpoint to intersection
339 int i=0;
340 do {
341 if (CrossPoint.GetIntersectionOfTwoLinesOnPlane(out, endpoints[i%3]->node->node, endpoints[(i+1)%3]->node->node, endpoints[(i+2)%3]->node->node, Intersection, &NormalVector)) {
342 helper.CopyVector(endpoints[(i+1)%3]->node->node);
343 helper.SubtractVector(endpoints[i%3]->node->node);
344 } else
345 i++;
346 if (i>2)
347 break;
348 } while (CrossPoint.NormSquared() < MYEPSILON);
349 if (i==3) {
350 *out << Verbose(1) << "ERROR: Could not find any cross points, something's utterly wrong here!" << endl;
351 exit(255);
352 }
353 CrossPoint.SubtractVector(endpoints[i%3]->node->node);
354
355 // check whether intersection is inside or not by comparing length of intersection and length of cross point
356 if ((CrossPoint.NormSquared() - helper.NormSquared()) > -MYEPSILON) { // inside
357 return true;
358 } else { // outside!
359 Intersection->Zero();
360 return false;
361 }
362};
363
364/** Checks whether lines is any of the three boundary lines this triangle contains.
365 * \param *line line to test
366 * \return true - line is of the triangle, false - is not
367 */
368bool BoundaryTriangleSet::ContainsBoundaryLine(class BoundaryLineSet *line)
369{
370 for(int i=0;i<3;i++)
371 if (line == lines[i])
372 return true;
373 return false;
374};
375
376/** Checks whether point is any of the three endpoints this triangle contains.
377 * \param *point point to test
378 * \return true - point is of the triangle, false - is not
379 */
380bool BoundaryTriangleSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
381{
382 for(int i=0;i<3;i++)
383 if (point == endpoints[i])
384 return true;
385 return false;
386};
387
388/** Checks whether three given \a *Points coincide with triangle's endpoints.
389 * \param *Points[3] pointer to BoundaryPointSet
390 * \return true - is the very triangle, false - is not
391 */
392bool BoundaryTriangleSet::IsPresentTupel(class BoundaryPointSet *Points[3])
393{
394 return (((endpoints[0] == Points[0])
395 || (endpoints[0] == Points[1])
396 || (endpoints[0] == Points[2])
397 ) && (
398 (endpoints[1] == Points[0])
399 || (endpoints[1] == Points[1])
400 || (endpoints[1] == Points[2])
401 ) && (
402 (endpoints[2] == Points[0])
403 || (endpoints[2] == Points[1])
404 || (endpoints[2] == Points[2])
405
406 ));
407};
408
409/** Returns the endpoint which is not contained in the given \a *line.
410 * \param *line baseline defining two endpoints
411 * \return pointer third endpoint or NULL if line does not belong to triangle.
412 */
413class BoundaryPointSet *BoundaryTriangleSet::GetThirdEndpoint(class BoundaryLineSet *line)
414{
415 // sanity check
416 if (!ContainsBoundaryLine(line))
417 return NULL;
418 for(int i=0;i<3;i++)
419 if (!line->ContainsBoundaryPoint(endpoints[i]))
420 return endpoints[i];
421 // actually, that' impossible :)
422 return NULL;
423};
424
425/** Calculates the center point of the triangle.
426 * Is third of the sum of all endpoints.
427 * \param *center central point on return.
428 */
429void BoundaryTriangleSet::GetCenter(Vector *center)
430{
431 center->Zero();
432 for(int i=0;i<3;i++)
433 center->AddVector(endpoints[i]->node->node);
434 center->Scale(1./3.);
435}
436
437ostream &
438operator <<(ostream &ost, BoundaryTriangleSet &a)
439{
440 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
441 << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
442 return ost;
443}
444;
445
446// =========================================================== class TESSELPOINT ===========================================
447
448/** Constructor of class TesselPoint.
449 */
450TesselPoint::TesselPoint()
451{
452 node = NULL;
453 nr = -1;
454 Name = NULL;
455};
456
457/** Destructor for class TesselPoint.
458 */
459TesselPoint::~TesselPoint()
460{
461 Free((void **)&Name, "TesselPoint::~TesselPoint: *Name");
462};
463
464/** Prints LCNode to screen.
465 */
466ostream & operator << (ostream &ost, const TesselPoint &a)
467{
468 ost << "[" << (a.Name) << "|" << &a << "]";
469 return ost;
470};
471
472/** Prints LCNode to screen.
473 */
474ostream & TesselPoint::operator << (ostream &ost)
475{
476 ost << "[" << (Name) << "|" << this << "]";
477 return ost;
478};
479
480
481// =========================================================== class POINTCLOUD ============================================
482
483/** Constructor of class PointCloud.
484 */
485PointCloud::PointCloud()
486{
487
488};
489
490/** Destructor for class PointCloud.
491 */
492PointCloud::~PointCloud()
493{
494
495};
496
497// ============================ CandidateForTesselation =============================
498
499/** Constructor of class CandidateForTesselation.
500 */
501CandidateForTesselation::CandidateForTesselation(TesselPoint *candidate, BoundaryLineSet* line, Vector OptCandidateCenter, Vector OtherOptCandidateCenter) {
502 point = candidate;
503 BaseLine = line;
504 OptCenter.CopyVector(&OptCandidateCenter);
505 OtherOptCenter.CopyVector(&OtherOptCandidateCenter);
506};
507
508/** Destructor for class CandidateForTesselation.
509 */
510CandidateForTesselation::~CandidateForTesselation() {
511 point = NULL;
512 BaseLine = NULL;
513};
514
515// =========================================================== class TESSELATION ===========================================
516
517/** Constructor of class Tesselation.
518 */
519Tesselation::Tesselation()
520{
521 PointsOnBoundaryCount = 0;
522 LinesOnBoundaryCount = 0;
523 TrianglesOnBoundaryCount = 0;
524 InternalPointer = PointsOnBoundary.begin();
525}
526;
527
528/** Destructor of class Tesselation.
529 * We have to free all points, lines and triangles.
530 */
531Tesselation::~Tesselation()
532{
533 cout << Verbose(1) << "Free'ing TesselStruct ... " << endl;
534 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
535 if (runner->second != NULL) {
536 delete (runner->second);
537 runner->second = NULL;
538 } else
539 cerr << "ERROR: The triangle " << runner->first << " has already been free'd." << endl;
540 }
541}
542;
543
544/** PointCloud implementation of GetCenter
545 * Uses PointsOnBoundary and STL stuff.
546 */
547Vector * Tesselation::GetCenter(ofstream *out)
548{
549 Vector *Center = new Vector(0.,0.,0.);
550 int num=0;
551 for (GoToFirst(); (!IsEnd()); GoToNext()) {
552 Center->AddVector(GetPoint()->node);
553 num++;
554 }
555 Center->Scale(1./num);
556 return Center;
557};
558
559/** PointCloud implementation of GoPoint
560 * Uses PointsOnBoundary and STL stuff.
561 */
562TesselPoint * Tesselation::GetPoint()
563{
564 return (InternalPointer->second->node);
565};
566
567/** PointCloud implementation of GetTerminalPoint.
568 * Uses PointsOnBoundary and STL stuff.
569 */
570TesselPoint * Tesselation::GetTerminalPoint()
571{
572 PointMap::iterator Runner = PointsOnBoundary.end();
573 Runner--;
574 return (Runner->second->node);
575};
576
577/** PointCloud implementation of GoToNext.
578 * Uses PointsOnBoundary and STL stuff.
579 */
580void Tesselation::GoToNext()
581{
582 if (InternalPointer != PointsOnBoundary.end())
583 InternalPointer++;
584};
585
586/** PointCloud implementation of GoToPrevious.
587 * Uses PointsOnBoundary and STL stuff.
588 */
589void Tesselation::GoToPrevious()
590{
591 if (InternalPointer != PointsOnBoundary.begin())
592 InternalPointer--;
593};
594
595/** PointCloud implementation of GoToFirst.
596 * Uses PointsOnBoundary and STL stuff.
597 */
598void Tesselation::GoToFirst()
599{
600 InternalPointer = PointsOnBoundary.begin();
601};
602
603/** PointCloud implementation of GoToLast.
604 * Uses PointsOnBoundary and STL stuff.
605 */
606void Tesselation::GoToLast()
607{
608 InternalPointer = PointsOnBoundary.end();
609 InternalPointer--;
610};
611
612/** PointCloud implementation of IsEmpty.
613 * Uses PointsOnBoundary and STL stuff.
614 */
615bool Tesselation::IsEmpty()
616{
617 return (PointsOnBoundary.empty());
618};
619
620/** PointCloud implementation of IsLast.
621 * Uses PointsOnBoundary and STL stuff.
622 */
623bool Tesselation::IsEnd()
624{
625 return (InternalPointer == PointsOnBoundary.end());
626};
627
628
629/** Gueses first starting triangle of the convex envelope.
630 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
631 * \param *out output stream for debugging
632 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
633 */
634void
635Tesselation::GuessStartingTriangle(ofstream *out)
636{
637 // 4b. create a starting triangle
638 // 4b1. create all distances
639 DistanceMultiMap DistanceMMap;
640 double distance, tmp;
641 Vector PlaneVector, TrialVector;
642 PointMap::iterator A, B, C; // three nodes of the first triangle
643 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
644
645 // with A chosen, take each pair B,C and sort
646 if (A != PointsOnBoundary.end())
647 {
648 B = A;
649 B++;
650 for (; B != PointsOnBoundary.end(); B++)
651 {
652 C = B;
653 C++;
654 for (; C != PointsOnBoundary.end(); C++)
655 {
656 tmp = A->second->node->node->DistanceSquared(B->second->node->node);
657 distance = tmp * tmp;
658 tmp = A->second->node->node->DistanceSquared(C->second->node->node);
659 distance += tmp * tmp;
660 tmp = B->second->node->node->DistanceSquared(C->second->node->node);
661 distance += tmp * tmp;
662 DistanceMMap.insert(DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator> (B, C)));
663 }
664 }
665 }
666 // // listing distances
667 // *out << Verbose(1) << "Listing DistanceMMap:";
668 // for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
669 // *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
670 // }
671 // *out << endl;
672 // 4b2. pick three baselines forming a triangle
673 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
674 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
675 for (; baseline != DistanceMMap.end(); baseline++)
676 {
677 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
678 // 2. next, we have to check whether all points reside on only one side of the triangle
679 // 3. construct plane vector
680 PlaneVector.MakeNormalVector(A->second->node->node,
681 baseline->second.first->second->node->node,
682 baseline->second.second->second->node->node);
683 *out << Verbose(2) << "Plane vector of candidate triangle is ";
684 PlaneVector.Output(out);
685 *out << endl;
686 // 4. loop over all points
687 double sign = 0.;
688 PointMap::iterator checker = PointsOnBoundary.begin();
689 for (; checker != PointsOnBoundary.end(); checker++)
690 {
691 // (neglecting A,B,C)
692 if ((checker == A) || (checker == baseline->second.first) || (checker
693 == baseline->second.second))
694 continue;
695 // 4a. project onto plane vector
696 TrialVector.CopyVector(checker->second->node->node);
697 TrialVector.SubtractVector(A->second->node->node);
698 distance = TrialVector.Projection(&PlaneVector);
699 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
700 continue;
701 *out << Verbose(3) << "Projection of " << checker->second->node->Name
702 << " yields distance of " << distance << "." << endl;
703 tmp = distance / fabs(distance);
704 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
705 if ((sign != 0) && (tmp != sign))
706 {
707 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
708 *out << Verbose(2) << "Current candidates: "
709 << A->second->node->Name << ","
710 << baseline->second.first->second->node->Name << ","
711 << baseline->second.second->second->node->Name << " leaves "
712 << checker->second->node->Name << " outside the convex hull."
713 << endl;
714 break;
715 }
716 else
717 { // note the sign for later
718 *out << Verbose(2) << "Current candidates: "
719 << A->second->node->Name << ","
720 << baseline->second.first->second->node->Name << ","
721 << baseline->second.second->second->node->Name << " leave "
722 << checker->second->node->Name << " inside the convex hull."
723 << endl;
724 sign = tmp;
725 }
726 // 4d. Check whether the point is inside the triangle (check distance to each node
727 tmp = checker->second->node->node->DistanceSquared(A->second->node->node);
728 int innerpoint = 0;
729 if ((tmp < A->second->node->node->DistanceSquared(
730 baseline->second.first->second->node->node)) && (tmp
731 < A->second->node->node->DistanceSquared(
732 baseline->second.second->second->node->node)))
733 innerpoint++;
734 tmp = checker->second->node->node->DistanceSquared(
735 baseline->second.first->second->node->node);
736 if ((tmp < baseline->second.first->second->node->node->DistanceSquared(
737 A->second->node->node)) && (tmp
738 < baseline->second.first->second->node->node->DistanceSquared(
739 baseline->second.second->second->node->node)))
740 innerpoint++;
741 tmp = checker->second->node->node->DistanceSquared(
742 baseline->second.second->second->node->node);
743 if ((tmp < baseline->second.second->second->node->node->DistanceSquared(
744 baseline->second.first->second->node->node)) && (tmp
745 < baseline->second.second->second->node->node->DistanceSquared(
746 A->second->node->node)))
747 innerpoint++;
748 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
749 if (innerpoint == 3)
750 break;
751 }
752 // 5. come this far, all on same side? Then break 1. loop and construct triangle
753 if (checker == PointsOnBoundary.end())
754 {
755 *out << "Looks like we have a candidate!" << endl;
756 break;
757 }
758 }
759 if (baseline != DistanceMMap.end())
760 {
761 BPS[0] = baseline->second.first->second;
762 BPS[1] = baseline->second.second->second;
763 BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
764 BPS[0] = A->second;
765 BPS[1] = baseline->second.second->second;
766 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
767 BPS[0] = baseline->second.first->second;
768 BPS[1] = A->second;
769 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
770
771 // 4b3. insert created triangle
772 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
773 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
774 TrianglesOnBoundaryCount++;
775 for (int i = 0; i < NDIM; i++)
776 {
777 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));
778 LinesOnBoundaryCount++;
779 }
780
781 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
782 }
783 else
784 {
785 *out << Verbose(1) << "No starting triangle found." << endl;
786 exit(255);
787 }
788}
789;
790
791/** Tesselates the convex envelope of a cluster from a single starting triangle.
792 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
793 * 2 triangles. Hence, we go through all current lines:
794 * -# if the lines contains to only one triangle
795 * -# We search all points in the boundary
796 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
797 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
798 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors)
799 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
800 * \param *out output stream for debugging
801 * \param *configuration for IsAngstroem
802 * \param *cloud cluster of points
803 */
804void Tesselation::TesselateOnBoundary(ofstream *out, PointCloud *cloud)
805{
806 bool flag;
807 PointMap::iterator winner;
808 class BoundaryPointSet *peak = NULL;
809 double SmallestAngle, TempAngle;
810 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, helper, PropagationVector, *Center = NULL;
811 LineMap::iterator LineChecker[2];
812
813 Center = cloud->GetCenter(out);
814 // create a first tesselation with the given BoundaryPoints
815 do {
816 flag = false;
817 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
818 if (baseline->second->triangles.size() == 1) {
819 // 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)
820 SmallestAngle = M_PI;
821
822 // get peak point with respect to this base line's only triangle
823 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
824 *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl;
825 for (int i = 0; i < 3; i++)
826 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
827 peak = BTS->endpoints[i];
828 *out << Verbose(3) << " and has peak " << *peak << "." << endl;
829
830 // prepare some auxiliary vectors
831 Vector BaseLineCenter, BaseLine;
832 BaseLineCenter.CopyVector(baseline->second->endpoints[0]->node->node);
833 BaseLineCenter.AddVector(baseline->second->endpoints[1]->node->node);
834 BaseLineCenter.Scale(1. / 2.); // points now to center of base line
835 BaseLine.CopyVector(baseline->second->endpoints[0]->node->node);
836 BaseLine.SubtractVector(baseline->second->endpoints[1]->node->node);
837
838 // offset to center of triangle
839 CenterVector.Zero();
840 for (int i = 0; i < 3; i++)
841 CenterVector.AddVector(BTS->endpoints[i]->node->node);
842 CenterVector.Scale(1. / 3.);
843 *out << Verbose(4) << "CenterVector of base triangle is " << CenterVector << endl;
844
845 // normal vector of triangle
846 NormalVector.CopyVector(Center);
847 NormalVector.SubtractVector(&CenterVector);
848 BTS->GetNormalVector(NormalVector);
849 NormalVector.CopyVector(&BTS->NormalVector);
850 *out << Verbose(4) << "NormalVector of base triangle is " << NormalVector << endl;
851
852 // vector in propagation direction (out of triangle)
853 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
854 PropagationVector.MakeNormalVector(&BaseLine, &NormalVector);
855 TempVector.CopyVector(&CenterVector);
856 TempVector.SubtractVector(baseline->second->endpoints[0]->node->node); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
857 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
858 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
859 PropagationVector.Scale(-1.);
860 *out << Verbose(4) << "PropagationVector of base triangle is " << PropagationVector << endl;
861 winner = PointsOnBoundary.end();
862
863 // loop over all points and calculate angle between normal vector of new and present triangle
864 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) {
865 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
866 *out << Verbose(3) << "Target point is " << *(target->second) << ":" << endl;
867
868 // first check direction, so that triangles don't intersect
869 VirtualNormalVector.CopyVector(target->second->node->node);
870 VirtualNormalVector.SubtractVector(&BaseLineCenter); // points from center of base line to target
871 VirtualNormalVector.ProjectOntoPlane(&NormalVector);
872 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
873 *out << Verbose(4) << "VirtualNormalVector is " << VirtualNormalVector << " and PropagationVector is " << PropagationVector << "." << endl;
874 if (TempAngle > (M_PI/2.)) { // no bends bigger than Pi/2 (90 degrees)
875 *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
876 continue;
877 } else
878 *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
879
880 // check first and second endpoint (if any connecting line goes to target has at least not more than 1 triangle)
881 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
882 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
883 if (((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[0]->second->triangles.size() == 2))) {
884 *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->triangles.size() << " triangles." << endl;
885 continue;
886 }
887 if (((LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (LineChecker[1]->second->triangles.size() == 2))) {
888 *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->triangles.size() << " triangles." << endl;
889 continue;
890 }
891
892 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
893 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)))) {
894 *out << Verbose(4) << "Current target is peak!" << endl;
895 continue;
896 }
897
898 // check for linear dependence
899 TempVector.CopyVector(baseline->second->endpoints[0]->node->node);
900 TempVector.SubtractVector(target->second->node->node);
901 helper.CopyVector(baseline->second->endpoints[1]->node->node);
902 helper.SubtractVector(target->second->node->node);
903 helper.ProjectOntoPlane(&TempVector);
904 if (fabs(helper.NormSquared()) < MYEPSILON) {
905 *out << Verbose(4) << "Chosen set of vectors is linear dependent." << endl;
906 continue;
907 }
908
909 // in case NOT both were found, create virtually this triangle, get its normal vector, calculate angle
910 flag = true;
911 VirtualNormalVector.MakeNormalVector(baseline->second->endpoints[0]->node->node, baseline->second->endpoints[1]->node->node, target->second->node->node);
912 TempVector.CopyVector(baseline->second->endpoints[0]->node->node);
913 TempVector.AddVector(baseline->second->endpoints[1]->node->node);
914 TempVector.AddVector(target->second->node->node);
915 TempVector.Scale(1./3.);
916 TempVector.SubtractVector(Center);
917 // make it always point outward
918 if (VirtualNormalVector.Projection(&TempVector) < 0)
919 VirtualNormalVector.Scale(-1.);
920 // calculate angle
921 TempAngle = NormalVector.Angle(&VirtualNormalVector);
922 *out << Verbose(4) << "NormalVector is " << VirtualNormalVector << " and the angle is " << TempAngle << "." << endl;
923 if ((SmallestAngle - TempAngle) > MYEPSILON) { // set to new possible winner
924 SmallestAngle = TempAngle;
925 winner = target;
926 *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
927 } else if (fabs(SmallestAngle - TempAngle) < MYEPSILON) { // check the angle to propagation, both possible targets are in one plane! (their normals have same angle)
928 // hence, check the angles to some normal direction from our base line but in this common plane of both targets...
929 helper.CopyVector(target->second->node->node);
930 helper.SubtractVector(&BaseLineCenter);
931 helper.ProjectOntoPlane(&BaseLine);
932 // ...the one with the smaller angle is the better candidate
933 TempVector.CopyVector(target->second->node->node);
934 TempVector.SubtractVector(&BaseLineCenter);
935 TempVector.ProjectOntoPlane(&VirtualNormalVector);
936 TempAngle = TempVector.Angle(&helper);
937 TempVector.CopyVector(winner->second->node->node);
938 TempVector.SubtractVector(&BaseLineCenter);
939 TempVector.ProjectOntoPlane(&VirtualNormalVector);
940 if (TempAngle < TempVector.Angle(&helper)) {
941 TempAngle = NormalVector.Angle(&VirtualNormalVector);
942 SmallestAngle = TempAngle;
943 winner = target;
944 *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle " << TempAngle << " to propagation direction." << endl;
945 } else
946 *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle to propagation direction." << endl;
947 } else
948 *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
949 }
950 } // end of loop over all boundary points
951
952 // 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
953 if (winner != PointsOnBoundary.end()) {
954 *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
955 // create the lins of not yet present
956 BLS[0] = baseline->second;
957 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
958 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
959 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
960 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
961 BPS[0] = baseline->second->endpoints[0];
962 BPS[1] = winner->second;
963 BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
964 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[1]));
965 LinesOnBoundaryCount++;
966 } else
967 BLS[1] = LineChecker[0]->second;
968 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
969 BPS[0] = baseline->second->endpoints[1];
970 BPS[1] = winner->second;
971 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
972 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[2]));
973 LinesOnBoundaryCount++;
974 } else
975 BLS[2] = LineChecker[1]->second;
976 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
977 BTS->GetCenter(&helper);
978 helper.SubtractVector(Center);
979 helper.Scale(-1);
980 BTS->GetNormalVector(helper);
981 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
982 TrianglesOnBoundaryCount++;
983 } else {
984 *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
985 }
986
987 // 5d. If the set of lines is not yet empty, go to 5. and continue
988 } else
989 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->triangles.size() << "." << endl;
990 } while (flag);
991
992 // exit
993 delete(Center);
994};
995
996/** Inserts all points outside of the tesselated surface into it by adding new triangles.
997 * \param *out output stream for debugging
998 * \param *cloud cluster of points
999 * \param *LC LinkedCell structure to find nearest point quickly
1000 * \return true - all straddling points insert, false - something went wrong
1001 */
1002bool Tesselation::InsertStraddlingPoints(ofstream *out, PointCloud *cloud, LinkedCell *LC)
1003{
1004 Vector Intersection, Normal;
1005 TesselPoint *Walker = NULL;
1006 Vector *Center = cloud->GetCenter(out);
1007 list<BoundaryTriangleSet*> *triangles = NULL;
1008
1009 *out << Verbose(1) << "Begin of InsertStraddlingPoints" << endl;
1010
1011 cloud->GoToFirst();
1012 while (!cloud->IsEnd()) { // we only have to go once through all points, as boundary can become only bigger
1013 LinkedCell BoundaryPoints(this, 5.);
1014 Walker = cloud->GetPoint();
1015 *out << Verbose(2) << "Current point is " << *Walker << "." << endl;
1016 // get the next triangle
1017 triangles = FindClosestTrianglesToPoint(out, Walker->node, &BoundaryPoints);
1018 if (triangles == NULL) {
1019 *out << Verbose(1) << "No triangles found, probably a tesselation point itself." << endl;
1020 cloud->GoToNext();
1021 continue;
1022 } else {
1023 BTS = triangles->front();
1024 }
1025 *out << Verbose(2) << "Closest triangle is " << *BTS << "." << endl;
1026 // get the intersection point
1027 if (BTS->GetIntersectionInsideTriangle(out, Center, Walker->node, &Intersection)) {
1028 *out << Verbose(2) << "We have an intersection at " << Intersection << "." << endl;
1029 // we have the intersection, check whether in- or outside of boundary
1030 if ((Center->DistanceSquared(Walker->node) - Center->DistanceSquared(&Intersection)) < -MYEPSILON) {
1031 // inside, next!
1032 *out << Verbose(2) << *Walker << " is inside wrt triangle " << *BTS << "." << endl;
1033 } else {
1034 // outside!
1035 *out << Verbose(2) << *Walker << " is outside wrt triangle " << *BTS << "." << endl;
1036 class BoundaryLineSet *OldLines[3], *NewLines[3];
1037 class BoundaryPointSet *OldPoints[3], *NewPoint;
1038 // store the three old lines and old points
1039 for (int i=0;i<3;i++) {
1040 OldLines[i] = BTS->lines[i];
1041 OldPoints[i] = BTS->endpoints[i];
1042 }
1043 Normal.CopyVector(&BTS->NormalVector);
1044 // add Walker to boundary points
1045 *out << Verbose(2) << "Adding " << *Walker << " to BoundaryPoints." << endl;
1046 AddPoint(Walker);
1047 if (BPS[0] != NULL)
1048 NewPoint = BPS[0];
1049 else
1050 continue;
1051 // remove triangle
1052 *out << Verbose(2) << "Erasing triangle " << *BTS << "." << endl;
1053 TrianglesOnBoundary.erase(BTS->Nr);
1054 delete(BTS);
1055 // create three new boundary lines
1056 for (int i=0;i<3;i++) {
1057 BPS[0] = NewPoint;
1058 BPS[1] = OldPoints[i];
1059 NewLines[i] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1060 *out << Verbose(3) << "Creating new line " << *NewLines[i] << "." << endl;
1061 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, NewLines[i])); // no need for check for unique insertion as BPS[0] is definitely a new one
1062 LinesOnBoundaryCount++;
1063 }
1064 // create three new triangle with new point
1065 for (int i=0;i<3;i++) { // find all baselines
1066 BLS[0] = OldLines[i];
1067 int n = 1;
1068 for (int j=0;j<3;j++) {
1069 if (NewLines[j]->IsConnectedTo(BLS[0])) {
1070 if (n>2) {
1071 *out << Verbose(1) << "ERROR: " << BLS[0] << " connects to all of the new lines?!" << endl;
1072 return false;
1073 } else
1074 BLS[n++] = NewLines[j];
1075 }
1076 }
1077 // create the triangle
1078 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1079 Normal.Scale(-1.);
1080 BTS->GetNormalVector(Normal);
1081 Normal.Scale(-1.);
1082 *out << Verbose(2) << "Created new triangle " << *BTS << "." << endl;
1083 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1084 TrianglesOnBoundaryCount++;
1085 }
1086 }
1087 } else { // something is wrong with FindClosestTriangleToPoint!
1088 *out << Verbose(1) << "ERROR: The closest triangle did not produce an intersection!" << endl;
1089 return false;
1090 }
1091 cloud->GoToNext();
1092 }
1093
1094 // exit
1095 delete(Center);
1096 *out << Verbose(1) << "End of InsertStraddlingPoints" << endl;
1097 return true;
1098};
1099
1100/** Adds an point to the tesselation::PointsOnBoundary list.
1101 * \param *Walker point to add
1102 */
1103void
1104Tesselation::AddPoint(TesselPoint *Walker)
1105{
1106 PointTestPair InsertUnique;
1107 BPS[0] = new class BoundaryPointSet(Walker);
1108 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[0]));
1109 if (InsertUnique.second) // if new point was not present before, increase counter
1110 PointsOnBoundaryCount++;
1111 else {
1112 delete(BPS[0]);
1113 BPS[0] = NULL;
1114 }
1115}
1116;
1117
1118/** Adds point to Tesselation::PointsOnBoundary if not yet present.
1119 * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
1120 * @param Candidate point to add
1121 * @param n index for this point in Tesselation::TPS array
1122 */
1123void
1124Tesselation::AddTrianglePoint(TesselPoint* Candidate, int n)
1125{
1126 PointTestPair InsertUnique;
1127 TPS[n] = new class BoundaryPointSet(Candidate);
1128 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
1129 if (InsertUnique.second) { // if new point was not present before, increase counter
1130 PointsOnBoundaryCount++;
1131 } else {
1132 delete TPS[n];
1133 cout << Verbose(3) << "Node " << *((InsertUnique.first)->second->node) << " is already present in PointsOnBoundary." << endl;
1134 TPS[n] = (InsertUnique.first)->second;
1135 }
1136}
1137;
1138
1139/** Function tries to add line from current Points in BPS to BoundaryLineSet.
1140 * If successful it raises the line count and inserts the new line into the BLS,
1141 * if unsuccessful, it writes the line which had been present into the BLS, deleting the new constructed one.
1142 * @param *a first endpoint
1143 * @param *b second endpoint
1144 * @param n index of Tesselation::BLS giving the line with both endpoints
1145 */
1146void Tesselation::AddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n) {
1147 bool insertNewLine = true;
1148
1149 if (a->lines.find(b->node->nr) != a->lines.end()) {
1150 LineMap::iterator FindLine;
1151 pair<LineMap::iterator,LineMap::iterator> FindPair;
1152 FindPair = a->lines.equal_range(b->node->nr);
1153
1154 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
1155 // If there is a line with less than two attached triangles, we don't need a new line.
1156 if (FindLine->second->triangles.size() < 2) {
1157 insertNewLine = false;
1158 cout << Verbose(3) << "Using existing line " << *FindLine->second << endl;
1159
1160 BPS[0] = FindLine->second->endpoints[0];
1161 BPS[1] = FindLine->second->endpoints[1];
1162 BLS[n] = FindLine->second;
1163
1164 break;
1165 }
1166 }
1167 }
1168
1169 if (insertNewLine) {
1170 AlwaysAddTriangleLine(a, b, n);
1171 }
1172}
1173;
1174
1175/**
1176 * Adds lines from each of the current points in the BPS to BoundaryLineSet.
1177 * Raises the line count and inserts the new line into the BLS.
1178 *
1179 * @param *a first endpoint
1180 * @param *b second endpoint
1181 * @param n index of Tesselation::BLS giving the line with both endpoints
1182 */
1183void Tesselation::AlwaysAddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n)
1184{
1185 cout << Verbose(3) << "Adding line between " << *(a->node) << " and " << *(b->node) << "." << endl;
1186 BPS[0] = a;
1187 BPS[1] = b;
1188 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); // this also adds the line to the local maps
1189 // add line to global map
1190 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
1191 // increase counter
1192 LinesOnBoundaryCount++;
1193};
1194
1195/** Function tries to add Triangle just created to Triangle and remarks if already existent (Failure of algorithm).
1196 * Furthermore it adds the triangle to all of its lines, in order to recognize those which are saturated later.
1197 */
1198void
1199Tesselation::AddTriangle()
1200{
1201 cout << Verbose(1) << "Adding triangle to global TrianglesOnBoundary map." << endl;
1202
1203 // add triangle to global map
1204 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1205 TrianglesOnBoundaryCount++;
1206
1207 // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
1208}
1209;
1210
1211/** Checks whether the triangle consisting of the three points is already present.
1212 * Searches for the points in Tesselation::PointsOnBoundary and checks their
1213 * lines. If any of the three edges already has two triangles attached, false is
1214 * returned.
1215 * \param *out output stream for debugging
1216 * \param *Candidates endpoints of the triangle candidate
1217 * \return integer 0 if no triangle exists, 1 if one triangle exists, 2 if two
1218 * triangles exist which is the maximum for three points
1219 */
1220int Tesselation::CheckPresenceOfTriangle(ofstream *out, TesselPoint *Candidates[3]) {
1221 int adjacentTriangleCount = 0;
1222 class BoundaryPointSet *Points[3];
1223
1224 *out << Verbose(2) << "Begin of CheckPresenceOfTriangle" << endl;
1225 // builds a triangle point set (Points) of the end points
1226 for (int i = 0; i < 3; i++) {
1227 PointMap::iterator FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
1228 if (FindPoint != PointsOnBoundary.end()) {
1229 Points[i] = FindPoint->second;
1230 } else {
1231 Points[i] = NULL;
1232 }
1233 }
1234
1235 // checks lines between the points in the Points for their adjacent triangles
1236 for (int i = 0; i < 3; i++) {
1237 if (Points[i] != NULL) {
1238 for (int j = i; j < 3; j++) {
1239 if (Points[j] != NULL) {
1240 LineMap::iterator FindLine = Points[i]->lines.find(Points[j]->node->nr);
1241 for (; (FindLine != Points[i]->lines.end()) && (FindLine->first == Points[j]->node->nr); FindLine++) {
1242 TriangleMap *triangles = &FindLine->second->triangles;
1243 *out << Verbose(3) << "Current line is " << FindLine->first << ": " << *(FindLine->second) << " with triangles " << triangles << "." << endl;
1244 for (TriangleMap::iterator FindTriangle = triangles->begin(); FindTriangle != triangles->end(); FindTriangle++) {
1245 if (FindTriangle->second->IsPresentTupel(Points)) {
1246 adjacentTriangleCount++;
1247 }
1248 }
1249 *out << Verbose(3) << "end." << endl;
1250 }
1251 // Only one of the triangle lines must be considered for the triangle count.
1252 *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1253 return adjacentTriangleCount;
1254 }
1255 }
1256 }
1257 }
1258
1259 *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1260 *out << Verbose(2) << "End of CheckPresenceOfTriangle" << endl;
1261 return adjacentTriangleCount;
1262};
1263
1264
1265/** Finds the starting triangle for find_non_convex_border().
1266 * Looks at the outermost point per axis, then Find_second_point_for_Tesselation()
1267 * for the second and Find_next_suitable_point_via_Angle_of_Sphere() for the third
1268 * point are called.
1269 * \param *out output stream for debugging
1270 * \param RADIUS radius of virtual rolling sphere
1271 * \param *LC LinkedCell structure with neighbouring TesselPoint's
1272 */
1273void Tesselation::Find_starting_triangle(ofstream *out, const double RADIUS, LinkedCell *LC)
1274{
1275 cout << Verbose(1) << "Begin of Find_starting_triangle\n";
1276 int i = 0;
1277 LinkedNodes *List = NULL;
1278 TesselPoint* FirstPoint = NULL;
1279 TesselPoint* SecondPoint = NULL;
1280 TesselPoint* MaxPoint[NDIM];
1281 double max_coordinate[NDIM];
1282 Vector Oben;
1283 Vector helper;
1284 Vector Chord;
1285 Vector SearchDirection;
1286
1287 Oben.Zero();
1288
1289 for (i = 0; i < 3; i++) {
1290 MaxPoint[i] = NULL;
1291 max_coordinate[i] = -1;
1292 }
1293
1294 // 1. searching topmost point with respect to each axis
1295 for (int i=0;i<NDIM;i++) { // each axis
1296 LC->n[i] = LC->N[i]-1; // current axis is topmost cell
1297 for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++)
1298 for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) {
1299 List = LC->GetCurrentCell();
1300 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1301 if (List != NULL) {
1302 for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
1303 if ((*Runner)->node->x[i] > max_coordinate[i]) {
1304 cout << Verbose(2) << "New maximal for axis " << i << " node is " << *(*Runner) << " at " << *(*Runner)->node << "." << endl;
1305 max_coordinate[i] = (*Runner)->node->x[i];
1306 MaxPoint[i] = (*Runner);
1307 }
1308 }
1309 } else {
1310 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
1311 }
1312 }
1313 }
1314
1315 cout << Verbose(2) << "Found maximum coordinates: ";
1316 for (int i=0;i<NDIM;i++)
1317 cout << i << ": " << *MaxPoint[i] << "\t";
1318 cout << endl;
1319
1320 BTS = NULL;
1321 CandidateList *Opt_Candidates = new CandidateList();
1322 for (int k=0;k<NDIM;k++) {
1323 Oben.x[k] = 1.;
1324 FirstPoint = MaxPoint[k];
1325 cout << Verbose(1) << "Coordinates of start node at " << *FirstPoint->node << "." << endl;
1326
1327 double ShortestAngle;
1328 TesselPoint* Opt_Candidate = NULL;
1329 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.
1330
1331 Find_second_point_for_Tesselation(FirstPoint, NULL, Oben, Opt_Candidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
1332 SecondPoint = Opt_Candidate;
1333 if (SecondPoint == NULL) // have we found a second point?
1334 continue;
1335 else
1336 cout << Verbose(1) << "Found second point is at " << *SecondPoint->node << ".\n";
1337
1338 helper.CopyVector(FirstPoint->node);
1339 helper.SubtractVector(SecondPoint->node);
1340 helper.Normalize();
1341 Oben.ProjectOntoPlane(&helper);
1342 Oben.Normalize();
1343 helper.VectorProduct(&Oben);
1344 ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1345
1346 Chord.CopyVector(FirstPoint->node); // bring into calling function
1347 Chord.SubtractVector(SecondPoint->node);
1348 double radius = Chord.ScalarProduct(&Chord);
1349 double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.);
1350 helper.CopyVector(&Oben);
1351 helper.Scale(CircleRadius);
1352 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized)
1353
1354 // look in one direction of baseline for initial candidate
1355 SearchDirection.MakeNormalVector(&Chord, &Oben); // whether we look "left" first or "right" first is not important ...
1356
1357 // adding point 1 and point 2 and add the line between them
1358 AddTrianglePoint(FirstPoint, 0);
1359 AddTrianglePoint(SecondPoint, 1);
1360 AddTriangleLine(TPS[0], TPS[1], 0);
1361
1362 //cout << Verbose(2) << "INFO: OldSphereCenter is at " << helper << ".\n";
1363 Find_third_point_for_Tesselation(
1364 Oben, SearchDirection, helper, BLS[0], NULL, *&Opt_Candidates, &ShortestAngle, RADIUS, LC
1365 );
1366 cout << Verbose(1) << "List of third Points is ";
1367 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1368 cout << " " << *(*it)->point;
1369 }
1370 cout << endl;
1371
1372 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1373 // add third triangle point
1374 AddTrianglePoint((*it)->point, 2);
1375 // add the second and third line
1376 AddTriangleLine(TPS[1], TPS[2], 1);
1377 AddTriangleLine(TPS[0], TPS[2], 2);
1378 // ... and triangles to the Maps of the Tesselation class
1379 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1380 AddTriangle();
1381 // ... and calculate its normal vector (with correct orientation)
1382 (*it)->OptCenter.Scale(-1.);
1383 cout << Verbose(2) << "Anti-Oben is currently " << (*it)->OptCenter << "." << endl;
1384 BTS->GetNormalVector((*it)->OptCenter); // vector to compare with should point inwards
1385 cout << Verbose(0) << "==> Found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and "
1386 << *(*it)->point << " with normal vector " << BTS->NormalVector << ".\n";
1387
1388 // if we do not reach the end with the next step of iteration, we need to setup a new first line
1389 if (it != Opt_Candidates->end()--) {
1390 FirstPoint = (*it)->BaseLine->endpoints[0]->node;
1391 SecondPoint = (*it)->point;
1392 // adding point 1 and point 2 and the line between them
1393 AddTrianglePoint(FirstPoint, 0);
1394 AddTrianglePoint(SecondPoint, 1);
1395 AddTriangleLine(TPS[0], TPS[1], 0);
1396 }
1397 cout << Verbose(2) << "Projection is " << BTS->NormalVector.Projection(&Oben) << "." << endl;
1398 }
1399 if (BTS != NULL) // we have created one starting triangle
1400 break;
1401 else {
1402 // remove all candidates from the list and then the list itself
1403 class CandidateForTesselation *remover = NULL;
1404 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1405 remover = *it;
1406 delete(remover);
1407 }
1408 Opt_Candidates->clear();
1409 }
1410 }
1411
1412 // remove all candidates from the list and then the list itself
1413 class CandidateForTesselation *remover = NULL;
1414 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1415 remover = *it;
1416 delete(remover);
1417 }
1418 delete(Opt_Candidates);
1419 cout << Verbose(1) << "End of Find_starting_triangle\n";
1420};
1421
1422
1423/** This function finds a triangle to a line, adjacent to an existing one.
1424 * @param out output stream for debugging
1425 * @param Line current baseline to search from
1426 * @param T current triangle which \a Line is edge of
1427 * @param RADIUS radius of the rolling ball
1428 * @param N number of found triangles
1429 * @param *LC LinkedCell structure with neighbouring points
1430 */
1431bool Tesselation::Find_next_suitable_triangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, int N, LinkedCell *LC)
1432{
1433 cout << Verbose(0) << "Begin of Find_next_suitable_triangle\n";
1434 bool result = true;
1435 CandidateList *Opt_Candidates = new CandidateList();
1436
1437 Vector CircleCenter;
1438 Vector CirclePlaneNormal;
1439 Vector OldSphereCenter;
1440 Vector SearchDirection;
1441 Vector helper;
1442 TesselPoint *ThirdNode = NULL;
1443 LineMap::iterator testline;
1444 double ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1445 double radius, CircleRadius;
1446
1447 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl;
1448 for (int i=0;i<3;i++)
1449 if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node))
1450 ThirdNode = T.endpoints[i]->node;
1451
1452 // construct center of circle
1453 CircleCenter.CopyVector(Line.endpoints[0]->node->node);
1454 CircleCenter.AddVector(Line.endpoints[1]->node->node);
1455 CircleCenter.Scale(0.5);
1456
1457 // construct normal vector of circle
1458 CirclePlaneNormal.CopyVector(Line.endpoints[0]->node->node);
1459 CirclePlaneNormal.SubtractVector(Line.endpoints[1]->node->node);
1460
1461 // calculate squared radius of circle
1462 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
1463 if (radius/4. < RADIUS*RADIUS) {
1464 CircleRadius = RADIUS*RADIUS - radius/4.;
1465 CirclePlaneNormal.Normalize();
1466 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
1467
1468 // construct old center
1469 GetCenterofCircumcircle(&OldSphereCenter, T.endpoints[0]->node->node, T.endpoints[1]->node->node, T.endpoints[2]->node->node);
1470 helper.CopyVector(&T.NormalVector); // normal vector ensures that this is correct center of the two possible ones
1471 radius = Line.endpoints[0]->node->node->DistanceSquared(&OldSphereCenter);
1472 helper.Scale(sqrt(RADIUS*RADIUS - radius));
1473 OldSphereCenter.AddVector(&helper);
1474 OldSphereCenter.SubtractVector(&CircleCenter);
1475 //cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
1476
1477 // construct SearchDirection
1478 SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal);
1479 helper.CopyVector(Line.endpoints[0]->node->node);
1480 helper.SubtractVector(ThirdNode->node);
1481 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
1482 SearchDirection.Scale(-1.);
1483 SearchDirection.ProjectOntoPlane(&OldSphereCenter);
1484 SearchDirection.Normalize();
1485 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
1486 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
1487 // rotated the wrong way!
1488 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
1489 }
1490
1491 // add third point
1492 Find_third_point_for_Tesselation(
1493 T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, Opt_Candidates,
1494 &ShortestAngle, RADIUS, LC
1495 );
1496
1497 } else {
1498 cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl;
1499 }
1500
1501 if (Opt_Candidates->begin() == Opt_Candidates->end()) {
1502 cerr << "WARNING: Could not find a suitable candidate." << endl;
1503 return false;
1504 }
1505 cout << Verbose(1) << "Third Points are ";
1506 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1507 cout << " " << *(*it)->point;
1508 }
1509 cout << endl;
1510
1511 BoundaryLineSet *BaseRay = &Line;
1512 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1513 cout << Verbose(1) << " Third point candidate is " << *(*it)->point
1514 << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
1515 cout << Verbose(1) << " Baseline is " << *BaseRay << endl;
1516
1517 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
1518 TesselPoint *PointCandidates[3];
1519 PointCandidates[0] = (*it)->point;
1520 PointCandidates[1] = BaseRay->endpoints[0]->node;
1521 PointCandidates[2] = BaseRay->endpoints[1]->node;
1522 int existentTrianglesCount = CheckPresenceOfTriangle(out, PointCandidates);
1523
1524 BTS = NULL;
1525 // If there is no triangle, add it regularly.
1526 if (existentTrianglesCount == 0) {
1527 AddTrianglePoint((*it)->point, 0);
1528 AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
1529 AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
1530
1531 if (CheckLineCriteriaforDegeneratedTriangle(TPS)) {
1532 AddTriangleLine(TPS[0], TPS[1], 0);
1533 AddTriangleLine(TPS[0], TPS[2], 1);
1534 AddTriangleLine(TPS[1], TPS[2], 2);
1535
1536 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1537 AddTriangle();
1538 (*it)->OptCenter.Scale(-1.);
1539 BTS->GetNormalVector((*it)->OptCenter);
1540 (*it)->OptCenter.Scale(-1.);
1541
1542 cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector
1543 << " for this triangle ... " << endl;
1544 //cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << *BaseRay << "." << endl;
1545 } else {
1546 cout << Verbose(1) << "WARNING: This triangle consisting of ";
1547 cout << *(*it)->point << ", ";
1548 cout << *BaseRay->endpoints[0]->node << " and ";
1549 cout << *BaseRay->endpoints[1]->node << " ";
1550 cout << "exists and is not added, as it does not seem helpful!" << endl;
1551 result = false;
1552 }
1553 } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time.
1554 AddTrianglePoint((*it)->point, 0);
1555 AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
1556 AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
1557
1558 // 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)
1559 // i.e. at least one of the three lines must be present with TriangleCount <= 1
1560 if (CheckLineCriteriaforDegeneratedTriangle(TPS)) {
1561 AddTriangleLine(TPS[0], TPS[1], 0);
1562 AddTriangleLine(TPS[0], TPS[2], 1);
1563 AddTriangleLine(TPS[1], TPS[2], 2);
1564
1565 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1566 AddTriangle(); // add to global map
1567
1568 (*it)->OtherOptCenter.Scale(-1.);
1569 BTS->GetNormalVector((*it)->OtherOptCenter);
1570 (*it)->OtherOptCenter.Scale(-1.);
1571
1572 cout << "--> WARNING: Special new triangle with " << *BTS << " and normal vector " << BTS->NormalVector
1573 << " for this triangle ... " << endl;
1574 cout << Verbose(1) << "We have "<< BaseRay->triangles.size() << " for line " << BaseRay << "." << endl;
1575 } else {
1576 cout << Verbose(1) << "WARNING: This triangle consisting of ";
1577 cout << *(*it)->point << ", ";
1578 cout << *BaseRay->endpoints[0]->node << " and ";
1579 cout << *BaseRay->endpoints[1]->node << " ";
1580 cout << "exists and is not added, as it does not seem helpful!" << endl;
1581 result = false;
1582 }
1583 } else {
1584 cout << Verbose(1) << "This triangle consisting of ";
1585 cout << *(*it)->point << ", ";
1586 cout << *BaseRay->endpoints[0]->node << " and ";
1587 cout << *BaseRay->endpoints[1]->node << " ";
1588 cout << "is invalid!" << endl;
1589 result = false;
1590 }
1591
1592 // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
1593 BaseRay = BLS[0];
1594 }
1595
1596 // remove all candidates from the list and then the list itself
1597 class CandidateForTesselation *remover = NULL;
1598 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1599 remover = *it;
1600 delete(remover);
1601 }
1602 delete(Opt_Candidates);
1603 cout << Verbose(0) << "End of Find_next_suitable_triangle\n";
1604 return result;
1605};
1606
1607
1608/** Goes over all baselines and checks whether adjacent triangles and convex to each other.
1609 * \param *out output stream for debugging
1610 * \return true - all baselines were corrected, false - there are still concave pieces
1611 */
1612bool Tesselation::CorrectConcaveBaselines(ofstream *out)
1613{
1614 class BoundaryLineSet *OldLines[4], *NewLine;
1615 class BoundaryPointSet *OldPoints[2];
1616 Vector BaseLineNormal;
1617 class BoundaryLineSet *Base = NULL;
1618 int OldTriangles[2], OldBaseLine;
1619 int i,m;
1620
1621 *out << Verbose(1) << "Begin of CorrectConcaveBaselines" << endl;
1622
1623 // go through every baseline
1624 LineMap::iterator Advancer = LinesOnBoundary.begin();
1625 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline = Advancer) {
1626 Advancer++; // as the base line might be removed, we rather have the next one already present
1627 Base = baseline->second;
1628 *out << Verbose(2) << "Current baseline is " << *Base << " ... " << endl;
1629 // calculate NormalVector for later use
1630 BaseLineNormal.Zero();
1631 if (Base->triangles.size() < 2) {
1632 *out << Verbose(2) << "ERROR: Less than two triangles are attached to this baseline!" << endl;
1633 return false;
1634 }
1635 for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
1636 *out << Verbose(4) << "INFO: Adding NormalVector " << runner->second->NormalVector << " of triangle " << *(runner->second) << "." << endl;
1637 BaseLineNormal.AddVector(&(runner->second->NormalVector));
1638 }
1639 BaseLineNormal.Scale(-1./2.); // has to point inside for BoundaryTriangleSet::GetNormalVector()
1640 // check convexity
1641 if (Base->CheckConvexityCriterion(out)) { // triangles are convex
1642 *out << Verbose(2) << "... has two convex triangles." << endl;
1643 } else { // not convex!
1644 *out << Verbose(2) << "... has two concave triangles!" << endl;
1645 // get the two triangles
1646 // gather four endpoints and four lines
1647 for (int j=0;j<4;j++)
1648 OldLines[j] = NULL;
1649 for (int j=0;j<2;j++)
1650 OldPoints[j] = NULL;
1651 i=0;
1652 m=0;
1653 *out << Verbose(3) << "The four old lines are: ";
1654 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1655 for (int j=0;j<3;j++) // all of their endpoints and baselines
1656 if (runner->second->lines[j] != Base) { // pick not the central baseline
1657 OldLines[i++] = runner->second->lines[j];
1658 *out << *runner->second->lines[j] << "\t";
1659 }
1660 *out << endl;
1661 *out << Verbose(3) << "The two old points are: ";
1662 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1663 for (int j=0;j<3;j++) // all of their endpoints and baselines
1664 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) { // and neither of its endpoints
1665 OldPoints[m++] = runner->second->endpoints[j];
1666 *out << *runner->second->endpoints[j] << "\t";
1667 }
1668 *out << endl;
1669 if (i<4) {
1670 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
1671 return false;
1672 }
1673 for (int j=0;j<4;j++)
1674 if (OldLines[j] == NULL) {
1675 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
1676 return false;
1677 }
1678 for (int j=0;j<2;j++)
1679 if (OldPoints[j] == NULL) {
1680 *out << Verbose(1) << "ERROR: We have not gathered enough endpoints!" << endl;
1681 return false;
1682 }
1683
1684 // remove triangles and baseline removes itself
1685 *out << Verbose(3) << "INFO: Deleting baseline " << *Base << "." << endl;
1686 OldBaseLine = Base->Nr;
1687 LinesOnBoundary.erase(OldBaseLine);
1688 m=0;
1689 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
1690 *out << Verbose(3) << "INFO: Deleting triangle " << *(runner->second) << "." << endl;
1691 TrianglesOnBoundary.erase(OldTriangles[m++] = runner->second->Nr);
1692 delete(runner->second);
1693 }
1694
1695 // construct new baseline (with same number as old one)
1696 BPS[0] = OldPoints[0];
1697 BPS[1] = OldPoints[1];
1698 NewLine = new class BoundaryLineSet(BPS, OldBaseLine);
1699 LinesOnBoundary.insert(LinePair(OldBaseLine, NewLine)); // no need for check for unique insertion as NewLine is definitely a new one
1700 *out << Verbose(3) << "INFO: Created new baseline " << *NewLine << "." << endl;
1701
1702 // construct new triangles with flipped baseline
1703 i=-1;
1704 if (OldLines[0]->IsConnectedTo(OldLines[2]))
1705 i=2;
1706 if (OldLines[0]->IsConnectedTo(OldLines[3]))
1707 i=3;
1708 if (i!=-1) {
1709 BLS[0] = OldLines[0];
1710 BLS[1] = OldLines[i];
1711 BLS[2] = NewLine;
1712 BTS = new class BoundaryTriangleSet(BLS, OldTriangles[0]);
1713 BTS->GetNormalVector(BaseLineNormal);
1714 TrianglesOnBoundary.insert(TrianglePair(OldTriangles[0], BTS));
1715 *out << Verbose(3) << "INFO: Created new triangle " << *BTS << "." << endl;
1716
1717 BLS[0] = (i==2 ? OldLines[3] : OldLines[2]);
1718 BLS[1] = OldLines[1];
1719 BLS[2] = NewLine;
1720 BTS = new class BoundaryTriangleSet(BLS, OldTriangles[1]);
1721 BTS->GetNormalVector(BaseLineNormal);
1722 TrianglesOnBoundary.insert(TrianglePair(OldTriangles[1], BTS));
1723 *out << Verbose(3) << "INFO: Created new triangle " << *BTS << "." << endl;
1724 } else {
1725 *out << Verbose(1) << "The four old lines do not connect, something's utterly wrong here!" << endl;
1726 return false;
1727 }
1728 }
1729 }
1730 *out << Verbose(1) << "End of CorrectConcaveBaselines" << endl;
1731 return true;
1732};
1733
1734/** Finds the second point of starting triangle.
1735 * \param *a first node
1736 * \param *Candidate pointer to candidate node on return
1737 * \param Oben vector indicating the outside
1738 * \param Opt_Candidate reference to recommended candidate on return
1739 * \param Storage[3] array storing angles and other candidate information
1740 * \param RADIUS radius of virtual sphere
1741 * \param *LC LinkedCell structure with neighbouring points
1742 */
1743void Tesselation::Find_second_point_for_Tesselation(TesselPoint* a, TesselPoint* Candidate, Vector Oben, TesselPoint*& Opt_Candidate, double Storage[3], double RADIUS, LinkedCell *LC)
1744{
1745 cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation" << endl;
1746 Vector AngleCheck;
1747 double norm = -1., angle;
1748 LinkedNodes *List = NULL;
1749 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
1750
1751 if (LC->SetIndexToNode(a)) { // get cell for the starting point
1752 for(int i=0;i<NDIM;i++) // store indices of this cell
1753 N[i] = LC->n[i];
1754 } else {
1755 cerr << "ERROR: Point " << *a << " is not found in cell " << LC->index << "." << endl;
1756 return;
1757 }
1758 // then go through the current and all neighbouring cells and check the contained points for possible candidates
1759 cout << Verbose(3) << "LC Intervals from [";
1760 for (int i=0;i<NDIM;i++) {
1761 cout << " " << N[i] << "<->" << LC->N[i];
1762 }
1763 cout << "] :";
1764 for (int i=0;i<NDIM;i++) {
1765 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
1766 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
1767 cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
1768 }
1769 cout << endl;
1770
1771
1772 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
1773 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
1774 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
1775 List = LC->GetCurrentCell();
1776 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1777 if (List != NULL) {
1778 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
1779 Candidate = (*Runner);
1780 // check if we only have one unique point yet ...
1781 if (a != Candidate) {
1782 // Calculate center of the circle with radius RADIUS through points a and Candidate
1783 Vector OrthogonalizedOben, a_Candidate, Center;
1784 double distance, scaleFactor;
1785
1786 OrthogonalizedOben.CopyVector(&Oben);
1787 a_Candidate.CopyVector(a->node);
1788 a_Candidate.SubtractVector(Candidate->node);
1789 OrthogonalizedOben.ProjectOntoPlane(&a_Candidate);
1790 OrthogonalizedOben.Normalize();
1791 distance = 0.5 * a_Candidate.Norm();
1792 scaleFactor = sqrt(((RADIUS * RADIUS) - (distance * distance)));
1793 OrthogonalizedOben.Scale(scaleFactor);
1794
1795 Center.CopyVector(Candidate->node);
1796 Center.AddVector(a->node);
1797 Center.Scale(0.5);
1798 Center.AddVector(&OrthogonalizedOben);
1799
1800 AngleCheck.CopyVector(&Center);
1801 AngleCheck.SubtractVector(a->node);
1802 norm = a_Candidate.Norm();
1803 // second point shall have smallest angle with respect to Oben vector
1804 if (norm < RADIUS*2.) {
1805 angle = AngleCheck.Angle(&Oben);
1806 if (angle < Storage[0]) {
1807 //cout << Verbose(3) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
1808 cout << Verbose(3) << "Current candidate is " << *Candidate << ": Is a better candidate with distance " << norm << " and angle " << angle << " to oben " << Oben << ".\n";
1809 Opt_Candidate = Candidate;
1810 Storage[0] = angle;
1811 //cout << Verbose(3) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
1812 } else {
1813 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl;
1814 }
1815 } else {
1816 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Refused due to Radius " << norm << endl;
1817 }
1818 } else {
1819 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Candidate is equal to first endpoint." << *a << "." << endl;
1820 }
1821 }
1822 } else {
1823 cout << Verbose(3) << "Linked cell list is empty." << endl;
1824 }
1825 }
1826 cout << Verbose(2) << "End of Find_second_point_for_Tesselation" << endl;
1827};
1828
1829
1830/** This recursive function finds a third point, to form a triangle with two given ones.
1831 * Note that this function is for the starting triangle.
1832 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points
1833 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then
1834 * the center of the sphere is still fixed up to a single parameter. The band of possible values
1835 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives
1836 * us the "null" on this circle, the new center of the candidate point will be some way along this
1837 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given
1838 * by the normal vector of the base triangle that always points outwards by construction.
1839 * Hence, we construct a Center of this circle which sits right in the middle of the current base line.
1840 * We construct the normal vector that defines the plane this circle lies in, it is just in the
1841 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest
1842 * with respect to the length of the baseline and the sphere's fixed \a RADIUS.
1843 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center
1844 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check
1845 * both.
1846 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check
1847 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check
1848 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal
1849 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality
1850 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether
1851 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI).
1852 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa Find_starting_triangle())
1853 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine
1854 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle
1855 * @param BaseLine BoundaryLineSet with the current base line
1856 * @param ThirdNode third point to avoid in search
1857 * @param candidates list of equally good candidates to return
1858 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate
1859 * @param RADIUS radius of sphere
1860 * @param *LC LinkedCell structure with neighbouring points
1861 */
1862void Tesselation::Find_third_point_for_Tesselation(Vector NormalVector, Vector SearchDirection, Vector OldSphereCenter, class BoundaryLineSet *BaseLine, class TesselPoint *ThirdNode, CandidateList* &candidates, double *ShortestAngle, const double RADIUS, LinkedCell *LC)
1863{
1864 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers
1865 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
1866 Vector SphereCenter;
1867 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility
1868 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility
1869 Vector NewNormalVector; // normal vector of the Candidate's triangle
1870 Vector helper, OptCandidateCenter, OtherOptCandidateCenter;
1871 LinkedNodes *List = NULL;
1872 double CircleRadius; // radius of this circle
1873 double radius;
1874 double alpha, Otheralpha; // angles (i.e. parameter for the circle).
1875 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
1876 TesselPoint *Candidate = NULL;
1877 CandidateForTesselation *optCandidate = NULL;
1878
1879 cout << Verbose(1) << "Begin of Find_third_point_for_Tesselation" << endl;
1880
1881 //cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
1882
1883 // construct center of circle
1884 CircleCenter.CopyVector(BaseLine->endpoints[0]->node->node);
1885 CircleCenter.AddVector(BaseLine->endpoints[1]->node->node);
1886 CircleCenter.Scale(0.5);
1887
1888 // construct normal vector of circle
1889 CirclePlaneNormal.CopyVector(BaseLine->endpoints[0]->node->node);
1890 CirclePlaneNormal.SubtractVector(BaseLine->endpoints[1]->node->node);
1891
1892 // calculate squared radius TesselPoint *ThirdNode,f circle
1893 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
1894 if (radius/4. < RADIUS*RADIUS) {
1895 CircleRadius = RADIUS*RADIUS - radius/4.;
1896 CirclePlaneNormal.Normalize();
1897 //cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
1898
1899 // test whether old center is on the band's plane
1900 if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
1901 cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
1902 OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal);
1903 }
1904 radius = OldSphereCenter.ScalarProduct(&OldSphereCenter);
1905 if (fabs(radius - CircleRadius) < HULLEPSILON) {
1906
1907 // check SearchDirection
1908 //cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
1909 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way!
1910 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl;
1911 }
1912
1913 // get cell for the starting point
1914 if (LC->SetIndexToVector(&CircleCenter)) {
1915 for(int i=0;i<NDIM;i++) // store indices of this cell
1916 N[i] = LC->n[i];
1917 //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
1918 } else {
1919 cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl;
1920 return;
1921 }
1922 // then go through the current and all neighbouring cells and check the contained points for possible candidates
1923 //cout << Verbose(2) << "LC Intervals:";
1924 for (int i=0;i<NDIM;i++) {
1925 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
1926 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
1927 //cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
1928 }
1929 //cout << endl;
1930 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
1931 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
1932 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
1933 List = LC->GetCurrentCell();
1934 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1935 if (List != NULL) {
1936 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
1937 Candidate = (*Runner);
1938
1939 // check for three unique points
1940 //cout << Verbose(2) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->node << "." << endl;
1941 if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) ){
1942
1943 // construct both new centers
1944 GetCenterofCircumcircle(&NewSphereCenter, BaseLine->endpoints[0]->node->node, BaseLine->endpoints[1]->node->node, Candidate->node);
1945 OtherNewSphereCenter.CopyVector(&NewSphereCenter);
1946
1947 if ((NewNormalVector.MakeNormalVector(BaseLine->endpoints[0]->node->node, BaseLine->endpoints[1]->node->node, Candidate->node))
1948 && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)
1949 ) {
1950 helper.CopyVector(&NewNormalVector);
1951 //cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl;
1952 radius = BaseLine->endpoints[0]->node->node->DistanceSquared(&NewSphereCenter);
1953 if (radius < RADIUS*RADIUS) {
1954 helper.Scale(sqrt(RADIUS*RADIUS - radius));
1955 //cout << Verbose(2) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << " with sphere radius " << RADIUS << "." << endl;
1956 NewSphereCenter.AddVector(&helper);
1957 NewSphereCenter.SubtractVector(&CircleCenter);
1958 //cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl;
1959
1960 // OtherNewSphereCenter is created by the same vector just in the other direction
1961 helper.Scale(-1.);
1962 OtherNewSphereCenter.AddVector(&helper);
1963 OtherNewSphereCenter.SubtractVector(&CircleCenter);
1964 //cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl;
1965
1966 alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
1967 Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
1968 alpha = min(alpha, Otheralpha);
1969 // if there is a better candidate, drop the current list and add the new candidate
1970 // otherwise ignore the new candidate and keep the list
1971 if (*ShortestAngle > (alpha - HULLEPSILON)) {
1972 optCandidate = new CandidateForTesselation(Candidate, BaseLine, OptCandidateCenter, OtherOptCandidateCenter);
1973 if (fabs(alpha - Otheralpha) > MYEPSILON) {
1974 optCandidate->OptCenter.CopyVector(&NewSphereCenter);
1975 optCandidate->OtherOptCenter.CopyVector(&OtherNewSphereCenter);
1976 } else {
1977 optCandidate->OptCenter.CopyVector(&OtherNewSphereCenter);
1978 optCandidate->OtherOptCenter.CopyVector(&NewSphereCenter);
1979 }
1980 // if there is an equal candidate, add it to the list without clearing the list
1981 if ((*ShortestAngle - HULLEPSILON) < alpha) {
1982 candidates->push_back(optCandidate);
1983 cout << Verbose(2) << "ACCEPT: We have found an equally good candidate: " << *(optCandidate->point) << " with "
1984 << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
1985 } else {
1986 // remove all candidates from the list and then the list itself
1987 class CandidateForTesselation *remover = NULL;
1988 for (CandidateList::iterator it = candidates->begin(); it != candidates->end(); ++it) {
1989 remover = *it;
1990 delete(remover);
1991 }
1992 candidates->clear();
1993 candidates->push_back(optCandidate);
1994 cout << Verbose(2) << "ACCEPT: We have found a better candidate: " << *(optCandidate->point) << " with "
1995 << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
1996 }
1997 *ShortestAngle = alpha;
1998 //cout << Verbose(2) << "INFO: There are " << candidates->size() << " candidates in the list now." << endl;
1999 } else {
2000 if ((optCandidate != NULL) && (optCandidate->point != NULL)) {
2001 //cout << Verbose(2) << "REJECT: Old candidate " << *(optCandidate->point) << " with " << *ShortestAngle << " is better than new one " << *Candidate << " with " << alpha << " ." << endl;
2002 } else {
2003 //cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl;
2004 }
2005 }
2006
2007 } else {
2008 //cout << Verbose(2) << "REJECT: NewSphereCenter " << NewSphereCenter << " for " << *Candidate << " is too far away: " << radius << "." << endl;
2009 }
2010 } else {
2011 //cout << Verbose(2) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl;
2012 }
2013 } else {
2014 if (ThirdNode != NULL) {
2015 //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl;
2016 } else {
2017 //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl;
2018 }
2019 }
2020 }
2021 }
2022 }
2023 } else {
2024 cerr << Verbose(2) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
2025 }
2026 } else {
2027 if (ThirdNode != NULL)
2028 cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl;
2029 else
2030 cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl;
2031 }
2032
2033 //cout << Verbose(2) << "INFO: Sorting candidate list ..." << endl;
2034 if (candidates->size() > 1) {
2035 candidates->unique();
2036 candidates->sort(sortCandidates);
2037 }
2038
2039 cout << Verbose(1) << "End of Find_third_point_for_Tesselation" << endl;
2040};
2041
2042/** Finds the endpoint two lines are sharing.
2043 * \param *line1 first line
2044 * \param *line2 second line
2045 * \return point which is shared or NULL if none
2046 */
2047class BoundaryPointSet *Tesselation::GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
2048{
2049 class BoundaryLineSet * lines[2] =
2050 { line1, line2 };
2051 class BoundaryPointSet *node = NULL;
2052 map<int, class BoundaryPointSet *> OrderMap;
2053 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
2054 for (int i = 0; i < 2; i++)
2055 // for both lines
2056 for (int j = 0; j < 2; j++)
2057 { // for both endpoints
2058 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
2059 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
2060 if (!OrderTest.second)
2061 { // if insertion fails, we have common endpoint
2062 node = OrderTest.first->second;
2063 cout << Verbose(5) << "Common endpoint of lines " << *line1
2064 << " and " << *line2 << " is: " << *node << "." << endl;
2065 j = 2;
2066 i = 2;
2067 break;
2068 }
2069 }
2070 return node;
2071};
2072
2073/** Finds the triangle that is closest to a given Vector \a *x.
2074 * \param *out output stream for debugging
2075 * \param *x Vector to look from
2076 * \return list of BoundaryTriangleSet of nearest triangles or NULL in degenerate case.
2077 */
2078list<BoundaryTriangleSet*> * Tesselation::FindClosestTrianglesToPoint(ofstream *out, Vector *x, LinkedCell* LC)
2079{
2080 TesselPoint *trianglePoints[3];
2081 TesselPoint *SecondPoint = NULL;
2082
2083 if (LinesOnBoundary.empty()) {
2084 *out << Verbose(0) << "Error: There is no tesselation structure to compare the point with, please create one first.";
2085 return NULL;
2086 }
2087
2088 trianglePoints[0] = findClosestPoint(x, SecondPoint, LC);
2089
2090 // check whether closest point is "too close" :), then it's inside
2091 if (trianglePoints[0] == NULL) {
2092 *out << Verbose(1) << "Is the only point, no one else is closeby." << endl;
2093 return NULL;
2094 }
2095 if (trianglePoints[0]->node->DistanceSquared(x) < MYEPSILON) {
2096 *out << Verbose(1) << "Point is right on a tesselation point, no nearest triangle." << endl;
2097 return NULL;
2098 }
2099 list<TesselPoint*> *connectedClosestPoints = getCircleOfConnectedPoints(out, trianglePoints[0], x);
2100 trianglePoints[1] = connectedClosestPoints->front();
2101 trianglePoints[2] = connectedClosestPoints->back();
2102 for (int i=0;i<3;i++) {
2103 if (trianglePoints[i] == NULL) {
2104 *out << Verbose(1) << "IsInnerPoint encounters serious error, point " << i << " not found." << endl;
2105 }
2106 //*out << Verbose(1) << "List of possible points:" << endl;
2107 //*out << Verbose(2) << *trianglePoints[i] << endl;
2108 }
2109
2110 list<BoundaryTriangleSet*> *triangles = FindTriangles(trianglePoints);
2111
2112 delete(connectedClosestPoints);
2113
2114 if (triangles->empty()) {
2115 *out << Verbose(0) << "Error: There is no nearest triangle. Please check the tesselation structure.";
2116 return NULL;
2117 } else
2118 return triangles;
2119};
2120
2121/** Finds closest triangle to a point.
2122 * This basically just takes care of the degenerate case, which is not handled in FindClosestTrianglesToPoint().
2123 * \param *out output stream for debugging
2124 * \param *x Vector to look from
2125 * \return list of BoundaryTriangleSet of nearest triangles or NULL.
2126 */
2127class BoundaryTriangleSet * Tesselation::FindClosestTriangleToPoint(ofstream *out, Vector *x, LinkedCell* LC)
2128{
2129 class BoundaryTriangleSet *result = NULL;
2130 list<BoundaryTriangleSet*> *triangles = FindClosestTrianglesToPoint(out, x, LC);
2131
2132 if (triangles == NULL)
2133 return NULL;
2134
2135 if (x->ScalarProduct(&triangles->front()->NormalVector) < 0)
2136 result = triangles->back();
2137 else
2138 result = triangles->front();
2139
2140 delete(triangles);
2141 return result;
2142};
2143
2144/** Checks whether the provided Vector is within the tesselation structure.
2145 *
2146 * @param point of which to check the position
2147 * @param *LC LinkedCell structure
2148 *
2149 * @return true if the point is inside the tesselation structure, false otherwise
2150 */
2151bool Tesselation::IsInnerPoint(ofstream *out, Vector Point, LinkedCell* LC)
2152{
2153 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, &Point, LC);
2154 if (result == NULL)
2155 return true;
2156 if (Point.ScalarProduct(&result->NormalVector) < 0)
2157 return true;
2158 else
2159 return false;
2160}
2161
2162/** Checks whether the provided TesselPoint is within the tesselation structure.
2163 *
2164 * @param *Point of which to check the position
2165 * @param *LC Linked Cell structure
2166 *
2167 * @return true if the point is inside the tesselation structure, false otherwise
2168 */
2169bool Tesselation::IsInnerPoint(ofstream *out, TesselPoint *Point, LinkedCell* LC)
2170{
2171 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, Point->node, LC);
2172 if (result == NULL)
2173 return true;
2174 if (Point->node->ScalarProduct(&result->NormalVector) < 0)
2175 return true;
2176 else
2177 return false;
2178}
2179
2180/** Gets all points connected to the provided point by triangulation lines.
2181 * Maps them down onto the plane designated by the axis \a *Point and \a *Reference. The center of all points
2182 * connected in the tesselation to \a *Point is mapped to spherical coordinates with the zero angle being given
2183 * by the mapped down \a *Reference. Hence, the biggest and the smallest angles are those of the two shanks of the
2184 * triangle we are looking for.
2185 *
2186 * @param *Point of which get all connected points
2187 * @param *Reference Vector to be checked whether it is an inner point
2188 *
2189 * @return list of the two points linked to the provided one and closest to the point to be checked,
2190 */
2191list<TesselPoint*> * Tesselation::getCircleOfConnectedPoints(ofstream *out, TesselPoint* Point, Vector* Reference)
2192{
2193 list<TesselPoint*> connectedPoints;
2194 map<double, TesselPoint*> anglesOfPoints;
2195 map<double, TesselPoint*>::iterator runner;
2196 list<TesselPoint*>::iterator listRunner;
2197 class BoundaryPointSet *ReferencePoint = NULL;
2198 Vector center, PlaneNormal, currentPoint, OrthogonalVector, helper, AngleZero;
2199 TesselPoint* current;
2200 bool takePoint = false;
2201
2202 // find the respective boundary point
2203 PointMap::iterator PointRunner = PointsOnBoundary.find(Point->nr);
2204 if (PointRunner != PointsOnBoundary.end()) {
2205 ReferencePoint = PointRunner->second;
2206 } else {
2207 *out << Verbose(2) << "getCircleOfConnectedPoints() could not find the BoundaryPoint belonging to " << *Point << "." << endl;
2208 ReferencePoint = NULL;
2209 }
2210
2211 // little trick so that we look just through lines connect to the BoundaryPoint
2212 // OR fall-back to look through all lines if there is no such BoundaryPoint
2213 LineMap *Lines = &LinesOnBoundary;
2214 if (ReferencePoint != NULL)
2215 Lines = &(ReferencePoint->lines);
2216 LineMap::iterator findLines = Lines->begin();
2217 while (findLines != Lines->end()) {
2218 takePoint = false;
2219
2220 if (findLines->second->endpoints[0]->Nr == Point->nr) {
2221 takePoint = true;
2222 current = findLines->second->endpoints[1]->node;
2223 } else if (findLines->second->endpoints[1]->Nr == Point->nr) {
2224 takePoint = true;
2225 current = findLines->second->endpoints[0]->node;
2226 }
2227
2228 if (takePoint) {
2229 *out << Verbose(3) << "INFO: Endpoint " << *current << " of line " << *(findLines->second) << " is taken into the circle." << endl;
2230 connectedPoints.push_back(current);
2231 currentPoint.CopyVector(current->node);
2232 currentPoint.ProjectOntoPlane(&PlaneNormal);
2233 center.AddVector(&currentPoint);
2234 }
2235
2236 findLines++;
2237 }
2238
2239 //*out << "Summed vectors " << center << "; number of points " << connectedPoints.size()
2240 // << "; scale factor " << 1.0/connectedPoints.size();
2241
2242 if (connectedPoints.size() == 0) { // if have not found any points
2243 *out << Verbose(1) << "ERROR: We have not found any connected points to " << *Point<< "." << endl;
2244 return NULL;
2245 }
2246 center.Scale(1.0/connectedPoints.size());
2247
2248 *out << Verbose(4) << "INFO: Calculated center of all circle points is " << center << "." << endl;
2249
2250 // projection plane of the circle is at the closes Point and normal is pointing away from center of all circle points
2251 PlaneNormal.CopyVector(Point->node);
2252 PlaneNormal.SubtractVector(&center);
2253 PlaneNormal.Normalize();
2254 *out << Verbose(4) << "INFO: Calculated plane normal of circle is " << PlaneNormal << "." << endl;
2255
2256 // construct one orthogonal vector
2257 AngleZero.CopyVector(Reference);
2258 AngleZero.SubtractVector(Point->node);
2259 AngleZero.ProjectOntoPlane(&PlaneNormal);
2260 *out << Verbose(4) << "INFO: Reference vector on this plane representing angle 0 is " << AngleZero << "." << endl;
2261 OrthogonalVector.MakeNormalVector(&PlaneNormal, &AngleZero);
2262 *out << Verbose(4) << "INFO: OrthogonalVector on plane is " << OrthogonalVector << "." << endl;
2263
2264 // go through all connected points and calculate angle
2265 listRunner = connectedPoints.begin();
2266 while (listRunner != connectedPoints.end()) {
2267 helper.CopyVector((*listRunner)->node);
2268 helper.SubtractVector(Point->node);
2269 helper.ProjectOntoPlane(&PlaneNormal);
2270 double angle = getAngle(helper, AngleZero, OrthogonalVector);
2271 *out << Verbose(2) << "INFO: Calculated angle is " << angle << " for point " << **listRunner << "." << endl;
2272 anglesOfPoints.insert(pair<double, TesselPoint*>(angle, (*listRunner)));
2273 listRunner++;
2274 }
2275
2276 list<TesselPoint*> *result = new list<TesselPoint*>;
2277 runner = anglesOfPoints.begin();
2278 result->push_back(runner->second);
2279 runner = anglesOfPoints.end();
2280 runner--;
2281 result->push_back(runner->second);
2282
2283 *out << Verbose(2) << "List of closest points has " << result->size() << " elements, which are "
2284 << *(result->front()) << " and " << *(result->back()) << endl;
2285
2286 return result;
2287}
2288
2289/** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
2290 * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
2291 * make it bigger (i.e. closing one (the baseline) and opening two new ones).
2292 * \param TPS[3] nodes of the triangle
2293 * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
2294 */
2295bool CheckLineCriteriaforDegeneratedTriangle(class BoundaryPointSet *nodes[3])
2296{
2297 bool result = false;
2298 int counter = 0;
2299
2300 // check all three points
2301 for (int i=0;i<3;i++)
2302 for (int j=i+1; j<3; j++) {
2303 if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) { // there already is a line
2304 LineMap::iterator FindLine;
2305 pair<LineMap::iterator,LineMap::iterator> FindPair;
2306 FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
2307 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
2308 // If there is a line with less than two attached triangles, we don't need a new line.
2309 if (FindLine->second->triangles.size() < 2) {
2310 counter++;
2311 break; // increase counter only once per edge
2312 }
2313 }
2314 } else { // no line
2315 cout << Verbose(1) << "The line between " << nodes[i] << " and " << nodes[j] << " is not yet present, hence no need for a degenerate triangle." << endl;
2316 result = true;
2317 }
2318 }
2319 if (counter > 1) {
2320 cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
2321 result = true;
2322 }
2323 return result;
2324};
2325
2326
2327/** Sort function for the candidate list.
2328 */
2329bool sortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2)
2330{
2331 Vector BaseLineVector, OrthogonalVector, helper;
2332 if (candidate1->BaseLine != candidate2->BaseLine) { // sanity check
2333 cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
2334 //return false;
2335 exit(1);
2336 }
2337 // create baseline vector
2338 BaseLineVector.CopyVector(candidate1->BaseLine->endpoints[1]->node->node);
2339 BaseLineVector.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2340 BaseLineVector.Normalize();
2341
2342 // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!)
2343 helper.CopyVector(candidate1->BaseLine->endpoints[0]->node->node);
2344 helper.SubtractVector(candidate1->point->node);
2345 OrthogonalVector.CopyVector(&helper);
2346 helper.VectorProduct(&BaseLineVector);
2347 OrthogonalVector.SubtractVector(&helper);
2348 OrthogonalVector.Normalize();
2349
2350 // calculate both angles and correct with in-plane vector
2351 helper.CopyVector(candidate1->point->node);
2352 helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2353 double phi = BaseLineVector.Angle(&helper);
2354 if (OrthogonalVector.ScalarProduct(&helper) > 0) {
2355 phi = 2.*M_PI - phi;
2356 }
2357 helper.CopyVector(candidate2->point->node);
2358 helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2359 double psi = BaseLineVector.Angle(&helper);
2360 if (OrthogonalVector.ScalarProduct(&helper) > 0) {
2361 psi = 2.*M_PI - psi;
2362 }
2363
2364 cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
2365 cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
2366
2367 // return comparison
2368 return phi < psi;
2369};
2370
2371/**
2372 * Finds the point which is second closest to the provided one.
2373 *
2374 * @param Point to which to find the second closest other point
2375 * @param linked cell structure
2376 *
2377 * @return point which is second closest to the provided one
2378 */
2379TesselPoint* findSecondClosestPoint(const Vector* Point, LinkedCell* LC)
2380{
2381 LinkedNodes *List = NULL;
2382 TesselPoint* closestPoint = NULL;
2383 TesselPoint* secondClosestPoint = NULL;
2384 double distance = 1e16;
2385 double secondDistance = 1e16;
2386 Vector helper;
2387 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2388
2389 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
2390 for(int i=0;i<NDIM;i++) // store indices of this cell
2391 N[i] = LC->n[i];
2392 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2393
2394 LC->GetNeighbourBounds(Nlower, Nupper);
2395 //cout << endl;
2396 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2397 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2398 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2399 List = LC->GetCurrentCell();
2400 cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
2401 if (List != NULL) {
2402 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2403 helper.CopyVector(Point);
2404 helper.SubtractVector((*Runner)->node);
2405 double currentNorm = helper. Norm();
2406 if (currentNorm < distance) {
2407 // remember second point
2408 secondDistance = distance;
2409 secondClosestPoint = closestPoint;
2410 // mark down new closest point
2411 distance = currentNorm;
2412 closestPoint = (*Runner);
2413 cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
2414 }
2415 }
2416 } else {
2417 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
2418 << LC->n[2] << " is invalid!" << endl;
2419 }
2420 }
2421
2422 return secondClosestPoint;
2423};
2424
2425
2426
2427/**
2428 * Finds the point which is closest to the provided one.
2429 *
2430 * @param Point to which to find the closest other point
2431 * @param SecondPoint the second closest other point on return, NULL if none found
2432 * @param linked cell structure
2433 *
2434 * @return point which is closest to the provided one, NULL if none found
2435 */
2436TesselPoint* findClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC)
2437{
2438 LinkedNodes *List = NULL;
2439 TesselPoint* closestPoint = NULL;
2440 SecondPoint = NULL;
2441 double distance = 1e16;
2442 double secondDistance = 1e16;
2443 Vector helper;
2444 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2445
2446 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
2447 for(int i=0;i<NDIM;i++) // store indices of this cell
2448 N[i] = LC->n[i];
2449 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2450
2451 LC->GetNeighbourBounds(Nlower, Nupper);
2452 //cout << endl;
2453 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2454 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2455 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2456 List = LC->GetCurrentCell();
2457 cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
2458 if (List != NULL) {
2459 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2460 helper.CopyVector(Point);
2461 helper.SubtractVector((*Runner)->node);
2462 double currentNorm = helper. Norm();
2463 if (currentNorm < distance) {
2464 secondDistance = distance;
2465 SecondPoint = closestPoint;
2466 distance = currentNorm;
2467 closestPoint = (*Runner);
2468 cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
2469 } else if (currentNorm < secondDistance) {
2470 secondDistance = currentNorm;
2471 SecondPoint = (*Runner);
2472 cout << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
2473 }
2474 }
2475 } else {
2476 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
2477 << LC->n[2] << " is invalid!" << endl;
2478 }
2479 }
2480
2481 return closestPoint;
2482};
2483
2484
2485/**
2486 * Finds triangles belonging to the three provided points.
2487 *
2488 * @param *Points[3] list, is expected to contain three points
2489 *
2490 * @return triangles which belong to the provided points, will be empty if there are none,
2491 * will usually be one, in case of degeneration, there will be two
2492 */
2493list<BoundaryTriangleSet*> *Tesselation::FindTriangles(TesselPoint* Points[3])
2494{
2495 list<BoundaryTriangleSet*> *result = new list<BoundaryTriangleSet*>;
2496 LineMap::iterator FindLine;
2497 PointMap::iterator FindPoint;
2498 TriangleMap::iterator FindTriangle;
2499 class BoundaryPointSet *TrianglePoints[3];
2500
2501 for (int i = 0; i < 3; i++) {
2502 FindPoint = PointsOnBoundary.find(Points[i]->nr);
2503 if (FindPoint != PointsOnBoundary.end()) {
2504 TrianglePoints[i] = FindPoint->second;
2505 } else {
2506 TrianglePoints[i] = NULL;
2507 }
2508 }
2509
2510 // checks lines between the points in the Points for their adjacent triangles
2511 for (int i = 0; i < 3; i++) {
2512 if (TrianglePoints[i] != NULL) {
2513 for (int j = i; j < 3; j++) {
2514 if (TrianglePoints[j] != NULL) {
2515 FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr);
2516 if (FindLine != TrianglePoints[i]->lines.end()) {
2517 for (; FindLine->first == TrianglePoints[j]->node->nr; FindLine++) {
2518 FindTriangle = FindLine->second->triangles.begin();
2519 for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
2520 if ((
2521 (FindTriangle->second->endpoints[0] == TrianglePoints[0])
2522 || (FindTriangle->second->endpoints[0] == TrianglePoints[1])
2523 || (FindTriangle->second->endpoints[0] == TrianglePoints[2])
2524 ) && (
2525 (FindTriangle->second->endpoints[1] == TrianglePoints[0])
2526 || (FindTriangle->second->endpoints[1] == TrianglePoints[1])
2527 || (FindTriangle->second->endpoints[1] == TrianglePoints[2])
2528 ) && (
2529 (FindTriangle->second->endpoints[2] == TrianglePoints[0])
2530 || (FindTriangle->second->endpoints[2] == TrianglePoints[1])
2531 || (FindTriangle->second->endpoints[2] == TrianglePoints[2])
2532 )
2533 ) {
2534 result->push_back(FindTriangle->second);
2535 }
2536 }
2537 }
2538 // Is it sufficient to consider one of the triangle lines for this.
2539 return result;
2540
2541 }
2542 }
2543 }
2544 }
2545 }
2546
2547 return result;
2548}
2549
2550/** Gets the angle between a point and a reference relative to the provided center.
2551 * We have two shanks point and reference between which the angle is calculated
2552 * and by scalar product with OrthogonalVector we decide the interval.
2553 * @param point to calculate the angle for
2554 * @param reference to which to calculate the angle
2555 * @param OrthogonalVector points in direction of [pi,2pi] interval
2556 *
2557 * @return angle between point and reference
2558 */
2559double getAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector)
2560{
2561 if (reference.IsNull())
2562 return M_PI;
2563
2564 // calculate both angles and correct with in-plane vector
2565 if (point.IsNull())
2566 return M_PI;
2567 double phi = point.Angle(&reference);
2568 if (OrthogonalVector.ScalarProduct(&point) > 0) {
2569 phi = 2.*M_PI - phi;
2570 }
2571
2572 cout << Verbose(3) << "INFO: " << point << " has angle " << phi << " with respect to reference " << reference << "." << endl;
2573
2574 return phi;
2575}
2576
Note: See TracBrowser for help on using the repository browser.