source: src/tesselationhelpers.cpp@ 57066a

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 57066a was 57066a, checked in by Frederik Heber <heber@…>, 16 years ago

Various fixes and attempt to get convex hull working.

Moved tesselation writing to tesselation.cpp

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