// Handle conversion from older format void VisibleObject::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { SimTK::Array_<SimTK::String> oldGeometryFiles; if ( versionNumber < XMLDocument::getLatestVersion()){ if (versionNumber<20101){ SimTK::Xml::element_iterator visPropIter = aNode.element_begin("VisibleProperties"); // Get geometry files and Preferences if any and set them into if (visPropIter!=aNode.element_end()){ // Move display_prference, and show_axes nodes up to VisibleObject SimTK::Xml::element_iterator prefIter = visPropIter->element_begin("display_preference"); if (prefIter!= visPropIter->element_end()){ SimTK::Xml::Node moveNode = visPropIter->removeNode(prefIter); aNode.insertNodeAfter(aNode.element_end(), moveNode); } SimTK::Xml::element_iterator showAxesIter = visPropIter->element_begin("show_axes"); if (showAxesIter!=aNode.element_end()){ SimTK::Xml::Node moveNode = visPropIter->removeNode(showAxesIter); aNode.insertNodeAfter(aNode.element_end(), moveNode); } } SimTK::Xml::element_iterator geometryIter = aNode.element_begin("geometry_files"); string propValue=""; bool hasPieces=false; if (geometryIter!= aNode.element_end()){ geometryIter->getValueAs(oldGeometryFiles); } } } Object::updateFromXMLNode(aNode, versionNumber); if (oldGeometryFiles.size()>0){ for(unsigned i=0; i< oldGeometryFiles.size(); i++) setGeometryFileName(i, oldGeometryFiles[i]); } }
void XMLDocument::addPhysicalOffsetFrame(SimTK::Xml::Element& element, const std::string& frameName, const std::string& parentFrameName, const SimTK::Vec3& location, const SimTK::Vec3& orientation) { SimTK::Xml::element_iterator frames_node = element.element_begin("frames"); //SimTK::String debug; //Only used for debugging if (frames_node == element.element_end()) { SimTK::Xml::Element framesElement("frames"); element.insertNodeBefore(element.element_begin(), framesElement); frames_node = element.element_begin("frames"); } // Here we're guaranteed frames node exists, add individual frame SimTK::Xml::Element newFrameElement("PhysicalOffsetFrame"); newFrameElement.setAttributeValue("name", frameName); //newFrameElement.writeToString(debug); XMLDocument::addConnector(newFrameElement, "Connector_PhysicalFrame_", "parent", parentFrameName); std::ostringstream transValue; transValue << location[0] << " " << location[1] << " " << location[2]; SimTK::Xml::Element translationElement("translation", transValue.str()); newFrameElement.insertNodeAfter(newFrameElement.element_end(), translationElement); std::ostringstream orientValue; orientValue << orientation[0] << " " << orientation[1] << " " << orientation[2]; SimTK::Xml::Element orientationElement("orientation", orientValue.str()); newFrameElement.insertNodeAfter(newFrameElement.element_end(), orientationElement); frames_node->insertNodeAfter(frames_node->element_end(), newFrameElement); //frames_node->writeToString(debug); }
void ModelComponent::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { if (versionNumber < XMLDocument::getLatestVersion()) { if (versionNumber < 30506) { // geometry list property removed. Everything that was in this list // should be moved to the components list property. SimTK::Xml::element_iterator geometry = aNode.element_begin("geometry"); if (geometry != aNode.element_end()) { // We found a list property of geometry. SimTK::Xml::Element componentsNode; SimTK::Xml::element_iterator componentsIt = aNode.element_begin("components"); if (componentsIt == aNode.element_end()) { // This component does not yet have a list property of // components, so we'll create one. componentsNode = SimTK::Xml::Element("components"); aNode.insertNodeBefore(aNode.element_begin(), componentsNode); } else { componentsNode = *componentsIt; } // Copy each node under <geometry> into <components>. for (auto geomIt = geometry->element_begin(); geomIt != geometry->element_end(); ++geomIt) { componentsNode.appendNode(geomIt->clone()); } // Now that we moved over the geometry, we can delete the // <geometry> element. aNode.eraseNode(geometry); } } } Super::updateFromXMLNode(aNode, versionNumber); }
/*static*/ void XMLDocument::renameChildNode(SimTK::Xml::Element& aNode, std::string oldElementName, std::string newElementName) { Xml::element_iterator elmtIter(aNode.element_begin(oldElementName)); if (elmtIter!=aNode.element_end()){ elmtIter->setElementTag(newElementName); } }
void PointToPointSpring::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; if (documentVersion < XMLDocument::getLatestVersion()) { if (documentVersion<30500) { // replace old properties with latest use of Connectors SimTK::Xml::element_iterator body1Element = aNode.element_begin("body1"); SimTK::Xml::element_iterator body2Element = aNode.element_begin("body2"); std::string body1_name(""), body2_name(""); // If default constructed then elements not serialized since they // are default values. Check that we have associated elements, then // extract their values. // Forces in pre-4.0 models are necessarily 1 level deep // Bodies are also necessarily 1 level deep. // Here we create the correct relative path (accounting for sets // being components). if (body1Element != aNode.element_end()) { body1Element->getValueAs<std::string>(body1_name); body1_name = XMLDocument::updateConnecteePath30517("bodyset", body1_name); } if (body2Element != aNode.element_end()) { body2Element->getValueAs<std::string>(body2_name); body2_name = XMLDocument::updateConnecteePath30517("bodyset", body2_name); } XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body1", body1_name); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body2", body2_name); } } Super::updateFromXMLNode(aNode, versionNumber); }
void Body::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { if (versionNumber < XMLDocument::getLatestVersion()) { if (versionNumber < 30500) { SimTK::Vec6 newInertia(1.0, 1.0, 1.0, 0., 0., 0.); std::string inertiaComponents[] = { "inertia_xx", "inertia_yy", "inertia_zz", "inertia_xy", "inertia_xz", "inertia_yz" }; for (int i = 0; i < 6; ++i) { SimTK::Xml::element_iterator iIter = aNode.element_begin(inertiaComponents[i]); if (iIter != aNode.element_end()) { newInertia[i] = iIter->getValueAs<double>(); aNode.removeNode(iIter); } } std::ostringstream strs; for (int i = 0; i < 6; ++i) { strs << newInertia[i]; if (i < 5) strs << " "; } std::string strInertia = strs.str(); SimTK::Xml::Element inertiaNode("inertia", strInertia); aNode.insertNodeAfter(aNode.element_end(), inertiaNode); } } Super::updateFromXMLNode(aNode, versionNumber); }
/*virtual*/ void Marker::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { if (versionNumber < XMLDocument::getLatestVersion()){ if (versionNumber < 30501) { // Parse name of Body under <body>node SimTK::Xml::element_iterator bIter = aNode.element_begin("body"); SimTK::String bName = bIter->getValue(); // Create nodes for new layout SimTK::Xml::Element connectorsElement("connectors"); SimTK::Xml::Element frameElement("Connector_PhysicalFrame_"); connectorsElement.insertNodeAfter(connectorsElement.node_end(), frameElement); frameElement.setAttributeValue("name", "parent_frame"); SimTK::Xml::Element connecteeElement("connectee_name"); // Markers in pre-4.0 models are necessarily 1 level deep // (model, markers), and Bodies were necessarily 1 level deep; // here we create the correct relative path (accounting for sets // being components). bName = XMLDocument::updateConnecteePath30517("bodyset", bName); connecteeElement.setValue(bName); frameElement.insertNodeAfter(frameElement.node_end(), connecteeElement); aNode.insertNodeAfter(bIter, connectorsElement); aNode.eraseNode(bIter); } } // Call base class now assuming _node has been corrected for current version Super::updateFromXMLNode(aNode, versionNumber); }
//_____________________________________________________________________________ // Override default implementation by object to intercept and fix the XML node // underneath the model to match current version. void Muscle::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { if ( versionNumber < XMLDocument::getLatestVersion()) { if (Object::getDebugLevel()>=1) cout << "Updating Muscle object to latest format..." << endl; if (versionNumber <= 20301){ SimTK::Xml::element_iterator pathIter = aNode.element_begin("GeometryPath"); if (pathIter != aNode.element_end()) { XMLDocument::renameChildNode(*pathIter, "MusclePointSet", "PathPointSet"); XMLDocument::renameChildNode(*pathIter, "MuscleWrapSet", "PathWrapSet"); } else { // There was no GeometryPath, just MusclePointSet SimTK::Xml::element_iterator musclePointSetIter = aNode.element_begin("MusclePointSet"); bool pathPointSetFound=false; if (musclePointSetIter != aNode.element_end()){ XMLDocument::renameChildNode(aNode, "MusclePointSet", "PathPointSet"); pathPointSetFound=true; } bool pathWrapSetFound=false; SimTK::Xml::element_iterator muscleWrapSetIter = aNode.element_begin("MuscleWrapSet"); if (muscleWrapSetIter != aNode.element_end()){ XMLDocument::renameChildNode(aNode, "MuscleWrapSet", "PathWrapSet"); pathWrapSetFound=true; } // Now create a "GeometryPath" node and move MusclePointSet & MuscleWrapSet under it SimTK::Xml::Element myPathElement("GeometryPath"); SimTK::Xml::Node moveNode; if (pathPointSetFound) { SimTK::Xml::element_iterator pathPointSetIter = aNode.element_begin("PathPointSet"); moveNode = aNode.removeNode(pathPointSetIter); myPathElement.insertNodeAfter(myPathElement.element_end(),moveNode); } if (pathWrapSetFound) { SimTK::Xml::element_iterator pathWrapSetIter = aNode.element_begin("PathWrapSet"); moveNode = aNode.removeNode(pathWrapSetIter); myPathElement.insertNodeAfter(myPathElement.element_end(),moveNode); } aNode.insertNodeAfter(aNode.element_end(), myPathElement); } XMLDocument::renameChildNode(aNode, "pennation_angle", "pennation_angle_at_optimal"); } } // Call base class now assuming aNode has been corrected for current version Super::updateFromXMLNode(aNode, versionNumber); }
/* * Helper function to add connector to the xmlElement passed in */ void XMLDocument::addConnector(SimTK::Xml::Element& element, const std::string& connectorTag, const std::string& connectorName, const std::string& connectorValue) { SimTK::Xml::element_iterator connectors_node = element.element_begin("connectors"); SimTK::String debug; if (connectors_node == element.element_end()){ SimTK::Xml::Element connectorsElement("connectors"); element.insertNodeBefore(element.element_begin(), connectorsElement); connectors_node = element.element_begin("connectors"); } // Here we're guaranteed connectors node exist, add individual connector SimTK::Xml::Element newConnectorElement(connectorTag); newConnectorElement.setAttributeValue("name", connectorName); newConnectorElement.writeToString(debug); SimTK::Xml::Element connecteeElement("connectee_name"); connecteeElement.insertNodeAfter(connecteeElement.element_end(), SimTK::Xml::Text(connectorValue)); // Insert text under newConnectorElement newConnectorElement.insertNodeAfter(newConnectorElement.element_end(), connecteeElement); connectors_node->insertNodeAfter(connectors_node->element_end(), newConnectorElement); connectors_node->writeToString(debug); }
void PointOnLineConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; if (documentVersion < XMLDocument::getLatestVersion()){ if (documentVersion<30500){ // replace old properties with latest use of Connectors SimTK::Xml::element_iterator body1Element = aNode.element_begin("line_body"); SimTK::Xml::element_iterator body2Element = aNode.element_begin("follower_body"); std::string body1_name(""), body2_name(""); // If default constructed then elements not serialized since they are default // values. Check that we have associated elements, then extract their values. if (body1Element != aNode.element_end()) body1Element->getValueAs<std::string>(body1_name); if (body2Element != aNode.element_end()) body2Element->getValueAs<std::string>(body2_name); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "line_body", body1_name); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "follower_body", body2_name); } } Super::updateFromXMLNode(aNode, versionNumber); }
void ContactGeometry::updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber) { if (versionNumber < XMLDocument::getLatestVersion()) { if (versionNumber < 30505) { SimTK::Xml::element_iterator bodyElement = node.element_begin("body_name"); std::string body_name(""); // Element may not exist if body_name property had default value. if (bodyElement != node.element_end()) { bodyElement->getValueAs<std::string>(body_name); } XMLDocument::addConnector(node, "Connector_PhysicalFrame_", "frame", body_name); } } Super::updateFromXMLNode(node, versionNumber); }
void PathPoint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; if (documentVersion < XMLDocument::getLatestVersion()) { if (documentVersion < 30505) { // replace old properties with latest use of Connectors SimTK::Xml::element_iterator bodyElement = aNode.element_begin("body"); std::string bodyName(""); if (bodyElement != aNode.element_end()) { bodyElement->getValueAs<std::string>(bodyName); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "parent_frame", bodyName); } } } Super::updateFromXMLNode(aNode, versionNumber); }
/** * Override default implementation by object to intercept and fix the XML node * underneath the tool to match current version */ /*virtual*/ void ForwardTool::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; bool neededSprings=false; std::string savedCwd; if(getDocument()) { savedCwd = IO::getCwd(); IO::chDir(IO::getParentDirectory(getDocument()->getFileName())); } if ( documentVersion < XMLDocument::getLatestVersion()){ // Now check if we need to create a correction controller to replace springs if (documentVersion<10904){ std::string propNames[]={ "body1_linear_corrective_spring_active", "body1_torsional_corrective_spring_active", "body2_linear_corrective_spring_active", "body2_torsional_corrective_spring_active" }; int i=0; while (!neededSprings && i<4){ neededSprings = (aNode.element_begin(propNames[i++])!=aNode.element_end()); } AbstractTool::updateFromXMLNode(aNode, versionNumber); if (neededSprings){ CorrectionController* cc = new CorrectionController(); cc->setKp(16.0); cc->setKv(8.0); _controllerSet.adoptAndAppend(cc); _parsingLog+= "This setup file contains corrective springs.\n"; _parsingLog+= "Corrective springs are deprecated in OpenSim 2.0\n"; _parsingLog+= "Instead, a Corrective Controller has been created.\n"; } } else AbstractTool::updateFromXMLNode(aNode, versionNumber); } else AbstractTool::updateFromXMLNode(aNode, versionNumber); if(getDocument()) IO::chDir(savedCwd); //Object::updateFromXMLNode(aNode, versionNumber); }
/*virtual*/ void Marker::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { if (versionNumber < XMLDocument::getLatestVersion()){ if (versionNumber < 30501) { // Parse name of Body under <body>node SimTK::Xml::element_iterator bIter = aNode.element_begin("body"); SimTK::String bName = bIter->getValue(); // Create nodes for new layout SimTK::Xml::Element connectorsElement("connectors"); SimTK::Xml::Element frameElement("Connector_PhysicalFrame_"); connectorsElement.insertNodeAfter(connectorsElement.node_end(), frameElement); frameElement.setAttributeValue("name", "reference_frame"); SimTK::Xml::Element connecteeElement("connectee_name"); connecteeElement.setValue(bName); frameElement.insertNodeAfter(frameElement.node_end(), connecteeElement); aNode.insertNodeAfter(bIter, connectorsElement); aNode.eraseNode(bIter); } } // Call base class now assuming _node has been corrected for current version Object::updateFromXMLNode(aNode, versionNumber); }
/** * Update this object based on its XML node. */ void PrescribedForce::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { // Base class // This test for veversion number needs to change when we have a new version number otherwise // subsequent versions will continue to trigger the conversion below. -Ayman 4/16 if (versionNumber != 30505) { // Convert body property into a connector to PhysicalFrame with name "frame" SimTK::Xml::element_iterator bodyElement = aNode.element_begin("body"); std::string frame_name(""); if (bodyElement != aNode.element_end()) { bodyElement->getValueAs<std::string>(frame_name); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "frame", frame_name); } } Super::updateFromXMLNode(aNode, versionNumber); const FunctionSet& forceFunctions = getForceFunctions(); const FunctionSet& pointFunctions = getPointFunctions(); const FunctionSet& torqueFunctions = getTorqueFunctions(); //Specify all or none of the components if(forceFunctions.getSize() != 3 && forceFunctions.getSize() != 0) { throw Exception("PrescribedForce:: three components of the force must be specified."); } if(pointFunctions.getSize() != 3 && pointFunctions.getSize() != 0) { throw Exception("PrescribedForce:: three components of the point must be specified."); } if(torqueFunctions.getSize() != 3 && torqueFunctions.getSize() != 0) { throw Exception("PrescribedForce:: three components of the torque must be specified."); } }
//----------------------------------------------------------------------------- // UPDATE FROM OLDER VERSION //----------------------------------------------------------------------------- //_____________________________________________________________________________ void ExternalLoads::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; if ( documentVersion < 20301){ if (Object::getDebugLevel()>=1) cout << "Updating ExternalLoad object to latest format..." << endl; _dataFileName=""; SimTK::Xml::element_iterator dataFileElementIter =aNode.element_begin("datafile"); if(dataFileElementIter!=aNode.element_end()) { // Could still be empty or whiteSpace SimTK::String transcoded = dataFileElementIter->getValueAs<SimTK::String>(); if (transcoded.length()>0) _dataFileName =transcoded; } SimTK::Xml::element_iterator kinFileNode = aNode.element_begin("external_loads_model_kinematics_file"); if (kinFileNode != aNode.element_end()){ SimTK::String transcoded = kinFileNode->getValueAs<SimTK::String>(); if (transcoded.length()>0) _externalLoadsModelKinematicsFileName =transcoded; } SimTK::Xml::element_iterator kinFilterNode = aNode.element_begin("lowpass_cutoff_frequency_for_load_kinematics"); if (kinFilterNode != aNode.element_end()){ _lowpassCutoffFrequencyForLoadKinematics = kinFilterNode->getValueAs<double>(); } bool changeWorkingDir = false; std::string savedCwd; // Change to directory of Document if(!ifstream(_dataFileName.c_str(), ios_base::in).good()) { string msg = "Object: ERR- Could not open file " + _dataFileName+ "IO. It may not exist or you don't have permission to read it."; cout << msg; // Try switching to directory of setup file before aborting if(getDocument()) { savedCwd = IO::getCwd(); IO::chDir(IO::getParentDirectory(getDocument()->getFileName())); changeWorkingDir=true; } if(!ifstream(_dataFileName.c_str(), ios_base::in).good()) { if(changeWorkingDir) IO::chDir(savedCwd); throw Exception(msg,__FILE__,__LINE__); } } Storage* dataSource = new Storage(_dataFileName, true); if (!dataSource->makeStorageLabelsUnique()){ cout << "Making labels unique in storage file "<< _dataFileName << endl; dataSource = new Storage(_dataFileName); dataSource->makeStorageLabelsUnique(); dataSource->print(_dataFileName); } if(changeWorkingDir) IO::chDir(savedCwd); const Array<string> &labels = dataSource->getColumnLabels(); // Populate data file and other things that haven't changed // Create a ForceSet out of this XML node, this will create a set of PrescribedForces then we can reassign at a higher level to ExternalForces ModelComponentSet<PrescribedForce> oldForces(updModel(), getDocument()->getFileName(), true); for(int i=0; i< oldForces.getSize(); i++){ PrescribedForce& oldPrescribedForce = oldForces.get(i); ExternalForce* newExternalForce = new ExternalForce(); newExternalForce->setName(oldPrescribedForce.getName()); newExternalForce->setAppliedToBodyName(oldPrescribedForce.getBodyName()); newExternalForce->setPointExpressedInBodyName("ground"); newExternalForce->setForceExpressedInBodyName("ground"); // Reconstruct function names and use these to extract the identifier(s) OpenSim::Array<std::string> aFunctionNames; oldPrescribedForce.getForceFunctionNames(aFunctionNames); // Get names from force functions newExternalForce->setForceIdentifier(createIdentifier(aFunctionNames, labels)); aFunctionNames.setSize(0); oldPrescribedForce.getPointFunctionNames(aFunctionNames); newExternalForce->setPointIdentifier(createIdentifier(aFunctionNames, labels)); aFunctionNames.setSize(0); // Now the torques oldPrescribedForce.getTorqueFunctionNames(aFunctionNames); newExternalForce->setTorqueIdentifier(createIdentifier(aFunctionNames, labels)); //newExternalForce->setDataSourceName(""); adoptAndAppend(newExternalForce); } delete dataSource; } else // Call base class now assuming _node has been corrected for current version ModelComponentSet<ExternalForce>::updateFromXMLNode(aNode, versionNumber); }
/** Override of the default implementation to account for versioning. */ void CustomJoint:: updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; if ( documentVersion < XMLDocument::getLatestVersion()){ if (Object::getDebugLevel()>=1) cout << "Updating CustomJoint to latest format..." << endl; // Version before refactoring spatialTransform if (documentVersion<10901){ // replace TransformAxisSet with SpatialTransform /////renameChildNode("TransformAxisSet", "SpatialTransform"); // Check how many TransformAxes are defined SimTK::Xml::element_iterator spatialTransformNode = aNode.element_begin("TransformAxisSet"); if (spatialTransformNode == aNode.element_end()) return; SimTK::Xml::element_iterator axesSetNode = spatialTransformNode->element_begin("objects"); /////if (axesSetNode != NULL) ///// spatialTransformNode->removeChild(axesSetNode); /////DOMElement*grpNode = XMLNode::GetFirstChildElementByTagName(spatialTransformNode,"groups"); /////if (grpNode != NULL) ///// spatialTransformNode->removeChild(grpNode); // (0, 1, 2 rotations & 3, 4, 5 translations then remove the is_rotation node) SimTK::Array_<SimTK::Xml::Element> list = axesSetNode->getAllElements(); unsigned int listLength = list.size(); int objectsFound = 0; Array<int> translationIndices(-1, 0); Array<int> rotationIndices(-1, 0); int nextAxis = 0; std::vector<TransformAxis *> axes; // Add children for all six axes here //////_node->removeChild(SpatialTransformNode); // Create a blank Spatial Transform and use it to populate the // XML structure for(int i=0; i<6; i++) updSpatialTransform()[i].setFunction(new OpenSim::Constant(0)); Array<OpenSim::TransformAxis*> oldAxes; for(unsigned int j=0;j<listLength;j++) { // getChildNodes() returns all types of DOMNodes including // comments, text, etc., but we only want // to process element nodes SimTK::Xml::Element objElmt = list[j]; string objectType = objElmt.getElementTag(); // (sherm) this is cleaning up old TransformAxis here but // that should really be done in TransformAxis instead. if (objectType == "TransformAxis"){ OpenSim::TransformAxis* readAxis = new OpenSim::TransformAxis(objElmt); assert(nextAxis <=5); bool isRotation = false; SimTK::Xml::element_iterator rotationNode = objElmt.element_begin("is_rotation"); if (rotationNode != objElmt.element_end()){ SimTK::String sValue = rotationNode->getValueAs<SimTK::String>(); bool value = (sValue.toLower() == "true"); isRotation = value; objElmt.eraseNode(rotationNode); } SimTK::Xml::element_iterator coordinateNode = objElmt.element_begin("coordinate"); SimTK::String coordinateName = coordinateNode->getValueAs<SimTK::String>(); Array<std::string> names(""); names.append(coordinateName); readAxis->setCoordinateNames(names); SimTK::Xml::element_iterator axisNode = objElmt.element_begin("axis"); SimTK::Vec3 axisVec= axisNode->getValueAs<SimTK::Vec3>(); readAxis->setAxis(axisVec); if (isRotation){ rotationIndices.append(nextAxis); } else { translationIndices.append(nextAxis); } axes.push_back(readAxis); nextAxis++; } } assert(rotationIndices.getSize() <=3); assert(translationIndices.getSize() <=3); //XMLNode::RemoveChildren(SpatialTransformAxesNode); int nRotations = rotationIndices.getSize(); int nTranslations = translationIndices.getSize(); // Now copy coordinateName, Axis, Function into proper slot for (int i=0; i<nRotations; i++){ updSpatialTransform()[i] = *axes[rotationIndices[i]]; } updSpatialTransform().constructIndependentAxes(nRotations, 0); // Add Translations from old list then pad with default ones, // make sure no singularity. for (int i=0; i<nTranslations; i++){ updSpatialTransform()[i+3] = *axes[translationIndices[i]]; } updSpatialTransform().constructIndependentAxes(nTranslations, 3); } } // Delegate to superclass now. Super::updateFromXMLNode(aNode, versionNumber); const CoordinateSet& coordinateSet = get_CoordinateSet(); // Fix coordinate type post deserialization // Fix coordinate type post deserialization for (int i=0; i<coordinateSet.getSize(); i++){ OpenSim::Coordinate& nextCoord = coordinateSet.get(i); // Find TransformAxis for the coordinate and use it to set Coordinate's motionType for(int axisIndex=0; axisIndex<6; axisIndex++){ const TransformAxis& nextAxis = getSpatialTransform()[axisIndex]; const Property<std::string>& coordNames = nextAxis.getCoordinateNames(); if (coordNames.findIndex(nextCoord.getName())!=-1){ coordinateSet.get(i).setMotionType((axisIndex>2)? Coordinate::Translational : Coordinate::Rotational); break; } } } // Axes should be independent otherwise Simbody throws an exception in addToSystem double tol = 1e-5; // Verify that none of the rotation axes are colinear const std::vector<SimTK::Vec3> axes=getSpatialTransform().getAxes(); for(int startIndex=0; startIndex<=3; startIndex+=3){ if(((axes[startIndex+0]%axes[startIndex+1]).norm() < tol)|| ((axes[startIndex+0]%axes[startIndex+2]).norm() < tol)|| ((axes[startIndex+1]%axes[startIndex+2]).norm() < tol)){ throw(Exception("CustomJoint " + getName() + " has colinear axes and so is not well-defined." " Please fix and retry loading..")); } } updProperty_SpatialTransform().setValueIsDefault(false); }
bool XMLDocument::isElementEqual(SimTK::Xml::Element& elt1, SimTK::Xml::Element& elt2, double toleranceForDoubles) { SimTK::String s1,s2; elt1.writeToString(s1); elt2.writeToString(s2); SimTK::Xml::attribute_iterator att1 = elt1.attribute_begin(); SimTK::Xml::attribute_iterator att2 = elt2.attribute_begin(); // Handle different # attributes if ( (att1 == elt1.attribute_end() && att2 != elt2.attribute_end()) || (att1 != elt1.attribute_end() && att2 == elt2.attribute_end()) ){ cout << "Number of attributes is different, element " << elt1.getElementTag() << endl; return false; } bool equal =true; // Same size attributes including none for(att1 = elt1.attribute_begin(); att1 != elt1.attribute_end() && equal; att1++, att2++){ equal = (att1->getName() == att2->getName()); equal = equal && (att1->getValue() == att2->getValue()); if (!equal) { cout << "Attribute " << att1->getName() << " is different " << att1->getValue() << "vs." << att2->getValue() << endl; } } if (!equal) return false; // Attributes match now children SimTK::Array_<SimTK::Xml::Element> elts1 = elt1.getAllElements(); SimTK::Array_<SimTK::Xml::Element> elts2 = elt2.getAllElements(); if (elts1.size() != elts2.size()){ cout << "Different number of children for Element " << elt1.getElementTag() << endl; equal = false; } if (!equal) return false; // Recursively compare Elements unless Value Elements in that case do direct compare for(unsigned it = 0; it < elts1.size() && equal; it++){ SimTK::String elt1Tag = elts1[it].getElementTag(); cout << "Compare " << elt1Tag << endl; SimTK::Xml::element_iterator elt2_iter = elt2.element_begin(elt1Tag); if (elt2_iter==elt2.element_end()){ cout << "Element " << elt1Tag << " was not found in reference document" << endl; equal = false; break; } bool value1 = elts1[it].isValueElement(); bool value2 = elt2_iter->isValueElement(); equal = (value1 == value2); if (!equal){ cout << elts1[it].getElementTag() << " is different. One is Value Element the other isn't" << endl; return false; } if (value1){ // We should check if this's a double or array of doubles in that case we can getValueAs<double> anbd try { SimTK::Array_<double> v1, v2; elts1[it].getValueAs(v1); elt2_iter->getValueAs(v2); for(unsigned ix=0; ix<v1.size() && equal; ix++) equal = (std::fabs(v1[ix]-v2[ix]) < toleranceForDoubles); } catch(...){ equal = (elts1[it].getValue() == elt2_iter->getValue()); } } else // recur equal = isElementEqual(elts1[it], elts2[it], toleranceForDoubles); if (!equal){ cout << elts1[it].getElementTag() << " is different" << endl; SimTK::String pad; elts1[it].writeToString(pad); cout << pad << endl; cout << "------------------- vs. ------" << endl; elts2[it].writeToString(pad); cout << pad << endl; return equal; } } return equal; }
void Joint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) { int documentVersion = versionNumber; //bool converting = false; if (documentVersion < XMLDocument::getLatestVersion()){ if (documentVersion<30500){ XMLDocument::renameChildNode(aNode, "location", "location_in_child"); XMLDocument::renameChildNode(aNode, "orientation", "orientation_in_child"); } // Version 30501 converted Connector_Body_ to Connector_PhysicalFrame_ if (documentVersion < 30501) { // Handle any models that have the Joint connecting to Bodies instead // of PhyscialFrames XMLDocument::renameChildNode(aNode, "Connector_Body_", "Connector_PhysicalFrame_"); } // Version 30505 changed "parent_body" connector name to "parent_frame" // Convert location and orientation into PhysicalOffsetFrames owned by the Joint if (documentVersion < 30505) { // Elements for the parent and child names the joint connects SimTK::Xml::element_iterator parentNameElt; SimTK::Xml::element_iterator childNameElt; // The names of the two PhysicalFrames this joint connects std::string parentFrameName(""); std::string childFrameName(""); SimTK::Xml::element_iterator connectors_node = aNode.element_begin("connectors"); SimTK::Xml::element_iterator connectorElement = connectors_node->element_begin("Connector_PhysicalFrame_"); while (connectorElement != aNode.element_end()) { // If connector name is "parent_body" rename it to "parent_frame" if (connectorElement->getRequiredAttributeValue("name") == "parent_body") { connectorElement->setAttributeValue("name", "parent_frame"); } // If connector name is "parent_frame" get the name of the connectee if (connectorElement->getRequiredAttributeValue("name") == "parent_frame"){ parentNameElt = connectorElement->element_begin("connectee_name"); parentNameElt->getValueAs<std::string>(parentFrameName); const auto slashLoc = parentFrameName.rfind('/'); if (slashLoc != std::string::npos) parentFrameName = parentFrameName.substr(slashLoc + 1); } if (connectorElement->getRequiredAttributeValue("name") == "child_body") { connectorElement->setAttributeValue("name", "child_frame"); } if (connectorElement->getRequiredAttributeValue("name") == "child_frame") { childNameElt = connectorElement->element_begin("connectee_name"); childNameElt->getValueAs<std::string>(childFrameName); const auto slashLoc = childFrameName.rfind('/'); if (slashLoc != std::string::npos) childFrameName = childFrameName.substr(slashLoc + 1); } ++connectorElement; } SimTK::Xml::element_iterator locParentElt = aNode.element_begin("location_in_parent"); SimTK::Xml::element_iterator orientParentElt = aNode.element_begin("orientation_in_parent"); SimTK::Xml::element_iterator locChildElt = aNode.element_begin("location_in_child"); SimTK::Xml::element_iterator orientChildElt = aNode.element_begin("orientation_in_child"); Vec3 location_in_parent(0); Vec3 orientation_in_parent(0); Vec3 location_in_child(0); Vec3 orientation_in_child(0); if (locParentElt != aNode.element_end()){ locParentElt->getValueAs<Vec3>(location_in_parent); } if (orientParentElt != aNode.element_end()){ orientParentElt->getValueAs<Vec3>(orientation_in_parent); } if (locChildElt != aNode.element_end()){ locChildElt->getValueAs<Vec3>(location_in_child); } if (orientChildElt != aNode.element_end()){ orientChildElt->getValueAs<Vec3>(orientation_in_child); } // now append updated frames to the property list for // both parent and child XMLDocument::addPhysicalOffsetFrame30505_30517(aNode, parentFrameName+"_offset", parentFrameName, location_in_parent, orientation_in_parent); parentNameElt->setValue(parentFrameName + "_offset"); XMLDocument::addPhysicalOffsetFrame30505_30517(aNode, childFrameName + "_offset", childFrameName, location_in_child, orientation_in_child); childNameElt->setValue(childFrameName + "_offset"); } // Version 30507 replaced Joint's CoordinateSet with a "coordinates" // list property. if (documentVersion < 30507) { if (aNode.hasElement("CoordinateSet")) { auto coordSetIter = aNode.element_begin("CoordinateSet"); if (coordSetIter->hasElement("objects")) { auto coordIter = coordSetIter->getRequiredElement("objects") .element_begin("Coordinate"); if (coordIter != aNode.element_end()) { // A "CoordinateSet" element exists, it contains an // "objects" element, and the "objects" element contains // at least one "Coordinate" element. // Create an element for the new layout. Xml::Element coordinatesElement("coordinates"); // Copy all "Coordinate" elements from the old layout. while (coordIter != aNode.element_end()) { coordinatesElement.appendNode(coordIter->clone()); ++coordIter; } // Insert new "coordinates" element. aNode.insertNodeAfter(coordSetIter, coordinatesElement); } } // Remove old "CoordinateSet" element. aNode.eraseNode(coordSetIter); } } // Version 30514 removed the user-facing "reverse" property from Joint. // The parent and child frames are swapped if a "reverse" element is // found and its value is "true". if (documentVersion < 30514) { auto reverseElt = aNode.element_begin("reverse"); if (reverseElt != aNode.element_end()) { bool swapFrames = false; reverseElt->getValue().tryConvertToBool(swapFrames); if (swapFrames) { std::string oldParentFrameName = ""; std::string oldChildFrameName = ""; // Find names of parent and child frames. If more than one // "parent_frame" or "child_frame" element exists, keep the // first one. The "parent_frame" and "child_frame" elements // may be listed in either order. SimTK::Xml::element_iterator connectorsNode = aNode.element_begin("connectors"); SimTK::Xml::element_iterator connectorElt = connectorsNode-> element_begin("Connector_PhysicalFrame_"); SimTK::Xml::element_iterator connecteeNameElt; while (connectorElt != connectorsNode->element_end()) { if (connectorElt->getRequiredAttributeValue("name") == "parent_frame" && oldParentFrameName.empty()) { connecteeNameElt = connectorElt-> element_begin("connectee_name"); connecteeNameElt->getValueAs<std::string>( oldParentFrameName); } else if (connectorElt->getRequiredAttributeValue("name") == "child_frame" && oldChildFrameName.empty()) { connecteeNameElt = connectorElt-> element_begin("connectee_name"); connecteeNameElt->getValueAs<std::string>( oldChildFrameName); } ++connectorElt; } // Swap parent and child frame names. If more than one // "parent_frame" or "child_frame" element exists, assign // the same value to all such elements. connectorsNode = aNode.element_begin("connectors"); connectorElt = connectorsNode->element_begin( "Connector_PhysicalFrame_"); while (connectorElt != connectorsNode->element_end()) { if (connectorElt->getRequiredAttributeValue("name") == "parent_frame") { connecteeNameElt = connectorElt-> element_begin("connectee_name"); connecteeNameElt->setValue(oldChildFrameName); } else if (connectorElt->getRequiredAttributeValue("name") == "child_frame") { connecteeNameElt = connectorElt-> element_begin("connectee_name"); connecteeNameElt->setValue(oldParentFrameName); } ++connectorElt; } } // Remove "reverse" element regardless of its value (it is no // longer a property of Joint). aNode.eraseNode(reverseElt); } } } Super::updateFromXMLNode(aNode, versionNumber); }