source: src/tesselationhelpers.cpp@ 4e10f5

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 4e10f5 was 4e10f5, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Merge branch 'stable' into StructureRefactoring

Conflicts:

src/Actions/WorldAction/CenterOnEdgeAction.cpp
src/Actions/WorldAction/ChangeBoxAction.cpp
src/Actions/WorldAction/RepeatBoxAction.cpp
src/Actions/WorldAction/ScaleBoxAction.cpp
src/World.cpp
src/boundary.cpp

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