public static GeometryGraphicsPath FromRegion(GeometryRegion region) { Rectangle[] scans = region.GetRegionScansReadOnlyInt(); if (scans.Length == 1) { var path = new GeometryGraphicsPath(); path.AddRectangle(scans[0]); path.CloseFigure(); return(path); } else { Rectangle bounds = region.GetBoundsInt(); var stencil = new BitVector2D(bounds.Width, bounds.Height); for (int i = 0; i < scans.Length; ++i) { Rectangle rect = scans[i]; rect.X -= bounds.X; rect.Y -= bounds.Y; stencil.UnsafeSet(rect, true); } GeometryGraphicsPath path = PathFromStencil(stencil, new Rectangle(0, 0, stencil.Width, stencil.Height)); using (Matrix matrix = new Matrix()) { matrix.Reset(); matrix.Translate(bounds.X, bounds.Y); path.Transform(matrix); } return(path); } }
/// <summary> /// Creates a graphics path from the given stencil buffer. It should be filled with 'true' values /// to indicate the areas that should be outlined. /// </summary> /// <param name="stencil">The stencil buffer to read from. NOTE: The contents of this will be destroyed when this method returns.</param> /// <param name="bounds">The bounding box within the stencil buffer to limit discovery to.</param> /// <returns>A GeometryGraphicsPath with traces that outline the various areas from the given stencil buffer.</returns> public unsafe static GeometryGraphicsPath PathFromStencil(IBitVector2D stencil, Rectangle bounds) { if (stencil.IsEmpty) { return(new GeometryGraphicsPath()); } var ret = new GeometryGraphicsPath(); Point start = bounds.Location; var pts = new Vector <Point>(); int count = 0; // find all islands while (true) { bool startFound = false; while (true) { if (stencil[start]) { startFound = true; break; } ++start.X; if (start.X >= bounds.Right) { ++start.Y; start.X = bounds.Left; if (start.Y >= bounds.Bottom) { break; } } } if (!startFound) { break; } pts.Clear(); Point last = new Point(start.X, start.Y + 1); Point curr = new Point(start.X, start.Y); Point next = curr; Point left = Point.Empty; Point right = Point.Empty; // trace island outline while (true) { left.X = ((curr.X - last.X) + (curr.Y - last.Y) + 2) / 2 + curr.X - 1; left.Y = ((curr.Y - last.Y) - (curr.X - last.X) + 2) / 2 + curr.Y - 1; right.X = ((curr.X - last.X) - (curr.Y - last.Y) + 2) / 2 + curr.X - 1; right.Y = ((curr.Y - last.Y) + (curr.X - last.X) + 2) / 2 + curr.Y - 1; if (bounds.Contains(left) && stencil[left]) { // go left next.X += curr.Y - last.Y; next.Y -= curr.X - last.X; } else if (bounds.Contains(right) && stencil[right]) { // go straight next.X += curr.X - last.X; next.Y += curr.Y - last.Y; } else { // turn right next.X -= curr.Y - last.Y; next.Y += curr.X - last.X; } if (Math.Sign(next.X - curr.X) != Math.Sign(curr.X - last.X) || Math.Sign(next.Y - curr.Y) != Math.Sign(curr.Y - last.Y)) { pts.Add(curr); ++count; } last = curr; curr = next; if (next.X == start.X && next.Y == start.Y) { break; } } Point[] points = pts.ToArray(); Scanline[] scans = Utility.GetScans(points); foreach (Scanline scan in scans) { stencil.Invert(scan); } ret.AddLines(points); ret.CloseFigure(); } return(ret); }