source: src/Tesselation/tesselation.cpp@ be6b3a

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 be6b3a was 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

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