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