void PlanarSPQRTree::setPosInEmbedding( NodeArray<SListPure<adjEntry> > &adjEdges, NodeArray<node> ¤tCopy, NodeArray<adjEntry> &lastAdj, SListPure<node> ¤t, const Skeleton &S, adjEntry adj) { node vT = S.treeNode(); adjEdges[vT].pushBack(adj); node vCopy = adj->theNode(); node vOrig = S.original(vCopy); if(currentCopy[vT] == nullptr) { currentCopy[vT] = vCopy; current.pushBack(vT); for (adjEntry adjVirt : vCopy->adjEdges) { edge eCopy = S.twinEdge(adjVirt->theEdge()); if (eCopy == nullptr) continue; if (adjVirt == adj) { lastAdj[vT] = adj; continue; } const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge())); adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ? eCopy->adjSource() : eCopy->adjTarget(); setPosInEmbedding(adjEdges,currentCopy,lastAdj,current, STwin, adjCopy); } } else if (lastAdj[vT] != nullptr && lastAdj[vT] != adj) { adjEntry adjVirt = lastAdj[vT]; edge eCopy = S.twinEdge(adjVirt->theEdge()); const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge())); adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ? eCopy->adjSource() : eCopy->adjTarget(); setPosInEmbedding(adjEdges,currentCopy,lastAdj,current, STwin, adjCopy); lastAdj[vT] = nullptr; } }
SkeletonFrame* SkeletonTracker::NewSkeleton(XnUserID uid) { SkeletonFrame skeleton(uid); UserSkeletonMap::iterator it; // if there's already a skeleton with this UID, bail out if (this->UserExists(uid)) { return NULL; } this->QueueAction("add", uid); it = this->skeletons.insert(std::pair<XnUserID,SkeletonFrame>(uid, skeleton)).first; return &it->second; }
// // embed original graph according to embedding of skeletons // // The procedure also handles the case when some (real or virtual) // edges are reversed (used in upward-planarity algorithms) void PlanarSPQRTree::embed(Graph &G) { OGDF_ASSERT(&G == &originalGraph()); const Skeleton &S = skeleton(rootNode()); const Graph &M = S.getGraph(); for (node v : M.nodes) { node vOrig = S.original(v); SListPure<adjEntry> adjEdges; for (adjEntry adj : v->adjEdges) { edge e = adj->theEdge(); edge eOrig = S.realEdge(e); if (eOrig != nullptr) { adjEntry adjOrig = (vOrig == eOrig->source()) ? eOrig->adjSource() : eOrig->adjTarget(); OGDF_ASSERT(adjOrig->theNode() == S.original(v)); adjEdges.pushBack(adjOrig); } else { node wT = S.twinTreeNode(e); edge eTwin = S.twinEdge(e); expandVirtualEmbed(wT, (vOrig == skeleton(wT).original(eTwin->source())) ? eTwin->adjSource() : eTwin->adjTarget(), adjEdges); } } G.sort(vOrig,adjEdges); } edge e; forall_adj_edges(e,rootNode()) { node wT = e->target(); if (wT != rootNode()) createInnerVerticesEmbed(G, wT); }
void LineFinder::createSkeleton(int threshold) { // the image has to be grayscale if (Play::getInstance()->getFinder()->getImage().channels() != 1) { cv::cvtColor(Play::getInstance()->getFinder()->getImage(), Play::getInstance()->getFinder()->getImage(), cv::COLOR_BGR2GRAY); } // we need to enhance the lighting before we can threshold the image cv::equalizeHist(Play::getInstance()->getFinder()->getImage(), Play::getInstance()->getFinder()->getImage()); // a binary image is needed cv::threshold(Play::getInstance()->getFinder()->getImage(), Play::getInstance()->getFinder()->getImage(), threshold, 255, cv::THRESH_BINARY_INV); // the resulting skeleton cv::Mat skeleton(Play::getInstance()->getFinder()->getImage().size(), CV_8UC1, cv::Scalar(0,0,0)); // needed if in-place processing is not possible cv::Mat temp(Play::getInstance()->getFinder()->getImage().size(), CV_8UC1); // eroded image is saved here cv::Mat eroded; // needed for morphological transforms (erosion, dilation) cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(9,9)); int i = 0; while(i != 20) { // eroding + dilating = opening cv::erode(Play::getInstance()->getFinder()->getImage(), eroded, element); cv::dilate(eroded, temp, element); cv::subtract(Play::getInstance()->getFinder()->getImage(), temp, temp); cv::bitwise_or(skeleton, temp, skeleton); eroded.copyTo(Play::getInstance()->getFinder()->getImage()); //done = (cv::countNonZero(image) == 0); ++i; } Play::getInstance()->getFinder()->setImage(skeleton); }
void PlanarSPQRTree::adoptEmbedding() { OGDF_ASSERT_IF(dlExtendedChecking, originalGraph().representsCombEmbedding()); // ordered list of adjacency entries (for one original node) in all // skeletons (where this node occurs) NodeArray<SListPure<adjEntry> > adjEdges(tree()); // copy in skeleton of current original node NodeArray<node> currentCopy(tree(),nullptr); NodeArray<adjEntry> lastAdj(tree(),nullptr); SListPure<node> current; // currently processed nodes for (node vOrig : originalGraph().nodes) { for(adjEntry adjOrig : vOrig->adjEdges) { edge eOrig = adjOrig->theEdge(); const Skeleton &S = skeletonOfReal(eOrig); edge eCopy = copyOfReal(eOrig); adjEntry adjCopy = (S.original(eCopy->source()) == vOrig) ? eCopy->adjSource() : eCopy->adjTarget(); setPosInEmbedding(adjEdges,currentCopy,lastAdj,current,S,adjCopy); } for(node vT : current) { skeleton(vT).getGraph().sort(currentCopy[vT],adjEdges[vT]); adjEdges[vT].clear(); currentCopy[vT] = nullptr; } current.clear(); } }
void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* filename, const char *sourcefile, size_t size) { if (sourcefile == NULL) { throw Ogre::InsufficientData(FormatString("Failed to load '%s/%s'", groupname, filename).getData()); } std::shared_ptr<StdMeshLoader::StdMeshXML> skeleton(new StdMeshLoader::StdMeshXML(filename, sourcefile)); TiXmlElement* skeleton_elem = skeleton->RequireFirstChild(NULL, "skeleton"); TiXmlElement* bones_elem = skeleton->RequireFirstChild(skeleton_elem, "bones"); // Read bones. Don't insert into Master bone table yet, as the master bone // table is sorted hierarchically, and we will read the hierarchy only // afterwards. std::vector<StdMeshBone*> bones; for (TiXmlElement* bone_elem = bones_elem->FirstChildElement("bone"); bone_elem != NULL; bone_elem = bone_elem->NextSiblingElement("bone")) { StdMeshBone* bone = new StdMeshBone; bones.push_back(bone); bone->ID = skeleton->RequireIntAttribute(bone_elem, "id"); bone->Name = skeleton->RequireStrAttribute(bone_elem, "name"); // TODO: Make sure ID and name are unique bone->Parent = NULL; // Index of bone will be set when building Master Bone Table later TiXmlElement* position_elem = skeleton->RequireFirstChild(bone_elem, "position"); TiXmlElement* rotation_elem = skeleton->RequireFirstChild(bone_elem, "rotation"); TiXmlElement* axis_elem = skeleton->RequireFirstChild(rotation_elem, "axis"); StdMeshVector d, r; d.x = skeleton->RequireFloatAttribute(position_elem, "x"); d.y = skeleton->RequireFloatAttribute(position_elem, "y"); d.z = skeleton->RequireFloatAttribute(position_elem, "z"); float angle = skeleton->RequireFloatAttribute(rotation_elem, "angle"); r.x = skeleton->RequireFloatAttribute(axis_elem, "x"); r.y = skeleton->RequireFloatAttribute(axis_elem, "y"); r.z = skeleton->RequireFloatAttribute(axis_elem, "z"); bone->Transformation.scale = StdMeshVector::UnitScale(); bone->Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r); bone->Transformation.translate = d; // We need this later for applying animations, and attaching meshes, therefore cache it here bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation); } // Bone hierarchy TiXmlElement* bonehierarchy_elem = skeleton->RequireFirstChild(skeleton_elem, "bonehierarchy"); for (TiXmlElement* boneparent_elem = bonehierarchy_elem->FirstChildElement("boneparent"); boneparent_elem != NULL; boneparent_elem = boneparent_elem->NextSiblingElement("boneparent")) { const char* child_name = skeleton->RequireStrAttribute(boneparent_elem, "bone"); const char* parent_name = skeleton->RequireStrAttribute(boneparent_elem, "parent"); // Lookup the two bones StdMeshBone* child = NULL; StdMeshBone* parent = NULL; for (unsigned int i = 0; i < bones.size() && (!child || !parent); ++i) { if (!child && bones[i]->Name == child_name) child = bones[i]; if (!parent && bones[i]->Name == parent_name) parent = bones[i]; } if (!child) skeleton->Error(FormatString("There is no such bone with name '%s'", child_name), boneparent_elem); if (!parent) skeleton->Error(FormatString("There is no such bone with name '%s'", parent_name), boneparent_elem); child->Parent = parent; parent->Children.push_back(child); } std::shared_ptr<StdMeshSkeleton> Skeleton(new StdMeshSkeleton); // Fill master bone table in hierarchical order: for (unsigned int i = 0; i < bones.size(); ++i) if (bones[i]->Parent == NULL) Skeleton->AddMasterBone(bones[i]); // Load Animations TiXmlElement* animations_elem = skeleton_elem->FirstChildElement("animations"); if (animations_elem) { for (TiXmlElement* animation_elem = animations_elem->FirstChildElement("animation"); animation_elem != NULL; animation_elem = animation_elem->NextSiblingElement("animation")) { StdCopyStrBuf name(skeleton->RequireStrAttribute(animation_elem, "name")); if (Skeleton->Animations.find(name) != Skeleton->Animations.end()) skeleton->Error(FormatString("There is already an animation with name '%s'", name.getData()), animation_elem); StdMeshAnimation& animation = Skeleton->Animations.insert(std::make_pair(name, StdMeshAnimation())).first->second; animation.Name = name; animation.Length = skeleton->RequireFloatAttribute(animation_elem, "length"); animation.Tracks.resize(Skeleton->GetNumBones()); animation.OriginSkeleton = &(*Skeleton); TiXmlElement* tracks_elem = skeleton->RequireFirstChild(animation_elem, "tracks"); for (TiXmlElement* track_elem = tracks_elem->FirstChildElement("track"); track_elem != NULL; track_elem = track_elem->NextSiblingElement("track")) { const char* bone_name = skeleton->RequireStrAttribute(track_elem, "bone"); StdMeshBone* bone = NULL; for (unsigned int i = 0; !bone && i < Skeleton->GetNumBones(); ++i) if (Skeleton->Bones[i]->Name == bone_name) bone = Skeleton->Bones[i]; if (!bone) skeleton->Error(FormatString("There is no such bone with name '%s'", bone_name), track_elem); if (animation.Tracks[bone->Index] != NULL) skeleton->Error(FormatString("There is already a track for bone '%s' in animation '%s'", bone_name, animation.Name.getData()), track_elem); StdMeshTrack* track = new StdMeshTrack; animation.Tracks[bone->Index] = track; TiXmlElement* keyframes_elem = skeleton->RequireFirstChild(track_elem, "keyframes"); for (TiXmlElement* keyframe_elem = keyframes_elem->FirstChildElement("keyframe"); keyframe_elem != NULL; keyframe_elem = keyframe_elem->NextSiblingElement("keyframe")) { float time = skeleton->RequireFloatAttribute(keyframe_elem, "time"); StdMeshKeyFrame& frame = track->Frames[time]; TiXmlElement* translate_elem = keyframe_elem->FirstChildElement("translate"); TiXmlElement* rotate_elem = keyframe_elem->FirstChildElement("rotate"); TiXmlElement* scale_elem = keyframe_elem->FirstChildElement("scale"); StdMeshVector d, s, r; d.x = d.y = d.z = 0.0f; s = StdMeshVector::UnitScale(); r.x = r.y = 0.0f; r.z = 1.0f; float angle = 0.0f; if (translate_elem) { d.x = skeleton->RequireFloatAttribute(translate_elem, "x"); d.y = skeleton->RequireFloatAttribute(translate_elem, "y"); d.z = skeleton->RequireFloatAttribute(translate_elem, "z"); } if (rotate_elem) { TiXmlElement* axis_elem = skeleton->RequireFirstChild(rotate_elem, "axis"); angle = skeleton->RequireFloatAttribute(rotate_elem, "angle"); r.x = skeleton->RequireFloatAttribute(axis_elem, "x"); r.y = skeleton->RequireFloatAttribute(axis_elem, "y"); r.z = skeleton->RequireFloatAttribute(axis_elem, "z"); } if (scale_elem) { s.x = skeleton->RequireFloatAttribute(scale_elem, "x"); s.y = skeleton->RequireFloatAttribute(scale_elem, "y"); s.z = skeleton->RequireFloatAttribute(scale_elem, "z"); } frame.Transformation.scale = s; frame.Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r); frame.Transformation.translate = bone->InverseTransformation.rotate * (bone->InverseTransformation.scale * d); frame.Transformation = OgreToClonk::TransformTransformation(frame.Transformation); } } } } // is there even any xml file that we load from? // it looks like this could never work: if the mesh has no skeleton, then the code below will fail because of a null pointer... // Apply parent transformation to each bone transformation. We need to // do this late since animation keyframe computation needs the bone // transformations, not bone+parent. for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i) { // Apply parent transformation if (Skeleton->Bones[i]->Parent) Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation); else Skeleton->Bones[i]->Transformation = OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation); // Update inverse Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation); } StoreSkeleton(groupname, filename, Skeleton); }
void CmpCharacterModelRender::update_animation(int milliseconds) { // Decide which animation should be playing, and update it. ICmpAnimChooser_Ptr cmpAnimChooser = m_objectManager->get_component(m_objectID, cmpAnimChooser); assert(cmpAnimChooser); m_animController->request_animation(cmpAnimChooser->choose_animation()); m_animController->update(milliseconds); // Clear any existing pose modifiers. m_animController->clear_pose_modifiers(); // Determine the animation extension of any carried item in order to determine which bones need to be inclined. std::string animExtension = ""; // the explicit initialisation is to make it clear that "" is the default ICmpInventory_Ptr cmpInventory = m_objectManager->get_component(m_objectID, cmpInventory); assert(cmpInventory); ObjectID activeItem = cmpInventory->active_item(); if(activeItem.valid()) { ICmpOwnable_Ptr cmpItemOwnable = m_objectManager->get_component(activeItem, cmpItemOwnable); assert(cmpItemOwnable); animExtension = cmpItemOwnable->anim_extension(); } // Calculate the inclination of the object's coordinate system and apply pose modifiers to the relevant bones. BoneModifierMap::const_iterator it = m_inclineBones.find(animExtension); if(it != m_inclineBones.end()) { ICmpOrientation_Ptr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation); const Vector3d& n = cmpOrientation->nuv_axes()->n(); double sinInclination = n.z / n.length(); if(sinInclination < -1) sinInclination = -1; if(sinInclination > 1) sinInclination = 1; double inclination = asin(sinInclination); for(std::map<std::string,Vector3d>::const_iterator jt=it->second.begin(), jend=it->second.end(); jt!=jend; ++jt) { m_animController->set_pose_modifier(jt->first, PoseModifier(jt->second, -inclination)); } } // Configure the pose. m_modelPose = model()->configure_pose(m_animController); // Update the animation for the active item (if any), e.g. the weapon being carried. if(activeItem.valid()) { ICmpOrientation_CPtr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation); ICmpPosition_CPtr cmpPosition = m_objectManager->get_component(m_objectID, cmpPosition); const Vector3d& p = cmpPosition->position(); const Vector3d& n = cmpOrientation->nuv_axes()->n(); const Vector3d& u = cmpOrientation->nuv_axes()->u(); const Vector3d& v = cmpOrientation->nuv_axes()->v(); RBTMatrix_CPtr modelMatrix = construct_model_matrix(p, n, u, v); ICmpOwnable_Ptr cmpItemOwnable = m_objectManager->get_component(activeItem, cmpItemOwnable); assert(cmpItemOwnable); ICmpBasicModelRender_Ptr cmpItemRender = m_objectManager->get_component(activeItem, cmpItemRender); if(cmpItemRender) { cmpItemRender->update_child_animation(milliseconds, skeleton()->bone_hierarchy(), cmpItemOwnable->attach_point(), modelMatrix); } } }
void WldModel::readAnimatedModel(Frag11* f11) { WLD* wld = m_wld; PFS* pfs = getPFS(); ConvSkeleton& skele = skeleton(); Frag10* f10 = (Frag10*)wld->getFrag(f11->ref); if (!f10 || f10->type() != 0x10 || f10->boneCount() == 0) throw 3; //fixme int boneCount = f10->boneCount(); Frag10Bone* rootBone = f10->boneList(); Frag10Bone* binBone = rootBone; skele.init((uint32_t)boneCount); // Read and convert bones for (int i = 0; i < boneCount; i++) { Frag13* f13 = (Frag13*)wld->getFrag(binBone->refA); if (!f13 || f13->type() != 0x13) throw 4; //fixme Frag12* f12 = (Frag12*)wld->getFrag(f13->ref); if (!f12 || f12->type() != 0x12) throw 5; //fixme Vec3 pos; Quaternion rot; f12->entry[0].getPosRot(pos, rot); skele.setBone((uint32_t)i, pos, rot); const char* name = wld->getFragName(f13); skele.addBoneNameToIndex(name, (uint32_t)i); if (strstr(name, "_point_track")) { AttachPoint::Type attach = AttachPoint::Type::NONE; const char* p = name + 3; switch (*p) { case 't': attach = AttachPoint::Type::RightHand; break; case 'l': attach = AttachPoint::Type::LeftHand; break; case 'h': if (strstr(p, "head")) attach = AttachPoint::Type::Camera; break; case 's': if (strstr(p, "shield")) attach = AttachPoint::Type::Shield; break; } skele.setAttachPointType((uint32_t)i, attach); } binBone = binBone->next(); } // Read bone hierarchy binBone = rootBone; for (int i = 0; i < boneCount; i++) { if (binBone->size > 0) { int* index = binBone->indexList(); for (int j = 0; j < binBone->size; j++) { skele.addChild((uint32_t)i, (uint32_t)index[j]); } } binBone = binBone->next(); } skele.buildIndexMap(); // Read animations struct Frag12PlusBoneIndex { Frag12* f12; uint32_t frameRate; uint32_t boneIndex; }; std::unordered_map<int, std::vector<Frag12PlusBoneIndex>> animsById; for (Fragment* frag : wld->getFragsByType(0x13)) { Frag13* f13 = (Frag13*)frag; uint32_t index; const char* name = wld->getFragName(frag); if (!skele.getIndexByName(name + 3, index)) continue; int animId = getAnimId(name); Frag12* f12 = (Frag12*)wld->getFrag(f13->ref); if (!f12 || f12->type() != 0x12) continue; Frag12PlusBoneIndex fbi; fbi.f12 = f12; fbi.frameRate = f13->getFrameRate(); fbi.boneIndex = index; animsById[animId].push_back(fbi); } // Convert anims for (auto& p : animsById) { uint32_t frameCount = 0; uint32_t frameRate = 0; for (Frag12PlusBoneIndex& fbi : p.second) { Frag12* f12 = fbi.f12; if (f12->count > frameCount) frameCount = f12->count; if (frameRate == 0 && fbi.frameRate) frameRate = fbi.frameRate; } printf("anim %i frameRate: %u\n", p.first, frameRate); Animation* anim = Animation::create(frameCount, frameRate, boneCount); for (Frag12PlusBoneIndex& fbi : p.second) { anim->addFrames(fbi.boneIndex, fbi.f12); } addAnimation(p.first, anim); } // VertexBuffers and Head models int modelCount = 0; int* refs = f10->refList(modelCount); struct HeadId { uint32_t id; WldModel* head; }; std::vector<HeadId> heads; for (int i = 0; i < modelCount; i++) { Frag2d* f2d = (Frag2d*)wld->getFrag(refs[i]); if (!f2d || f2d->type() != 0x2d) continue; Frag36* f36 = (Frag36*)wld->getFrag(f2d->ref); if (!f36 || f36->type() != 0x36) continue; const char* name = wld->getFragName(f36); printf("%s\n", name); WldModel* model; if (name[3] == 'h' && name[4] == 'e') { model = new WldModel(pfs, wld); HeadId h; h.id = ::strtol(name + 5, nullptr, 10); h.head = model; heads.push_back(h); } else { model = this; } model->readMaterials(f36); model->readMesh(f36, false, &skele); } std::sort(heads.begin(), heads.end(), [](const HeadId& a, const HeadId& b) { return a.id < b.id; }); for (auto& h : heads) { addHeadModel(h.head); } }
bool CalSaver::saveXmlCoreSkeleton(const std::string& strFilename, CalCoreSkeleton *pCoreSkeleton) { std::stringstream str; vsxTiXmlDocument doc(strFilename); vsxTiXmlElement skeleton("SKELETON"); //skeleton.SetAttribute("MAGIC",Cal::SKELETON_XMLFILE_MAGIC); skeleton.SetAttribute("VERSION",Cal::LIBRARY_VERSION); skeleton.SetAttribute("NUMBONES",pCoreSkeleton->getVectorCoreBone().size()); int boneId; for(boneId = 0; boneId < (int)pCoreSkeleton->getVectorCoreBone().size(); ++boneId) { CalCoreBone* pCoreBone=pCoreSkeleton->getCoreBone(boneId); vsxTiXmlElement bone("BONE"); bone.SetAttribute("ID",boneId); bone.SetAttribute("NAME",pCoreBone->getName()); bone.SetAttribute("NUMCHILDS",pCoreBone->getListChildId().size()); vsxTiXmlElement translation("TRANSLATION"); const CalVector& translationVector = pCoreBone->getTranslation(); str.str(""); str << translationVector.x << " " << translationVector.y << " " << translationVector.z; vsxTiXmlText translationdata(str.str()); translation.InsertEndChild(translationdata); bone.InsertEndChild(translation); vsxTiXmlElement rotation("ROTATION"); const CalQuaternion& rotationQuad = pCoreBone->getRotation(); str.str(""); str << rotationQuad.x << " " << rotationQuad.y << " " << rotationQuad.z << " " << rotationQuad.w; vsxTiXmlText rotationdata(str.str()); rotation.InsertEndChild(rotationdata); bone.InsertEndChild(rotation); vsxTiXmlElement localtranslation("LOCALTRANSLATION"); const CalVector& localtranslationVector = pCoreBone->getTranslationBoneSpace(); str.str(""); str << localtranslationVector.x << " " << localtranslationVector.y << " " << localtranslationVector.z; vsxTiXmlText localtranslationdata(str.str()); localtranslation.InsertEndChild(localtranslationdata); bone.InsertEndChild(localtranslation); vsxTiXmlElement localrotation("LOCALROTATION"); const CalQuaternion& localrotationQuad = pCoreBone->getRotationBoneSpace(); str.str(""); str << localrotationQuad.x << " " << localrotationQuad.y << " " << localrotationQuad.z << " " << localrotationQuad.w; vsxTiXmlText localrotationdata(str.str()); localrotation.InsertEndChild(localrotationdata); bone.InsertEndChild(localrotation); vsxTiXmlElement parent("PARENTID"); str.str(""); str << pCoreBone->getParentId(); vsxTiXmlText parentid(str.str()); parent.InsertEndChild(parentid); bone.InsertEndChild(parent); // get children list std::list<int>& listChildId = pCoreBone->getListChildId(); // write all children ids std::list<int>::iterator iteratorChildId; for(iteratorChildId = listChildId.begin(); iteratorChildId != listChildId.end(); ++iteratorChildId) { vsxTiXmlElement child("CHILDID"); str.str(""); //int id=*iteratorChildId; str << *iteratorChildId; vsxTiXmlText childid(str.str()); child.InsertEndChild(childid); bone.InsertEndChild(child); } skeleton.InsertEndChild(bone); } doc.InsertEndChild(skeleton); if(!doc.SaveFile()) { CalError::setLastError(CalError::FILE_WRITING_FAILED, __FILE__, __LINE__, strFilename); return false; } return true; }