source: src/tesselationhelpers.cpp@ 72e7fa

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 72e7fa was 0a4f7f, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Made data internal data-structure of vector class private

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