1 | #include "boundary.hpp"
|
---|
2 | #include "linkedcell.hpp"
|
---|
3 | #include "molecules.hpp"
|
---|
4 | #include <gsl/gsl_matrix.h>
|
---|
5 | #include <gsl/gsl_linalg.h>
|
---|
6 | #include <gsl/gsl_multimin.h>
|
---|
7 | #include <gsl/gsl_permutation.h>
|
---|
8 |
|
---|
9 | #define DEBUG 1
|
---|
10 | #define DoSingleStepOutput 0
|
---|
11 | #define DoTecplotOutput 1
|
---|
12 | #define DoRaster3DOutput 1
|
---|
13 | #define DoVRMLOutput 1
|
---|
14 | #define TecplotSuffix ".dat"
|
---|
15 | #define Raster3DSuffix ".r3d"
|
---|
16 | #define VRMLSUffix ".wrl"
|
---|
17 | #define HULLEPSILON 1e-7
|
---|
18 |
|
---|
19 | // ======================================== Points on Boundary =================================
|
---|
20 |
|
---|
21 | BoundaryPointSet::BoundaryPointSet()
|
---|
22 | {
|
---|
23 | LinesCount = 0;
|
---|
24 | Nr = -1;
|
---|
25 | }
|
---|
26 | ;
|
---|
27 |
|
---|
28 | BoundaryPointSet::BoundaryPointSet(atom *Walker)
|
---|
29 | {
|
---|
30 | node = Walker;
|
---|
31 | LinesCount = 0;
|
---|
32 | Nr = Walker->nr;
|
---|
33 | }
|
---|
34 | ;
|
---|
35 |
|
---|
36 | BoundaryPointSet::~BoundaryPointSet()
|
---|
37 | {
|
---|
38 | cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
|
---|
39 | if (!lines.empty())
|
---|
40 | cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some lines." << endl;
|
---|
41 | node = NULL;
|
---|
42 | }
|
---|
43 | ;
|
---|
44 |
|
---|
45 | void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
|
---|
46 | {
|
---|
47 | cout << Verbose(6) << "Adding " << *this << " to line " << *line << "."
|
---|
48 | << endl;
|
---|
49 | if (line->endpoints[0] == this)
|
---|
50 | {
|
---|
51 | lines.insert(LinePair(line->endpoints[1]->Nr, line));
|
---|
52 | }
|
---|
53 | else
|
---|
54 | {
|
---|
55 | lines.insert(LinePair(line->endpoints[0]->Nr, line));
|
---|
56 | }
|
---|
57 | LinesCount++;
|
---|
58 | }
|
---|
59 | ;
|
---|
60 |
|
---|
61 | ostream &
|
---|
62 | operator <<(ostream &ost, BoundaryPointSet &a)
|
---|
63 | {
|
---|
64 | ost << "[" << a.Nr << "|" << a.node->Name << "]";
|
---|
65 | return ost;
|
---|
66 | }
|
---|
67 | ;
|
---|
68 |
|
---|
69 | // ======================================== Lines on Boundary =================================
|
---|
70 |
|
---|
71 | BoundaryLineSet::BoundaryLineSet()
|
---|
72 | {
|
---|
73 | for (int i = 0; i < 2; i++)
|
---|
74 | endpoints[i] = NULL;
|
---|
75 | TrianglesCount = 0;
|
---|
76 | Nr = -1;
|
---|
77 | }
|
---|
78 | ;
|
---|
79 |
|
---|
80 | BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
|
---|
81 | {
|
---|
82 | // set number
|
---|
83 | Nr = number;
|
---|
84 | // set endpoints in ascending order
|
---|
85 | SetEndpointsOrdered(endpoints, Point[0], Point[1]);
|
---|
86 | // add this line to the hash maps of both endpoints
|
---|
87 | Point[0]->AddLine(this); //Taken out, to check whether we can avoid unwanted double adding.
|
---|
88 | Point[1]->AddLine(this); //
|
---|
89 | // clear triangles list
|
---|
90 | TrianglesCount = 0;
|
---|
91 | cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
|
---|
92 | }
|
---|
93 | ;
|
---|
94 |
|
---|
95 | BoundaryLineSet::~BoundaryLineSet()
|
---|
96 | {
|
---|
97 | int Numbers[2];
|
---|
98 | Numbers[0] = endpoints[1]->Nr;
|
---|
99 | Numbers[1] = endpoints[0]->Nr;
|
---|
100 | for (int i = 0; i < 2; i++) {
|
---|
101 | cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
|
---|
102 | // as there may be multiple lines with same endpoints, we have to go through each and find in the endpoint's line list this line set
|
---|
103 | pair<LineMap::iterator, LineMap::iterator> erasor = endpoints[i]->lines.equal_range(Numbers[i]);
|
---|
104 | for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
|
---|
105 | if ((*Runner).second == this) {
|
---|
106 | endpoints[i]->lines.erase(Runner);
|
---|
107 | break;
|
---|
108 | }
|
---|
109 | if (endpoints[i]->lines.empty()) {
|
---|
110 | cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
|
---|
111 | if (endpoints[i] != NULL) {
|
---|
112 | delete(endpoints[i]);
|
---|
113 | endpoints[i] = NULL;
|
---|
114 | } else
|
---|
115 | cerr << "ERROR: Endpoint " << i << " has already been free'd." << endl;
|
---|
116 | } else
|
---|
117 | cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl;
|
---|
118 | }
|
---|
119 | if (!triangles.empty())
|
---|
120 | cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some triangles." << endl;
|
---|
121 | }
|
---|
122 | ;
|
---|
123 |
|
---|
124 | void
|
---|
125 | BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
|
---|
126 | {
|
---|
127 | cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "."
|
---|
128 | << endl;
|
---|
129 | triangles.insert(TrianglePair(triangle->Nr, triangle));
|
---|
130 | TrianglesCount++;
|
---|
131 | }
|
---|
132 | ;
|
---|
133 |
|
---|
134 | /** Checks whether we have a common endpoint with given \a *line.
|
---|
135 | * \param *line other line to test
|
---|
136 | * \return true - common endpoint present, false - not connected
|
---|
137 | */
|
---|
138 | bool BoundaryLineSet::IsConnectedTo(class BoundaryLineSet *line)
|
---|
139 | {
|
---|
140 | if ((endpoints[0] == line->endpoints[0]) || (endpoints[1] == line->endpoints[0]) || (endpoints[0] == line->endpoints[1]) || (endpoints[1] == line->endpoints[1]))
|
---|
141 | return true;
|
---|
142 | else
|
---|
143 | return false;
|
---|
144 | };
|
---|
145 |
|
---|
146 | /** Checks whether the adjacent triangles of a baseline are convex or not.
|
---|
147 | * We sum the two angles of each normal vector with a ficticious normnal vector from this baselinbe pointing outwards.
|
---|
148 | * If greater/equal M_PI than we are convex.
|
---|
149 | * \param *out output stream for debugging
|
---|
150 | * \return true - triangles are convex, false - concave or less than two triangles connected
|
---|
151 | */
|
---|
152 | bool BoundaryLineSet::CheckConvexityCriterion(ofstream *out)
|
---|
153 | {
|
---|
154 | Vector BaseLineNormal;
|
---|
155 | double angle = 0;
|
---|
156 | // get the two triangles
|
---|
157 | if (TrianglesCount != 2) {
|
---|
158 | *out << Verbose(1) << "ERROR: Baseline " << this << " is connect to less than two triangles, Tesselation incomplete!" << endl;
|
---|
159 | return false;
|
---|
160 | }
|
---|
161 | // have a normal vector on the base line pointing outwards
|
---|
162 | BaseLineNormal.Zero();
|
---|
163 | for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++)
|
---|
164 | BaseLineNormal.AddVector(&runner->second->NormalVector);
|
---|
165 | BaseLineNormal.Normalize();
|
---|
166 | // and calculate the sum of the angles with this normal vector and each of the triangle ones'
|
---|
167 | for(TriangleMap::iterator runner = triangles.begin(); runner != triangles.end(); runner++)
|
---|
168 | angle += BaseLineNormal.Angle(&runner->second->NormalVector);
|
---|
169 |
|
---|
170 | if ((angle - M_PI) > -MYEPSILON)
|
---|
171 | return true;
|
---|
172 | else
|
---|
173 | return false;
|
---|
174 | }
|
---|
175 |
|
---|
176 | /** Checks whether point is any of the two endpoints this line contains.
|
---|
177 | * \param *point point to test
|
---|
178 | * \return true - point is of the line, false - is not
|
---|
179 | */
|
---|
180 | bool BoundaryLineSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
|
---|
181 | {
|
---|
182 | for(int i=0;i<2;i++)
|
---|
183 | if (point == endpoints[i])
|
---|
184 | return true;
|
---|
185 | return false;
|
---|
186 | };
|
---|
187 |
|
---|
188 | ostream &
|
---|
189 | operator <<(ostream &ost, BoundaryLineSet &a)
|
---|
190 | {
|
---|
191 | ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
|
---|
192 | << a.endpoints[1]->node->Name << "]";
|
---|
193 | return ost;
|
---|
194 | }
|
---|
195 | ;
|
---|
196 |
|
---|
197 | // ======================================== Triangles on Boundary =================================
|
---|
198 |
|
---|
199 |
|
---|
200 | BoundaryTriangleSet::BoundaryTriangleSet()
|
---|
201 | {
|
---|
202 | for (int i = 0; i < 3; i++)
|
---|
203 | {
|
---|
204 | endpoints[i] = NULL;
|
---|
205 | lines[i] = NULL;
|
---|
206 | }
|
---|
207 | Nr = -1;
|
---|
208 | }
|
---|
209 | ;
|
---|
210 |
|
---|
211 | BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number)
|
---|
212 | {
|
---|
213 | // set number
|
---|
214 | Nr = number;
|
---|
215 | // set lines
|
---|
216 | cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
|
---|
217 | for (int i = 0; i < 3; i++)
|
---|
218 | {
|
---|
219 | lines[i] = line[i];
|
---|
220 | lines[i]->AddTriangle(this);
|
---|
221 | }
|
---|
222 | // get ascending order of endpoints
|
---|
223 | map<int, class BoundaryPointSet *> OrderMap;
|
---|
224 | for (int i = 0; i < 3; i++)
|
---|
225 | // for all three lines
|
---|
226 | for (int j = 0; j < 2; j++)
|
---|
227 | { // for both endpoints
|
---|
228 | OrderMap.insert(pair<int, class BoundaryPointSet *> (
|
---|
229 | line[i]->endpoints[j]->Nr, line[i]->endpoints[j]));
|
---|
230 | // and we don't care whether insertion fails
|
---|
231 | }
|
---|
232 | // set endpoints
|
---|
233 | int Counter = 0;
|
---|
234 | cout << Verbose(6) << " with end points ";
|
---|
235 | for (map<int, class BoundaryPointSet *>::iterator runner = OrderMap.begin(); runner
|
---|
236 | != OrderMap.end(); runner++)
|
---|
237 | {
|
---|
238 | endpoints[Counter] = runner->second;
|
---|
239 | cout << " " << *endpoints[Counter];
|
---|
240 | Counter++;
|
---|
241 | }
|
---|
242 | if (Counter < 3)
|
---|
243 | {
|
---|
244 | cerr << "ERROR! We have a triangle with only two distinct endpoints!"
|
---|
245 | << endl;
|
---|
246 | //exit(1);
|
---|
247 | }
|
---|
248 | cout << "." << endl;
|
---|
249 | }
|
---|
250 | ;
|
---|
251 |
|
---|
252 | BoundaryTriangleSet::~BoundaryTriangleSet()
|
---|
253 | {
|
---|
254 | for (int i = 0; i < 3; i++) {
|
---|
255 | cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl;
|
---|
256 | lines[i]->triangles.erase(Nr);
|
---|
257 | if (lines[i]->triangles.empty()) {
|
---|
258 | if (lines[i] != NULL) {
|
---|
259 | cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
|
---|
260 | delete (lines[i]);
|
---|
261 | lines[i] = NULL;
|
---|
262 | } else
|
---|
263 | cerr << "ERROR: This line " << i << " has already been free'd." << endl;
|
---|
264 | } else
|
---|
265 | cout << Verbose(5) << *lines[i] << " is still attached to another triangle." << endl;
|
---|
266 | }
|
---|
267 | }
|
---|
268 | ;
|
---|
269 |
|
---|
270 | /** Calculates the normal vector for this triangle.
|
---|
271 | * Is made unique by comparison with \a OtherVector to point in the other direction.
|
---|
272 | * \param &OtherVector direction vector to make normal vector unique.
|
---|
273 | */
|
---|
274 | void BoundaryTriangleSet::GetNormalVector(Vector &OtherVector)
|
---|
275 | {
|
---|
276 | // get normal vector
|
---|
277 | NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x,
|
---|
278 | &endpoints[2]->node->x);
|
---|
279 |
|
---|
280 | // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
|
---|
281 | if (NormalVector.Projection(&OtherVector) > 0)
|
---|
282 | NormalVector.Scale(-1.);
|
---|
283 | };
|
---|
284 |
|
---|
285 | /** Finds the point on the triangle \a *BTS the line defined by \a *MolCenter and \a *x crosses through.
|
---|
286 | * We call Vector::GetIntersectionWithPlane() to receive the intersection point with the plane
|
---|
287 | * This we test if it's really on the plane and whether it's inside the triangle on the plane or not.
|
---|
288 | * The latter is done as follows: if it's really outside, then for any endpoint of the triangle and it's opposite
|
---|
289 | * base line, the intersection between the line from endpoint to intersection and the base line will have a Vector::NormSquared()
|
---|
290 | * smaller than the first line.
|
---|
291 | * \param *out output stream for debugging
|
---|
292 | * \param *MolCenter offset vector of line
|
---|
293 | * \param *x second endpoint of line, minus \a *MolCenter is directional vector of line
|
---|
294 | * \param *Intersection intersection on plane on return
|
---|
295 | * \return true - \a *Intersection contains intersection on plane defined by triangle, false - zero vector if outside of triangle.
|
---|
296 | */
|
---|
297 | bool BoundaryTriangleSet::GetIntersectionInsideTriangle(ofstream *out, Vector *MolCenter, Vector *x, Vector *Intersection)
|
---|
298 | {
|
---|
299 | Vector CrossPoint;
|
---|
300 | Vector helper;
|
---|
301 | int i=0;
|
---|
302 |
|
---|
303 | if (Intersection->GetIntersectionWithPlane(out, &NormalVector, &endpoints[0]->node->x, MolCenter, x)) {
|
---|
304 | *out << Verbose(1) << "Alas! [Bronstein] failed - at least numerically - the intersection is not on the plane!" << endl;
|
---|
305 | return false;
|
---|
306 | }
|
---|
307 |
|
---|
308 | // Calculate cross point between one baseline and the line from the third endpoint to intersection
|
---|
309 | do {
|
---|
310 | CrossPoint.GetIntersectionOfTwoLinesOnPlane(out, &endpoints[i%3]->node->x, &endpoints[(i+1)%3]->node->x, &endpoints[(i+2)%3]->node->x, Intersection);
|
---|
311 | helper.CopyVector(&endpoints[(i+1)%3]->node->x);
|
---|
312 | helper.SubtractVector(&endpoints[i%3]->node->x);
|
---|
313 | i++;
|
---|
314 | if (i>3)
|
---|
315 | break;
|
---|
316 | } while (CrossPoint.NormSquared() < MYEPSILON);
|
---|
317 | if (i>3) {
|
---|
318 | *out << Verbose(1) << "ERROR: Could not find any cross points, something's utterly wrong here!" << endl;
|
---|
319 | exit(255);
|
---|
320 | }
|
---|
321 | CrossPoint.SubtractVector(&endpoints[i%3]->node->x);
|
---|
322 |
|
---|
323 | // check whether intersection is inside or not by comparing length of intersection and length of cross point
|
---|
324 | if ((CrossPoint.NormSquared() - helper.NormSquared()) > -MYEPSILON) { // inside
|
---|
325 | return true;
|
---|
326 | } else { // outside!
|
---|
327 | Intersection->Zero();
|
---|
328 | return false;
|
---|
329 | }
|
---|
330 | };
|
---|
331 |
|
---|
332 | /** Checks whether lines is any of the three boundary lines this triangle contains.
|
---|
333 | * \param *line line to test
|
---|
334 | * \return true - line is of the triangle, false - is not
|
---|
335 | */
|
---|
336 | bool BoundaryTriangleSet::ContainsBoundaryLine(class BoundaryLineSet *line)
|
---|
337 | {
|
---|
338 | for(int i=0;i<3;i++)
|
---|
339 | if (line == lines[i])
|
---|
340 | return true;
|
---|
341 | return false;
|
---|
342 | };
|
---|
343 |
|
---|
344 | /** Checks whether point is any of the three endpoints this triangle contains.
|
---|
345 | * \param *point point to test
|
---|
346 | * \return true - point is of the triangle, false - is not
|
---|
347 | */
|
---|
348 | bool BoundaryTriangleSet::ContainsBoundaryPoint(class BoundaryPointSet *point)
|
---|
349 | {
|
---|
350 | for(int i=0;i<3;i++)
|
---|
351 | if (point == endpoints[i])
|
---|
352 | return true;
|
---|
353 | return false;
|
---|
354 | };
|
---|
355 |
|
---|
356 | ostream &
|
---|
357 | operator <<(ostream &ost, BoundaryTriangleSet &a)
|
---|
358 | {
|
---|
359 | ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
|
---|
360 | << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
|
---|
361 | return ost;
|
---|
362 | }
|
---|
363 | ;
|
---|
364 |
|
---|
365 |
|
---|
366 | // ============================ CandidateForTesselation =============================
|
---|
367 |
|
---|
368 | CandidateForTesselation::CandidateForTesselation(
|
---|
369 | atom *candidate, BoundaryLineSet* line, Vector OptCandidateCenter, Vector OtherOptCandidateCenter
|
---|
370 | ) {
|
---|
371 | point = candidate;
|
---|
372 | BaseLine = line;
|
---|
373 | OptCenter.CopyVector(&OptCandidateCenter);
|
---|
374 | OtherOptCenter.CopyVector(&OtherOptCandidateCenter);
|
---|
375 | }
|
---|
376 |
|
---|
377 | CandidateForTesselation::~CandidateForTesselation() {
|
---|
378 | point = NULL;
|
---|
379 | BaseLine = NULL;
|
---|
380 | }
|
---|
381 |
|
---|
382 | // ========================================== F U N C T I O N S =================================
|
---|
383 |
|
---|
384 | /** Finds the endpoint two lines are sharing.
|
---|
385 | * \param *line1 first line
|
---|
386 | * \param *line2 second line
|
---|
387 | * \return point which is shared or NULL if none
|
---|
388 | */
|
---|
389 | class BoundaryPointSet *
|
---|
390 | GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
|
---|
391 | {
|
---|
392 | class BoundaryLineSet * lines[2] =
|
---|
393 | { line1, line2 };
|
---|
394 | class BoundaryPointSet *node = NULL;
|
---|
395 | map<int, class BoundaryPointSet *> OrderMap;
|
---|
396 | pair<map<int, class BoundaryPointSet *>::iterator, bool> OrderTest;
|
---|
397 | for (int i = 0; i < 2; i++)
|
---|
398 | // for both lines
|
---|
399 | for (int j = 0; j < 2; j++)
|
---|
400 | { // for both endpoints
|
---|
401 | OrderTest = OrderMap.insert(pair<int, class BoundaryPointSet *> (
|
---|
402 | lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]));
|
---|
403 | if (!OrderTest.second)
|
---|
404 | { // if insertion fails, we have common endpoint
|
---|
405 | node = OrderTest.first->second;
|
---|
406 | cout << Verbose(5) << "Common endpoint of lines " << *line1
|
---|
407 | << " and " << *line2 << " is: " << *node << "." << endl;
|
---|
408 | j = 2;
|
---|
409 | i = 2;
|
---|
410 | break;
|
---|
411 | }
|
---|
412 | }
|
---|
413 | return node;
|
---|
414 | }
|
---|
415 | ;
|
---|
416 |
|
---|
417 | /** Determines the boundary points of a cluster.
|
---|
418 | * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
|
---|
419 | * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
|
---|
420 | * center and first and last point in the triple, it is thrown out.
|
---|
421 | * \param *out output stream for debugging
|
---|
422 | * \param *mol molecule structure representing the cluster
|
---|
423 | */
|
---|
424 | Boundaries *
|
---|
425 | GetBoundaryPoints(ofstream *out, molecule *mol)
|
---|
426 | {
|
---|
427 | atom *Walker = NULL;
|
---|
428 | PointMap PointsOnBoundary;
|
---|
429 | LineMap LinesOnBoundary;
|
---|
430 | TriangleMap TrianglesOnBoundary;
|
---|
431 | Vector *MolCenter = mol->DetermineCenterOfAll(out);
|
---|
432 | Vector helper;
|
---|
433 |
|
---|
434 | *out << Verbose(1) << "Finding all boundary points." << endl;
|
---|
435 | Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
|
---|
436 | BoundariesTestPair BoundaryTestPair;
|
---|
437 | Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
|
---|
438 | double radius, angle;
|
---|
439 | // 3a. Go through every axis
|
---|
440 | for (int axis = 0; axis < NDIM; axis++) {
|
---|
441 | AxisVector.Zero();
|
---|
442 | AngleReferenceVector.Zero();
|
---|
443 | AngleReferenceNormalVector.Zero();
|
---|
444 | AxisVector.x[axis] = 1.;
|
---|
445 | AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
|
---|
446 | AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
|
---|
447 |
|
---|
448 | *out << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl;
|
---|
449 |
|
---|
450 | // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
|
---|
451 | Walker = mol->start;
|
---|
452 | while (Walker->next != mol->end) {
|
---|
453 | Walker = Walker->next;
|
---|
454 | Vector ProjectedVector;
|
---|
455 | ProjectedVector.CopyVector(&Walker->x);
|
---|
456 | ProjectedVector.SubtractVector(MolCenter);
|
---|
457 | ProjectedVector.ProjectOntoPlane(&AxisVector);
|
---|
458 |
|
---|
459 | // correct for negative side
|
---|
460 | radius = ProjectedVector.NormSquared();
|
---|
461 | if (fabs(radius) > MYEPSILON)
|
---|
462 | angle = ProjectedVector.Angle(&AngleReferenceVector);
|
---|
463 | else
|
---|
464 | angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
|
---|
465 |
|
---|
466 | //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
|
---|
467 | if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
|
---|
468 | angle = 2. * M_PI - angle;
|
---|
469 | }
|
---|
470 | *out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl;
|
---|
471 | BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker)));
|
---|
472 | if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
|
---|
473 | *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
|
---|
474 | *out << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl;
|
---|
475 | *out << Verbose(2) << "New vector: " << *Walker << endl;
|
---|
476 | double tmp = ProjectedVector.NormSquared();
|
---|
477 | if ((tmp - BoundaryTestPair.first->second.first) > MYEPSILON) {
|
---|
478 | BoundaryTestPair.first->second.first = tmp;
|
---|
479 | BoundaryTestPair.first->second.second = Walker;
|
---|
480 | *out << Verbose(2) << "Keeping new vector due to larger projected distance " << tmp << "." << endl;
|
---|
481 | } else if (fabs(tmp - BoundaryTestPair.first->second.first) < MYEPSILON) {
|
---|
482 | helper.CopyVector(&Walker->x);
|
---|
483 | helper.SubtractVector(MolCenter);
|
---|
484 | tmp = helper.NormSquared();
|
---|
485 | helper.CopyVector(&BoundaryTestPair.first->second.second->x);
|
---|
486 | helper.SubtractVector(MolCenter);
|
---|
487 | if (helper.NormSquared() < tmp) {
|
---|
488 | BoundaryTestPair.first->second.second = Walker;
|
---|
489 | *out << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl;
|
---|
490 | } else {
|
---|
491 | *out << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << tmp << "." << endl;
|
---|
492 | }
|
---|
493 | } else {
|
---|
494 | *out << Verbose(2) << "Keeping present vector due to larger projected distance " << tmp << "." << endl;
|
---|
495 | }
|
---|
496 | }
|
---|
497 | }
|
---|
498 | // printing all inserted for debugging
|
---|
499 | // {
|
---|
500 | // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
|
---|
501 | // int i=0;
|
---|
502 | // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
503 | // if (runner != BoundaryPoints[axis].begin())
|
---|
504 | // *out << ", " << i << ": " << *runner->second.second;
|
---|
505 | // else
|
---|
506 | // *out << i << ": " << *runner->second.second;
|
---|
507 | // i++;
|
---|
508 | // }
|
---|
509 | // *out << endl;
|
---|
510 | // }
|
---|
511 | // 3c. throw out points whose distance is less than the mean of left and right neighbours
|
---|
512 | bool flag = false;
|
---|
513 | *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
|
---|
514 | do { // do as long as we still throw one out per round
|
---|
515 | flag = false;
|
---|
516 | Boundaries::iterator left = BoundaryPoints[axis].end();
|
---|
517 | Boundaries::iterator right = BoundaryPoints[axis].end();
|
---|
518 | for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
519 | // set neighbours correctly
|
---|
520 | if (runner == BoundaryPoints[axis].begin()) {
|
---|
521 | left = BoundaryPoints[axis].end();
|
---|
522 | } else {
|
---|
523 | left = runner;
|
---|
524 | }
|
---|
525 | left--;
|
---|
526 | right = runner;
|
---|
527 | right++;
|
---|
528 | if (right == BoundaryPoints[axis].end()) {
|
---|
529 | right = BoundaryPoints[axis].begin();
|
---|
530 | }
|
---|
531 | // check distance
|
---|
532 |
|
---|
533 | // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
|
---|
534 | {
|
---|
535 | Vector SideA, SideB, SideC, SideH;
|
---|
536 | SideA.CopyVector(&left->second.second->x);
|
---|
537 | SideA.SubtractVector(MolCenter);
|
---|
538 | SideA.ProjectOntoPlane(&AxisVector);
|
---|
539 | // *out << "SideA: ";
|
---|
540 | // SideA.Output(out);
|
---|
541 | // *out << endl;
|
---|
542 |
|
---|
543 | SideB.CopyVector(&right->second.second->x);
|
---|
544 | SideB.SubtractVector(MolCenter);
|
---|
545 | SideB.ProjectOntoPlane(&AxisVector);
|
---|
546 | // *out << "SideB: ";
|
---|
547 | // SideB.Output(out);
|
---|
548 | // *out << endl;
|
---|
549 |
|
---|
550 | SideC.CopyVector(&left->second.second->x);
|
---|
551 | SideC.SubtractVector(&right->second.second->x);
|
---|
552 | SideC.ProjectOntoPlane(&AxisVector);
|
---|
553 | // *out << "SideC: ";
|
---|
554 | // SideC.Output(out);
|
---|
555 | // *out << endl;
|
---|
556 |
|
---|
557 | SideH.CopyVector(&runner->second.second->x);
|
---|
558 | SideH.SubtractVector(MolCenter);
|
---|
559 | SideH.ProjectOntoPlane(&AxisVector);
|
---|
560 | // *out << "SideH: ";
|
---|
561 | // SideH.Output(out);
|
---|
562 | // *out << endl;
|
---|
563 |
|
---|
564 | // calculate each length
|
---|
565 | double a = SideA.Norm();
|
---|
566 | //double b = SideB.Norm();
|
---|
567 | //double c = SideC.Norm();
|
---|
568 | double h = SideH.Norm();
|
---|
569 | // calculate the angles
|
---|
570 | double alpha = SideA.Angle(&SideH);
|
---|
571 | double beta = SideA.Angle(&SideC);
|
---|
572 | double gamma = SideB.Angle(&SideH);
|
---|
573 | double delta = SideC.Angle(&SideH);
|
---|
574 | double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
|
---|
575 | //*out << Verbose(2) << " I calculated: a = " << a << ", h = " << h << ", beta(" << left->second.second->Name << "," << left->second.second->Name << "-" << right->second.second->Name << ") = " << beta << ", delta(" << left->second.second->Name << "," << runner->second.second->Name << ") = " << delta << ", Min = " << MinDistance << "." << endl;
|
---|
576 | *out << Verbose(1) << "Checking CoG distance of runner " << *runner->second.second << " " << h << " against triangle's side length spanned by (" << *left->second.second << "," << *right->second.second << ") of " << MinDistance << "." << endl;
|
---|
577 | if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
|
---|
578 | // throw out point
|
---|
579 | *out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
|
---|
580 | BoundaryPoints[axis].erase(runner);
|
---|
581 | flag = true;
|
---|
582 | }
|
---|
583 | }
|
---|
584 | }
|
---|
585 | } while (flag);
|
---|
586 | }
|
---|
587 | delete(MolCenter);
|
---|
588 | return BoundaryPoints;
|
---|
589 | }
|
---|
590 | ;
|
---|
591 |
|
---|
592 | /** Determines greatest diameters of a cluster defined by its convex envelope.
|
---|
593 | * Looks at lines parallel to one axis and where they intersect on the projected planes
|
---|
594 | * \param *out output stream for debugging
|
---|
595 | * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
|
---|
596 | * \param *mol molecule structure representing the cluster
|
---|
597 | * \param IsAngstroem whether we have angstroem or atomic units
|
---|
598 | * \return NDIM array of the diameters
|
---|
599 | */
|
---|
600 | double *
|
---|
601 | GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol,
|
---|
602 | bool IsAngstroem)
|
---|
603 | {
|
---|
604 | // get points on boundary of NULL was given as parameter
|
---|
605 | bool BoundaryFreeFlag = false;
|
---|
606 | Boundaries *BoundaryPoints = BoundaryPtr;
|
---|
607 | if (BoundaryPoints == NULL)
|
---|
608 | {
|
---|
609 | BoundaryFreeFlag = true;
|
---|
610 | BoundaryPoints = GetBoundaryPoints(out, mol);
|
---|
611 | }
|
---|
612 | else
|
---|
613 | {
|
---|
614 | *out << Verbose(1) << "Using given boundary points set." << endl;
|
---|
615 | }
|
---|
616 | // determine biggest "diameter" of cluster for each axis
|
---|
617 | Boundaries::iterator Neighbour, OtherNeighbour;
|
---|
618 | double *GreatestDiameter = new double[NDIM];
|
---|
619 | for (int i = 0; i < NDIM; i++)
|
---|
620 | GreatestDiameter[i] = 0.;
|
---|
621 | double OldComponent, tmp, w1, w2;
|
---|
622 | Vector DistanceVector, OtherVector;
|
---|
623 | int component, Othercomponent;
|
---|
624 | for (int axis = 0; axis < NDIM; axis++)
|
---|
625 | { // regard each projected plane
|
---|
626 | //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
|
---|
627 | for (int j = 0; j < 2; j++)
|
---|
628 | { // and for both axis on the current plane
|
---|
629 | component = (axis + j + 1) % NDIM;
|
---|
630 | Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
|
---|
631 | //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
|
---|
632 | for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
|
---|
633 | != BoundaryPoints[axis].end(); runner++)
|
---|
634 | {
|
---|
635 | //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
|
---|
636 | // seek for the neighbours pair where the Othercomponent sign flips
|
---|
637 | Neighbour = runner;
|
---|
638 | Neighbour++;
|
---|
639 | if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
|
---|
640 | Neighbour = BoundaryPoints[axis].begin();
|
---|
641 | DistanceVector.CopyVector(&runner->second.second->x);
|
---|
642 | DistanceVector.SubtractVector(&Neighbour->second.second->x);
|
---|
643 | do
|
---|
644 | { // seek for neighbour pair where it flips
|
---|
645 | OldComponent = DistanceVector.x[Othercomponent];
|
---|
646 | Neighbour++;
|
---|
647 | if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
|
---|
648 | Neighbour = BoundaryPoints[axis].begin();
|
---|
649 | DistanceVector.CopyVector(&runner->second.second->x);
|
---|
650 | DistanceVector.SubtractVector(&Neighbour->second.second->x);
|
---|
651 | //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
|
---|
652 | }
|
---|
653 | while ((runner != Neighbour) && (fabs(OldComponent / fabs(
|
---|
654 | OldComponent) - DistanceVector.x[Othercomponent] / fabs(
|
---|
655 | DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
|
---|
656 | if (runner != Neighbour)
|
---|
657 | {
|
---|
658 | OtherNeighbour = Neighbour;
|
---|
659 | if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
|
---|
660 | OtherNeighbour = BoundaryPoints[axis].end();
|
---|
661 | OtherNeighbour--;
|
---|
662 | //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
|
---|
663 | // now we have found the pair: Neighbour and OtherNeighbour
|
---|
664 | OtherVector.CopyVector(&runner->second.second->x);
|
---|
665 | OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
|
---|
666 | //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
|
---|
667 | //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
|
---|
668 | // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
|
---|
669 | w1 = fabs(OtherVector.x[Othercomponent]);
|
---|
670 | w2 = fabs(DistanceVector.x[Othercomponent]);
|
---|
671 | tmp = fabs((w1 * DistanceVector.x[component] + w2
|
---|
672 | * OtherVector.x[component]) / (w1 + w2));
|
---|
673 | // mark if it has greater diameter
|
---|
674 | //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
|
---|
675 | GreatestDiameter[component] = (GreatestDiameter[component]
|
---|
676 | > tmp) ? GreatestDiameter[component] : tmp;
|
---|
677 | } //else
|
---|
678 | //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
|
---|
679 | }
|
---|
680 | }
|
---|
681 | }
|
---|
682 | *out << Verbose(0) << "RESULT: The biggest diameters are "
|
---|
683 | << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
|
---|
684 | << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
|
---|
685 | : "atomiclength") << "." << endl;
|
---|
686 |
|
---|
687 | // free reference lists
|
---|
688 | if (BoundaryFreeFlag)
|
---|
689 | delete[] (BoundaryPoints);
|
---|
690 |
|
---|
691 | return GreatestDiameter;
|
---|
692 | }
|
---|
693 | ;
|
---|
694 |
|
---|
695 | /** Creates the objects in a VRML file.
|
---|
696 | * \param *out output stream for debugging
|
---|
697 | * \param *vrmlfile output stream for tecplot data
|
---|
698 | * \param *Tess Tesselation structure with constructed triangles
|
---|
699 | * \param *mol molecule structure with atom positions
|
---|
700 | */
|
---|
701 | void write_vrml_file(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, class molecule *mol)
|
---|
702 | {
|
---|
703 | atom *Walker = mol->start;
|
---|
704 | bond *Binder = mol->first;
|
---|
705 | int i;
|
---|
706 | Vector *center = mol->DetermineCenterOfAll(out);
|
---|
707 | if (vrmlfile != NULL) {
|
---|
708 | //cout << Verbose(1) << "Writing Raster3D file ... ";
|
---|
709 | *vrmlfile << "#VRML V2.0 utf8" << endl;
|
---|
710 | *vrmlfile << "#Created by molecuilder" << endl;
|
---|
711 | *vrmlfile << "#All atoms as spheres" << endl;
|
---|
712 | while (Walker->next != mol->end) {
|
---|
713 | Walker = Walker->next;
|
---|
714 | *vrmlfile << "Sphere {" << endl << " "; // 2 is sphere type
|
---|
715 | for (i=0;i<NDIM;i++)
|
---|
716 | *vrmlfile << Walker->x.x[i]-center->x[i] << " ";
|
---|
717 | *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
|
---|
718 | }
|
---|
719 |
|
---|
720 | *vrmlfile << "# All bonds as vertices" << endl;
|
---|
721 | while (Binder->next != mol->last) {
|
---|
722 | Binder = Binder->next;
|
---|
723 | *vrmlfile << "3" << endl << " "; // 2 is round-ended cylinder type
|
---|
724 | for (i=0;i<NDIM;i++)
|
---|
725 | *vrmlfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
|
---|
726 | *vrmlfile << "\t0.03\t";
|
---|
727 | for (i=0;i<NDIM;i++)
|
---|
728 | *vrmlfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
|
---|
729 | *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
|
---|
730 | }
|
---|
731 |
|
---|
732 | *vrmlfile << "# All tesselation triangles" << endl;
|
---|
733 | for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
|
---|
734 | *vrmlfile << "1" << endl << " "; // 1 is triangle type
|
---|
735 | for (i=0;i<3;i++) { // print each node
|
---|
736 | for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
|
---|
737 | *vrmlfile << TriangleRunner->second->endpoints[i]->node->x.x[j]-center->x[j] << " ";
|
---|
738 | *vrmlfile << "\t";
|
---|
739 | }
|
---|
740 | *vrmlfile << "1. 0. 0." << endl; // red as colour
|
---|
741 | *vrmlfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
|
---|
742 | }
|
---|
743 | } else {
|
---|
744 | cerr << "ERROR: Given vrmlfile is " << vrmlfile << "." << endl;
|
---|
745 | }
|
---|
746 | delete(center);
|
---|
747 | };
|
---|
748 |
|
---|
749 | /** Creates the objects in a raster3d file (renderable with a header.r3d).
|
---|
750 | * \param *out output stream for debugging
|
---|
751 | * \param *rasterfile output stream for tecplot data
|
---|
752 | * \param *Tess Tesselation structure with constructed triangles
|
---|
753 | * \param *mol molecule structure with atom positions
|
---|
754 | */
|
---|
755 | void write_raster3d_file(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, class molecule *mol)
|
---|
756 | {
|
---|
757 | atom *Walker = mol->start;
|
---|
758 | bond *Binder = mol->first;
|
---|
759 | int i;
|
---|
760 | Vector *center = mol->DetermineCenterOfAll(out);
|
---|
761 | if (rasterfile != NULL) {
|
---|
762 | //cout << Verbose(1) << "Writing Raster3D file ... ";
|
---|
763 | *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl;
|
---|
764 | *rasterfile << "@header.r3d" << endl;
|
---|
765 | *rasterfile << "# All atoms as spheres" << endl;
|
---|
766 | while (Walker->next != mol->end) {
|
---|
767 | Walker = Walker->next;
|
---|
768 | *rasterfile << "2" << endl << " "; // 2 is sphere type
|
---|
769 | for (i=0;i<NDIM;i++)
|
---|
770 | *rasterfile << Walker->x.x[i]-center->x[i] << " ";
|
---|
771 | *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
|
---|
772 | }
|
---|
773 |
|
---|
774 | *rasterfile << "# All bonds as vertices" << endl;
|
---|
775 | while (Binder->next != mol->last) {
|
---|
776 | Binder = Binder->next;
|
---|
777 | *rasterfile << "3" << endl << " "; // 2 is round-ended cylinder type
|
---|
778 | for (i=0;i<NDIM;i++)
|
---|
779 | *rasterfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
|
---|
780 | *rasterfile << "\t0.03\t";
|
---|
781 | for (i=0;i<NDIM;i++)
|
---|
782 | *rasterfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
|
---|
783 | *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
|
---|
784 | }
|
---|
785 |
|
---|
786 | *rasterfile << "# All tesselation triangles" << endl;
|
---|
787 | *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";
|
---|
788 | for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
|
---|
789 | *rasterfile << "1" << endl << " "; // 1 is triangle type
|
---|
790 | for (i=0;i<3;i++) { // print each node
|
---|
791 | for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
|
---|
792 | *rasterfile << TriangleRunner->second->endpoints[i]->node->x.x[j]-center->x[j] << " ";
|
---|
793 | *rasterfile << "\t";
|
---|
794 | }
|
---|
795 | *rasterfile << "1. 0. 0." << endl; // red as colour
|
---|
796 | //*rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
|
---|
797 | }
|
---|
798 | *rasterfile << "9\n terminating special property\n";
|
---|
799 | } else {
|
---|
800 | cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl;
|
---|
801 | }
|
---|
802 | delete(center);
|
---|
803 | };
|
---|
804 |
|
---|
805 | /** This function creates the tecplot file, displaying the tesselation of the hull.
|
---|
806 | * \param *out output stream for debugging
|
---|
807 | * \param *tecplot output stream for tecplot data
|
---|
808 | * \param N arbitrary number to differentiate various zones in the tecplot format
|
---|
809 | */
|
---|
810 | void write_tecplot_file(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, class molecule *mol, int N)
|
---|
811 | {
|
---|
812 | if (tecplot != NULL) {
|
---|
813 | *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
|
---|
814 | *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
|
---|
815 | *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
|
---|
816 | int *LookupList = new int[mol->AtomCount];
|
---|
817 | for (int i = 0; i < mol->AtomCount; i++)
|
---|
818 | LookupList[i] = -1;
|
---|
819 |
|
---|
820 | // print atom coordinates
|
---|
821 | *out << Verbose(2) << "The following triangles were created:";
|
---|
822 | int Counter = 1;
|
---|
823 | atom *Walker = NULL;
|
---|
824 | for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
|
---|
825 | Walker = target->second->node;
|
---|
826 | LookupList[Walker->nr] = Counter++;
|
---|
827 | *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl;
|
---|
828 | }
|
---|
829 | *tecplot << endl;
|
---|
830 | // print connectivity
|
---|
831 | for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
|
---|
832 | *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
|
---|
833 | *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
|
---|
834 | }
|
---|
835 | delete[] (LookupList);
|
---|
836 | *out << endl;
|
---|
837 | }
|
---|
838 | }
|
---|
839 |
|
---|
840 | /** Tesselates the convex boundary by finding all boundary points.
|
---|
841 | * \param *out output stream for debugging
|
---|
842 | * \param *mol molecule structure with Atom's and Bond's
|
---|
843 | * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
|
---|
844 | * \param *LCList atoms in LinkedCell list
|
---|
845 | * \param *filename filename prefix for output of vertex data
|
---|
846 | * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
|
---|
847 | */
|
---|
848 | void Find_convex_border(ofstream *out, molecule* mol, class Tesselation *&TesselStruct, class LinkedCell *LCList, const char *filename)
|
---|
849 | {
|
---|
850 | bool BoundaryFreeFlag = false;
|
---|
851 | Boundaries *BoundaryPoints = NULL;
|
---|
852 |
|
---|
853 | cout << Verbose(1) << "Begin of find_convex_border" << endl;
|
---|
854 |
|
---|
855 | if (TesselStruct != NULL) // free if allocated
|
---|
856 | delete(TesselStruct);
|
---|
857 | TesselStruct = new class Tesselation;
|
---|
858 |
|
---|
859 | // 1. Find all points on the boundary
|
---|
860 | if (BoundaryPoints == NULL) {
|
---|
861 | BoundaryFreeFlag = true;
|
---|
862 | BoundaryPoints = GetBoundaryPoints(out, mol);
|
---|
863 | } else {
|
---|
864 | *out << Verbose(1) << "Using given boundary points set." << endl;
|
---|
865 | }
|
---|
866 |
|
---|
867 | // printing all inserted for debugging
|
---|
868 | for (int axis=0; axis < NDIM; axis++)
|
---|
869 | {
|
---|
870 | *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
|
---|
871 | int i=0;
|
---|
872 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
873 | if (runner != BoundaryPoints[axis].begin())
|
---|
874 | *out << ", " << i << ": " << *runner->second.second;
|
---|
875 | else
|
---|
876 | *out << i << ": " << *runner->second.second;
|
---|
877 | i++;
|
---|
878 | }
|
---|
879 | *out << endl;
|
---|
880 | }
|
---|
881 |
|
---|
882 | // 2. fill the boundary point list
|
---|
883 | for (int axis = 0; axis < NDIM; axis++)
|
---|
884 | for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
|
---|
885 | TesselStruct->AddPoint(runner->second.second);
|
---|
886 |
|
---|
887 | *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
|
---|
888 | // now we have the whole set of edge points in the BoundaryList
|
---|
889 |
|
---|
890 | // listing for debugging
|
---|
891 | // *out << Verbose(1) << "Listing PointsOnBoundary:";
|
---|
892 | // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
|
---|
893 | // *out << " " << *runner->second;
|
---|
894 | // }
|
---|
895 | // *out << endl;
|
---|
896 |
|
---|
897 | // 3a. guess starting triangle
|
---|
898 | TesselStruct->GuessStartingTriangle(out);
|
---|
899 |
|
---|
900 | // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
|
---|
901 | TesselStruct->TesselateOnBoundary(out, mol);
|
---|
902 |
|
---|
903 | // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
|
---|
904 | if (!TesselStruct->InsertStraddlingPoints(out, mol))
|
---|
905 | *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
|
---|
906 |
|
---|
907 | // 3d. check all baselines whether the peaks of the two adjacent triangles with respect to center of baseline are convex, if not, make the baseline between the two peaks and baseline endpoints become the new peaks
|
---|
908 | if (!TesselStruct->CorrectConcaveBaselines(out))
|
---|
909 | *out << Verbose(1) << "Correction of concave baselines failed!" << endl;
|
---|
910 |
|
---|
911 | *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl;
|
---|
912 |
|
---|
913 | // 4. Store triangles in tecplot file
|
---|
914 | if (filename != NULL) {
|
---|
915 | if (DoTecplotOutput) {
|
---|
916 | string OutputName(filename);
|
---|
917 | OutputName.append(TecplotSuffix);
|
---|
918 | ofstream *tecplot = new ofstream(OutputName.c_str());
|
---|
919 | write_tecplot_file(out, tecplot, TesselStruct, mol, 0);
|
---|
920 | tecplot->close();
|
---|
921 | delete(tecplot);
|
---|
922 | }
|
---|
923 | if (DoRaster3DOutput) {
|
---|
924 | string OutputName(filename);
|
---|
925 | OutputName.append(Raster3DSuffix);
|
---|
926 | ofstream *rasterplot = new ofstream(OutputName.c_str());
|
---|
927 | write_raster3d_file(out, rasterplot, TesselStruct, mol);
|
---|
928 | rasterplot->close();
|
---|
929 | delete(rasterplot);
|
---|
930 | }
|
---|
931 | }
|
---|
932 |
|
---|
933 | // free reference lists
|
---|
934 | if (BoundaryFreeFlag)
|
---|
935 | delete[] (BoundaryPoints);
|
---|
936 |
|
---|
937 | cout << Verbose(1) << "End of find_convex_border" << endl;
|
---|
938 | };
|
---|
939 |
|
---|
940 |
|
---|
941 | /** Determines the volume of a cluster.
|
---|
942 | * Determines first the convex envelope, then tesselates it and calculates its volume.
|
---|
943 | * \param *out output stream for debugging
|
---|
944 | * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
|
---|
945 | * \param *configuration needed for path to store convex envelope file
|
---|
946 | * \return determined volume of the cluster in cubed config:GetIsAngstroem()
|
---|
947 | */
|
---|
948 | double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
|
---|
949 | {
|
---|
950 | bool IsAngstroem = configuration->GetIsAngstroem();
|
---|
951 | double volume = 0.;
|
---|
952 | double PyramidVolume = 0.;
|
---|
953 | double G, h;
|
---|
954 | Vector x, y;
|
---|
955 | double a, b, c;
|
---|
956 |
|
---|
957 | // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
|
---|
958 | *out << Verbose(1)
|
---|
959 | << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
|
---|
960 | << endl;
|
---|
961 | for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner
|
---|
962 | != TesselStruct->TrianglesOnBoundary.end(); runner++)
|
---|
963 | { // go through every triangle, calculate volume of its pyramid with CoG as peak
|
---|
964 | x.CopyVector(&runner->second->endpoints[0]->node->x);
|
---|
965 | x.SubtractVector(&runner->second->endpoints[1]->node->x);
|
---|
966 | y.CopyVector(&runner->second->endpoints[0]->node->x);
|
---|
967 | y.SubtractVector(&runner->second->endpoints[2]->node->x);
|
---|
968 | a = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared(
|
---|
969 | &runner->second->endpoints[1]->node->x));
|
---|
970 | b = sqrt(runner->second->endpoints[0]->node->x.DistanceSquared(
|
---|
971 | &runner->second->endpoints[2]->node->x));
|
---|
972 | c = sqrt(runner->second->endpoints[2]->node->x.DistanceSquared(
|
---|
973 | &runner->second->endpoints[1]->node->x));
|
---|
974 | G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
|
---|
975 | x.MakeNormalVector(&runner->second->endpoints[0]->node->x,
|
---|
976 | &runner->second->endpoints[1]->node->x,
|
---|
977 | &runner->second->endpoints[2]->node->x);
|
---|
978 | x.Scale(runner->second->endpoints[1]->node->x.Projection(&x));
|
---|
979 | h = x.Norm(); // distance of CoG to triangle
|
---|
980 | PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
|
---|
981 | *out << Verbose(2) << "Area of triangle is " << G << " "
|
---|
982 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
|
---|
983 | << h << " and the volume is " << PyramidVolume << " "
|
---|
984 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
|
---|
985 | volume += PyramidVolume;
|
---|
986 | }
|
---|
987 | *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
|
---|
988 | << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
|
---|
989 | << endl;
|
---|
990 |
|
---|
991 | return volume;
|
---|
992 | }
|
---|
993 | ;
|
---|
994 |
|
---|
995 | /** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
|
---|
996 | * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
|
---|
997 | * \param *out output stream for debugging
|
---|
998 | * \param *configuration needed for path to store convex envelope file
|
---|
999 | * \param *mol molecule structure representing the cluster
|
---|
1000 | * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
|
---|
1001 | * \param celldensity desired average density in final cell
|
---|
1002 | */
|
---|
1003 | void
|
---|
1004 | PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
|
---|
1005 | double ClusterVolume, double celldensity)
|
---|
1006 | {
|
---|
1007 | // transform to PAS
|
---|
1008 | mol->PrincipalAxisSystem(out, true);
|
---|
1009 |
|
---|
1010 | // some preparations beforehand
|
---|
1011 | bool IsAngstroem = configuration->GetIsAngstroem();
|
---|
1012 | Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
|
---|
1013 | class Tesselation *TesselStruct = NULL;
|
---|
1014 | LinkedCell LCList(mol, 10.);
|
---|
1015 | Find_convex_border(out, mol, TesselStruct, &LCList, NULL);
|
---|
1016 | double clustervolume;
|
---|
1017 | if (ClusterVolume == 0)
|
---|
1018 | clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
|
---|
1019 | else
|
---|
1020 | clustervolume = ClusterVolume;
|
---|
1021 | double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
|
---|
1022 | Vector BoxLengths;
|
---|
1023 | int repetition[NDIM] =
|
---|
1024 | { 1, 1, 1 };
|
---|
1025 | int TotalNoClusters = 1;
|
---|
1026 | for (int i = 0; i < NDIM; i++)
|
---|
1027 | TotalNoClusters *= repetition[i];
|
---|
1028 |
|
---|
1029 | // sum up the atomic masses
|
---|
1030 | double totalmass = 0.;
|
---|
1031 | atom *Walker = mol->start;
|
---|
1032 | while (Walker->next != mol->end)
|
---|
1033 | {
|
---|
1034 | Walker = Walker->next;
|
---|
1035 | totalmass += Walker->type->mass;
|
---|
1036 | }
|
---|
1037 | *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
|
---|
1038 | << totalmass << " atomicmassunit." << endl;
|
---|
1039 |
|
---|
1040 | *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
|
---|
1041 | << totalmass / clustervolume << " atomicmassunit/"
|
---|
1042 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
|
---|
1043 |
|
---|
1044 | // solve cubic polynomial
|
---|
1045 | *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
|
---|
1046 | << endl;
|
---|
1047 | double cellvolume;
|
---|
1048 | if (IsAngstroem)
|
---|
1049 | cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
|
---|
1050 | / clustervolume)) / (celldensity - 1);
|
---|
1051 | else
|
---|
1052 | cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
|
---|
1053 | / clustervolume)) / (celldensity - 1);
|
---|
1054 | *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
|
---|
1055 | << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
|
---|
1056 | : "atomiclength") << "^3." << endl;
|
---|
1057 |
|
---|
1058 | double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
|
---|
1059 | * GreatestDiameter[1] * GreatestDiameter[2]);
|
---|
1060 | *out << Verbose(1)
|
---|
1061 | << "Minimum volume of the convex envelope contained in a rectangular box is "
|
---|
1062 | << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
|
---|
1063 | : "atomiclength") << "^3." << endl;
|
---|
1064 | if (minimumvolume > cellvolume)
|
---|
1065 | {
|
---|
1066 | cerr << Verbose(0)
|
---|
1067 | << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
|
---|
1068 | << endl;
|
---|
1069 | cout << Verbose(0)
|
---|
1070 | << "Setting Box dimensions to minimum possible, the greatest diameters."
|
---|
1071 | << endl;
|
---|
1072 | for (int i = 0; i < NDIM; i++)
|
---|
1073 | BoxLengths.x[i] = GreatestDiameter[i];
|
---|
1074 | mol->CenterEdge(out, &BoxLengths);
|
---|
1075 | }
|
---|
1076 | else
|
---|
1077 | {
|
---|
1078 | BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
|
---|
1079 | * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
|
---|
1080 | BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
|
---|
1081 | * GreatestDiameter[1] + repetition[0] * repetition[2]
|
---|
1082 | * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
|
---|
1083 | * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
|
---|
1084 | BoxLengths.x[2] = minimumvolume - cellvolume;
|
---|
1085 | double x0 = 0., x1 = 0., x2 = 0.;
|
---|
1086 | if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
|
---|
1087 | BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
|
---|
1088 | *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
|
---|
1089 | << " ." << endl;
|
---|
1090 | else
|
---|
1091 | {
|
---|
1092 | *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
|
---|
1093 | << " and " << x1 << " and " << x2 << " ." << endl;
|
---|
1094 | x0 = x2; // sorted in ascending order
|
---|
1095 | }
|
---|
1096 |
|
---|
1097 | cellvolume = 1;
|
---|
1098 | for (int i = 0; i < NDIM; i++)
|
---|
1099 | {
|
---|
1100 | BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
|
---|
1101 | cellvolume *= BoxLengths.x[i];
|
---|
1102 | }
|
---|
1103 |
|
---|
1104 | // set new box dimensions
|
---|
1105 | *out << Verbose(0) << "Translating to box with these boundaries." << endl;
|
---|
1106 | mol->SetBoxDimension(&BoxLengths);
|
---|
1107 | mol->CenterInBox((ofstream *) &cout);
|
---|
1108 | }
|
---|
1109 | // update Box of atoms by boundary
|
---|
1110 | mol->SetBoxDimension(&BoxLengths);
|
---|
1111 | *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
|
---|
1112 | << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
|
---|
1113 | << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
|
---|
1114 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
|
---|
1115 | }
|
---|
1116 | ;
|
---|
1117 |
|
---|
1118 |
|
---|
1119 | /** Fills the empty space of the simulation box with water/
|
---|
1120 | * \param *out output stream for debugging
|
---|
1121 | * \param *List list of molecules already present in box
|
---|
1122 | * \param *TesselStruct contains tesselated surface
|
---|
1123 | * \param *filler molecule which the box is to be filled with
|
---|
1124 | * \param configuration contains box dimensions
|
---|
1125 | * \param distance[NDIM] distance between filling molecules in each direction
|
---|
1126 | * \param RandAtomDisplacement maximum distance for random displacement per atom
|
---|
1127 | * \param RandMolDisplacement maximum distance for random displacement per filler molecule
|
---|
1128 | * \param DoRandomRotation true - do random rotiations, false - don't
|
---|
1129 | * \return *mol pointer to new molecule with filled atoms
|
---|
1130 | */
|
---|
1131 | molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
|
---|
1132 | {
|
---|
1133 | molecule *Filling = new molecule(filler->elemente);
|
---|
1134 | Vector CurrentPosition;
|
---|
1135 | int N[NDIM];
|
---|
1136 | int n[NDIM];
|
---|
1137 | double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size);
|
---|
1138 | double Rotations[NDIM*NDIM];
|
---|
1139 | Vector AtomTranslations;
|
---|
1140 | Vector FillerTranslations;
|
---|
1141 | Vector FillerDistance;
|
---|
1142 | double FillIt = false;
|
---|
1143 | atom *Walker = NULL, *Runner = NULL;
|
---|
1144 | bond *Binder = NULL;
|
---|
1145 |
|
---|
1146 | // Center filler at origin
|
---|
1147 | filler->CenterOrigin(out);
|
---|
1148 | filler->Center.Zero();
|
---|
1149 |
|
---|
1150 | // calculate filler grid in [0,1]^3
|
---|
1151 | FillerDistance.Init(distance[0], distance[1], distance[2]);
|
---|
1152 | FillerDistance.InverseMatrixMultiplication(M);
|
---|
1153 | for(int i=0;i<NDIM;i++)
|
---|
1154 | N[i] = ceil(1./FillerDistance.x[i]);
|
---|
1155 |
|
---|
1156 | // go over [0,1]^3 filler grid
|
---|
1157 | for (n[0] = 0; n[0] < N[0]; n[0]++)
|
---|
1158 | for (n[1] = 0; n[1] < N[1]; n[1]++)
|
---|
1159 | for (n[2] = 0; n[2] < N[2]; n[2]++) {
|
---|
1160 | // calculate position of current grid vector in untransformed box
|
---|
1161 | CurrentPosition.Init(n[0], n[1], n[2]);
|
---|
1162 | CurrentPosition.MatrixMultiplication(M);
|
---|
1163 | // Check whether point is in- or outside
|
---|
1164 | FillIt = true;
|
---|
1165 | for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
|
---|
1166 | FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInside(&CurrentPosition));
|
---|
1167 | }
|
---|
1168 |
|
---|
1169 | if (FillIt) {
|
---|
1170 | // fill in Filler
|
---|
1171 | *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
|
---|
1172 |
|
---|
1173 | // create molecule random translation vector ...
|
---|
1174 | for (int i=0;i<NDIM;i++)
|
---|
1175 | FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
|
---|
1176 |
|
---|
1177 | // go through all atoms
|
---|
1178 | Walker = filler->start;
|
---|
1179 | while (Walker != filler->end) {
|
---|
1180 | Walker = Walker->next;
|
---|
1181 | // copy atom ...
|
---|
1182 | *Runner = new atom(Walker);
|
---|
1183 |
|
---|
1184 | // create atomic random translation vector ...
|
---|
1185 | for (int i=0;i<NDIM;i++)
|
---|
1186 | AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
|
---|
1187 |
|
---|
1188 | // ... and rotation matrix
|
---|
1189 | if (DoRandomRotation) {
|
---|
1190 | double phi[NDIM];
|
---|
1191 | for (int i=0;i<NDIM;i++) {
|
---|
1192 | phi[i] = rand()/(RAND_MAX/(2.*M_PI));
|
---|
1193 | }
|
---|
1194 |
|
---|
1195 | Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
|
---|
1196 | Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
|
---|
1197 | Rotations[6] = cos(phi[1])*sin(phi[2]) ;
|
---|
1198 | Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
|
---|
1199 | Rotations[4] = cos(phi[0])*cos(phi[1]) ;
|
---|
1200 | Rotations[7] = sin(phi[1]) ;
|
---|
1201 | Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
|
---|
1202 | Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
|
---|
1203 | Rotations[8] = cos(phi[1])*cos(phi[2]) ;
|
---|
1204 | }
|
---|
1205 |
|
---|
1206 | // ... and put at new position
|
---|
1207 | if (DoRandomRotation)
|
---|
1208 | Runner->x.MatrixMultiplication(Rotations);
|
---|
1209 | Runner->x.AddVector(&AtomTranslations);
|
---|
1210 | Runner->x.AddVector(&FillerTranslations);
|
---|
1211 | Runner->x.AddVector(&CurrentPosition);
|
---|
1212 | // insert into Filling
|
---|
1213 | Filling->AddAtom(Runner);
|
---|
1214 | }
|
---|
1215 |
|
---|
1216 | // go through all bonds and add as well
|
---|
1217 | Binder = filler->first;
|
---|
1218 | while(Binder != filler->last) {
|
---|
1219 | Binder = Binder->next;
|
---|
1220 | }
|
---|
1221 | } else {
|
---|
1222 | // leave empty
|
---|
1223 | *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
|
---|
1224 | }
|
---|
1225 | }
|
---|
1226 | return Filling;
|
---|
1227 | };
|
---|
1228 |
|
---|
1229 |
|
---|
1230 | // =========================================================== class TESSELATION ===========================================
|
---|
1231 |
|
---|
1232 | /** Constructor of class Tesselation.
|
---|
1233 | */
|
---|
1234 | Tesselation::Tesselation()
|
---|
1235 | {
|
---|
1236 | PointsOnBoundaryCount = 0;
|
---|
1237 | LinesOnBoundaryCount = 0;
|
---|
1238 | TrianglesOnBoundaryCount = 0;
|
---|
1239 | TriangleFilesWritten = 0;
|
---|
1240 | }
|
---|
1241 | ;
|
---|
1242 |
|
---|
1243 | /** Constructor of class Tesselation.
|
---|
1244 | * We have to free all points, lines and triangles.
|
---|
1245 | */
|
---|
1246 | Tesselation::~Tesselation()
|
---|
1247 | {
|
---|
1248 | cout << Verbose(1) << "Free'ing TesselStruct ... " << endl;
|
---|
1249 | for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
|
---|
1250 | if (runner->second != NULL) {
|
---|
1251 | delete (runner->second);
|
---|
1252 | runner->second = NULL;
|
---|
1253 | } else
|
---|
1254 | cerr << "ERROR: The triangle " << runner->first << " has already been free'd." << endl;
|
---|
1255 | }
|
---|
1256 | }
|
---|
1257 | ;
|
---|
1258 |
|
---|
1259 | /** Gueses first starting triangle of the convex envelope.
|
---|
1260 | * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
|
---|
1261 | * \param *out output stream for debugging
|
---|
1262 | * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
|
---|
1263 | */
|
---|
1264 | void
|
---|
1265 | Tesselation::GuessStartingTriangle(ofstream *out)
|
---|
1266 | {
|
---|
1267 | // 4b. create a starting triangle
|
---|
1268 | // 4b1. create all distances
|
---|
1269 | DistanceMultiMap DistanceMMap;
|
---|
1270 | double distance, tmp;
|
---|
1271 | Vector PlaneVector, TrialVector;
|
---|
1272 | PointMap::iterator A, B, C; // three nodes of the first triangle
|
---|
1273 | A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
|
---|
1274 |
|
---|
1275 | // with A chosen, take each pair B,C and sort
|
---|
1276 | if (A != PointsOnBoundary.end())
|
---|
1277 | {
|
---|
1278 | B = A;
|
---|
1279 | B++;
|
---|
1280 | for (; B != PointsOnBoundary.end(); B++)
|
---|
1281 | {
|
---|
1282 | C = B;
|
---|
1283 | C++;
|
---|
1284 | for (; C != PointsOnBoundary.end(); C++)
|
---|
1285 | {
|
---|
1286 | tmp = A->second->node->x.DistanceSquared(&B->second->node->x);
|
---|
1287 | distance = tmp * tmp;
|
---|
1288 | tmp = A->second->node->x.DistanceSquared(&C->second->node->x);
|
---|
1289 | distance += tmp * tmp;
|
---|
1290 | tmp = B->second->node->x.DistanceSquared(&C->second->node->x);
|
---|
1291 | distance += tmp * tmp;
|
---|
1292 | DistanceMMap.insert(DistanceMultiMapPair(distance, pair<
|
---|
1293 | PointMap::iterator, PointMap::iterator> (B, C)));
|
---|
1294 | }
|
---|
1295 | }
|
---|
1296 | }
|
---|
1297 | // // listing distances
|
---|
1298 | // *out << Verbose(1) << "Listing DistanceMMap:";
|
---|
1299 | // for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
|
---|
1300 | // *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
|
---|
1301 | // }
|
---|
1302 | // *out << endl;
|
---|
1303 | // 4b2. pick three baselines forming a triangle
|
---|
1304 | // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
|
---|
1305 | DistanceMultiMap::iterator baseline = DistanceMMap.begin();
|
---|
1306 | for (; baseline != DistanceMMap.end(); baseline++)
|
---|
1307 | {
|
---|
1308 | // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
|
---|
1309 | // 2. next, we have to check whether all points reside on only one side of the triangle
|
---|
1310 | // 3. construct plane vector
|
---|
1311 | PlaneVector.MakeNormalVector(&A->second->node->x,
|
---|
1312 | &baseline->second.first->second->node->x,
|
---|
1313 | &baseline->second.second->second->node->x);
|
---|
1314 | *out << Verbose(2) << "Plane vector of candidate triangle is ";
|
---|
1315 | PlaneVector.Output(out);
|
---|
1316 | *out << endl;
|
---|
1317 | // 4. loop over all points
|
---|
1318 | double sign = 0.;
|
---|
1319 | PointMap::iterator checker = PointsOnBoundary.begin();
|
---|
1320 | for (; checker != PointsOnBoundary.end(); checker++)
|
---|
1321 | {
|
---|
1322 | // (neglecting A,B,C)
|
---|
1323 | if ((checker == A) || (checker == baseline->second.first) || (checker
|
---|
1324 | == baseline->second.second))
|
---|
1325 | continue;
|
---|
1326 | // 4a. project onto plane vector
|
---|
1327 | TrialVector.CopyVector(&checker->second->node->x);
|
---|
1328 | TrialVector.SubtractVector(&A->second->node->x);
|
---|
1329 | distance = TrialVector.Projection(&PlaneVector);
|
---|
1330 | if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
|
---|
1331 | continue;
|
---|
1332 | *out << Verbose(3) << "Projection of " << checker->second->node->Name
|
---|
1333 | << " yields distance of " << distance << "." << endl;
|
---|
1334 | tmp = distance / fabs(distance);
|
---|
1335 | // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
|
---|
1336 | if ((sign != 0) && (tmp != sign))
|
---|
1337 | {
|
---|
1338 | // 4c. If so, break 4. loop and continue with next candidate in 1. loop
|
---|
1339 | *out << Verbose(2) << "Current candidates: "
|
---|
1340 | << A->second->node->Name << ","
|
---|
1341 | << baseline->second.first->second->node->Name << ","
|
---|
1342 | << baseline->second.second->second->node->Name << " leaves "
|
---|
1343 | << checker->second->node->Name << " outside the convex hull."
|
---|
1344 | << endl;
|
---|
1345 | break;
|
---|
1346 | }
|
---|
1347 | else
|
---|
1348 | { // note the sign for later
|
---|
1349 | *out << Verbose(2) << "Current candidates: "
|
---|
1350 | << A->second->node->Name << ","
|
---|
1351 | << baseline->second.first->second->node->Name << ","
|
---|
1352 | << baseline->second.second->second->node->Name << " leave "
|
---|
1353 | << checker->second->node->Name << " inside the convex hull."
|
---|
1354 | << endl;
|
---|
1355 | sign = tmp;
|
---|
1356 | }
|
---|
1357 | // 4d. Check whether the point is inside the triangle (check distance to each node
|
---|
1358 | tmp = checker->second->node->x.DistanceSquared(&A->second->node->x);
|
---|
1359 | int innerpoint = 0;
|
---|
1360 | if ((tmp < A->second->node->x.DistanceSquared(
|
---|
1361 | &baseline->second.first->second->node->x)) && (tmp
|
---|
1362 | < A->second->node->x.DistanceSquared(
|
---|
1363 | &baseline->second.second->second->node->x)))
|
---|
1364 | innerpoint++;
|
---|
1365 | tmp = checker->second->node->x.DistanceSquared(
|
---|
1366 | &baseline->second.first->second->node->x);
|
---|
1367 | if ((tmp < baseline->second.first->second->node->x.DistanceSquared(
|
---|
1368 | &A->second->node->x)) && (tmp
|
---|
1369 | < baseline->second.first->second->node->x.DistanceSquared(
|
---|
1370 | &baseline->second.second->second->node->x)))
|
---|
1371 | innerpoint++;
|
---|
1372 | tmp = checker->second->node->x.DistanceSquared(
|
---|
1373 | &baseline->second.second->second->node->x);
|
---|
1374 | if ((tmp < baseline->second.second->second->node->x.DistanceSquared(
|
---|
1375 | &baseline->second.first->second->node->x)) && (tmp
|
---|
1376 | < baseline->second.second->second->node->x.DistanceSquared(
|
---|
1377 | &A->second->node->x)))
|
---|
1378 | innerpoint++;
|
---|
1379 | // 4e. If so, break 4. loop and continue with next candidate in 1. loop
|
---|
1380 | if (innerpoint == 3)
|
---|
1381 | break;
|
---|
1382 | }
|
---|
1383 | // 5. come this far, all on same side? Then break 1. loop and construct triangle
|
---|
1384 | if (checker == PointsOnBoundary.end())
|
---|
1385 | {
|
---|
1386 | *out << "Looks like we have a candidate!" << endl;
|
---|
1387 | break;
|
---|
1388 | }
|
---|
1389 | }
|
---|
1390 | if (baseline != DistanceMMap.end())
|
---|
1391 | {
|
---|
1392 | BPS[0] = baseline->second.first->second;
|
---|
1393 | BPS[1] = baseline->second.second->second;
|
---|
1394 | BLS[0] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
|
---|
1395 | BPS[0] = A->second;
|
---|
1396 | BPS[1] = baseline->second.second->second;
|
---|
1397 | BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
|
---|
1398 | BPS[0] = baseline->second.first->second;
|
---|
1399 | BPS[1] = A->second;
|
---|
1400 | BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
|
---|
1401 |
|
---|
1402 | // 4b3. insert created triangle
|
---|
1403 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
|
---|
1404 | TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
|
---|
1405 | TrianglesOnBoundaryCount++;
|
---|
1406 | for (int i = 0; i < NDIM; i++)
|
---|
1407 | {
|
---|
1408 | LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BTS->lines[i]));
|
---|
1409 | LinesOnBoundaryCount++;
|
---|
1410 | }
|
---|
1411 |
|
---|
1412 | *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
|
---|
1413 | }
|
---|
1414 | else
|
---|
1415 | {
|
---|
1416 | *out << Verbose(1) << "No starting triangle found." << endl;
|
---|
1417 | exit(255);
|
---|
1418 | }
|
---|
1419 | }
|
---|
1420 | ;
|
---|
1421 |
|
---|
1422 | /** Tesselates the convex envelope of a cluster from a single starting triangle.
|
---|
1423 | * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
|
---|
1424 | * 2 triangles. Hence, we go through all current lines:
|
---|
1425 | * -# if the lines contains to only one triangle
|
---|
1426 | * -# We search all points in the boundary
|
---|
1427 | * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
|
---|
1428 | * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
|
---|
1429 | * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors)
|
---|
1430 | * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
|
---|
1431 | * \param *out output stream for debugging
|
---|
1432 | * \param *configuration for IsAngstroem
|
---|
1433 | * \param *mol the cluster as a molecule structure
|
---|
1434 | */
|
---|
1435 | void Tesselation::TesselateOnBoundary(ofstream *out, molecule *mol)
|
---|
1436 | {
|
---|
1437 | bool flag;
|
---|
1438 | PointMap::iterator winner;
|
---|
1439 | class BoundaryPointSet *peak = NULL;
|
---|
1440 | double SmallestAngle, TempAngle;
|
---|
1441 | Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, helper, PropagationVector, *MolCenter = NULL;
|
---|
1442 | LineMap::iterator LineChecker[2];
|
---|
1443 |
|
---|
1444 | MolCenter = mol->DetermineCenterOfAll(out);
|
---|
1445 | // create a first tesselation with the given BoundaryPoints
|
---|
1446 | do {
|
---|
1447 | flag = false;
|
---|
1448 | for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
|
---|
1449 | if (baseline->second->TrianglesCount == 1) {
|
---|
1450 | // 5a. go through each boundary point if not _both_ edges between either endpoint of the current line and this point exist (and belong to 2 triangles)
|
---|
1451 | SmallestAngle = M_PI;
|
---|
1452 |
|
---|
1453 | // get peak point with respect to this base line's only triangle
|
---|
1454 | BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
|
---|
1455 | *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl;
|
---|
1456 | for (int i = 0; i < 3; i++)
|
---|
1457 | if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
|
---|
1458 | peak = BTS->endpoints[i];
|
---|
1459 | *out << Verbose(3) << " and has peak " << *peak << "." << endl;
|
---|
1460 |
|
---|
1461 | // prepare some auxiliary vectors
|
---|
1462 | Vector BaseLineCenter, BaseLine;
|
---|
1463 | BaseLineCenter.CopyVector(&baseline->second->endpoints[0]->node->x);
|
---|
1464 | BaseLineCenter.AddVector(&baseline->second->endpoints[1]->node->x);
|
---|
1465 | BaseLineCenter.Scale(1. / 2.); // points now to center of base line
|
---|
1466 | BaseLine.CopyVector(&baseline->second->endpoints[0]->node->x);
|
---|
1467 | BaseLine.SubtractVector(&baseline->second->endpoints[1]->node->x);
|
---|
1468 |
|
---|
1469 | // offset to center of triangle
|
---|
1470 | CenterVector.Zero();
|
---|
1471 | for (int i = 0; i < 3; i++)
|
---|
1472 | CenterVector.AddVector(&BTS->endpoints[i]->node->x);
|
---|
1473 | CenterVector.Scale(1. / 3.);
|
---|
1474 | *out << Verbose(4) << "CenterVector of base triangle is " << CenterVector << endl;
|
---|
1475 |
|
---|
1476 | // normal vector of triangle
|
---|
1477 | NormalVector.CopyVector(MolCenter);
|
---|
1478 | NormalVector.SubtractVector(&CenterVector);
|
---|
1479 | BTS->GetNormalVector(NormalVector);
|
---|
1480 | NormalVector.CopyVector(&BTS->NormalVector);
|
---|
1481 | *out << Verbose(4) << "NormalVector of base triangle is " << NormalVector << endl;
|
---|
1482 |
|
---|
1483 | // vector in propagation direction (out of triangle)
|
---|
1484 | // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
|
---|
1485 | PropagationVector.MakeNormalVector(&BaseLine, &NormalVector);
|
---|
1486 | TempVector.CopyVector(&CenterVector);
|
---|
1487 | TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
|
---|
1488 | //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
|
---|
1489 | if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
|
---|
1490 | PropagationVector.Scale(-1.);
|
---|
1491 | *out << Verbose(4) << "PropagationVector of base triangle is " << PropagationVector << endl;
|
---|
1492 | winner = PointsOnBoundary.end();
|
---|
1493 |
|
---|
1494 | // loop over all points and calculate angle between normal vector of new and present triangle
|
---|
1495 | for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) {
|
---|
1496 | if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
|
---|
1497 | *out << Verbose(3) << "Target point is " << *(target->second) << ":" << endl;
|
---|
1498 |
|
---|
1499 | // first check direction, so that triangles don't intersect
|
---|
1500 | VirtualNormalVector.CopyVector(&target->second->node->x);
|
---|
1501 | VirtualNormalVector.SubtractVector(&BaseLineCenter); // points from center of base line to target
|
---|
1502 | VirtualNormalVector.ProjectOntoPlane(&NormalVector);
|
---|
1503 | TempAngle = VirtualNormalVector.Angle(&PropagationVector);
|
---|
1504 | *out << Verbose(4) << "VirtualNormalVector is " << VirtualNormalVector << " and PropagationVector is " << PropagationVector << "." << endl;
|
---|
1505 | if (TempAngle > (M_PI/2.)) { // no bends bigger than Pi/2 (90 degrees)
|
---|
1506 | *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
|
---|
1507 | continue;
|
---|
1508 | } else
|
---|
1509 | *out << Verbose(4) << "Angle on triangle plane between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
|
---|
1510 |
|
---|
1511 | // check first and second endpoint (if any connecting line goes to target has at least not more than 1 triangle)
|
---|
1512 | LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
|
---|
1513 | LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
|
---|
1514 | if (((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[0]->second->TrianglesCount == 2))) {
|
---|
1515 | *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
|
---|
1516 | continue;
|
---|
1517 | }
|
---|
1518 | if (((LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (LineChecker[1]->second->TrianglesCount == 2))) {
|
---|
1519 | *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
|
---|
1520 | continue;
|
---|
1521 | }
|
---|
1522 |
|
---|
1523 | // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
|
---|
1524 | if ((((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak)))) {
|
---|
1525 | *out << Verbose(4) << "Current target is peak!" << endl;
|
---|
1526 | continue;
|
---|
1527 | }
|
---|
1528 |
|
---|
1529 | // check for linear dependence
|
---|
1530 | TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
|
---|
1531 | TempVector.SubtractVector(&target->second->node->x);
|
---|
1532 | helper.CopyVector(&baseline->second->endpoints[1]->node->x);
|
---|
1533 | helper.SubtractVector(&target->second->node->x);
|
---|
1534 | helper.ProjectOntoPlane(&TempVector);
|
---|
1535 | if (fabs(helper.NormSquared()) < MYEPSILON) {
|
---|
1536 | *out << Verbose(4) << "Chosen set of vectors is linear dependent." << endl;
|
---|
1537 | continue;
|
---|
1538 | }
|
---|
1539 |
|
---|
1540 | // in case NOT both were found, create virtually this triangle, get its normal vector, calculate angle
|
---|
1541 | flag = true;
|
---|
1542 | VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x);
|
---|
1543 | TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
|
---|
1544 | TempVector.AddVector(&baseline->second->endpoints[1]->node->x);
|
---|
1545 | TempVector.AddVector(&target->second->node->x);
|
---|
1546 | TempVector.Scale(1./3.);
|
---|
1547 | TempVector.SubtractVector(MolCenter);
|
---|
1548 | // make it always point outward
|
---|
1549 | if (VirtualNormalVector.Projection(&TempVector) < 0)
|
---|
1550 | VirtualNormalVector.Scale(-1.);
|
---|
1551 | // calculate angle
|
---|
1552 | TempAngle = NormalVector.Angle(&VirtualNormalVector);
|
---|
1553 | *out << Verbose(4) << "NormalVector is " << VirtualNormalVector << " and the angle is " << TempAngle << "." << endl;
|
---|
1554 | if ((SmallestAngle - TempAngle) > MYEPSILON) { // set to new possible winner
|
---|
1555 | SmallestAngle = TempAngle;
|
---|
1556 | winner = target;
|
---|
1557 | *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
|
---|
1558 | } else if (fabs(SmallestAngle - TempAngle) < MYEPSILON) { // check the angle to propagation, both possible targets are in one plane! (their normals have same angle)
|
---|
1559 | // hence, check the angles to some normal direction from our base line but in this common plane of both targets...
|
---|
1560 | helper.CopyVector(&target->second->node->x);
|
---|
1561 | helper.SubtractVector(&BaseLineCenter);
|
---|
1562 | helper.ProjectOntoPlane(&BaseLine);
|
---|
1563 | // ...the one with the smaller angle is the better candidate
|
---|
1564 | TempVector.CopyVector(&target->second->node->x);
|
---|
1565 | TempVector.SubtractVector(&BaseLineCenter);
|
---|
1566 | TempVector.ProjectOntoPlane(&VirtualNormalVector);
|
---|
1567 | TempAngle = TempVector.Angle(&helper);
|
---|
1568 | TempVector.CopyVector(&winner->second->node->x);
|
---|
1569 | TempVector.SubtractVector(&BaseLineCenter);
|
---|
1570 | TempVector.ProjectOntoPlane(&VirtualNormalVector);
|
---|
1571 | if (TempAngle < TempVector.Angle(&helper)) {
|
---|
1572 | TempAngle = NormalVector.Angle(&VirtualNormalVector);
|
---|
1573 | SmallestAngle = TempAngle;
|
---|
1574 | winner = target;
|
---|
1575 | *out << Verbose(4) << "New winner " << *winner->second->node << " due to smaller angle " << TempAngle << " to propagation direction." << endl;
|
---|
1576 | } else
|
---|
1577 | *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle to propagation direction." << endl;
|
---|
1578 | } else
|
---|
1579 | *out << Verbose(4) << "Keeping old winner " << *winner->second->node << " due to smaller angle between normal vectors." << endl;
|
---|
1580 | }
|
---|
1581 | } // end of loop over all boundary points
|
---|
1582 |
|
---|
1583 | // 5b. The point of the above whose triangle has the greatest angle with the triangle the current line belongs to (it only belongs to one, remember!): New triangle
|
---|
1584 | if (winner != PointsOnBoundary.end()) {
|
---|
1585 | *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
|
---|
1586 | // create the lins of not yet present
|
---|
1587 | BLS[0] = baseline->second;
|
---|
1588 | // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
|
---|
1589 | LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
|
---|
1590 | LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
|
---|
1591 | if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
|
---|
1592 | BPS[0] = baseline->second->endpoints[0];
|
---|
1593 | BPS[1] = winner->second;
|
---|
1594 | BLS[1] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
|
---|
1595 | LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[1]));
|
---|
1596 | LinesOnBoundaryCount++;
|
---|
1597 | } else
|
---|
1598 | BLS[1] = LineChecker[0]->second;
|
---|
1599 | if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
|
---|
1600 | BPS[0] = baseline->second->endpoints[1];
|
---|
1601 | BPS[1] = winner->second;
|
---|
1602 | BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
|
---|
1603 | LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[2]));
|
---|
1604 | LinesOnBoundaryCount++;
|
---|
1605 | } else
|
---|
1606 | BLS[2] = LineChecker[1]->second;
|
---|
1607 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
|
---|
1608 | TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
|
---|
1609 | TrianglesOnBoundaryCount++;
|
---|
1610 | } else {
|
---|
1611 | *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
|
---|
1612 | }
|
---|
1613 |
|
---|
1614 | // 5d. If the set of lines is not yet empty, go to 5. and continue
|
---|
1615 | } else
|
---|
1616 | *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl;
|
---|
1617 | } while (flag);
|
---|
1618 |
|
---|
1619 | // exit
|
---|
1620 | delete(MolCenter);
|
---|
1621 | };
|
---|
1622 |
|
---|
1623 | /** Inserts all atoms outside of the tesselated surface into it by adding new triangles.
|
---|
1624 | * \param *out output stream for debugging
|
---|
1625 | * \param *mol molecule structure with atoms
|
---|
1626 | * \return true - all straddling points insert, false - something went wrong
|
---|
1627 | */
|
---|
1628 | bool Tesselation::InsertStraddlingPoints(ofstream *out, molecule *mol)
|
---|
1629 | {
|
---|
1630 | Vector Intersection;
|
---|
1631 | atom *Walker = mol->start;
|
---|
1632 | Vector *MolCenter = mol->DetermineCenterOfAll(out);
|
---|
1633 | while (Walker->next != mol->end) { // we only have to go once through all points, as boundary can become only bigger
|
---|
1634 | // get the next triangle
|
---|
1635 | BTS = FindClosestTriangleToPoint(out, &Walker->x);
|
---|
1636 | if (BTS == NULL) {
|
---|
1637 | *out << Verbose(1) << "ERROR: No triangle closest to " << Walker << " was found." << endl;
|
---|
1638 | return false;
|
---|
1639 | }
|
---|
1640 | // get the intersection point
|
---|
1641 | if (BTS->GetIntersectionInsideTriangle(out, MolCenter, &Walker->x, &Intersection)) {
|
---|
1642 | // we have the intersection, check whether in- or outside of boundary
|
---|
1643 | if ((MolCenter->DistanceSquared(&Walker->x) - MolCenter->DistanceSquared(&Intersection)) < -MYEPSILON) {
|
---|
1644 | // inside, next!
|
---|
1645 | *out << Verbose(4) << Walker << " is inside wrt triangle " << BTS << "." << endl;
|
---|
1646 | } else {
|
---|
1647 | // outside!
|
---|
1648 | *out << Verbose(3) << Walker << " is outside wrt triangle " << BTS << "." << endl;
|
---|
1649 | class BoundaryLineSet *OldLines[3], *NewLines[3];
|
---|
1650 | class BoundaryPointSet *OldPoints[3], *NewPoint;
|
---|
1651 | // store the three old lines and old points
|
---|
1652 | for (int i=0;i<3;i++) {
|
---|
1653 | OldLines[i] = BTS->lines[i];
|
---|
1654 | OldPoints[i] = BTS->endpoints[i];
|
---|
1655 | }
|
---|
1656 | // add Walker to boundary points
|
---|
1657 | AddPoint(Walker);
|
---|
1658 | if (BPS[0] == NULL)
|
---|
1659 | NewPoint = BPS[0];
|
---|
1660 | else
|
---|
1661 | continue;
|
---|
1662 | // remove triangle
|
---|
1663 | TrianglesOnBoundary.erase(BTS->Nr);
|
---|
1664 | // create three new boundary lines
|
---|
1665 | for (int i=0;i<3;i++) {
|
---|
1666 | BPS[0] = NewPoint;
|
---|
1667 | BPS[1] = OldPoints[i];
|
---|
1668 | NewLines[i] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
|
---|
1669 | LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, NewLines[i])); // no need for check for unique insertion as BPS[0] is definitely a new one
|
---|
1670 | LinesOnBoundaryCount++;
|
---|
1671 | }
|
---|
1672 | // create three new triangle with new point
|
---|
1673 | for (int i=0;i<3;i++) { // find all baselines
|
---|
1674 | BLS[0] = OldLines[i];
|
---|
1675 | int n = 1;
|
---|
1676 | for (int j=0;j<3;j++) {
|
---|
1677 | if (NewLines[j]->IsConnectedTo(BLS[0])) {
|
---|
1678 | if (n>2) {
|
---|
1679 | *out << Verbose(1) << "ERROR: " << BLS[0] << " connects to all of the new lines?!" << endl;
|
---|
1680 | return false;
|
---|
1681 | } else
|
---|
1682 | BLS[n++] = NewLines[j];
|
---|
1683 | }
|
---|
1684 | }
|
---|
1685 | // create the triangle
|
---|
1686 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
|
---|
1687 | TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
|
---|
1688 | TrianglesOnBoundaryCount++;
|
---|
1689 | }
|
---|
1690 | }
|
---|
1691 | } else { // something is wrong with FindClosestTriangleToPoint!
|
---|
1692 | *out << Verbose(1) << "ERROR: The closest triangle did not produce an intersection!" << endl;
|
---|
1693 | return false;
|
---|
1694 | }
|
---|
1695 | }
|
---|
1696 |
|
---|
1697 | // exit
|
---|
1698 | delete(MolCenter);
|
---|
1699 | return true;
|
---|
1700 | };
|
---|
1701 |
|
---|
1702 | /** Goes over all baselines and checks whether adjacent triangles and convex to each other.
|
---|
1703 | * \param *out output stream for debugging
|
---|
1704 | * \return true - all baselines were corrected, false - there are still concave pieces
|
---|
1705 | */
|
---|
1706 | bool Tesselation::CorrectConcaveBaselines(ofstream *out)
|
---|
1707 | {
|
---|
1708 | class BoundaryTriangleSet *triangle[2];
|
---|
1709 | class BoundaryLineSet *OldLines[4], *NewLine;
|
---|
1710 | class BoundaryPointSet *OldPoints[2];
|
---|
1711 | Vector BaseLineNormal;
|
---|
1712 | class BoundaryLineSet *Base = NULL;
|
---|
1713 | int OldTriangles[2], OldBaseLine;
|
---|
1714 | int i;
|
---|
1715 | for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++) {
|
---|
1716 | Base = baseline->second;
|
---|
1717 |
|
---|
1718 | // check convexity
|
---|
1719 | if (Base->CheckConvexityCriterion(out)) { // triangles are convex
|
---|
1720 | *out << Verbose(3) << Base << " has two convex triangles." << endl;
|
---|
1721 | } else { // not convex!
|
---|
1722 | // get the two triangles
|
---|
1723 | i=0;
|
---|
1724 | for(TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++)
|
---|
1725 | triangle[i++] = runner->second;
|
---|
1726 | // gather four endpoints and four lines
|
---|
1727 | for (int j=0;j<4;j++)
|
---|
1728 | OldLines[j] = NULL;
|
---|
1729 | for (int j=0;j<2;j++)
|
---|
1730 | OldPoints[j] = NULL;
|
---|
1731 | i=0;
|
---|
1732 | for (int m=0;m<2;m++) { // go over both triangles
|
---|
1733 | for (int j=0;j<3;j++) { // all of their endpoints and baselines
|
---|
1734 | if (triangle[m]->lines[j] != Base) // pick not the central baseline
|
---|
1735 | OldLines[i++] = triangle[m]->lines[j];
|
---|
1736 | if (!Base->ContainsBoundaryPoint(triangle[m]->endpoints[j])) // and neither of its endpoints
|
---|
1737 | OldPoints[m] = triangle[m]->endpoints[j];
|
---|
1738 | }
|
---|
1739 | }
|
---|
1740 | if (i<4) {
|
---|
1741 | *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
|
---|
1742 | return false;
|
---|
1743 | }
|
---|
1744 | for (int j=0;j<4;j++)
|
---|
1745 | if (OldLines[j] == NULL) {
|
---|
1746 | *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
|
---|
1747 | return false;
|
---|
1748 | }
|
---|
1749 | for (int j=0;j<2;j++)
|
---|
1750 | if (OldPoints[j] == NULL) {
|
---|
1751 | *out << Verbose(1) << "ERROR: We have not gathered enough endpoints!" << endl;
|
---|
1752 | return false;
|
---|
1753 | }
|
---|
1754 |
|
---|
1755 | // remove triangles
|
---|
1756 | for (int j=0;j<2;j++) {
|
---|
1757 | OldTriangles[j] = triangle[j]->Nr;
|
---|
1758 | TrianglesOnBoundary.erase(OldTriangles[j]);
|
---|
1759 | triangle[j] = NULL;
|
---|
1760 | }
|
---|
1761 |
|
---|
1762 | // remove baseline
|
---|
1763 | OldBaseLine = Base->Nr;
|
---|
1764 | LinesOnBoundary.erase(OldBaseLine);
|
---|
1765 | Base = NULL;
|
---|
1766 |
|
---|
1767 | // construct new baseline (with same number as old one)
|
---|
1768 | BPS[0] = OldPoints[0];
|
---|
1769 | BPS[1] = OldPoints[1];
|
---|
1770 | NewLine = new class BoundaryLineSet(BPS, OldBaseLine);
|
---|
1771 | LinesOnBoundary.insert(LinePair(OldBaseLine, NewLine)); // no need for check for unique insertion as NewLine is definitely a new one
|
---|
1772 |
|
---|
1773 | // construct new triangles with flipped baseline
|
---|
1774 | i=-1;
|
---|
1775 | if (BLS[0]->IsConnectedTo(OldLines[2]))
|
---|
1776 | i=2;
|
---|
1777 | if (BLS[0]->IsConnectedTo(OldLines[2]))
|
---|
1778 | i=3;
|
---|
1779 | if (i!=-1) {
|
---|
1780 | BLS[0] = OldLines[0];
|
---|
1781 | BLS[1] = OldLines[i];
|
---|
1782 | BLS[2] = NewLine;
|
---|
1783 | BTS = new class BoundaryTriangleSet(BLS, OldTriangles[0]);
|
---|
1784 | TrianglesOnBoundary.insert(TrianglePair(OldTriangles[0], BTS));
|
---|
1785 |
|
---|
1786 | BLS[0] = (i==2 ? OldLines[3] : OldLines[2]);
|
---|
1787 | BLS[1] = OldLines[1];
|
---|
1788 | BLS[2] = NewLine;
|
---|
1789 | BTS = new class BoundaryTriangleSet(BLS, OldTriangles[1]);
|
---|
1790 | TrianglesOnBoundary.insert(TrianglePair(OldTriangles[1], BTS));
|
---|
1791 | } else {
|
---|
1792 | *out << Verbose(1) << "The four old lines do not connect, something's utterly wrong here!" << endl;
|
---|
1793 | return false;
|
---|
1794 | }
|
---|
1795 | }
|
---|
1796 | }
|
---|
1797 | return true;
|
---|
1798 | };
|
---|
1799 |
|
---|
1800 |
|
---|
1801 | /** States whether point is in- or outside of a tesselated surface.
|
---|
1802 | * \param *pointer point to be checked
|
---|
1803 | * \return true - is inside, false - is outside
|
---|
1804 | */
|
---|
1805 | bool Tesselation::IsInside(Vector *pointer)
|
---|
1806 | {
|
---|
1807 |
|
---|
1808 | // hier kommt dann Saskias Routine hin...
|
---|
1809 |
|
---|
1810 | return true;
|
---|
1811 | };
|
---|
1812 |
|
---|
1813 | /** Finds the closest triangle to a given point.
|
---|
1814 | * \param *out output stream for debugging
|
---|
1815 | * \param *x second endpoint of line
|
---|
1816 | * \return pointer triangle that is closest, NULL if none was found
|
---|
1817 | */
|
---|
1818 | class BoundaryTriangleSet * Tesselation::FindClosestTriangleToPoint(ofstream *out, Vector *x)
|
---|
1819 | {
|
---|
1820 | class BoundaryTriangleSet *triangle = NULL;
|
---|
1821 |
|
---|
1822 | // hier kommt dann Saskias Routine hin...
|
---|
1823 |
|
---|
1824 | return triangle;
|
---|
1825 | };
|
---|
1826 |
|
---|
1827 | /** Adds an atom to the tesselation::PointsOnBoundary list.
|
---|
1828 | * \param *Walker atom to add
|
---|
1829 | */
|
---|
1830 | void
|
---|
1831 | Tesselation::AddPoint(atom *Walker)
|
---|
1832 | {
|
---|
1833 | PointTestPair InsertUnique;
|
---|
1834 | BPS[0] = new class BoundaryPointSet(Walker);
|
---|
1835 | InsertUnique = PointsOnBoundary.insert(PointPair(Walker->nr, BPS[0]));
|
---|
1836 | if (InsertUnique.second) // if new point was not present before, increase counter
|
---|
1837 | PointsOnBoundaryCount++;
|
---|
1838 | else {
|
---|
1839 | delete(BPS[0]);
|
---|
1840 | BPS[0] = NULL;
|
---|
1841 | }
|
---|
1842 | }
|
---|
1843 | ;
|
---|
1844 |
|
---|
1845 | /** Adds point to Tesselation::PointsOnBoundary if not yet present.
|
---|
1846 | * Tesselation::TPS is set to either this new BoundaryPointSet or to the existing one of not unique.
|
---|
1847 | * @param Candidate point to add
|
---|
1848 | * @param n index for this point in Tesselation::TPS array
|
---|
1849 | */
|
---|
1850 | void
|
---|
1851 | Tesselation::AddTrianglePoint(atom* Candidate, int n)
|
---|
1852 | {
|
---|
1853 | PointTestPair InsertUnique;
|
---|
1854 | TPS[n] = new class BoundaryPointSet(Candidate);
|
---|
1855 | InsertUnique = PointsOnBoundary.insert(PointPair(Candidate->nr, TPS[n]));
|
---|
1856 | if (InsertUnique.second) { // if new point was not present before, increase counter
|
---|
1857 | PointsOnBoundaryCount++;
|
---|
1858 | } else {
|
---|
1859 | delete TPS[n];
|
---|
1860 | cout << Verbose(3) << "Atom " << *((InsertUnique.first)->second->node) << " is already present in PointsOnBoundary." << endl;
|
---|
1861 | TPS[n] = (InsertUnique.first)->second;
|
---|
1862 | }
|
---|
1863 | }
|
---|
1864 | ;
|
---|
1865 |
|
---|
1866 | /** Function tries to add line from current Points in BPS to BoundaryLineSet.
|
---|
1867 | * If successful it raises the line count and inserts the new line into the BLS,
|
---|
1868 | * if unsuccessful, it writes the line which had been present into the BLS, deleting the new constructed one.
|
---|
1869 | * @param *a first endpoint
|
---|
1870 | * @param *b second endpoint
|
---|
1871 | * @param n index of Tesselation::BLS giving the line with both endpoints
|
---|
1872 | */
|
---|
1873 | void Tesselation::AddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n) {
|
---|
1874 | bool insertNewLine = true;
|
---|
1875 |
|
---|
1876 | if (a->lines.find(b->node->nr) != a->lines.end()) {
|
---|
1877 | LineMap::iterator FindLine;
|
---|
1878 | pair<LineMap::iterator,LineMap::iterator> FindPair;
|
---|
1879 | FindPair = a->lines.equal_range(b->node->nr);
|
---|
1880 |
|
---|
1881 | for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
|
---|
1882 | // If there is a line with less than two attached triangles, we don't need a new line.
|
---|
1883 | if (FindLine->second->TrianglesCount < 2) {
|
---|
1884 | insertNewLine = false;
|
---|
1885 | cout << Verbose(3) << "Using existing line " << *FindLine->second << endl;
|
---|
1886 |
|
---|
1887 | BPS[0] = FindLine->second->endpoints[0];
|
---|
1888 | BPS[1] = FindLine->second->endpoints[1];
|
---|
1889 | BLS[n] = FindLine->second;
|
---|
1890 |
|
---|
1891 | break;
|
---|
1892 | }
|
---|
1893 | }
|
---|
1894 | }
|
---|
1895 |
|
---|
1896 | if (insertNewLine) {
|
---|
1897 | AlwaysAddTriangleLine(a, b, n);
|
---|
1898 | }
|
---|
1899 | }
|
---|
1900 | ;
|
---|
1901 |
|
---|
1902 | /**
|
---|
1903 | * Adds lines from each of the current points in the BPS to BoundaryLineSet.
|
---|
1904 | * Raises the line count and inserts the new line into the BLS.
|
---|
1905 | *
|
---|
1906 | * @param *a first endpoint
|
---|
1907 | * @param *b second endpoint
|
---|
1908 | * @param n index of Tesselation::BLS giving the line with both endpoints
|
---|
1909 | */
|
---|
1910 | void Tesselation::AlwaysAddTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n)
|
---|
1911 | {
|
---|
1912 | cout << Verbose(3) << "Adding line between " << *(a->node) << " and " << *(b->node) << "." << endl;
|
---|
1913 | BPS[0] = a;
|
---|
1914 | BPS[1] = b;
|
---|
1915 | BLS[n] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); // this also adds the line to the local maps
|
---|
1916 | // add line to global map
|
---|
1917 | LinesOnBoundary.insert(LinePair(LinesOnBoundaryCount, BLS[n]));
|
---|
1918 | // increase counter
|
---|
1919 | LinesOnBoundaryCount++;
|
---|
1920 | };
|
---|
1921 |
|
---|
1922 | /** Function tries to add Triangle just created to Triangle and remarks if already existent (Failure of algorithm).
|
---|
1923 | * Furthermore it adds the triangle to all of its lines, in order to recognize those which are saturated later.
|
---|
1924 | */
|
---|
1925 | void
|
---|
1926 | Tesselation::AddTriangle()
|
---|
1927 | {
|
---|
1928 | cout << Verbose(1) << "Adding triangle to global TrianglesOnBoundary map." << endl;
|
---|
1929 |
|
---|
1930 | // add triangle to global map
|
---|
1931 | TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
|
---|
1932 | TrianglesOnBoundaryCount++;
|
---|
1933 |
|
---|
1934 | // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
|
---|
1935 | }
|
---|
1936 | ;
|
---|
1937 |
|
---|
1938 |
|
---|
1939 | double det_get(gsl_matrix *A, int inPlace) {
|
---|
1940 | /*
|
---|
1941 | inPlace = 1 => A is replaced with the LU decomposed copy.
|
---|
1942 | inPlace = 0 => A is retained, and a copy is used for LU.
|
---|
1943 | */
|
---|
1944 |
|
---|
1945 | double det;
|
---|
1946 | int signum;
|
---|
1947 | gsl_permutation *p = gsl_permutation_alloc(A->size1);
|
---|
1948 | gsl_matrix *tmpA;
|
---|
1949 |
|
---|
1950 | if (inPlace)
|
---|
1951 | tmpA = A;
|
---|
1952 | else {
|
---|
1953 | gsl_matrix *tmpA = gsl_matrix_alloc(A->size1, A->size2);
|
---|
1954 | gsl_matrix_memcpy(tmpA , A);
|
---|
1955 | }
|
---|
1956 |
|
---|
1957 |
|
---|
1958 | gsl_linalg_LU_decomp(tmpA , p , &signum);
|
---|
1959 | det = gsl_linalg_LU_det(tmpA , signum);
|
---|
1960 | gsl_permutation_free(p);
|
---|
1961 | if (! inPlace)
|
---|
1962 | gsl_matrix_free(tmpA);
|
---|
1963 |
|
---|
1964 | return det;
|
---|
1965 | };
|
---|
1966 |
|
---|
1967 | void get_sphere(Vector *center, Vector &a, Vector &b, Vector &c, double RADIUS)
|
---|
1968 | {
|
---|
1969 | gsl_matrix *A = gsl_matrix_calloc(3,3);
|
---|
1970 | double m11, m12, m13, m14;
|
---|
1971 |
|
---|
1972 | for(int i=0;i<3;i++) {
|
---|
1973 | gsl_matrix_set(A, i, 0, a.x[i]);
|
---|
1974 | gsl_matrix_set(A, i, 1, b.x[i]);
|
---|
1975 | gsl_matrix_set(A, i, 2, c.x[i]);
|
---|
1976 | }
|
---|
1977 | m11 = det_get(A, 1);
|
---|
1978 |
|
---|
1979 | for(int i=0;i<3;i++) {
|
---|
1980 | gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]);
|
---|
1981 | gsl_matrix_set(A, i, 1, b.x[i]);
|
---|
1982 | gsl_matrix_set(A, i, 2, c.x[i]);
|
---|
1983 | }
|
---|
1984 | m12 = det_get(A, 1);
|
---|
1985 |
|
---|
1986 | for(int i=0;i<3;i++) {
|
---|
1987 | gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]);
|
---|
1988 | gsl_matrix_set(A, i, 1, a.x[i]);
|
---|
1989 | gsl_matrix_set(A, i, 2, c.x[i]);
|
---|
1990 | }
|
---|
1991 | m13 = det_get(A, 1);
|
---|
1992 |
|
---|
1993 | for(int i=0;i<3;i++) {
|
---|
1994 | gsl_matrix_set(A, i, 0, a.x[i]*a.x[i] + b.x[i]*b.x[i] + c.x[i]*c.x[i]);
|
---|
1995 | gsl_matrix_set(A, i, 1, a.x[i]);
|
---|
1996 | gsl_matrix_set(A, i, 2, b.x[i]);
|
---|
1997 | }
|
---|
1998 | m14 = det_get(A, 1);
|
---|
1999 |
|
---|
2000 | if (fabs(m11) < MYEPSILON)
|
---|
2001 | cerr << "ERROR: three points are colinear." << endl;
|
---|
2002 |
|
---|
2003 | center->x[0] = 0.5 * m12/ m11;
|
---|
2004 | center->x[1] = -0.5 * m13/ m11;
|
---|
2005 | center->x[2] = 0.5 * m14/ m11;
|
---|
2006 |
|
---|
2007 | if (fabs(a.Distance(center) - RADIUS) > MYEPSILON)
|
---|
2008 | cerr << "ERROR: The given center is further way by " << fabs(a.Distance(center) - RADIUS) << " from a than RADIUS." << endl;
|
---|
2009 |
|
---|
2010 | gsl_matrix_free(A);
|
---|
2011 | };
|
---|
2012 |
|
---|
2013 |
|
---|
2014 |
|
---|
2015 | /**
|
---|
2016 | * Function returns center of sphere with RADIUS, which rests on points a, b, c
|
---|
2017 | * @param Center this vector will be used for return
|
---|
2018 | * @param a vector first point of triangle
|
---|
2019 | * @param b vector second point of triangle
|
---|
2020 | * @param c vector third point of triangle
|
---|
2021 | * @param *Umkreismittelpunkt new cneter point of circumference
|
---|
2022 | * @param Direction vector indicates up/down
|
---|
2023 | * @param AlternativeDirection vecotr, needed in case the triangles have 90 deg angle
|
---|
2024 | * @param Halfplaneindicator double indicates whether Direction is up or down
|
---|
2025 | * @param AlternativeIndicator doube indicates in case of orthogonal triangles which direction of AlternativeDirection is suitable
|
---|
2026 | * @param alpha double angle at a
|
---|
2027 | * @param beta double, angle at b
|
---|
2028 | * @param gamma, double, angle at c
|
---|
2029 | * @param Radius, double
|
---|
2030 | * @param Umkreisradius double radius of circumscribing circle
|
---|
2031 | */
|
---|
2032 | void Get_center_of_sphere(Vector* Center, Vector a, Vector b, Vector c, Vector *NewUmkreismittelpunkt, Vector* Direction, Vector* AlternativeDirection,
|
---|
2033 | double HalfplaneIndicator, double AlternativeIndicator, double alpha, double beta, double gamma, double RADIUS, double Umkreisradius)
|
---|
2034 | {
|
---|
2035 | Vector TempNormal, helper;
|
---|
2036 | double Restradius;
|
---|
2037 | Vector OtherCenter;
|
---|
2038 | cout << Verbose(3) << "Begin of Get_center_of_sphere.\n";
|
---|
2039 | Center->Zero();
|
---|
2040 | helper.CopyVector(&a);
|
---|
2041 | helper.Scale(sin(2.*alpha));
|
---|
2042 | Center->AddVector(&helper);
|
---|
2043 | helper.CopyVector(&b);
|
---|
2044 | helper.Scale(sin(2.*beta));
|
---|
2045 | Center->AddVector(&helper);
|
---|
2046 | helper.CopyVector(&c);
|
---|
2047 | helper.Scale(sin(2.*gamma));
|
---|
2048 | Center->AddVector(&helper);
|
---|
2049 | //*Center = a * sin(2.*alpha) + b * sin(2.*beta) + c * sin(2.*gamma) ;
|
---|
2050 | Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma)));
|
---|
2051 | NewUmkreismittelpunkt->CopyVector(Center);
|
---|
2052 | cout << Verbose(4) << "Center of new circumference is " << *NewUmkreismittelpunkt << ".\n";
|
---|
2053 | // Here we calculated center of circumscribing circle, using barycentric coordinates
|
---|
2054 | cout << Verbose(4) << "Center of circumference is " << *Center << " in direction " << *Direction << ".\n";
|
---|
2055 |
|
---|
2056 | TempNormal.CopyVector(&a);
|
---|
2057 | TempNormal.SubtractVector(&b);
|
---|
2058 | helper.CopyVector(&a);
|
---|
2059 | helper.SubtractVector(&c);
|
---|
2060 | TempNormal.VectorProduct(&helper);
|
---|
2061 | if (fabs(HalfplaneIndicator) < MYEPSILON)
|
---|
2062 | {
|
---|
2063 | if ((TempNormal.ScalarProduct(AlternativeDirection) <0 and AlternativeIndicator >0) or (TempNormal.ScalarProduct(AlternativeDirection) >0 and AlternativeIndicator <0))
|
---|
2064 | {
|
---|
2065 | TempNormal.Scale(-1);
|
---|
2066 | }
|
---|
2067 | }
|
---|
2068 | else
|
---|
2069 | {
|
---|
2070 | if (TempNormal.ScalarProduct(Direction)<0 && HalfplaneIndicator >0 || TempNormal.ScalarProduct(Direction)>0 && HalfplaneIndicator<0)
|
---|
2071 | {
|
---|
2072 | TempNormal.Scale(-1);
|
---|
2073 | }
|
---|
2074 | }
|
---|
2075 |
|
---|
2076 | TempNormal.Normalize();
|
---|
2077 | Restradius = sqrt(RADIUS*RADIUS - Umkreisradius*Umkreisradius);
|
---|
2078 | cout << Verbose(4) << "Height of center of circumference to center of sphere is " << Restradius << ".\n";
|
---|
2079 | TempNormal.Scale(Restradius);
|
---|
2080 | cout << Verbose(4) << "Shift vector to sphere of circumference is " << TempNormal << ".\n";
|
---|
2081 |
|
---|
2082 | Center->AddVector(&TempNormal);
|
---|
2083 | cout << Verbose(0) << "Center of sphere of circumference is " << *Center << ".\n";
|
---|
2084 | get_sphere(&OtherCenter, a, b, c, RADIUS);
|
---|
2085 | cout << Verbose(0) << "OtherCenter of sphere of circumference is " << OtherCenter << ".\n";
|
---|
2086 | cout << Verbose(3) << "End of Get_center_of_sphere.\n";
|
---|
2087 | };
|
---|
2088 |
|
---|
2089 |
|
---|
2090 | /** Constructs the center of the circumcircle defined by three points \a *a, \a *b and \a *c.
|
---|
2091 | * \param *Center new center on return
|
---|
2092 | * \param *a first point
|
---|
2093 | * \param *b second point
|
---|
2094 | * \param *c third point
|
---|
2095 | */
|
---|
2096 | void GetCenterofCircumcircle(Vector *Center, Vector *a, Vector *b, Vector *c)
|
---|
2097 | {
|
---|
2098 | Vector helper;
|
---|
2099 | double alpha, beta, gamma;
|
---|
2100 | Vector SideA, SideB, SideC;
|
---|
2101 | SideA.CopyVector(b);
|
---|
2102 | SideA.SubtractVector(c);
|
---|
2103 | SideB.CopyVector(c);
|
---|
2104 | SideB.SubtractVector(a);
|
---|
2105 | SideC.CopyVector(a);
|
---|
2106 | SideC.SubtractVector(b);
|
---|
2107 | alpha = M_PI - SideB.Angle(&SideC);
|
---|
2108 | beta = M_PI - SideC.Angle(&SideA);
|
---|
2109 | gamma = M_PI - SideA.Angle(&SideB);
|
---|
2110 | //cout << Verbose(3) << "INFO: alpha = " << alpha/M_PI*180. << ", beta = " << beta/M_PI*180. << ", gamma = " << gamma/M_PI*180. << "." << endl;
|
---|
2111 | if (fabs(M_PI - alpha - beta - gamma) > HULLEPSILON)
|
---|
2112 | cerr << "GetCenterofCircumcircle: Sum of angles " << (alpha+beta+gamma)/M_PI*180. << " > 180 degrees by " << fabs(M_PI - alpha - beta - gamma)/M_PI*180. << "!" << endl;
|
---|
2113 |
|
---|
2114 | Center->Zero();
|
---|
2115 | helper.CopyVector(a);
|
---|
2116 | helper.Scale(sin(2.*alpha));
|
---|
2117 | Center->AddVector(&helper);
|
---|
2118 | helper.CopyVector(b);
|
---|
2119 | helper.Scale(sin(2.*beta));
|
---|
2120 | Center->AddVector(&helper);
|
---|
2121 | helper.CopyVector(c);
|
---|
2122 | helper.Scale(sin(2.*gamma));
|
---|
2123 | Center->AddVector(&helper);
|
---|
2124 | Center->Scale(1./(sin(2.*alpha) + sin(2.*beta) + sin(2.*gamma)));
|
---|
2125 | };
|
---|
2126 |
|
---|
2127 | /** 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.
|
---|
2128 | * Test whether the \a NewSphereCenter is really on the given plane and in distance \a CircleRadius from \a CircleCenter.
|
---|
2129 | * It calculates the angle, making it unique on [0,2.*M_PI) by comparing to SearchDirection.
|
---|
2130 | * 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).
|
---|
2131 | * \param CircleCenter Center of the parameter circle
|
---|
2132 | * \param CirclePlaneNormal normal vector to plane of the parameter circle
|
---|
2133 | * \param CircleRadius radius of the parameter circle
|
---|
2134 | * \param NewSphereCenter new center of a circumcircle
|
---|
2135 | * \param OldSphereCenter old center of a circumcircle, defining the zero "path length" on the parameter circle
|
---|
2136 | * \param NormalVector normal vector
|
---|
2137 | * \param SearchDirection search direction to make angle unique on return.
|
---|
2138 | * \return Angle between \a NewSphereCenter and \a OldSphereCenter relative to \a CircleCenter, 2.*M_PI if one test fails
|
---|
2139 | */
|
---|
2140 | double GetPathLengthonCircumCircle(Vector &CircleCenter, Vector &CirclePlaneNormal, double CircleRadius, Vector &NewSphereCenter, Vector &OldSphereCenter, Vector &NormalVector, Vector &SearchDirection)
|
---|
2141 | {
|
---|
2142 | Vector helper;
|
---|
2143 | double radius, alpha;
|
---|
2144 |
|
---|
2145 | helper.CopyVector(&NewSphereCenter);
|
---|
2146 | // test whether new center is on the parameter circle's plane
|
---|
2147 | if (fabs(helper.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
|
---|
2148 | cerr << "ERROR: Something's very wrong here: NewSphereCenter is not on the band's plane as desired by " <<fabs(helper.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
|
---|
2149 | helper.ProjectOntoPlane(&CirclePlaneNormal);
|
---|
2150 | }
|
---|
2151 | radius = helper.ScalarProduct(&helper);
|
---|
2152 | // test whether the new center vector has length of CircleRadius
|
---|
2153 | if (fabs(radius - CircleRadius) > HULLEPSILON)
|
---|
2154 | cerr << Verbose(1) << "ERROR: The projected center of the new sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
|
---|
2155 | alpha = helper.Angle(&OldSphereCenter);
|
---|
2156 | // make the angle unique by checking the halfplanes/search direction
|
---|
2157 | if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON) // acos is not unique on [0, 2.*M_PI), hence extra check to decide between two half intervals
|
---|
2158 | alpha = 2.*M_PI - alpha;
|
---|
2159 | //cout << Verbose(2) << "INFO: RelativeNewSphereCenter is " << helper << ", RelativeOldSphereCenter is " << OldSphereCenter << " and resulting angle is " << alpha << "." << endl;
|
---|
2160 | radius = helper.Distance(&OldSphereCenter);
|
---|
2161 | helper.ProjectOntoPlane(&NormalVector);
|
---|
2162 | // check whether new center is somewhat away or at least right over the current baseline to prevent intersecting triangles
|
---|
2163 | if ((radius > HULLEPSILON) || (helper.Norm() < HULLEPSILON)) {
|
---|
2164 | //cout << Verbose(2) << "INFO: Distance between old and new center is " << radius << " and between new center and baseline center is " << helper.Norm() << "." << endl;
|
---|
2165 | return alpha;
|
---|
2166 | } else {
|
---|
2167 | //cout << Verbose(1) << "INFO: NewSphereCenter " << helper << " is too close to OldSphereCenter" << OldSphereCenter << "." << endl;
|
---|
2168 | return 2.*M_PI;
|
---|
2169 | }
|
---|
2170 | };
|
---|
2171 |
|
---|
2172 |
|
---|
2173 | /** Checks whether the triangle consisting of the three atoms is already present.
|
---|
2174 | * Searches for the points in Tesselation::PointsOnBoundary and checks their
|
---|
2175 | * lines. If any of the three edges already has two triangles attached, false is
|
---|
2176 | * returned.
|
---|
2177 | * \param *out output stream for debugging
|
---|
2178 | * \param *Candidates endpoints of the triangle candidate
|
---|
2179 | * \return integer 0 if no triangle exists, 1 if one triangle exists, 2 if two
|
---|
2180 | * triangles exist which is the maximum for three points
|
---|
2181 | */
|
---|
2182 | int Tesselation::CheckPresenceOfTriangle(ofstream *out, atom *Candidates[3]) {
|
---|
2183 | LineMap::iterator FindLine;
|
---|
2184 | PointMap::iterator FindPoint;
|
---|
2185 | TriangleMap::iterator FindTriangle;
|
---|
2186 | int adjacentTriangleCount = 0;
|
---|
2187 | class BoundaryPointSet *Points[3];
|
---|
2188 |
|
---|
2189 | //*out << Verbose(2) << "Begin of CheckPresenceOfTriangle" << endl;
|
---|
2190 | // builds a triangle point set (Points) of the end points
|
---|
2191 | for (int i = 0; i < 3; i++) {
|
---|
2192 | FindPoint = PointsOnBoundary.find(Candidates[i]->nr);
|
---|
2193 | if (FindPoint != PointsOnBoundary.end()) {
|
---|
2194 | Points[i] = FindPoint->second;
|
---|
2195 | } else {
|
---|
2196 | Points[i] = NULL;
|
---|
2197 | }
|
---|
2198 | }
|
---|
2199 |
|
---|
2200 | // checks lines between the points in the Points for their adjacent triangles
|
---|
2201 | for (int i = 0; i < 3; i++) {
|
---|
2202 | if (Points[i] != NULL) {
|
---|
2203 | for (int j = i; j < 3; j++) {
|
---|
2204 | if (Points[j] != NULL) {
|
---|
2205 | FindLine = Points[i]->lines.find(Points[j]->node->nr);
|
---|
2206 | if (FindLine != Points[i]->lines.end()) {
|
---|
2207 | for (; FindLine->first == Points[j]->node->nr; FindLine++) {
|
---|
2208 | FindTriangle = FindLine->second->triangles.begin();
|
---|
2209 | for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
|
---|
2210 | if ((
|
---|
2211 | (FindTriangle->second->endpoints[0] == Points[0])
|
---|
2212 | || (FindTriangle->second->endpoints[0] == Points[1])
|
---|
2213 | || (FindTriangle->second->endpoints[0] == Points[2])
|
---|
2214 | ) && (
|
---|
2215 | (FindTriangle->second->endpoints[1] == Points[0])
|
---|
2216 | || (FindTriangle->second->endpoints[1] == Points[1])
|
---|
2217 | || (FindTriangle->second->endpoints[1] == Points[2])
|
---|
2218 | ) && (
|
---|
2219 | (FindTriangle->second->endpoints[2] == Points[0])
|
---|
2220 | || (FindTriangle->second->endpoints[2] == Points[1])
|
---|
2221 | || (FindTriangle->second->endpoints[2] == Points[2])
|
---|
2222 | )
|
---|
2223 | ) {
|
---|
2224 | adjacentTriangleCount++;
|
---|
2225 | }
|
---|
2226 | }
|
---|
2227 | }
|
---|
2228 | // Only one of the triangle lines must be considered for the triangle count.
|
---|
2229 | *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
|
---|
2230 | return adjacentTriangleCount;
|
---|
2231 |
|
---|
2232 | }
|
---|
2233 | }
|
---|
2234 | }
|
---|
2235 | }
|
---|
2236 | }
|
---|
2237 |
|
---|
2238 | *out << Verbose(2) << "Found " << adjacentTriangleCount << " adjacent triangles for the point set." << endl;
|
---|
2239 | return adjacentTriangleCount;
|
---|
2240 | };
|
---|
2241 |
|
---|
2242 | /** This recursive function finds a third point, to form a triangle with two given ones.
|
---|
2243 | * Note that this function is for the starting triangle.
|
---|
2244 | * The idea is as follows: A sphere with fixed radius is (almost) uniquely defined in space by three points
|
---|
2245 | * that sit on its boundary. Hence, when two points are given and we look for the (next) third point, then
|
---|
2246 | * the center of the sphere is still fixed up to a single parameter. The band of possible values
|
---|
2247 | * describes a circle in 3D-space. The old center of the sphere for the current base triangle gives
|
---|
2248 | * us the "null" on this circle, the new center of the candidate point will be some way along this
|
---|
2249 | * circle. The shorter the way the better is the candidate. Note that the direction is clearly given
|
---|
2250 | * by the normal vector of the base triangle that always points outwards by construction.
|
---|
2251 | * Hence, we construct a Center of this circle which sits right in the middle of the current base line.
|
---|
2252 | * We construct the normal vector that defines the plane this circle lies in, it is just in the
|
---|
2253 | * direction of the baseline. And finally, we need the radius of the circle, which is given by the rest
|
---|
2254 | * with respect to the length of the baseline and the sphere's fixed \a RADIUS.
|
---|
2255 | * Note that there is one difficulty: The circumcircle is uniquely defined, but for the circumsphere's center
|
---|
2256 | * there are two possibilities which becomes clear from the construction as seen below. Hence, we must check
|
---|
2257 | * both.
|
---|
2258 | * Note also that the acos() function is not unique on [0, 2.*M_PI). Hence, we need an additional check
|
---|
2259 | * to decide for one of the two possible angles. Therefore we need a SearchDirection and to make this check
|
---|
2260 | * sensible we need OldSphereCenter to be orthogonal to it. Either we construct SearchDirection orthogonal
|
---|
2261 | * right away, or -- what we do here -- we rotate the relative sphere centers such that this orthogonality
|
---|
2262 | * holds. Then, the normalized projection onto the SearchDirection is either +1 or -1 and thus states whether
|
---|
2263 | * the angle is uniquely in either (0,M_PI] or [M_PI, 2.*M_PI).
|
---|
2264 | * @param NormalVector normal direction of the base triangle (here the unit axis vector, \sa Find_starting_triangle())
|
---|
2265 | * @param SearchDirection general direction where to search for the next point, relative to center of BaseLine
|
---|
2266 | * @param OldSphereCenter center of sphere for base triangle, relative to center of BaseLine, giving null angle for the parameter circle
|
---|
2267 | * @param BaseLine BoundaryLineSet with the current base line
|
---|
2268 | * @param ThirdNode third atom to avoid in search
|
---|
2269 | * @param candidates list of equally good candidates to return
|
---|
2270 | * @param ShortestAngle the current path length on this circle band for the current Opt_Candidate
|
---|
2271 | * @param RADIUS radius of sphere
|
---|
2272 | * @param *LC LinkedCell structure with neighbouring atoms
|
---|
2273 | */
|
---|
2274 | void Find_third_point_for_Tesselation(
|
---|
2275 | Vector NormalVector, Vector SearchDirection, Vector OldSphereCenter,
|
---|
2276 | class BoundaryLineSet *BaseLine, atom *ThirdNode, CandidateList* &candidates,
|
---|
2277 | double *ShortestAngle, const double RADIUS, LinkedCell *LC
|
---|
2278 | ) {
|
---|
2279 | Vector CircleCenter; // center of the circle, i.e. of the band of sphere's centers
|
---|
2280 | Vector CirclePlaneNormal; // normal vector defining the plane this circle lives in
|
---|
2281 | Vector SphereCenter;
|
---|
2282 | Vector NewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, first possibility
|
---|
2283 | Vector OtherNewSphereCenter; // center of the sphere defined by the two points of BaseLine and the one of Candidate, second possibility
|
---|
2284 | Vector NewNormalVector; // normal vector of the Candidate's triangle
|
---|
2285 | Vector helper, OptCandidateCenter, OtherOptCandidateCenter;
|
---|
2286 | LinkedAtoms *List = NULL;
|
---|
2287 | double CircleRadius; // radius of this circle
|
---|
2288 | double radius;
|
---|
2289 | double alpha, Otheralpha; // angles (i.e. parameter for the circle).
|
---|
2290 | int N[NDIM], Nlower[NDIM], Nupper[NDIM];
|
---|
2291 | atom *Candidate = NULL;
|
---|
2292 | CandidateForTesselation *optCandidate = NULL;
|
---|
2293 |
|
---|
2294 | cout << Verbose(1) << "Begin of Find_third_point_for_Tesselation" << endl;
|
---|
2295 |
|
---|
2296 | //cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
|
---|
2297 |
|
---|
2298 | // construct center of circle
|
---|
2299 | CircleCenter.CopyVector(&(BaseLine->endpoints[0]->node->x));
|
---|
2300 | CircleCenter.AddVector(&BaseLine->endpoints[1]->node->x);
|
---|
2301 | CircleCenter.Scale(0.5);
|
---|
2302 |
|
---|
2303 | // construct normal vector of circle
|
---|
2304 | CirclePlaneNormal.CopyVector(&BaseLine->endpoints[0]->node->x);
|
---|
2305 | CirclePlaneNormal.SubtractVector(&BaseLine->endpoints[1]->node->x);
|
---|
2306 |
|
---|
2307 | // calculate squared radius atom *ThirdNode,f circle
|
---|
2308 | radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
|
---|
2309 | if (radius/4. < RADIUS*RADIUS) {
|
---|
2310 | CircleRadius = RADIUS*RADIUS - radius/4.;
|
---|
2311 | CirclePlaneNormal.Normalize();
|
---|
2312 | //cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
|
---|
2313 |
|
---|
2314 | // test whether old center is on the band's plane
|
---|
2315 | if (fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) > HULLEPSILON) {
|
---|
2316 | cerr << "ERROR: Something's very wrong here: OldSphereCenter is not on the band's plane as desired by " << fabs(OldSphereCenter.ScalarProduct(&CirclePlaneNormal)) << "!" << endl;
|
---|
2317 | OldSphereCenter.ProjectOntoPlane(&CirclePlaneNormal);
|
---|
2318 | }
|
---|
2319 | radius = OldSphereCenter.ScalarProduct(&OldSphereCenter);
|
---|
2320 | if (fabs(radius - CircleRadius) < HULLEPSILON) {
|
---|
2321 |
|
---|
2322 | // check SearchDirection
|
---|
2323 | //cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
|
---|
2324 | if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) { // rotated the wrong way!
|
---|
2325 | cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are not orthogonal!" << endl;
|
---|
2326 | }
|
---|
2327 |
|
---|
2328 | // get cell for the starting atom
|
---|
2329 | if (LC->SetIndexToVector(&CircleCenter)) {
|
---|
2330 | for(int i=0;i<NDIM;i++) // store indices of this cell
|
---|
2331 | N[i] = LC->n[i];
|
---|
2332 | //cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
|
---|
2333 | } else {
|
---|
2334 | cerr << "ERROR: Vector " << CircleCenter << " is outside of LinkedCell's bounding box." << endl;
|
---|
2335 | return;
|
---|
2336 | }
|
---|
2337 | // then go through the current and all neighbouring cells and check the contained atoms for possible candidates
|
---|
2338 | //cout << Verbose(2) << "LC Intervals:";
|
---|
2339 | for (int i=0;i<NDIM;i++) {
|
---|
2340 | Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
|
---|
2341 | Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
|
---|
2342 | //cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
|
---|
2343 | }
|
---|
2344 | //cout << endl;
|
---|
2345 | for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
|
---|
2346 | for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
|
---|
2347 | for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
|
---|
2348 | List = LC->GetCurrentCell();
|
---|
2349 | //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
|
---|
2350 | if (List != NULL) {
|
---|
2351 | for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
|
---|
2352 | Candidate = (*Runner);
|
---|
2353 |
|
---|
2354 | // check for three unique points
|
---|
2355 | //cout << Verbose(2) << "INFO: Current Candidate is " << *Candidate << " at " << Candidate->x << "." << endl;
|
---|
2356 | if ((Candidate != BaseLine->endpoints[0]->node) && (Candidate != BaseLine->endpoints[1]->node) ){
|
---|
2357 |
|
---|
2358 | // construct both new centers
|
---|
2359 | GetCenterofCircumcircle(&NewSphereCenter, &(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x));
|
---|
2360 | OtherNewSphereCenter.CopyVector(&NewSphereCenter);
|
---|
2361 |
|
---|
2362 | if ((NewNormalVector.MakeNormalVector(&(BaseLine->endpoints[0]->node->x), &(BaseLine->endpoints[1]->node->x), &(Candidate->x)))
|
---|
2363 | && (fabs(NewNormalVector.ScalarProduct(&NewNormalVector)) > HULLEPSILON)
|
---|
2364 | ) {
|
---|
2365 | helper.CopyVector(&NewNormalVector);
|
---|
2366 | //cout << Verbose(2) << "INFO: NewNormalVector is " << NewNormalVector << "." << endl;
|
---|
2367 | radius = BaseLine->endpoints[0]->node->x.DistanceSquared(&NewSphereCenter);
|
---|
2368 | if (radius < RADIUS*RADIUS) {
|
---|
2369 | helper.Scale(sqrt(RADIUS*RADIUS - radius));
|
---|
2370 | //cout << Verbose(2) << "INFO: Distance of NewCircleCenter to NewSphereCenter is " << helper.Norm() << " with sphere radius " << RADIUS << "." << endl;
|
---|
2371 | NewSphereCenter.AddVector(&helper);
|
---|
2372 | NewSphereCenter.SubtractVector(&CircleCenter);
|
---|
2373 | //cout << Verbose(2) << "INFO: NewSphereCenter is at " << NewSphereCenter << "." << endl;
|
---|
2374 |
|
---|
2375 | // OtherNewSphereCenter is created by the same vector just in the other direction
|
---|
2376 | helper.Scale(-1.);
|
---|
2377 | OtherNewSphereCenter.AddVector(&helper);
|
---|
2378 | OtherNewSphereCenter.SubtractVector(&CircleCenter);
|
---|
2379 | //cout << Verbose(2) << "INFO: OtherNewSphereCenter is at " << OtherNewSphereCenter << "." << endl;
|
---|
2380 |
|
---|
2381 | alpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, NewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
|
---|
2382 | Otheralpha = GetPathLengthonCircumCircle(CircleCenter, CirclePlaneNormal, CircleRadius, OtherNewSphereCenter, OldSphereCenter, NormalVector, SearchDirection);
|
---|
2383 | alpha = min(alpha, Otheralpha);
|
---|
2384 | // if there is a better candidate, drop the current list and add the new candidate
|
---|
2385 | // otherwise ignore the new candidate and keep the list
|
---|
2386 | if (*ShortestAngle > (alpha - HULLEPSILON)) {
|
---|
2387 | optCandidate = new CandidateForTesselation(Candidate, BaseLine, OptCandidateCenter, OtherOptCandidateCenter);
|
---|
2388 | if (fabs(alpha - Otheralpha) > MYEPSILON) {
|
---|
2389 | optCandidate->OptCenter.CopyVector(&NewSphereCenter);
|
---|
2390 | optCandidate->OtherOptCenter.CopyVector(&OtherNewSphereCenter);
|
---|
2391 | } else {
|
---|
2392 | optCandidate->OptCenter.CopyVector(&OtherNewSphereCenter);
|
---|
2393 | optCandidate->OtherOptCenter.CopyVector(&NewSphereCenter);
|
---|
2394 | }
|
---|
2395 | // if there is an equal candidate, add it to the list without clearing the list
|
---|
2396 | if ((*ShortestAngle - HULLEPSILON) < alpha) {
|
---|
2397 | candidates->push_back(optCandidate);
|
---|
2398 | cout << Verbose(2) << "ACCEPT: We have found an equally good candidate: " << *(optCandidate->point) << " with "
|
---|
2399 | << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
|
---|
2400 | } else {
|
---|
2401 | // remove all candidates from the list and then the list itself
|
---|
2402 | class CandidateForTesselation *remover = NULL;
|
---|
2403 | for (CandidateList::iterator it = candidates->begin(); it != candidates->end(); ++it) {
|
---|
2404 | remover = *it;
|
---|
2405 | delete(remover);
|
---|
2406 | }
|
---|
2407 | candidates->clear();
|
---|
2408 | candidates->push_back(optCandidate);
|
---|
2409 | cout << Verbose(2) << "ACCEPT: We have found a better candidate: " << *(optCandidate->point) << " with "
|
---|
2410 | << alpha << " and circumsphere's center at " << optCandidate->OptCenter << "." << endl;
|
---|
2411 | }
|
---|
2412 | *ShortestAngle = alpha;
|
---|
2413 | //cout << Verbose(2) << "INFO: There are " << candidates->size() << " candidates in the list now." << endl;
|
---|
2414 | } else {
|
---|
2415 | if ((optCandidate != NULL) && (optCandidate->point != NULL)) {
|
---|
2416 | //cout << Verbose(2) << "REJECT: Old candidate: " << *(optCandidate->point) << " is better than " << alpha << " with " << *ShortestAngle << "." << endl;
|
---|
2417 | } else {
|
---|
2418 | //cout << Verbose(2) << "REJECT: Candidate " << *Candidate << " with " << alpha << " was rejected." << endl;
|
---|
2419 | }
|
---|
2420 | }
|
---|
2421 |
|
---|
2422 | } else {
|
---|
2423 | //cout << Verbose(2) << "REJECT: NewSphereCenter " << NewSphereCenter << " is too far away: " << radius << "." << endl;
|
---|
2424 | }
|
---|
2425 | } else {
|
---|
2426 | //cout << Verbose(2) << "REJECT: Three points from " << *BaseLine << " and Candidate " << *Candidate << " are linear-dependent." << endl;
|
---|
2427 | }
|
---|
2428 | } else {
|
---|
2429 | if (ThirdNode != NULL) {
|
---|
2430 | //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " and " << *ThirdNode << " contains Candidate " << *Candidate << "." << endl;
|
---|
2431 | } else {
|
---|
2432 | //cout << Verbose(2) << "REJECT: Base triangle " << *BaseLine << " contains Candidate " << *Candidate << "." << endl;
|
---|
2433 | }
|
---|
2434 | }
|
---|
2435 | }
|
---|
2436 | }
|
---|
2437 | }
|
---|
2438 | } else {
|
---|
2439 | cerr << Verbose(2) << "ERROR: The projected center of the old sphere has radius " << radius << " instead of " << CircleRadius << "." << endl;
|
---|
2440 | }
|
---|
2441 | } else {
|
---|
2442 | if (ThirdNode != NULL)
|
---|
2443 | cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " and third node " << *ThirdNode << " is too big!" << endl;
|
---|
2444 | else
|
---|
2445 | cout << Verbose(2) << "Circumcircle for base line " << *BaseLine << " is too big!" << endl;
|
---|
2446 | }
|
---|
2447 |
|
---|
2448 | //cout << Verbose(2) << "INFO: Sorting candidate list ..." << endl;
|
---|
2449 | if (candidates->size() > 1) {
|
---|
2450 | candidates->unique();
|
---|
2451 | candidates->sort(sortCandidates);
|
---|
2452 | }
|
---|
2453 |
|
---|
2454 | cout << Verbose(1) << "End of Find_third_point_for_Tesselation" << endl;
|
---|
2455 | };
|
---|
2456 |
|
---|
2457 | struct Intersection {
|
---|
2458 | Vector x1;
|
---|
2459 | Vector x2;
|
---|
2460 | Vector x3;
|
---|
2461 | Vector x4;
|
---|
2462 | };
|
---|
2463 |
|
---|
2464 | /**
|
---|
2465 | * Intersection calculation function.
|
---|
2466 | *
|
---|
2467 | * @param x to find the result for
|
---|
2468 | * @param function parameter
|
---|
2469 | */
|
---|
2470 | double MinIntersectDistance(const gsl_vector * x, void *params) {
|
---|
2471 | double retval = 0;
|
---|
2472 | struct Intersection *I = (struct Intersection *)params;
|
---|
2473 | Vector intersection;
|
---|
2474 | Vector SideA,SideB,HeightA, HeightB;
|
---|
2475 | for (int i=0;i<NDIM;i++)
|
---|
2476 | intersection.x[i] = gsl_vector_get(x, i);
|
---|
2477 |
|
---|
2478 | SideA.CopyVector(&(I->x1));
|
---|
2479 | SideA.SubtractVector(&I->x2);
|
---|
2480 | HeightA.CopyVector(&intersection);
|
---|
2481 | HeightA.SubtractVector(&I->x1);
|
---|
2482 | HeightA.ProjectOntoPlane(&SideA);
|
---|
2483 |
|
---|
2484 | SideB.CopyVector(&I->x3);
|
---|
2485 | SideB.SubtractVector(&I->x4);
|
---|
2486 | HeightB.CopyVector(&intersection);
|
---|
2487 | HeightB.SubtractVector(&I->x3);
|
---|
2488 | HeightB.ProjectOntoPlane(&SideB);
|
---|
2489 |
|
---|
2490 | retval = HeightA.ScalarProduct(&HeightA) + HeightB.ScalarProduct(&HeightB);
|
---|
2491 | //cout << Verbose(2) << "MinIntersectDistance called, result: " << retval << endl;
|
---|
2492 |
|
---|
2493 | return retval;
|
---|
2494 | };
|
---|
2495 |
|
---|
2496 |
|
---|
2497 | /**
|
---|
2498 | * Calculates whether there is an intersection between two lines. The first line
|
---|
2499 | * always goes through point 1 and point 2 and the second line is given by the
|
---|
2500 | * connection between point 4 and point 5.
|
---|
2501 | *
|
---|
2502 | * @param point 1 of line 1
|
---|
2503 | * @param point 2 of line 1
|
---|
2504 | * @param point 1 of line 2
|
---|
2505 | * @param point 2 of line 2
|
---|
2506 | *
|
---|
2507 | * @return true if there is an intersection between the given lines, false otherwise
|
---|
2508 | */
|
---|
2509 | bool existsIntersection(Vector point1, Vector point2, Vector point3, Vector point4) {
|
---|
2510 | bool result;
|
---|
2511 |
|
---|
2512 | struct Intersection par;
|
---|
2513 | par.x1.CopyVector(&point1);
|
---|
2514 | par.x2.CopyVector(&point2);
|
---|
2515 | par.x3.CopyVector(&point3);
|
---|
2516 | par.x4.CopyVector(&point4);
|
---|
2517 |
|
---|
2518 | const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
|
---|
2519 | gsl_multimin_fminimizer *s = NULL;
|
---|
2520 | gsl_vector *ss, *x;
|
---|
2521 | gsl_multimin_function minex_func;
|
---|
2522 |
|
---|
2523 | size_t iter = 0;
|
---|
2524 | int status;
|
---|
2525 | double size;
|
---|
2526 |
|
---|
2527 | /* Starting point */
|
---|
2528 | x = gsl_vector_alloc(NDIM);
|
---|
2529 | gsl_vector_set(x, 0, point1.x[0]);
|
---|
2530 | gsl_vector_set(x, 1, point1.x[1]);
|
---|
2531 | gsl_vector_set(x, 2, point1.x[2]);
|
---|
2532 |
|
---|
2533 | /* Set initial step sizes to 1 */
|
---|
2534 | ss = gsl_vector_alloc(NDIM);
|
---|
2535 | gsl_vector_set_all(ss, 1.0);
|
---|
2536 |
|
---|
2537 | /* Initialize method and iterate */
|
---|
2538 | minex_func.n = NDIM;
|
---|
2539 | minex_func.f = &MinIntersectDistance;
|
---|
2540 | minex_func.params = (void *)∥
|
---|
2541 |
|
---|
2542 | s = gsl_multimin_fminimizer_alloc(T, NDIM);
|
---|
2543 | gsl_multimin_fminimizer_set(s, &minex_func, x, ss);
|
---|
2544 |
|
---|
2545 | do {
|
---|
2546 | iter++;
|
---|
2547 | status = gsl_multimin_fminimizer_iterate(s);
|
---|
2548 |
|
---|
2549 | if (status) {
|
---|
2550 | break;
|
---|
2551 | }
|
---|
2552 |
|
---|
2553 | size = gsl_multimin_fminimizer_size(s);
|
---|
2554 | status = gsl_multimin_test_size(size, 1e-2);
|
---|
2555 |
|
---|
2556 | if (status == GSL_SUCCESS) {
|
---|
2557 | cout << Verbose(2) << "converged to minimum" << endl;
|
---|
2558 | }
|
---|
2559 | } while (status == GSL_CONTINUE && iter < 100);
|
---|
2560 |
|
---|
2561 | // check whether intersection is in between or not
|
---|
2562 | Vector intersection, SideA, SideB, HeightA, HeightB;
|
---|
2563 | double t1, t2;
|
---|
2564 | for (int i = 0; i < NDIM; i++) {
|
---|
2565 | intersection.x[i] = gsl_vector_get(s->x, i);
|
---|
2566 | }
|
---|
2567 |
|
---|
2568 | SideA.CopyVector(&par.x2);
|
---|
2569 | SideA.SubtractVector(&par.x1);
|
---|
2570 | HeightA.CopyVector(&intersection);
|
---|
2571 | HeightA.SubtractVector(&par.x1);
|
---|
2572 |
|
---|
2573 | t1 = HeightA.Projection(&SideA)/SideA.ScalarProduct(&SideA);
|
---|
2574 |
|
---|
2575 | SideB.CopyVector(&par.x4);
|
---|
2576 | SideB.SubtractVector(&par.x3);
|
---|
2577 | HeightB.CopyVector(&intersection);
|
---|
2578 | HeightB.SubtractVector(&par.x3);
|
---|
2579 |
|
---|
2580 | t2 = HeightB.Projection(&SideB)/SideB.ScalarProduct(&SideB);
|
---|
2581 |
|
---|
2582 | cout << Verbose(2) << "Intersection " << intersection << " is at "
|
---|
2583 | << t1 << " for (" << point1 << "," << point2 << ") and at "
|
---|
2584 | << t2 << " for (" << point3 << "," << point4 << "): ";
|
---|
2585 |
|
---|
2586 | if (((t1 >= 0) && (t1 <= 1)) && ((t2 >= 0) && (t2 <= 1))) {
|
---|
2587 | cout << "true intersection." << endl;
|
---|
2588 | result = true;
|
---|
2589 | } else {
|
---|
2590 | cout << "intersection out of region of interest." << endl;
|
---|
2591 | result = false;
|
---|
2592 | }
|
---|
2593 |
|
---|
2594 | // free minimizer stuff
|
---|
2595 | gsl_vector_free(x);
|
---|
2596 | gsl_vector_free(ss);
|
---|
2597 | gsl_multimin_fminimizer_free(s);
|
---|
2598 |
|
---|
2599 | return result;
|
---|
2600 | }
|
---|
2601 |
|
---|
2602 | /** Finds the second point of starting triangle.
|
---|
2603 | * \param *a first atom
|
---|
2604 | * \param *Candidate pointer to candidate atom on return
|
---|
2605 | * \param Oben vector indicating the outside
|
---|
2606 | * \param Opt_Candidate reference to recommended candidate on return
|
---|
2607 | * \param Storage[3] array storing angles and other candidate information
|
---|
2608 | * \param RADIUS radius of virtual sphere
|
---|
2609 | * \param *LC LinkedCell structure with neighbouring atoms
|
---|
2610 | */
|
---|
2611 | void Find_second_point_for_Tesselation(atom* a, atom* Candidate, Vector Oben, atom*& Opt_Candidate, double Storage[3], double RADIUS, LinkedCell *LC)
|
---|
2612 | {
|
---|
2613 | cout << Verbose(2) << "Begin of Find_second_point_for_Tesselation" << endl;
|
---|
2614 | Vector AngleCheck;
|
---|
2615 | double norm = -1., angle;
|
---|
2616 | LinkedAtoms *List = NULL;
|
---|
2617 | int N[NDIM], Nlower[NDIM], Nupper[NDIM];
|
---|
2618 |
|
---|
2619 | if (LC->SetIndexToAtom(a)) { // get cell for the starting atom
|
---|
2620 | for(int i=0;i<NDIM;i++) // store indices of this cell
|
---|
2621 | N[i] = LC->n[i];
|
---|
2622 | } else {
|
---|
2623 | cerr << "ERROR: Atom " << *a << " is not found in cell " << LC->index << "." << endl;
|
---|
2624 | return;
|
---|
2625 | }
|
---|
2626 | // then go through the current and all neighbouring cells and check the contained atoms for possible candidates
|
---|
2627 | cout << Verbose(3) << "LC Intervals from [";
|
---|
2628 | for (int i=0;i<NDIM;i++) {
|
---|
2629 | cout << " " << N[i] << "<->" << LC->N[i];
|
---|
2630 | }
|
---|
2631 | cout << "] :";
|
---|
2632 | for (int i=0;i<NDIM;i++) {
|
---|
2633 | Nlower[i] = ((N[i]-1) >= 0) ? N[i]-1 : 0;
|
---|
2634 | Nupper[i] = ((N[i]+1) < LC->N[i]) ? N[i]+1 : LC->N[i]-1;
|
---|
2635 | cout << " [" << Nlower[i] << "," << Nupper[i] << "] ";
|
---|
2636 | }
|
---|
2637 | cout << endl;
|
---|
2638 |
|
---|
2639 |
|
---|
2640 | for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
|
---|
2641 | for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
|
---|
2642 | for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
|
---|
2643 | List = LC->GetCurrentCell();
|
---|
2644 | //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
|
---|
2645 | if (List != NULL) {
|
---|
2646 | for (LinkedAtoms::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
|
---|
2647 | Candidate = (*Runner);
|
---|
2648 | // check if we only have one unique point yet ...
|
---|
2649 | if (a != Candidate) {
|
---|
2650 | // Calculate center of the circle with radius RADIUS through points a and Candidate
|
---|
2651 | Vector OrthogonalizedOben, a_Candidate, Center;
|
---|
2652 | double distance, scaleFactor;
|
---|
2653 |
|
---|
2654 | OrthogonalizedOben.CopyVector(&Oben);
|
---|
2655 | a_Candidate.CopyVector(&(a->x));
|
---|
2656 | a_Candidate.SubtractVector(&(Candidate->x));
|
---|
2657 | OrthogonalizedOben.ProjectOntoPlane(&a_Candidate);
|
---|
2658 | OrthogonalizedOben.Normalize();
|
---|
2659 | distance = 0.5 * a_Candidate.Norm();
|
---|
2660 | scaleFactor = sqrt(((RADIUS * RADIUS) - (distance * distance)));
|
---|
2661 | OrthogonalizedOben.Scale(scaleFactor);
|
---|
2662 |
|
---|
2663 | Center.CopyVector(&(Candidate->x));
|
---|
2664 | Center.AddVector(&(a->x));
|
---|
2665 | Center.Scale(0.5);
|
---|
2666 | Center.AddVector(&OrthogonalizedOben);
|
---|
2667 |
|
---|
2668 | AngleCheck.CopyVector(&Center);
|
---|
2669 | AngleCheck.SubtractVector(&(a->x));
|
---|
2670 | norm = a_Candidate.Norm();
|
---|
2671 | // second point shall have smallest angle with respect to Oben vector
|
---|
2672 | if (norm < RADIUS*2.) {
|
---|
2673 | angle = AngleCheck.Angle(&Oben);
|
---|
2674 | if (angle < Storage[0]) {
|
---|
2675 | //cout << Verbose(3) << "Old values of Storage: %lf %lf \n", Storage[0], Storage[1]);
|
---|
2676 | cout << Verbose(3) << "Current candidate is " << *Candidate << ": Is a better candidate with distance " << norm << " and angle " << angle << " to oben " << Oben << ".\n";
|
---|
2677 | Opt_Candidate = Candidate;
|
---|
2678 | Storage[0] = angle;
|
---|
2679 | //cout << Verbose(3) << "Changing something in Storage: %lf %lf. \n", Storage[0], Storage[2]);
|
---|
2680 | } else {
|
---|
2681 | //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Looses with angle " << angle << " to a better candidate " << *Opt_Candidate << endl;
|
---|
2682 | }
|
---|
2683 | } else {
|
---|
2684 | //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Refused due to Radius " << norm << endl;
|
---|
2685 | }
|
---|
2686 | } else {
|
---|
2687 | //cout << Verbose(3) << "Current candidate is " << *Candidate << ": Candidate is equal to first endpoint." << *a << "." << endl;
|
---|
2688 | }
|
---|
2689 | }
|
---|
2690 | } else {
|
---|
2691 | cout << Verbose(3) << "Linked cell list is empty." << endl;
|
---|
2692 | }
|
---|
2693 | }
|
---|
2694 | cout << Verbose(2) << "End of Find_second_point_for_Tesselation" << endl;
|
---|
2695 | };
|
---|
2696 |
|
---|
2697 | /** Finds the starting triangle for find_non_convex_border().
|
---|
2698 | * Looks at the outermost atom per axis, then Find_second_point_for_Tesselation()
|
---|
2699 | * for the second and Find_next_suitable_point_via_Angle_of_Sphere() for the third
|
---|
2700 | * point are called.
|
---|
2701 | * \param RADIUS radius of virtual rolling sphere
|
---|
2702 | * \param *LC LinkedCell structure with neighbouring atoms
|
---|
2703 | */
|
---|
2704 | void Tesselation::Find_starting_triangle(ofstream *out, molecule *mol, const double RADIUS, LinkedCell *LC)
|
---|
2705 | {
|
---|
2706 | cout << Verbose(1) << "Begin of Find_starting_triangle\n";
|
---|
2707 | int i = 0;
|
---|
2708 | LinkedAtoms *List = NULL;
|
---|
2709 | atom* FirstPoint = NULL;
|
---|
2710 | atom* SecondPoint = NULL;
|
---|
2711 | atom* MaxAtom[NDIM];
|
---|
2712 | double max_coordinate[NDIM];
|
---|
2713 | Vector Oben;
|
---|
2714 | Vector helper;
|
---|
2715 | Vector Chord;
|
---|
2716 | Vector SearchDirection;
|
---|
2717 |
|
---|
2718 | Oben.Zero();
|
---|
2719 |
|
---|
2720 | for (i = 0; i < 3; i++) {
|
---|
2721 | MaxAtom[i] = NULL;
|
---|
2722 | max_coordinate[i] = -1;
|
---|
2723 | }
|
---|
2724 |
|
---|
2725 | // 1. searching topmost atom with respect to each axis
|
---|
2726 | for (int i=0;i<NDIM;i++) { // each axis
|
---|
2727 | LC->n[i] = LC->N[i]-1; // current axis is topmost cell
|
---|
2728 | for (LC->n[(i+1)%NDIM]=0;LC->n[(i+1)%NDIM]<LC->N[(i+1)%NDIM];LC->n[(i+1)%NDIM]++)
|
---|
2729 | for (LC->n[(i+2)%NDIM]=0;LC->n[(i+2)%NDIM]<LC->N[(i+2)%NDIM];LC->n[(i+2)%NDIM]++) {
|
---|
2730 | List = LC->GetCurrentCell();
|
---|
2731 | //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
|
---|
2732 | if (List != NULL) {
|
---|
2733 | for (LinkedAtoms::iterator Runner = List->begin();Runner != List->end();Runner++) {
|
---|
2734 | if ((*Runner)->x.x[i] > max_coordinate[i]) {
|
---|
2735 | cout << Verbose(2) << "New maximal for axis " << i << " atom is " << *(*Runner) << " at " << (*Runner)->x << "." << endl;
|
---|
2736 | max_coordinate[i] = (*Runner)->x.x[i];
|
---|
2737 | MaxAtom[i] = (*Runner);
|
---|
2738 | }
|
---|
2739 | }
|
---|
2740 | } else {
|
---|
2741 | cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl;
|
---|
2742 | }
|
---|
2743 | }
|
---|
2744 | }
|
---|
2745 |
|
---|
2746 | cout << Verbose(2) << "Found maximum coordinates: ";
|
---|
2747 | for (int i=0;i<NDIM;i++)
|
---|
2748 | cout << i << ": " << *MaxAtom[i] << "\t";
|
---|
2749 | cout << endl;
|
---|
2750 |
|
---|
2751 | BTS = NULL;
|
---|
2752 | CandidateList *Opt_Candidates = new CandidateList();
|
---|
2753 | for (int k=0;k<NDIM;k++) {
|
---|
2754 | Oben.x[k] = 1.;
|
---|
2755 | FirstPoint = MaxAtom[k];
|
---|
2756 | cout << Verbose(1) << "Coordinates of start atom " << *FirstPoint << " at " << FirstPoint->x << "." << endl;
|
---|
2757 |
|
---|
2758 | double ShortestAngle;
|
---|
2759 | atom* Opt_Candidate = NULL;
|
---|
2760 | ShortestAngle = 999999.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant.
|
---|
2761 |
|
---|
2762 | Find_second_point_for_Tesselation(FirstPoint, NULL, Oben, Opt_Candidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
|
---|
2763 | SecondPoint = Opt_Candidate;
|
---|
2764 | if (SecondPoint == NULL) // have we found a second point?
|
---|
2765 | continue;
|
---|
2766 | else
|
---|
2767 | cout << Verbose(1) << "Found second point is " << *SecondPoint << " at " << SecondPoint->x << ".\n";
|
---|
2768 |
|
---|
2769 | helper.CopyVector(&(FirstPoint->x));
|
---|
2770 | helper.SubtractVector(&(SecondPoint->x));
|
---|
2771 | helper.Normalize();
|
---|
2772 | Oben.ProjectOntoPlane(&helper);
|
---|
2773 | Oben.Normalize();
|
---|
2774 | helper.VectorProduct(&Oben);
|
---|
2775 | ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
|
---|
2776 |
|
---|
2777 | Chord.CopyVector(&(FirstPoint->x)); // bring into calling function
|
---|
2778 | Chord.SubtractVector(&(SecondPoint->x));
|
---|
2779 | double radius = Chord.ScalarProduct(&Chord);
|
---|
2780 | double CircleRadius = sqrt(RADIUS*RADIUS - radius/4.);
|
---|
2781 | helper.CopyVector(&Oben);
|
---|
2782 | helper.Scale(CircleRadius);
|
---|
2783 | // Now, oben and helper are two orthonormalized vectors in the plane defined by Chord (not normalized)
|
---|
2784 |
|
---|
2785 | // look in one direction of baseline for initial candidate
|
---|
2786 | SearchDirection.MakeNormalVector(&Chord, &Oben); // whether we look "left" first or "right" first is not important ...
|
---|
2787 |
|
---|
2788 | // adding point 1 and point 2 and the line between them
|
---|
2789 | AddTrianglePoint(FirstPoint, 0);
|
---|
2790 | AddTrianglePoint(SecondPoint, 1);
|
---|
2791 | AddTriangleLine(TPS[0], TPS[1], 0);
|
---|
2792 |
|
---|
2793 | //cout << Verbose(2) << "INFO: OldSphereCenter is at " << helper << ".\n";
|
---|
2794 | Find_third_point_for_Tesselation(
|
---|
2795 | Oben, SearchDirection, helper, BLS[0], NULL, *&Opt_Candidates, &ShortestAngle, RADIUS, LC
|
---|
2796 | );
|
---|
2797 | cout << Verbose(1) << "List of third Points is ";
|
---|
2798 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
2799 | cout << " " << *(*it)->point;
|
---|
2800 | }
|
---|
2801 | cout << endl;
|
---|
2802 |
|
---|
2803 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
2804 | // add third triangle point
|
---|
2805 | AddTrianglePoint((*it)->point, 2);
|
---|
2806 | // add the second and third line
|
---|
2807 | AddTriangleLine(TPS[1], TPS[2], 1);
|
---|
2808 | AddTriangleLine(TPS[0], TPS[2], 2);
|
---|
2809 | // ... and triangles to the Maps of the Tesselation class
|
---|
2810 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
|
---|
2811 | AddTriangle();
|
---|
2812 | // ... and calculate its normal vector (with correct orientation)
|
---|
2813 | (*it)->OptCenter.Scale(-1.);
|
---|
2814 | cout << Verbose(2) << "Anti-Oben is currently " << (*it)->OptCenter << "." << endl;
|
---|
2815 | BTS->GetNormalVector((*it)->OptCenter); // vector to compare with should point inwards
|
---|
2816 | cout << Verbose(0) << "==> Found starting triangle consists of " << *FirstPoint << ", " << *SecondPoint << " and "
|
---|
2817 | << *(*it)->point << " with normal vector " << BTS->NormalVector << ".\n";
|
---|
2818 |
|
---|
2819 | // if we do not reach the end with the next step of iteration, we need to setup a new first line
|
---|
2820 | if (it != Opt_Candidates->end()--) {
|
---|
2821 | FirstPoint = (*it)->BaseLine->endpoints[0]->node;
|
---|
2822 | SecondPoint = (*it)->point;
|
---|
2823 | // adding point 1 and point 2 and the line between them
|
---|
2824 | AddTrianglePoint(FirstPoint, 0);
|
---|
2825 | AddTrianglePoint(SecondPoint, 1);
|
---|
2826 | AddTriangleLine(TPS[0], TPS[1], 0);
|
---|
2827 | }
|
---|
2828 | cout << Verbose(2) << "Projection is " << BTS->NormalVector.Projection(&Oben) << "." << endl;
|
---|
2829 | }
|
---|
2830 | if (BTS != NULL) // we have created one starting triangle
|
---|
2831 | break;
|
---|
2832 | else {
|
---|
2833 | // remove all candidates from the list and then the list itself
|
---|
2834 | class CandidateForTesselation *remover = NULL;
|
---|
2835 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
2836 | remover = *it;
|
---|
2837 | delete(remover);
|
---|
2838 | }
|
---|
2839 | Opt_Candidates->clear();
|
---|
2840 | }
|
---|
2841 | }
|
---|
2842 |
|
---|
2843 | // remove all candidates from the list and then the list itself
|
---|
2844 | class CandidateForTesselation *remover = NULL;
|
---|
2845 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
2846 | remover = *it;
|
---|
2847 | delete(remover);
|
---|
2848 | }
|
---|
2849 | delete(Opt_Candidates);
|
---|
2850 | cout << Verbose(1) << "End of Find_starting_triangle\n";
|
---|
2851 | };
|
---|
2852 |
|
---|
2853 | /** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
|
---|
2854 | * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
|
---|
2855 | * make it bigger (i.e. closing one (the baseline) and opening two new ones).
|
---|
2856 | * \param TPS[3] nodes of the triangle
|
---|
2857 | * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
|
---|
2858 | */
|
---|
2859 | bool CheckLineCriteriaforDegeneratedTriangle(class BoundaryPointSet *nodes[3])
|
---|
2860 | {
|
---|
2861 | bool result = false;
|
---|
2862 | int counter = 0;
|
---|
2863 |
|
---|
2864 | // check all three points
|
---|
2865 | for (int i=0;i<3;i++)
|
---|
2866 | for (int j=i+1; j<3; j++) {
|
---|
2867 | if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) { // there already is a line
|
---|
2868 | LineMap::iterator FindLine;
|
---|
2869 | pair<LineMap::iterator,LineMap::iterator> FindPair;
|
---|
2870 | FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
|
---|
2871 | for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
|
---|
2872 | // If there is a line with less than two attached triangles, we don't need a new line.
|
---|
2873 | if (FindLine->second->TrianglesCount < 2) {
|
---|
2874 | counter++;
|
---|
2875 | break; // increase counter only once per edge
|
---|
2876 | }
|
---|
2877 | }
|
---|
2878 | } else { // no line
|
---|
2879 | cout << Verbose(1) << "ERROR: The line between " << nodes[i] << " and " << nodes[j] << " is not yet present, hence no need for a degenerate triangle!" << endl;
|
---|
2880 | result = true;
|
---|
2881 | }
|
---|
2882 | }
|
---|
2883 | if (counter > 1) {
|
---|
2884 | cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
|
---|
2885 | result = true;
|
---|
2886 | }
|
---|
2887 | return result;
|
---|
2888 | };
|
---|
2889 |
|
---|
2890 |
|
---|
2891 | /** This function finds a triangle to a line, adjacent to an existing one.
|
---|
2892 | * @param out output stream for debugging
|
---|
2893 | * @param *mol molecule with Atom's and Bond's
|
---|
2894 | * @param Line current baseline to search from
|
---|
2895 | * @param T current triangle which \a Line is edge of
|
---|
2896 | * @param RADIUS radius of the rolling ball
|
---|
2897 | * @param N number of found triangles
|
---|
2898 | * @param *filename filename base for intermediate envelopes
|
---|
2899 | * @param *LC LinkedCell structure with neighbouring atoms
|
---|
2900 | */
|
---|
2901 | bool Tesselation::Find_next_suitable_triangle(ofstream *out,
|
---|
2902 | molecule *mol, BoundaryLineSet &Line, BoundaryTriangleSet &T,
|
---|
2903 | const double& RADIUS, int N, const char *tempbasename, LinkedCell *LC)
|
---|
2904 | {
|
---|
2905 | cout << Verbose(0) << "Begin of Find_next_suitable_triangle\n";
|
---|
2906 | ofstream *tempstream = NULL;
|
---|
2907 | char NumberName[255];
|
---|
2908 | bool result = true;
|
---|
2909 | CandidateList *Opt_Candidates = new CandidateList();
|
---|
2910 |
|
---|
2911 | Vector CircleCenter;
|
---|
2912 | Vector CirclePlaneNormal;
|
---|
2913 | Vector OldSphereCenter;
|
---|
2914 | Vector SearchDirection;
|
---|
2915 | Vector helper;
|
---|
2916 | atom *ThirdNode = NULL;
|
---|
2917 | LineMap::iterator testline;
|
---|
2918 | double ShortestAngle = 2.*M_PI; // This will indicate the quadrant.
|
---|
2919 | double radius, CircleRadius;
|
---|
2920 |
|
---|
2921 | cout << Verbose(1) << "Current baseline is " << Line << " of triangle " << T << "." << endl;
|
---|
2922 | for (int i=0;i<3;i++)
|
---|
2923 | if ((T.endpoints[i]->node != Line.endpoints[0]->node) && (T.endpoints[i]->node != Line.endpoints[1]->node))
|
---|
2924 | ThirdNode = T.endpoints[i]->node;
|
---|
2925 |
|
---|
2926 | // construct center of circle
|
---|
2927 | CircleCenter.CopyVector(&Line.endpoints[0]->node->x);
|
---|
2928 | CircleCenter.AddVector(&Line.endpoints[1]->node->x);
|
---|
2929 | CircleCenter.Scale(0.5);
|
---|
2930 |
|
---|
2931 | // construct normal vector of circle
|
---|
2932 | CirclePlaneNormal.CopyVector(&Line.endpoints[0]->node->x);
|
---|
2933 | CirclePlaneNormal.SubtractVector(&Line.endpoints[1]->node->x);
|
---|
2934 |
|
---|
2935 | // calculate squared radius of circle
|
---|
2936 | radius = CirclePlaneNormal.ScalarProduct(&CirclePlaneNormal);
|
---|
2937 | if (radius/4. < RADIUS*RADIUS) {
|
---|
2938 | CircleRadius = RADIUS*RADIUS - radius/4.;
|
---|
2939 | CirclePlaneNormal.Normalize();
|
---|
2940 | cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
|
---|
2941 |
|
---|
2942 | // construct old center
|
---|
2943 | GetCenterofCircumcircle(&OldSphereCenter, &(T.endpoints[0]->node->x), &(T.endpoints[1]->node->x), &(T.endpoints[2]->node->x));
|
---|
2944 | helper.CopyVector(&T.NormalVector); // normal vector ensures that this is correct center of the two possible ones
|
---|
2945 | radius = Line.endpoints[0]->node->x.DistanceSquared(&OldSphereCenter);
|
---|
2946 | helper.Scale(sqrt(RADIUS*RADIUS - radius));
|
---|
2947 | OldSphereCenter.AddVector(&helper);
|
---|
2948 | OldSphereCenter.SubtractVector(&CircleCenter);
|
---|
2949 | //cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
|
---|
2950 |
|
---|
2951 | // construct SearchDirection
|
---|
2952 | SearchDirection.MakeNormalVector(&T.NormalVector, &CirclePlaneNormal);
|
---|
2953 | helper.CopyVector(&Line.endpoints[0]->node->x);
|
---|
2954 | helper.SubtractVector(&ThirdNode->x);
|
---|
2955 | if (helper.ScalarProduct(&SearchDirection) < -HULLEPSILON)// ohoh, SearchDirection points inwards!
|
---|
2956 | SearchDirection.Scale(-1.);
|
---|
2957 | SearchDirection.ProjectOntoPlane(&OldSphereCenter);
|
---|
2958 | SearchDirection.Normalize();
|
---|
2959 | cout << Verbose(2) << "INFO: SearchDirection is " << SearchDirection << "." << endl;
|
---|
2960 | if (fabs(OldSphereCenter.ScalarProduct(&SearchDirection)) > HULLEPSILON) {
|
---|
2961 | // rotated the wrong way!
|
---|
2962 | cerr << "ERROR: SearchDirection and RelativeOldSphereCenter are still not orthogonal!" << endl;
|
---|
2963 | }
|
---|
2964 |
|
---|
2965 | // add third point
|
---|
2966 | Find_third_point_for_Tesselation(
|
---|
2967 | T.NormalVector, SearchDirection, OldSphereCenter, &Line, ThirdNode, Opt_Candidates,
|
---|
2968 | &ShortestAngle, RADIUS, LC
|
---|
2969 | );
|
---|
2970 |
|
---|
2971 | } else {
|
---|
2972 | cout << Verbose(1) << "Circumcircle for base line " << Line << " and base triangle " << T << " is too big!" << endl;
|
---|
2973 | }
|
---|
2974 |
|
---|
2975 | if (Opt_Candidates->begin() == Opt_Candidates->end()) {
|
---|
2976 | cerr << "WARNING: Could not find a suitable candidate." << endl;
|
---|
2977 | return false;
|
---|
2978 | }
|
---|
2979 | cout << Verbose(1) << "Third Points are ";
|
---|
2980 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
2981 | cout << " " << *(*it)->point;
|
---|
2982 | }
|
---|
2983 | cout << endl;
|
---|
2984 |
|
---|
2985 | BoundaryLineSet *BaseRay = &Line;
|
---|
2986 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
2987 | cout << Verbose(1) << " Third point candidate is " << *(*it)->point
|
---|
2988 | << " with circumsphere's center at " << (*it)->OptCenter << "." << endl;
|
---|
2989 | cout << Verbose(1) << " Baseline is " << *BaseRay << endl;
|
---|
2990 |
|
---|
2991 | // check whether all edges of the new triangle still have space for one more triangle (i.e. TriangleCount <2)
|
---|
2992 | atom *AtomCandidates[3];
|
---|
2993 | AtomCandidates[0] = (*it)->point;
|
---|
2994 | AtomCandidates[1] = BaseRay->endpoints[0]->node;
|
---|
2995 | AtomCandidates[2] = BaseRay->endpoints[1]->node;
|
---|
2996 | int existentTrianglesCount = CheckPresenceOfTriangle(out, AtomCandidates);
|
---|
2997 |
|
---|
2998 | BTS = NULL;
|
---|
2999 | // If there is no triangle, add it regularly.
|
---|
3000 | if (existentTrianglesCount == 0) {
|
---|
3001 | AddTrianglePoint((*it)->point, 0);
|
---|
3002 | AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
|
---|
3003 | AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
|
---|
3004 |
|
---|
3005 | AddTriangleLine(TPS[0], TPS[1], 0);
|
---|
3006 | AddTriangleLine(TPS[0], TPS[2], 1);
|
---|
3007 | AddTriangleLine(TPS[1], TPS[2], 2);
|
---|
3008 |
|
---|
3009 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
|
---|
3010 | AddTriangle();
|
---|
3011 | (*it)->OptCenter.Scale(-1.);
|
---|
3012 | BTS->GetNormalVector((*it)->OptCenter);
|
---|
3013 | (*it)->OptCenter.Scale(-1.);
|
---|
3014 |
|
---|
3015 | cout << "--> New triangle with " << *BTS << " and normal vector " << BTS->NormalVector
|
---|
3016 | << " for this triangle ... " << endl;
|
---|
3017 | //cout << Verbose(1) << "We have "<< TrianglesOnBoundaryCount << " for line " << *BaseRay << "." << endl;
|
---|
3018 | } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time.
|
---|
3019 | AddTrianglePoint((*it)->point, 0);
|
---|
3020 | AddTrianglePoint(BaseRay->endpoints[0]->node, 1);
|
---|
3021 | AddTrianglePoint(BaseRay->endpoints[1]->node, 2);
|
---|
3022 |
|
---|
3023 | // We demand that at most one new degenerate line is created and that this line also already exists (which has to be the case due to existentTrianglesCount == 1)
|
---|
3024 | // i.e. at least one of the three lines must be present with TriangleCount <= 1
|
---|
3025 | if (CheckLineCriteriaforDegeneratedTriangle(TPS)) {
|
---|
3026 | AddTriangleLine(TPS[0], TPS[1], 0);
|
---|
3027 | AddTriangleLine(TPS[0], TPS[2], 1);
|
---|
3028 | AddTriangleLine(TPS[1], TPS[2], 2);
|
---|
3029 |
|
---|
3030 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
|
---|
3031 | AddTriangle();
|
---|
3032 |
|
---|
3033 | (*it)->OtherOptCenter.Scale(-1.);
|
---|
3034 | BTS->GetNormalVector((*it)->OtherOptCenter);
|
---|
3035 | (*it)->OtherOptCenter.Scale(-1.);
|
---|
3036 |
|
---|
3037 | cout << "--> WARNING: Special new triangle with " << *BTS << " and normal vector " << BTS->NormalVector
|
---|
3038 | << " for this triangle ... " << endl;
|
---|
3039 | cout << Verbose(1) << "We have "<< BaseRay->TrianglesCount << " for line " << BaseRay << "." << endl;
|
---|
3040 | } else {
|
---|
3041 | cout << Verbose(1) << "WARNING: This triangle consisting of ";
|
---|
3042 | cout << *(*it)->point << ", ";
|
---|
3043 | cout << *BaseRay->endpoints[0]->node << " and ";
|
---|
3044 | cout << *BaseRay->endpoints[1]->node << " ";
|
---|
3045 | cout << "exists and is not added, as it does not seem helpful!" << endl;
|
---|
3046 | result = false;
|
---|
3047 | }
|
---|
3048 | } else {
|
---|
3049 | cout << Verbose(1) << "This triangle consisting of ";
|
---|
3050 | cout << *(*it)->point << ", ";
|
---|
3051 | cout << *BaseRay->endpoints[0]->node << " and ";
|
---|
3052 | cout << *BaseRay->endpoints[1]->node << " ";
|
---|
3053 | cout << "is invalid!" << endl;
|
---|
3054 | result = false;
|
---|
3055 | }
|
---|
3056 |
|
---|
3057 | if ((result) && (existentTrianglesCount < 2) && (DoSingleStepOutput && (TrianglesOnBoundaryCount % 1 == 0))) { // if we have a new triangle and want to output each new triangle configuration
|
---|
3058 | sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, BTS->endpoints[0]->node->Name, BTS->endpoints[1]->node->Name, BTS->endpoints[2]->node->Name);
|
---|
3059 | if (DoTecplotOutput) {
|
---|
3060 | string NameofTempFile(tempbasename);
|
---|
3061 | NameofTempFile.append(NumberName);
|
---|
3062 | for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
|
---|
3063 | NameofTempFile.erase(npos, 1);
|
---|
3064 | NameofTempFile.append(TecplotSuffix);
|
---|
3065 | cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
|
---|
3066 | tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
|
---|
3067 | write_tecplot_file(out, tempstream, this, mol, TriangleFilesWritten);
|
---|
3068 | tempstream->close();
|
---|
3069 | tempstream->flush();
|
---|
3070 | delete(tempstream);
|
---|
3071 | }
|
---|
3072 |
|
---|
3073 | if (DoRaster3DOutput) {
|
---|
3074 | string NameofTempFile(tempbasename);
|
---|
3075 | NameofTempFile.append(NumberName);
|
---|
3076 | for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
|
---|
3077 | NameofTempFile.erase(npos, 1);
|
---|
3078 | NameofTempFile.append(Raster3DSuffix);
|
---|
3079 | cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
|
---|
3080 | tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
|
---|
3081 | write_raster3d_file(out, tempstream, this, mol);
|
---|
3082 | // include the current position of the virtual sphere in the temporary raster3d file
|
---|
3083 | // make the circumsphere's center absolute again
|
---|
3084 | helper.CopyVector(&BaseRay->endpoints[0]->node->x);
|
---|
3085 | helper.AddVector(&BaseRay->endpoints[1]->node->x);
|
---|
3086 | helper.Scale(0.5);
|
---|
3087 | (*it)->OptCenter.AddVector(&helper);
|
---|
3088 | Vector *center = mol->DetermineCenterOfAll(out);
|
---|
3089 | (*it)->OptCenter.SubtractVector(center);
|
---|
3090 | delete(center);
|
---|
3091 | // and add to file plus translucency object
|
---|
3092 | *tempstream << "# current virtual sphere\n";
|
---|
3093 | *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
|
---|
3094 | *tempstream << "2\n " << (*it)->OptCenter.x[0] << " "
|
---|
3095 | << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
|
---|
3096 | << "\t" << RADIUS << "\t1 0 0\n";
|
---|
3097 | *tempstream << "9\n terminating special property\n";
|
---|
3098 | tempstream->close();
|
---|
3099 | tempstream->flush();
|
---|
3100 | delete(tempstream);
|
---|
3101 | }
|
---|
3102 | if (DoTecplotOutput || DoRaster3DOutput)
|
---|
3103 | TriangleFilesWritten++;
|
---|
3104 | }
|
---|
3105 |
|
---|
3106 | // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
|
---|
3107 | BaseRay = BLS[0];
|
---|
3108 | }
|
---|
3109 |
|
---|
3110 | // remove all candidates from the list and then the list itself
|
---|
3111 | class CandidateForTesselation *remover = NULL;
|
---|
3112 | for (CandidateList::iterator it = Opt_Candidates->begin(); it != Opt_Candidates->end(); ++it) {
|
---|
3113 | remover = *it;
|
---|
3114 | delete(remover);
|
---|
3115 | }
|
---|
3116 | delete(Opt_Candidates);
|
---|
3117 | cout << Verbose(0) << "End of Find_next_suitable_triangle\n";
|
---|
3118 | return result;
|
---|
3119 | };
|
---|
3120 |
|
---|
3121 | /**
|
---|
3122 | * Sort function for the candidate list.
|
---|
3123 | */
|
---|
3124 | bool sortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2) {
|
---|
3125 | Vector BaseLineVector, OrthogonalVector, helper;
|
---|
3126 | if (candidate1->BaseLine != candidate2->BaseLine) { // sanity check
|
---|
3127 | cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
|
---|
3128 | //return false;
|
---|
3129 | exit(1);
|
---|
3130 | }
|
---|
3131 | // create baseline vector
|
---|
3132 | BaseLineVector.CopyVector(&(candidate1->BaseLine->endpoints[1]->node->x));
|
---|
3133 | BaseLineVector.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x));
|
---|
3134 | BaseLineVector.Normalize();
|
---|
3135 |
|
---|
3136 | // 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!)
|
---|
3137 | helper.CopyVector(&(candidate1->BaseLine->endpoints[0]->node->x));
|
---|
3138 | helper.SubtractVector(&(candidate1->point->x));
|
---|
3139 | OrthogonalVector.CopyVector(&helper);
|
---|
3140 | helper.VectorProduct(&BaseLineVector);
|
---|
3141 | OrthogonalVector.SubtractVector(&helper);
|
---|
3142 | OrthogonalVector.Normalize();
|
---|
3143 |
|
---|
3144 | // calculate both angles and correct with in-plane vector
|
---|
3145 | helper.CopyVector(&(candidate1->point->x));
|
---|
3146 | helper.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x));
|
---|
3147 | double phi = BaseLineVector.Angle(&helper);
|
---|
3148 | if (OrthogonalVector.ScalarProduct(&helper) > 0) {
|
---|
3149 | phi = 2.*M_PI - phi;
|
---|
3150 | }
|
---|
3151 | helper.CopyVector(&(candidate2->point->x));
|
---|
3152 | helper.SubtractVector(&(candidate1->BaseLine->endpoints[0]->node->x));
|
---|
3153 | double psi = BaseLineVector.Angle(&helper);
|
---|
3154 | if (OrthogonalVector.ScalarProduct(&helper) > 0) {
|
---|
3155 | psi = 2.*M_PI - psi;
|
---|
3156 | }
|
---|
3157 |
|
---|
3158 | cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
|
---|
3159 | cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
|
---|
3160 |
|
---|
3161 | // return comparison
|
---|
3162 | return phi < psi;
|
---|
3163 | }
|
---|
3164 |
|
---|
3165 | /** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
|
---|
3166 | * \param *out output stream for debugging
|
---|
3167 | * \param *mol molecule structure with Atom's and Bond's
|
---|
3168 | * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
|
---|
3169 | * \param *LCList atoms in LinkedCell list
|
---|
3170 | * \param *filename filename prefix for output of vertex data
|
---|
3171 | * \para RADIUS radius of the virtual sphere
|
---|
3172 | */
|
---|
3173 | void Find_non_convex_border(ofstream *out, molecule* mol, class Tesselation *Tess, class LinkedCell *LCList, const char *filename, const double RADIUS)
|
---|
3174 | {
|
---|
3175 | int N = 0;
|
---|
3176 | bool freeTess = false;
|
---|
3177 | bool freeLC = false;
|
---|
3178 | *out << Verbose(1) << "Entering search for non convex hull. " << endl;
|
---|
3179 | if (Tess == NULL) {
|
---|
3180 | *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
|
---|
3181 | Tess = new Tesselation;
|
---|
3182 | freeTess = true;
|
---|
3183 | }
|
---|
3184 | LineMap::iterator baseline;
|
---|
3185 | LineMap::iterator testline;
|
---|
3186 | *out << Verbose(0) << "Begin of Find_non_convex_border\n";
|
---|
3187 | bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
|
---|
3188 | bool failflag = false;
|
---|
3189 |
|
---|
3190 | if (LCList == NULL) {
|
---|
3191 | LCList = new LinkedCell(mol, 2.*RADIUS);
|
---|
3192 | freeLC = true;
|
---|
3193 | }
|
---|
3194 |
|
---|
3195 | Tess->Find_starting_triangle(out, mol, RADIUS, LCList);
|
---|
3196 |
|
---|
3197 | baseline = Tess->LinesOnBoundary.begin();
|
---|
3198 | while ((baseline != Tess->LinesOnBoundary.end()) || (flag)) {
|
---|
3199 | if (baseline->second->TrianglesCount == 1) {
|
---|
3200 | failflag = Tess->Find_next_suitable_triangle(out, mol, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, filename, LCList); //the line is there, so there is a triangle, but only one.
|
---|
3201 | flag = flag || failflag;
|
---|
3202 | if (!failflag)
|
---|
3203 | cerr << "WARNING: Find_next_suitable_triangle failed." << endl;
|
---|
3204 | } else {
|
---|
3205 | //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->TrianglesCount << " triangles adjacent" << endl;
|
---|
3206 | if (baseline->second->TrianglesCount != 2)
|
---|
3207 | cout << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
|
---|
3208 | }
|
---|
3209 |
|
---|
3210 | N++;
|
---|
3211 | baseline++;
|
---|
3212 | if ((baseline == Tess->LinesOnBoundary.end()) && (flag)) {
|
---|
3213 | baseline = Tess->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
|
---|
3214 | flag = false;
|
---|
3215 | }
|
---|
3216 | }
|
---|
3217 | if (filename != 0) {
|
---|
3218 | *out << Verbose(1) << "Writing final tecplot file\n";
|
---|
3219 | if (DoTecplotOutput) {
|
---|
3220 | string OutputName(filename);
|
---|
3221 | OutputName.append(TecplotSuffix);
|
---|
3222 | ofstream *tecplot = new ofstream(OutputName.c_str());
|
---|
3223 | write_tecplot_file(out, tecplot, Tess, mol, -1);
|
---|
3224 | tecplot->close();
|
---|
3225 | delete(tecplot);
|
---|
3226 | }
|
---|
3227 | if (DoRaster3DOutput) {
|
---|
3228 | string OutputName(filename);
|
---|
3229 | OutputName.append(Raster3DSuffix);
|
---|
3230 | ofstream *raster = new ofstream(OutputName.c_str());
|
---|
3231 | write_raster3d_file(out, raster, Tess, mol);
|
---|
3232 | raster->close();
|
---|
3233 | delete(raster);
|
---|
3234 | }
|
---|
3235 | } else {
|
---|
3236 | cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
|
---|
3237 | }
|
---|
3238 |
|
---|
3239 | cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
|
---|
3240 | int counter = 0;
|
---|
3241 | for (testline = Tess->LinesOnBoundary.begin(); testline != Tess->LinesOnBoundary.end(); testline++) {
|
---|
3242 | if (testline->second->TrianglesCount != 2) {
|
---|
3243 | cout << Verbose(2) << *testline->second << "\t" << testline->second->TrianglesCount << endl;
|
---|
3244 | counter++;
|
---|
3245 | }
|
---|
3246 | }
|
---|
3247 | if (counter == 0)
|
---|
3248 | cout << Verbose(2) << "None." << endl;
|
---|
3249 |
|
---|
3250 | if (freeTess)
|
---|
3251 | delete(Tess);
|
---|
3252 | if (freeLC)
|
---|
3253 | delete(LCList);
|
---|
3254 | *out << Verbose(0) << "End of Find_non_convex_border\n";
|
---|
3255 | };
|
---|
3256 |
|
---|
3257 | /** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
|
---|
3258 | * \param *out output stream for debugging
|
---|
3259 | * \param *srcmol molecule to embed into
|
---|
3260 | * \return *Vector new center of \a *srcmol for embedding relative to \a this
|
---|
3261 | */
|
---|
3262 | Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol)
|
---|
3263 | {
|
---|
3264 | Vector *Center = new Vector;
|
---|
3265 | Center->Zero();
|
---|
3266 | // calculate volume/shape of \a *srcmol
|
---|
3267 |
|
---|
3268 | // find embedding holes
|
---|
3269 |
|
---|
3270 | // if more than one, let user choose
|
---|
3271 |
|
---|
3272 | // return embedding center
|
---|
3273 | return Center;
|
---|
3274 | };
|
---|
3275 |
|
---|