source: src/Shapes/BaseShapes.cpp@ eb0d77

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since eb0d77 was 5d4179f, checked in by Frederik Heber <heber@…>, 13 years ago

Fixed minimal radius, so r will never be 0.

  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * BaseShapes_impl.cpp
10 *
11 * Created on: Jun 18, 2010
12 * Author: crueger
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include "Shapes/BaseShapes.hpp"
23#include "Shapes/BaseShapes_impl.hpp"
24#include "Shapes/ShapeExceptions.hpp"
25#include "Shapes/ShapeOps.hpp"
26
27#include "Helpers/defs.hpp"
28
29#include "CodePatterns/Assert.hpp"
30#include "LinearAlgebra/Vector.hpp"
31#include "LinearAlgebra/RealSpaceMatrix.hpp"
32#include "LinearAlgebra/Line.hpp"
33#include "LinearAlgebra/Plane.hpp"
34#include "LinearAlgebra/LineSegment.hpp"
35#include "LinearAlgebra/LineSegmentSet.hpp"
36
37#include <cmath>
38#include <algorithm>
39
40// CYLINDER CODE
41// ----------------------------------------------------------------------------
42bool Cylinder_impl::isInside(const Vector &point) const {
43 return (Vector(point[0], point[1], 0.0).NormSquared() < 1.0+MYEPSILON) &&
44 (point[2] > -1.0-MYEPSILON) && (point[2] < 1.0+MYEPSILON);
45}
46
47bool Cylinder_impl::isOnSurface(const Vector &point) const {
48 return fabs(Vector(point[0], point[1], 0.0).NormSquared()-1.0)<MYEPSILON &&
49 (point[2] > -1.0-MYEPSILON) && (point[2] < 1.0+MYEPSILON);
50
51}
52
53Vector Cylinder_impl::getNormal(const Vector &point) const throw(NotOnSurfaceException) {
54 if(!isOnSurface(point)){
55 throw NotOnSurfaceException() << ShapeVector(&point);
56 }
57
58 if ((fabs(point[2]-1)<MYEPSILON) || (fabs(point[2])<MYEPSILON))
59 return Vector(0.0, 0.0, point[2]);
60 else
61 return Vector(point[0], point[1], 0.0);
62}
63
64Vector Cylinder_impl::getCenter() const
65{
66 return Vector(0.0, 0.0, 0.0);
67}
68
69double Cylinder_impl::getRadius() const
70{
71 return 1.0;
72}
73
74double Cylinder_impl::getVolume() const
75{
76 return M_PI*2.0; // pi r^2 h
77}
78
79double Cylinder_impl::getSurfaceArea() const
80{
81 return 2.0*M_PI*2.0; // 2 pi r h
82}
83
84LineSegmentSet Cylinder_impl::getLineIntersections(const Line &line) const {
85 const Vector origin = line.getOrigin();
86 const Vector direction = line.getDirection();
87
88 const Vector e(direction[0], direction[1], 0.0);
89 const Vector f(origin[0], origin[1], 0.0);
90 const double A = e.ScalarProduct(e);
91 const double B = 2.0*e.ScalarProduct(f);
92 const double C = f.ScalarProduct(f) - 1.0;
93
94 std::vector<double> solutions;
95
96 // Common routine to solve quadratic quations, anywhere?
97 const double neg_p_half = -B/(2.0*A);
98 const double q = C/A;
99 const double radicant = neg_p_half*neg_p_half-q;
100
101 if (radicant > 0.0) {
102 const double root = sqrt(radicant);
103 solutions.push_back(neg_p_half+root);
104 const double sln2 = neg_p_half-root;
105 if (sln2 != solutions.back())
106 solutions.push_back(sln2);
107 }
108
109 // Now get parameter for intersection with z-Planes.
110 const double origin_z = origin[2];
111 const double dir_z = direction[2];
112
113 if (dir_z != 0.0) {
114 solutions.push_back((-1.0-origin_z)/dir_z);
115 solutions.push_back((1.0-origin_z)/dir_z);
116 }
117
118 // Calculate actual vectors from obtained parameters and check,
119 // if they are actual intersections.
120 std::vector<Vector> intersections;
121
122 for(unsigned int i=0; i<solutions.size(); i++) {
123 const Vector check_me(origin + direction*solutions[i]);
124 if (isOnSurface(check_me))
125 intersections.push_back(check_me);
126 }
127
128 LineSegmentSet result(line);
129 if (intersections.size()==2)
130 result.insert(LineSegment(intersections[0], intersections[1]));
131 return result;
132}
133
134std::string Cylinder_impl::toString() const
135{
136 return "Cylinder()";
137}
138
139enum ShapeType Cylinder_impl::getType() const
140{
141 return CylinderType;
142}
143
144std::vector<Vector> Cylinder_impl::getHomogeneousPointsOnSurface(const size_t N) const {
145 const double nz_float = sqrt(N/M_PI);
146 const int nu = round(N/nz_float);
147 const int nz = round(nz_float);
148
149 const double dphi = 2.0*M_PI/nu;
150 const double dz = 2.0/nz;
151
152 std::vector<Vector> result;
153
154 for(int useg=0; useg<nu; useg++)
155 for(int zseg=0; zseg<nz; zseg++)
156 result.push_back(Vector(cos(useg*dphi), sin(useg*dphi), zseg*dz-1.0));
157
158 return result;
159}
160
161std::vector<Vector> Cylinder_impl::getHomogeneousPointsInVolume(const size_t N) const {
162 const double nz_float = pow(N/(2.0*M_PI), 1.0/3.0);
163 const int nu = round(nz_float*M_PI);
164 const int nr = round(nz_float*0.5);
165 const int nz = round(nz_float);
166
167 const double dphi = 2.0*M_PI/nu;
168 const double dz = 2.0/nz;
169 const double dr = 1.0/nr;
170
171 std::vector<Vector> result;
172
173 for(int useg=0; useg<nu; useg++)
174 for(int zseg=0; zseg<nz; zseg++)
175 for(int rseg=0; rseg<nr; rseg++)
176 {
177 const double r = dr+rseg*dr;
178 result.push_back(Vector(r*cos(useg*dphi), r*sin(useg*dphi), zseg*dz-1.0));
179 }
180
181 return result;
182}
183
184Shape Cylinder() {
185 Shape::impl_ptr impl = Shape::impl_ptr(new Cylinder_impl());
186 return Shape(impl);
187}
188
189Shape Cylinder(const Vector &center, const double xrot, const double yrot,
190 const double height, const double radius)
191{
192 RealSpaceMatrix rot;
193 rot.setRotation(xrot, yrot, 0.0);
194
195 return translate(
196 transform(
197 stretch(
198 Cylinder(),
199 Vector(radius, radius, height*0.5)),
200 rot),
201 center);
202}
203// ----------------------------------------------------------------------------
204
205bool Sphere_impl::isInside(const Vector &point) const{
206 return point.NormSquared()<=1.;
207}
208
209bool Sphere_impl::isOnSurface(const Vector &point) const{
210 return fabs(point.NormSquared()-1.)<MYEPSILON;
211}
212
213Vector Sphere_impl::getNormal(const Vector &point) const throw(NotOnSurfaceException){
214 if(!isOnSurface(point)){
215 throw NotOnSurfaceException() << ShapeVector(&point);
216 }
217 return point;
218}
219
220Vector Sphere_impl::getCenter() const
221{
222 return Vector(0.,0.,0.);
223}
224
225double Sphere_impl::getRadius() const
226{
227 return 1.;
228}
229
230double Sphere_impl::getVolume() const
231{
232 return (4./3.)*M_PI; // 4/3 pi r^3
233}
234
235double Sphere_impl::getSurfaceArea() const
236{
237 return 2.*M_PI; // 2 pi r^2
238}
239
240
241LineSegmentSet Sphere_impl::getLineIntersections(const Line &line) const{
242 LineSegmentSet res(line);
243 std::vector<Vector> intersections = line.getSphereIntersections();
244 if(intersections.size()==2){
245 res.insert(LineSegment(intersections[0],intersections[1]));
246 }
247 return res;
248}
249
250std::string Sphere_impl::toString() const{
251 return "Sphere()";
252}
253
254enum ShapeType Sphere_impl::getType() const
255{
256 return SphereType;
257}
258
259/**
260 * algorithm taken from http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere
261 * \param N number of points on surface
262 */
263std::vector<Vector> Sphere_impl::getHomogeneousPointsOnSurface(const size_t N) const
264{
265 std::vector<Vector> PointsOnSurface;
266 if (true) {
267 // Exactly N points but not symmetric.
268
269 // This formula is derived by finding a curve on the sphere that spirals down from
270 // the north pole to the south pole keeping a constant distance between consecutive turns.
271 // The curve is then parametrized by arch length and evaluated in constant intervals.
272 double a = sqrt(N) * 2;
273 for (int i=0; i<N; i++){
274 double t0 = ((double)i + 0.5) / (double)N;
275 double t = (sqrt(t0) - sqrt(1.0 - t0) + 1.0) / 2.0 * M_PI;
276 Vector point;
277 point.Zero();
278 point[0] = sin(t) * sin(t * a);
279 point[1] = sin(t) * cos(t * a);
280 point[2] = cos(t);
281 PointsOnSurface.push_back(point);
282 }
283 ASSERT(PointsOnSurface.size() == N,
284 "Sphere_impl::getHomogeneousPointsOnSurface() did not create "
285 +::toString(N)+" but "+::toString(PointsOnSurface.size())+" points.");
286 } else {
287 // Symmetric but only approximately N points.
288 double a=4*M_PI/N;
289 double d= sqrt(a);
290 int Mtheta=int(M_PI/d);
291 double dtheta=M_PI/Mtheta;
292 double dphi=a/dtheta;
293 for (int m=0; m<Mtheta; m++)
294 {
295 double theta=M_PI*(m+0.5)/Mtheta;
296 int Mphi=int(2*M_PI*sin(theta)/dphi);
297 for (int n=0; n<Mphi;n++)
298 {
299 double phi= 2*M_PI*n/Mphi;
300 Vector point;
301 point.Zero();
302 point[0]=sin(theta)*cos(phi);
303 point[1]=sin(theta)*sin(phi);
304 point[2]=cos(theta);
305 PointsOnSurface.push_back(point);
306 }
307 }
308 }
309 return PointsOnSurface;
310}
311
312std::vector<Vector> Sphere_impl::getHomogeneousPointsInVolume(const size_t N) const {
313 ASSERT(0,
314 "Sphere_impl::getHomogeneousPointsInVolume() - not implemented.");
315 return std::vector<Vector>();
316}
317
318Shape Sphere(){
319 Shape::impl_ptr impl = Shape::impl_ptr(new Sphere_impl());
320 return Shape(impl);
321}
322
323Shape Sphere(const Vector &center,double radius){
324 return translate(resize(Sphere(),radius),center);
325}
326
327Shape Ellipsoid(const Vector &center, const Vector &radius){
328 return translate(stretch(Sphere(),radius),center);
329}
330
331bool Cuboid_impl::isInside(const Vector &point) const{
332 return (point[0]>=0 && point[0]<=1) && (point[1]>=0 && point[1]<=1) && (point[2]>=0 && point[2]<=1);
333}
334
335bool Cuboid_impl::isOnSurface(const Vector &point) const{
336 bool retVal = isInside(point);
337 // test all borders of the cuboid
338 // double fabs
339 retVal = retVal &&
340 (((fabs(point[0]-1.) < MYEPSILON) || (fabs(point[0]) < MYEPSILON)) ||
341 ((fabs(point[1]-1.) < MYEPSILON) || (fabs(point[1]) < MYEPSILON)) ||
342 ((fabs(point[2]-1.) < MYEPSILON) || (fabs(point[2]) < MYEPSILON)));
343 return retVal;
344}
345
346Vector Cuboid_impl::getNormal(const Vector &point) const throw(NotOnSurfaceException){
347 if(!isOnSurface(point)){
348 throw NotOnSurfaceException() << ShapeVector(&point);
349 }
350 Vector res;
351 // figure out on which sides the Vector lies (maximum 3, when it is in a corner)
352 for(int i=NDIM;i--;){
353 if(fabs(fabs(point[i])-1)<MYEPSILON){
354 // add the scaled (-1/+1) Vector to the set of surface vectors
355 res[i] = point[i];
356 }
357 }
358 ASSERT(res.NormSquared()>=1 && res.NormSquared()<=3,"To many or to few sides found for this Vector");
359
360 res.Normalize();
361 return res;
362}
363
364
365Vector Cuboid_impl::getCenter() const
366{
367 return Vector(0.5,0.5,0.5);
368}
369
370double Cuboid_impl::getRadius() const
371{
372 return .5;
373}
374
375double Cuboid_impl::getVolume() const
376{
377 return 1.; // l^3
378}
379
380double Cuboid_impl::getSurfaceArea() const
381{
382 return 6.; // 6 * l^2
383}
384
385LineSegmentSet Cuboid_impl::getLineIntersections(const Line &line) const{
386 LineSegmentSet res(line);
387 // get the intersection on each of the six faces
388 std::vector<Vector> intersections;
389 intersections.resize(2);
390 int c=0;
391 int x[2]={-1,+1};
392 for(int i=NDIM;i--;){
393 for(int p=0;p<2;++p){
394 if(c==2) goto end; // I know this sucks, but breaking two loops is stupid
395 Vector base;
396 base[i]=x[p];
397 // base now points to the surface and is normal to it at the same time
398 Plane p(base,base);
399 Vector intersection = p.GetIntersection(line);
400 if(isInside(intersection)){
401 // if we have a point on the edge it might already be contained
402 if(c==1 && intersections[0]==intersection)
403 continue;
404 intersections[c++]=intersection;
405 }
406 }
407 }
408 end:
409 if(c==2){
410 res.insert(LineSegment(intersections[0],intersections[1]));
411 }
412 return res;
413}
414
415std::string Cuboid_impl::toString() const{
416 return "Cuboid()";
417}
418
419enum ShapeType Cuboid_impl::getType() const
420{
421 return CuboidType;
422}
423
424/**
425 * \param N number of points on surface
426 */
427std::vector<Vector> Cuboid_impl::getHomogeneousPointsOnSurface(const size_t N) const {
428 std::vector<Vector> PointsOnSurface;
429 ASSERT(false, "Cuboid_impl::getHomogeneousPointsOnSurface() not implemented yet");
430 return PointsOnSurface;
431}
432
433std::vector<Vector> Cuboid_impl::getHomogeneousPointsInVolume(const size_t N) const {
434 ASSERT(0,
435 "Cuboid_impl::getHomogeneousPointsInVolume() - not implemented.");
436 return std::vector<Vector>();
437}
438
439Shape Cuboid(){
440 Shape::impl_ptr impl = Shape::impl_ptr(new Cuboid_impl());
441 return Shape(impl);
442}
443
444Shape Cuboid(const Vector &corner1, const Vector &corner2){
445 // make sure the two edges are upper left front and lower right back
446 Vector sortedC1;
447 Vector sortedC2;
448 for(int i=NDIM;i--;){
449 sortedC1[i] = std::min(corner1[i],corner2[i]);
450 sortedC2[i] = std::max(corner1[i],corner2[i]);
451 ASSERT(corner1[i]!=corner2[i],"Given points for cuboid edges did not define a valid space");
452 }
453 // get the middle point
454 Vector middle = (1./2.)*(sortedC1+sortedC2);
455 Vector factors = sortedC2-middle;
456 return translate(stretch(Cuboid(),factors),middle);
457}
Note: See TracBrowser for help on using the repository browser.