Skip to content

PatternPen with a four-value pattern and LineJoin.Miter draws an EllipsePolygon almost solid #430

Open

Description

@ericverschoor

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Drawing
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

ImageSharp.Drawing version

3.1.3

Other ImageSharp packages and versions

SixLabors.ImageSharp 4.1.3 (SixLabors.Fonts 3.2.0, SixLabors.PolygonClipper 1.0.2 via dependencies)

Environment (Operating system, version and so on)

Windows 11 x64

.NET Framework version

.NET 10 (SDK 10.0.401)

Description

A PatternPen with the four-value pattern [4, 2, 1, 2] and LineJoin.Miter draws an EllipsePolygon as an almost continuous line: the ink is 97 % of a solid pen with the same options, where about 56–60 % is expected. Only one gap remains visible.

The same pattern is correct on a closed square polygon. A two-value pattern [3, 2] is correct on the same ellipse. With the default join (Bevel) the four-value pattern is also correct on the ellipse (60 %), and with LineJoin.Round it is 66 %. So the combination of a short dash/gap pattern on a densely flattened curve with miter (and to a lesser extent round) joins seems to fill the gaps.

In ImageSharp.Drawing 2.1.6 the same drawing (with JointStyle.Miter, EndCapStyle.Butt) was dashed as expected.

Join, cap [3, 2] [4, 2, 1, 2]
default (Bevel, Butt) 60 % 60 %
Miter, Butt 60 % 97 %
Round, Butt 60 % 66 %
Miter, Round 74 % 101 %

(ink as a share of a solid pen with the same StrokeOptions; circle of 200 px diameter, pen width 2, 256 × 256 image)

Steps to Reproduce

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

IPath circle = new EllipsePolygon(128, 128, 200, 200);

double Ink(Pen pen)
{
    using var image = new Image<Rgba32>(256, 256, Color.White.ToPixel<Rgba32>());
    image.Mutate(ctx => ctx.Paint(canvas => canvas.Draw(pen, circle)));
    double ink = 0;
    image.ProcessPixelRows(rows =>
    {
        for (var y = 0; y < rows.Height; y++)
            foreach (var p in rows.GetRowSpan(y))
                ink += (255 - p.R) / 255.0;
    });
    return ink;
}

var stroke = new StrokeOptions { LineJoin = LineJoin.Miter, LineCap = LineCap.Butt };
var solid = Ink(new SolidPen(new PenOptions(Color.Black, 2, []) { StrokeOptions = stroke }));
var dashed = Ink(new PatternPen(new PenOptions(Color.Black, 2, [4f, 2f, 1f, 2f]) { StrokeOptions = stroke }));

Console.WriteLine($"{dashed / solid:P0}"); // 97 %, expected about 56–60 %

Images

The arc is drawn as a continuous line with a single gap, instead of dash, gap, dot, gap.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions