source: src/tesselation.cpp@ 570125

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 570125 was 08ef35, checked in by Frederik Heber <heber@…>, 16 years ago

New function ConvexizeNonconvexEnvelope() to calculate the volume of a non-convex envelope.

The central idea is that the volume of a convex envelope is easy to determine as a sum of pyramids with respect to a center inside the envelope. Hence, if we can "reduce" the non-convex envelope to a convex one in such a way that we know the added volume, we may determine the volume of a non-convex envelope.
The nice side effect is that we may use our Find_non_convex_border() algorithm to calculate also the convex envelope.

  • We go through all BoundaryPoints and check whether one of its Baselines does not fulfill the ConvexCriterion. If so, we remove it, as it can not be a boundary point on the convex envelope, and re-construct the attached triangles. The added volume is a general tetraeder, whose formula is known.
  • FIX: Find_convex_border() - We check whether AddPoint is successful or not.
  • builder.cpp: case 'o' - changed to use ConvexizeNonconvexEnvelope() instead of Find_convex_border()
  • Tesselation:AddPoint() - now takes second argument which is the index for BPS and always set BPS to either the newly created or the already present point. Return argument discerns between new and already present point.
  • Tesselation::BPS, BLS, BTS are now public not private. We have to access them from ConvexizeNonconvexEnvelope()
  • Property mode set to 100644
File size: 109.5 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 */
210class 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 if (AddPoint(Walker,0))
1047 NewPoint = BPS[0];
1048 else
1049 continue;
1050 // remove triangle
1051 *out << Verbose(2) << "Erasing triangle " << *BTS << "." << endl;
1052 TrianglesOnBoundary.erase(BTS->Nr);
1053 delete(BTS);
1054 // create three new boundary lines
1055 for (int i=0;i<3;i++) {
1056 BPS[0] = NewPoint;
1057 BPS[1] = OldPoints[i];
1058 NewLines[i] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
1059 *out << Verbose(3) << "Creating new line " << *NewLines[i] << "." << endl;
1060 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, NewLines[i])); // no need for check for unique insertion as BPS[0] is definitely a new one
1061 LinesOnBoundaryCount++;
1062 }
1063 // create three new triangle with new point
1064 for (int i=0;i<3;i++) { // find all baselines
1065 BLS[0] = OldLines[i];
1066 int n = 1;
1067 for (int j=0;j<3;j++) {
1068 if (NewLines[j]->IsConnectedTo(BLS[0])) {
1069 if (n>2) {
1070 *out << Verbose(1) << "ERROR: " << BLS[0] << " connects to all of the new lines?!" << endl;
1071 return false;
1072 } else
1073 BLS[n++] = NewLines[j];
1074 }
1075 }
1076 // create the triangle
1077 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1078 Normal.Scale(-1.);
1079 BTS->GetNormalVector(Normal);
1080 Normal.Scale(-1.);
1081 *out << Verbose(2) << "Created new triangle " << *BTS << "." << endl;
1082 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1083 TrianglesOnBoundaryCount++;
1084 }
1085 }
1086 } else { // something is wrong with FindClosestTriangleToPoint!
1087 *out << Verbose(1) << "ERROR: The closest triangle did not produce an intersection!" << endl;
1088 return false;
1089 }
1090 cloud->GoToNext();
1091 }
1092
1093 // exit
1094 delete(Center);
1095 *out << Verbose(1) << "End of InsertStraddlingPoints" << endl;
1096 return true;
1097};
1098
1099/** Adds an point to the tesselation::PointsOnBoundary list.
1100 * \param *Walker point to add
1101 * \param n TesselStruct::BPS index to put pointer into
1102 * \return true - new point was added, false - point already present
1103 */
1104bool
1105Tesselation::AddPoint(TesselPoint *Walker, int n)
1106{
1107 PointTestPair InsertUnique;
1108 BPS[n] = new class BoundaryPointSet(Walker);
1109 InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[n]));
1110 if (InsertUnique.second) { // if new point was not present before, increase counter
1111 PointsOnBoundaryCount++;
1112 return true;
1113 } else {
1114 delete(BPS[n]);
1115 BPS[n] = InsertUnique.first->second;
1116 return false;
1117 }
1118}
1119;
1120
1121/** Adds point to Tesselation::PointsOnBoundary if not yet present.
1122 * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
1123 * @param Candidate point to add
1124 * @param n index for this point in Tesselation::TPS array
1125 */
1126void
1127Tesselation::AddTrianglePoint(TesselPoint* Candidate, int n)
1128{
1129 PointTestPair InsertUnique;
1130 TPS[n] = new class BoundaryPointSet(Candidate);
1131 InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
1132 if (InsertUnique.second) { // if new point was not present before, increase counter
1133 PointsOnBoundaryCount++;
1134 } else {
1135 delete TPS[n];
1136 cout << Verbose(3) << "Node " << *((InsertUnique.first)->second->node) << " is already present in PointsOnBoundary." << endl;
1137 TPS[n] = (InsertUnique.first)->second;
1138 }
1139}
1140;
1141
1142/** Function tries to add line from current Points in BPS to BoundaryLineSet.
1143 * If successful it raises the line count and inserts the new line into the BLS,
1144 * if unsuccessful, it writes the line which had been present into the BLS, deleting the new constructed one.
1145 * @param *a first endpoint
1146 * @param *b second endpoint
1147 * @param n index of Tesselation::BLS giving the line with both endpoints
1148 */
1149void Tesselation::AddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n) {
1150 bool insertNewLine = true;
1151
1152 if (a->lines.find(b->node->nr) != a->lines.end()) {
1153 LineMap::iterator FindLine;
1154 pair<LineMap::iterator,LineMap::iterator> FindPair;
1155 FindPair = a->lines.equal_range(b->node->nr);
1156
1157 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
1158 // If there is a line with less than two attached triangles, we don't need a new line.
1159 if (FindLine->second->triangles.size() < 2) {
1160 insertNewLine = false;
1161 cout << Verbose(3) << "Using existing line " << *FindLine->second << endl;
1162
1163 BPS[0] = FindLine->second->endpoints[0];
1164 BPS[1] = FindLine->second->endpoints[1];
1165 BLS[n] = FindLine->second;
1166
1167 break;
1168 }
1169 }
1170 }
1171
1172 if (insertNewLine) {
1173 AlwaysAddTriangleLine(a, b, n);
1174 }
1175}
1176;
1177
1178/**
1179 * Adds lines from each of the current points in the BPS to BoundaryLineSet.
1180 * Raises the line count and inserts the new line into the BLS.
1181 *
1182 * @param *a first endpoint
1183 * @param *b second endpoint
1184 * @param n index of Tesselation::BLS giving the line with both endpoints
1185 */
1186void Tesselation::AlwaysAddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n)
1187{
1188 cout << Verbose(3) << "Adding line between " << *(a->node) << " and " << *(b->node) << "." << endl;
1189 BPS[0] = a;
1190 BPS[1] = b;
1191 BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); // this also adds the line to the local maps
1192 // add line to global map
1193 LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
1194 // increase counter
1195 LinesOnBoundaryCount++;
1196};
1197
1198/** Function tries to add Triangle just created to Triangle and remarks if already existent (Failure of algorithm).
1199 * Furthermore it adds the triangle to all of its lines, in order to recognize those which are saturated later.
1200 */
1201void
1202Tesselation::AddTriangle()
1203{
1204 cout << Verbose(1) << "Adding triangle to global TrianglesOnBoundary map." << endl;
1205
1206 // add triangle to global map
1207 TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
1208 TrianglesOnBoundaryCount++;
1209
1210 // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
1211}
1212;
1213
1214/** Checks whether the triangle consisting of the three points is already present.
1215 * Searches for the points in Tesselation::PointsOnBoundary and checks their
1216 * lines. If any of the three edges already has two triangles attached, false is
1217 * returned.
1218 * \param *out output stream for debugging
1219 * \param *Candidates endpoints of the triangle candidate
1220 * \return integer 0 if no triangle exists, 1 if one triangle exists, 2 if two
1221 * triangles exist which is the maximum for three points
1222 */
1223int Tesselation::CheckPresenceOfTriangle(ofstream *out, TesselPoint *Candidates[3]) {
1224 int adjacentTriangleCount = 0;
1225 class BoundaryPointSet *Points[3];
1226
1227 *out << Verbose(2) << "Begin of CheckPresenceOfTriangle" << endl;
1228 // builds a triangle point set (Points) of the end points
1229 for (int i = 0; i < 3; i++) {
1230 PointMap::iterator FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
1231 if (FindPoint != PointsOnBoundary.end()) {
1232 Points[i] = FindPoint->second;
1233 } else {
1234 Points[i] = NULL;
1235 }
1236 }
1237
1238 // checks lines between the points in the Points for their adjacent triangles
1239 for (int i = 0; i < 3; i++) {
1240 if (Points[i] != NULL) {
1241 for (int j = i; j < 3; j++) {
1242 if (Points[j] != NULL) {
1243 LineMap::iterator FindLine = Points[i]->lines.find(Points[j]->node->nr);
1244 for (; (FindLine != Points[i]->lines.end()) && (FindLine->first == Points[j]->node->nr); FindLine++) {
1245 TriangleMap *triangles = &FindLine->second->triangles;
1246 *out << Verbose(3) << "Current line is " << FindLine->first << ": " << *(FindLine->second) << " with triangles " << triangles << "." << endl;
1247 for (TriangleMap::iterator FindTriangle = triangles->begin(); FindTriangle != triangles->end(); FindTriangle++) {
1248 if (FindTriangle->second->IsPresentTupel(Points)) {
1249 adjacentTriangleCount++;
1250 }
1251 }
1252 *out << Verbose(3) << "end." << endl;
1253 }
1254 // Only one of the triangle lines must be considered for the triangle count.
1255 *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1256 return adjacentTriangleCount;
1257 }
1258 }
1259 }
1260 }
1261
1262 *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
1263 *out << Verbose(2) << "End of CheckPresenceOfTriangle" << endl;
1264 return adjacentTriangleCount;
1265};
1266
1267
1268/** Finds the starting triangle for find_non_convex_border().
1269 * Looks at the outermost point per axis, then Find_second_point_for_Tesselation()
1270 * for the second and Find_next_suitable_point_via_Angle_of_Sphere() for the third
1271 * point are called.
1272 * \param *out output stream for debugging
1273 * \param RADIUS radius of virtual rolling sphere
1274 * \param *LC LinkedCell structure with neighbouring TesselPoint's
1275 */
1276void Tesselation::Find_starting_triangle(ofstream *out, const double RADIUS, LinkedCell *LC)
1277{
1278 cout << Verbose(1) << "Begin of Find_starting_triangle\n";
1279 int i = 0;
1280 LinkedNodes *List = NULL;
1281 TesselPoint* FirstPoint = NULL;
1282 TesselPoint* SecondPoint = NULL;
1283 TesselPoint* MaxPoint[NDIM];
1284 double max_coordinate[NDIM];
1285 Vector Oben;
1286 Vector helper;
1287 Vector Chord;
1288 Vector SearchDirection;
1289
1290 Oben.Zero();
1291
1292 for (i = 0; i < 3; i++) {
1293 MaxPoint[i] = NULL;
1294 max_coordinate[i] = -1;
1295 }
1296
1297 // 1. searching topmost point with respect to each axis
1298 for (int i=0;i<NDIM;i++) { // each axis
1299 LC->n[i] = LC->N[i]-1; // current axis is topmost cell
1300 for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++)
1301 for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) {
1302 List = LC->GetCurrentCell();
1303 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1304 if (List != NULL) {
1305 for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
1306 if ((*Runner)->node->x[i] > max_coordinate[i]) {
1307 cout << Verbose(2) << "New maximal for axis " << i << " node is " << *(*Runner) << " at " << *(*Runner)->node << "." << endl;
1308 max_coordinate[i] = (*Runner)->node->x[i];
1309 MaxPoint[i] = (*Runner);
1310 }
1311 }
1312 } else {
1313 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
1314 }
1315 }
1316 }
1317
1318 cout << Verbose(2) << "Found maximum coordinates: ";
1319 for (int i=0;i<NDIM;i++)
1320 cout << i << ": " << *MaxPoint[i] << "\t";
1321 cout << endl;
1322
1323 BTS = NULL;
1324 CandidateList *Opt_Candidates = new CandidateList();
1325 for (int k=0;k<NDIM;k++) {
1326 Oben.x[k] = 1.;
1327 FirstPoint = MaxPoint[k];
1328 cout << Verbose(1) << "Coordinates of start node at " << *FirstPoint->node << "." << endl;
1329
1330 double ShortestAngle;
1331 TesselPoint* Opt_Candidate = NULL;
1332 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.
1333
1334 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_...
1335 SecondPoint = Opt_Candidate;
1336 if (SecondPoint == NULL) // have we found a second point?
1337 continue;
1338 else
1339 cout << Verbose(1) << "Found second point is at " << *SecondPoint->node << ".\n";
1340
1341 helper.CopyVector(FirstPoint->node);
1342 helper.SubtractVector(SecondPoint->node);
1343 helper.Normalize();
1344 Oben.ProjectOntoPlane(&helper);
1345 Oben.Normalize();
1346 helper.VectorProduct(&Oben);
1347 ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1348
1349 Chord.CopyVector(FirstPoint->node); // bring into calling function
1350 Chord.SubtractVector(SecondPoint->node);
1351 double radius = Chord.ScalarProduct(&Chord);
1352 double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.);
1353 helper.CopyVector(&Oben);
1354 helper.Scale(CircleRadius);
1355 // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized)
1356
1357 // look in one direction of baseline for initial candidate
1358 SearchDirection.MakeNormalVector(&Chord, &Oben); // whether we look "left" first or "right" first is not important ...
1359
1360 // adding point 1 and point 2 and add the line between them
1361 AddTrianglePoint(FirstPoint, 0);
1362 AddTrianglePoint(SecondPoint, 1);
1363 AddTriangleLine(TPS[0], TPS[1], 0);
1364
1365 //cout << Verbose(2) << "INFO: OldSphereCenter is at " << helper << ".\n";
1366 Find_third_point_for_Tesselation(
1367 Oben, SearchDirection, helper, BLS[0], NULL, *&Opt_Candidates, &ShortestAngle, RADIUS, LC
1368 );
1369 cout << Verbose(1) << "List of third Points is ";
1370 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1371 cout << " " << *(*it)->point;
1372 }
1373 cout << endl;
1374
1375 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1376 // add third triangle point
1377 AddTrianglePoint((*it)->point, 2);
1378 // add the second and third line
1379 AddTriangleLine(TPS[1], TPS[2], 1);
1380 AddTriangleLine(TPS[0], TPS[2], 2);
1381 // ... and triangles to the Maps of the Tesselation class
1382 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1383 AddTriangle();
1384 // ... and calculate its normal vector (with correct orientation)
1385 (*it)->OptCenter.Scale(-1.);
1386 cout << Verbose(2) << "Anti-Oben is currently " << (*it)->OptCenter << "." << endl;
1387 BTS->GetNormalVector((*it)->OptCenter); // vector to compare with should point inwards
1388 cout << Verbose(0) << "==> Found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and "
1389 << *(*it)->point << " with normal vector " << BTS->NormalVector << ".\n";
1390
1391 // if we do not reach the end with the next step of iteration, we need to setup a new first line
1392 if (it != Opt_Candidates->end()--) {
1393 FirstPoint = (*it)->BaseLine->endpoints[0]->node;
1394 SecondPoint = (*it)->point;
1395 // adding point 1 and point 2 and the line between them
1396 AddTrianglePoint(FirstPoint, 0);
1397 AddTrianglePoint(SecondPoint, 1);
1398 AddTriangleLine(TPS[0], TPS[1], 0);
1399 }
1400 cout << Verbose(2) << "Projection is " << BTS->NormalVector.Projection(&Oben) << "." << endl;
1401 }
1402 if (BTS != NULL) // we have created one starting triangle
1403 break;
1404 else {
1405 // remove all candidates from the list and then the list itself
1406 class CandidateForTesselation *remover = NULL;
1407 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1408 remover = *it;
1409 delete(remover);
1410 }
1411 Opt_Candidates->clear();
1412 }
1413 }
1414
1415 // remove all candidates from the list and then the list itself
1416 class CandidateForTesselation *remover = NULL;
1417 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1418 remover = *it;
1419 delete(remover);
1420 }
1421 delete(Opt_Candidates);
1422 cout << Verbose(1) << "End of Find_starting_triangle\n";
1423};
1424
1425
1426/** This function finds a triangle to a line, adjacent to an existing one.
1427 * @param out output stream for debugging
1428 * @param Line current baseline to search from
1429 * @param T current triangle which \a Line is edge of
1430 * @param RADIUS radius of the rolling ball
1431 * @param N number of found triangles
1432 * @param *LC LinkedCell structure with neighbouring points
1433 */
1434bool Tesselation::Find_next_suitable_triangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, int N, LinkedCell *LC)
1435{
1436 cout << Verbose(0) << "Begin of Find_next_suitable_triangle\n";
1437 bool result = true;
1438 CandidateList *Opt_Candidates = new CandidateList();
1439
1440 Vector CircleCenter;
1441 Vector CirclePlaneNormal;
1442 Vector OldSphereCenter;
1443 Vector SearchDirection;
1444 Vector helper;
1445 TesselPoint *ThirdNode = NULL;
1446 LineMap::iterator testline;
1447 double ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
1448 double radius, CircleRadius;
1449
1450 cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl;
1451 for (int i=0;i<3;i++)
1452 if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node))
1453 ThirdNode = T.endpoints[i]->node;
1454
1455 // construct center of circle
1456 CircleCenter.CopyVector(Line.endpoints[0]->node->node);
1457 CircleCenter.AddVector(Line.endpoints[1]->node->node);
1458 CircleCenter.Scale(0.5);
1459
1460 // construct normal vector of circle
1461 CirclePlaneNormal.CopyVector(Line.endpoints[0]->node->node);
1462 CirclePlaneNormal.SubtractVector(Line.endpoints[1]->node->node);
1463
1464 // calculate squared radius of circle
1465 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
1466 if (radius/4. < RADIUS*RADIUS) {
1467 CircleRadius = RADIUS*RADIUS - radius/4.;
1468 CirclePlaneNormal.Normalize();
1469 cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
1470
1471 // construct old center
1472 GetCenterofCircumcircle(&OldSphereCenter, T.endpoints[0]->node->node, T.endpoints[1]->node->node, T.endpoints[2]->node->node);
1473 helper.CopyVector(&T.NormalVector); // normal vector ensures that this is correct center of the two possible ones
1474 radius = Line.endpoints[0]->node->node->DistanceSquared(&OldSphereCenter);
1475 helper.Scale(sqrt(RADIUS*RADIUS - radius));
1476 OldSphereCenter.AddVector(&helper);
1477 OldSphereCenter.SubtractVector(&CircleCenter);
1478 //cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
1479
1480 // construct SearchDirection
1481 SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal);
1482 helper.CopyVector(Line.endpoints[0]->node->node);
1483 helper.SubtractVector(ThirdNode->node);
1484 if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
1485 SearchDirection.Scale(-1.);
1486 SearchDirection.ProjectOntoPlane(&OldSphereCenter);
1487 SearchDirection.Normalize();
1488 cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
1489 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
1490 // rotated the wrong way!
1491 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
1492 }
1493
1494 // add third point
1495 Find_third_point_for_Tesselation(
1496 T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, Opt_Candidates,
1497 &ShortestAngle, RADIUS, LC
1498 );
1499
1500 } else {
1501 cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl;
1502 }
1503
1504 if (Opt_Candidates->begin() == Opt_Candidates->end()) {
1505 cerr << "WARNING: Could not find a suitable candidate." << endl;
1506 return false;
1507 }
1508 cout << Verbose(1) << "Third Points are ";
1509 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1510 cout << " " << *(*it)->point;
1511 }
1512 cout << endl;
1513
1514 BoundaryLineSet *BaseRay = &Line;
1515 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1516 cout << Verbose(1) << " Third point candidate is " << *(*it)->point
1517 << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
1518 cout << Verbose(1) << " Baseline is " << *BaseRay << endl;
1519
1520 // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
1521 TesselPoint *PointCandidates[3];
1522 PointCandidates[0] = (*it)->point;
1523 PointCandidates[1] = BaseRay->endpoints[0]->node;
1524 PointCandidates[2] = BaseRay->endpoints[1]->node;
1525 int existentTrianglesCount = CheckPresenceOfTriangle(out, PointCandidates);
1526
1527 BTS = NULL;
1528 // If there is no triangle, add it regularly.
1529 if (existentTrianglesCount == 0) {
1530 AddTrianglePoint((*it)->point, 0);
1531 AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
1532 AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
1533
1534 if (CheckLineCriteriaforDegeneratedTriangle(TPS)) {
1535 AddTriangleLine(TPS[0], TPS[1], 0);
1536 AddTriangleLine(TPS[0], TPS[2], 1);
1537 AddTriangleLine(TPS[1], TPS[2], 2);
1538
1539 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1540 AddTriangle();
1541 (*it)->OptCenter.Scale(-1.);
1542 BTS->GetNormalVector((*it)->OptCenter);
1543 (*it)->OptCenter.Scale(-1.);
1544
1545 cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector
1546 << " for this triangle ... " << endl;
1547 //cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << *BaseRay << "." << endl;
1548 } else {
1549 cout << Verbose(1) << "WARNING: This triangle consisting of ";
1550 cout << *(*it)->point << ", ";
1551 cout << *BaseRay->endpoints[0]->node << " and ";
1552 cout << *BaseRay->endpoints[1]->node << " ";
1553 cout << "exists and is not added, as it does not seem helpful!" << endl;
1554 result = false;
1555 }
1556 } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time.
1557 AddTrianglePoint((*it)->point, 0);
1558 AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
1559 AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
1560
1561 // 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)
1562 // i.e. at least one of the three lines must be present with TriangleCount <= 1
1563 if (CheckLineCriteriaforDegeneratedTriangle(TPS)) {
1564 AddTriangleLine(TPS[0], TPS[1], 0);
1565 AddTriangleLine(TPS[0], TPS[2], 1);
1566 AddTriangleLine(TPS[1], TPS[2], 2);
1567
1568 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1569 AddTriangle(); // add to global map
1570
1571 (*it)->OtherOptCenter.Scale(-1.);
1572 BTS->GetNormalVector((*it)->OtherOptCenter);
1573 (*it)->OtherOptCenter.Scale(-1.);
1574
1575 cout << "--> WARNING: Special new triangle with " << *BTS << " and normal vector " << BTS->NormalVector
1576 << " for this triangle ... " << endl;
1577 cout << Verbose(1) << "We have "<< BaseRay->triangles.size() << " for line " << BaseRay << "." << endl;
1578 } else {
1579 cout << Verbose(1) << "WARNING: This triangle consisting of ";
1580 cout << *(*it)->point << ", ";
1581 cout << *BaseRay->endpoints[0]->node << " and ";
1582 cout << *BaseRay->endpoints[1]->node << " ";
1583 cout << "exists and is not added, as it does not seem helpful!" << endl;
1584 result = false;
1585 }
1586 } else {
1587 cout << Verbose(1) << "This triangle consisting of ";
1588 cout << *(*it)->point << ", ";
1589 cout << *BaseRay->endpoints[0]->node << " and ";
1590 cout << *BaseRay->endpoints[1]->node << " ";
1591 cout << "is invalid!" << endl;
1592 result = false;
1593 }
1594
1595 // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
1596 BaseRay = BLS[0];
1597 }
1598
1599 // remove all candidates from the list and then the list itself
1600 class CandidateForTesselation *remover = NULL;
1601 for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
1602 remover = *it;
1603 delete(remover);
1604 }
1605 delete(Opt_Candidates);
1606 cout << Verbose(0) << "End of Find_next_suitable_triangle\n";
1607 return result;
1608};
1609
1610
1611/** Goes over all baselines and checks whether adjacent triangles and convex to each other.
1612 * \param *out output stream for debugging
1613 * \return true - all baselines were corrected, false - there are still concave pieces
1614 */
1615bool Tesselation::CorrectConcaveBaselines(ofstream *out)
1616{
1617 class BoundaryLineSet *OldLines[4], *NewLine;
1618 class BoundaryPointSet *OldPoints[2];
1619 Vector BaseLineNormal;
1620 class BoundaryLineSet *Base = NULL;
1621 int OldTriangles[2], OldBaseLine;
1622 int i,m;
1623
1624 *out << Verbose(1) << "Begin of CorrectConcaveBaselines" << endl;
1625
1626 // go through every baseline
1627 LineMap::iterator Advancer = LinesOnBoundary.begin();
1628 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline = Advancer) {
1629 Advancer++; // as the base line might be removed, we rather have the next one already present
1630 Base = baseline->second;
1631 *out << Verbose(2) << "Current baseline is " << *Base << " ... " << endl;
1632 // calculate NormalVector for later use
1633 BaseLineNormal.Zero();
1634 if (Base->triangles.size() < 2) {
1635 *out << Verbose(2) << "ERROR: Less than two triangles are attached to this baseline!" << endl;
1636 return false;
1637 }
1638 for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
1639 *out << Verbose(4) << "INFO: Adding NormalVector " << runner->second->NormalVector << " of triangle " << *(runner->second) << "." << endl;
1640 BaseLineNormal.AddVector(&(runner->second->NormalVector));
1641 }
1642 BaseLineNormal.Scale(-1./2.); // has to point inside for BoundaryTriangleSet::GetNormalVector()
1643 // check convexity
1644 if (Base->CheckConvexityCriterion(out)) { // triangles are convex
1645 *out << Verbose(2) << "... has two convex triangles." << endl;
1646 } else { // not convex!
1647 *out << Verbose(2) << "... has two concave triangles!" << endl;
1648 // get the two triangles
1649 // gather four endpoints and four lines
1650 for (int j=0;j<4;j++)
1651 OldLines[j] = NULL;
1652 for (int j=0;j<2;j++)
1653 OldPoints[j] = NULL;
1654 i=0;
1655 m=0;
1656 *out << Verbose(3) << "The four old lines are: ";
1657 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1658 for (int j=0;j<3;j++) // all of their endpoints and baselines
1659 if (runner->second->lines[j] != Base) { // pick not the central baseline
1660 OldLines[i++] = runner->second->lines[j];
1661 *out << *runner->second->lines[j] << "\t";
1662 }
1663 *out << endl;
1664 *out << Verbose(3) << "The two old points are: ";
1665 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
1666 for (int j=0;j<3;j++) // all of their endpoints and baselines
1667 if (!Base->ContainsBoundaryPoint(runner->second->endpoints[j])) { // and neither of its endpoints
1668 OldPoints[m++] = runner->second->endpoints[j];
1669 *out << *runner->second->endpoints[j] << "\t";
1670 }
1671 *out << endl;
1672 if (i<4) {
1673 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
1674 return false;
1675 }
1676 for (int j=0;j<4;j++)
1677 if (OldLines[j] == NULL) {
1678 *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
1679 return false;
1680 }
1681 for (int j=0;j<2;j++)
1682 if (OldPoints[j] == NULL) {
1683 *out << Verbose(1) << "ERROR: We have not gathered enough endpoints!" << endl;
1684 return false;
1685 }
1686
1687 // remove triangles and baseline removes itself
1688 *out << Verbose(3) << "INFO: Deleting baseline " << *Base << "." << endl;
1689 OldBaseLine = Base->Nr;
1690 LinesOnBoundary.erase(OldBaseLine);
1691 m=0;
1692 for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
1693 *out << Verbose(3) << "INFO: Deleting triangle " << *(runner->second) << "." << endl;
1694 TrianglesOnBoundary.erase(OldTriangles[m++] = runner->second->Nr);
1695 delete(runner->second);
1696 }
1697
1698 // construct new baseline (with same number as old one)
1699 BPS[0] = OldPoints[0];
1700 BPS[1] = OldPoints[1];
1701 NewLine = new class BoundaryLineSet(BPS, OldBaseLine);
1702 LinesOnBoundary.insert(LinePair(OldBaseLine, NewLine)); // no need for check for unique insertion as NewLine is definitely a new one
1703 *out << Verbose(3) << "INFO: Created new baseline " << *NewLine << "." << endl;
1704
1705 // construct new triangles with flipped baseline
1706 i=-1;
1707 if (OldLines[0]->IsConnectedTo(OldLines[2]))
1708 i=2;
1709 if (OldLines[0]->IsConnectedTo(OldLines[3]))
1710 i=3;
1711 if (i!=-1) {
1712 BLS[0] = OldLines[0];
1713 BLS[1] = OldLines[i];
1714 BLS[2] = NewLine;
1715 BTS = new class BoundaryTriangleSet(BLS, OldTriangles[0]);
1716 BTS->GetNormalVector(BaseLineNormal);
1717 TrianglesOnBoundary.insert(TrianglePair(OldTriangles[0], BTS));
1718 *out << Verbose(3) << "INFO: Created new triangle " << *BTS << "." << endl;
1719
1720 BLS[0] = (i==2 ? OldLines[3] : OldLines[2]);
1721 BLS[1] = OldLines[1];
1722 BLS[2] = NewLine;
1723 BTS = new class BoundaryTriangleSet(BLS, OldTriangles[1]);
1724 BTS->GetNormalVector(BaseLineNormal);
1725 TrianglesOnBoundary.insert(TrianglePair(OldTriangles[1], BTS));
1726 *out << Verbose(3) << "INFO: Created new triangle " << *BTS << "." << endl;
1727 } else {
1728 *out << Verbose(1) << "The four old lines do not connect, something's utterly wrong here!" << endl;
1729 return false;
1730 }
1731 }
1732 }
1733 *out << Verbose(1) << "End of CorrectConcaveBaselines" << endl;
1734 return true;
1735};
1736
1737/** Finds the second point of starting triangle.
1738 * \param *a first node
1739 * \param *Candidate pointer to candidate node on return
1740 * \param Oben vector indicating the outside
1741 * \param Opt_Candidate reference to recommended candidate on return
1742 * \param Storage[3] array storing angles and other candidate information
1743 * \param RADIUS radius of virtual sphere
1744 * \param *LC LinkedCell structure with neighbouring points
1745 */
1746void Tesselation::Find_second_point_for_Tesselation(TesselPoint* a, TesselPoint* Candidate, Vector Oben, TesselPoint*& Opt_Candidate, double Storage[3], double RADIUS, LinkedCell *LC)
1747{
1748 cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation" << endl;
1749 Vector AngleCheck;
1750 double norm = -1., angle;
1751 LinkedNodes *List = NULL;
1752 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
1753
1754 if (LC->SetIndexToNode(a)) { // get cell for the starting point
1755 for(int i=0;i<NDIM;i++) // store indices of this cell
1756 N[i] = LC->n[i];
1757 } else {
1758 cerr << "ERROR: Point " << *a << " is not found in cell " << LC->index << "." << endl;
1759 return;
1760 }
1761 // then go through the current and all neighbouring cells and check the contained points for possible candidates
1762 cout << Verbose(3) << "LC Intervals from [";
1763 for (int i=0;i<NDIM;i++) {
1764 cout << " " << N[i] << "<->" << LC->N[i];
1765 }
1766 cout << "] :";
1767 for (int i=0;i<NDIM;i++) {
1768 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
1769 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
1770 cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
1771 }
1772 cout << endl;
1773
1774
1775 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
1776 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
1777 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
1778 List = LC->GetCurrentCell();
1779 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1780 if (List != NULL) {
1781 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
1782 Candidate = (*Runner);
1783 // check if we only have one unique point yet ...
1784 if (a != Candidate) {
1785 // Calculate center of the circle with radius RADIUS through points a and Candidate
1786 Vector OrthogonalizedOben, a_Candidate, Center;
1787 double distance, scaleFactor;
1788
1789 OrthogonalizedOben.CopyVector(&Oben);
1790 a_Candidate.CopyVector(a->node);
1791 a_Candidate.SubtractVector(Candidate->node);
1792 OrthogonalizedOben.ProjectOntoPlane(&a_Candidate);
1793 OrthogonalizedOben.Normalize();
1794 distance = 0.5 * a_Candidate.Norm();
1795 scaleFactor = sqrt(((RADIUS * RADIUS) - (distance * distance)));
1796 OrthogonalizedOben.Scale(scaleFactor);
1797
1798 Center.CopyVector(Candidate->node);
1799 Center.AddVector(a->node);
1800 Center.Scale(0.5);
1801 Center.AddVector(&OrthogonalizedOben);
1802
1803 AngleCheck.CopyVector(&Center);
1804 AngleCheck.SubtractVector(a->node);
1805 norm = a_Candidate.Norm();
1806 // second point shall have smallest angle with respect to Oben vector
1807 if (norm < RADIUS*2.) {
1808 angle = AngleCheck.Angle(&Oben);
1809 if (angle < Storage[0]) {
1810 //cout << Verbose(3) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
1811 cout << Verbose(3) << "Current candidate is " << *Candidate << ": Is a better candidate with distance " << norm << " and angle " << angle << " to oben " << Oben << ".\n";
1812 Opt_Candidate = Candidate;
1813 Storage[0] = angle;
1814 //cout << Verbose(3) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
1815 } else {
1816 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl;
1817 }
1818 } else {
1819 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Refused due to Radius " << norm << endl;
1820 }
1821 } else {
1822 //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Candidate is equal to first endpoint." << *a << "." << endl;
1823 }
1824 }
1825 } else {
1826 cout << Verbose(3) << "Linked cell list is empty." << endl;
1827 }
1828 }
1829 cout << Verbose(2) << "End of Find_second_point_for_Tesselation" << endl;
1830};
1831
1832
1833/** This recursive function finds a third point, to form a triangle with two given ones.
1834 * Note that this function is for the starting triangle.
1835 * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points
1836 * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then
1837 * the center of the sphere is still fixed up to a single parameter. The band of possible values
1838 * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives
1839 * us the "null" on this circle, the new center of the candidate point will be some way along this
1840 * circle. The shorter the way the better is the candidate. Note that the direction is clearly given
1841 * by the normal vector of the base triangle that always points outwards by construction.
1842 * Hence, we construct a Center of this circle which sits right in the middle of the current base line.
1843 * We construct the normal vector that defines the plane this circle lies in, it is just in the
1844 * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest
1845 * with respect to the length of the baseline and the sphere's fixed \a RADIUS.
1846 * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center
1847 * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check
1848 * both.
1849 * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check
1850 * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check
1851 * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal
1852 * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality
1853 * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether
1854 * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI).
1855 * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa Find_starting_triangle())
1856 * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine
1857 * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle
1858 * @param BaseLine BoundaryLineSet with the current base line
1859 * @param ThirdNode third point to avoid in search
1860 * @param candidates list of equally good candidates to return
1861 * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate
1862 * @param RADIUS radius of sphere
1863 * @param *LC LinkedCell structure with neighbouring points
1864 */
1865void 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)
1866{
1867 Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers
1868 Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
1869 Vector SphereCenter;
1870 Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility
1871 Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility
1872 Vector NewNormalVector; // normal vector of the Candidate's triangle
1873 Vector helper, OptCandidateCenter, OtherOptCandidateCenter;
1874 LinkedNodes *List = NULL;
1875 double CircleRadius; // radius of this circle
1876 double radius;
1877 double alpha, Otheralpha; // angles (i.e. parameter for the circle).
1878 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
1879 TesselPoint *Candidate = NULL;
1880 CandidateForTesselation *optCandidate = NULL;
1881
1882 cout << Verbose(1) << "Begin of Find_third_point_for_Tesselation" << endl;
1883
1884 //cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
1885
1886 // construct center of circle
1887 CircleCenter.CopyVector(BaseLine->endpoints[0]->node->node);
1888 CircleCenter.AddVector(BaseLine->endpoints[1]->node->node);
1889 CircleCenter.Scale(0.5);
1890
1891 // construct normal vector of circle
1892 CirclePlaneNormal.CopyVector(BaseLine->endpoints[0]->node->node);
1893 CirclePlaneNormal.SubtractVector(BaseLine->endpoints[1]->node->node);
1894
1895 // calculate squared radius TesselPoint *ThirdNode,f circle
1896 radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
1897 if (radius/4. < RADIUS*RADIUS) {
1898 CircleRadius = RADIUS*RADIUS - radius/4.;
1899 CirclePlaneNormal.Normalize();
1900 //cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
1901
1902 // test whether old center is on the band's plane
1903 if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
1904 cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
1905 OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal);
1906 }
1907 radius = OldSphereCenter.ScalarProduct(&OldSphereCenter);
1908 if (fabs(radius - CircleRadius) < HULLEPSILON) {
1909
1910 // check SearchDirection
1911 //cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
1912 if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way!
1913 cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl;
1914 }
1915
1916 // get cell for the starting point
1917 if (LC->SetIndexToVector(&CircleCenter)) {
1918 for(int i=0;i<NDIM;i++) // store indices of this cell
1919 N[i] = LC->n[i];
1920 //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
1921 } else {
1922 cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl;
1923 return;
1924 }
1925 // then go through the current and all neighbouring cells and check the contained points for possible candidates
1926 //cout << Verbose(2) << "LC Intervals:";
1927 for (int i=0;i<NDIM;i++) {
1928 Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
1929 Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
1930 //cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
1931 }
1932 //cout << endl;
1933 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
1934 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
1935 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
1936 List = LC->GetCurrentCell();
1937 //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1938 if (List != NULL) {
1939 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
1940 Candidate = (*Runner);
1941
1942 // check for three unique points
1943 //cout << Verbose(2) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->node << "." << endl;
1944 if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) ){
1945
1946 // construct both new centers
1947 GetCenterofCircumcircle(&NewSphereCenter, BaseLine->endpoints[0]->node->node, BaseLine->endpoints[1]->node->node, Candidate->node);
1948 OtherNewSphereCenter.CopyVector(&NewSphereCenter);
1949
1950 if ((NewNormalVector.MakeNormalVector(BaseLine->endpoints[0]->node->node, BaseLine->endpoints[1]->node->node, Candidate->node))
1951 && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)
1952 ) {
1953 helper.CopyVector(&NewNormalVector);
1954 //cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl;
1955 radius = BaseLine->endpoints[0]->node->node->DistanceSquared(&NewSphereCenter);
1956 if (radius < RADIUS*RADIUS) {
1957 helper.Scale(sqrt(RADIUS*RADIUS - radius));
1958 //cout << Verbose(2) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << " with sphere radius " << RADIUS << "." << endl;
1959 NewSphereCenter.AddVector(&helper);
1960 NewSphereCenter.SubtractVector(&CircleCenter);
1961 //cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl;
1962
1963 // OtherNewSphereCenter is created by the same vector just in the other direction
1964 helper.Scale(-1.);
1965 OtherNewSphereCenter.AddVector(&helper);
1966 OtherNewSphereCenter.SubtractVector(&CircleCenter);
1967 //cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl;
1968
1969 alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
1970 Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
1971 alpha = min(alpha, Otheralpha);
1972 // if there is a better candidate, drop the current list and add the new candidate
1973 // otherwise ignore the new candidate and keep the list
1974 if (*ShortestAngle > (alpha - HULLEPSILON)) {
1975 optCandidate = new CandidateForTesselation(Candidate, BaseLine, OptCandidateCenter, OtherOptCandidateCenter);
1976 if (fabs(alpha - Otheralpha) > MYEPSILON) {
1977 optCandidate->OptCenter.CopyVector(&NewSphereCenter);
1978 optCandidate->OtherOptCenter.CopyVector(&OtherNewSphereCenter);
1979 } else {
1980 optCandidate->OptCenter.CopyVector(&OtherNewSphereCenter);
1981 optCandidate->OtherOptCenter.CopyVector(&NewSphereCenter);
1982 }
1983 // if there is an equal candidate, add it to the list without clearing the list
1984 if ((*ShortestAngle - HULLEPSILON) < alpha) {
1985 candidates->push_back(optCandidate);
1986 cout << Verbose(2) << "ACCEPT: We have found an equally good candidate: " << *(optCandidate->point) << " with "
1987 << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
1988 } else {
1989 // remove all candidates from the list and then the list itself
1990 class CandidateForTesselation *remover = NULL;
1991 for (CandidateList::iterator it = candidates->begin(); it != candidates->end(); ++it) {
1992 remover = *it;
1993 delete(remover);
1994 }
1995 candidates->clear();
1996 candidates->push_back(optCandidate);
1997 cout << Verbose(2) << "ACCEPT: We have found a better candidate: " << *(optCandidate->point) << " with "
1998 << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
1999 }
2000 *ShortestAngle = alpha;
2001 //cout << Verbose(2) << "INFO: There are " << candidates->size() << " candidates in the list now." << endl;
2002 } else {
2003 if ((optCandidate != NULL) && (optCandidate->point != NULL)) {
2004 //cout << Verbose(2) << "REJECT: Old candidate " << *(optCandidate->point) << " with " << *ShortestAngle << " is better than new one " << *Candidate << " with " << alpha << " ." << endl;
2005 } else {
2006 //cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl;
2007 }
2008 }
2009
2010 } else {
2011 //cout << Verbose(2) << "REJECT: NewSphereCenter " << NewSphereCenter << " for " << *Candidate << " is too far away: " << radius << "." << endl;
2012 }
2013 } else {
2014 //cout << Verbose(2) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl;
2015 }
2016 } else {
2017 if (ThirdNode != NULL) {
2018 //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl;
2019 } else {
2020 //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl;
2021 }
2022 }
2023 }
2024 }
2025 }
2026 } else {
2027 cerr << Verbose(2) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
2028 }
2029 } else {
2030 if (ThirdNode != NULL)
2031 cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl;
2032 else
2033 cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl;
2034 }
2035
2036 //cout << Verbose(2) << "INFO: Sorting candidate list ..." << endl;
2037 if (candidates->size() > 1) {
2038 candidates->unique();
2039 candidates->sort(sortCandidates);
2040 }
2041
2042 cout << Verbose(1) << "End of Find_third_point_for_Tesselation" << endl;
2043};
2044
2045/** Finds the endpoint two lines are sharing.
2046 * \param *line1 first line
2047 * \param *line2 second line
2048 * \return point which is shared or NULL if none
2049 */
2050class BoundaryPointSet *Tesselation::GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
2051{
2052 class BoundaryLineSet * lines[2] =
2053 { line1, line2 };
2054 class BoundaryPointSet *node = NULL;
2055 map<int, class BoundaryPointSet *> OrderMap;
2056 pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
2057 for (int i = 0; i < 2; i++)
2058 // for both lines
2059 for (int j = 0; j < 2; j++)
2060 { // for both endpoints
2061 OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
2062 lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
2063 if (!OrderTest.second)
2064 { // if insertion fails, we have common endpoint
2065 node = OrderTest.first->second;
2066 cout << Verbose(5) << "Common endpoint of lines " << *line1
2067 << " and " << *line2 << " is: " << *node << "." << endl;
2068 j = 2;
2069 i = 2;
2070 break;
2071 }
2072 }
2073 return node;
2074};
2075
2076/** Finds the triangle that is closest to a given Vector \a *x.
2077 * \param *out output stream for debugging
2078 * \param *x Vector to look from
2079 * \return list of BoundaryTriangleSet of nearest triangles or NULL in degenerate case.
2080 */
2081list<BoundaryTriangleSet*> * Tesselation::FindClosestTrianglesToPoint(ofstream *out, Vector *x, LinkedCell* LC)
2082{
2083 TesselPoint *trianglePoints[3];
2084 TesselPoint *SecondPoint = NULL;
2085
2086 if (LinesOnBoundary.empty()) {
2087 *out << Verbose(0) << "Error: There is no tesselation structure to compare the point with, please create one first.";
2088 return NULL;
2089 }
2090
2091 trianglePoints[0] = findClosestPoint(x, SecondPoint, LC);
2092
2093 // check whether closest point is "too close" :), then it's inside
2094 if (trianglePoints[0] == NULL) {
2095 *out << Verbose(1) << "Is the only point, no one else is closeby." << endl;
2096 return NULL;
2097 }
2098 if (trianglePoints[0]->node->DistanceSquared(x) < MYEPSILON) {
2099 *out << Verbose(1) << "Point is right on a tesselation point, no nearest triangle." << endl;
2100 return NULL;
2101 }
2102 list<TesselPoint*> *connectedClosestPoints = getCircleOfConnectedPoints(out, trianglePoints[0], x);
2103 trianglePoints[1] = connectedClosestPoints->front();
2104 trianglePoints[2] = connectedClosestPoints->back();
2105 for (int i=0;i<3;i++) {
2106 if (trianglePoints[i] == NULL) {
2107 *out << Verbose(1) << "IsInnerPoint encounters serious error, point " << i << " not found." << endl;
2108 }
2109 //*out << Verbose(1) << "List of possible points:" << endl;
2110 //*out << Verbose(2) << *trianglePoints[i] << endl;
2111 }
2112
2113 list<BoundaryTriangleSet*> *triangles = FindTriangles(trianglePoints);
2114
2115 delete(connectedClosestPoints);
2116
2117 if (triangles->empty()) {
2118 *out << Verbose(0) << "Error: There is no nearest triangle. Please check the tesselation structure.";
2119 return NULL;
2120 } else
2121 return triangles;
2122};
2123
2124/** Finds closest triangle to a point.
2125 * This basically just takes care of the degenerate case, which is not handled in FindClosestTrianglesToPoint().
2126 * \param *out output stream for debugging
2127 * \param *x Vector to look from
2128 * \return list of BoundaryTriangleSet of nearest triangles or NULL.
2129 */
2130class BoundaryTriangleSet * Tesselation::FindClosestTriangleToPoint(ofstream *out, Vector *x, LinkedCell* LC)
2131{
2132 class BoundaryTriangleSet *result = NULL;
2133 list<BoundaryTriangleSet*> *triangles = FindClosestTrianglesToPoint(out, x, LC);
2134
2135 if (triangles == NULL)
2136 return NULL;
2137
2138 if (x->ScalarProduct(&triangles->front()->NormalVector) < 0)
2139 result = triangles->back();
2140 else
2141 result = triangles->front();
2142
2143 delete(triangles);
2144 return result;
2145};
2146
2147/** Checks whether the provided Vector is within the tesselation structure.
2148 *
2149 * @param point of which to check the position
2150 * @param *LC LinkedCell structure
2151 *
2152 * @return true if the point is inside the tesselation structure, false otherwise
2153 */
2154bool Tesselation::IsInnerPoint(ofstream *out, Vector Point, LinkedCell* LC)
2155{
2156 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, &Point, LC);
2157 if (result == NULL)
2158 return true;
2159 if (Point.ScalarProduct(&result->NormalVector) < 0)
2160 return true;
2161 else
2162 return false;
2163}
2164
2165/** Checks whether the provided TesselPoint is within the tesselation structure.
2166 *
2167 * @param *Point of which to check the position
2168 * @param *LC Linked Cell structure
2169 *
2170 * @return true if the point is inside the tesselation structure, false otherwise
2171 */
2172bool Tesselation::IsInnerPoint(ofstream *out, TesselPoint *Point, LinkedCell* LC)
2173{
2174 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, Point->node, LC);
2175 if (result == NULL)
2176 return true;
2177 if (Point->node->ScalarProduct(&result->NormalVector) < 0)
2178 return true;
2179 else
2180 return false;
2181}
2182
2183/** Gets all points connected to the provided point by triangulation lines.
2184 * Maps them down onto the plane designated by the axis \a *Point and \a *Reference. The center of all points
2185 * connected in the tesselation to \a *Point is mapped to spherical coordinates with the zero angle being given
2186 * by the mapped down \a *Reference. Hence, the biggest and the smallest angles are those of the two shanks of the
2187 * triangle we are looking for.
2188 *
2189 * @param *Point of which get all connected points
2190 * @param *Reference Vector to be checked whether it is an inner point
2191 *
2192 * @return list of the two points linked to the provided one and closest to the point to be checked,
2193 */
2194list<TesselPoint*> * Tesselation::getCircleOfConnectedPoints(ofstream *out, TesselPoint* Point, Vector* Reference)
2195{
2196 list<TesselPoint*> connectedPoints;
2197 map<double, TesselPoint*> anglesOfPoints;
2198 map<double, TesselPoint*>::iterator runner;
2199 list<TesselPoint*>::iterator listRunner;
2200 class BoundaryPointSet *ReferencePoint = NULL;
2201 Vector center, PlaneNormal, currentPoint, OrthogonalVector, helper, AngleZero;
2202 TesselPoint* current;
2203 bool takePoint = false;
2204
2205 // find the respective boundary point
2206 PointMap::iterator PointRunner = PointsOnBoundary.find(Point->nr);
2207 if (PointRunner != PointsOnBoundary.end()) {
2208 ReferencePoint = PointRunner->second;
2209 } else {
2210 *out << Verbose(2) << "getCircleOfConnectedPoints() could not find the BoundaryPoint belonging to " << *Point << "." << endl;
2211 ReferencePoint = NULL;
2212 }
2213
2214 // little trick so that we look just through lines connect to the BoundaryPoint
2215 // OR fall-back to look through all lines if there is no such BoundaryPoint
2216 LineMap *Lines = &LinesOnBoundary;
2217 if (ReferencePoint != NULL)
2218 Lines = &(ReferencePoint->lines);
2219 LineMap::iterator findLines = Lines->begin();
2220 while (findLines != Lines->end()) {
2221 takePoint = false;
2222
2223 if (findLines->second->endpoints[0]->Nr == Point->nr) {
2224 takePoint = true;
2225 current = findLines->second->endpoints[1]->node;
2226 } else if (findLines->second->endpoints[1]->Nr == Point->nr) {
2227 takePoint = true;
2228 current = findLines->second->endpoints[0]->node;
2229 }
2230
2231 if (takePoint) {
2232 *out << Verbose(3) << "INFO: Endpoint " << *current << " of line " << *(findLines->second) << " is taken into the circle." << endl;
2233 connectedPoints.push_back(current);
2234 currentPoint.CopyVector(current->node);
2235 currentPoint.ProjectOntoPlane(&PlaneNormal);
2236 center.AddVector(&currentPoint);
2237 }
2238
2239 findLines++;
2240 }
2241
2242 //*out << "Summed vectors " << center << "; number of points " << connectedPoints.size()
2243 // << "; scale factor " << 1.0/connectedPoints.size();
2244
2245 if (connectedPoints.size() == 0) { // if have not found any points
2246 *out << Verbose(1) << "ERROR: We have not found any connected points to " << *Point<< "." << endl;
2247 return NULL;
2248 }
2249 center.Scale(1.0/connectedPoints.size());
2250
2251 *out << Verbose(4) << "INFO: Calculated center of all circle points is " << center << "." << endl;
2252
2253 // projection plane of the circle is at the closes Point and normal is pointing away from center of all circle points
2254 PlaneNormal.CopyVector(Point->node);
2255 PlaneNormal.SubtractVector(&center);
2256 PlaneNormal.Normalize();
2257 *out << Verbose(4) << "INFO: Calculated plane normal of circle is " << PlaneNormal << "." << endl;
2258
2259 // construct one orthogonal vector
2260 AngleZero.CopyVector(Reference);
2261 AngleZero.SubtractVector(Point->node);
2262 AngleZero.ProjectOntoPlane(&PlaneNormal);
2263 *out << Verbose(4) << "INFO: Reference vector on this plane representing angle 0 is " << AngleZero << "." << endl;
2264 OrthogonalVector.MakeNormalVector(&PlaneNormal, &AngleZero);
2265 *out << Verbose(4) << "INFO: OrthogonalVector on plane is " << OrthogonalVector << "." << endl;
2266
2267 // go through all connected points and calculate angle
2268 listRunner = connectedPoints.begin();
2269 while (listRunner != connectedPoints.end()) {
2270 helper.CopyVector((*listRunner)->node);
2271 helper.SubtractVector(Point->node);
2272 helper.ProjectOntoPlane(&PlaneNormal);
2273 double angle = getAngle(helper, AngleZero, OrthogonalVector);
2274 *out << Verbose(2) << "INFO: Calculated angle is " << angle << " for point " << **listRunner << "." << endl;
2275 anglesOfPoints.insert(pair<double, TesselPoint*>(angle, (*listRunner)));
2276 listRunner++;
2277 }
2278
2279 list<TesselPoint*> *result = new list<TesselPoint*>;
2280 runner = anglesOfPoints.begin();
2281 result->push_back(runner->second);
2282 runner = anglesOfPoints.end();
2283 runner--;
2284 result->push_back(runner->second);
2285
2286 *out << Verbose(2) << "List of closest points has " << result->size() << " elements, which are "
2287 << *(result->front()) << " and " << *(result->back()) << endl;
2288
2289 return result;
2290}
2291
2292/** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
2293 * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
2294 * make it bigger (i.e. closing one (the baseline) and opening two new ones).
2295 * \param TPS[3] nodes of the triangle
2296 * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
2297 */
2298bool CheckLineCriteriaforDegeneratedTriangle(class BoundaryPointSet *nodes[3])
2299{
2300 bool result = false;
2301 int counter = 0;
2302
2303 // check all three points
2304 for (int i=0;i<3;i++)
2305 for (int j=i+1; j<3; j++) {
2306 if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) { // there already is a line
2307 LineMap::iterator FindLine;
2308 pair<LineMap::iterator,LineMap::iterator> FindPair;
2309 FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
2310 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
2311 // If there is a line with less than two attached triangles, we don't need a new line.
2312 if (FindLine->second->triangles.size() < 2) {
2313 counter++;
2314 break; // increase counter only once per edge
2315 }
2316 }
2317 } else { // no line
2318 cout << Verbose(1) << "The line between " << nodes[i] << " and " << nodes[j] << " is not yet present, hence no need for a degenerate triangle." << endl;
2319 result = true;
2320 }
2321 }
2322 if (counter > 1) {
2323 cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
2324 result = true;
2325 }
2326 return result;
2327};
2328
2329
2330/** Sort function for the candidate list.
2331 */
2332bool sortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2)
2333{
2334 Vector BaseLineVector, OrthogonalVector, helper;
2335 if (candidate1->BaseLine != candidate2->BaseLine) { // sanity check
2336 cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
2337 //return false;
2338 exit(1);
2339 }
2340 // create baseline vector
2341 BaseLineVector.CopyVector(candidate1->BaseLine->endpoints[1]->node->node);
2342 BaseLineVector.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2343 BaseLineVector.Normalize();
2344
2345 // 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!)
2346 helper.CopyVector(candidate1->BaseLine->endpoints[0]->node->node);
2347 helper.SubtractVector(candidate1->point->node);
2348 OrthogonalVector.CopyVector(&helper);
2349 helper.VectorProduct(&BaseLineVector);
2350 OrthogonalVector.SubtractVector(&helper);
2351 OrthogonalVector.Normalize();
2352
2353 // calculate both angles and correct with in-plane vector
2354 helper.CopyVector(candidate1->point->node);
2355 helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2356 double phi = BaseLineVector.Angle(&helper);
2357 if (OrthogonalVector.ScalarProduct(&helper) > 0) {
2358 phi = 2.*M_PI - phi;
2359 }
2360 helper.CopyVector(candidate2->point->node);
2361 helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
2362 double psi = BaseLineVector.Angle(&helper);
2363 if (OrthogonalVector.ScalarProduct(&helper) > 0) {
2364 psi = 2.*M_PI - psi;
2365 }
2366
2367 cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
2368 cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
2369
2370 // return comparison
2371 return phi < psi;
2372};
2373
2374/**
2375 * Finds the point which is second closest to the provided one.
2376 *
2377 * @param Point to which to find the second closest other point
2378 * @param linked cell structure
2379 *
2380 * @return point which is second closest to the provided one
2381 */
2382TesselPoint* findSecondClosestPoint(const Vector* Point, LinkedCell* LC)
2383{
2384 LinkedNodes *List = NULL;
2385 TesselPoint* closestPoint = NULL;
2386 TesselPoint* secondClosestPoint = NULL;
2387 double distance = 1e16;
2388 double secondDistance = 1e16;
2389 Vector helper;
2390 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2391
2392 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
2393 for(int i=0;i<NDIM;i++) // store indices of this cell
2394 N[i] = LC->n[i];
2395 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2396
2397 LC->GetNeighbourBounds(Nlower, Nupper);
2398 //cout << endl;
2399 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2400 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2401 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2402 List = LC->GetCurrentCell();
2403 cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
2404 if (List != NULL) {
2405 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2406 helper.CopyVector(Point);
2407 helper.SubtractVector((*Runner)->node);
2408 double currentNorm = helper. Norm();
2409 if (currentNorm < distance) {
2410 // remember second point
2411 secondDistance = distance;
2412 secondClosestPoint = closestPoint;
2413 // mark down new closest point
2414 distance = currentNorm;
2415 closestPoint = (*Runner);
2416 cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
2417 }
2418 }
2419 } else {
2420 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
2421 << LC->n[2] << " is invalid!" << endl;
2422 }
2423 }
2424
2425 return secondClosestPoint;
2426};
2427
2428
2429
2430/**
2431 * Finds the point which is closest to the provided one.
2432 *
2433 * @param Point to which to find the closest other point
2434 * @param SecondPoint the second closest other point on return, NULL if none found
2435 * @param linked cell structure
2436 *
2437 * @return point which is closest to the provided one, NULL if none found
2438 */
2439TesselPoint* findClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC)
2440{
2441 LinkedNodes *List = NULL;
2442 TesselPoint* closestPoint = NULL;
2443 SecondPoint = NULL;
2444 double distance = 1e16;
2445 double secondDistance = 1e16;
2446 Vector helper;
2447 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
2448
2449 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
2450 for(int i=0;i<NDIM;i++) // store indices of this cell
2451 N[i] = LC->n[i];
2452 cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
2453
2454 LC->GetNeighbourBounds(Nlower, Nupper);
2455 //cout << endl;
2456 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
2457 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
2458 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
2459 List = LC->GetCurrentCell();
2460 cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
2461 if (List != NULL) {
2462 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
2463 helper.CopyVector(Point);
2464 helper.SubtractVector((*Runner)->node);
2465 double currentNorm = helper. Norm();
2466 if (currentNorm < distance) {
2467 secondDistance = distance;
2468 SecondPoint = closestPoint;
2469 distance = currentNorm;
2470 closestPoint = (*Runner);
2471 cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
2472 } else if (currentNorm < secondDistance) {
2473 secondDistance = currentNorm;
2474 SecondPoint = (*Runner);
2475 cout << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
2476 }
2477 }
2478 } else {
2479 cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
2480 << LC->n[2] << " is invalid!" << endl;
2481 }
2482 }
2483
2484 return closestPoint;
2485};
2486
2487
2488/**
2489 * Finds triangles belonging to the three provided points.
2490 *
2491 * @param *Points[3] list, is expected to contain three points
2492 *
2493 * @return triangles which belong to the provided points, will be empty if there are none,
2494 * will usually be one, in case of degeneration, there will be two
2495 */
2496list<BoundaryTriangleSet*> *Tesselation::FindTriangles(TesselPoint* Points[3])
2497{
2498 list<BoundaryTriangleSet*> *result = new list<BoundaryTriangleSet*>;
2499 LineMap::iterator FindLine;
2500 PointMap::iterator FindPoint;
2501 TriangleMap::iterator FindTriangle;
2502 class BoundaryPointSet *TrianglePoints[3];
2503
2504 for (int i = 0; i < 3; i++) {
2505 FindPoint = PointsOnBoundary.find(Points[i]->nr);
2506 if (FindPoint != PointsOnBoundary.end()) {
2507 TrianglePoints[i] = FindPoint->second;
2508 } else {
2509 TrianglePoints[i] = NULL;
2510 }
2511 }
2512
2513 // checks lines between the points in the Points for their adjacent triangles
2514 for (int i = 0; i < 3; i++) {
2515 if (TrianglePoints[i] != NULL) {
2516 for (int j = i; j < 3; j++) {
2517 if (TrianglePoints[j] != NULL) {
2518 FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr);
2519 if (FindLine != TrianglePoints[i]->lines.end()) {
2520 for (; FindLine->first == TrianglePoints[j]->node->nr; FindLine++) {
2521 FindTriangle = FindLine->second->triangles.begin();
2522 for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
2523 if ((
2524 (FindTriangle->second->endpoints[0] == TrianglePoints[0])
2525 || (FindTriangle->second->endpoints[0] == TrianglePoints[1])
2526 || (FindTriangle->second->endpoints[0] == TrianglePoints[2])
2527 ) && (
2528 (FindTriangle->second->endpoints[1] == TrianglePoints[0])
2529 || (FindTriangle->second->endpoints[1] == TrianglePoints[1])
2530 || (FindTriangle->second->endpoints[1] == TrianglePoints[2])
2531 ) && (
2532 (FindTriangle->second->endpoints[2] == TrianglePoints[0])
2533 || (FindTriangle->second->endpoints[2] == TrianglePoints[1])
2534 || (FindTriangle->second->endpoints[2] == TrianglePoints[2])
2535 )
2536 ) {
2537 result->push_back(FindTriangle->second);
2538 }
2539 }
2540 }
2541 // Is it sufficient to consider one of the triangle lines for this.
2542 return result;
2543
2544 }
2545 }
2546 }
2547 }
2548 }
2549
2550 return result;
2551}
2552
2553/** Gets the angle between a point and a reference relative to the provided center.
2554 * We have two shanks point and reference between which the angle is calculated
2555 * and by scalar product with OrthogonalVector we decide the interval.
2556 * @param point to calculate the angle for
2557 * @param reference to which to calculate the angle
2558 * @param OrthogonalVector points in direction of [pi,2pi] interval
2559 *
2560 * @return angle between point and reference
2561 */
2562double getAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector)
2563{
2564 if (reference.IsNull())
2565 return M_PI;
2566
2567 // calculate both angles and correct with in-plane vector
2568 if (point.IsNull())
2569 return M_PI;
2570 double phi = point.Angle(&reference);
2571 if (OrthogonalVector.ScalarProduct(&point) > 0) {
2572 phi = 2.*M_PI - phi;
2573 }
2574
2575 cout << Verbose(3) << "INFO: " << point << " has angle " << phi << " with respect to reference " << reference << "." << endl;
2576
2577 return phi;
2578}
2579
Note: See TracBrowser for help on using the repository browser.