1 /*******************************************************************************
2 Copyright (c) 2012, Jonathan Hiller
3
4 This file is part of the AMF Tools suite. http://amf.wikispaces.com/
5 AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6 AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
7 See <http://www.opensource.org/licenses/lgpl-3.0.html> for license details.
8 *******************************************************************************/
9
10 #include "nConstellation.h"
11 #include "XmlStream.h"
12 #include "nAmf.h"
13
nConstellation(nAmf * pnAmfIn)14 nConstellation::nConstellation(nAmf* pnAmfIn)
15 {
16 pnAmf = pnAmfIn;
17 Clear();
18 }
19
20
~nConstellation(void)21 nConstellation::~nConstellation(void)
22 {
23 }
24
operator =(const nConstellation & In)25 nConstellation& nConstellation::operator=(const nConstellation& In)
26 {
27 aID = In.aID;
28 Instances = In.Instances;
29 Metadata = In.Metadata;
30
31 pnAmf = In.pnAmf;
32
33 return *this;
34 }
35
36
Clear(void)37 void nConstellation::Clear(void)
38 {
39 aID = pnAmf->GetUnusedGeoID();
40 Instances.clear();
41 Metadata.clear();
42
43 }
44
WriteXML(CXmlStreamWrite * pXML,std::string * pMessage)45 bool nConstellation::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage)
46 {
47 pXML->OpenElement("constellation");
48 pXML->SetElAttI("id", aID);
49
50 for(std::vector<nMetadata>::iterator it = Metadata.begin(); it != Metadata.end(); it++){
51 if (!it->WriteXML(pXML, pMessage)) return false;
52 }
53
54 for(std::vector<nInstance>::iterator it = Instances.begin(); it != Instances.end(); it++){
55 if (!it->WriteXML(pXML, pMessage)) return false;
56 }
57
58 pXML->CloseElement();
59 return true;
60 }
61
62
ReadXML(CXmlStreamRead * pXML,nAmf * pAmf,bool StrictLoad,std::string * pMessage)63 bool nConstellation::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage)
64 {
65 Clear();
66
67 if (!pXML->GetElAttI("id", &aID)) aID = -1;
68
69 //read as many metadata tags as there are...
70 nMetadata tmpMeta;
71 while(pXML->OpenElement("metadata", true)){ //<metadata>
72 if (!tmpMeta.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false;
73 Metadata.push_back(tmpMeta);
74 }
75 // if (Metadata.size() != 0) pXML->UpLevel(); //</metadata>
76
77 //read as many instance tags as there are...
78 nInstance tmpInst;
79 while(pXML->OpenElement("instance", true)){ //<Vertex>
80 if (!tmpInst.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false;
81 Instances.push_back(tmpInst);
82 }
83 // if (Instances.size() != 0) pXML->UpLevel(); //</triangle>
84
85
86 return CheckValid(pAmf, !StrictLoad, pMessage);
87 }
88
CheckValid(nAmf * pAmf,bool FixNode,std::string * pMessage)89 bool nConstellation::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage)
90 {
91
92
93 //Check for invalid geometry ID
94 if (aID < 0 || pAmf->IsDuplicateGeoID(aID)){
95 if (FixNode) {
96 aID = pAmf->GetUnusedGeoID();
97 if (pMessage) *pMessage += "Warning: Invalid or duplicate geometry ID found. Setting to an unused ID. Constellations may need to be adjusted.\n";
98 }
99 else {
100 if (pMessage) *pMessage += "Error: Invalid or duplicate geometry ID found.\n";
101 return false;
102 }
103 }
104
105 //check for no instances (just a warning...)
106 if (Instances.size() == 0 && pMessage) {*pMessage += "Constellation found with no instances.\n"; }
107
108 //Check for invalid geometry IDs in instances (here instead of nInstance so we can delete effonding ones to fix Amf)
109 std::vector<int> InsIndToDelete;
110 int count=0;
111 for (std::vector<nInstance>::iterator it = Instances.begin(); it!=Instances.end(); it++){
112 if (it->aObjectID < 0 || (pAmf->GetObjectByID(it->aObjectID) == NULL && pAmf->GetConstellationByID(it->aObjectID) == NULL)){
113 if (FixNode) {
114 InsIndToDelete.push_back(count);
115 if (pMessage) *pMessage += "Warning: Invalid geometry ID in instance. Deleting instance.\n";
116 }
117 else {
118 if (pMessage) *pMessage += "Error: Invalid geometry ID in instance.\n";
119 return false;
120 }
121 }
122 count++;
123 }
124 for (int i=InsIndToDelete.size()-1; i >= 0; i--) Instances.erase(Instances.begin()+InsIndToDelete[i]); //go backwards so out indices stay correct...
125
126
127 return true;
128 }
129
SetName(std::string NewName)130 void nConstellation::SetName(std::string NewName)
131 {
132 for (std::vector<nMetadata>::iterator it = Metadata.begin(); it != Metadata.end(); it++){
133 if(it->Type == MD_NAME){
134 it->Data = NewName; //replace the name!!
135 return;
136 }
137 }
138
139 //if we get here there was no existing Name metadata so add one...
140 Metadata.push_back(nMetadata(MD_NAME, NewName));
141 }
142
GetName(void)143 std::string nConstellation::GetName(void)
144 {
145 for (std::vector<nMetadata>::iterator it = Metadata.begin(); it != Metadata.end(); it++){
146 if(it->Type == MD_NAME) return it->Data;
147 }
148 return "";
149 }
150
IsReferencedBy(nConstellation * pConstellationCheck)151 bool nConstellation::IsReferencedBy(nConstellation* pConstellationCheck) //returns true if pUsesCheck references pCheck anywhere in its tree.
152 {
153 if (aID == pConstellationCheck->aID) return true;
154
155 nConstellation* pTmpConst;
156 std::vector<nConstellation*> OpenList; //list of constellations referenced by pUsesCheck
157 OpenList.reserve(1000); //allcoate maximum reasonable number of materials because using iterators with a push-back inside loop can cause re-allocation and therefore bad iterator.
158 OpenList.push_back(pConstellationCheck);
159
160 for(std::vector<nConstellation*>::iterator jt = OpenList.begin(); jt != OpenList.end(); jt++){
161 for(std::vector<nInstance>::iterator it = (*jt)->Instances.begin(); it != (*jt)->Instances.end(); it++){
162 // for (int i=0; i<(*jt)->Instances.size(); i++){
163 pTmpConst = pnAmf->GetConstellationByID(it->aObjectID);
164 if (pTmpConst){ //if this id is a constellation
165 //check to see if it's already on the open list. If not, add it.
166 bool inList = false;
167 for (int i=0; i<(int)OpenList.size(); i++){
168 if (OpenList[i] == pTmpConst){
169 inList = true;
170 break;
171 }
172 }
173 if (!inList){
174 OpenList.push_back(pTmpConst);
175 if (aID == pTmpConst->aID) return true; //we've found a recursion back to the one we're checking against!
176 }
177 }
178 }
179
180 }
181 return false;
182 }
183