/// <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 PdnGraphicsPath with traces that outline the various areas from the given stencil buffer.</returns> public unsafe static PdnGraphicsPath PathFromStencil(IBitVector2D stencil, Rectangle bounds) { if (stencil.IsEmpty) { return(new PdnGraphicsPath()); } PdnGraphicsPath ret = new PdnGraphicsPath(); Point start = bounds.Location; Vector <Point> 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); }
/// <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 PdnGraphicsPath with traces that outline the various areas from the given stencil buffer.</returns> public unsafe static PdnGraphicsPath PathFromStencil(IBitVector2D stencil, Rectangle bounds) { if (stencil.IsEmpty) { return new PdnGraphicsPath(); } PdnGraphicsPath ret = new PdnGraphicsPath(); Point start = bounds.Location; Vector<Point> 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; }