/** * Attempts to translate, rotate, and scale @points to match @target as closely as possible. * Only points[0, target.Length] coordinates are used in the matching process - points[target.Length, points.Length] * are just along for the ride. */ public static pb_Transform2D MatchCoordinates(Vector2[] points, Vector2[] target) { int length = points.Length < target.Length ? points.Length : target.Length; pb_Bounds2D t_bounds = new pb_Bounds2D(target, length); // only match the bounds of known matching points // move points to the center of target Vector2 translation = t_bounds.center - pb_Bounds2D.Center(points, length); Vector2[] transformed = new Vector2[points.Length]; for (int i = 0; i < points.Length; i++) { transformed[i] = points[i] + translation; } // rotate to match target points Vector2 target_angle = target[1] - target[0], transform_angle = transformed[1] - transformed[0]; float angle = Vector2.Angle(target_angle, transform_angle); float dot = Vector2.Dot(pb_Math.Perpendicular(target_angle), transform_angle); if (dot < 0) { angle = 360f - angle; } for (int i = 0; i < points.Length; i++) { transformed[i] = transformed[i].RotateAroundPoint(t_bounds.center, angle); } // and lastly scale pb_Bounds2D p_bounds = new pb_Bounds2D(transformed, length); Vector2 scale = t_bounds.size.DivideBy(p_bounds.size); // for(int i = 0; i < points.Length; i++) // transformed[i] = transformed[i].ScaleAroundPoint(t_bounds.center, scale); return(new pb_Transform2D(translation, angle, scale)); }
/** * Returns true if the polygon contains point. False otherwise. * Casts a ray from outside the bounds to the polygon and checks how * many edges are hit. * @param polygon A series of individual edges composing a polygon. polygon length *must* be divisible by 2. * This overload accepts an array of points and an array of indices that compose the polygon. */ public static bool PointInPolygon(Vector2[] polygon, int[] indices, Vector2 point) { pb_Bounds2D bounds = new pb_Bounds2D(polygon, indices); if (bounds.ContainsPoint(point)) { Vector2 rayStart = bounds.center + Vector2.up * (bounds.size.y + 2f); int collisions = 0; for (int i = 0; i < polygon.Length; i += 2) { if (GetLineSegmentIntersect(rayStart, point, polygon[indices[i]], polygon[indices[i + 1]])) { collisions++; } } return(collisions % 2 != 0); } else { return(false); } }
public static bool GeneratePolygonCrosshatch(Vector2[] polygon, float scale, Color color, int lineSpacing, ref Texture2D texture) #endif { #if PB_DEBUG profiler.BeginSample("GeneratePolygonCrosshatch"); #endif pb_Bounds2D bounds = new pb_Bounds2D(polygon); Vector2 offset = bounds.center - bounds.extents; /// shift polygon to origin 0,0 for (int i = 0; i < polygon.Length; i++) { polygon[i] -= offset; polygon[i] *= scale; } bounds.center -= offset; bounds.size *= scale; int width = (int)(bounds.size.x); int height = (int)(bounds.size.y); if (width <= 0 || height <= 0) { return(false); } #if PB_DEBUG profiler.BeginSample("Allocate Texture"); #endif if (texture == null) { texture = new Texture2D(width, height, TextureFormat.ARGB32, false); texture.filterMode = FilterMode.Point; texture.wrapMode = TextureWrapMode.Clamp; } else { if (texture.width != width || texture.height != height) { texture.Resize(width, height, TextureFormat.ARGB32, false); } } #if PB_DEBUG profiler.EndSample(); profiler.BeginSample("Fill Clear"); #endif Color[] colors = new Color[width * height]; List <int> intersects = new List <int>(); for (int i = 0; i < width * height; i++) { colors[i] = Color.clear; } #if PB_DEBUG profiler.EndSample(); #endif /** * Horizontal lines */ for (int h = 0; h < height / lineSpacing; h++) { int y = (h * lineSpacing); intersects.Clear(); #if PB_DEBUG profiler.BeginSample("Find Intersections"); #endif Vector2 start = new Vector2(bounds.center.x - bounds.size.x, y); Vector2 end = new Vector2(bounds.center.x + bounds.size.x, y); for (int i = 0; i < polygon.Length; i += 2) { Vector2 intersect = Vector2.zero; if (pb_Math.GetLineSegmentIntersect(polygon[i], polygon[i + 1], start, end, ref intersect)) { intersects.Add((int)intersect.x); } } intersects = intersects.Distinct().ToList(); intersects.Sort(); #if PB_DEBUG profiler.EndSample(); profiler.BeginSample("Fill Color"); #endif for (int i = 0; i < intersects.Count - 1; i++) { // can't just use Dot product because we the winding order isn't consistent if (pb_Math.PointInPolygon(polygon, new Vector2(intersects[i] + 2, y))) { for (int n = intersects[i]; n < intersects[i + 1]; n++) { colors[((height - 1) - y) * width + n] = color; } } } #if PB_DEBUG profiler.EndSample(); #endif } /** * Vertical lines */ if (lineSpacing > 1) { for (int w = 0; w < width / lineSpacing; w++) { int x = (w * lineSpacing); intersects.Clear(); Vector2 start = new Vector2(x, bounds.center.y - bounds.size.y); Vector2 end = new Vector2(x, bounds.center.y + bounds.size.y); for (int i = 0; i < polygon.Length; i += 2) { Vector2 intersect = Vector2.zero; if (pb_Math.GetLineSegmentIntersect(polygon[i], polygon[i + 1], start, end, ref intersect)) { intersects.Add((int)intersect.y); } } intersects = intersects.Distinct().ToList(); intersects.Sort(); for (int i = 0; i < intersects.Count - 1; i++) { if (pb_Math.PointInPolygon(polygon, new Vector2(x, intersects[i] + 2))) { for (int y = intersects[i]; y < intersects[i + 1]; y++) { colors[((height - 1) - y) * width + x] = color; } } } } } #if PB_DEBUG profiler.BeginSample("SetPixels"); #endif texture.SetPixels(colors); texture.Apply(false); #if PB_DEBUG profiler.EndSample(); profiler.EndSample(); #endif return(true); }