Help with rigid constraints?

Hello.
I am having a problem figuring out what I am doing wrong when setting a rigid body to a ref_attachment and to attachment child of a rigid body constraint.
Not matter hwo I do it I get and error in the API and also in the coherencytest.
To ilustate the problem I made a very simple file to expose problem.
If somebody with expericence in collada run it thought the coherencytest it will show the error, and maybe they can tell me what is wrong and hwo can I solve it,

<?xml version="1.0"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
    <asset>
        <created>2007-01-01T13:30:00Z</created>
        <modified>2007-01-01T13:30:00Z</modified>
        <unit name="meter"/>
        <up_axis>Y_UP</up_axis>
    </asset>
    <library_images>
        <image id="texture_204e1995" depth="1">
            <init_from>./wood.tga</init_from>
        </image>
    </library_images>
    <library_effects>
        <effect id="materialFx_0">
            <profile_COMMON>
                <technique sid="common">
                    <lambert>
                        <diffuse>
                            <color>0.7 0.7 0.7 1</color>
                        </diffuse>
                    </lambert>
                </technique>
            </profile_COMMON>
        </effect>
        <effect id="materialFx_204e1995">
            <profile_COMMON>
                <newparam sid="texture_204e1995_image">
                    <surface type="2D">
                        <init_from>texture_204e1995</init_from>
                        <format>A8R8G8B8</format>
                    </surface>
                </newparam>
                <newparam sid="texture_204e1995">
                    <sampler2D>
                        <source>texture_204e1995_image</source>
                    </sampler2D>
                </newparam>
                <technique sid="common">
                    <lambert>
                        <diffuse>
                            <texture texture="texture_204e1995" texcoord="CHANNEL1"/>
                        </diffuse>
                    </lambert>
                </technique>
            </profile_COMMON>
        </effect>
    </library_effects>
    <library_materials>
        <material id="material_0">
            <instance_effect url="#materialFx_0"/>
        </material>
        <material id="material_204e1995">
            <instance_effect url="#materialFx_204e1995"/>
        </material>
    </library_materials>
    <library_geometries>
        <geometry id="box_0000">
            <mesh>
                <source id="box_0000_position">
                    <float_array id="box_0000_position-array" count="72">-0.28125 1 0.28125 0.28125 1 0.28125 0.28125 1 -0.28125 -0.28125 1 -0.28125 0.28125 -1 0.28125 0.28125 1 0.28125 -0.28125 1 0.28125 -0.28125 -1 0.28125 0.28125 1 -0.28125 0.28125 1 0.28125 0.28125 -1 0.28125 0.28125 -1 -0.28125 -0.28125 -1 0.28125 -0.28125 1 0.28125 -0.28125 1 -0.28125 -0.28125 -1 -0.28125 0.28125 -1 -0.28125 0.28125 -1 0.28125 -0.28125 -1 0.28125 -0.28125 -1 -0.28125 -0.28125 1 -0.28125 0.28125 1 -0.28125 0.28125 -1 -0.28125 -0.28125 -1 -0.28125</float_array>
                    <technique_common>
                        <accessor count="24" offset="0" source="#box_0000_position-array" stride="3">
                            <param name="x" type="float"/>
                            <param name="y" type="float"/>
                            <param name="z" type="float"/>
                        </accessor>
                    </technique_common>
                </source>
                <source id="box_0000_normal">
                    <float_array id="box_0000_normal-array" count="72">0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1</float_array>
                    <technique_common>
                        <accessor count="24" offset="0" source="#box_0000_normal-array" stride="3">
                            <param name="x" type="float"/>
                            <param name="y" type="float"/>
                            <param name="z" type="float"/>
                        </accessor>
                    </technique_common>
                </source>
                <source id="box_0000_UV">
                    <float_array id="box_0000_UV-array" count="48">0.415837 0.584163 0.584163 0.584163 0.584163 0.415837 0.415837 0.415837 0.584163 0.584163 0.584163 0.584163 0.415837 0.584163 0.415837 0.584163 0.584163 0.415837 0.584163 0.584163 0.584163 0.584163 0.584163 0.415837 0.415837 0.584163 0.415837 0.584163 0.415837 0.415837 0.415837 0.415837 0.584163 0.415837 0.584163 0.584163 0.415837 0.584163 0.415837 0.415837 0.415837 0.415837 0.584163 0.415837 0.584163 0.415837 0.415837 0.415837</float_array>
                    <technique_common>
                        <accessor count="24" offset="0" source="#box_0000_UV-array" stride="2">
                            <param name="s" type="float"/>
                            <param name="t" type="float"/>
                        </accessor>
                    </technique_common>
                </source>
                <vertices id="box_0000-vertices">
                    <input semantic="POSITION" source="#box_0000_position"/>
                </vertices>
                <triangles count="12" material="material_204e1995">
                    <input offset="0" semantic="VERTEX" source="#box_0000-vertices"/>
                    <input offset="0" semantic="NORMAL" source="#box_0000_normal"/>
                    <input offset="0" semantic="TEXCOORD" source="#box_0000_UV" set="0"/>
                    

0 1 2 0 2 3 4 5 6 4 6 7 8 9 10 8 10 11 12 13 14 12 14 15 16 17 18 16 18 19 20 21 22 20 22 23</p>
                </triangles>
            </mesh>
            <extra>
                <technique profile="UNIFIED_VERTEX_FORMAT"/>
            </extra>
        </geometry>
    </library_geometries>
    <library_visual_scenes>
        <visual_scene id="root_node__visual">
            <node id="node_0000">
                <matrix>1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
            </node>
            <node id="node_0001">
                <matrix>1 0 0 0 0 1 0 4 0 0 1 0 0 0 0 1</matrix>
                <instance_geometry url="#box_0000">
                    <bind_material>
                        <technique_common>
                            <instance_material symbol="material_204e1995" target="#material_204e1995"/>
                        </technique_common>
                    </bind_material>
                </instance_geometry>
            </node>
        </visual_scene>
    </library_visual_scenes>
    <library_physics_materials>
        <physics_material id="physicsMaterial_0">
            <technique_common>
                <dynamic_friction>0.4</dynamic_friction>
                <restitution>0.3</restitution>
                <static_friction>0.6</static_friction>
            </technique_common>
        </physics_material>
    </library_physics_materials>
    <library_physics_models>
        <physics_model id="physicsModel">
            <rigid_body sid="rigidBody_0000">
                <technique_common>
                    <dynamic>false</dynamic>
                    <mass>0</mass>
                    <mass_frame>
                        <translate>0 0 0</translate>
                        <rotate>0 0 1 0</rotate>
                    </mass_frame>
                    <inertia>0 0 0</inertia>
                    <instance_physics_material url="#physicsMaterial_0"/>
                    <shape>
                        <plane>
                            <equation>0 1 0 -2</equation>
                        </plane>
                        <translate>0 0 0</translate>
                        <rotate>0 0 1 0</rotate>
                    </shape>
                </technique_common>
                <extra>
                    <technique profile="Newton"/>
                </extra>
            </rigid_body>
            <rigid_body sid="rigidBody_0001">
                <technique_common>
                    <dynamic>true</dynamic>
                    <mass>10</mass>
                    <mass_frame>
                        <translate>0 0 0</translate>
                        <rotate>0 0 1 0</rotate>
                    </mass_frame>
                    <inertia>10 10 10</inertia>
                    <instance_physics_material url="#physicsMaterial_0"/>
                    <shape>
                        <sphere>
                            <radius>0.5625</radius>
                        </sphere>
                        <translate>0 0 0</translate>
                        <rotate>0 0 1 0</rotate>
                    </shape>
                </technique_common>
                <extra>
                    <technique profile="Newton"/>
                </extra>
            </rigid_body>
            <rigid_constraint sid="hingeConstraint_0000">
                <ref_attachment rigid_body="rigidBody_0000"/>
                <attachment rigid_body="./rigidBody_0001"/>
                <technique_common/>
            </rigid_constraint>
        </physics_model>
    </library_physics_models>
</COLLADA>

the ploblem happens when I add the ref_attachment, here is my code

domRigid_constraint* AddRigidContstarint (daeDocument* document, domPhysics_model* model, const NewtonJoint* newtonJoint, int enumID)
	{
		const NewtonBody* body0;
		const NewtonBody* body1;
		domRigid_body* rigidBody0;
		domRigid_body* rigidBody1;
		domRigid_constraint* rigidConstraint;
		domRigid_constraint::domAttachment* ref1;
		domRigid_constraint::domRef_attachment* ref0;
		domRigid_constraint::domTechnique_common* techniqueCommon;
		char tmpName[256];

		rigidConstraint = daeSafeCast<domRigid_constraint>(model->createAndPlace(COLLADA_ELEMENT_RIGID_CONSTRAINT));
		sprintf (tmpName, "%s%04d", D_PHYSICS_RIGIDCONSTRAINT_NAME, enumID);
		rigidConstraint->setSid(tmpName);

		rigidBody0 = NULL;
		ref0 = daeSafeCast<domRigid_constraint::domRef_attachment>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_REF_ATTACHMENT));
		body0 = NewtonJointGetBody0 (newtonJoint);
		if (body0) {
			rigidBody0 = m_rigidBodyMap.Find(body0)->GetInfo();
//			sprintf (tmpName, "./%s", rigidBody0->getSid());
//			xsAnyURI uri (rigidBody0->getSid());
//			daeURI uri(rigidBody0->getSid());
//			uri.setElement (rigidBody0);			
//			uri.resolveElement(rigidBody0->getSid());
			// this funtion is failing here 
//			uri.resolveURI();

			daeURI uri(rigidBody0->getSid());
			uri.setElement (rigidBody1);

			// this funtion set the url to invalid
			uri.resolveURI();
			ref1->setRigid_body(uri);


			ref0->setRigid_body(uri);
		} else {
//			sprintf (tmpName, "./%s_visual", D_ROOT_NODE_NAME);
//			daeURI uri (tmpName);
//			ref0->setRigid_body(uri);
		}
		
		rigidBody1 = NULL;
		ref1 = daeSafeCast<domRigid_constraint::domAttachment>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_ATTACHMENT));
		body1 = NewtonJointGetBody1 (newtonJoint);
		if (body1) {
			rigidBody1 = m_rigidBodyMap.Find(body1)->GetInfo();
			sprintf (tmpName, "./%s", rigidBody1->getSid());
			daeURI uri (tmpName);

			uri.setElement (rigidBody1);
			uri.resolveURI();
			ref1->setRigid_body(uri);
		} else {
//			sprintf (tmpName, "./%s_visual", D_ROOT_NODE_NAME);
//			daeURI uri (tmpName);
//			ref1->setRigid_body(uri);
		}

		// add rigid constraint info
		techniqueCommon = daeSafeCast<domRigid_constraint::domTechnique_common>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
		_ASSERTE (techniqueCommon);



		return rigidConstraint;
	}

the funtion check to see if teh element had and ID and if not then sets invalid and returning, I when is debug mode and I saw that rigid bodies are element that do not have ID, so I can not figure out how to make the valid, here is the part where the function resolveURI bails out.

daeURI::resolveURI()
{
	// !!!GAC bug 486, there used to be code here that just returned if state was uri_empty or uri_resolve_local this has been removed.
	if (element != NULL)
	{
		// !!!GAC bug 388 and 421, need to add a fragment (#) before the ID (was setURI(element->getID()))
		if(element->getID() == NULL || element->getID()[0] == 0)
		{
			// We can't resolve to an element that has no ID, so if the ID is blank, fail and return
			state = uri_failed_invalid_reference;
			return;
		}

It looks like the same happen with coherencytest since it also report similar error.
I had made many different kind of file and they are all pass the coherance test, but I can not figure out hwo to make the constraint.
There is not sample code showing how to do it either.
According to documentation section 5-36, I believe I am doing right but it does not work.
I also tried setting the fragment

            <rigid_constraint sid="hingeConstraint_0000">
                <ref_attachment rigid_body="rigidBody_0000"/>
                <attachment rigid_body="./rigidBody_0001"/>
                <technique_common/>
            </rigid_constraint>

To by hand

            <rigid_constraint sid="hingeConstraint_0000">
                <ref_attachment rigid_body="#rigidBody_0000"/>
                <attachment rigid_body="#rigidBody_0001"/>
                <technique_common/>
            </rigid_constraint>

and many other permunation, but the coheraance test keep giving me this error

C:\collada>coherencytest.exe -i xxx1.dae
CHECK_uri Failed uri=file:///C:/collada/rigidBody_0000 not resolved

The problem is not your code or the DOM API. There is a bug in the schema that we found a month or two ago. The ref_attachment and attachment attributes are the wrong type. The schema says they are xs:anyURI so the DOM creates a domURI to try and resolve it. URI’s resolve based on id attributes. The rigid_body attribute is supposed to resolve based on sid. It should be type xs:NCName.

This should be fixed in the next COLLADA patch release.

Until then you can work around it. When you get the rigid_body attribute instead of using it as a URI just treat it as the text. On export you can create the URI with the string, ie daeURI uri( body1->getSid() ); And not with the setEelment() resolveURI() approach (which I am glad other people are using because it is nice and helpful). Then don’t bother trying to resolve it because it will fail.

On import you can get the value by uri->getOriginalURI(). That will return the original string that appeared in the document before the daeURI tried to normalize the uri. Then you have to do your own SID lookup either with the daeSIDResolver or just iterating over the rigid bodies looking for the one you need.

The Coherency checker will always give this error. Its because the URI is not resolvable but its not an error. We might have updated the coherency in the office to not check that (its done or scheduled to be done sometime after GDC) and then it will be in a public update.

-Andy

Thank you for answering the question, that will do.
I have another one that I am posting here, not to make to much noise.
I noticed that the definition of constraint and rigid bodies in Collada 1.4.1 in not too general.
And that forces different API to customized teh format for one reason or another.
As much as I hate polluding the format with vendor specific extensions, I see not more choice than to add my own.
I will paste a fragment of the definition of a rigid body so it is more clear what I want to do

            
<rigid_body sid="rigidBody_0001">
    <technique_common>
         <dynamic>true</dynamic>
         <mass>5</mass>
         <mass_frame>
              <translate>0 0 0</translate>
               <rotate>0 0 1 0</rotate>
         </mass_frame>
         <inertia>30.4167 28.3333 5.41667</inertia>
         <instance_physics_material url="#physicsMaterial_1"/>
             <shape>
                  <box>
                     <half_extents>1 1.5 4</half_extents>
                  </box>
                  <translate>0 0 0</translate>
                  <rotate>1 0 0 0</rotate>
          </shape>
    </technique_common>
    <extra>
            <technique profile="Newton"/>
    </extra>
</rigid_body> 

in the extra element I want to add these options

<extra>
   <technique profile="Newton">
        <InternalLinearDrag 0 </InternalLinearDrag>
        <InternalAngularDrag 0 0 0 </InternalAngularDrag>
        <InternalGyroscopyForces true</InternalGyroscopyForces>
        <ExternalBindingForceFunction ApplyGravity</ExternalBindingForceFunction>
         ....
         ....
   </technique profile>
</extra>

the problem is that I can not figure out how to create element like that, I see that it is possible and I can do it by adding the Floats array but it is not elegant and the output does not looks too good.
If you can post a code fragment that could help out on that I think I will be on my way and not bother anymore.

First you would create the <extra> and the <technique> just like you would when creating any other COLLADA document. Then for the children of <technique> you can just call createAndPlace passing in the name of the element you want created. The function will return to you a domAny object to represent that element.

domAny is a weakly typed element, so that means that it can only hold string data. You will need to convert your float array into a string yourself. Heres some example code (assuming you have already created the <technique> element.

 domTechnique *teq; //The technique element you already have created
domAny *ild = (domAny*)(daeElement*)teq->createAndPlace( "InternalLinearDrag" );
ild->setValue( "0" );

You can also give the elements attributes using setAttribute. setAttribute will automatically create the attribute if it doesn’t already exist.

The only real “gotcha” here is that daeSafeCast does not work for domAny elements. You need to do the cast to domAny yourself.

I hope that helps you.
-Andy

I am having a small suggestion for whatever is worth.
It seems that constraints in Collada are on limited side in many levels.

If I may suggest that for next patch the maintainers consider the possibility to allow for at least one o the two reference bodies of a joint to be optional. This will allow for the possibility to save unilateral joints that can serve as controllers in a standard mode.

As it is now the only way to do that is to add a sentinel bodies to serve a the NULL ankle but this causes problems when the same file is load and save many times, since the sentinel is an actual body in the scene it keeps getting duplicated.

Of course there are ways to deal with that with extras but I believe that the format should provide for this posibility without having to do any work around.

Thanks.

Seems a good suggestion.
Could you open a bug/rfe on the specification.

Thanks