Commit f32875dc authored by Václav Šmilauer's avatar Václav Šmilauer
Browse files

1. Add noqt3 feature (still keeps OpenGL available), run qt4 app at the beginning (emits warning)

2. Make GLUtils independent of QGLViewer
3. Add some metadata to attribute docstrings
4. Add scripts to render scene to pyQGLViewer and to show basic serialization interface in PyQt4.
5. Make static attributes non-static in python (enables docstrings)
parent 672b600e
......@@ -139,7 +139,7 @@ opts.AddVariables(
BoolVariable('optimize','Turn on heavy optimizations',defOptions['optimize']),
ListVariable('exclude','Yade components that will not be built','none',names=['gui','extra','common','dem','lattice','snow']),
EnumVariable('PGO','Whether to "gen"erate or "use" Profile-Guided Optimization','',['','gen','use'],{'no':'','0':'','false':''},1),
ListVariable('features','Optional features that are turned on','log4cxx,opengl,gts,openmp,vtk',names=['opengl','log4cxx','cgal','openmp','gts','vtk','python','gl2ps','devirt-functors','never_use_this_one']),
ListVariable('features','Optional features that are turned on','log4cxx,opengl,gts,openmp,vtk',names=['opengl','log4cxx','cgal','openmp','gts','vtk','python','gl2ps','devirt-functors','noqt3','never_use_this_one']),
('jobs','Number of jobs to run at the same time (same as -j, but saved)',2,None,int),
#('extraModules', 'Extra directories with their own SConscript files (must be in-tree) (whitespace separated)',None,None,Split),
('buildPrefix','Where to create build-[version][variant] directory for intermediary files','..'),
......@@ -359,12 +359,13 @@ if not env.GetOption('clean'):
ok=conf.CheckLibWithHeader('glut','GL/glut.h','c++','glutGetModifiers();',autoadd=1)
# TODO ok=True for darwin platform where openGL (and glut) is native
if not ok: featureNotOK('opengl')
ok=conf.CheckQt(env['QTDIR'])
if not ok: featureNotOK('opengl','Building with OpenGL implies qt3 interface, which was not found, although OpenGL was.')
env.Tool('qt'); env.Replace(QT_LIB='qt-mt')
ok=conf.CheckLibWithHeader(['qglviewer'],'QGLViewer/qglviewer.h','c++','QGLViewer();',autoadd=0)
if not ok: featureNotOK('opengl','Building with OpenGL implies the QGLViewer library installed (libqglviewer-qt3-dev package in debian/ubuntu)')
env['QGLVIEWER_LIB']='qglviewer-qt3';
if not 'noqt3' in env['features']:
ok=conf.CheckQt(env['QTDIR'])
if not ok: featureNotOK('opengl','Building with OpenGL implies qt3 interface, which was not found, although OpenGL was.')
env.Tool('qt'); env.Replace(QT_LIB='qt-mt')
ok=conf.CheckLibWithHeader(['qglviewer'],'QGLViewer/qglviewer.h','c++','QGLViewer();',autoadd=0)
if not ok: featureNotOK('opengl','Building with OpenGL implies the QGLViewer library installed (libqglviewer-qt3-dev package in debian/ubuntu)')
env['QGLVIEWER_LIB']='qglviewer-qt3';
if 'vtk' in env['features']:
ok=conf.CheckLibWithHeader(['vtkCommon'],'vtkInstantiator.h','c++','vtkInstantiator::New();',autoadd=1)
env.Append(LIBS='vtkHybrid')
......
......@@ -56,7 +56,8 @@ env.Install('$PREFIX/lib/yade$SUFFIX/lib',[
'yade-support',
'rt', # realtime lib, for clock_gettime
]+
(['qglviewer-qt3','yade-opengl'] if 'YADE_OPENGL' in env['CPPDEFINES'] else [])
(['qglviewer-qt3'] if not 'noqt3' in env['features'] else [])+
(['yade-opengl'] if 'opengl' in env['features'] else [])
,
)
])
......@@ -40,6 +40,14 @@ if opts.threads: os.environ['OMP_NUM_THREADS']=str(opts.threads)
sys.stderr.write('Welcome to Yade '+version+'\n')
if 'opengl' in features and 'noqt3' in features:
try:
from PyQt4 import QtGui
qapp=QtGui.QApplication(sys.argv)
import thread
thread.start_new_thread(qapp.exec_,()) # this will warn, but I don't know a way around that
except ImportError: pass
# initialization and c++ plugins import
import yade
# other parts we will need soon
......@@ -69,13 +77,14 @@ if 'log4cxx' in yade.config.features and opts.verbosity:
# run servers
yade.system.runServers()
# open GUI if possible
qtEnabled=False
if not opts.nogui:
try:
import yade.qt
qtEnabled=True
except ImportError: pass
if not 'noqt3' in features:
# open GUI if possible
qtEnabled=False
if not opts.nogui:
try:
import yade.qt
qtEnabled=True
except ImportError: pass
# prepare nice namespace for users
......@@ -106,7 +115,7 @@ if 1:
if 1:
from IPython.Shell import IPShellEmbed
ipshell=IPShellEmbed(
argv=[],
argv=['-q4thread'],
#exit_msg='Bye.',
banner='[[ ^L clears screen, ^U kills line.'+(' F12 controller, F11 3d view, F10 both, F9 generator, F8 plot.' if qtEnabled else '')+' ]]',
rc_override=dict( # ipython options, see e.g. http://www.cv.nrao.edu/~rreid/casa/tips/ipy_user_conf.py
......
......@@ -71,7 +71,7 @@ def formatRest(db):
## ReST uses <..> to delimit URL, therefore < and > must be encoded in the URL (http://www.blooberry.com/indexdot/html/topics/urlencoding.htm)
def escapeUrl(url): return url.replace('<','%3c').replace('>','%3e')
if i.has_key('doi'): line+=' DOI `%s <http://dx.doi.org/%s>`_'%(i['doi'],escapeUrl(i['doi']))
if i.has_key('url'): line+=' `(fulltext) <%s>`_'%escapeUrl(i['url'])
if i.has_key('url'): line+=' `(fulltext) <%s>`__'%escapeUrl(i['url'])
if i.has_key('note'): line+=' (%s)'%i['note']
ret.append(line)
return [l.replace('@tilde@','~') for l in ret]
......
......@@ -108,11 +108,15 @@ def mkYrefNode(target,text,rawtext,role,explicitText,lineno,options={}):
def ydefault_role(role,rawtext,text,lineno,inliner,options={},content=[]):
"Handle the :ydefault:`something` role. fixSignature handles it now in the member signature itself, this merely expands to nothing."
return [],[]
def yattrtype_role(role,rawtext,text,lineno,inliner,options={},content=[]):
"Handle the :yattrtype:`something` role. fixSignature handles it now in the member signature itself, this merely expands to nothing."
return [],[]
from docutils.parsers.rst import roles
roles.register_canonical_role('yref', yaderef_role)
roles.register_canonical_role('ysrc', yadesrc_role)
roles.register_canonical_role('ydefault', ydefault_role)
roles.register_canonical_role('yattrtype', yattrtype_role)
## http://sphinx.pocoo.org/config.html#confval-rst_epilog
......@@ -125,12 +129,8 @@ rst_epilog = """
def customExclude(app, what, name, obj, skip, options):
if obj=='<unbound method Serializable.clone>':
print 1000*'@'
return False
if re.match(r'\bclone\b',name):
#if 'Serializable' in name: print 1000*'#',name
#print 1000*'#',name, obj, what
if name=='clone':
if 'Serializable.clone' in str(obj): return False
return True
if hasattr(obj,'__doc__') and obj.__doc__ and ('|ydeprecated|' in obj.__doc__ or '|ynodoc|' in obj.__doc__): return True
#if re.match(r'\b(__init__|__reduce__|__repr__|__str__)\b',name): return True
......@@ -167,6 +167,7 @@ def fixDocstring(app,what,name,obj,options,lines):
# remove empty default roles, which is not properly interpreted by docutils parser
for i in range(0,len(lines)):
lines[i]=lines[i].replace(':ydefault:``','')
lines[i]=lines[i].replace(':yattrtype:``','')
#lines[i]=re.sub(':``',':` `',lines[i])
# remove signature of boost::python function docstring, which is the first line of the docstring
if isBoostFunc(what,obj):
......@@ -233,6 +234,7 @@ def boostFuncSignature(name,obj,removeSelf=False):
# grab the return value
try:
sig=') -> '+sig.split('->')[-1]
#if 'Serializable' in name: print 1000*'#',name
except IndexError:
sig=')'
return '('+sig,strippedDoc
......
......@@ -131,7 +131,7 @@ Class reference (yade.wrapper module)
sect('Constitutive laws','',['LawFunctor','LawDispatcher'])+
sect('Callbacks','',['BodyCallback','IntrCallback'])+
sect('Preprocessors','',['FileGenerator'])+
sect('Rendering','',['OpenGLRenderingEngine','GlShapeFunctor','GlStateFunctor','GlBoundFunctor','GlInteractionGeometryFunctor','GlInteractionPhysicsFunctor','GlShapeDispatcher','GlStateDispatcher','GlBoundDispatcher,','GlInteractionGeometryDispatcher','GlInteractionPhysicsDispatcher'])+
sect('Rendering','',['OpenGLRenderingEngine','GlShapeFunctor','GlStateFunctor','GlBoundFunctor','GlInteractionGeometryFunctor','GlInteractionPhysicsFunctor']), # ,'GlShapeDispatcher','GlStateDispatcher','GlBoundDispatcher','GlInteractionGeometryDispatcher','GlInteractionPhysicsDispatcher'])+
sect('Simulation data','',['Omega','BodyContainer','InteractionContainer','ForceContainer','MaterialContainer'])
+"""
Other classes
......
......@@ -2,7 +2,7 @@
Import('*')
linkPlugins=env['linkPlugins']
if 'opengl' in env['features']:
if 'opengl' in env['features'] and not 'noqt3' in env['features']:
env.Install('$PREFIX/lib/yade$SUFFIX/gui',[
env.SharedLibrary('QtGUI',
['qt3/FileDialog.cpp',
......
......@@ -9,8 +9,9 @@ def yadeStaticOrSharedLib(*args,**kw):
#return env.Install('$PREFIX/lib/yade$SUFFIX/lib',env.StaticLibrary(*args,**kw))
if 'opengl' in env['features']:
yadeStaticOrSharedLib('yade-serialization-qt',['serialization-qt/QtGUIGenerator.cpp'],LIBS=['yade-support'])
yadeStaticOrSharedLib('yade-opengl',env.Combine('yade-opengl.cpp',['opengl/FpsTracker.cpp','opengl/GLTextLabel.cpp','opengl/GLWindow.cpp','opengl/GLWindowsManager.cpp','opengl/GLUtils.cpp']),LIBS=env['LIBS']+['glut','GL','qglviewer-qt3']),
yadeStaticOrSharedLib('yade-opengl',env.Combine('yade-opengl.cpp',['opengl/FpsTracker.cpp','opengl/GLTextLabel.cpp','opengl/GLWindow.cpp','opengl/GLWindowsManager.cpp','opengl/GLUtils.cpp']),LIBS=env['LIBS']+['glut','GL','GLU']),
if not 'noqt3' in env['features']:
yadeStaticOrSharedLib('yade-serialization-qt',['serialization-qt/QtGUIGenerator.cpp'],LIBS=['yade-support'])
yadeStaticOrSharedLib('yade-support',[
env.Combine('yade-support.cpp',['base/Math.cpp']+
......
......@@ -11,3 +11,47 @@ void GLUtils::Parallelepiped(const Vector3r& a, const Vector3r& b, const Vector3
glVertex3v(Vector3r(a+c)); glVertex3v(Vector3r(a+b+c));
glEnd();
}
/****
code copied over from qglviewer
****/
/*! Draws a 3D arrow along the positive Z axis.
\p length, \p radius and \p nbSubdivisions define its geometry. If \p radius is negative
(default), it is set to 0.05 * \p length.
Use drawArrow(const Vec& from, const Vec& to, float radius, int nbSubdivisions) or change the \c
ModelView matrix to place the arrow in 3D.
Uses current color and does not modify the OpenGL state. */
void GLUtils::QGLViewer::drawArrow(float length, float radius, int nbSubdivisions)
{
static GLUquadric* quadric = gluNewQuadric();
if (radius < 0.0)
radius = 0.05 * length;
const float head = 2.5*(radius / length) + 0.1;
const float coneRadiusCoef = 4.0 - 5.0 * head;
gluCylinder(quadric, radius, radius, length * (1.0 - head/coneRadiusCoef), nbSubdivisions, 1);
glTranslatef(0.0, 0.0, length * (1.0 - head));
gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, nbSubdivisions, 1);
glTranslatef(0.0, 0.0, -length * (1.0 - head));
}
/*! Draws a 3D arrow between the 3D point \p from and the 3D point \p to, both defined in the
current ModelView coordinates system.
See drawArrow(float length, float radius, int nbSubdivisions) for details. */
void GLUtils::QGLViewer::drawArrow(const Vector3r& from, const Vector3r& to, float radius, int nbSubdivisions)
{
glPushMatrix();
glTranslatef(from[0],from[1],from[2]);
Quaternionr q(Quaternionr().setFromTwoVectors(Vector3r(0,0,1),to-from));
glMultMatrixd(q.toRotationMatrix().data());
drawArrow((to-from).norm(), radius, nbSubdivisions);
glPopMatrix();
}
......@@ -5,17 +5,21 @@
#pragma once
#include<yade/lib-opengl/OpenGLWrapper.hpp>
#include<QGLViewer/qglviewer.h>
#include<boost/lexical_cast.hpp>
#include<sstream>
#include<iomanip>
#include<string>
struct GLUtils{
// code copied from qglviewer
struct QGLViewer{
static void drawArrow(float length=1.0f, float radius=-1.0f, int nbSubdivisions=12);
static void drawArrow(const Vector3r& from, const Vector3r& to, float radius=-1.0f, int nbSubdivisions=12);
};
// render wire of parallelepiped with sides given by vectors a,b,c; zero corner is at origin
static void Parallelepiped(const Vector3r& a, const Vector3r& b, const Vector3r& c);
static void GLDrawArrow(const Vector3r& from, const Vector3r& to, const Vector3r& color=Vector3r(1,1,1)){
glEnable(GL_LIGHTING); glColor3v(color); qglviewer::Vec a(from[0],from[1],from[2]),b(to[0],to[1],to[2]); QGLViewer::drawArrow(a,b);
glEnable(GL_LIGHTING); glColor3v(color); QGLViewer::drawArrow(from,to);
}
static void GLDrawLine(const Vector3r& from, const Vector3r& to, const Vector3r& color=Vector3r(1,1,1)){
glEnable(GL_LIGHTING); glColor3v(color);
......
......@@ -181,7 +181,7 @@ namespace yade{
// use later: void must_use_both_YADE_CLASS_BASE_DOC_ATTRS_and_YADE_PLUGIN();
// #define YADE_CLASS_BASE_DOC_ATTRS_PY(thisClass,baseClass,docString,attrs,extras) YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,attrs,,extras)
#define _STRIPDECL4(x,y,z) (( BOOST_PP_TUPLE_ELEM(4,1,z),BOOST_PP_TUPLE_ELEM(4,3,z) " :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "`" ))
#define _STRIPDECL4(x,y,z) (( BOOST_PP_TUPLE_ELEM(4,1,z),BOOST_PP_TUPLE_ELEM(4,3,z) " :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "`" " :yattrtype:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,0,z)) "`" ))
// return type name; (for declaration)
#define _ATTR_DECL(x,y,z) BOOST_PP_TUPLE_ELEM(4,0,z) BOOST_PP_TUPLE_ELEM(4,1,z);
// return name(default), (for initializers list); TRICKY: last one must not have the comma
......@@ -196,8 +196,8 @@ namespace yade{
thisClass() BOOST_PP_IF(BOOST_PP_SEQ_SIZE(inits attrDecls),:,) BOOST_PP_SEQ_FOR_EACH_I(_ATTR_INI,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(inits attrDecls)), inits BOOST_PP_SEQ_FOR_EACH(_DECLINI4,~,attrDecls)) { ctor ; } /* ctor, with initialization of defaults */ \
_YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,BOOST_PP_SEQ_FOR_EACH(_STRIPDECL4,~,attrDecls),deprec,extras)
#define _DEF_READWRITE_STATIC(thisClass,attr,doc)
#define _STATATTR_PY(x,thisClass,z) _DEF_READWRITE_CUSTOM_STATIC(thisClass,BOOST_PP_TUPLE_ELEM(4,1,z),/*docstring*/ "|ystatic| :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "` " BOOST_PP_TUPLE_ELEM(4,3,z))
#define _STAT_NONSTAT_ATTR_PY(thisClass,attr,doc) /* _DEF_READWRITE_CUSTOM_STATIC(thisClass,attr,doc) */ _DEF_READWRITE_CUSTOM(thisClass,attr,doc) /* duplicate static and non-static attributes do not work (they apparently trigger to-python converter being added; for now, make then non-static, that's it. */
#define _STATATTR_PY(x,thisClass,z) _STAT_NONSTAT_ATTR_PY(thisClass,BOOST_PP_TUPLE_ELEM(4,1,z),/*docstring*/ "|ystatic| :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "` :yattrtype:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,0,z)) "` " BOOST_PP_TUPLE_ELEM(4,3,z))
#define _STATATTR_DECL(x,y,z) static BOOST_PP_TUPLE_ELEM(4,0,z) BOOST_PP_TUPLE_ELEM(4,1,z);
#define _STRIP_TYPE_DEFAULT_DOC(x,y,z) (BOOST_PP_TUPLE_ELEM(4,1,z))
#define _STATATTR_SET(x,thisClass,z) thisClass::BOOST_PP_TUPLE_ELEM(4,1,z)=BOOST_PP_TUPLE_ELEM(4,2,z);
......
......@@ -46,14 +46,6 @@ class OpenGLRenderingEngine : public Serializable
// updated after every call to render
shared_ptr<Scene> scene;
#if 0
DynLibDispatcher<InteractionGeometry, GlInteractionGeometryFunctor, void, TYPELIST_5(const shared_ptr<InteractionGeometry>&, const shared_ptr<Interaction>&, const shared_ptr<Body>&, const shared_ptr<Body>&, bool)> interactionGeometryDispatcher;
DynLibDispatcher<InteractionPhysics, GlInteractionPhysicsFunctor, void, TYPELIST_5(const shared_ptr<InteractionPhysics>&, const shared_ptr<Interaction>&, const shared_ptr<Body>&, const shared_ptr<Body>&, bool)> interactionPhysicsDispatcher;
DynLibDispatcher<State, GlStateFunctor, void, TYPELIST_1(const shared_ptr<State>&)> stateDispatcher;
DynLibDispatcher<Bound, GlBoundFunctor, void, TYPELIST_2(const shared_ptr<Bound>&, Scene*)> boundDispatcher;
DynLibDispatcher<Shape, GlShapeFunctor, void, TYPELIST_4(const shared_ptr<Shape>&, const shared_ptr<State>&,bool,const GLViewInfo&)> shapeDispatcher;
#endif
GlBoundDispatcher boundDispatcher;
GlInteractionGeometryDispatcher interactionGeometryDispatcher;
GlInteractionPhysicsDispatcher interactionPhysicsDispatcher;
......@@ -80,6 +72,7 @@ class OpenGLRenderingEngine : public Serializable
void init();
void initgl();
void render(const shared_ptr<Scene>& scene, body_id_t selection = body_id_t(-1));
void pyRender(){render(Omega::instance().getScene());}
void renderWithNames(const shared_ptr<Scene>& );
private :
......@@ -130,7 +123,8 @@ class OpenGLRenderingEngine : public Serializable
/*init*/,
/*ctor*/,
/*py*/
.def("setRefSe3",&OpenGLRenderingEngine::setBodiesRefSe3,"Make current positions and orientation reference for scaleDisplacements and scaleRotations.");
.def("setRefSe3",&OpenGLRenderingEngine::setBodiesRefSe3,"Make current positions and orientation reference for scaleDisplacements and scaleRotations.")
.def("render",&OpenGLRenderingEngine::pyRender,"Render the scene in the current OpenGL context.")
);
};
REGISTER_SERIALIZABLE(OpenGLRenderingEngine);
......
......@@ -6,6 +6,7 @@
// boost::python
#if 0
#include<indexing_suite/container_suite.hpp>
// #include<indexing_suite/container_proxy.hpp>
#include<indexing_suite/vector.hpp>
#endif
......@@ -112,13 +113,35 @@ struct custom_numpyBoost_to_py{
}
};
#if 0
template<typename T>
std::string vectorRepr(const vector<T>& v){ std::string ret("["); for(size_t i=0; i<v.size(); i++) { if(i>0) ret+=","; ret+=lexical_cast<string>(v[i]); } return ret+"]"; }
template<>
std::string vectorRepr(const vector<std::string>& v){ std::string ret("["); for(size_t i=0; i<v.size(); i++) { if(i>0) ret+=","; ret+="'"+lexical_cast<string>(v[i])+"'"; } return ret+"]"; }
// is not picked up?
bool operator<(const Vector3r& a, const Vector3r& b){ return a[0]<b[0]; }
#endif
using namespace boost::python;
BOOST_PYTHON_MODULE(_customConverters){
// class_<std::vector<int> >("vecInt").def(indexing::container_suite<std::vector<int> >());
// syntax ??
// http://language-binding.net/pyplusplus/documentation/indexing_suite_v2.html.html#container_proxy
// http://www.mail-archive.com/cplusplus-sig@python.org/msg00862.html
//class_<indexing::container_proxy<std::vector<string> >,bases<class_<std::vector<string> > > >("vecStr").def(indexing::container_suite<indexing::container_proxy<std::vector<string> > >());
//class_<std::vector<string> >("vecStr").def(indexing::container_suite<std::vector<string> >());
#if 0
custom_vector_from_seq<string>(); class_<std::vector<string> >("vector_" "string").def(indexing::container_suite<std::vector<string> >()).def("__repr__",&vectorRepr<string>);
custom_vector_from_seq<int>(); class_<std::vector<int> >("vector_" "int").def(indexing::container_suite<std::vector<int> >()).def("__repr__",&vectorRepr<int>);
custom_vector_from_seq<Real>(); class_<std::vector<Real> >("vector_" "Real").def(indexing::container_suite<std::vector<Real> >()).def("__repr__",&vectorRepr<Real>);
// this needs operator< for Vector3r (defined above, but not picked up for some reason)
custom_vector_from_seq<Vector3r>(); class_<std::vector<Vector3r> >("vector_" "Vector3r").def(indexing::container_suite<std::vector<Vector3r> >()).def("__repr__",&vectorRepr<Vector3r>);
#endif
custom_Se3r_from_seq(); to_python_converter<Se3r,custom_se3_to_tuple>();
// StrArrayMap (typedef for std::map<std::string,numpy_boost>) → python dictionary
......@@ -126,7 +149,7 @@ BOOST_PYTHON_MODULE(_customConverters){
// register from-python converter and to-python converter
// register 2-way conversion between c++ vector and python homogeneous sequence (list/tuple) of corresponding type
#define VECTOR_SEQ_CONV(Type) custom_vector_from_seq<Type>(); to_python_converter<std::vector<Type>, custom_vector_to_list<Type> >();
#define VECTOR_SEQ_CONV(Type) custom_vector_from_seq<Type>(); to_python_converter<std::vector<Type>, custom_vector_to_list<Type> >();
VECTOR_SEQ_CONV(int);
VECTOR_SEQ_CONV(Real);
VECTOR_SEQ_CONV(Se3r);
......
......@@ -38,7 +38,7 @@ O.engines=[
]
#Generate a spiral
Ne=200
Ne=400
for i in range(0, Ne):
omega=60.0/float(Ne); hy=0.10; hz=0.15;
px=float(i)*(omega/60.0); py=sin(float(i)*omega)*hy; pz=cos(float(i)*omega)*hz;
......@@ -67,5 +67,6 @@ def history():
#yade.qt.Renderer().bound=True
plot.plot()
O.saveTmp()
#O.bodies[0].state.angVel=Vector3(0.05,0,0)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#from PyQt4 import Qwt5
import re
import logging
logging.basicConfig(level=logging.DEBUG)
from logging import debug,info,warning,error
class SerializableData(QWidget):
"Class displaying and modifying serializable attributes of a yade object."
import collections
# each attribute has one entry associated with itself
class EntryData:
def __init__(self,name,T):
self.name,self.T=name,T
self.lineNo,self.widget=None,None
def __init__(self,ser,parent=None):
"Construct window, *ser* is the object we want to show."
QWidget.__init__(self,parent)
self.ser=ser
self.entries=[]
print self.ser
debug('New Serializable of type %s'%ser.__class__.__name__)
self.setWindowTitle(str(ser))
self.mkWidgets()
def getListTypeFromDocstring(self,attr):
"Guess type of array by scanning docstring for :yattrtype: and parsing its argument; ugly, but works."
doc=getattr(self.ser.__class__,attr).__doc__
if doc==None:
error("Attribute %s has no docstring."%attr)
return None
m=re.search(r':yattrtype:`([^`]*)`',doc)
if not m:
error("Attribute %s does not contain :yattrtype:`....` (docstring is '%s'"%(attr,doc))
return None
cxxT=m.group(1)
#debug('Got type "%s" from :yattrtype:'%cxxT)
def vecTest(T,cxxT):
regexp=r'^\s*(std\s*::)?\s*vector\s*<\s*(std\s*::)?\s*('+T+r')\s*>\s*$'
m=re.match(regexp,cxxT)
return m
vecMap={
'int':int,'long':int,'body_id_t':long,'size_t':long,
'Real':float,'float':float,'double':float,
'Vector3r':Vector3,'Matrix3r':Matrix3,
'string':str
}
for T,ret in vecMap.items():
if vecTest(T,cxxT):
debug("Got type %s from cxx type %s"%(ret.__name__,cxxT))
return (ret,)
error("Unable to guess python type from cxx type '%s'"%cxxT)
return None
def mkAttrEntries(self):
d=self.ser.dict()
for attr,val in self.ser.dict().items():
if isinstance(val,list):
if len(val)==0: t=self.getListTypeFromDocstring(attr)
else: t=(val[0].__class__,) # 1-tuple is list of the contained type
else: t=val.__class__
debug('Attr %s is of type %s'%(attr,((t[0].__name__,) if isinstance(t,tuple) else t.__name__)))
self.entries.append(self.EntryData(name=attr,T=t))
def mkWidget(self,entry):
self.chgPalette=QPalette()
self.chgPalette.setColor(QPalette.Window,QColor('red'))
widget=None
if entry.T==bool:
widget=QCheckBox('',self)
widget.setChecked(getattr(self.ser,entry.name))
self.connect(widget,SIGNAL('stateChanged(int)'),lambda num: setattr(self.ser,entry.name,(True if num>0 else False)))
elif entry.T==str:
widget=QLineEdit('',self)
widget.setText(getattr(self.ser,entry.name))
self.connect(widget,SIGNAL('editingFinished()'),lambda: setattr(self.ser,entry.name,str(widget.text())))
elif entry.T==int:
widget=QSpinBox(self)
widget.setRange(int(-1e10),int(1e10)); widget.setSingleStep(1);
widget.setValue(getattr(self.ser,entry.name))
self.connect(widget,SIGNAL('valueChanged(int)'),lambda val: setattr(self.ser,entry.name,val))
elif entry.T==float:
widget=QLineEdit('',self)
widget.setText(str(getattr(self.ser,entry.name)))
self.connect(widget,SIGNAL('editingFinished()'),lambda val: setattr(self.ser,entry.name,float(str(widget.text()))))
elif entry.T==Vector3:
widget=QFrame(self); widget.setContentsMargins(0,0,0,0)
box=QHBoxLayout(widget); box.setSpacing(0)
vec=getattr(self.ser,entry.name)
for i in range(3):
subw=QLineEdit('')
subw.setText(str(vec[i]))
subw.setSizePolicy(QSizePolicy().setHorizontalPolicy(
class updateVec:
"bind local args... ugly"
def __init__(self,i,ser,name,subw): self.i,self.ser,self.name,self.subw=i,ser,name,subw
def __call__(self):
newVal=float(str(self.subw.text()))
debug('updating %d with %s'%(self.i,newVal))
v=getattr(self.ser,self.name); v[self.i]=newVal; setattr(self.ser,self.name,v)
self.connect(subw,SIGNAL('editingFinished()'), updateVec(i,self.ser,entry.name,subw))
box.addWidget(subw)
return widget
def mkWidgets(self):
self.mkAttrEntries()
grid=QtGui.QGridLayout()
for lineNo,entry in enumerate(self.entries):
grid.addWidget(QLabel(entry.name),lineNo,0)
entry.widget=self.mkWidget(entry)
if entry.widget: grid.addWidget(entry.widget,lineNo,1)
else: grid.addWidget(QLabel('<i>unhandled type</i>'),lineNo,1)
self.setLayout(grid)
s1=SerializableData(VTKRecorder())
s2=SerializableData(OpenGLRenderingEngine())
s1.show()
s2.show()
# install pyqglviewer from https://launchpad.net/~nakednous/+ppa-packages
from PyQGLViewer import *
class Viewer(QGLViewer):
def __init__(self):
QGLViewer.__init__(self)
self.renderer=OpenGLRenderingEngine()
def init(self):
self.setAxisIsDrawn(True)
self.setGridIsDrawn(True)
def draw(self):
self.renderer.render()
O.bodies.append([utils.sphere((0,0,-.4),.3),utils.sphere((0,0,.4),.3)])
viewer=Viewer()
viewer.setWindowTitle('Yade')
viewer.show()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment