PageRenderTime 55ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/src/org/omoa/util/GeometryFunctions.as

http://github.com/omoa/omoa-as3
ActionScript | 214 lines | 176 code | 18 blank | 20 comment | 33 complexity | 703d31a32a3c2c0f0d8f91f98d3ff25d MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. package org.omoa.util
  2. {
  3. import flash.display.GraphicsPath;
  4. import flash.display.GraphicsPathCommand;
  5. import flash.geom.Point;
  6. import org.omoa.framework.BoundingBox;
  7. /**
  8. * ...
  9. * @author SKS
  10. */
  11. public class GeometryFunctions {
  12. public function GeometryFunctions() {}
  13. /**
  14. * Calculates the bounding values from a GraphicsPath object. This bounding box includes
  15. * all existing points including control points of curves.
  16. * @param bb A BoundingBox instance - will be overwritten.
  17. * @param path A GraphicsPath instance.
  18. */
  19. public static function boundsFromPath( path:GraphicsPath, bb:BoundingBox ):void {
  20. var val:Number, xmin:Number, xmax:Number, ymin:Number, ymax:Number;
  21. var i:int;
  22. var points:Vector.<Number> = path.data;
  23. var numPoints:int = points.length / 2;
  24. if (numPoints > 0) {
  25. xmin = xmax = points[0];
  26. ymin = ymax = points[1];
  27. for (i = 1; i < numPoints; i++) {
  28. val = points[i * 2];
  29. if (val > xmax) xmax = val;
  30. if (val < xmin) xmin = val;
  31. val = points[i * 2 + 1];
  32. if (val > ymax) ymax = val;
  33. if (val < ymin) ymin = val;
  34. }
  35. bb.minx = xmin;
  36. bb.maxx = xmax;
  37. bb.miny = ymin;
  38. bb.maxy = ymax;
  39. }
  40. }
  41. /**
  42. * Adds copies of the individual polygons from a composite polygon to the polys Vector.
  43. *
  44. * @param path The composite polygon.
  45. * @param polys The result.
  46. */
  47. public static function polygonsFromPath( path:GraphicsPath, polys:Vector.<GraphicsPath> ):void {
  48. var points:Vector.<Number> = path.data;
  49. var numCommands:int = path.commands.length;
  50. var currentPath:GraphicsPath;
  51. if (numCommands > 0) {
  52. var i:int = 0;
  53. var currentCommand:int = 0;
  54. while (currentCommand < numCommands) {
  55. switch ( path.commands[currentCommand] ) {
  56. case GraphicsPathCommand.LINE_TO:
  57. currentPath.lineTo( points[i++], points[i++] );
  58. break;
  59. case GraphicsPathCommand.MOVE_TO:
  60. if (currentPath && currentPath.commands) {
  61. polys.push( currentPath );
  62. }
  63. currentPath = new GraphicsPath( new Vector.<int>, new Vector.<Number> );
  64. currentPath.moveTo( points[i++], points[i++] );
  65. break;
  66. case GraphicsPathCommand.CURVE_TO:
  67. currentPath.curveTo( points[i++], points[i++], points[i++], points[i++] );
  68. break;
  69. case GraphicsPathCommand.CUBIC_CURVE_TO:
  70. currentPath.cubicCurveTo( points[i++], points[i++], points[i++], points[i++], points[i++], points[i++] );
  71. break;
  72. case GraphicsPathCommand.WIDE_LINE_TO:
  73. currentPath.wideLineTo( points[i++], points[i++] );
  74. i++; i++;
  75. // TODO: Test
  76. break;
  77. case GraphicsPathCommand.WIDE_MOVE_TO:
  78. if (currentPath && currentPath.commands) {
  79. polys.push( currentPath );
  80. }
  81. currentPath = new GraphicsPath( new Vector.<int>, new Vector.<Number> );
  82. currentPath.wideMoveTo( points[i++], points[i++] );
  83. i++; i++;
  84. break;
  85. }
  86. currentCommand++;
  87. }
  88. if (currentPath && currentPath.commands) {
  89. polys.push( currentPath );
  90. }
  91. }
  92. }
  93. public static function area( path:GraphicsPath ):Number {
  94. var area:Number = 0;
  95. var points:Vector.<Number> = path.data;
  96. var numPoints:int = path.data.length - 2;
  97. var pointIndex:int = 0;
  98. while (pointIndex < numPoints) {
  99. area += points[pointIndex] * points[pointIndex + 3] - points[pointIndex + 2] * points[pointIndex + 1];
  100. pointIndex += 2;
  101. }
  102. area += points[pointIndex] * points[1] - points[0] * points[pointIndex + 1];
  103. return area/-2;
  104. }
  105. public static function centroid( path:GraphicsPath, p:Point, area:Number = NaN ):void {
  106. var x:Number = 0, y:Number = 0;
  107. var c:Number = 0;
  108. if (p && path) {
  109. var points:Vector.<Number> = path.data;
  110. var numPoints:int = path.data.length - 2;
  111. var pointIndex:int = 0;
  112. if (isNaN(area)) {
  113. area = GeometryFunctions.area( path );
  114. }
  115. while (pointIndex < numPoints) {
  116. c = points[pointIndex] * points[pointIndex + 3] - points[pointIndex + 2] * points[pointIndex + 1];
  117. x += (points[pointIndex] + points[pointIndex + 2]) * c;
  118. y += (points[pointIndex+1] + points[pointIndex + 3]) * c;
  119. pointIndex += 2;
  120. }
  121. c = points[pointIndex] * points[1] - points[0] * points[pointIndex + 1];
  122. x += (points[pointIndex] + points[0]) * c;
  123. y += (points[pointIndex + 1] + points[1]) * c;
  124. p.x = x / (-6 * area);
  125. p.y = y / (-6 * area);
  126. }
  127. }
  128. public static function pointInPolygon( path:GraphicsPath, x:Number, y:Number ):Boolean {
  129. if (path) {
  130. var points:Vector.<Number> = path.data;
  131. var numCommands:int = path.commands.length;
  132. var currentPath:GraphicsPath;
  133. if (numCommands > 0) {
  134. // adapted from GKA
  135. // https://bitbucket.org/gka/as3-vis4/src/f3fc7fd5a8b8e1612dd48c50765d9d44bd590aed/src/net/vis4/geom/Polygon.as?at=default
  136. var xinters:Number;
  137. var counter:int = 0;
  138. var i:int = 0;
  139. var currentCommand:int = 0;
  140. var p1:Point = new Point( points[i++], points[i++] );
  141. var p2:Point = new Point(0, 0);
  142. currentCommand++;
  143. while (currentCommand < numCommands) {
  144. switch ( path.commands[currentCommand] ) {
  145. case GraphicsPathCommand.LINE_TO:
  146. p2.x = points[i++];
  147. p2.y = points[i++];
  148. break;
  149. case GraphicsPathCommand.MOVE_TO:
  150. p2.x = points[i++];
  151. p2.y = points[i++];
  152. break;
  153. case GraphicsPathCommand.CURVE_TO:
  154. i++; i++;
  155. p2.x = points[i++];
  156. p2.y = points[i++];
  157. break;
  158. case GraphicsPathCommand.CUBIC_CURVE_TO:
  159. i++; i++;
  160. i++; i++;
  161. p2.x = points[i++];
  162. p2.y = points[i++];
  163. break;
  164. case GraphicsPathCommand.WIDE_LINE_TO:
  165. p2.x = points[i++];
  166. p2.y = points[i++];
  167. i++; i++;
  168. // TODO: Test
  169. break;
  170. case GraphicsPathCommand.WIDE_MOVE_TO:
  171. p2.x = points[i++];
  172. p2.y = points[i++];
  173. i++; i++;
  174. break;
  175. }
  176. currentCommand++;
  177. if (y > Math.min(p1.y, p2.y)) {
  178. if (y <= Math.max(p1.y, p2.y)) {
  179. if (x <= Math.max(p1.x, p2.x)) {
  180. if (p1.y != p2.y) {
  181. xinters = (y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
  182. if (p1.x == p2.x || x <= xinters) counter++;
  183. }
  184. }
  185. }
  186. }
  187. p1.x = p2.x;
  188. p1.y = p2.y;
  189. }
  190. return (counter % 2 != 0);
  191. }
  192. }
  193. return false;
  194. }
  195. }
  196. }