source: src/tesselationhelpers.cpp@ 04ef48

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 Candidate_v1.7.0 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 04ef48 was 04ef48, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Made the GetSphere() function use matrix objects

  • Property mode set to 100644
File size: 43.4 KB
Line 
1/*
2 * TesselationHelpers.cpp
3 *
4 * Created on: Aug 3, 2009
5 * Author: heber
6 */
7
8#include "Helpers/MemDebug.hpp"
9
10#include <fstream>
11
12#include "info.hpp"
13#include "linkedcell.hpp"
14#include "linearsystemofequations.hpp"
15#include "log.hpp"
16#include "tesselation.hpp"
17#include "tesselationhelpers.hpp"
18#include "vector.hpp"
19#include "Line.hpp"
20#include "vector_ops.hpp"
21#include "verbose.hpp"
22#include "Plane.hpp"
23#include "Matrix.hpp"
24
25double DetGet(gsl_matrix * const A, const int inPlace)
26{
27 Info FunctionInfo(__func__);
28 /*
29 inPlace = 1 => A is replaced with the LU decomposed copy.
30 inPlace = 0 => A is retained, and a copy is used for LU.
31 */
32
33 double det;
34 int signum;
35 gsl_permutation *p = gsl_permutation_alloc(A->size1);
36 gsl_matrix *tmpA=0;
37
38 if (inPlace)
39 tmpA = A;
40 else {
41 gsl_matrix *tmpA = gsl_matrix_alloc(A->size1, A->size2);
42 gsl_matrix_memcpy(tmpA , A);
43 }
44
45
46 gsl_linalg_LU_decomp(tmpA , p , &signum);
47 det = gsl_linalg_LU_det(tmpA , signum);
48 gsl_permutation_free(p);
49 if (! inPlace)
50 gsl_matrix_free(tmpA);
51
52 return det;
53};
54
55void GetSphere(Vector * const center, const Vector &a, const Vector &b, const Vector &c, const double RADIUS)
56{
57 Info FunctionInfo(__func__);
58 Matrix mat;
59 double m11, m12, m13, m14;
60
61 for(int i=0;i<3;i++) {
62 mat.set(i, 0, a[i]);
63 mat.set(i, 1, b[i]);
64 mat.set(i, 2, c[i]);
65 }
66 m11 = mat.determinant();
67
68 for(int i=0;i<3;i++) {
69 mat.set(i, 0, a[i]*a[i] + b[i]*b[i] + c[i]*c[i]);
70 mat.set(i, 1, b[i]);
71 mat.set(i, 2, c[i]);
72 }
73 m12 = mat.determinant();
74
75 for(int i=0;i<3;i++) {
76 mat.set(i, 0, a[i]*a[i] + b[i]*b[i] + c[i]*c[i]);
77 mat.set(i, 1, a[i]);
78 mat.set(i, 2, c[i]);
79 }
80 m13 = mat.determinant();
81
82 for(int i=0;i<3;i++) {
83 mat.set(i, 0, a[i]*a[i] + b[i]*b[i] + c[i]*c[i]);
84 mat.set(i, 1, a[i]);
85 mat.set(i, 2, b[i]);
86 }
87 m14 = mat.determinant();
88
89 if (fabs(m11) < MYEPSILON)
90 DoeLog(1) && (eLog()<< Verbose(1) << "three points are colinear." << endl);
91
92 center->at(0) = 0.5 * m12/ m11;
93 center->at(1) = -0.5 * m13/ m11;
94 center->at(2) = 0.5 * m14/ m11;
95
96 if (fabs(a.distance(*center) - RADIUS) > MYEPSILON)
97 DoeLog(1) && (eLog()<< Verbose(1) << "The given center is further way by " << fabs(a.distance(*center) - RADIUS) << " from a than RADIUS." << endl);
98};
99
100
101
102/**
103 * Function returns center of sphere with RADIUS, which rests on points a, b, c
104 * @param Center this vector will be used for return
105 * @param a vector first point of triangle
106 * @param b vector second point of triangle
107 * @param c vector third point of triangle
108 * @param *Umkreismittelpunkt new center point of circumference
109 * @param Direction vector indicates up/down
110 * @param AlternativeDirection Vector, needed in case the triangles have 90 deg angle
111 * @param Halfplaneindicator double indicates whether Direction is up or down
112 * @param AlternativeIndicator double indicates in case of orthogonal triangles which direction of AlternativeDirection is suitable
113 * @param alpha double angle at a
114 * @param beta double, angle at b
115 * @param gamma, double, angle at c
116 * @param Radius, double
117 * @param Umkreisradius double radius of circumscribing circle
118 */
119void GetCenterOfSphere(Vector* const & Center, const Vector &a, const Vector &b, const Vector &c, Vector * const NewUmkreismittelpunkt, const Vector* const Direction, const Vector* const AlternativeDirection,
120 const double HalfplaneIndicator, const double AlternativeIndicator, const double alpha, const double beta, const double gamma, const double RADIUS, const double Umkreisradius)
121{
122 Info FunctionInfo(__func__);
123 Vector TempNormal, helper;
124 double Restradius;
125 Vector OtherCenter;
126 Center->Zero();
127 helper = sin(2.*alpha) * a;
128 (*Center) += helper;
129 helper = sin(2.*beta) * b;
130 (*Center) += helper;
131 helper = sin(2.*gamma) * c;
132 (*Center) += helper;
133 //*Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ;
134 Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma)));
135 (*NewUmkreismittelpunkt) = (*Center);
136 DoLog(1) && (Log() << Verbose(1) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n");
137 // Here we calculated center of circumscribing circle, using barycentric coordinates
138 DoLog(1) && (Log() << Verbose(1) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n");
139
140 TempNormal = a - b;
141 helper = a - c;
142 TempNormal.VectorProduct(helper);
143 if (fabs(HalfplaneIndicator) < MYEPSILON)
144 {
145 if ((TempNormal.ScalarProduct(*AlternativeDirection) <0 && AlternativeIndicator >0) || (TempNormal.ScalarProduct(*AlternativeDirection) >0 && AlternativeIndicator <0))
146 {
147 TempNormal *= -1;
148 }
149 }
150 else
151 {
152 if (((TempNormal.ScalarProduct(*Direction)<0) && (HalfplaneIndicator >0)) || ((TempNormal.ScalarProduct(*Direction)>0) && (HalfplaneIndicator<0)))
153 {
154 TempNormal *= -1;
155 }
156 }
157
158 TempNormal.Normalize();
159 Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius);
160 DoLog(1) && (Log() << Verbose(1) << "Height of center of circumference to center of sphere is " << Restradius << ".\n");
161 TempNormal.Scale(Restradius);
162 DoLog(1) && (Log() << Verbose(1) << "Shift vector to sphere of circumference is " << TempNormal << ".\n");
163 (*Center) += TempNormal;
164 DoLog(1) && (Log() << Verbose(1) << "Center of sphere of circumference is " << *Center << ".\n");
165 GetSphere(&OtherCenter, a, b, c, RADIUS);
166 DoLog(1) && (Log() << Verbose(1) << "OtherCenter of sphere of circumference is " << OtherCenter << ".\n");
167};
168
169
170/** Constructs the center of the circumcircle defined by three points \a *a, \a *b and \a *c.
171 * \param *Center new center on return
172 * \param *a first point
173 * \param *b second point
174 * \param *c third point
175 */
176void GetCenterofCircumcircle(Vector * const Center, const Vector &a, const Vector &b, const Vector &c)
177{
178 Info FunctionInfo(__func__);
179 Vector helper;
180 Vector SideA = b - c;
181 Vector SideB = c - a;
182 Vector SideC = a - b;
183
184 helper[0] = SideA.NormSquared()*(SideB.NormSquared()+SideC.NormSquared() - SideA.NormSquared());
185 helper[1] = SideB.NormSquared()*(SideC.NormSquared()+SideA.NormSquared() - SideB.NormSquared());
186 helper[2] = SideC.NormSquared()*(SideA.NormSquared()+SideB.NormSquared() - SideC.NormSquared());
187
188 Center->Zero();
189 *Center += helper[0] * a;
190 *Center += helper[1] * b;
191 *Center += helper[2] * c;
192 Center->Scale(1./(helper[0]+helper[1]+helper[2]));
193 Log() << Verbose(1) << "INFO: Center (2nd algo) is at " << *Center << "." << endl;
194};
195
196/** Returns the parameter "path length" for a given \a NewSphereCenter relative to \a OldSphereCenter on a circle on the plane \a CirclePlaneNormal with center \a CircleCenter and radius \a CircleRadius.
197 * Test whether the \a NewSphereCenter is really on the given plane and in distance \a CircleRadius from \a CircleCenter.
198 * It calculates the angle, making it unique on [0,2.*M_PI) by comparing to SearchDirection.
199 * Also the new center is invalid if it the same as the old one and does not lie right above (\a NormalVector) the base line (\a CircleCenter).
200 * \param CircleCenter Center of the parameter circle
201 * \param CirclePlaneNormal normal vector to plane of the parameter circle
202 * \param CircleRadius radius of the parameter circle
203 * \param NewSphereCenter new center of a circumcircle
204 * \param OldSphereCenter old center of a circumcircle, defining the zero "path length" on the parameter circle
205 * \param NormalVector normal vector
206 * \param SearchDirection search direction to make angle unique on return.
207 * \return Angle between \a NewSphereCenter and \a OldSphereCenter relative to \a CircleCenter, 2.*M_PI if one test fails
208 */
209double GetPathLengthonCircumCircle(const Vector &CircleCenter, const Vector &CirclePlaneNormal, const double CircleRadius, const Vector &NewSphereCenter, const Vector &OldSphereCenter, const Vector &NormalVector, const Vector &SearchDirection)
210{
211 Info FunctionInfo(__func__);
212 Vector helper;
213 double radius, alpha;
214
215 Vector RelativeOldSphereCenter = OldSphereCenter - CircleCenter;
216 Vector RelativeNewSphereCenter = NewSphereCenter - CircleCenter;
217 helper = RelativeNewSphereCenter;
218 // test whether new center is on the parameter circle's plane
219 if (fabs(helper.ScalarProduct(CirclePlaneNormal)) > HULLEPSILON) {
220 DoeLog(1) && (eLog()<< Verbose(1) << "Something's very wrong here: NewSphereCenter is not on the band's plane as desired by " <<fabs(helper.ScalarProduct(CirclePlaneNormal)) << "!" << endl);
221 helper.ProjectOntoPlane(CirclePlaneNormal);
222 }
223 radius = helper.NormSquared();
224 // test whether the new center vector has length of CircleRadius
225 if (fabs(radius - CircleRadius) > HULLEPSILON)
226 DoeLog(1) && (eLog()<< Verbose(1) << "The projected center of the new sphere has radius " << radius << " instead of " << CircleRadius << "." << endl);
227 alpha = helper.Angle(RelativeOldSphereCenter);
228 // make the angle unique by checking the halfplanes/search direction
229 if (helper.ScalarProduct(SearchDirection) < -HULLEPSILON) // acos is not unique on [0, 2.*M_PI), hence extra check to decide between two half intervals
230 alpha = 2.*M_PI - alpha;
231 DoLog(1) && (Log() << Verbose(1) << "INFO: RelativeNewSphereCenter is " << helper << ", RelativeOldSphereCenter is " << RelativeOldSphereCenter << " and resulting angle is " << alpha << "." << endl);
232 radius = helper.distance(RelativeOldSphereCenter);
233 helper.ProjectOntoPlane(NormalVector);
234 // check whether new center is somewhat away or at least right over the current baseline to prevent intersecting triangles
235 if ((radius > HULLEPSILON) || (helper.Norm() < HULLEPSILON)) {
236 DoLog(1) && (Log() << Verbose(1) << "INFO: Distance between old and new center is " << radius << " and between new center and baseline center is " << helper.Norm() << "." << endl);
237 return alpha;
238 } else {
239 DoLog(1) && (Log() << Verbose(1) << "INFO: NewSphereCenter " << RelativeNewSphereCenter << " is too close to RelativeOldSphereCenter" << RelativeOldSphereCenter << "." << endl);
240 return 2.*M_PI;
241 }
242};
243
244struct Intersection {
245 Vector x1;
246 Vector x2;
247 Vector x3;
248 Vector x4;
249};
250
251/**
252 * Intersection calculation function.
253 *
254 * @param x to find the result for
255 * @param function parameter
256 */
257double MinIntersectDistance(const gsl_vector * x, void *params)
258{
259 Info FunctionInfo(__func__);
260 double retval = 0;
261 struct Intersection *I = (struct Intersection *)params;
262 Vector intersection;
263 for (int i=0;i<NDIM;i++)
264 intersection[i] = gsl_vector_get(x, i);
265
266 Vector SideA = I->x1 -I->x2 ;
267 Vector HeightA = intersection - I->x1;
268 HeightA.ProjectOntoPlane(SideA);
269
270 Vector SideB = I->x3 - I->x4;
271 Vector HeightB = intersection - I->x3;
272 HeightB.ProjectOntoPlane(SideB);
273
274 retval = HeightA.ScalarProduct(HeightA) + HeightB.ScalarProduct(HeightB);
275 //Log() << Verbose(1) << "MinIntersectDistance called, result: " << retval << endl;
276
277 return retval;
278};
279
280
281/**
282 * Calculates whether there is an intersection between two lines. The first line
283 * always goes through point 1 and point 2 and the second line is given by the
284 * connection between point 4 and point 5.
285 *
286 * @param point 1 of line 1
287 * @param point 2 of line 1
288 * @param point 1 of line 2
289 * @param point 2 of line 2
290 *
291 * @return true if there is an intersection between the given lines, false otherwise
292 */
293bool existsIntersection(const Vector &point1, const Vector &point2, const Vector &point3, const Vector &point4)
294{
295 Info FunctionInfo(__func__);
296 bool result;
297
298 struct Intersection par;
299 par.x1 = point1;
300 par.x2 = point2;
301 par.x3 = point3;
302 par.x4 = point4;
303
304 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
305 gsl_multimin_fminimizer *s = NULL;
306 gsl_vector *ss, *x;
307 gsl_multimin_function minexFunction;
308
309 size_t iter = 0;
310 int status;
311 double size;
312
313 /* Starting point */
314 x = gsl_vector_alloc(NDIM);
315 gsl_vector_set(x, 0, point1[0]);
316 gsl_vector_set(x, 1, point1[1]);
317 gsl_vector_set(x, 2, point1[2]);
318
319 /* Set initial step sizes to 1 */
320 ss = gsl_vector_alloc(NDIM);
321 gsl_vector_set_all(ss, 1.0);
322
323 /* Initialize method and iterate */
324 minexFunction.n = NDIM;
325 minexFunction.f = &MinIntersectDistance;
326 minexFunction.params = (void *)&par;
327
328 s = gsl_multimin_fminimizer_alloc(T, NDIM);
329 gsl_multimin_fminimizer_set(s, &minexFunction, x, ss);
330
331 do {
332 iter++;
333 status = gsl_multimin_fminimizer_iterate(s);
334
335 if (status) {
336 break;
337 }
338
339 size = gsl_multimin_fminimizer_size(s);
340 status = gsl_multimin_test_size(size, 1e-2);
341
342 if (status == GSL_SUCCESS) {
343 DoLog(1) && (Log() << Verbose(1) << "converged to minimum" << endl);
344 }
345 } while (status == GSL_CONTINUE && iter < 100);
346
347 // check whether intersection is in between or not
348 Vector intersection;
349 double t1, t2;
350 for (int i = 0; i < NDIM; i++) {
351 intersection[i] = gsl_vector_get(s->x, i);
352 }
353
354 Vector SideA = par.x2 - par.x1;
355 Vector HeightA = intersection - par.x1;
356
357 t1 = HeightA.ScalarProduct(SideA)/SideA.ScalarProduct(SideA);
358
359 Vector SideB = par.x4 - par.x3;
360 Vector HeightB = intersection - par.x3;
361
362 t2 = HeightB.ScalarProduct(SideB)/SideB.ScalarProduct(SideB);
363
364 Log() << Verbose(1) << "Intersection " << intersection << " is at "
365 << t1 << " for (" << point1 << "," << point2 << ") and at "
366 << t2 << " for (" << point3 << "," << point4 << "): ";
367
368 if (((t1 >= 0) && (t1 <= 1)) && ((t2 >= 0) && (t2 <= 1))) {
369 DoLog(1) && (Log() << Verbose(1) << "true intersection." << endl);
370 result = true;
371 } else {
372 DoLog(1) && (Log() << Verbose(1) << "intersection out of region of interest." << endl);
373 result = false;
374 }
375
376 // free minimizer stuff
377 gsl_vector_free(x);
378 gsl_vector_free(ss);
379 gsl_multimin_fminimizer_free(s);
380
381 return result;
382};
383
384/** Gets the angle between a point and a reference relative to the provided center.
385 * We have two shanks point and reference between which the angle is calculated
386 * and by scalar product with OrthogonalVector we decide the interval.
387 * @param point to calculate the angle for
388 * @param reference to which to calculate the angle
389 * @param OrthogonalVector points in direction of [pi,2pi] interval
390 *
391 * @return angle between point and reference
392 */
393double GetAngle(const Vector &point, const Vector &reference, const Vector &OrthogonalVector)
394{
395 Info FunctionInfo(__func__);
396 if (reference.IsZero())
397 return M_PI;
398
399 // calculate both angles and correct with in-plane vector
400 if (point.IsZero())
401 return M_PI;
402 double phi = point.Angle(reference);
403 if (OrthogonalVector.ScalarProduct(point) > 0) {
404 phi = 2.*M_PI - phi;
405 }
406
407 DoLog(1) && (Log() << Verbose(1) << "INFO: " << point << " has angle " << phi << " with respect to reference " << reference << "." << endl);
408
409 return phi;
410}
411
412
413/** Calculates the volume of a general tetraeder.
414 * \param *a first vector
415 * \param *b second vector
416 * \param *c third vector
417 * \param *d fourth vector
418 * \return \f$ \frac{1}{6} \cdot ((a-d) \times (a-c) \cdot (a-b)) \f$
419 */
420double CalculateVolumeofGeneralTetraeder(const Vector &a, const Vector &b, const Vector &c, const Vector &d)
421{
422 Info FunctionInfo(__func__);
423 Vector Point, TetraederVector[3];
424 double volume;
425
426 TetraederVector[0] = a;
427 TetraederVector[1] = b;
428 TetraederVector[2] = c;
429 for (int j=0;j<3;j++)
430 TetraederVector[j].SubtractVector(d);
431 Point = TetraederVector[0];
432 Point.VectorProduct(TetraederVector[1]);
433 volume = 1./6. * fabs(Point.ScalarProduct(TetraederVector[2]));
434 return volume;
435};
436
437/** Calculates the area of a general triangle.
438 * We use the Heron's formula of area, [Bronstein, S. 138]
439 * \param &A first vector
440 * \param &B second vector
441 * \param &C third vector
442 * \return \f$ \frac{1}{6} \cdot ((a-d) \times (a-c) \cdot (a-b)) \f$
443 */
444double CalculateAreaofGeneralTriangle(const Vector &A, const Vector &B, const Vector &C)
445{
446 Info FunctionInfo(__func__);
447
448 const double sidea = B.distance(C);
449 const double sideb = A.distance(C);
450 const double sidec = A.distance(B);
451 const double s = (sidea+sideb+sidec)/2.;
452
453 const double area = sqrt(s*(s-sidea)*(s-sideb)*(s-sidec));
454 return area;
455};
456
457
458/** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
459 * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
460 * make it bigger (i.e. closing one (the baseline) and opening two new ones).
461 * \param TPS[3] nodes of the triangle
462 * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
463 */
464bool CheckLineCriteriaForDegeneratedTriangle(const BoundaryPointSet * const nodes[3])
465{
466 Info FunctionInfo(__func__);
467 bool result = false;
468 int counter = 0;
469
470 // check all three points
471 for (int i=0;i<3;i++)
472 for (int j=i+1; j<3; j++) {
473 if (nodes[i] == NULL) {
474 DoLog(1) && (Log() << Verbose(1) << "Node nr. " << i << " is not yet present." << endl);
475 result = true;
476 } else if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) { // there already is a line
477 LineMap::const_iterator FindLine;
478 pair<LineMap::const_iterator,LineMap::const_iterator> FindPair;
479 FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
480 for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
481 // If there is a line with less than two attached triangles, we don't need a new line.
482 if (FindLine->second->triangles.size() < 2) {
483 counter++;
484 break; // increase counter only once per edge
485 }
486 }
487 } else { // no line
488 DoLog(1) && (Log() << Verbose(1) << "The line between " << *nodes[i] << " and " << *nodes[j] << " is not yet present, hence no need for a degenerate triangle." << endl);
489 result = true;
490 }
491 }
492 if ((!result) && (counter > 1)) {
493 DoLog(1) && (Log() << Verbose(1) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl);
494 result = true;
495 }
496 return result;
497};
498
499
500///** Sort function for the candidate list.
501// */
502//bool SortCandidates(const CandidateForTesselation* candidate1, const CandidateForTesselation* candidate2)
503//{
504// Info FunctionInfo(__func__);
505// Vector BaseLineVector, OrthogonalVector, helper;
506// if (candidate1->BaseLine != candidate2->BaseLine) { // sanity check
507// DoeLog(1) && (eLog()<< Verbose(1) << "sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl);
508// //return false;
509// exit(1);
510// }
511// // create baseline vector
512// BaseLineVector.CopyVector(candidate1->BaseLine->endpoints[1]->node->node);
513// BaseLineVector.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
514// BaseLineVector.Normalize();
515//
516// // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!)
517// helper.CopyVector(candidate1->BaseLine->endpoints[0]->node->node);
518// helper.SubtractVector(candidate1->point->node);
519// OrthogonalVector.CopyVector(&helper);
520// helper.VectorProduct(&BaseLineVector);
521// OrthogonalVector.SubtractVector(&helper);
522// OrthogonalVector.Normalize();
523//
524// // calculate both angles and correct with in-plane vector
525// helper.CopyVector(candidate1->point->node);
526// helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
527// double phi = BaseLineVector.Angle(&helper);
528// if (OrthogonalVector.ScalarProduct(&helper) > 0) {
529// phi = 2.*M_PI - phi;
530// }
531// helper.CopyVector(candidate2->point->node);
532// helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
533// double psi = BaseLineVector.Angle(&helper);
534// if (OrthogonalVector.ScalarProduct(&helper) > 0) {
535// psi = 2.*M_PI - psi;
536// }
537//
538// Log() << Verbose(1) << *candidate1->point << " has angle " << phi << endl;
539// Log() << Verbose(1) << *candidate2->point << " has angle " << psi << endl;
540//
541// // return comparison
542// return phi < psi;
543//};
544
545/**
546 * Finds the point which is second closest to the provided one.
547 *
548 * @param Point to which to find the second closest other point
549 * @param linked cell structure
550 *
551 * @return point which is second closest to the provided one
552 */
553TesselPoint* FindSecondClosestTesselPoint(const Vector* Point, const LinkedCell* const LC)
554{
555 Info FunctionInfo(__func__);
556 TesselPoint* closestPoint = NULL;
557 TesselPoint* secondClosestPoint = NULL;
558 double distance = 1e16;
559 double secondDistance = 1e16;
560 Vector helper;
561 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
562
563 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
564 for(int i=0;i<NDIM;i++) // store indices of this cell
565 N[i] = LC->n[i];
566 DoLog(1) && (Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl);
567
568 LC->GetNeighbourBounds(Nlower, Nupper);
569 //Log() << Verbose(1) << endl;
570 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
571 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
572 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
573 const LinkedCell::LinkedNodes *List = LC->GetCurrentCell();
574 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
575 if (List != NULL) {
576 for (LinkedCell::LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
577 helper = (*Point) - (*(*Runner)->node);
578 double currentNorm = helper. Norm();
579 if (currentNorm < distance) {
580 // remember second point
581 secondDistance = distance;
582 secondClosestPoint = closestPoint;
583 // mark down new closest point
584 distance = currentNorm;
585 closestPoint = (*Runner);
586 //Log() << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *secondClosestPoint << "." << endl;
587 }
588 }
589 } else {
590 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << ","
591 << LC->n[2] << " is invalid!" << endl;
592 }
593 }
594
595 return secondClosestPoint;
596};
597
598/**
599 * Finds the point which is closest to the provided one.
600 *
601 * @param Point to which to find the closest other point
602 * @param SecondPoint the second closest other point on return, NULL if none found
603 * @param linked cell structure
604 *
605 * @return point which is closest to the provided one, NULL if none found
606 */
607TesselPoint* FindClosestTesselPoint(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC)
608{
609 Info FunctionInfo(__func__);
610 TesselPoint* closestPoint = NULL;
611 SecondPoint = NULL;
612 double distance = 1e16;
613 double secondDistance = 1e16;
614 Vector helper;
615 int N[NDIM], Nlower[NDIM], Nupper[NDIM];
616
617 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
618 for(int i=0;i<NDIM;i++) // store indices of this cell
619 N[i] = LC->n[i];
620 DoLog(1) && (Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl);
621
622 LC->GetNeighbourBounds(Nlower, Nupper);
623 //Log() << Verbose(1) << endl;
624 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
625 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
626 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
627 const LinkedCell::LinkedNodes *List = LC->GetCurrentCell();
628 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
629 if (List != NULL) {
630 for (LinkedCell::LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
631 helper = (*Point) - (*(*Runner)->node);
632 double currentNorm = helper.NormSquared();
633 if (currentNorm < distance) {
634 secondDistance = distance;
635 SecondPoint = closestPoint;
636 distance = currentNorm;
637 closestPoint = (*Runner);
638 //Log() << Verbose(1) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
639 } else if (currentNorm < secondDistance) {
640 secondDistance = currentNorm;
641 SecondPoint = (*Runner);
642 //Log() << Verbose(1) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
643 }
644 }
645 } else {
646 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << ","
647 << LC->n[2] << " is invalid!" << endl;
648 }
649 }
650 // output
651 if (closestPoint != NULL) {
652 DoLog(1) && (Log() << Verbose(1) << "Closest point is " << *closestPoint);
653 if (SecondPoint != NULL)
654 DoLog(0) && (Log() << Verbose(0) << " and second closest is " << *SecondPoint);
655 DoLog(0) && (Log() << Verbose(0) << "." << endl);
656 }
657 return closestPoint;
658};
659
660/** Returns the closest point on \a *Base with respect to \a *OtherBase.
661 * \param *out output stream for debugging
662 * \param *Base reference line
663 * \param *OtherBase other base line
664 * \return Vector on reference line that has closest distance
665 */
666Vector * GetClosestPointBetweenLine(const BoundaryLineSet * const Base, const BoundaryLineSet * const OtherBase)
667{
668 Info FunctionInfo(__func__);
669 // construct the plane of the two baselines (i.e. take both their directional vectors)
670 Vector Baseline = (*Base->endpoints[1]->node->node) - (*Base->endpoints[0]->node->node);
671 Vector OtherBaseline = (*OtherBase->endpoints[1]->node->node) - (*OtherBase->endpoints[0]->node->node);
672 Vector Normal = Baseline;
673 Normal.VectorProduct(OtherBaseline);
674 Normal.Normalize();
675 DoLog(1) && (Log() << Verbose(1) << "First direction is " << Baseline << ", second direction is " << OtherBaseline << ", normal of intersection plane is " << Normal << "." << endl);
676
677 // project one offset point of OtherBase onto this plane (and add plane offset vector)
678 Vector NewOffset = (*OtherBase->endpoints[0]->node->node) - (*Base->endpoints[0]->node->node);
679 NewOffset.ProjectOntoPlane(Normal);
680 NewOffset += (*Base->endpoints[0]->node->node);
681 Vector NewDirection = NewOffset + OtherBaseline;
682
683 // calculate the intersection between this projected baseline and Base
684 Vector *Intersection = new Vector;
685 Line line1 = makeLineThrough(*(Base->endpoints[0]->node->node),*(Base->endpoints[1]->node->node));
686 Line line2 = makeLineThrough(NewOffset, NewDirection);
687 *Intersection = line1.getIntersection(line2);
688 Normal = (*Intersection) - (*Base->endpoints[0]->node->node);
689 DoLog(1) && (Log() << Verbose(1) << "Found closest point on " << *Base << " at " << *Intersection << ", factor in line is " << fabs(Normal.ScalarProduct(Baseline)/Baseline.NormSquared()) << "." << endl);
690
691 return Intersection;
692};
693
694/** Returns the distance to the plane defined by \a *triangle
695 * \param *out output stream for debugging
696 * \param *x Vector to calculate distance to
697 * \param *triangle triangle defining plane
698 * \return distance between \a *x and plane defined by \a *triangle, -1 - if something went wrong
699 */
700double DistanceToTrianglePlane(const Vector *x, const BoundaryTriangleSet * const triangle)
701{
702 Info FunctionInfo(__func__);
703 double distance = 0.;
704 if (x == NULL) {
705 return -1;
706 }
707 distance = x->DistanceToSpace(triangle->getPlane());
708 return distance;
709};
710
711/** Creates the objects in a VRML file.
712 * \param *out output stream for debugging
713 * \param *vrmlfile output stream for tecplot data
714 * \param *Tess Tesselation structure with constructed triangles
715 * \param *mol molecule structure with atom positions
716 */
717void WriteVrmlFile(ofstream * const vrmlfile, const Tesselation * const Tess, const PointCloud * const cloud)
718{
719 Info FunctionInfo(__func__);
720 TesselPoint *Walker = NULL;
721 int i;
722 Vector *center = cloud->GetCenter();
723 if (vrmlfile != NULL) {
724 //Log() << Verbose(1) << "Writing Raster3D file ... ";
725 *vrmlfile << "#VRML V2.0 utf8" << endl;
726 *vrmlfile << "#Created by molecuilder" << endl;
727 *vrmlfile << "#All atoms as spheres" << endl;
728 cloud->GoToFirst();
729 while (!cloud->IsEnd()) {
730 Walker = cloud->GetPoint();
731 *vrmlfile << "Sphere {" << endl << " "; // 2 is sphere type
732 for (i=0;i<NDIM;i++)
733 *vrmlfile << Walker->node->at(i)-center->at(i) << " ";
734 *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
735 cloud->GoToNext();
736 }
737
738 *vrmlfile << "# All tesselation triangles" << endl;
739 for (TriangleMap::const_iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
740 *vrmlfile << "1" << endl << " "; // 1 is triangle type
741 for (i=0;i<3;i++) { // print each node
742 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
743 *vrmlfile << TriangleRunner->second->endpoints[i]->node->node->at(j)-center->at(j) << " ";
744 *vrmlfile << "\t";
745 }
746 *vrmlfile << "1. 0. 0." << endl; // red as colour
747 *vrmlfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
748 }
749 } else {
750 DoeLog(1) && (eLog()<< Verbose(1) << "Given vrmlfile is " << vrmlfile << "." << endl);
751 }
752 delete(center);
753};
754
755/** Writes additionally the current sphere (i.e. the last triangle to file).
756 * \param *out output stream for debugging
757 * \param *rasterfile output stream for tecplot data
758 * \param *Tess Tesselation structure with constructed triangles
759 * \param *mol molecule structure with atom positions
760 */
761void IncludeSphereinRaster3D(ofstream * const rasterfile, const Tesselation * const Tess, const PointCloud * const cloud)
762{
763 Info FunctionInfo(__func__);
764 Vector helper;
765
766 if (Tess->LastTriangle != NULL) {
767 // include the current position of the virtual sphere in the temporary raster3d file
768 Vector *center = cloud->GetCenter();
769 // make the circumsphere's center absolute again
770 Vector helper = (1./3.) * ((*Tess->LastTriangle->endpoints[0]->node->node) +
771 (*Tess->LastTriangle->endpoints[1]->node->node) +
772 (*Tess->LastTriangle->endpoints[2]->node->node));
773 helper -= (*center);
774 // and add to file plus translucency object
775 *rasterfile << "# current virtual sphere\n";
776 *rasterfile << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
777 *rasterfile << "2\n " << helper[0] << " " << helper[1] << " " << helper[2] << "\t" << 5. << "\t1 0 0\n";
778 *rasterfile << "9\n terminating special property\n";
779 delete(center);
780 }
781};
782
783/** Creates the objects in a raster3d file (renderable with a header.r3d).
784 * \param *out output stream for debugging
785 * \param *rasterfile output stream for tecplot data
786 * \param *Tess Tesselation structure with constructed triangles
787 * \param *mol molecule structure with atom positions
788 */
789void WriteRaster3dFile(ofstream * const rasterfile, const Tesselation * const Tess, const PointCloud * const cloud)
790{
791 Info FunctionInfo(__func__);
792 TesselPoint *Walker = NULL;
793 int i;
794 Vector *center = cloud->GetCenter();
795 if (rasterfile != NULL) {
796 //Log() << Verbose(1) << "Writing Raster3D file ... ";
797 *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl;
798 *rasterfile << "@header.r3d" << endl;
799 *rasterfile << "# All atoms as spheres" << endl;
800 cloud->GoToFirst();
801 while (!cloud->IsEnd()) {
802 Walker = cloud->GetPoint();
803 *rasterfile << "2" << endl << " "; // 2 is sphere type
804 for (int j=0;j<NDIM;j++) { // and for each node all NDIM coordinates
805 const double tmp = Walker->node->at(j)-center->at(j);
806 *rasterfile << ((fabs(tmp) < MYEPSILON) ? 0 : tmp) << " ";
807 }
808 *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
809 cloud->GoToNext();
810 }
811
812 *rasterfile << "# All tesselation triangles" << endl;
813 *rasterfile << "8\n 25. -1. 1. 1. 1. 0.0 0 0 0 2\n SOLID 1.0 0.0 0.0\n BACKFACE 0.3 0.3 1.0 0 0\n";
814 for (TriangleMap::const_iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
815 *rasterfile << "1" << endl << " "; // 1 is triangle type
816 for (i=0;i<3;i++) { // print each node
817 for (int j=0;j<NDIM;j++) { // and for each node all NDIM coordinates
818 const double tmp = TriangleRunner->second->endpoints[i]->node->node->at(j)-center->at(j);
819 *rasterfile << ((fabs(tmp) < MYEPSILON) ? 0 : tmp) << " ";
820 }
821 *rasterfile << "\t";
822 }
823 *rasterfile << "1. 0. 0." << endl; // red as colour
824 //*rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
825 }
826 *rasterfile << "9\n# terminating special property\n";
827 } else {
828 DoeLog(1) && (eLog()<< Verbose(1) << "Given rasterfile is " << rasterfile << "." << endl);
829 }
830 IncludeSphereinRaster3D(rasterfile, Tess, cloud);
831 delete(center);
832};
833
834/** This function creates the tecplot file, displaying the tesselation of the hull.
835 * \param *out output stream for debugging
836 * \param *tecplot output stream for tecplot data
837 * \param N arbitrary number to differentiate various zones in the tecplot format
838 */
839void WriteTecplotFile(ofstream * const tecplot, const Tesselation * const TesselStruct, const PointCloud * const cloud, const int N)
840{
841 Info FunctionInfo(__func__);
842 if ((tecplot != NULL) && (TesselStruct != NULL)) {
843 // write header
844 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
845 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\" \"U\"" << endl;
846 *tecplot << "ZONE T=\"";
847 if (N < 0) {
848 *tecplot << cloud->GetName();
849 } else {
850 *tecplot << N << "-";
851 if (TesselStruct->LastTriangle != NULL) {
852 for (int i=0;i<3;i++)
853 *tecplot << (i==0 ? "" : "_") << TesselStruct->LastTriangle->endpoints[i]->node->getName();
854 } else {
855 *tecplot << "none";
856 }
857 }
858 *tecplot << "\", N=" << TesselStruct->PointsOnBoundary.size() << ", E=" << TesselStruct->TrianglesOnBoundary.size() << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
859 const int MaxId=cloud->GetMaxId();
860 int *LookupList = new int[MaxId];
861 for (int i=0; i< MaxId ; i++){
862 LookupList[i] = -1;
863 }
864
865 // print atom coordinates
866 int Counter = 1;
867 TesselPoint *Walker = NULL;
868 for (PointMap::const_iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); ++target) {
869 Walker = target->second->node;
870 LookupList[Walker->nr] = Counter++;
871 for (int i=0;i<NDIM;i++) {
872 const double tmp = Walker->node->at(i);
873 *tecplot << ((fabs(tmp) < MYEPSILON) ? 0 : tmp) << " ";
874 }
875 *tecplot << target->second->value << endl;
876 }
877 *tecplot << endl;
878 // print connectivity
879 DoLog(1) && (Log() << Verbose(1) << "The following triangles were created:" << endl);
880 for (TriangleMap::const_iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
881 DoLog(1) && (Log() << Verbose(1) << " " << runner->second->endpoints[0]->node->getName() << "<->" << runner->second->endpoints[1]->node->getName() << "<->" << runner->second->endpoints[2]->node->getName() << endl);
882 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
883 }
884 delete[] (LookupList);
885 }
886};
887
888/** Calculates the concavity for each of the BoundaryPointSet's in a Tesselation.
889 * Sets BoundaryPointSet::value equal to the number of connected lines that are not convex.
890 * \param *out output stream for debugging
891 * \param *TesselStruct pointer to Tesselation structure
892 */
893void CalculateConcavityPerBoundaryPoint(const Tesselation * const TesselStruct)
894{
895 Info FunctionInfo(__func__);
896 class BoundaryPointSet *point = NULL;
897 class BoundaryLineSet *line = NULL;
898 class BoundaryTriangleSet *triangle = NULL;
899 double ConcavityPerLine = 0.;
900 double ConcavityPerTriangle = 0.;
901 double area = 0.;
902 double totalarea = 0.;
903
904 for (PointMap::const_iterator PointRunner = TesselStruct->PointsOnBoundary.begin(); PointRunner != TesselStruct->PointsOnBoundary.end(); PointRunner++) {
905 point = PointRunner->second;
906 DoLog(1) && (Log() << Verbose(1) << "INFO: Current point is " << *point << "." << endl);
907
908 // calculate mean concavity over all connected line
909 ConcavityPerLine = 0.;
910 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
911 line = LineRunner->second;
912 //Log() << Verbose(1) << "INFO: Current line of point " << *point << " is " << *line << "." << endl;
913 ConcavityPerLine -= line->CalculateConvexity();
914 }
915 ConcavityPerLine /= point->lines.size();
916
917 // weigh with total area of the surrounding triangles
918 totalarea = 0.;
919 TriangleSet *triangles = TesselStruct->GetAllTriangles(PointRunner->second);
920 for (TriangleSet::iterator TriangleRunner = triangles->begin(); TriangleRunner != triangles->end(); ++TriangleRunner) {
921 totalarea += CalculateAreaofGeneralTriangle(*(*TriangleRunner)->endpoints[0]->node->node, *(*TriangleRunner)->endpoints[1]->node->node, *(*TriangleRunner)->endpoints[2]->node->node);
922 }
923 ConcavityPerLine *= totalarea;
924
925 // calculate mean concavity over all attached triangles
926 ConcavityPerTriangle = 0.;
927 for (TriangleSet::const_iterator TriangleRunner = triangles->begin(); TriangleRunner != triangles->end(); ++TriangleRunner) {
928 line = (*TriangleRunner)->GetThirdLine(PointRunner->second);
929 triangle = line->GetOtherTriangle(*TriangleRunner);
930 area = CalculateAreaofGeneralTriangle(*triangle->endpoints[0]->node->node, *triangle->endpoints[1]->node->node, *triangle->endpoints[2]->node->node);
931 area += CalculateAreaofGeneralTriangle(*(*TriangleRunner)->endpoints[0]->node->node, *(*TriangleRunner)->endpoints[1]->node->node, *(*TriangleRunner)->endpoints[2]->node->node);
932 area *= -line->CalculateConvexity();
933 if (area > 0)
934 ConcavityPerTriangle += area;
935// else
936// ConcavityPerTriangle -= area;
937 }
938 ConcavityPerTriangle /= triangles->size()/totalarea;
939 delete(triangles);
940
941 // add up
942 point->value = ConcavityPerLine + ConcavityPerTriangle;
943 }
944};
945
946
947
948/** Calculates the concavity for each of the BoundaryPointSet's in a Tesselation.
949 * Sets BoundaryPointSet::value equal to the nearest distance to convex envelope.
950 * \param *out output stream for debugging
951 * \param *TesselStruct pointer to Tesselation structure
952 * \param *Convex pointer to convex Tesselation structure as reference
953 */
954void CalculateConstrictionPerBoundaryPoint(const Tesselation * const TesselStruct, const Tesselation * const Convex)
955{
956 Info FunctionInfo(__func__);
957 double distance = 0.;
958
959 for (PointMap::const_iterator PointRunner = TesselStruct->PointsOnBoundary.begin(); PointRunner != TesselStruct->PointsOnBoundary.end(); PointRunner++) {
960 DoeLog(1) && (eLog() << Verbose(1) << "INFO: Current point is " << * PointRunner->second << "." << endl);
961
962 distance = 0.;
963 for (TriangleMap::const_iterator TriangleRunner = Convex->TrianglesOnBoundary.begin(); TriangleRunner != Convex->TrianglesOnBoundary.end(); TriangleRunner++) {
964 const double CurrentDistance = Convex->GetDistanceSquaredToTriangle(*PointRunner->second->node->node, TriangleRunner->second);
965 if (CurrentDistance < distance)
966 distance = CurrentDistance;
967 }
968
969 PointRunner->second->value = distance;
970 }
971};
972
973/** Checks whether each BoundaryLineSet in the Tesselation has two triangles.
974 * \param *out output stream for debugging
975 * \param *TesselStruct
976 * \return true - all have exactly two triangles, false - some not, list is printed to screen
977 */
978bool CheckListOfBaselines(const Tesselation * const TesselStruct)
979{
980 Info FunctionInfo(__func__);
981 LineMap::const_iterator testline;
982 bool result = false;
983 int counter = 0;
984
985 DoLog(1) && (Log() << Verbose(1) << "Check: List of Baselines with not two connected triangles:" << endl);
986 for (testline = TesselStruct->LinesOnBoundary.begin(); testline != TesselStruct->LinesOnBoundary.end(); testline++) {
987 if (testline->second->triangles.size() != 2) {
988 DoLog(2) && (Log() << Verbose(2) << *testline->second << "\t" << testline->second->triangles.size() << endl);
989 counter++;
990 }
991 }
992 if (counter == 0) {
993 DoLog(1) && (Log() << Verbose(1) << "None." << endl);
994 result = true;
995 }
996 return result;
997}
998
999/** Counts the number of triangle pairs that contain the given polygon.
1000 * \param *P polygon with endpoints to look for
1001 * \param *T set of triangles to create pairs from containing \a *P
1002 */
1003int CountTrianglePairContainingPolygon(const BoundaryPolygonSet * const P, const TriangleSet * const T)
1004{
1005 Info FunctionInfo(__func__);
1006 // check number of endpoints in *P
1007 if (P->endpoints.size() != 4) {
1008 DoeLog(1) && (eLog()<< Verbose(1) << "CountTrianglePairContainingPolygon works only on polygons with 4 nodes!" << endl);
1009 return 0;
1010 }
1011
1012 // check number of triangles in *T
1013 if (T->size() < 2) {
1014 DoeLog(1) && (eLog()<< Verbose(1) << "Not enough triangles to have pairs!" << endl);
1015 return 0;
1016 }
1017
1018 DoLog(0) && (Log() << Verbose(0) << "Polygon is " << *P << endl);
1019 // create each pair, get the endpoints and check whether *P is contained.
1020 int counter = 0;
1021 PointSet Trianglenodes;
1022 class BoundaryPolygonSet PairTrianglenodes;
1023 for(TriangleSet::iterator Walker = T->begin(); Walker != T->end(); Walker++) {
1024 for (int i=0;i<3;i++)
1025 Trianglenodes.insert((*Walker)->endpoints[i]);
1026
1027 for(TriangleSet::iterator PairWalker = Walker; PairWalker != T->end(); PairWalker++) {
1028 if (Walker != PairWalker) { // skip first
1029 PairTrianglenodes.endpoints = Trianglenodes;
1030 for (int i=0;i<3;i++)
1031 PairTrianglenodes.endpoints.insert((*PairWalker)->endpoints[i]);
1032 const int size = PairTrianglenodes.endpoints.size();
1033 if (size == 4) {
1034 DoLog(0) && (Log() << Verbose(0) << " Current pair of triangles: " << **Walker << "," << **PairWalker << " with " << size << " distinct endpoints:" << PairTrianglenodes << endl);
1035 // now check
1036 if (PairTrianglenodes.ContainsPresentTupel(P)) {
1037 counter++;
1038 DoLog(0) && (Log() << Verbose(0) << " ACCEPT: Matches with " << *P << endl);
1039 } else {
1040 DoLog(0) && (Log() << Verbose(0) << " REJECT: No match with " << *P << endl);
1041 }
1042 } else {
1043 DoLog(0) && (Log() << Verbose(0) << " REJECT: Less than four endpoints." << endl);
1044 }
1045 }
1046 }
1047 Trianglenodes.clear();
1048 }
1049 return counter;
1050};
1051
1052/** Checks whether two give polygons have two or more points in common.
1053 * \param *P1 first polygon
1054 * \param *P2 second polygon
1055 * \return true - are connected, false = are note
1056 */
1057bool ArePolygonsEdgeConnected(const BoundaryPolygonSet * const P1, const BoundaryPolygonSet * const P2)
1058{
1059 Info FunctionInfo(__func__);
1060 int counter = 0;
1061 for(PointSet::const_iterator Runner = P1->endpoints.begin(); Runner != P1->endpoints.end(); Runner++) {
1062 if (P2->ContainsBoundaryPoint((*Runner))) {
1063 counter++;
1064 DoLog(1) && (Log() << Verbose(1) << *(*Runner) << " of second polygon is found in the first one." << endl);
1065 return true;
1066 }
1067 }
1068 return false;
1069};
1070
1071/** Combines second into the first and deletes the second.
1072 * \param *P1 first polygon, contains all nodes on return
1073 * \param *&P2 second polygon, is deleted.
1074 */
1075void CombinePolygons(BoundaryPolygonSet * const P1, BoundaryPolygonSet * &P2)
1076{
1077 Info FunctionInfo(__func__);
1078 pair <PointSet::iterator, bool> Tester;
1079 for(PointSet::iterator Runner = P2->endpoints.begin(); Runner != P2->endpoints.end(); Runner++) {
1080 Tester = P1->endpoints.insert((*Runner));
1081 if (Tester.second)
1082 DoLog(0) && (Log() << Verbose(0) << "Inserting endpoint " << *(*Runner) << " into first polygon." << endl);
1083 }
1084 P2->endpoints.clear();
1085 delete(P2);
1086};
1087
Note: See TracBrowser for help on using the repository browser.