Author: eudoxos
Date: 2009-06-13 17:09:51 +0200 (Sat, 13 Jun 2009)
New Revision: 1794

Added:
   trunk/gui/py/_packPredicates.cpp
   trunk/gui/py/pack.py
Modified:
   trunk/gui/SConscript
   trunk/gui/py/PythonUI.cpp
   trunk/gui/py/PythonUI_rc.py
   trunk/scripts/test/regular-sphere-pack.py
Log:
1. Move all python modules to PREFIX/lib/yadeSUFFIX/py/yade instead of 
*/gui/yade
2. Add pack module for generating regular packings (thanks to Anton Gladky for 
his ideas & code)
3. Add _packPredicates module for solid inclusion testing.
4. Update regular-sphere-pack.py to test new packing features.



Modified: trunk/gui/SConscript
===================================================================
--- trunk/gui/SConscript        2009-06-09 11:23:06 UTC (rev 1793)
+++ trunk/gui/SConscript        2009-06-13 15:09:51 UTC (rev 1794)
@@ -49,7 +49,7 @@
                env.File('PythonUI_rc.py','py'),
        ])
        if 'qt3' not in env['exclude']:
-               env.Install('$PREFIX/lib/yade$SUFFIX/gui/yade',[
+               env.Install('$PREFIX/lib/yade$SUFFIX/py/yade',[
                        
env.SharedLibrary('_qt',['qt3/QtGUI-python.cpp'],SHLIBPREFIX='',LIBS=env['LIBS']+['QtGUI'],CPPPATH=env['CPPPATH']+[env['buildDir']+'/gui/qt3']),
 # CPPPATH is for files generated by moc which are indirectly included
                        env.File('qt.py','qt3'),
                ])
@@ -57,7 +57,7 @@
        
env.InstallAs('$PREFIX/bin/yade$SUFFIX-multi',env.File('yade-multi','py'))
 
        # python modules are one level deeper so that you can say: from 
yade.wrapper import *
-       env.Install('$PREFIX/lib/yade$SUFFIX/gui/yade',[
+       env.Install('$PREFIX/lib/yade$SUFFIX/py/yade',[
                
env.SharedLibrary('wrapper',['py/yadeControl.cpp'],SHLIBPREFIX='',
                        
LIBS=env['LIBS']+['XMLFormatManager','yade-factory','yade-serialization','Shop',
                                'BoundingVolumeMetaEngine',
@@ -75,6 +75,7 @@
                        ),
                env.SharedLibrary('_utils',['py/_utils.cpp'],SHLIBPREFIX='',
                        LIBS=env['LIBS']+['Shop','ConcretePM']),
+               
env.SharedLibrary('_packPredicates',['py/_packPredicates.cpp'],SHLIBPREFIX=''),
                
env.SharedLibrary('_eudoxos',['py/_eudoxos.cpp'],SHLIBPREFIX='',CXXFLAGS=env['CXXFLAGS']+([]
 if not os.path.exists('../../brefcom-mm.hh') else 
['-include','../brefcom-mm.hh']),LIBS=env['LIBS']+['Shop','ConcretePM']),
                env.SharedLibrary('log',['py/log.cpp'],SHLIBPREFIX=''),
                env.File('__init__.py','py'),
@@ -86,6 +87,7 @@
                env.File('linterpolation.py','py'),
                env.File('timing.py','py'),
                env.File('PythonTCPServer.py','py'),
+               env.File('pack.py','py'),
        ])
        if os.path.exists('../../brefcom-mm.hh'): 
Depends('py/_eudoxos.cpp','../../brefcom-mm.hh')
 

Modified: trunk/gui/py/PythonUI.cpp
===================================================================
--- trunk/gui/py/PythonUI.cpp   2009-06-09 11:23:06 UTC (rev 1793)
+++ trunk/gui/py/PythonUI.cpp   2009-06-13 15:09:51 UTC (rev 1794)
@@ -79,7 +79,7 @@
        PyGILState_STATE pyState = PyGILState_Ensure();
                LOG_DEBUG("Got Global Interpreter Lock, good.");
                /* import yade (for startUI()) and yade.runtime (initially 
empty) namespaces */
-               PyRun_SimpleString("import sys; sys.path.insert(0,'" PREFIX 
"/lib/yade" SUFFIX "/gui')");
+               PyRun_SimpleString("import sys; sys.path.insert(0,'" PREFIX 
"/lib/yade" SUFFIX "/py')");
                PyRun_SimpleString("import yade");
                PyRun_SimpleString("from __future__ import division");
 

Modified: trunk/gui/py/PythonUI_rc.py
===================================================================
--- trunk/gui/py/PythonUI_rc.py 2009-06-09 11:23:06 UTC (rev 1793)
+++ trunk/gui/py/PythonUI_rc.py 2009-06-13 15:09:51 UTC (rev 1794)
@@ -122,7 +122,7 @@
          | | (_| | |_| |  __/ | |__| (_) | | | \__ \ (_) | |  __/
          |_|\__,_|____/ \___|  \____\___/|_| |_|___/\___/|_|\___|
        """,exit_msg='Bye.'
-               
,rc_override={'execfile':[runtime.prefix+'/lib/yade'+runtime.suffix+'/gui/yade/ipython.py']})
+               
,rc_override={'execfile':[runtime.prefix+'/lib/yade'+runtime.suffix+'/py/yade/ipython.py']})
 
                ipshell()
                # save history -- a workaround for atexit handlers not being 
run (why?)

Added: trunk/gui/py/_packPredicates.cpp
===================================================================
--- trunk/gui/py/_packPredicates.cpp    2009-06-09 11:23:06 UTC (rev 1793)
+++ trunk/gui/py/_packPredicates.cpp    2009-06-13 15:09:51 UTC (rev 1794)
@@ -0,0 +1,93 @@
+// 2009 © Václav Šmilauer <[email protected]>
+#include<boost/python.hpp>
+#include<yade/extra/boost_python_len.hpp>
+#include<yade/lib-base/Logging.hpp>
+#include<yade/lib-base/yadeWm3.hpp>
+#include<Wm3Vector3.h>
+
+using namespace boost;
+using namespace std;
+#ifdef LOG4CXX
+       log4cxx::LoggerPtr logger=log4cxx::Logger::getLogger("yade.predicates");
+#endif
+
+/*
+This file contains various predicates that say whether a given point is within 
the solid,
+or, not closer than "pad" to its boundary, if pad is nonzero
+Besides the (point,pad) operator, each predicate defines aabb() method that 
returns
+(min,max) tuple defining minimum and maximum point of axis-aligned bounding 
box 
+for the predicate.
+
+These classes are primarily used for yade.pack.* functions creating packings.
+See scripts/test/regular-sphere-pack.py for an example.
+
+*/
+
+// aux functions
+python::tuple vec2tuple(const Vector3r& v){return 
boost::python::make_tuple(v[0],v[1],v[2]);}
+Vector3r tuple2vec(const python::tuple& t){return 
Vector3r(python::extract<double>(t[0])(),python::extract<double>(t[1])(),python::extract<double>(t[2])());}
+void ttuple2vvec(const python::tuple& t, Vector3r& v1, Vector3r& v2){ 
v1=tuple2vec(python::extract<python::tuple>(t[0])()); 
v2=tuple2vec(python::extract<python::tuple>(t[1])()); }
+python::tuple vvec2ttuple(const Vector3r&v1, const Vector3r&v2){ return 
python::make_tuple(vec2tuple(v1),vec2tuple(v2)); }
+
+
+/*! Sphere predicate */
+class inSphere {
+       Vector3r center; Real radius;
+public:
+       inSphere(python::tuple _center, Real 
_radius){center=tuple2vec(_center); radius=_radius;}
+       bool operator()(python::tuple _pt, Real pad=0.){
+               Vector3r pt=tuple2vec(_pt);
+               return ((pt-center).Length()-pad<=radius-pad);
+       }
+       python::tuple aabb(){return 
vvec2ttuple(Vector3r(center[0]-radius,center[1]-radius,center[2]-radius),Vector3r(center[0]+radius,center[1]+radius,center[2]+radius));}
+};
+
+/* Axis-aligned box predicate */
+class inAlignedBox{
+       Vector3r mn, mx;
+public:
+       inAlignedBox(python::tuple _mn, python::tuple _mx){mn=tuple2vec(_mn); 
mx=tuple2vec(_mx);}
+       bool operator()(python::tuple _pt, Real pad=0.){
+               Vector3r pt=tuple2vec(_pt);
+               return
+                       mn[0]+pad<=pt[0] && mx[0]-pad>=pt[0] &&
+                       mn[1]+pad<=pt[1] && mx[1]-pad>=pt[1] &&
+                       mn[2]+pad<=pt[2] && mx[2]-pad>=pt[2];
+       }
+       python::tuple aabb(){ return vvec2ttuple(mn,mx); }
+};
+
+/* Arbitrarily oriented cylinder predicate */
+class inCylinder{
+       Vector3r c1,c2,c12; Real radius,ht;
+public:
+       inCylinder(python::tuple _c1, python::tuple _c2, Real 
_radius){c1=tuple2vec(_c1); c2=tuple2vec(_c2); c12=c2-c1; radius=_radius; 
ht=c12.Length(); }
+       bool operator()(python::tuple _pt, Real pad=0.){
+               Vector3r pt=tuple2vec(_pt);
+               Real u=(pt.Dot(c12)-c1.Dot(c12))/(ht*ht); // normalized 
coordinate along the c1--c2 axis
+               if((u*ht<0+pad) || (u*ht>ht-pad)) return false; // out of 
cylinder along the axis
+               Real axisDist=((pt-c1).Cross(pt-c2)).Length()/ht;
+               if(axisDist>radius-pad) return false;
+               return true;
+       }
+       python::tuple aabb(){
+               // see 
http://www.gamedev.net/community/forums/topic.asp?topic_id=338522&forum_id=20&gforum_id=0
 for the algorithm
+               Vector3r& A(c1); Vector3r& B(c2); 
+               Vector3r k(
+                       sqrt((pow(A[1]-B[1],2)+pow(A[2]-B[2],2)))/ht,
+                       sqrt((pow(A[0]-B[0],2)+pow(A[2]-B[2],2)))/ht,
+                       sqrt((pow(A[0]-B[0],2)+pow(A[1]-B[1],2)))/ht);
+               Vector3r mn(min(A[0],B[0]),min(A[1],B[1]),min(A[2],B[2])), 
mx(max(A[0],B[0]),max(A[1],B[1]),max(A[2],B[2]));
+               return vvec2ttuple(mn-radius*k,mx+radius*k);
+       }
+};
+
+BOOST_PYTHON_MODULE(_packPredicates){
+       boost::python::class_<inSphere>("inSphere","Sphere 
predicate.",python::init<python::tuple,Real>("Ctor taking center (as a 3-tuple) 
and radius"))
+               .def("__call__",&inSphere::operator(),"Tell whether given point 
lies within this sphere, still having 'pad' space to the solid 
boundary").def("aabb",&inSphere::aabb,"Return minimum and maximum values for 
AABB");
+       boost::python::class_<inAlignedBox>("inAlignedBox","Axis-aligned box 
predicate",python::init<python::tuple,python::tuple>("Ctor taking minumum and 
maximum points of the box (as 3-tuples)."))
+               .def("__call__",&inAlignedBox::operator(),"Tell whether given 
point lies within this box, still having 'pad' space to the solid 
boundary").def("aabb",&inAlignedBox::aabb,"Return minimum and maximum values 
for AABB");
+       boost::python::class_<inCylinder>("inCylinder","Cylinder 
predicate",python::init<python::tuple,python::tuple,Real>("Ctor taking centers 
of the lateral walls (as 3-tuples) and radius."))
+               .def("__call__",&inCylinder::operator(),"Tell whether given 
point lies within this cylinder, still having 'pad' space to the solid 
boundary").def("aabb",&inCylinder::aabb,"Return minimum and maximum values for 
AABB");
+}
+

Added: trunk/gui/py/pack.py
===================================================================
--- trunk/gui/py/pack.py        2009-06-09 11:23:06 UTC (rev 1793)
+++ trunk/gui/py/pack.py        2009-06-13 15:09:51 UTC (rev 1794)
@@ -0,0 +1,34 @@
+
+from numpy import arange; from math import sqrt
+import itertools
+from yade import utils
+
+# make predicates available from yade.pack
+from _packPredicates import *
+
+def regularOrtho(predicate,radius,gap,**kw):
+       """Return set of spheres in regular orthogonal grid, clipped inside 
solid given by predicate.
+       Created spheres will have given radius and will be separated by gap 
space."""
+       ret=[]
+       mn,mx=predicate.aabb()
+       xx,yy,zz=[arange(mn[i]+radius,mx[i]-radius,2*radius+gap) for i in 0,1,2]
+       for xyz in itertools.product(xx,yy,zz):
+               if predicate(xyz,radius): 
ret+=[utils.sphere(xyz,radius=radius,**kw)]
+       return ret
+
+def regularHexa(predicate,radius,gap,**kw):
+       """Return set of spheres in regular hexagonal grid, clipped inside 
solid given by predicate.
+       Created spheres will have given radius and will be separated by gap 
space."""
+       ret=[]
+       a=2*radius+gap
+       h=a*sqrt(3)/2.
+       mn,mx=predicate.aabb()
+       dim=[mx[i]-mn[i] for i in 0,1,2]
+       
ii,jj,kk=[range(0,int(2*dim[0]/a)+1),range(0,int(dim[1]/h)+1),range(0,int(dim[2]/h)+1)]
+       for i,j,k in itertools.product(ii,jj,kk):
+               x,y,z=mn[0]+radius+i*a,mn[1]+radius+j*h,mn[2]+radius+k*h
+               if j%2==0: x+= a/2. if k%2==0 else -a/2.
+               if k%2!=0: x+=a/2.; y+=h/2.
+               if predicate((x,y,z),radius): 
ret+=[utils.sphere((x,y,z),radius=radius,**kw)]
+       return ret
+

Modified: trunk/scripts/test/regular-sphere-pack.py
===================================================================
--- trunk/scripts/test/regular-sphere-pack.py   2009-06-09 11:23:06 UTC (rev 
1793)
+++ trunk/scripts/test/regular-sphere-pack.py   2009-06-13 15:09:51 UTC (rev 
1794)
@@ -1,3 +1,43 @@
-O.bodies.append(utils.regularSphereOrthoPack([0,0,0],extents=[2,2,2],radius=.1,gap=.1,color=(1,0,1)))
-O.bodies.append(utils.regularSphereOrthoPack([0,0,4],extents=2,radius=.1,gap=.1,color=(0,1,0),velocity=[0,10,0]))
+from yade import pack
 
+rad,gap=.15,.02
+rho=1e3
+kw={'density':rho}
+
+O.bodies.append(
+       
pack.regularHexa(pack.inSphere((0,0,4),2),radius=rad,gap=gap,color=(0,1,0),density=10*rho)
 # head
+       
+[utils.sphere((.8,1.9,5),radius=.2,color=(.6,.6,.6),density=rho),utils.sphere((-.8,1.9,5),radius=.2,color=(.6,.6,.6),density=rho),utils.sphere((0,2.4,4),radius=.4,color=(1,0,0),density=rho)]
 # eyes and nose
+       +[utils.facet([(12,0,-6),(0,12,-6,),(-12,-12,-6)],dynamic=False)] # 
ground
+)
+
+for part in [
+       pack.regularHexa 
(pack.inAlignedBox((-2,-2,-2),(2,2,2)),radius=1.5*rad,gap=2*gap,color=(1,0,1),**kw),
 # body,
+       
pack.regularOrtho(pack.inCylinder((-1,0,-2),(-1,0,-6),1),radius=rad,gap=gap,color=(0,1,1),**kw),
 # left leg
+       pack.regularHexa 
(pack.inCylinder((+1,1,-2.5),(0,3,-5),1),radius=rad,gap=gap,color=(0,1,1),**kw),
 # right leg
+       pack.regularHexa 
(pack.inCylinder((+2,0,1),(+6,0,1),1),radius=rad,gap=gap,color=(0,0,1),**kw), # 
right hand
+       
pack.regularOrtho(pack.inCylinder((-2,0,2),(-5,0,4),1),radius=rad,gap=gap,color=(0,0,1),**kw)
 # left hand
+       ]: O.bodies.appendClumped(part)
+
+
+
+try:
+       from yade import qt
+       qt.Controller()
+except ImportError: pass
+
+O.engines=[
+       BexResetter(),
+       
BoundingVolumeMetaEngine([InteractingSphere2AABB(),InteractingFacet2AABB(),MetaInteractingGeometry2AABB()]),
+       InsertionSortCollider(),
+       InteractionDispatchers(
+               
[ef2_Sphere_Sphere_Dem3DofGeom(),ef2_Facet_Sphere_Dem3DofGeom()],
+               [SimpleElasticRelationships()],
+               [ef2_Dem3Dof_Elastic_ElasticLaw()],
+       ),
+       GravityEngine(gravity=(1e-2,1e-2,-1000)),
+       NewtonsDampedLaw(damping=.1)
+]
+# we don't care about physical accuracy here, over-critical step is fine as 
long as the simulation doesn't explode
+O.dt=2*utils.PWaveTimeStep()
+O.saveTmp('init')
+#for b in O.bodies: 


_______________________________________________
Mailing list: https://launchpad.net/~yade-dev
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~yade-dev
More help   : https://help.launchpad.net/ListHelp

Reply via email to