/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2010, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redstributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Willow Garage nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ #include "collada_urdf/ColladaWriter.h" #include "collada_urdf/STLLoader.h" #include #include #include #define foreach BOOST_FOREACH using std::string; using std::map; using std::vector; using boost::shared_ptr; namespace collada_urdf { ColladaWriter::ColladaWriter(std::string const& filename) : source_(filename), dae_(NULL), dom_(NULL) { TiXmlDocument xml; if (!xml.LoadFile(filename.c_str())) throw ColladaWriterException("Error reading XML file"); TiXmlElement* robot_xml = xml.FirstChildElement("robot"); if (!robot_xml) throw ColladaWriterException("Error parsing URDF model from XML (robot element not found)"); robot_ = shared_ptr(new urdf::Model); if (!robot_->initXml(robot_xml)) throw ColladaWriterException("Error parsing URDF model from XML"); } ColladaWriter::ColladaWriter(shared_ptr robot, string const& source) : robot_(robot), source_(source), dae_(NULL), dom_(NULL) { } bool ColladaWriter::writeDocument(string const& documentName) { initDocument(documentName); SCENE scene = createScene(); setupPhysics(scene); addGeometries(); addKinematics(scene); addVisuals(scene); addMaterials(); addBindings(scene); collada_->writeAll(); return true; } ColladaWriter::~ColladaWriter() { collada_.reset(); DAE::cleanup(); } // Implementation void ColladaWriter::handleError(daeString msg) { std::cerr << "COLLADA error: " << msg << std::endl; } void ColladaWriter::handleWarning(daeString msg) { std::cerr << "COLLADA warning: " << msg << std::endl; } void ColladaWriter::initDocument(string const& documentName) { daeErrorHandler::setErrorHandler(this); dae_ = new DAE(); collada_.reset(dae_); collada_->setIOPlugin(NULL); collada_->setDatabase(NULL); daeDocument* doc = NULL; daeInt error = collada_->getDatabase()->insertDocument(documentName.c_str(), &doc); // also creates a collada root if (error != DAE_OK || doc == NULL) throw ColladaWriterException("Failed to create document"); dom_ = daeSafeCast(doc->getDomRoot()); dom_->setAttribute("xmlns:math", "http://www.w3.org/1998/Math/MathML"); // Create the required asset tag domAssetRef asset = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_ASSET)); { string date = getTimeStampString(); domAsset::domCreatedRef created = daeSafeCast(asset->createAndPlace(COLLADA_ELEMENT_CREATED)); created->setValue(date.c_str()); domAsset::domModifiedRef modified = daeSafeCast(asset->createAndPlace(COLLADA_ELEMENT_MODIFIED)); modified->setValue(date.c_str()); domAsset::domContributorRef contrib = daeSafeCast(asset->createAndPlace(COLLADA_TYPE_CONTRIBUTOR)); domAsset::domContributor::domAuthoring_toolRef authoringtool = daeSafeCast(contrib->createAndPlace(COLLADA_ELEMENT_AUTHORING_TOOL)); authoringtool->setValue("URDF Collada Writer"); domAsset::domContributor::domSource_dataRef sourcedata = daeSafeCast(contrib->createAndPlace(COLLADA_ELEMENT_SOURCE_DATA)); sourcedata->setValue(source_.c_str()); domAsset::domUnitRef units = daeSafeCast(asset->createAndPlace(COLLADA_ELEMENT_UNIT)); units->setMeter(1); units->setName("meter"); domAsset::domUp_axisRef zup = daeSafeCast(asset->createAndPlace(COLLADA_ELEMENT_UP_AXIS)); zup->setValue(UP_AXIS_Z_UP); } scene_ = dom_->getScene(); if (!scene_) scene_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_SCENE)); visualScenesLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_VISUAL_SCENES)); visualScenesLib_->setId("vscenes"); geometriesLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_GEOMETRIES)); geometriesLib_->setId("geometries"); kinematicsScenesLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_KINEMATICS_SCENES)); kinematicsScenesLib_->setId("kscenes"); kinematicsModelsLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_KINEMATICS_MODELS)); kinematicsModelsLib_->setId("kmodels"); jointsLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_JOINTS)); jointsLib_->setId("joints"); physicsScenesLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_PHYSICS_SCENES)); physicsScenesLib_->setId("physics_scenes"); effectsLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_EFFECTS)); effectsLib_->setId("effects"); materialsLib_ = daeSafeCast(dom_->createAndPlace(COLLADA_ELEMENT_LIBRARY_MATERIALS)); materialsLib_->setId("materials"); } ColladaWriter::SCENE ColladaWriter::createScene() { SCENE s; // Create visual scene s.vscene = daeSafeCast(visualScenesLib_->createAndPlace(COLLADA_ELEMENT_VISUAL_SCENE)); s.vscene->setId("vscene"); s.vscene->setName("URDF Visual Scene"); // Create instance visual scene s.viscene = daeSafeCast(scene_->createAndPlace(COLLADA_ELEMENT_INSTANCE_VISUAL_SCENE)); s.viscene->setUrl((string("#") + string(s.vscene->getID())).c_str()); // Create kinematics scene s.kscene = daeSafeCast(kinematicsScenesLib_->createAndPlace(COLLADA_ELEMENT_KINEMATICS_SCENE)); s.kscene->setId("kscene"); s.kscene->setName("URDF Kinematics Scene"); // Create instance kinematics scene s.kiscene = daeSafeCast(scene_->createAndPlace(COLLADA_ELEMENT_INSTANCE_KINEMATICS_SCENE)); s.kiscene->setUrl((string("#") + string(s.kscene->getID())).c_str()); // Create physics scene s.pscene = daeSafeCast(physicsScenesLib_->createAndPlace(COLLADA_ELEMENT_PHYSICS_SCENE)); s.pscene->setId("pscene"); s.pscene->setName("URDF Physics Scene"); // Create instance physics scene s.piscene = daeSafeCast(scene_->createAndPlace(COLLADA_ELEMENT_INSTANCE_PHYSICS_SCENE)); s.piscene->setUrl((string("#") + string(s.pscene->getID())).c_str()); return s; } void ColladaWriter::setupPhysics(SCENE const& scene) { // domPhysics_scene::domTechnique_commonRef common = daeSafeCast(scene.pscene->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON)); { // 0 0 0 domTargetable_float3Ref g = daeSafeCast(common->createAndPlace(COLLADA_ELEMENT_GRAVITY)); g->getValue().set3(0.0, 0.0, 0.0); // } // } void ColladaWriter::addGeometries() { int link_num = 0; for (map >::const_iterator i = robot_->links_.begin(); i != robot_->links_.end(); i++) { shared_ptr urdf_link = i->second; if (urdf_link->visual == NULL || urdf_link->visual->geometry == NULL) continue; switch (urdf_link->visual->geometry->type) { case urdf::Geometry::MESH: { urdf::Mesh* urdf_mesh = (urdf::Mesh*) urdf_link->visual->geometry.get(); string filename = urdf_mesh->filename; urdf::Vector3 scale = urdf_mesh->scale; // @todo use scale // domGeometryRef geometry = daeSafeCast(geometriesLib_->createAndPlace(COLLADA_ELEMENT_GEOMETRY)); string geometry_id = string("g1.link") + boost::lexical_cast(link_num) + string(".geom0"); geometry->setId(geometry_id.c_str()); { loadMesh(filename, geometry, geometry_id); } geometry_ids_[urdf_link->name] = geometry_id; // link_num++; break; } case urdf::Geometry::SPHERE: { std::cerr << "Warning: geometry type SPHERE of link " << urdf_link->name << " not exported" << std::endl; break; } case urdf::Geometry::BOX: { std::cerr << "Warning: geometry type BOX of link " << urdf_link->name << " not exported" << std::endl; break; } case urdf::Geometry::CYLINDER: { std::cerr << "Warning: geometry type CYLINDER of link " << urdf_link->name << " not exported" << std::endl; break; } default: { std::cerr << "Warning: geometry type " << urdf_link->visual->geometry->type << " of link " << urdf_link->name << " not exported" << std::endl; break; } } } } void ColladaWriter::loadMesh(string const& filename, domGeometryRef geometry, string const& geometry_id) { // Load the mesh resource_retriever::MemoryResource resource; resource_retriever::Retriever retriever; try { resource = retriever.get(filename.c_str()); } catch (resource_retriever::Exception& e) { std::cerr << "Unable to load mesh file " << filename << ": " << e.what() << std::endl; return; } // Try assimp first, then STLLoader if (!loadMeshWithSTLLoader(resource, geometry, geometry_id)) std::cerr << "Can't load mesh " << filename << std::endl; } bool ColladaWriter::loadMeshWithSTLLoader(resource_retriever::MemoryResource const& resource, domGeometryRef geometry, string const& geometry_id) { // Write the resource to a temporary file char tmp_filename[] = "/tmp/collada_urdf_XXXXXX"; int fd = mkstemp(tmp_filename); write(fd, resource.data.get(), resource.size); close(fd); // Import the mesh using STLLoader STLLoader loader; shared_ptr stl_mesh = loader.load(string(tmp_filename)); buildMeshFromSTLLoader(stl_mesh, geometry, geometry_id); // Delete the temporary file unlink(tmp_filename); return true; } void ColladaWriter::buildMeshFromSTLLoader(shared_ptr stl_mesh, daeElementRef parent, string const& geometry_id) { // domMeshRef mesh = daeSafeCast(parent->createAndPlace(COLLADA_ELEMENT_MESH)); { unsigned int num_vertices = stl_mesh->vertices.size(); unsigned int num_indices = stl_mesh->indices.size(); unsigned int num_faces = num_indices / 3; // domSourceRef positions_source = daeSafeCast(mesh->createAndPlace(COLLADA_ELEMENT_SOURCE)); positions_source->setId((geometry_id + string(".positions")).c_str()); { // domFloat_arrayRef positions_array = daeSafeCast(positions_source->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY)); positions_array->setId((geometry_id + string(".positions-array")).c_str()); positions_array->setCount(num_vertices * 3); positions_array->setDigits(6); // 6 decimal places positions_array->getValue().setCount(num_vertices * 3); for (unsigned int j = 0; j < num_vertices; j++) { positions_array->getValue()[j * 3 ] = stl_mesh->vertices[j].x; positions_array->getValue()[j * 3 + 1] = stl_mesh->vertices[j].y; positions_array->getValue()[j * 3 + 2] = stl_mesh->vertices[j].z; } // // domSource::domTechnique_commonRef source_tech = daeSafeCast(positions_source->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON)); { // domAccessorRef accessor = daeSafeCast(source_tech->createAndPlace(COLLADA_ELEMENT_ACCESSOR)); accessor->setCount(num_vertices / 3); accessor->setSource(xsAnyURI(*positions_array, string("#") + geometry_id + string(".positions-array"))); accessor->setStride(3); { // // // domParamRef px = daeSafeCast(accessor->createAndPlace(COLLADA_ELEMENT_PARAM)); px->setName("X"); px->setType("float"); domParamRef py = daeSafeCast(accessor->createAndPlace(COLLADA_ELEMENT_PARAM)); py->setName("Y"); py->setType("float"); domParamRef pz = daeSafeCast(accessor->createAndPlace(COLLADA_ELEMENT_PARAM)); pz->setName("Z"); pz->setType("float"); } // } // } // domVerticesRef vertices = daeSafeCast(mesh->createAndPlace(COLLADA_ELEMENT_VERTICES)); string vertices_id = geometry_id + string(".vertices"); vertices->setId(vertices_id.c_str()); { // domInput_localRef vertices_input = daeSafeCast(vertices->createAndPlace(COLLADA_ELEMENT_INPUT)); vertices_input->setSemantic("POSITION"); vertices_input->setSource(domUrifragment(*positions_source, string("#") + string(positions_source->getId()))); } // // domTrianglesRef triangles = daeSafeCast(mesh->createAndPlace(COLLADA_ELEMENT_TRIANGLES)); triangles->setCount(num_faces); triangles->setMaterial("mat0"); { // domInput_local_offsetRef vertex_offset = daeSafeCast(triangles->createAndPlace(COLLADA_ELEMENT_INPUT)); vertex_offset->setSemantic("VERTEX"); vertex_offset->setOffset(0); vertex_offset->setSource(domUrifragment(*positions_source, string("#") + vertices_id)); { //

0 1 2 3 ... domPRef indices = daeSafeCast(triangles->createAndPlace(COLLADA_ELEMENT_P)); indices->getValue().setCount(num_indices); for (unsigned int i = 0; i < num_indices; i++) indices->getValue()[i] = stl_mesh->indices[i]; //

} } //
} //
} void ColladaWriter::addJoints(daeElementRef parent) { int joint_num = 0; for (map >::const_iterator i = robot_->joints_.begin(); i != robot_->joints_.end(); i++) { shared_ptr urdf_joint = i->second; // domJointRef joint = daeSafeCast(parent->createAndPlace(COLLADA_ELEMENT_JOINT)); string joint_sid = string("joint") + boost::lexical_cast(joint_num); joint_num++; joint->setName(urdf_joint->name.c_str()); joint->setSid(joint_sid.c_str()); joint_sids_[urdf_joint->name] = joint_sid; double axis_x = urdf_joint->axis.x; double axis_y = urdf_joint->axis.y; double axis_z = urdf_joint->axis.z; if (axis_x == 0.0 && axis_y == 0.0 && axis_z == 0.0) { axis_x = 1.0; axis_y = 0.0; axis_z = 0.0; } // @hack: OpenRAVE appears to flip joint axes axis_x *= -1.0; axis_y *= -1.0; axis_z *= -1.0; switch (urdf_joint->type) { case urdf::Joint::REVOLUTE: { // domAxis_constraintRef revolute = daeSafeCast(joint->createAndPlace(COLLADA_ELEMENT_REVOLUTE)); revolute->setSid("axis0"); { // domAxisRef axis = daeSafeCast(revolute->createAndPlace(COLLADA_ELEMENT_AXIS)); { axis->getValue().setCount(3); axis->getValue()[0] = axis_x; axis->getValue()[1] = axis_y; axis->getValue()[2] = axis_z; } // // domJoint_limitsRef limits = daeSafeCast(revolute->createAndPlace(COLLADA_TYPE_LIMITS)); { daeSafeCast(limits->createAndPlace(COLLADA_ELEMENT_MIN))->getValue() = angles::to_degrees(urdf_joint->limits->lower); daeSafeCast(limits->createAndPlace(COLLADA_ELEMENT_MAX))->getValue() = angles::to_degrees(urdf_joint->limits->upper); } // } // break; } case urdf::Joint::CONTINUOUS: { // Model as a REVOLUTE joint without limits // domAxis_constraintRef revolute = daeSafeCast(joint->createAndPlace(COLLADA_ELEMENT_REVOLUTE)); revolute->setSid("axis0"); { // domAxisRef axis = daeSafeCast(revolute->createAndPlace(COLLADA_ELEMENT_AXIS)); { axis->getValue().setCount(3); axis->getValue()[0] = axis_x; axis->getValue()[1] = axis_y; axis->getValue()[2] = axis_z; } // } // break; } case urdf::Joint::PRISMATIC: { // domAxis_constraintRef prismatic = daeSafeCast(joint->createAndPlace(COLLADA_ELEMENT_PRISMATIC)); prismatic->setSid("axis0"); { // domAxisRef axis = daeSafeCast(prismatic->createAndPlace(COLLADA_ELEMENT_AXIS)); { axis->getValue().setCount(3); axis->getValue()[0] = axis_x; axis->getValue()[1] = axis_y; axis->getValue()[2] = axis_z; } // // domJoint_limitsRef limits = daeSafeCast(prismatic->createAndPlace(COLLADA_TYPE_LIMITS)); { daeSafeCast(limits->createAndPlace(COLLADA_ELEMENT_MIN))->getValue() = urdf_joint->limits->lower; daeSafeCast(limits->createAndPlace(COLLADA_ELEMENT_MAX))->getValue() = urdf_joint->limits->upper; } // } // break; } case urdf::Joint::FIXED: { // Model as a REVOLUTE joint with no leeway domAxis_constraintRef revolute = daeSafeCast(joint->createAndPlace(COLLADA_ELEMENT_REVOLUTE)); revolute->setSid("axis0"); { // domAxisRef axis = daeSafeCast(revolute->createAndPlace(COLLADA_ELEMENT_AXIS)); { axis->getValue().setCount(3); axis->getValue()[0] = axis_x; axis->getValue()[1] = axis_y; axis->getValue()[2] = axis_z; } // // domJoint_limitsRef limits = daeSafeCast(revolute->createAndPlace(COLLADA_TYPE_LIMITS)); { daeSafeCast(limits->createAndPlace(COLLADA_ELEMENT_MIN))->getValue() = 0.0; daeSafeCast(limits->createAndPlace(COLLADA_ELEMENT_MAX))->getValue() = 0.0; } // } // break; } case urdf::Joint::UNKNOWN: { std::cerr << "Joint type UNKNOWN of joint " << urdf_joint->name << " is unsupported" << std::endl; break; } case urdf::Joint::FLOATING: { std::cerr << "Joint type FLOATING of joint " << urdf_joint->name << " is unsupported" << std::endl; break; } case urdf::Joint::PLANAR: { std::cerr << "Joint type PLANAR of joint " << urdf_joint->name << " is unsupported" << std::endl; break; } default: { std::cerr << "Joint type " << urdf_joint->type << " of joint " << urdf_joint->name << " is unsupported" << std::endl; break; } } } } void ColladaWriter::addBindings(SCENE const& scene) { string model_id = kmodel_->getID(); string inst_model_sid = string("inst_") + model_id; // // domBind_kinematics_modelRef kmodel_bind = daeSafeCast(scene.kiscene->createAndPlace(COLLADA_ELEMENT_BIND_KINEMATICS_MODEL)); kmodel_bind->setNode("v1.node0"); // @todo daeSafeCast(kmodel_bind->createAndPlace(COLLADA_ELEMENT_PARAM))->setValue(string(string(scene.kscene->getID()) + string(".") + inst_model_sid).c_str()); for (map >::const_iterator i = robot_->joints_.begin(); i != robot_->joints_.end(); i++) { shared_ptr urdf_joint = i->second; int idof = 0; // @todo assuming 1 dof joints string joint_sid = joint_sids_[urdf_joint->name]; string axis_name = string("axis") + boost::lexical_cast(idof); string joint_axis_sid = string("kscene.inst_") + model_id + string(".") + joint_sid + string(".") + axis_name; string joint_axis_value_sid = joint_axis_sid + string("_value"); // domBind_joint_axisRef joint_bind = daeSafeCast(scene.kiscene->createAndPlace(COLLADA_ELEMENT_BIND_JOINT_AXIS)); string node_name = node_ids_[urdf_joint->name]; joint_bind->setTarget((node_name + string("/node_") + joint_sid + string("_") + axis_name).c_str()); { // domCommon_sidref_or_paramRef axis_bind = daeSafeCast(joint_bind->createAndPlace(COLLADA_ELEMENT_AXIS)); { daeSafeCast(axis_bind->createAndPlace(COLLADA_TYPE_PARAM))->setValue(joint_axis_sid.c_str()); } // // domCommon_float_or_paramRef value_bind = daeSafeCast(joint_bind->createAndPlace(COLLADA_ELEMENT_VALUE)); { daeSafeCast(value_bind->createAndPlace(COLLADA_TYPE_PARAM))->setValue(joint_axis_value_sid.c_str()); } } // } } void ColladaWriter::addKinematics(SCENE const& scene) { // domKinematics_modelRef kmodel = daeSafeCast(kinematicsModelsLib_->createAndPlace(COLLADA_ELEMENT_KINEMATICS_MODEL)); kmodel->setId("k1"); kmodel->setName(robot_->getName().c_str()); { // domKinematics_model_techniqueRef technique = daeSafeCast(kmodel->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON)); addJoints(technique); // // int link_num = 0; addKinematicLink(robot_->getRoot(), technique, link_num); // } kmodel_ = kmodel; // string model_id = kmodel->getID(); string inst_model_sid = string("inst_") + model_id; // domInstance_kinematics_modelRef ikm = daeSafeCast(scene.kscene->createAndPlace(COLLADA_ELEMENT_INSTANCE_KINEMATICS_MODEL)); ikm->setUrl((string("#") + model_id).c_str()); ikm->setSid(inst_model_sid.c_str()); { // domKinematics_newparamRef newparam_model = daeSafeCast(ikm->createAndPlace(COLLADA_ELEMENT_NEWPARAM)); string newparam_model_sid = string("kscene.inst_") + model_id; newparam_model->setSid(newparam_model_sid.c_str()); { // kscene/inst_k1 string model_sidref = string("kscene/inst_") + model_id; daeSafeCast(newparam_model->createAndPlace(COLLADA_ELEMENT_SIDREF))->setValue(model_sidref.c_str()); } // for (map >::const_iterator i = robot_->joints_.begin(); i != robot_->joints_.end(); i++) { shared_ptr urdf_joint = i->second; int idof = 0; // @todo assuming 1 dof joints string joint_sid = joint_sids_[urdf_joint->name]; string axis_name = string("axis") + boost::lexical_cast(idof); // domKinematics_newparamRef newparam = daeSafeCast(ikm->createAndPlace(COLLADA_ELEMENT_NEWPARAM)); string newparam_sid = string("kscene.inst_") + model_id + string(".") + joint_sid + string(".") + axis_name; newparam->setSid(newparam_sid.c_str()); { // kscene/inst_k1/joint0/axis0 string sidref = string("kscene/inst_") + model_id + string("/") + joint_sid + string("/") + axis_name; daeSafeCast(newparam->createAndPlace(COLLADA_ELEMENT_SIDREF))->setValue(sidref.c_str()); } // // domKinematics_newparamRef newparam_value = daeSafeCast(ikm->createAndPlace(COLLADA_ELEMENT_NEWPARAM)); string newparam_value_sid = string("kscene.inst_") + model_id + string(".") + joint_sid + string(".") + axis_name + string("_value"); newparam_value->setSid(newparam_value_sid.c_str()); { // 0 daeSafeCast(newparam_value->createAndPlace(COLLADA_ELEMENT_FLOAT))->setValue(0.0f); } // } } // } void ColladaWriter::addKinematicLink(shared_ptr urdf_link, daeElementRef parent, int& link_num) { // domLinkRef link = daeSafeCast(parent->createAndPlace(COLLADA_ELEMENT_LINK)); string link_sid = string("link") + boost::lexical_cast(link_num); link->setName(urdf_link->name.c_str()); link->setSid(link_sid.c_str()); link_num++; foreach(shared_ptr urdf_joint, urdf_link->child_joints) { // domLink::domAttachment_fullRef attachment_full = daeSafeCast(link->createAndPlace(COLLADA_TYPE_ATTACHMENT_FULL)); string attachment_joint = string("k1/") + joint_sids_[urdf_joint->name]; attachment_full->setJoint(attachment_joint.c_str()); { addRotate(attachment_full, urdf_joint->parent_to_joint_origin_transform.rotation); addTranslate(attachment_full, urdf_joint->parent_to_joint_origin_transform.position); addKinematicLink(robot_->getLink(urdf_joint->child_link_name), attachment_full, link_num); } // } // } void ColladaWriter::addVisuals(SCENE const& scene) { // domNodeRef root_node = daeSafeCast(scene.vscene->createAndPlace(COLLADA_ELEMENT_NODE)); root_node->setId("v1"); root_node->setName(robot_->getName().c_str()); { int link_num = 0; addVisualLink(robot_->getRoot(), root_node, link_num); } } void ColladaWriter::addMaterials() { urdf::Color ambient, diffuse; ambient.init("1 1 1 0"); diffuse.init("1 1 1 0"); for (map >::const_iterator i = robot_->links_.begin(); i != robot_->links_.end(); i++) { shared_ptr urdf_link = i->second; map::const_iterator j = geometry_ids_.find(urdf_link->name); if (j == geometry_ids_.end()) continue; string geometry_id = j->second; domEffectRef effect = addEffect(geometry_id, ambient, diffuse); // domMaterialRef material = daeSafeCast(materialsLib_->createAndPlace(COLLADA_ELEMENT_MATERIAL)); string material_id = geometry_id + string(".mat"); material->setId(material_id.c_str()); { // domInstance_effectRef instance_effect = daeSafeCast(material->createAndPlace(COLLADA_ELEMENT_INSTANCE_EFFECT)); string effect_id(effect->getId()); instance_effect->setUrl((string("#") + effect_id).c_str()); } // } } domEffectRef ColladaWriter::addEffect(string const& geometry_id, urdf::Color const& color_ambient, urdf::Color const& color_diffuse) { // domEffectRef effect = daeSafeCast(effectsLib_->createAndPlace(COLLADA_ELEMENT_EFFECT)); string effect_id = geometry_id + string(".eff"); effect->setId(effect_id.c_str()); { // domProfile_commonRef profile = daeSafeCast(effect->createAndPlace(COLLADA_ELEMENT_PROFILE_COMMON)); { // domProfile_common::domTechniqueRef technique = daeSafeCast(profile->createAndPlace(COLLADA_ELEMENT_TECHNIQUE)); { // domProfile_common::domTechnique::domPhongRef phong = daeSafeCast(technique->createAndPlace(COLLADA_ELEMENT_PHONG)); { // domFx_common_color_or_textureRef ambient = daeSafeCast(phong->createAndPlace(COLLADA_ELEMENT_AMBIENT)); { // r g b a domFx_common_color_or_texture::domColorRef ambient_color = daeSafeCast(ambient->createAndPlace(COLLADA_ELEMENT_COLOR)); ambient_color->getValue().setCount(4); ambient_color->getValue()[0] = color_ambient.r; ambient_color->getValue()[1] = color_ambient.g; ambient_color->getValue()[2] = color_ambient.b; ambient_color->getValue()[3] = color_ambient.a; // } // // domFx_common_color_or_textureRef diffuse = daeSafeCast(phong->createAndPlace(COLLADA_ELEMENT_DIFFUSE)); { // r g b a domFx_common_color_or_texture::domColorRef diffuse_color = daeSafeCast(diffuse->createAndPlace(COLLADA_ELEMENT_COLOR)); diffuse_color->getValue().setCount(4); diffuse_color->getValue()[0] = color_diffuse.r; diffuse_color->getValue()[1] = color_diffuse.g; diffuse_color->getValue()[2] = color_diffuse.b; diffuse_color->getValue()[3] = color_diffuse.a; // } // } // } // } // } // return effect; } void ColladaWriter::addVisualLink(shared_ptr urdf_link, daeElementRef parent, int& link_num) { // domNodeRef node = daeSafeCast(parent->createAndPlace(COLLADA_ELEMENT_NODE)); string node_sid = string("node") + boost::lexical_cast(link_num); string node_id = string("v1.") + node_sid; node->setName(urdf_link->name.c_str()); node->setSid(node_sid.c_str()); node->setId(node_id.c_str()); link_num++; { if (urdf_link->parent_joint != NULL) { // x y z w addRotate(node, urdf_link->parent_joint->parent_to_joint_origin_transform.rotation); // x y z addTranslate(node, urdf_link->parent_joint->parent_to_joint_origin_transform.position); // x y z angle domRotateRef joint_rotate = addRotate(node, urdf_link->parent_joint->parent_to_joint_origin_transform.rotation); string joint_sid = joint_sids_[urdf_link->parent_joint->name]; string joint_rotate_sid = string("node_") + joint_sid + string("_axis0"); joint_rotate->setSid(joint_rotate_sid.c_str()); node_ids_[urdf_link->parent_joint->name] = node_id; } // map::const_iterator i = geometry_ids_.find(urdf_link->name); if (i != geometry_ids_.end()) { domInstance_geometryRef instance_geometry = daeSafeCast(node->createAndPlace(COLLADA_ELEMENT_INSTANCE_GEOMETRY)); string geometry_id = i->second; string instance_geometry_url = string("#") + geometry_id; instance_geometry->setUrl(instance_geometry_url.c_str()); { // domBind_materialRef bind_material = daeSafeCast(instance_geometry->createAndPlace(COLLADA_ELEMENT_BIND_MATERIAL)); { // domBind_material::domTechnique_commonRef technique_common = daeSafeCast(bind_material->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON)); { // domInstance_materialRef instance_material = daeSafeCast(technique_common->createAndPlace(COLLADA_ELEMENT_INSTANCE_MATERIAL)); instance_material->setTarget((instance_geometry_url + string(".mat")).c_str()); instance_material->setSymbol("mat0"); // } // } // } } // // foreach(shared_ptr link2, urdf_link->child_links) addVisualLink(link2, node, link_num); // } // } domTranslateRef ColladaWriter::addTranslate(daeElementRef parent, urdf::Vector3 const& position) { // x y z domTranslateRef trans = daeSafeCast(parent->createAndPlace(COLLADA_ELEMENT_TRANSLATE)); trans->getValue().setCount(3); trans->getValue()[0] = position.x; trans->getValue()[1] = position.y; trans->getValue()[2] = position.z; return trans; } domRotateRef ColladaWriter::addRotate(daeElementRef parent, urdf::Rotation const& r) { double ax, ay, az, aa; // Convert from quaternion to axis-angle double sqr_len = r.x * r.x + r.y * r.y + r.z * r.z; if (sqr_len > 0) { aa = 2 * acos(r.w); double inv_len = 1.0 / sqrt(sqr_len); ax = r.x * inv_len; ay = r.y * inv_len; az = r.z * inv_len; } else { // Angle is 0 (mod 2*pi), so any axis will do aa = 0.0; ax = 1.0; ay = 0.0; az = 0.0; } // x y z w domRotateRef rot = daeSafeCast(parent->createAndPlace(COLLADA_ELEMENT_ROTATE)); rot->getValue().setCount(4); rot->getValue()[0] = ax; rot->getValue()[1] = ay; rot->getValue()[2] = az; rot->getValue()[3] = angles::to_degrees(aa); return rot; } string ColladaWriter::getTimeStampString() const { //"2009-04-06T17:01:00.891550" // facet becomes owned by locale, so no need to explicitly delete boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%Y-%m-%dT%H:%M:%s"); std::stringstream ss(std::stringstream::in | std::stringstream::out); ss.imbue(std::locale(ss.getloc(), facet)); ss << boost::posix_time::second_clock::local_time(); string date; ss >> date; return date; } }