source: src/Tesselation/tesselation.cpp@ 32d7e4

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 32d7e4 was 32d7e4, checked in by Frederik Heber <heber@…>, 10 years ago

FIX: Tesselation::FlipBaseline() caclculated NormalVectors wrong.

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