1 | /*
|
---|
2 | * Project: MoleCuilder
|
---|
3 | * Description: creates and alters molecular systems
|
---|
4 | * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
|
---|
5 | * Copyright (C) 2013 Frederik Heber. All rights reserved.
|
---|
6 | *
|
---|
7 | *
|
---|
8 | * This file is part of MoleCuilder.
|
---|
9 | *
|
---|
10 | * MoleCuilder is free software: you can redistribute it and/or modify
|
---|
11 | * it under the terms of the GNU General Public License as published by
|
---|
12 | * the Free Software Foundation, either version 2 of the License, or
|
---|
13 | * (at your option) any later version.
|
---|
14 | *
|
---|
15 | * MoleCuilder is distributed in the hope that it will be useful,
|
---|
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
18 | * GNU General Public License for more details.
|
---|
19 | *
|
---|
20 | * You should have received a copy of the GNU General Public License
|
---|
21 | * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
|
---|
22 | */
|
---|
23 |
|
---|
24 | /** \file boundary.cpp
|
---|
25 | *
|
---|
26 | * Implementations and super-function for envelopes
|
---|
27 | */
|
---|
28 |
|
---|
29 | // include config.h
|
---|
30 | #ifdef HAVE_CONFIG_H
|
---|
31 | #include <config.h>
|
---|
32 | #endif
|
---|
33 |
|
---|
34 | //#include "CodePatterns/MemDebug.hpp"
|
---|
35 |
|
---|
36 | #include "Atom/atom.hpp"
|
---|
37 | #include "Bond/bond.hpp"
|
---|
38 | #include "boundary.hpp"
|
---|
39 | #include "BoundaryLineSet.hpp"
|
---|
40 | #include "BoundaryPointSet.hpp"
|
---|
41 | #include "BoundaryTriangleSet.hpp"
|
---|
42 | #include "Box.hpp"
|
---|
43 | #include "CandidateForTesselation.hpp"
|
---|
44 | #include "CodePatterns/Info.hpp"
|
---|
45 | #include "CodePatterns/Log.hpp"
|
---|
46 | #include "CodePatterns/Verbose.hpp"
|
---|
47 | #include "config.hpp"
|
---|
48 | #include "Element/element.hpp"
|
---|
49 | #include "LinearAlgebra/Plane.hpp"
|
---|
50 | #include "LinearAlgebra/RealSpaceMatrix.hpp"
|
---|
51 | #include "LinkedCell/linkedcell.hpp"
|
---|
52 | #include "LinkedCell/PointCloudAdaptor.hpp"
|
---|
53 | #include "molecule.hpp"
|
---|
54 | #include "RandomNumbers/RandomNumberGeneratorFactory.hpp"
|
---|
55 | #include "RandomNumbers/RandomNumberGenerator.hpp"
|
---|
56 | #include "tesselation.hpp"
|
---|
57 | #include "tesselationhelpers.hpp"
|
---|
58 | #include "World.hpp"
|
---|
59 |
|
---|
60 | #include <iostream>
|
---|
61 | #include <iomanip>
|
---|
62 |
|
---|
63 | #include<gsl/gsl_poly.h>
|
---|
64 | #include<time.h>
|
---|
65 |
|
---|
66 | // ========================================== F U N C T I O N S =================================
|
---|
67 |
|
---|
68 |
|
---|
69 | /** Determines greatest diameters of a cluster defined by its convex envelope.
|
---|
70 | * Looks at lines parallel to one axis and where they intersect on the projected planes
|
---|
71 | * \param *out output stream for debugging
|
---|
72 | * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
|
---|
73 | * \param *mol molecule structure representing the cluster
|
---|
74 | * \param *&TesselStruct Tesselation structure with triangles
|
---|
75 | * \param IsAngstroem whether we have angstroem or atomic units
|
---|
76 | * \return NDIM array of the diameters
|
---|
77 | */
|
---|
78 | double *GetDiametersOfCluster(const Boundaries *BoundaryPtr, const molecule *mol, Tesselation *&TesselStruct, const bool IsAngstroem)
|
---|
79 | {
|
---|
80 | //Info FunctionInfo(__func__);
|
---|
81 | // get points on boundary of NULL was given as parameter
|
---|
82 | bool BoundaryFreeFlag = false;
|
---|
83 | double OldComponent = 0.;
|
---|
84 | double tmp = 0.;
|
---|
85 | double w1 = 0.;
|
---|
86 | double w2 = 0.;
|
---|
87 | Vector DistanceVector;
|
---|
88 | Vector OtherVector;
|
---|
89 | int component = 0;
|
---|
90 | int Othercomponent = 0;
|
---|
91 | Boundaries::const_iterator Neighbour;
|
---|
92 | Boundaries::const_iterator OtherNeighbour;
|
---|
93 | double *GreatestDiameter = new double[NDIM];
|
---|
94 |
|
---|
95 | const Boundaries *BoundaryPoints;
|
---|
96 | if (BoundaryPtr == NULL) {
|
---|
97 | BoundaryFreeFlag = true;
|
---|
98 | BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
|
---|
99 | } else {
|
---|
100 | BoundaryPoints = BoundaryPtr;
|
---|
101 | LOG(0, "Using given boundary points set.");
|
---|
102 | }
|
---|
103 | // determine biggest "diameter" of cluster for each axis
|
---|
104 | for (int i = 0; i < NDIM; i++)
|
---|
105 | GreatestDiameter[i] = 0.;
|
---|
106 | for (int axis = 0; axis < NDIM; axis++)
|
---|
107 | { // regard each projected plane
|
---|
108 | //LOG(1, "Current axis is " << axis << ".");
|
---|
109 | for (int j = 0; j < 2; j++)
|
---|
110 | { // and for both axis on the current plane
|
---|
111 | component = (axis + j + 1) % NDIM;
|
---|
112 | Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
|
---|
113 | //LOG(1, "Current component is " << component << ", Othercomponent is " << Othercomponent << ".");
|
---|
114 | for (Boundaries::const_iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
115 | //LOG(1, "Current runner is " << *(runner->second.second) << ".");
|
---|
116 | // seek for the neighbours pair where the Othercomponent sign flips
|
---|
117 | Neighbour = runner;
|
---|
118 | Neighbour++;
|
---|
119 | if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
|
---|
120 | Neighbour = BoundaryPoints[axis].begin();
|
---|
121 | DistanceVector = (runner->second.second->getPosition()) - (Neighbour->second.second->getPosition());
|
---|
122 | do { // seek for neighbour pair where it flips
|
---|
123 | OldComponent = DistanceVector[Othercomponent];
|
---|
124 | Neighbour++;
|
---|
125 | if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
|
---|
126 | Neighbour = BoundaryPoints[axis].begin();
|
---|
127 | DistanceVector = (runner->second.second->getPosition()) - (Neighbour->second.second->getPosition());
|
---|
128 | //LOG(2, "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << ".");
|
---|
129 | } while ((runner != Neighbour) && (fabs(OldComponent / fabs(
|
---|
130 | OldComponent) - DistanceVector[Othercomponent] / fabs(
|
---|
131 | DistanceVector[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
|
---|
132 | if (runner != Neighbour) {
|
---|
133 | OtherNeighbour = Neighbour;
|
---|
134 | if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
|
---|
135 | OtherNeighbour = BoundaryPoints[axis].end();
|
---|
136 | OtherNeighbour--;
|
---|
137 | //LOG(1, "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << ".");
|
---|
138 | // now we have found the pair: Neighbour and OtherNeighbour
|
---|
139 | OtherVector = (runner->second.second->getPosition()) - (OtherNeighbour->second.second->getPosition());
|
---|
140 | //LOG(1, "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << ".");
|
---|
141 | //LOG(1, "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << ".");
|
---|
142 | // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
|
---|
143 | w1 = fabs(OtherVector[Othercomponent]);
|
---|
144 | w2 = fabs(DistanceVector[Othercomponent]);
|
---|
145 | tmp = fabs((w1 * DistanceVector[component] + w2
|
---|
146 | * OtherVector[component]) / (w1 + w2));
|
---|
147 | // mark if it has greater diameter
|
---|
148 | //LOG(1, "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << ".");
|
---|
149 | GreatestDiameter[component] = (GreatestDiameter[component]
|
---|
150 | > tmp) ? GreatestDiameter[component] : tmp;
|
---|
151 | } //else
|
---|
152 | //LOG(1, "Saw no sign flip, probably top or bottom node.");
|
---|
153 | }
|
---|
154 | }
|
---|
155 | }
|
---|
156 | LOG(0, "RESULT: The biggest diameters are "
|
---|
157 | << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
|
---|
158 | << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
|
---|
159 | : "atomiclength") << ".");
|
---|
160 |
|
---|
161 | // free reference lists
|
---|
162 | if (BoundaryFreeFlag)
|
---|
163 | delete[] (BoundaryPoints);
|
---|
164 |
|
---|
165 | return GreatestDiameter;
|
---|
166 | }
|
---|
167 | ;
|
---|
168 |
|
---|
169 |
|
---|
170 | /** Determines the boundary points of a cluster.
|
---|
171 | * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
|
---|
172 | * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
|
---|
173 | * center and first and last point in the triple, it is thrown out.
|
---|
174 | *
|
---|
175 | * \todo When storing const ptrs in tesselation structures, remove const_cast
|
---|
176 | *
|
---|
177 | * \param *out output stream for debugging
|
---|
178 | * \param *mol molecule structure representing the cluster
|
---|
179 | * \param *&TesselStruct pointer to Tesselation structure
|
---|
180 | */
|
---|
181 | Boundaries *GetBoundaryPoints(const molecule *mol, Tesselation *&TesselStruct)
|
---|
182 | {
|
---|
183 | //Info FunctionInfo(__func__);
|
---|
184 | PointMap PointsOnBoundary;
|
---|
185 | LineMap LinesOnBoundary;
|
---|
186 | TriangleMap TrianglesOnBoundary;
|
---|
187 | Vector MolCenter = mol->DetermineCenterOfAll();
|
---|
188 | Vector helper;
|
---|
189 | BoundariesTestPair BoundaryTestPair;
|
---|
190 | Vector AxisVector;
|
---|
191 | Vector AngleReferenceVector;
|
---|
192 | Vector AngleReferenceNormalVector;
|
---|
193 | Vector ProjectedVector;
|
---|
194 | Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, Nr)
|
---|
195 | double angle = 0.;
|
---|
196 |
|
---|
197 | // 3a. Go through every axis
|
---|
198 | for (int axis = 0; axis < NDIM; axis++) {
|
---|
199 | AxisVector.Zero();
|
---|
200 | AngleReferenceVector.Zero();
|
---|
201 | AngleReferenceNormalVector.Zero();
|
---|
202 | AxisVector[axis] = 1.;
|
---|
203 | AngleReferenceVector[(axis + 1) % NDIM] = 1.;
|
---|
204 | AngleReferenceNormalVector[(axis + 2) % NDIM] = 1.;
|
---|
205 |
|
---|
206 | LOG(1, "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << ".");
|
---|
207 |
|
---|
208 | // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
|
---|
209 | // Boundaries stores non-const TesselPoint ref, hence we need iterator here
|
---|
210 | for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
|
---|
211 | ProjectedVector = (*iter)->getPosition() - (MolCenter);
|
---|
212 | ProjectedVector.ProjectOntoPlane(AxisVector);
|
---|
213 |
|
---|
214 | // correct for negative side
|
---|
215 | const double radius = ProjectedVector.NormSquared();
|
---|
216 | if (fabs(radius) > MYEPSILON)
|
---|
217 | angle = ProjectedVector.Angle(AngleReferenceVector);
|
---|
218 | else
|
---|
219 | angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
|
---|
220 |
|
---|
221 | //LOG(1, "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << ".");
|
---|
222 | if (ProjectedVector.ScalarProduct(AngleReferenceNormalVector) > 0) {
|
---|
223 | angle = 2. * M_PI - angle;
|
---|
224 | }
|
---|
225 | LOG(1, "Inserting " << **iter << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector);
|
---|
226 | BoundaryTestPair = BoundaryPoints[axis].insert(
|
---|
227 | BoundariesPair(angle, TesselPointDistancePair (radius, const_cast<atom *>(*iter))));
|
---|
228 | if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
|
---|
229 | LOG(2, "Encountered two vectors whose projection onto axis " << axis << " is equal: ");
|
---|
230 | LOG(2, "Present vector: " << *BoundaryTestPair.first->second.second);
|
---|
231 | LOG(2, "New vector: " << **iter);
|
---|
232 | const double ProjectedVectorNorm = ProjectedVector.NormSquared();
|
---|
233 | if ((ProjectedVectorNorm - BoundaryTestPair.first->second.first) > MYEPSILON) {
|
---|
234 | BoundaryTestPair.first->second.first = ProjectedVectorNorm;
|
---|
235 | BoundaryTestPair.first->second.second = const_cast<atom *>(*iter);
|
---|
236 | LOG(2, "Keeping new vector due to larger projected distance " << ProjectedVectorNorm << ".");
|
---|
237 | } else if (fabs(ProjectedVectorNorm - BoundaryTestPair.first->second.first) < MYEPSILON) {
|
---|
238 | helper = (*iter)->getPosition() - (MolCenter);
|
---|
239 | const double oldhelperNorm = helper.NormSquared();
|
---|
240 | helper = BoundaryTestPair.first->second.second->getPosition() - (MolCenter);
|
---|
241 | if (helper.NormSquared() < oldhelperNorm) {
|
---|
242 | BoundaryTestPair.first->second.second = const_cast<atom *>(*iter);
|
---|
243 | LOG(2, "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << ".");
|
---|
244 | } else {
|
---|
245 | LOG(2, "Keeping present vector due to larger distance to molecule center " << oldhelperNorm << ".");
|
---|
246 | }
|
---|
247 | } else {
|
---|
248 | LOG(2, "Keeping present vector due to larger projected distance " << ProjectedVectorNorm << ".");
|
---|
249 | }
|
---|
250 | }
|
---|
251 | }
|
---|
252 | // printing all inserted for debugging
|
---|
253 | // {
|
---|
254 | // std::stringstream output;
|
---|
255 | // output << "Printing list of candidates for axis " << axis << " which we have inserted so far: ";
|
---|
256 | // int i=0;
|
---|
257 | // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
258 | // if (runner != BoundaryPoints[axis].begin())
|
---|
259 | // output << ", " << i << ": " << *runner->second.second;
|
---|
260 | // else
|
---|
261 | // output << i << ": " << *runner->second.second;
|
---|
262 | // i++;
|
---|
263 | // }
|
---|
264 | // LOG(1, output.str());
|
---|
265 | // }
|
---|
266 | // 3c. throw out points whose distance is less than the mean of left and right neighbours
|
---|
267 | bool flag = false;
|
---|
268 | LOG(1, "Looking for candidates to kick out by convex condition ... ");
|
---|
269 | do { // do as long as we still throw one out per round
|
---|
270 | flag = false;
|
---|
271 | Boundaries::iterator left = BoundaryPoints[axis].begin();
|
---|
272 | Boundaries::iterator right = BoundaryPoints[axis].begin();
|
---|
273 | Boundaries::iterator runner = BoundaryPoints[axis].begin();
|
---|
274 | bool LoopOnceDone = false;
|
---|
275 | while (!LoopOnceDone) {
|
---|
276 | runner = right;
|
---|
277 | right++;
|
---|
278 | // set neighbours correctly
|
---|
279 | if (runner == BoundaryPoints[axis].begin()) {
|
---|
280 | left = BoundaryPoints[axis].end();
|
---|
281 | } else {
|
---|
282 | left = runner;
|
---|
283 | }
|
---|
284 | left--;
|
---|
285 | if (right == BoundaryPoints[axis].end()) {
|
---|
286 | right = BoundaryPoints[axis].begin();
|
---|
287 | LoopOnceDone = true;
|
---|
288 | }
|
---|
289 | // check distance
|
---|
290 |
|
---|
291 | // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
|
---|
292 | {
|
---|
293 | Vector SideA, SideB, SideC, SideH;
|
---|
294 | SideA = left->second.second->getPosition() - (MolCenter);
|
---|
295 | SideA.ProjectOntoPlane(AxisVector);
|
---|
296 | // LOG(1, "SideA: " << SideA);
|
---|
297 |
|
---|
298 | SideB = right->second.second->getPosition() -(MolCenter);
|
---|
299 | SideB.ProjectOntoPlane(AxisVector);
|
---|
300 | // LOG(1, "SideB: " << SideB);
|
---|
301 |
|
---|
302 | SideC = left->second.second->getPosition() - right->second.second->getPosition();
|
---|
303 | SideC.ProjectOntoPlane(AxisVector);
|
---|
304 | // LOG(1, "SideC: " << SideC);
|
---|
305 |
|
---|
306 | SideH = runner->second.second->getPosition() -(MolCenter);
|
---|
307 | SideH.ProjectOntoPlane(AxisVector);
|
---|
308 | // LOG(1, "SideH: " << SideH);
|
---|
309 |
|
---|
310 | // calculate each length
|
---|
311 | const double a = SideA.Norm();
|
---|
312 | //const double b = SideB.Norm();
|
---|
313 | //const double c = SideC.Norm();
|
---|
314 | const double h = SideH.Norm();
|
---|
315 | // calculate the angles
|
---|
316 | const double alpha = SideA.Angle(SideH);
|
---|
317 | const double beta = SideA.Angle(SideC);
|
---|
318 | const double gamma = SideB.Angle(SideH);
|
---|
319 | const double delta = SideC.Angle(SideH);
|
---|
320 | const double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
|
---|
321 | //LOG(1, " 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 << ".");
|
---|
322 | LOG(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 << ".");
|
---|
323 | if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
|
---|
324 | // throw out point
|
---|
325 | LOG(1, "Throwing out " << *runner->second.second << ".");
|
---|
326 | BoundaryPoints[axis].erase(runner);
|
---|
327 | runner = right;
|
---|
328 | flag = true;
|
---|
329 | }
|
---|
330 | }
|
---|
331 | }
|
---|
332 | } while (flag);
|
---|
333 | }
|
---|
334 | return BoundaryPoints;
|
---|
335 | };
|
---|
336 |
|
---|
337 | /** Tesselates the convex boundary by finding all boundary points.
|
---|
338 | * \param *out output stream for debugging
|
---|
339 | * \param *mol molecule structure with Atom's and Bond's.
|
---|
340 | * \param *BoundaryPts set of boundary points to use or NULL
|
---|
341 | * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
|
---|
342 | * \param *LCList atoms in LinkedCell_deprecated list
|
---|
343 | * \param *filename filename prefix for output of vertex data
|
---|
344 | * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
|
---|
345 | */
|
---|
346 | void FindConvexBorder(const molecule* mol, Boundaries *BoundaryPts, Tesselation *&TesselStruct, const LinkedCell_deprecated *LCList, const char *filename)
|
---|
347 | {
|
---|
348 | //Info FunctionInfo(__func__);
|
---|
349 | bool BoundaryFreeFlag = false;
|
---|
350 | Boundaries *BoundaryPoints = NULL;
|
---|
351 |
|
---|
352 | if (TesselStruct != NULL) // free if allocated
|
---|
353 | delete(TesselStruct);
|
---|
354 | TesselStruct = new class Tesselation;
|
---|
355 |
|
---|
356 | // 1. Find all points on the boundary
|
---|
357 | if (BoundaryPts == NULL) {
|
---|
358 | BoundaryFreeFlag = true;
|
---|
359 | BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
|
---|
360 | } else {
|
---|
361 | BoundaryPoints = BoundaryPts;
|
---|
362 | LOG(0, "Using given boundary points set.");
|
---|
363 | }
|
---|
364 |
|
---|
365 | // printing all inserted for debugging
|
---|
366 | if (DoLog(1)) {
|
---|
367 | for (int axis=0; axis < NDIM; axis++) {
|
---|
368 | std::stringstream output;
|
---|
369 | output << "Printing list of candidates for axis " << axis << " which we have inserted so far: ";
|
---|
370 | int i=0;
|
---|
371 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
372 | if (runner != BoundaryPoints[axis].begin())
|
---|
373 | output << ", " << i << ": " << *runner->second.second;
|
---|
374 | else
|
---|
375 | output << i << ": " << *runner->second.second;
|
---|
376 | i++;
|
---|
377 | }
|
---|
378 | LOG(1, output.str());
|
---|
379 | }
|
---|
380 | }
|
---|
381 |
|
---|
382 | // 2. fill the boundary point list
|
---|
383 | for (int axis = 0; axis < NDIM; axis++)
|
---|
384 | for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
|
---|
385 | if (!TesselStruct->AddBoundaryPoint(runner->second.second, 0))
|
---|
386 | LOG(2, "Point " << *(runner->second.second) << " is already present.");
|
---|
387 |
|
---|
388 | LOG(0, "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary.");
|
---|
389 | // now we have the whole set of edge points in the BoundaryList
|
---|
390 |
|
---|
391 | // listing for debugging
|
---|
392 | //if (DoLog(1)) {
|
---|
393 | // std::stringstream output;
|
---|
394 | // output << "Listing PointsOnBoundary:";
|
---|
395 | // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
|
---|
396 | // output << " " << *runner->second;
|
---|
397 | // }
|
---|
398 | // LOG(1, output.str());
|
---|
399 | //}
|
---|
400 |
|
---|
401 | // 3a. guess starting triangle
|
---|
402 | TesselStruct->GuessStartingTriangle();
|
---|
403 |
|
---|
404 | // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
|
---|
405 | PointCloudAdaptor< molecule > cloud(const_cast<molecule *>(mol), mol->name);
|
---|
406 | TesselStruct->TesselateOnBoundary(cloud);
|
---|
407 |
|
---|
408 | // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
|
---|
409 | if (!TesselStruct->InsertStraddlingPoints(cloud, LCList))
|
---|
410 | ELOG(1, "Insertion of straddling points failed!");
|
---|
411 |
|
---|
412 | LOG(0, "I created " << TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points.");
|
---|
413 |
|
---|
414 | // 4. Store triangles in tecplot file
|
---|
415 | StoreTrianglesinFile(mol, TesselStruct, filename, "_intermed");
|
---|
416 |
|
---|
417 | // 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
|
---|
418 | bool AllConvex = true;
|
---|
419 | class BoundaryLineSet *line = NULL;
|
---|
420 | do {
|
---|
421 | AllConvex = true;
|
---|
422 | for (LineMap::iterator LineRunner = TesselStruct->LinesOnBoundary.begin(); LineRunner != TesselStruct->LinesOnBoundary.end(); LineRunner++) {
|
---|
423 | line = LineRunner->second;
|
---|
424 | LOG(1, "INFO: Current line is " << *line << ".");
|
---|
425 | if (!line->CheckConvexityCriterion()) {
|
---|
426 | LOG(1, "... line " << *line << " is concave, flipping it.");
|
---|
427 |
|
---|
428 | // flip the line
|
---|
429 | if (TesselStruct->PickFarthestofTwoBaselines(line) == 0.)
|
---|
430 | ELOG(1, "Correction of concave baselines failed!");
|
---|
431 | else {
|
---|
432 | TesselStruct->FlipBaseline(line);
|
---|
433 | LOG(1, "INFO: Correction of concave baselines worked.");
|
---|
434 | LineRunner = TesselStruct->LinesOnBoundary.begin(); // LineRunner may have been erase if line was deleted from LinesOnBoundary
|
---|
435 | }
|
---|
436 | }
|
---|
437 | }
|
---|
438 | } while (!AllConvex);
|
---|
439 |
|
---|
440 | // 3e. we need another correction here, for TesselPoints that are below the surface (i.e. have an odd number of concave triangles surrounding it)
|
---|
441 | // if (!TesselStruct->CorrectConcaveTesselPoints(out))
|
---|
442 | // ELOG(1, "Correction of concave tesselpoints failed!");
|
---|
443 |
|
---|
444 | LOG(0, "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points.");
|
---|
445 |
|
---|
446 | // 4. Store triangles in tecplot file
|
---|
447 | StoreTrianglesinFile(mol, TesselStruct, filename, "");
|
---|
448 |
|
---|
449 | // free reference lists
|
---|
450 | if (BoundaryFreeFlag)
|
---|
451 | delete[] (BoundaryPoints);
|
---|
452 | };
|
---|
453 |
|
---|
454 | /** For testing removes one boundary point after another to check for leaks.
|
---|
455 | * \param *out output stream for debugging
|
---|
456 | * \param *TesselStruct Tesselation containing envelope with boundary points
|
---|
457 | * \param *mol molecule
|
---|
458 | * \param *filename name of file
|
---|
459 | * \return true - all removed, false - something went wrong
|
---|
460 | */
|
---|
461 | bool RemoveAllBoundaryPoints(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
|
---|
462 | {
|
---|
463 | //Info FunctionInfo(__func__);
|
---|
464 | int i=0;
|
---|
465 | char number[MAXSTRINGSIZE];
|
---|
466 |
|
---|
467 | if ((TesselStruct == NULL) || (TesselStruct->PointsOnBoundary.empty())) {
|
---|
468 | ELOG(1, "TesselStruct is empty.");
|
---|
469 | return false;
|
---|
470 | }
|
---|
471 |
|
---|
472 | PointMap::iterator PointRunner;
|
---|
473 | while (!TesselStruct->PointsOnBoundary.empty()) {
|
---|
474 | if (DoLog(1)) {
|
---|
475 | std::stringstream output;
|
---|
476 | output << "Remaining points are: ";
|
---|
477 | for (PointMap::iterator PointSprinter = TesselStruct->PointsOnBoundary.begin(); PointSprinter != TesselStruct->PointsOnBoundary.end(); PointSprinter++)
|
---|
478 | output << *(PointSprinter->second) << "\t";
|
---|
479 | LOG(1, output.str());
|
---|
480 | }
|
---|
481 |
|
---|
482 | PointRunner = TesselStruct->PointsOnBoundary.begin();
|
---|
483 | // remove point
|
---|
484 | TesselStruct->RemovePointFromTesselatedSurface(PointRunner->second);
|
---|
485 |
|
---|
486 | // store envelope
|
---|
487 | sprintf(number, "-%04d", i++);
|
---|
488 | StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, number);
|
---|
489 | }
|
---|
490 |
|
---|
491 | return true;
|
---|
492 | };
|
---|
493 |
|
---|
494 | /** Creates a convex envelope from a given non-convex one.
|
---|
495 | * -# First step, remove concave spots, i.e. singular "dents"
|
---|
496 | * -# We go through all PointsOnBoundary.
|
---|
497 | * -# We CheckConvexityCriterion() for all its lines.
|
---|
498 | * -# If all its lines are concave, it cannot be on the convex envelope.
|
---|
499 | * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
|
---|
500 | * -# We calculate the additional volume.
|
---|
501 | * -# We go over all lines until none yields a concavity anymore.
|
---|
502 | * -# Second step, remove concave lines, i.e. line-shape "dents"
|
---|
503 | * -# We go through all LinesOnBoundary
|
---|
504 | * -# We CheckConvexityCriterion()
|
---|
505 | * -# If it returns concave, we flip the line in this quadrupel of points (abusing the degeneracy of the tesselation)
|
---|
506 | * -# We CheckConvexityCriterion(),
|
---|
507 | * -# if it's concave, we continue
|
---|
508 | * -# if not, we mark an error and stop
|
---|
509 | * Note: This routine - for free - calculates the difference in volume between convex and
|
---|
510 | * non-convex envelope, as the former is easy to calculate - Tesselation::getVolumeOfConvexEnvelope() - it
|
---|
511 | * can be used to compute volumes of arbitrary shapes.
|
---|
512 | * \param *out output stream for debugging
|
---|
513 | * \param *TesselStruct non-convex envelope, is changed in return!
|
---|
514 | * \param *mol molecule
|
---|
515 | * \param *filename name of file
|
---|
516 | * \return volume difference between the non- and the created convex envelope
|
---|
517 | */
|
---|
518 | double ConvexizeNonconvexEnvelope(
|
---|
519 | Tesselation *&TesselStruct,
|
---|
520 | const molecule * const mol,
|
---|
521 | const char * const filename,
|
---|
522 | bool DebugOutputEveryStep)
|
---|
523 | {
|
---|
524 | //Info FunctionInfo(__func__);
|
---|
525 | double volume = 0;
|
---|
526 | class BoundaryPointSet *point = NULL;
|
---|
527 | class BoundaryLineSet *line = NULL;
|
---|
528 | bool Concavity = false;
|
---|
529 | char dummy[MAXSTRINGSIZE];
|
---|
530 | PointMap::iterator PointRunner;
|
---|
531 | PointMap::iterator PointAdvance;
|
---|
532 | LineMap::iterator LineRunner;
|
---|
533 | LineMap::iterator LineAdvance;
|
---|
534 | TriangleMap::iterator TriangleRunner;
|
---|
535 | TriangleMap::iterator TriangleAdvance;
|
---|
536 | int run = 0;
|
---|
537 |
|
---|
538 | // check whether there is something to work on
|
---|
539 | if (TesselStruct == NULL) {
|
---|
540 | ELOG(1, "TesselStruct is empty!");
|
---|
541 | return volume;
|
---|
542 | }
|
---|
543 |
|
---|
544 | LOG(1, "INFO: Making tesselated surface with " << TesselStruct->TrianglesOnBoundaryCount
|
---|
545 | << " convex ...");
|
---|
546 |
|
---|
547 | // first purge all degenerate triangles
|
---|
548 | TesselStruct->RemoveDegeneratedTriangles();
|
---|
549 |
|
---|
550 | do {
|
---|
551 | Concavity = false;
|
---|
552 |
|
---|
553 | if (DebugOutputEveryStep) {
|
---|
554 | sprintf(dummy, "-%d", run++);
|
---|
555 | //CalculateConcavityPerBoundaryPoint(TesselStruct);
|
---|
556 | LOG(1, "INFO: Writing " << run << "th tesselation file.");
|
---|
557 | StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
|
---|
558 | }
|
---|
559 |
|
---|
560 | // first step: remove all full-concave point
|
---|
561 | PointRunner = TesselStruct->PointsOnBoundary.begin();
|
---|
562 | PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
|
---|
563 | while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
|
---|
564 | PointAdvance++;
|
---|
565 | point = PointRunner->second;
|
---|
566 | LOG(2, "INFO: Current point is " << *point << ".");
|
---|
567 | // check that at least a single line is concave
|
---|
568 | LineMap::iterator LineRunner = point->lines.begin();
|
---|
569 | for (; LineRunner != point->lines.end(); LineRunner++) {
|
---|
570 | const BoundaryLineSet * line = LineRunner->second;
|
---|
571 | LOG(3, "INFO: Current line of point " << *point << " is " << *line << ".");
|
---|
572 | if (!line->CheckConvexityCriterion())
|
---|
573 | break;
|
---|
574 | }
|
---|
575 | // remove the point if needed
|
---|
576 | if (LineRunner != point->lines.end()) {
|
---|
577 | const double tmp = TesselStruct->RemoveFullConcavePointFromTesselatedSurface(point);
|
---|
578 | if (tmp > 0.) {
|
---|
579 | volume += tmp;
|
---|
580 | Concavity = true;
|
---|
581 | }
|
---|
582 | }
|
---|
583 | PointRunner = PointAdvance;
|
---|
584 | }
|
---|
585 |
|
---|
586 | if (DebugOutputEveryStep) {
|
---|
587 | sprintf(dummy, "-%d", run++);
|
---|
588 | //CalculateConcavityPerBoundaryPoint(TesselStruct);
|
---|
589 | LOG(1, "INFO: Writing " << run << "th tesselation file.");
|
---|
590 | StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
|
---|
591 | }
|
---|
592 |
|
---|
593 | // second step: flip baselines, i.e. add general tetraeder at concave lines
|
---|
594 | // when the tetraeder does not intersect with other already present triangles
|
---|
595 | LineRunner = TesselStruct->LinesOnBoundary.begin();
|
---|
596 | LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
|
---|
597 | std::map<double, std::pair<BoundaryLineSet *, double> > GainMap;
|
---|
598 | while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
|
---|
599 | LineAdvance++;
|
---|
600 | line = LineRunner->second;
|
---|
601 | if (!line->CheckConvexityCriterion()) {
|
---|
602 | LOG(2, "INFO: concave line is " << *line << ".");
|
---|
603 | // gather the other points
|
---|
604 | BoundaryPointSet *BPS[4];
|
---|
605 | int m = 0;
|
---|
606 | {
|
---|
607 | for (TriangleMap::iterator runner = line->triangles.begin(); runner != line->triangles.end(); runner++)
|
---|
608 | for (int j = 0; j < 3; j++) // all of their endpoints and baselines
|
---|
609 | if (!line->ContainsBoundaryPoint(runner->second->endpoints[j])) // and neither of its endpoints
|
---|
610 | BPS[m++] = runner->second->endpoints[j];
|
---|
611 | }
|
---|
612 | BPS[2] = line->endpoints[0];
|
---|
613 | BPS[3] = line->endpoints[1];
|
---|
614 | LOG(3, "DEBUG: other line would consist of " << *BPS[0] << " and "
|
---|
615 | << *BPS[1] << ".");
|
---|
616 |
|
---|
617 | // check for already present (third) side of the tetraeder as we then
|
---|
618 | // would create a degenerate triangle
|
---|
619 | bool TetraederSidePresent = false;
|
---|
620 | {
|
---|
621 | class TesselPoint *TriangleCandidates[3];
|
---|
622 | TriangleCandidates[0] = BPS[0]->node;
|
---|
623 | TriangleCandidates[1] = BPS[1]->node;
|
---|
624 | TriangleCandidates[2] = BPS[2]->node;
|
---|
625 | if ((TesselStruct->GetPresentTriangle(TriangleCandidates) != NULL)) {
|
---|
626 | LOG(2, "REJECT: Triangle side " << *TriangleCandidates[0] << ","
|
---|
627 | << *TriangleCandidates[1] << "," << *TriangleCandidates[2] << " present.");
|
---|
628 | TetraederSidePresent = true;
|
---|
629 | }
|
---|
630 | TriangleCandidates[2] = BPS[3]->node;
|
---|
631 | if ((TesselStruct->GetPresentTriangle(TriangleCandidates) != NULL)) {
|
---|
632 | LOG(2, "REJECT: Triangle side " << *TriangleCandidates[0] << ","
|
---|
633 | << *TriangleCandidates[1] << "," << *TriangleCandidates[2] << " present.");
|
---|
634 | TetraederSidePresent = true;
|
---|
635 | }
|
---|
636 | }
|
---|
637 |
|
---|
638 | if ((BPS[0] != BPS[1]) && (m == 2) && (!TetraederSidePresent)) {
|
---|
639 | // check whether all adjacent triangles do not intersect with new line
|
---|
640 | bool no_line_intersects = true;
|
---|
641 | Vector Intersection;
|
---|
642 | TriangleSet triangles;
|
---|
643 | TriangleSet *firsttriangles = TesselStruct->GetAllTriangles(line->endpoints[0]);
|
---|
644 | TriangleSet *secondtriangles = TesselStruct->GetAllTriangles(line->endpoints[1]);
|
---|
645 | triangles.insert( firsttriangles->begin(), firsttriangles->end() );
|
---|
646 | triangles.insert( secondtriangles->begin(), secondtriangles->end() );
|
---|
647 | delete firsttriangles;
|
---|
648 | delete secondtriangles;
|
---|
649 | for (TriangleSet::const_iterator triangleiter = triangles.begin();
|
---|
650 | triangleiter != triangles.end(); ++triangleiter) {
|
---|
651 | const BoundaryTriangleSet * triangle = *triangleiter;
|
---|
652 | bool line_intersects = triangle->GetIntersectionInsideTriangle(
|
---|
653 | BPS[0]->node->getPosition(),
|
---|
654 | BPS[1]->node->getPosition(),
|
---|
655 | Intersection);
|
---|
656 | // switch result when coinciding with endpoint
|
---|
657 | bool concave_adjacent_line = false;
|
---|
658 | bool intersection_is_endnode = false;
|
---|
659 | for (int j=0;j<2;++j) {
|
---|
660 | if (Intersection.DistanceSquared(BPS[j]->node->getPosition()) < MYEPSILON) {
|
---|
661 | intersection_is_endnode = true;
|
---|
662 | // check whether its an adjacent triangle and if it's concavely connected
|
---|
663 | // only then are we in danger of cutting through it and need to check
|
---|
664 | // sign of normal vector and intersecting line
|
---|
665 | for (int i=0;i<2;++i)
|
---|
666 | for (int lineindex=0;lineindex < 3;++lineindex)
|
---|
667 | if ((triangle->lines[lineindex]->ContainsBoundaryPoint(line->endpoints[i]))
|
---|
668 | && (triangle->lines[lineindex]->ContainsBoundaryPoint(BPS[j]))) {
|
---|
669 | concave_adjacent_line = !triangle->lines[lineindex]->CheckConvexityCriterion();
|
---|
670 | }
|
---|
671 | if (concave_adjacent_line) {
|
---|
672 | const Vector intersector =
|
---|
673 | BPS[(j+1)%2]->node->getPosition() - Intersection;
|
---|
674 | if (triangle->NormalVector.ScalarProduct(intersector) >= -MYEPSILON) {
|
---|
675 | LOG(4, "ACCEPT: Intersection coincides with first endpoint "
|
---|
676 | << *BPS[j] << ".");
|
---|
677 | line_intersects = false;
|
---|
678 | } else {
|
---|
679 | LOG(4, "REJECT: Intersection ends on wrong side of triangle.");
|
---|
680 | }
|
---|
681 | } else {
|
---|
682 | LOG(4, "ACCEPT: Intersection coincides with first endpoint "
|
---|
683 | << *BPS[j] << ".");
|
---|
684 | line_intersects = false;
|
---|
685 | }
|
---|
686 | }
|
---|
687 | }
|
---|
688 | // if we have an intersection, check that it is within either
|
---|
689 | // endpoint, i.e. check that scalar product between vectors going
|
---|
690 | // from intersction to either endpoint has negative sign (both
|
---|
691 | // vectors point in opposite directions)
|
---|
692 | if (!intersection_is_endnode && line_intersects) {
|
---|
693 | const Vector firstvector = BPS[0]->node->getPosition() - Intersection;
|
---|
694 | const Vector secondvector = BPS[1]->node->getPosition() - Intersection;
|
---|
695 | if (firstvector.ScalarProduct(secondvector) >= 0)
|
---|
696 | line_intersects = false;
|
---|
697 | }
|
---|
698 | no_line_intersects &= !line_intersects;
|
---|
699 | }
|
---|
700 |
|
---|
701 | if (no_line_intersects) {
|
---|
702 | // calculate the volume
|
---|
703 | const double tmp = line->CalculateConvexity();
|
---|
704 | const double gain =
|
---|
705 | CalculateVolumeofGeneralTetraeder(
|
---|
706 | BPS[0]->node->getPosition(),
|
---|
707 | BPS[1]->node->getPosition(),
|
---|
708 | BPS[2]->node->getPosition(),
|
---|
709 | BPS[3]->node->getPosition());
|
---|
710 |
|
---|
711 | GainMap.insert(std::make_pair(tmp, std::make_pair(line,gain) ));
|
---|
712 | LOG(2, "DEBUG: Adding concave line " << *line << " with gain of "
|
---|
713 | << gain << ".");
|
---|
714 | } else {
|
---|
715 | // if 2 or 3 don't
|
---|
716 | LOG(2, "DEBUG: We don't added concave line " << *line
|
---|
717 | << " as other line intersects with adjacent triangles.");
|
---|
718 | }
|
---|
719 | }
|
---|
720 | }
|
---|
721 | LineRunner = LineAdvance;
|
---|
722 | }
|
---|
723 | // flip line with most gain
|
---|
724 | if (!GainMap.empty()) {
|
---|
725 | line = GainMap.begin()->second.first;
|
---|
726 | const double tmp = GainMap.begin()->second.second;
|
---|
727 | volume += tmp;
|
---|
728 |
|
---|
729 | // GainMap.clear();
|
---|
730 |
|
---|
731 | // and flip the line
|
---|
732 | LOG(1, "INFO: Flipping current most concave line " << *line << " with gain of "
|
---|
733 | << tmp << ".");
|
---|
734 | TesselStruct->FlipBaseline(line);
|
---|
735 | Concavity = true;
|
---|
736 | }
|
---|
737 | } while ((Concavity)); // && (run < 100)
|
---|
738 |
|
---|
739 | CalculateConcavityPerBoundaryPoint(TesselStruct);
|
---|
740 | StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
|
---|
741 |
|
---|
742 | // end
|
---|
743 | LOG(0, "RESULT: Added volume in convexization is " << volume << ".");
|
---|
744 | return volume;
|
---|
745 | };
|
---|
746 |
|
---|
747 |
|
---|
748 | /** Stores triangles to file.
|
---|
749 | * \param *out output stream for debugging
|
---|
750 | * \param *mol molecule with atoms and bonds
|
---|
751 | * \param *TesselStruct Tesselation with boundary triangles
|
---|
752 | * \param *filename prefix of filename
|
---|
753 | * \param *extraSuffix intermediate suffix
|
---|
754 | */
|
---|
755 | void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix)
|
---|
756 | {
|
---|
757 | //Info FunctionInfo(__func__);
|
---|
758 | PointCloudAdaptor< molecule > cloud(const_cast<molecule *>(mol), mol->name);
|
---|
759 | // 4. Store triangles in tecplot file
|
---|
760 | if (filename != NULL) {
|
---|
761 | if (DoTecplotOutput) {
|
---|
762 | string OutputName(filename);
|
---|
763 | OutputName.append(extraSuffix);
|
---|
764 | OutputName.append(TecplotSuffix);
|
---|
765 | ofstream *tecplot = new ofstream(OutputName.c_str());
|
---|
766 | WriteTecplotFile(tecplot, TesselStruct, cloud, -1);
|
---|
767 | tecplot->close();
|
---|
768 | delete(tecplot);
|
---|
769 | }
|
---|
770 | if (DoRaster3DOutput) {
|
---|
771 | string OutputName(filename);
|
---|
772 | OutputName.append(extraSuffix);
|
---|
773 | OutputName.append(Raster3DSuffix);
|
---|
774 | ofstream *rasterplot = new ofstream(OutputName.c_str());
|
---|
775 | WriteRaster3dFile(rasterplot, TesselStruct, cloud);
|
---|
776 | rasterplot->close();
|
---|
777 | delete(rasterplot);
|
---|
778 | }
|
---|
779 | }
|
---|
780 | };
|
---|
781 |
|
---|
782 | /** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
|
---|
783 | * \param *out output stream for debugging
|
---|
784 | * \param *mol molecule structure with Atom's and Bond's
|
---|
785 | * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
|
---|
786 | * \param *&LCList atoms in LinkedCell_deprecated list
|
---|
787 | * \param RADIUS radius of the virtual sphere
|
---|
788 | * \param *filename filename prefix for output of vertex data
|
---|
789 | * \return true - tesselation successful, false - tesselation failed
|
---|
790 | */
|
---|
791 | bool FindNonConvexBorder(molecule* const mol, Tesselation *&TesselStruct, const LinkedCell_deprecated *&LCList, const double RADIUS, const char *filename = NULL)
|
---|
792 | {
|
---|
793 | //Info FunctionInfo(__func__);
|
---|
794 | bool freeLC = false;
|
---|
795 | bool status = false;
|
---|
796 | CandidateForTesselation *baseline = NULL;
|
---|
797 | bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
|
---|
798 | // bool TesselationFailFlag = false;
|
---|
799 |
|
---|
800 | mol->getAtomCount();
|
---|
801 |
|
---|
802 | if (TesselStruct == NULL) {
|
---|
803 | LOG(1, "Allocating Tesselation struct ...");
|
---|
804 | TesselStruct= new Tesselation;
|
---|
805 | } else {
|
---|
806 | delete(TesselStruct);
|
---|
807 | LOG(1, "Re-Allocating Tesselation struct ...");
|
---|
808 | TesselStruct = new Tesselation;
|
---|
809 | }
|
---|
810 |
|
---|
811 | // initialise Linked Cell
|
---|
812 | PointCloudAdaptor< molecule > cloud(mol, mol->name);
|
---|
813 | if (LCList == NULL) {
|
---|
814 | LCList = new LinkedCell_deprecated(cloud, 2.*RADIUS);
|
---|
815 | freeLC = true;
|
---|
816 | }
|
---|
817 |
|
---|
818 | // 1. get starting triangle
|
---|
819 | if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
|
---|
820 | ELOG(0, "No valid starting triangle found.");
|
---|
821 | //performCriticalExit();
|
---|
822 | }
|
---|
823 | if (filename != NULL) {
|
---|
824 | if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
|
---|
825 | TesselStruct->Output(filename, cloud);
|
---|
826 | }
|
---|
827 | }
|
---|
828 |
|
---|
829 | // 2. expand from there
|
---|
830 | while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
|
---|
831 | (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
|
---|
832 | // 2a. print OpenLines without candidates
|
---|
833 | LOG(1, "There are the following open lines to scan for a candidates:");
|
---|
834 | for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
|
---|
835 | if (Runner->second->pointlist.empty())
|
---|
836 | LOG(1, " " << *(Runner->second));
|
---|
837 |
|
---|
838 | // 2b. find best candidate for each OpenLine
|
---|
839 | const bool TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
|
---|
840 | ASSERT( TesselationFailFlag,
|
---|
841 | "FindNonConvexBorder() - at least one open line without candidate exists.");
|
---|
842 |
|
---|
843 | // 2c. print OpenLines with candidates again
|
---|
844 | LOG(1, "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:");
|
---|
845 | for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
|
---|
846 | LOG(1, " " << *(Runner->second));
|
---|
847 |
|
---|
848 | // 2d. search for smallest ShortestAngle among all candidates
|
---|
849 | double ShortestAngle = 4.*M_PI;
|
---|
850 | for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
|
---|
851 | if (Runner->second->ShortestAngle < ShortestAngle) {
|
---|
852 | baseline = Runner->second;
|
---|
853 | ShortestAngle = baseline->ShortestAngle;
|
---|
854 | LOG(1, "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle);
|
---|
855 | }
|
---|
856 | }
|
---|
857 | // 2e. if we found one, add candidate
|
---|
858 | if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
|
---|
859 | OneLoopWithoutSuccessFlag = false;
|
---|
860 | else {
|
---|
861 | TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
|
---|
862 | }
|
---|
863 |
|
---|
864 | // 2f. write temporary envelope
|
---|
865 | if (filename != NULL) {
|
---|
866 | if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
|
---|
867 | TesselStruct->Output(filename, cloud);
|
---|
868 | }
|
---|
869 | }
|
---|
870 | }
|
---|
871 | // // check envelope for consistency
|
---|
872 | // status = CheckListOfBaselines(TesselStruct);
|
---|
873 | //
|
---|
874 | // // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
|
---|
875 | // //->InsertStraddlingPoints(mol, LCList);
|
---|
876 | // for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
|
---|
877 | // class TesselPoint *Runner = NULL;
|
---|
878 | // Runner = *iter;
|
---|
879 | // LOG(1, "Checking on " << Runner->Name << " ... ");
|
---|
880 | // if (!->IsInnerPoint(Runner, LCList)) {
|
---|
881 | // LOG(2, Runner->Name << " is outside of envelope, adding via degenerated triangles.");
|
---|
882 | // ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
|
---|
883 | // } else {
|
---|
884 | // LOG(2, Runner->Name << " is inside of or on envelope.");
|
---|
885 | // }
|
---|
886 | // }
|
---|
887 |
|
---|
888 | // // Purges surplus triangles.
|
---|
889 | // TesselStruct->RemoveDegeneratedTriangles();
|
---|
890 | //
|
---|
891 | // // check envelope for consistency
|
---|
892 | // status = CheckListOfBaselines(TesselStruct);
|
---|
893 |
|
---|
894 | // cout << "before correction" << endl;
|
---|
895 |
|
---|
896 | // store before correction
|
---|
897 | StoreTrianglesinFile(mol, TesselStruct, filename, "");
|
---|
898 |
|
---|
899 | // // correct degenerated polygons
|
---|
900 | // TesselStruct->CorrectAllDegeneratedPolygons();
|
---|
901 | //
|
---|
902 | // check envelope for consistency
|
---|
903 | status = CheckListOfBaselines(TesselStruct);
|
---|
904 |
|
---|
905 | // write final envelope
|
---|
906 | CalculateConcavityPerBoundaryPoint(TesselStruct);
|
---|
907 | // cout << "after correction" << endl;
|
---|
908 | StoreTrianglesinFile(mol, TesselStruct, filename, "");
|
---|
909 |
|
---|
910 | if (freeLC)
|
---|
911 | delete(LCList);
|
---|
912 |
|
---|
913 | return status;
|
---|
914 | };
|
---|