source: src/tesselationhelpers.cpp@ 776b64

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

Huge refactoring to make const what is const (ticket #38), continued.

  • too many changes because of too many cross-references to be able to list them up here.
  • NOTE that "make check" runs fine and did catch several error.
  • note that we had to use const_iterator several times when the map, ... was declared const.
  • at times we changed an allocated LinkedCell LCList(...) into

const LinkedCell *LCList;
LCList = new LinkedCell(...);

  • also mutable (see ticket #5) was used, e.g. for molecule::InternalPointer (PointCloud changes are allowed, because they are just accounting).

Signed-off-by: Frederik Heber <heber@…>

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