diff --git a/conda/meta.yaml b/conda/meta.yaml index 5874d232..e56cbbc6 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -29,11 +29,12 @@ requirements: - cgal-cpp - qhull - ann - - boost <=1.73 - - expat # [linux] - - libxcb # [linux] - - pthread-stubs # [linux] - - {{ cdt('mesa-libgl-devel') }} # [linux] + - boost # [unix] + - boost <1.74 # [win] # v1.74 has a bug on windows. + - expat # [linux] + - libxcb # [linux] + - pthread-stubs # [linux] + - {{ cdt('mesa-libgl-devel') }} # [linux] - libglu # [linux] - xorg-libxfixes # [linux] diff --git a/src/cpp/plantgl/scenegraph/appearance/texture.cpp b/src/cpp/plantgl/scenegraph/appearance/texture.cpp index b9f7e5d5..9c687d4b 100644 --- a/src/cpp/plantgl/scenegraph/appearance/texture.cpp +++ b/src/cpp/plantgl/scenegraph/appearance/texture.cpp @@ -443,6 +443,14 @@ Texture2D::Texture2D(const ImageTexturePtr& image, __BaseColor(basecolor) { } +Texture2D::Texture2D(const ImageTexturePtr& image, + const Color4& basecolor): + Appearance(), + __Image(image), + __Transformation(DEFAULT_TRANSFORMATION), + __BaseColor(basecolor) { +} + Texture2D::Texture2D(const std::string& name, const ImageTexturePtr& image, diff --git a/src/cpp/plantgl/scenegraph/appearance/texture.h b/src/cpp/plantgl/scenegraph/appearance/texture.h index 42fa58ab..61da7b59 100644 --- a/src/cpp/plantgl/scenegraph/appearance/texture.h +++ b/src/cpp/plantgl/scenegraph/appearance/texture.h @@ -293,6 +293,9 @@ class SG_API Texture2D : public Appearance const Texture2DTransformationPtr& transformation = DEFAULT_TRANSFORMATION, const Color4& basecolor = DEFAULT_BASECOLOR); + Texture2D(const ImageTexturePtr& image, + const Color4& basecolor); + Texture2D(const std::string& name, const ImageTexturePtr& image, const Texture2DTransformationPtr& transformation = DEFAULT_TRANSFORMATION, diff --git a/src/cpp/plantgl/version.h b/src/cpp/plantgl/version.h index 03bc0a77..80ac9f46 100644 --- a/src/cpp/plantgl/version.h +++ b/src/cpp/plantgl/version.h @@ -48,7 +48,7 @@ #define __plantgl_version_h__ /// PGL Version macro -#define PGL_VERSION 0x030600 +#define PGL_VERSION 0x030700 #endif diff --git a/src/openalea/plantgl/algo/jsonrep.py b/src/openalea/plantgl/algo/jsonrep.py new file mode 100644 index 00000000..490b5745 --- /dev/null +++ b/src/openalea/plantgl/algo/jsonrep.py @@ -0,0 +1,193 @@ +import openalea.plantgl.scenegraph as sg +import openalea.plantgl.math as mt +import openalea.plantgl.scenegraph.pglinspect as inspect +from openalea.plantgl.algo.pyalgo import * + + +class ToJsonRepConverter (PyAlgo): + def __init__(self): + PyAlgo.__init__(self) + self.clear() + + def clear(self): + self.cache = set() + + def pglobject(self, obj, *args): + res = dict( type = obj.__class__.__name__, id = obj.getObjectId()) + return self.pglattributes(res, obj, *args) + + def pglattributes(self, res, obj): + attributes = inspect.get_pgl_attributes(obj) + + for att in attributes: + if inspect.is_pgl_attribute_to_default(obj, att): + continue + res[att] = self.convert(getattr(obj,att)) + return res + + def convert(self,obj): + if obj is None: + return None + elif hasattr(obj,'getObjectId') : + if obj.getObjectId() in self.cache : + return { 'type' : 'Instance', 'id' : obj.getObjectId() } + else: + self.cache.add(obj.getObjectId()) + return self.apply(obj) + else: + return self.apply(obj) + + @for_types((bool, int, float, str)) + def simpletype(self, value): + return value + + @for_types(sg.Color3) + def color3(self, value): + return [value.red,value.green,value.blue] + + @for_types(sg.Color4) + def color4(self, value): + return [value.red,value.green,value.blue, value.alpha] + + @for_types((mt.Vector2,mt.Vector3,mt.Vector4,sg.Index,sg.Index3,sg.Index4)) + def vector(self, value): + return list(value) + + @for_types(sg.Transform4) + def transform4(self, value): + return { 'type' : value.__class__.__name__ , 'data' : self.convert(value.getMatrix()) } + + @for_types((sg.Point2Array,sg.Point3Array,sg.Point4Array,sg.Color3Array,sg.Color4Array,sg.IndexArray,sg.Index3Array,sg.Index4Array, sg.GeometryArray, sg.RealArray, sg.Transform4Array)) + def array(self, value): + return { 'type' : value.__class__.__name__ , 'id' : value.getPglId() , 'data' : list(map(self.convert,value)) } + + @for_types((sg.Point2Matrix,sg.Point3Matrix,sg.Point4Matrix,sg.RealArray2)) + def array2(self, value): + return { 'type' : value.__class__.__name__ , 'id' : value.getPglId() , 'data' : [list(map(self.convert,row)) for row in value] } + + @for_types((mt.Matrix2,mt.Matrix3,mt.Matrix4)) + def matrix(self, value): + return { 'type' : value.__class__.__name__ , 'data' : value.data() } + + @for_types(sg.SceneObject) + def sceneobject(self, value): + return self.pglobject(value) + + @for_types(sg.Scene) + def scene(self, value): + return { 'type' : 'Scene', 'data' : list(map(self.convert,value)) } + + @for_types(sg.QuantisedFunction) + def qfunction(self, qfunc): + return { 'type' : 'QuantisedFunction', 'clamped' : qfunc.clamped, 'sampling' : qfunc.sampling, 'data' : self.convert(qfunc.input) } + + +class FromJsonRepConverter(PyAlgo): + def __init__(self): + PyAlgo.__init__(self) + self.clear() + self.set_default_mapping(self.default) + + def clear(self): + self.cache = dict() + + @for_identifiers(('Matrix2','Matrix3','Matrix4')) + def matrix(self, jsonrep): + ptype = jsonrep['type'] + constructor = mt.__dict__[ptype] + dim = int(ptype[-1]) + values = jsonrep['data'] + values = tuple([tuple(values[dim*i:dim*(i+1)]) for i in range(dim)]) + return constructor(*values) + + @for_identifiers('Scene') + def scene(self, jsonrep): + return sg.Scene(list(map(self.convert,jsonrep['data']))) + + @for_identifiers('Instance') + def instance(self, jsonrep): + return self.cache[jsonrep.get('id') ] + + @for_identifiers('QuantisedFunction') + def qfunction(self, jsonrep): + input = self.convert(jsonrep['data']) + res = sg.QuantisedFunction(input, clamped = jsonrep['clamped'], sampling = jsonrep['sampling']) + res.input = input + return res + + def array(self, values): + return list(map(self.convert, values)) + + def default(self, jsonrep): + name = jsonrep.get('name') + attributes = [key for key in jsonrep if not key in ['type','name','id']] + values = {} + for att in attributes: + value = self.convert(jsonrep[att]) + values[att] = value + if 'data' in values: + rawdata = values['data'] + del values['data'] + else: + rawdata = None + ptype = jsonrep['type'] + try: + constructor = sg.__dict__[ptype] + except KeyError as ke: + constructor = mt.__dict__[ptype] + toremove = [] + for param, pvalue in values.items(): + if pvalue is None: + toremove.append(param) + for p in toremove: + del values[p] + try: + if rawdata: + res = constructor(rawdata, **values) + else: + res = constructor(**values) + except Exception as e: + print(jsonrep) + raise e + if name: + res.name = name + return res + + def convert(self, jsonrep): + if type(jsonrep) != dict: + if type(jsonrep) == list: + return self.array(jsonrep) + else: + return jsonrep + res = self.apply(jsonrep, jsonrep['type']) + self.cache[jsonrep.get('id')] = res + return res + + +def to_json_rep(object): + fj = ToJsonRepConverter() + return fj.convert(object) + +def from_json_rep(jsonrep): + fj = FromJsonRepConverter() + return fj.convert(jsonrep) + + + +pattern =""" @for_types([sg.%s]) + def %s(self, obj): + return self.pglobject(obj, %s) +""" + + +def generate_class_methods(): + candidates = [] + for classname,cls in sg.__dict__.items(): + if inspect.is_sceneobject_subclass(cls) and not inspect.is_pgl_abstract(cls): + candidates.append((classname,cls)) + candidates.sort(key = lambda v : v[0]) + for classname,cls in candidates: + attributes = inspect.get_pgl_attributes(cls) + print(pattern % (classname, classname.lower(), ', '.join(map(repr,attributes)))) + +#generate_class_methods() \ No newline at end of file diff --git a/src/openalea/plantgl/algo/pyalgo.py b/src/openalea/plantgl/algo/pyalgo.py new file mode 100644 index 00000000..657b0b5a --- /dev/null +++ b/src/openalea/plantgl/algo/pyalgo.py @@ -0,0 +1,44 @@ +import openalea.plantgl.scenegraph.pglinspect as inspect + + +def for_types(types): + if not type(types) in [tuple,list]: + types = (types,) + types = sum([inspect.get_all_subclasses(t) for t in types if inspect.is_sceneobject_subclass(t)],[])+[t for t in types if not inspect.is_sceneobject_subclass(t)] + types = tuple(types) + def for_given_types(f): + f.__for_identifiers__ = types + return f + return for_given_types + +def for_identifiers(identifiers): + if not type(identifiers) in [tuple,list]: + identifiers = (identifiers,) + def for_given_types(f): + f.__for_identifiers__ = identifiers + return f + return for_given_types + +class PyAlgo: + def __init__(self): + self.build_conversion_map() + self.__default_mapping = None + + def build_conversion_map(self): + self.__conversion_map = { } + for funcname in dir(self): + func = getattr(self,funcname) + if hasattr(func,'__for_identifiers__'): + for t in func.__for_identifiers__: + self.add_to_conversion_map(t,func) + + def add_to_conversion_map(self, identifier, func): + self.__conversion_map[identifier] = func + + def set_default_mapping(self, func): + self.__default_mapping = func + + def apply(self, value, identifier = None): + if identifier is None: + identifier = type(value) + return self.__conversion_map.get(identifier,self.__default_mapping)(value) \ No newline at end of file diff --git a/src/openalea/plantgl/codec/__init__.py b/src/openalea/plantgl/codec/__init__.py index bb1cd93a..ebc48965 100644 --- a/src/openalea/plantgl/codec/__init__.py +++ b/src/openalea/plantgl/codec/__init__.py @@ -1,4 +1,5 @@ -from . import asc from . import gts from . import obj -from . import ply \ No newline at end of file +from . import json +#from . import asc +#from . import ply \ No newline at end of file diff --git a/src/openalea/plantgl/codec/json.py b/src/openalea/plantgl/codec/json.py new file mode 100644 index 00000000..2befe27e --- /dev/null +++ b/src/openalea/plantgl/codec/json.py @@ -0,0 +1,33 @@ +import openalea.plantgl.scenegraph as sg +import openalea.plantgl.algo.jsonrep as jr +import json + +class JsonCodec (sg.SceneCodec): + """ Json File Format """ + + def __init__(self): + """ + Initialisation of the codec info + """ + sg.SceneCodec.__init__(self,"JSON",sg.SceneCodec.Mode.ReadWrite) + + def formats(self): + """ return formats """ + return [ sg.SceneFormat("Json Codec",["json"],"The json format") ] + + def read(self,fname): + """ read a json file """ + with open(fname, 'r') as json_file: + json_schema = json.load(json_file) + return jr.from_json_rep(json_schema) + + def write(self, fname, scene): + """ Write a JSON file from a plantGL scene graph. + + This method will convert a PlantGL scene graph into an JSON file. + """ + with open(fname, 'w') as json_file: + json.dump(jr.to_json_rep(scene), json_file) + +codec = JsonCodec() +sg.SceneFactory.get().registerCodec(codec) \ No newline at end of file diff --git a/src/openalea/plantgl/codec/obj.py b/src/openalea/plantgl/codec/obj.py index f81ef3de..b6a68ffb 100644 --- a/src/openalea/plantgl/codec/obj.py +++ b/src/openalea/plantgl/codec/obj.py @@ -481,11 +481,13 @@ def write(self,fname,scene): """ Write an OBJ file from a plantGL scene graph. This method will convert a PlantGL scene graph into an OBJ file. - It does not manage materials correctly yet. :Examples: import openalea.plantgl.scenegraph as sg - scene = sg.Scene()""" + scene = sg.Scene() + scene.write('scene.obj') + + """ print("Write "+fname) d = alg.Discretizer() f = open(fname,'w') diff --git a/src/openalea/plantgl/scenegraph/__init__.py b/src/openalea/plantgl/scenegraph/__init__.py index 24d04939..3bdfd3a2 100644 --- a/src/openalea/plantgl/scenegraph/__init__.py +++ b/src/openalea/plantgl/scenegraph/__init__.py @@ -18,6 +18,7 @@ def newFunc(*args, **kwargs): warnings.warn("Call to deprecated function %s." % func.__name__, category=DeprecationWarning) return func(*args, **kwargs) + newFunc.__deprecated__ = True newFunc.__name__ = func.__name__ newFunc.__doc__ = func.__doc__ newFunc.__dict__.update(func.__dict__) @@ -31,7 +32,7 @@ def __extrusion_get_scale(extrusion): def __extrusion_set_scale(extrusion,value): extrusion.scaleList = value -Extrusion.scale = property(__extrusion_get_scale,__extrusion_set_scale) +Extrusion.scale = property(__extrusion_get_scale,__extrusion_set_scale, doc='DEPRECATED') @deprecated def __extrusion_get_orientation(extrusion): @@ -41,7 +42,7 @@ def __extrusion_get_orientation(extrusion): def __extrusion_set_orientation(extrusion,value): extrusion.orientationList = value -Extrusion.orientation = property(__extrusion_get_orientation,__extrusion_set_orientation) +Extrusion.orientation = property(__extrusion_get_orientation,__extrusion_set_orientation, doc='DEPRECATED') """ Copy functions for Curve2D types """ diff --git a/src/openalea/plantgl/scenegraph/pglinspect.py b/src/openalea/plantgl/scenegraph/pglinspect.py new file mode 100644 index 00000000..d94283a7 --- /dev/null +++ b/src/openalea/plantgl/scenegraph/pglinspect.py @@ -0,0 +1,66 @@ +from inspect import * +from . import _pglsg as sg + +def is_deprecated_attribute(obj, attname): + d = getattr(getattr(obj.__class__,attname),'__doc__') + if not d is None: + return d.startswith('DEPRECATED') + return False + +def get_pgl_attributes(obj): + attributes = [n for n in dir(obj) if not '__' in n and isdatadescriptor(getattr(obj.__class__,n)) and not is_deprecated_attribute(obj,n)] + toremove = [] + def att_rank(v): + try: + return obj.__init__.__doc__.index(v) + except ValueError as ve: + if v != 'name': + toremove.append(v) + return len(obj.__init__.__doc__) + attributes.sort(key = att_rank ) + for v in toremove: + del attributes[attributes.index(v)] + return attributes + +def is_pgl_attribute_to_default(obj, attname): + if attname == 'name' : + return not obj.isNamed() + specific = { 'ccw' : 'isCCWToDefault'} + prefix = 2 if attname[0] in 'uv' else 1 + todefault = 'is'+attname[:prefix].upper()+attname[prefix:]+'ToDefault' + defaulttest = specific.get(attname, todefault) + if hasattr(obj,defaulttest) : + return getattr(obj,defaulttest)() + else: + return False + + +def is_pgl_abstract(cls): + import inspect + if not inspect.isclass(cls) : return False + #if not issubclass(cls,sg.SceneObject): return False + try: + cls() + return False + except RuntimeError as re: + return True + except: + return False + + +def is_sceneobject_subclass(cls): + return issubclass(cls, sg.SceneObject) + +def get_all_subclasses(cls_or_tuple): + if type(cls_or_tuple) in [tuple,list]: + toprocess = list(cls_or_tuple) + else: + toprocess = [cls_or_tuple] + subclasses = [] + while len(toprocess) > 0: + newtoprocess = [] + for t in toprocess: + newtoprocess += t.__subclasses__() + subclasses += newtoprocess + toprocess = newtoprocess + return subclasses \ No newline at end of file diff --git a/src/wrapper/scenegraph/arrays2_macro.h b/src/wrapper/scenegraph/arrays2_macro.h index 9bd56720..3ac1b645 100644 --- a/src/wrapper/scenegraph/arrays2_macro.h +++ b/src/wrapper/scenegraph/arrays2_macro.h @@ -526,7 +526,7 @@ std::string PREFIX##_str(ARRAY * a) { return array2_str(a, #ARRAY); } #define EXPORT_CLASS_ARRAY( PREFIX, ARRAY )\ - class_< ARRAY, ARRAY##Ptr, boost::noncopyable>( #ARRAY , init( #ARRAY "(int rows, int cols)", args("rows","cols")) ) \ + class_< ARRAY, ARRAY##Ptr, bases, boost::noncopyable>( #ARRAY , init( #ARRAY "(int rows, int cols)", args("rows","cols")) ) \ .def( "__init__", make_constructor( &extract_array2_from_list ), #ARRAY "([[a,b,c],[d,e,f]])" ) \ #define EXPORT_ARRAY_FUNC_COMMON( ARRAY, PREFIX ) \ diff --git a/src/wrapper/scenegraph/export_amapsymbol.cpp b/src/wrapper/scenegraph/export_amapsymbol.cpp index a6f277c4..9e80a5e7 100644 --- a/src/wrapper/scenegraph/export_amapsymbol.cpp +++ b/src/wrapper/scenegraph/export_amapsymbol.cpp @@ -59,7 +59,8 @@ void export_AmapSymbol() ( "AmapSymbol", "The AmapSymbol describes an object of class of Mesh stored in the SMB file format of the Amap software." "This is provided for ascendant compatibility.", - init< optional >("AmapSymbol(filename)")) + init< optional >("AmapSymbol(filename,solid)", + (bp::arg("filename"),bp::arg("solid")=FaceSet::DEFAULT_SOLID)) ) .def("readFile",&AmapSymbol::readFile) .DEC_BT_PROPERTY(filename,AmapSymbol,FileName,std::string) .DEF_PGLBASE(AmapSymbol) diff --git a/src/wrapper/scenegraph/export_bezierpatch.cpp b/src/wrapper/scenegraph/export_bezierpatch.cpp index ed76d5ed..7d74238a 100644 --- a/src/wrapper/scenegraph/export_bezierpatch.cpp +++ b/src/wrapper/scenegraph/export_bezierpatch.cpp @@ -69,8 +69,8 @@ void export_BezierPatch() "and using the parametric equation S(u,v) = Sum(i=0,n)Sum(j=0,m)(Bi,n(u)Bj,m(v)Pi,j) with u and v in [0,1]\n" "where Bi,n(u) and Bi,m(v) are the classical n and m-th degree Bernstein polynomials.", init > - ("BezierPatch(Point4Matrix ctrlPointList [,ustride,vstride,ccw])", - (bp::arg("ctrlPointList"), + ("BezierPatch(Point4Matrix ctrlPointMatrix [,ustride,vstride,ccw])", + (bp::arg("ctrlPointMatrix"), bp::arg("ustride")=BezierPatch::DEFAULT_STRIDE, bp::arg("vstride")=BezierPatch::DEFAULT_STRIDE, bp::arg("ccw")=Patch::DEFAULT_CCW))) diff --git a/src/wrapper/scenegraph/export_nurbspatch.cpp b/src/wrapper/scenegraph/export_nurbspatch.cpp index d98f80f3..3383563c 100644 --- a/src/wrapper/scenegraph/export_nurbspatch.cpp +++ b/src/wrapper/scenegraph/export_nurbspatch.cpp @@ -91,11 +91,11 @@ void export_NurbsPatch() "and using the parametric equation S(u,v) = Sum(i=0,n)Sum(j=0,m)(Ri,n(u)Rj,m(v)Pi,j) with u and v in [0,1]\n" "where Ri,n(u) and Ri,m(v) are classical n and m-th degree rational basis function.", init > - ("NurbsPatch(Point4Matrix ctrlPointList, RealArray uKnotList,RealArray vKnotList [,uDeg, vDeg,ustride,vstride,ccw])")) + ("NurbsPatch(Point4Matrix ctrlPointMatrix, RealArray uKnotList,RealArray vKnotList [,uDeg, vDeg,ustride,vstride,ccw])")) .def(init > - ("NurbsPatch(Point4Matrix ctrlPointList, udegree, vdegree," + ("NurbsPatch(Point4Matrix ctrlPointMatrix, udegree, vdegree," "uknotList, vknotList [,ustride,vstride,ccw])", - (bp::arg("ctrlPointList"), + (bp::arg("ctrlPointMatrix"), bp::arg("udegree") = NurbsPatch::DEFAULT_NURBS_DEGREE, bp::arg("vdegree") = NurbsPatch::DEFAULT_NURBS_DEGREE, bp::arg("uknotList") = TOOLS(RealArrayPtr()), diff --git a/src/wrapper/scenegraph/export_tapered.cpp b/src/wrapper/scenegraph/export_tapered.cpp index fbae702c..50790365 100644 --- a/src/wrapper/scenegraph/export_tapered.cpp +++ b/src/wrapper/scenegraph/export_tapered.cpp @@ -54,6 +54,10 @@ using namespace boost::python; DEF_POINTEE(Tapered) + +PrimitivePtr tr_primitive(Tapered * obj) { return obj->getPrimitive(); } +void tr_setprimitive(Tapered * obj, PrimitivePtr value) { obj->getPrimitive() = value; } + void export_Tapered() { class_< Tapered, TaperedPtr, bases< Transformed > , boost::noncopyable > @@ -70,7 +74,8 @@ void export_Tapered() .DEF_PGLBASE(Tapered) .DEC_BT_PROPERTY_WDV(topRadius,Tapered,TopRadius,real_t,DEFAULT_TOP_RADIUS) .DEC_BT_PROPERTY_WDV(baseRadius,Tapered,BaseRadius,real_t,DEFAULT_BASE_RADIUS) - .DEC_PTR_PROPERTY(primitive,Deformed,Primitive,PrimitivePtr) + // .DEC_PTR_PROPERTY(primitive,Deformed,Primitive,PrimitivePtr) + .add_property("primitive", &tr_primitive, &tr_setprimitive) ; implicitly_convertible< TaperedPtr, TransformedPtr >(); diff --git a/src/wrapper/scenegraph/export_texture.cpp b/src/wrapper/scenegraph/export_texture.cpp index f2146576..85e8776c 100644 --- a/src/wrapper/scenegraph/export_texture.cpp +++ b/src/wrapper/scenegraph/export_texture.cpp @@ -125,7 +125,7 @@ void export_Texture2DTransformation() class_< Texture2DTransformation, Texture2DTransformationPtr, bases< SceneObject >, boost::noncopyable > ( "Texture2DTransformation", "The transformation of a texture 2D.", init< boost::python::optional > - ((bp::arg("name"), + ((bp::arg("name")="", bp::arg("scale")=Texture2DTransformation::DEFAULT_SCALE, bp::arg("translation")=Texture2DTransformation::DEFAULT_TRANSLATION, bp::arg("rotationCenter")=Texture2DTransformation::DEFAULT_ROTATIONCENTER, @@ -168,11 +168,21 @@ void export_Texture2D() class_< Texture2D, Texture2DPtr, bases< Appearance >, boost::noncopyable > ( "Texture2D", "The material of a textured object.", init< ImageTexturePtr, boost::python::optional > - (args("image","transformation","baseColor"), + ((bp::arg("image"), + bp::arg("transformation"), + bp::arg("baseColor")=Texture2D::DEFAULT_BASECOLOR), "Texture2D(image [,transformation, baseColor])")) + .def(init< string, ImageTexturePtr, boost::python::optional > - (args("name","image","transformation","baseColor"), + ((bp::arg("name"), + bp::arg("image"), + bp::arg("transformation"), + bp::arg("baseColor")=Texture2D::DEFAULT_BASECOLOR), "Texture2D(name, image [,transformation, baseColor])")) + .def(init< ImageTexturePtr, Color4 > + ((bp::arg("image"), + bp::arg("baseColor")=Texture2D::DEFAULT_BASECOLOR), + "Texture2D(name, image, baseColor])")) .DEC_PTR_PROPERTY(image,Texture2D,Image,ImageTexturePtr ) .DEC_PTR_PROPERTY_WDV(transformation,Texture2D, Transformation, Texture2DTransformationPtr,DEFAULT_TRANSFORMATION) .DEC_BT_PROPERTY_WDV(baseColor,Texture2D, BaseColor, Color4, DEFAULT_BASECOLOR) diff --git a/test/test_geomprinter.py b/test/test_geomprinter.py index 681d0e52..ba3bc113 100644 --- a/test/test_geomprinter.py +++ b/test/test_geomprinter.py @@ -8,7 +8,7 @@ def eval_code(sceneobj,verbose = True): assert sceneobj.isValid() hasname = sceneobj.isNamed() if not hasname: - sceneobj.name = 'testedobject' + sceneobj.name = 'testedobject' fname = 'geomprinteroutput.geom' printer = pgl.PglFilePrinter(fname) sceneobj.apply(printer) diff --git a/test/test_jsonrep.py b/test/test_jsonrep.py new file mode 100644 index 00000000..a4ee7c8d --- /dev/null +++ b/test/test_jsonrep.py @@ -0,0 +1,73 @@ +import openalea.plantgl.all as pgl +import openalea.plantgl.algo.jsonrep as jr +from test_object_creation import shapebenchmark_generator,randtransform,randint +import pytest + + +def jsonconversion(sceneobj, verbose = False): + assert sceneobj.isValid() + if verbose: + print(sceneobj) + res = jr.to_json_rep(sceneobj) + if verbose: + print(res) + assert type(res) == dict + sceneobj2 = jr.from_json_rep(res) + assert type(sceneobj2) == type(sceneobj) + +@pytest.mark.parametrize('sceneobj', list(shapebenchmark_generator())) +def test_jsonconversion_on_benchmark_objects(sceneobj): + jsonconversion(sceneobj) + +def test_matrix(): + t = pgl.Matrix4() + jsonconversion(t) + +def test_extrusion(): + bc = pgl.BezierCurve([(0,0,0,1),(.5,1,0,1),(1.,1,0,1),(1.5,0,0,1)]) + circle = pgl.Polyline2D.Circle(1,20) + t = pgl.Extrusion(bc,circle) + jsonconversion(t) + +def test_tapered(): + ds = pgl.Sphere() + t = pgl.Tapered(1.,1.,ds) + jsonconversion(t) + +def test_scene(): + ds = pgl.Sphere() + t = pgl.Tapered(1.,1.,ds) + t2 = pgl.Translated(0.,0.,1., ds) + sc = pgl.Scene([pgl.Shape(t, pgl.Material((255,0,0))),pgl.Shape(t2, pgl.Material((0,255,0)))]) + jsonconversion(sc) + +def test_texture(): + fname = '../share/plantgl/pixmap/geomviewer.png' + t = pgl.ImageTexture(fname) + t.baseColor = (255,0,0,0) + sh = pgl.Shape(pgl.Cylinder(),t, 2) + jsonconversion(sh) + + +def te_st_jsonrep(): + jc = jr.JsonRepConverter() + print(jc.conversion_map.keys()) + +if __name__ == '__main__': + import traceback as tb + test_func = [ (n,v) for n,v in list(globals().items()) if 'test_' in n] + test_func.sort(key=lambda x : x[1].__code__.co_firstlineno) + for tfn,tf in test_func: + print(tfn) + if hasattr(tf, 'pytestmark'): + args = tf.pytestmark[0].args[1] + for arg in args: + try: + tf(arg) + except: + tb.print_exc() + else: + try: + tf() + except: + tb.print_exc() \ No newline at end of file