source: src/Shapes/BaseShapes.cpp@ 8b58ac

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 8b58ac was 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

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