PageRenderTime 43ms CodeModel.GetById 85ms RepoModel.GetById 1ms app.codeStats 0ms

/CS/migrated/branches/R0_16/libs/csgeom/poly2d.cpp

#
C++ | 411 lines | 303 code | 36 blank | 72 comment | 67 complexity | 9ebad0a5375a29714de4fc3c9f9848fb MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Copyright (C) 1998 by Jorrit Tyberghein
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this library; if not, write to the Free
  13. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "cssysdef.h"
  16. #include "csgeom/poly2d.h"
  17. #include "csgeom/polyclip.h"
  18. csPoly2DFactory* csPoly2DFactory::SharedFactory()
  19. {
  20. static csPoly2DFactory p;
  21. return &p;
  22. }
  23. csPoly2D::csPoly2D (int start_size)
  24. {
  25. max_vertices = start_size;
  26. vertices = new csVector2 [max_vertices];
  27. MakeEmpty ();
  28. }
  29. csPoly2D::csPoly2D (const csPoly2D& copy)
  30. {
  31. max_vertices = copy.max_vertices;
  32. vertices = new csVector2 [max_vertices];
  33. num_vertices = copy.num_vertices;
  34. memcpy (vertices, copy.vertices, sizeof (csVector2)*num_vertices);
  35. bbox = copy.bbox;
  36. }
  37. csPoly2D& csPoly2D::operator= (const csPoly2D& other)
  38. {
  39. if (other.num_vertices <= max_vertices)
  40. {
  41. num_vertices = other.num_vertices;
  42. if (num_vertices)
  43. memcpy (vertices, other.vertices, sizeof (csVector2)*num_vertices);
  44. }
  45. else
  46. {
  47. delete [] vertices;
  48. max_vertices = other.max_vertices;
  49. vertices = new csVector2 [max_vertices];
  50. num_vertices = other.num_vertices;
  51. if (num_vertices)
  52. memcpy (vertices, other.vertices, sizeof (csVector2)*num_vertices);
  53. }
  54. bbox = other.bbox;
  55. return *this;
  56. }
  57. csPoly2D::~csPoly2D ()
  58. {
  59. delete [] vertices;
  60. }
  61. void csPoly2D::MakeEmpty ()
  62. {
  63. num_vertices = 0;
  64. bbox.StartBoundingBox ();
  65. }
  66. bool csPoly2D::In (const csVector2& v)
  67. {
  68. int i, i1;
  69. i1 = num_vertices-1;
  70. for (i = 0 ; i < num_vertices ; i++)
  71. {
  72. if (csMath2::WhichSide2D (v, vertices[i1], vertices[i]) < 0) return false;
  73. i1 = i;
  74. }
  75. return true;
  76. }
  77. bool csPoly2D::In (csVector2* poly, int num_poly, const csVector2& v)
  78. {
  79. int i, i1;
  80. i1 = num_poly-1;
  81. for (i = 0 ; i < num_poly ; i++)
  82. {
  83. if (csMath2::WhichSide2D (v, poly[i1], poly[i]) < 0) return false;
  84. i1 = i;
  85. }
  86. return true;
  87. }
  88. void csPoly2D::MakeRoom (int new_max)
  89. {
  90. if (new_max <= max_vertices) return;
  91. csVector2* new_vertices = new csVector2 [new_max];
  92. memcpy (new_vertices, vertices, num_vertices*sizeof (csVector2));
  93. delete [] vertices;
  94. vertices = new_vertices;
  95. max_vertices = new_max;
  96. }
  97. int csPoly2D::AddVertex (float x, float y)
  98. {
  99. if (num_vertices >= max_vertices)
  100. MakeRoom (max_vertices+5);
  101. vertices[num_vertices].x = x;
  102. vertices[num_vertices].y = y;
  103. num_vertices++;
  104. bbox.AddBoundingVertex (x, y);
  105. return num_vertices-1;
  106. }
  107. void csPoly2D::UpdateBoundingBox ()
  108. {
  109. int i;
  110. bbox.StartBoundingBox (vertices[0]);
  111. for (i = 1 ; i < num_vertices ; i++)
  112. bbox.AddBoundingVertex (vertices[i]);
  113. }
  114. bool csPoly2D::ClipAgainst (csClipper *view)
  115. {
  116. MakeRoom (num_vertices + view->GetNumVertices () + 1);
  117. return view->Clip (vertices, num_vertices, bbox);
  118. }
  119. void csPoly2D::Intersect (const csPlane2& plane,
  120. csPoly2D& left, csPoly2D& right) const
  121. {
  122. int i, i1;
  123. float c, c1;
  124. csVector2 isect;
  125. float dist;
  126. // The skip variables hold the number of initial skipped vertices.
  127. // Those are vertices that are on the plane so in principle they should
  128. // get added to both polygons. However, we try not to generate degenerate
  129. // polygons (one edge only) so we only add those plane-vertices if
  130. // we know that the polygon has other vertices too.
  131. int skip_left = 0, skip_right = 0;
  132. // Ignore the specified number of vertices in the beginning (just
  133. // before skip_??? vertices).
  134. int ignore_left = 0, ignore_right = 0;
  135. left.MakeEmpty ();
  136. right.MakeEmpty ();
  137. i1 = num_vertices-1;
  138. c1 = plane.Classify (vertices[i1]);
  139. for (i = 0 ; i < num_vertices ; i++)
  140. {
  141. c = plane.Classify (vertices[i]);
  142. if (c > -EPSILON && c < EPSILON)
  143. {
  144. // This vertex is on the edge. Add it to both polygons
  145. // unless the polygon has no vertices yet. In that
  146. // case we remember it for later (skip_xxx var) so
  147. // that we can later add them if the polygon ever
  148. // gets vertices.
  149. if (left.GetNumVertices ())
  150. left.AddVertex (vertices[i]);
  151. else
  152. skip_left++;
  153. if (right.GetNumVertices ())
  154. right.AddVertex (vertices[i]);
  155. else
  156. skip_right++;
  157. }
  158. else if (c <= -EPSILON && c1 < EPSILON)
  159. {
  160. // This vertex is on the left and the previous
  161. // vertex is not right (i.e. on the left or on the edge).
  162. left.AddVertex (vertices[i]);
  163. if (!skip_right && !right.GetNumVertices ())
  164. ignore_right++;
  165. }
  166. else if (c >= EPSILON && c1 > -EPSILON)
  167. {
  168. // This vertex is on the right and the previous
  169. // vertex is not left.
  170. right.AddVertex (vertices[i]);
  171. if (!skip_left && !left.GetNumVertices ())
  172. ignore_left++;
  173. }
  174. else
  175. {
  176. // We need to split.
  177. csIntersect2::Plane (vertices[i1], vertices[i],
  178. plane, isect, dist);
  179. right.AddVertex (isect);
  180. left.AddVertex (isect);
  181. if (c <= 0)
  182. left.AddVertex (vertices[i]);
  183. else
  184. right.AddVertex (vertices[i]);
  185. }
  186. i1 = i;
  187. c1 = c;
  188. }
  189. // If skip_xxx > 0 then there are a number of vertices in
  190. // the beginning that we ignored. These vertices are all on
  191. // 'plane'. We will add them to the corresponding polygon if
  192. // that polygon is not empty.
  193. i = ignore_left;
  194. if (left.GetNumVertices ())
  195. while (skip_left > 0)
  196. {
  197. left.AddVertex (vertices[i]);
  198. i++;
  199. skip_left--;
  200. }
  201. i = ignore_right;
  202. if (right.GetNumVertices ())
  203. while (skip_right > 0)
  204. {
  205. right.AddVertex (vertices[i]);
  206. i++;
  207. skip_right--;
  208. }
  209. }
  210. void csPoly2D::ClipPlane (const csPlane2& plane, csPoly2D& right) const
  211. {
  212. int i, i1;
  213. float c, c1;
  214. csVector2 isect;
  215. float dist;
  216. // The skip variables hold the number of initial skipped vertices.
  217. // Those are vertices that are on the plane so in principle they should
  218. // get added to both polygons. However, we try not to generate degenerate
  219. // polygons (one edge only) so we only add those plane-vertices if
  220. // we know that the polygon has other vertices too.
  221. int skip_right = 0;
  222. // Ignore the specified number of vertices in the beginning (just
  223. // before skip_right vertices).
  224. int ignore_right = 0;
  225. right.MakeEmpty ();
  226. i1 = num_vertices-1;
  227. c1 = plane.Classify (vertices[i1]);
  228. for (i = 0 ; i < num_vertices ; i++)
  229. {
  230. c = plane.Classify (vertices[i]);
  231. if (c > -EPSILON && c < EPSILON)
  232. {
  233. // This vertex is on the edge. Add it to both polygons
  234. // unless the polygon has no vertices yet. In that
  235. // case we remember it for later (skip_xxx var) so
  236. // that we can later add them if the polygon ever
  237. // gets vertices.
  238. if (right.GetNumVertices ())
  239. right.AddVertex (vertices[i]);
  240. else
  241. skip_right++;
  242. }
  243. else if (c <= -EPSILON && c1 < EPSILON)
  244. {
  245. // This vertex is on the left and the previous
  246. // vertex is not right (i.e. on the left or on the edge).
  247. if (!skip_right && !right.GetNumVertices ())
  248. ignore_right++;
  249. }
  250. else if (c >= EPSILON && c1 > -EPSILON)
  251. {
  252. // This vertex is on the right and the previous
  253. // vertex is not left.
  254. right.AddVertex (vertices[i]);
  255. }
  256. else
  257. {
  258. // We need to split.
  259. csIntersect2::Plane (vertices[i1], vertices[i],
  260. plane, isect, dist);
  261. right.AddVertex (isect);
  262. if (c > 0)
  263. right.AddVertex (vertices[i]);
  264. }
  265. i1 = i;
  266. c1 = c;
  267. }
  268. // If skip_xxx > 0 then there are a number of vertices in
  269. // the beginning that we ignored. These vertices are all on
  270. // 'plane'. We will add them to the corresponding polygon if
  271. // that polygon is not empty.
  272. i = ignore_right;
  273. if (right.GetNumVertices ())
  274. while (skip_right > 0)
  275. {
  276. right.AddVertex (vertices[i]);
  277. i++;
  278. skip_right--;
  279. }
  280. }
  281. void csPoly2D::ExtendConvex (const csPoly2D& other, int this_edge)
  282. {
  283. int this_edge2 = (this_edge+1)%num_vertices;
  284. int i, i1, j;
  285. // First clip the other polygon to the two edges from this polygon
  286. // that connect to the shared edge. This way we can reduce the algorithm
  287. // to just having to connect the two remaining polygons. The resulting
  288. // connection will be convex.
  289. csPoly2D other1;
  290. csPlane2 pl;
  291. pl.Set (vertices[(this_edge-1+num_vertices)%num_vertices],
  292. vertices[this_edge]);
  293. other.ClipPlane (pl, other1);
  294. if (other1.GetNumVertices () < 0) return; // Nothing to be done.
  295. csPoly2D other2;
  296. pl.Set (vertices[this_edge2], vertices[(this_edge2+1)%num_vertices]);
  297. other1.ClipPlane (pl, other2);
  298. if (other2.GetNumVertices () < 0) return; // Nothing to be done.
  299. // Find the common edge in this new polygon.
  300. int other_edge = -1, other_edge2 = -1;
  301. for (i = 0 ; i < other2.GetNumVertices () ; i++)
  302. {
  303. if ((vertices[this_edge]-other2[i]) < EPSILON)
  304. other_edge2 = i;
  305. if ((vertices[this_edge2]-other2[i]) < EPSILON)
  306. other_edge = i;
  307. }
  308. if (other_edge == -1 || other_edge2 == -1)
  309. printf ("INTERNAL ERROR: csPoly2D::ExtendConvex\n");
  310. csPoly2D orig (*this);
  311. MakeEmpty ();
  312. // Now join the two polygons. Note that this function
  313. // assumes that the two polygons are oriented the same way.
  314. // i.e. the polygons go along the adjacent edge in seperate directions.
  315. i1 = orig.num_vertices-1;
  316. for (i = 0 ; i < orig.num_vertices ; i++)
  317. {
  318. // Join other polygon.
  319. if (i == this_edge)
  320. {
  321. j = (other_edge2+1)%other2.GetNumVertices ();
  322. while (j != other_edge)
  323. {
  324. AddVertex (other2[j]);
  325. j = (j+1)%other2.GetNumVertices ();
  326. }
  327. }
  328. else if (i == this_edge2)
  329. {
  330. // Ignore this edge.
  331. }
  332. else if (i1 == this_edge2)
  333. {
  334. AddVertex (orig[i]);
  335. }
  336. else
  337. {
  338. AddVertex (orig[i]);
  339. }
  340. i1 = i;
  341. }
  342. }
  343. float csPoly2D::GetSignedArea ()
  344. {
  345. float area = 0.0;
  346. // triangulize the polygon, triangles are (0,1,2), (0,2,3), (0,3,4), etc..
  347. for (int i=0 ; i < GetNumVertices()-2 ; i++)
  348. area += csMath2::Area2 ( vertices[0], vertices[i+1], vertices[i+2] );
  349. return area / 2.0;
  350. }
  351. static float randflt ()
  352. {
  353. return ((float)rand ()) / RAND_MAX;
  354. }
  355. void csPoly2D::Random (int num, const csBox2& max_bbox)
  356. {
  357. MakeEmpty ();
  358. int i;
  359. csVector2 v;
  360. float w = max_bbox.MaxX () - max_bbox.MinX ();
  361. float h = max_bbox.MaxY () - max_bbox.MinY ();
  362. float dx = max_bbox.MinX ();
  363. float dy = max_bbox.MinY ();
  364. for (i = 0 ; i < 3 ; i++)
  365. {
  366. v.Set (randflt ()*w+dx, randflt ()*h+dy);
  367. AddVertex (v);
  368. }
  369. // @@@ Only triangles are supported right now.
  370. (void)num;
  371. }
  372. //---------------------------------------------------------------------------