source: src/tesselation.cpp@ 5e8f82

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

The finding of the degenerated polygons' endpoints was not yet correct, fixed.

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