<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ode.org/wiki/index.php?action=history&amp;feed=atom&amp;title=Composite_Objects</id>
	<title>Composite Objects - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://ode.org/wiki/index.php?action=history&amp;feed=atom&amp;title=Composite_Objects"/>
	<link rel="alternate" type="text/html" href="https://ode.org/wiki/index.php?title=Composite_Objects&amp;action=history"/>
	<updated>2026-04-08T19:18:32Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://ode.org/wiki/index.php?title=Composite_Objects&amp;diff=106&amp;oldid=prev</id>
		<title>imported&gt;Russ: Created page with &quot;&#039;&#039;This article is known to contain outdated information. If you know of correct information, please edit this article! Thank you.&#039;&#039;  &#039;&#039;&#039;Copy-dump from old wiki! Is it still up...&quot;</title>
		<link rel="alternate" type="text/html" href="https://ode.org/wiki/index.php?title=Composite_Objects&amp;diff=106&amp;oldid=prev"/>
		<updated>2019-01-07T04:47:26Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;#039;&amp;#039;This article is known to contain outdated information. If you know of correct information, please edit this article! Thank you.&amp;#039;&amp;#039;  &amp;#039;&amp;#039;&amp;#039;Copy-dump from old wiki! Is it still up...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;#039;&amp;#039;This article is known to contain outdated information. If you know of correct information, please edit this article! Thank you.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Copy-dump from old wiki! Is it still up-to-date (notably the GeomTransform parts) ?&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
ODE allows you to have composite objects. These are more complex objects build from several others. For instance a table could be built by combining four leg boxes with a table-top box.&lt;br /&gt;
&lt;br /&gt;
The ODE documentation tells you which functions to call, and there&amp;#039;s a &amp;quot;box stack&amp;quot; demo which includes composite objects. It can be a little tricky to get to grips with, so here&amp;#039;s a page on the subject.&lt;br /&gt;
&lt;br /&gt;
= Theory =&lt;br /&gt;
&lt;br /&gt;
A body can contain multiple geoms. However to build a useful composite object you&amp;#039;re likely going to need to separate the geoms in space. To do this you need to wrap the collision geoms in &amp;quot;GeomTransforms&amp;quot;. A GeomTransform is a geom which has no collision, it just wraps another geom and allows it to be translated/rotated. So the hierarchy for a simple table would look like this:&lt;br /&gt;
&lt;br /&gt;
 dBody             // Table composite object&lt;br /&gt;
    dGeomTransform // Transform for offsetting table-top&lt;br /&gt;
        dGeomBox   // Table-top collision geom&lt;br /&gt;
    dGeomTransform // Transform for offsetting leg&lt;br /&gt;
        dGeomBox   // Leg 1 collision geom&lt;br /&gt;
    dGeomTransform // Transform for offsetting leg&lt;br /&gt;
        dGeomBox   // Leg 2 collision geom&lt;br /&gt;
    dGeomTransform // Transform for offsetting leg&lt;br /&gt;
        dGeomBox   // Leg 3 collision geom&lt;br /&gt;
    dGeomTransform // Transform for offsetting leg&lt;br /&gt;
        dGeomBox   // Leg 4 collision geom&lt;br /&gt;
&lt;br /&gt;
= Building a Composite Object =&lt;br /&gt;
&lt;br /&gt;
The following code has been copied from the &amp;quot;box stack&amp;quot; sample, cleaned, and commented. The code has also been simplified in that it only uses boxes for the sub objects.&lt;br /&gt;
&lt;br /&gt;
 const int NUM_BOXES = 3;&lt;br /&gt;
 &lt;br /&gt;
 dGeomID odeGeomTransformList[NUM_BOXES]; /* Geometry transforms which contain single sub objects */&lt;br /&gt;
 dGeomID tempOdeBoxGeomList[NUM_BOXES]; /* Temp array for holding onto the boxes in the transforms. &lt;br /&gt;
                                         * This doesn&amp;#039;t need to be kept, as dGeomTransformSetCleanup&lt;br /&gt;
                                         * will take care of it. */&lt;br /&gt;
 dReal boxOffset[NUM_BOXES][3]; /* delta-positions for encapsulated geometries */&lt;br /&gt;
 &lt;br /&gt;
 /* Start accumulating masses for the encapsulated geometries */&lt;br /&gt;
 dMass compositeMass, componentMass;&lt;br /&gt;
 dMassSetZero (&amp;amp;compositeMass);&lt;br /&gt;
 &lt;br /&gt;
 /* Pick random positions geoms will be placed at */&lt;br /&gt;
 for (j=0; j&amp;lt;NUM_BOXES; j++)&lt;br /&gt;
 {&lt;br /&gt;
     /* Loop through XYZ */&lt;br /&gt;
     for (k=0; k&amp;lt;3; k++) &lt;br /&gt;
     {&lt;br /&gt;
         boxOffset[j][k] = dRandReal()*0.3-0.15;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 for (k=0; k&amp;lt;NUM_BOXES; k++)&lt;br /&gt;
 {&lt;br /&gt;
     odeGeomTransformList[k] = dCreateGeomTransform (space); /* Create geom transform that sub &lt;br /&gt;
                                                              * objects are added to */&lt;br /&gt;
     dGeomTransformSetCleanup (odeGeomTransformList[k],1);/* If &amp;#039;1&amp;#039; deleting odeGeomTransformList[k]&lt;br /&gt;
                                                           * will delete the geom added to it */&lt;br /&gt;
 &lt;br /&gt;
     tempOdeBoxGeomList[k] = dCreateBox (0, sides[0], /* Create box sub-object */&lt;br /&gt;
                                         sides[1],&lt;br /&gt;
                                         sides[2]); &lt;br /&gt;
     dMassSetBox (&amp;amp;componentMass, /* Create normal mass for a box */&lt;br /&gt;
                  DENSITY, &lt;br /&gt;
                  sides[0], &lt;br /&gt;
                  sides[1], &lt;br /&gt;
                  sides[2]); &lt;br /&gt;
 &lt;br /&gt;
     dGeomTransformSetGeom (odeGeomTransformList[k], /* Attach box to the geom transform */ &lt;br /&gt;
                            tempOdeBoxGeomList[k]); &lt;br /&gt;
 &lt;br /&gt;
     /* Move and rotate the box within the compound object, including the mass */&lt;br /&gt;
     dGeomSetPosition (tempOdeBoxGeomList[k], &lt;br /&gt;
                       boxOffset[k][0], &lt;br /&gt;
                       boxOffset[k][1], &lt;br /&gt;
                       boxOffset[k][2]);&lt;br /&gt;
     dMassTranslate (&amp;amp;componentMass, &lt;br /&gt;
                     boxOffset[k][0], &lt;br /&gt;
                     boxOffset[k][1], &lt;br /&gt;
                     boxOffset[k][2]);&lt;br /&gt;
     dMatrix3 rotation;&lt;br /&gt;
     dRFromAxisAndAngle (rotation, &lt;br /&gt;
                         dRandReal()*2.0-1.0, &lt;br /&gt;
                         dRandReal()*2.0-1.0,&lt;br /&gt;
                         dRandReal()*2.0-1.0, &lt;br /&gt;
                         dRandReal()*10.0-5.0);&lt;br /&gt;
     dGeomSetRotation (tempOdeBoxGeomList[k], rotation);&lt;br /&gt;
     dMassRotate (&amp;amp;componentMass, rotation);&lt;br /&gt;
 &lt;br /&gt;
     /* Add sub object mass to the total mass */&lt;br /&gt;
     dMassAdd (&amp;amp;compositeMass,&amp;amp;componentMass);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // We&amp;#039;ve finished adding object. The center of mass is not going to be centered at the moment.&lt;br /&gt;
 // Move all encapsulated objects so that the center of mass is (0,0,0)&lt;br /&gt;
 for (k=0; k&amp;lt;NUM_BOXES; k++) &lt;br /&gt;
 {&lt;br /&gt;
     dGeomSetPosition (tempOdeBoxGeomList[k],&lt;br /&gt;
                       boxOffset[k][0]-compositeMass.c[0],&lt;br /&gt;
                       boxOffset[k][1]-compositeMass.c[1],&lt;br /&gt;
                       boxOffset[k][2]-compositeMass.c[2]);&lt;br /&gt;
 }&lt;br /&gt;
 dMassTranslate (&amp;amp;compositeMass,&lt;br /&gt;
                 -compositeMass.c[0],&lt;br /&gt;
                 -compositeMass.c[1],&lt;br /&gt;
                 -compositeMass.c[2]);&lt;br /&gt;
 &lt;br /&gt;
 /* Tell all the geom transforms that they belong to the parent body */&lt;br /&gt;
 for (k=0; k &amp;lt; NUM_BOXES; k++) &lt;br /&gt;
 {&lt;br /&gt;
     if (odeGeomTransformList?[k])&lt;br /&gt;
         dGeomSetBody (odeGeomTransformList[k], parentBody );&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /* Set the parent body mass to be the one we&amp;#039;ve calculated. */&lt;br /&gt;
 dBodySetMass (parentBody, &amp;amp;compositeMass );&lt;br /&gt;
&lt;br /&gt;
= Getting the position of a composite object component =&lt;br /&gt;
&lt;br /&gt;
If you get the position of a composite object component, ODE will return the relative/local position within the body. The code that follows is for converting this to a real world position. Again the code originates from the &amp;#039;box stack&amp;#039; sample. Apologies that it&amp;#039;s not in straight C calls, but it&amp;#039;s quick to change to whatever you&amp;#039;re using.&lt;br /&gt;
&lt;br /&gt;
 // Get the geomID of the component from the geom transform&lt;br /&gt;
 dGeomID geomID = dGeomTransformGetGeom( geomTransformID? );&lt;br /&gt;
 &lt;br /&gt;
 // Get world position/orientation of parent body&lt;br /&gt;
 const Real* pBodyPos = parentBody-&amp;gt;getPosition();&lt;br /&gt;
 const Real* pBodyRotMat = parentBody-&amp;gt;getRotation();&lt;br /&gt;
 &lt;br /&gt;
 // Get local position/orientation of component within geom transform&lt;br /&gt;
 const Real* pLocalPos = dGeomGetPosition (geomID);&lt;br /&gt;
 const Real* pLocalRotMat = dGeomGetRotation (geomID);&lt;br /&gt;
 &lt;br /&gt;
 // Calculate world space position of component by using the body position/orientation&lt;br /&gt;
 dVector3 worldPos;&lt;br /&gt;
 dMatrix3 worldRotMat;&lt;br /&gt;
 dMULTIPLY0_331( worldPos, pBodyRotMat, pLocalPos );&lt;br /&gt;
 worldPos[0] += pBodyPos[0];&lt;br /&gt;
 worldPos[1] += pBodyPos[1];&lt;br /&gt;
 worldPos[2] += pBodyPos[2];&lt;br /&gt;
 dMULTIPLY0_333( worldRotMat, pBodyRotMat, pLocalRotMat );&lt;br /&gt;
 &lt;br /&gt;
 // And if you want a quaternion instead of a matrix...&lt;br /&gt;
 dQuaternion worldQuat;&lt;br /&gt;
 dQfromR(worldQuat, worldRotMat);&lt;/div&gt;</summary>
		<author><name>imported&gt;Russ</name></author>
	</entry>
</feed>