1 /*
2 *	Copyright (C) 2008-2012 Thorsten Liebig (Thorsten.Liebig@gmx.de)
3 *
4 *	This program is free software: you can redistribute it and/or modify
5 *	it under the terms of the GNU Lesser General Public License as published
6 *	by the Free Software Foundation, either version 3 of the License, or
7 *	(at your option) any later version.
8 *
9 *	This program is distributed in the hope that it will be useful,
10 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *	GNU Lesser General Public License for more details.
13 *
14 *	You should have received a copy of the GNU Lesser General Public License
15 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include <sstream>
19 #include <iostream>
20 #include <limits>
21 #include "tinyxml.h"
22 #include "stdint.h"
23 
24 #include "CSPrimPolygon.h"
25 #include "CSProperties.h"
26 #include "CSUseful.h"
27 
CSPrimPolygon(unsigned int ID,ParameterSet * paraSet,CSProperties * prop)28 CSPrimPolygon::CSPrimPolygon(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop)
29 {
30 	Type=POLYGON;
31 	m_NormDir = 0;
32 	Elevation.SetParameterSet(paraSet);
33 	PrimTypeName = std::string("Polygon");
34 }
35 
CSPrimPolygon(CSPrimPolygon * primPolygon,CSProperties * prop)36 CSPrimPolygon::CSPrimPolygon(CSPrimPolygon* primPolygon, CSProperties *prop) : CSPrimitives(primPolygon,prop)
37 {
38 	Type=POLYGON;
39 	m_NormDir = primPolygon->m_NormDir;
40 	Elevation.Copy(&primPolygon->Elevation);
41 	PrimTypeName = std::string("Polygon");
42 }
43 
CSPrimPolygon(ParameterSet * paraSet,CSProperties * prop)44 CSPrimPolygon::CSPrimPolygon(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop)
45 {
46 	Type=POLYGON;
47 	m_NormDir = 0;
48 	Elevation.SetParameterSet(paraSet);
49 	PrimTypeName = std::string("Polygon");
50 }
51 
~CSPrimPolygon()52 CSPrimPolygon::~CSPrimPolygon()
53 {
54 }
55 
GetCopy(CSProperties * prop)56 CSPrimPolygon* CSPrimPolygon::GetCopy(CSProperties *prop) {return new CSPrimPolygon(this,prop);}
57 
SetCoord(int index,double val)58 void CSPrimPolygon::SetCoord(int index, double val)
59 {
60 	if ((index>=0) && (index<(int)vCoords.size())) vCoords.at(index).SetValue(val);
61 }
62 
SetCoord(int index,const std::string val)63 void CSPrimPolygon::SetCoord(int index, const std::string val)
64 {
65 	if ((index>=0) && (index<(int)vCoords.size())) vCoords.at(index).SetValue(val);
66 }
67 
AddCoord(double val)68 void CSPrimPolygon::AddCoord(double val)
69 {
70 	vCoords.push_back(ParameterScalar(clParaSet,val));
71 }
72 
AddCoord(const std::string val)73 void CSPrimPolygon::AddCoord(const std::string val)
74 {
75 	vCoords.push_back(ParameterScalar(clParaSet,val));
76 }
77 
RemoveCoords(int)78 void CSPrimPolygon::RemoveCoords(int /*index*/)
79 {
80 	//not yet implemented
81 }
82 
GetCoord(int index)83 double CSPrimPolygon::GetCoord(int index)
84 {
85 	if ((index>=0) && (index<(int)vCoords.size())) return vCoords.at(index).GetValue();
86 	return 0;
87 }
88 
GetCoordPS(int index)89 ParameterScalar* CSPrimPolygon::GetCoordPS(int index)
90 {
91 	if ((index>=0) && (index<(int)vCoords.size())) return &vCoords.at(index);
92 	return NULL;
93 }
94 
GetQtyCoords()95 size_t CSPrimPolygon::GetQtyCoords() {return vCoords.size()/2;}
96 
GetAllCoords(size_t & Qty,double * array)97 double* CSPrimPolygon::GetAllCoords(size_t &Qty, double* array)
98 {
99 	Qty=vCoords.size();
100 	delete[] array;
101 	array = new double[Qty];
102 	for (size_t i=0;i<Qty;++i) array[i]=vCoords.at(i).GetValue();
103 	return array;
104 }
105 
SetNormDir(int dir)106 void CSPrimPolygon::SetNormDir(int dir) {if ((dir>=0) && (dir<3)) m_NormDir=dir;}
107 
GetBoundBox(double dBoundBox[6],bool PreserveOrientation)108 bool CSPrimPolygon::GetBoundBox(double dBoundBox[6], bool PreserveOrientation)
109 {
110 	UNUSED(PreserveOrientation); //has no orientation or preserved anyways
111 	bool accurate=false;
112 	m_BoundBox_CoordSys = CARTESIAN;
113 	if (vCoords.size()<2)
114 	{
115 		for (int i=0;i<6;++i) dBoundBox[i]=0;
116 		return dBoundBox;
117 	}
118 	double xmin = vCoords.at(0).GetValue(), xmax = vCoords.at(0).GetValue();
119 	double ymin = vCoords.at(1).GetValue(), ymax = vCoords.at(1).GetValue();
120 	for (size_t i=1;i<vCoords.size()/2;++i)
121 	{
122 		double x = vCoords.at(2*i).GetValue();
123 		double y = vCoords.at(2*i+1).GetValue();
124 		if (x<xmin) xmin=x;
125 		else if (x>xmax) xmax=x;
126 		if (y<ymin) ymin=y;
127 		else if (y>ymax) ymax=y;
128 	}
129 	int nP = (m_NormDir+1)%3;
130 	int nPP = (m_NormDir+2)%3;
131 	dBoundBox[2*m_NormDir] = dBoundBox[2*m_NormDir+1] = Elevation.GetValue();
132 	dBoundBox[2*nP] = xmin;
133 	dBoundBox[2*nP+1] = xmax;
134 	dBoundBox[2*nPP] = ymin;
135 	dBoundBox[2*nPP+1] = ymax;
136 	m_Dimension=0;
137 	for (int n=0;n<3;++n)
138 	{
139 		if (dBoundBox[2*n]!=dBoundBox[2*n+1])
140 			++m_Dimension;
141 	}
142 	return accurate;
143 }
144 
IsInside(const double * inCoord,double)145 bool CSPrimPolygon::IsInside(const double* inCoord, double /*tol*/)
146 {
147 	if (inCoord==NULL) return false;
148 	if (vCoords.size()<2) return false;
149 
150 	double Coord[3];
151 	//transform incoming coordinates into cartesian coords
152 	TransformCoordSystem(inCoord,Coord,m_MeshType,CARTESIAN);
153 	if (m_Transform && Type==POLYGON)
154 		TransformCoords(Coord,true, CARTESIAN);
155 
156 	for (unsigned int n=0;n<3;++n)
157 		if ((m_BoundBox[2*n]>Coord[n]) || (m_BoundBox[2*n+1]<Coord[n])) return false;
158 
159 	double x=0,y=0;
160 	int nP = (m_NormDir+1)%3;
161 	int nPP = (m_NormDir+2)%3;
162 	x = Coord[nP];
163 	y = Coord[nPP];
164 
165 	int wn = 0;
166 
167 	size_t np = vCoords.size()/2;
168 	double x1 = vCoords[2*np-2].GetValue();
169 	double y1 = vCoords[2*np-1].GetValue();
170 	double x2 = vCoords[0].GetValue();
171 	double y2 = vCoords[1].GetValue();
172 	bool startover = y1 >= y ? true : false;
173 	bool endover;
174 
175 	for (size_t i=0;i<np;++i)
176 	{
177 		x2 = vCoords[2*i].GetValue();
178 		y2 = vCoords[2*i+1].GetValue();
179 
180 		//check if coord is on a cartesian edge exactly
181 		if ((x2==x1) && (x1==x) && ( ((y<y1) && (y>y2)) || ((y>y1) && (y<y2)) ))
182 			return true;
183 		if ((y2==y1) && (y1==y) && ( ((x<x1) && (x>x2)) || ((x>x1) && (x<x2)) ))
184 			return true;
185 
186 		endover = y2 >= y ? true : false;
187 		if (startover != endover)
188 		{
189 			if ((y2 - y)*(x2 - x1) <= (y2 - y1)*(x2 - x))
190 			{
191 				if (endover) wn ++;
192 			}
193 			else
194 			{
195 				if (!endover) wn --;
196 			}
197 		}
198 		startover = endover;
199 		y1 = y2;
200 		x1 = x2;
201 	}
202 	// return true if polygon is inside the polygon
203 	if (wn != 0)
204 		return true;
205 
206 	return false;
207 }
208 
209 
Update(std::string * ErrStr)210 bool CSPrimPolygon::Update(std::string *ErrStr)
211 {
212 	int EC=0;
213 	bool bOK=true;
214 	if (! ((m_PrimCoordSystem==CARTESIAN) || (m_PrimCoordSystem==UNDEFINED_CS && m_MeshType==CARTESIAN)))
215 	{
216 		std::cerr << "CSPrimPolygon::Update: Warning: CSPrimPolygon can not be defined in non Cartesian coordinate systems! Result may be unexpected..." << std::endl;
217 		ErrStr->append("Warning: CSPrimPolygon can not be defined in non Cartesian coordinate systems! Result may be unexpected...\n");
218 	}
219 	for (size_t i=1;i<vCoords.size();++i)
220 	{
221 		EC=vCoords[i].Evaluate();
222 		if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
223 		if ((EC!=ParameterScalar::PS_NO_ERROR)  && (ErrStr!=NULL))
224 		{
225 			bOK=false;
226 			std::stringstream stream;
227 			stream << std::endl << "Error in Polygon (ID: " << uiID << "): ";
228 			ErrStr->append(stream.str());
229 			PSErrorCode2Msg(EC,ErrStr);
230 		}
231 	}
232 
233 	EC=Elevation.Evaluate();
234 	if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
235 	if ((EC!=ParameterScalar::PS_NO_ERROR)  && (ErrStr!=NULL))
236 	{
237 		bOK=false;
238 		std::stringstream stream;
239 		stream << std::endl << "Error in Polygon Elevation (ID: " << uiID << "): ";
240 		ErrStr->append(stream.str());
241 		PSErrorCode2Msg(EC,ErrStr);
242 	}
243 
244 	//update local bounding box used to speedup IsInside()
245 	m_BoundBoxValid = GetBoundBox(m_BoundBox);
246 
247 	return bOK;
248 }
249 
Write2XML(TiXmlElement & elem,bool parameterised)250 bool CSPrimPolygon::Write2XML(TiXmlElement &elem, bool parameterised)
251 {
252 	CSPrimitives::Write2XML(elem,parameterised);
253 
254 	WriteTerm(Elevation,elem,"Elevation",parameterised);
255 
256 	elem.SetAttribute("NormDir",m_NormDir);
257 
258 	elem.SetAttribute("QtyVertices",(int)vCoords.size()/2);
259 
260 	for (size_t i=0;i<vCoords.size()/2;++i)
261 	{
262 		TiXmlElement VT("Vertex");
263 		WriteTerm(vCoords.at(i*2),VT,"X1",parameterised);
264 		WriteTerm(vCoords.at(i*2+1),VT,"X2",parameterised);
265 		elem.InsertEndChild(VT);
266 	}
267 	return true;
268 }
269 
ReadFromXML(TiXmlNode & root)270 bool CSPrimPolygon::ReadFromXML(TiXmlNode &root)
271 {
272 	if (CSPrimitives::ReadFromXML(root)==false) return false;
273 
274 	TiXmlElement *elem = root.ToElement();
275 	if (elem==NULL) return false;
276 	if (ReadTerm(Elevation,*elem,"Elevation")==false)
277 		Elevation.SetValue(0);
278 
279 	int help;
280 	if (elem->QueryIntAttribute("NormDir",&help)!=TIXML_SUCCESS)
281 		 return false;
282 	m_NormDir=help;
283 
284 	TiXmlElement *VT=root.FirstChildElement("Vertex");
285 	if (vCoords.size()!=0) return false;
286 	int i=0;
287 	while (VT)
288 	{
289 		for (int n=0;n<2;++n) this->AddCoord(0.0);
290 
291 		if (ReadTerm(vCoords.at(i*2),*VT,"X1")==false) return false;
292 		if (ReadTerm(vCoords.at(i*2+1),*VT,"X2")==false) return false;
293 
294 		VT=VT->NextSiblingElement("Vertex");
295 		++i;
296 	};
297 
298 	return true;
299 }
300