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