source: src/tesselationhelpers.cpp@ ebe4d6

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 ebe4d6 was 71b20e, checked in by Frederik Heber <heber@…>, 15 years ago

Attempt to fix the embedding.

Basically it would be working, but there was some failures with the FindClosestTriangleToPoint() routines.
We get triangles wrong if we start looking for the closest point. Actually, we should really look at each
triangle and check the distance. Now, we look at least at each line, but code is unfinished and crashes at the end
unexplainedly.

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