/src/org/mt4j/util/math/ConvexityUtil.java

http://mt4j.googlecode.com/ · Java · 297 lines · 105 code · 56 blank · 136 comment · 32 complexity · cb7d138f5b7fd245a94bd8e903178d55 MD5 · raw file

  1. /***********************************************************************
  2. * mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * 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 General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. ***********************************************************************/
  18. package org.mt4j.util.math;
  19. /**
  20. * Class to check whether a series of vectors which belong to
  21. * a polygon are convex or concave.
  22. * <p>C code from the article
  23. * "Testing the Convexity of a Polygon"
  24. * by Peter Schorn and Frederick Fisher,
  25. * (schorn@inf.ethz.ch, fred@kpc.com)
  26. * in "Graphics Gems IV", Academic Press, 1994
  27. * @author C.Ruff
  28. */
  29. public class ConvexityUtil {
  30. /** The Constant NotConvex. */
  31. public static final int NotConvex = 0;
  32. /** The Constant NotConvexDegenerate. */
  33. public static final int NotConvexDegenerate = 1;
  34. /** The Constant ConvexDegenerate. */
  35. public static final int ConvexDegenerate = 2;
  36. /** The Constant ConvexCCW. */
  37. public static final int ConvexCCW = 3;
  38. /** The Constant ConvexCW. */
  39. public static final int ConvexCW = 4;
  40. /*
  41. * C code from the article
  42. * "Testing the Convexity of a Polygon"
  43. * by Peter Schorn and Frederick Fisher,
  44. * (schorn@inf.ethz.ch, fred@kpc.com)
  45. * in "Graphics Gems IV", Academic Press, 1994
  46. */
  47. /* Reasonably Optimized Routine to Classify a Polygon's Shape */
  48. /*
  49. .. code omitted which reads polygon, stores in an array, and calls
  50. classifyPolygon2()
  51. */
  52. // typedef enum { NotConvex, NotConvexDegenerate,
  53. // ConvexDegenerate, ConvexCCW, ConvexCW } PolygonClass;
  54. //
  55. // typedef double Number; /* float or double */
  56. //
  57. // #define ConvexCompare(delta) \
  58. // ( (delta[0] > 0) ? -1 : /* x coord diff, second pt > first pt */\
  59. // (delta[0] < 0) ? 1 : /* x coord diff, second pt < first pt */\
  60. // (delta[1] > 0) ? -1 : /* x coord same, second pt > first pt */\
  61. // (delta[1] < 0) ? 1 : /* x coord same, second pt > first pt */\
  62. // 0 ) /* second pt equals first point */
  63. /**
  64. * Convex compare.
  65. *
  66. * @param delta the delta
  67. *
  68. * @return the int
  69. */
  70. private static int ConvexCompare(Vector3D delta){
  71. int returnval = (
  72. (delta.x > 0) ? -1 : /* x coord diff, second pt > first pt */
  73. (delta.x < 0) ? 1 : /* x coord diff, second pt < first pt */
  74. (delta.y > 0) ? -1 : /* x coord same, second pt > first pt */
  75. (delta.y < 0) ? 1 : /* x coord same, second pt > first pt */
  76. 0 );
  77. return returnval;
  78. }
  79. /**
  80. * Convex get point delta.
  81. *
  82. * @param delta the delta
  83. * @param pprev the pprev
  84. * @param pcur the pcur
  85. */
  86. private static void ConvexGetPointDelta(Vector3D delta, Vector3D pprev, Vector3D pcur) {
  87. pcur = pVert[iread++];
  88. delta.x = pcur.x - pprev.x;
  89. delta.y = pcur.y - pprev.y;
  90. }
  91. /**
  92. * Convex cross.
  93. *
  94. * @param p the p
  95. * @param q the q
  96. *
  97. * @return the float
  98. */
  99. private static float ConvexCross(Vector3D p, Vector3D q){
  100. return (p.x * q.y - p.y * q.x);
  101. }
  102. //
  103. // #define ConvexCheckTriple
  104. // if ( (thisDir = ConvexCompare(dcur)) == -curDir ) {
  105. // ++dirChanges;
  106. // /* The following line will optimize for polygons that are */
  107. // /* not convex because of classification condition 4, */
  108. // /* otherwise, this will only slow down the classification. */
  109. // /* if ( dirChanges > 2 ) return NotConvex; */
  110. // }
  111. // curDir = thisDir;
  112. // cross = ConvexCross(dprev, dcur);
  113. // if ( cross > 0 ) { if ( angleSign == -1 ) return NotConvex;
  114. // angleSign = 1;
  115. // }
  116. // else if (cross < 0) { if (angleSign == 1) return NotConvex;
  117. // angleSign = -1;
  118. // }
  119. // pSecond = pThird; /* Remember ptr to current point. */
  120. // dprev[0] = dcur[0]; /* Remember current delta. */
  121. // dprev[1] = dcur[1];
  122. /**
  123. * Convex check triple.
  124. *
  125. * @return the int
  126. */
  127. private static int ConvexCheckTriple(){
  128. if ( (thisDir = ConvexCompare(dcur)) == -curDir ) {
  129. ++dirChanges;
  130. // System.out.println("Dirchange! " + dirChanges);
  131. /* The following line will optimize for polygons that are */
  132. /* not convex because of classification condition 4, */
  133. /* otherwise, this will only slow down the classification. */
  134. /* if ( dirChanges > 2 ) return NotConvex; */
  135. }
  136. curDir = thisDir;
  137. cross = ConvexCross(dprev, dcur);
  138. if ( cross > 0 ) {
  139. if ( angleSign == -1 ){
  140. return NotConvex;
  141. }
  142. angleSign = 1;
  143. } else if (cross < 0) {
  144. if (angleSign == 1){
  145. return NotConvex; //TODO ander smachen
  146. // return NotConvexDegenerate;
  147. }
  148. angleSign = -1;
  149. }
  150. pSecond = pThird; /* Remember ptr to current point. */
  151. dprev.x = dcur.x; /* Remember current delta. */
  152. dprev.y = dcur.y;
  153. return -1;
  154. }
  155. /** The nvert. */
  156. private static int nvert;
  157. /** The p vert. */
  158. private static Vector3D[] pVert;
  159. /** The iread. */
  160. private static int
  161. curDir,
  162. thisDir,
  163. dirChanges = 0,
  164. angleSign = 0,
  165. iread ;
  166. /** The cross. */
  167. private static float cross;
  168. /** The dprev. */
  169. private static Vector3D dprev = new Vector3D(0,0,0);
  170. /** The dcur. */
  171. private static Vector3D dcur = new Vector3D(0,0,0);
  172. /** The p second. */
  173. private static Vector3D pSecond = new Vector3D(0,0,0);
  174. /** The p third. */
  175. private static Vector3D pThird = new Vector3D(0,0,0);
  176. /** The p save second. */
  177. private static Vector3D pSaveSecond = new Vector3D(0,0,0);
  178. /**
  179. * Classify polygon2.
  180. *
  181. * @param vertCount the vert count
  182. * @param pVerts the verts
  183. *
  184. * @return the int
  185. */
  186. public static int classifyPolygon2(int vertCount, Vector3D[] pVerts){
  187. nvert = vertCount;
  188. pVert = Vector3D.getDeepVertexArrayCopy(pVerts);
  189. // pVert = pVerts;
  190. /* if ( nvert <= 0 ) return error; if you care */
  191. /* Get different point, return if less than 3 diff points. */
  192. if ( nvert < 3 )
  193. return ConvexDegenerate;
  194. iread = 1;
  195. while ( true ) {
  196. ConvexGetPointDelta(dprev, pVert[0], pSecond);
  197. if ( dprev.x != 0 || dprev.y != 0)
  198. break;
  199. /* Check if out of points. Check here to avoid slowing down cases
  200. * without repeated points.
  201. */
  202. if ( iread >= nvert )
  203. return ConvexDegenerate;
  204. }
  205. pSaveSecond = pSecond;
  206. curDir = ConvexCompare(dprev); /* Find initial direction */
  207. while ( iread < nvert ) {
  208. /* Get different point, break if no more points */
  209. ConvexGetPointDelta(dcur, pSecond, pThird );
  210. if ( dcur.x == 0.0 && dcur.y == 0.0 )
  211. continue;
  212. if (ConvexCheckTriple() == NotConvex ){ /* Check current three points */
  213. return NotConvex;
  214. }
  215. }
  216. /* Must check for direction changes from last vertex back to first */
  217. pThird = pVert[0]; /* Prepare for 'ConvexCheckTriple' */
  218. dcur.x = pThird.x - pSecond.x;
  219. dcur.y = pThird.y - pSecond.y;
  220. if ( ConvexCompare(dcur) != 0) {
  221. if (ConvexCheckTriple() == NotConvex ){ /* Check current three points */
  222. return NotConvex;
  223. }
  224. }
  225. /* and check for direction changes back to second vertex */
  226. dcur.x = pSaveSecond.x - pSecond.x;
  227. dcur.y = pSaveSecond.y - pSecond.y;
  228. if (ConvexCheckTriple() == NotConvex ){ /* Don't care about 'pThird' now */
  229. return NotConvex;
  230. }
  231. /* Decide on polygon type given accumulated status */
  232. if ( dirChanges > 2 )
  233. return (angleSign != 0 ) ? NotConvex : NotConvexDegenerate;
  234. if ( angleSign > 0 )
  235. return ConvexCCW;
  236. if ( angleSign < 0 )
  237. return ConvexCW;
  238. return ConvexDegenerate;
  239. }
  240. }