source: src/Tesselation/tesselationhelpers.cpp@ b4f72c

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

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

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