Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here is a nice alternative. It's not as sophisticated as @Simon's, but it gives nice results (that can be further improved), with much simpler code.</p> <p>The idea is to reuse the existing functionality of <code>GraphicsPath.Widen</code> in order to get the points.</p> <p>When we call <code>Widen</code> on a <code>GraphicsPath</code> that consists of <em>n</em> closed figures, the resulting path has <em>2n</em> edges. An outer and an inner edge for each original figure.</p> <p>So, I create a temporary path, widen it, and copy only the inner edges.</p> <p>Here's the code:</p> <pre><code>public static GraphicsPath Shrink(this GraphicsPath path, float width) { using (var p = new GraphicsPath()) { p.AddPath(path, false); p.CloseAllFigures(); p.Widen(new Pen(Color.Black, width*2)); var position = 0; var result = new GraphicsPath(); while (position &lt; p.PointCount) { // skip outer edge position += CountNextFigure(p.PathData, position); // count inner edge var figureCount = CountNextFigure(p.PathData, position); var points = new PointF[figureCount]; var types = new byte[figureCount]; Array.Copy(p.PathPoints, position, points, 0, figureCount); Array.Copy(p.PathTypes, position, types, 0, figureCount); position += figureCount; result.AddPath(new GraphicsPath(points, types), false); } path.Reset(); path.AddPath(result, false); return path; } } static int CountNextFigure(PathData data, int position) { int count = 0; for (var i = position; i &lt; data.Types.Length; i++) { count++; if (0 != (data.Types[i] &amp; (int) PathPointType.CloseSubpath)) { return count; } } return count; } </code></pre> <p><strong>And here's an example:</strong></p> <pre><code>GraphicsPath path = new GraphicsPath(); path.AddString("cool", new FontFamily("Times New Roman"), 0, 300, new PointF(), StringFormat.GenericDefault); e.Graphics.DrawPath(new Pen(Color.Black, 1), path); path.Shrink(3); e.Graphics.DrawPath(new Pen(Color.Red), path); </code></pre> <p>Admittedly, my solution also has undesired artifacts when the offset is large enough to cause the shape to intersect with itself.</p> <p><img src="https://i.stack.imgur.com/IyQ8H.png" alt="alt text"><br> <strong>EDIT:</strong></p> <p>I can easily detect all the intersection points in O(<em>n^2</em>), or with some effort - detect them in O(<em>n logn</em>), using a sweep line algorithm (<em>n</em> being the number of points).</p> <p>But once I've found the intersection points, I'm not sure how to decide which parts of the path to remove. Anyone has an idea? :)</p> <p><strong>EDIT 2:</strong></p> <p>Actually, we don't really need to find intersections of the figures.</p> <p>What we can do is scan all the points on the figure. Once we found a point that is either outside of the original figure, or is too close to an edge on the original figure, then we have to fix it.</p> <p>In order to fix a point, we look at the edge between this point and the previous one, and we have to cut this edge so that it will now end in a new point, on the right distance from the original figure.</p> <p>I've done some experiments with an approximate of this algorithm (with a crude but easy algorithm where I removed the "off" points entirely instead of moving them to shorten their edge, and I checked distances to points on the original figure instead of to edges on it). This got some nice results of removing most of the unwanted artifacts.</p> <p>To implement the full solution would probably take a few hours...</p> <p><strong>EDIT 3:</strong></p> <p>Though still far from perfect, I posted my improved solution in a separate answer.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload