Open brean opened 2 years ago
If I understand the problem correctly, you could inspect SdfElement.children
, which is a list of all direct child elements that were explicitly set/modified.
The spec does, technically, allow you to set 0 or 2+ children for Geometry though. I don't know what gazebo will do in this case and I can't think of a scenario where you'd want to do so. Hence, assuming that your SDF is sensible and the geometry element has exactly one type set, you could do the following:
from pysdf import Geometry
my_geometry = Geometry()
my_geometry.ellipsoid.radii = (1, 2, 3)
geometry_type = my_geometry.children[0]
isinstance(geometry_type , Geometry.Ellipsoid) # True
The downside is that you will lose typed auto-completion because you won't know geometry_type
's type until runtime.
If you are looking for something "cleaner", e.g., assert my_geometry.type == "ellipsoid"
then this currently doesn't exist. I'm happy to add a feature like this, if you have a concrete suggestion for how this should look like. Does the official C parser have a method for this? If so, how does it look like?
Hello, thank you for creating such a useful library that enables easy manipulation of models using Python.
Following the topic raised in the current issue, I wonder which way is the preferred way to define a Geometry
. Reading the codes, I can come up with three different approaches:
Geometry.sphere
is a descriptor whose __get__
method will instantiate Geometry.Sphere
and add to the invoking instance's children
method and that Geometry.Sphere.radius
is a data descriptor.
g = Geometry()
g.sphere.radius = 0.1
Sphere
instance. (I personally prefer this approach since the implicit creation of a Sphere appears a little bit weird IMO.)
sphere = Geometry.Sphere()
sphere.radius = 0.1
g = Geometry(sphere)
Geometry
in one line.
Geometry(Geometry.Sphere(Geometry.Sphere.Radius(text=0.1)))
but it uses the dynamically created type Radius
(therefore IDE will complains it and thus might lead to typos) and manually sets the text
attribute which cannot be validated.
@huweiATgithub The short answer is that you can use either of these approaches.
The slightly longer answer is that SDF heavily relies on tags to configure attributes, e.g.. world.gravity
or scene.background
. Each tag in SDF is represented by a python class in python-sdformat
(standard behavior for bindings), and it would be awkward UX to have to create and assign them one-by-one:
scene = Scene()
scene.sky.clouds.speed = 0.6
# vs.
scene = Scene()
scene,sky = Scene.Sky()
scene.sky.clouds = Scene.Sky.Clouds()
clouds.speed = 0.6 # Speed is a tag, too, but can't have children, so we cant instantiate it
The latter is perhaps more familiar from a software engineering background and preferred when engineering. However, it is also more verbose and doesn't offer much gain over writing SDF directly:
<scene>
<sky>
<clouds>
<speed>0.6</speed>
</clouds>
</sky>
</scene>
My goal with python-sdformat
was to make it faster to work with (and/or generate) SDF. SDF is essentially a (complex) config file format, so I am okay with it creating the necessary config (be that objects or tags) under the hood when I say:
scene = Scene()
scene.sky.clouds.speed = 0.6
Regarding auto-completion for dynamic types this is an unfortunate limitation of the project. I used this project to create a faster (and type-hint-guided) way to interact with SDF, but I didn't discover that you can separate definitions (.py files) and type annotations (.pyi files) until much later. If you were to create a .pyi
file for the project, you could add type annotations for Radius
and other dynamically generated types. I'd be happy to review and merge a contribution on this!
@FirefoxMetzger Thanks for your reply. I now understand the design. SDF relies heavily on nesting tags. I will take a look at the pyi
generation and try to add the annotations.
Hi!
Thanks a lot for providing python-sdformat, I think it will help me a lot!
My problem with it is that a collision geometry has all parameter set (empty, box, mesh, polyline, sphere, cylinder...). So how do I figure out what is actually used? I for now I convert the data to dict and see if "geometry/mesh", "geometry/box"... are set but that seems like an ugly hack. Is there a better way to check the type?