wpf c# 在顶点周围创建多边形

wpf c# create polygons around vertex points

在我的 WPF 项目中,我想绘制一些多边形或折线。它们需要是具有圆角的多边形,这些圆角在给定的顶点之外传递,如下图示例:

还需要第一个点(多边形的左上角)有一个钩子,但主要问题是关于给定点之外的传递。

例如,如果点具有给定的坐标:

p1(10,10)

p2(10,100)

p3(100,100)

p4(100,10)

如何创建多边形?

我找到了一个示例 here 但是给定的顶点在形状外部而不是内部。

有没有办法在 WPF 中构建这种形状?无论是库还是本机代码。

看来您应该实施某种等距算法。假设多边形线与每个顶点的距离为 d。算法步骤为:

  1. 将每条多边形线从其原始位置d偏移
  2. 对每个顶点画一条弧线段,圆弧中心为顶点,起点和终点为关节线段的点。

Algorithm for the first step

更新

创建了用于说明算法的示例代码。

XAML

    <Canvas Name="canvas">
        <Polygon Name="poly" Stroke="Black" >
            <Polygon.Points>
                <Point X="110" Y="110" />
                <Point X="110" Y="200" />
                <Point X="200" Y="200" />
                <Point X="300" Y="110" />
                <Point X="200" Y="110" />
            </Polygon.Points>
        </Polygon>
    </Canvas>

C#

    double _distance = 10.0;

    Line CreateLine(Point pointStart, Point pointEnd)
    {
        Line line = new Line();

        line.Stroke = Brushes.Red;
        line.X1 = pointStart.X;
        line.Y1 = pointStart.Y;
        line.X2 = pointEnd.X;
        line.Y2 = pointEnd.Y;

        return line;
    }

    Path CreateArc(Point pointStart, Point pointEnd, double radius)
    {
        ArcSegment arc = new ArcSegment();
        arc.Point = pointEnd;
        arc.Size = new Size(radius, radius);


        var pathFigure = new PathFigure(pointStart, new PathSegment[] { arc }, false);
        Path path = new Path();
        path.Data = new PathGeometry(new PathFigure[] { pathFigure });
        path.Stroke = Brushes.Red;

        return path;
    }

    private void CreateDrawing()
    {

        for (int i = 0; i < poly.Points.Count; i++)
        {
            int lastPointIndex = (i > 0) ? i - 1 : poly.Points.Count - 1;
            int nextPointIndex = (i < poly.Points.Count - 1) ? i + 1 : 0;


            var pointsPair = GetPerpendicularPoint(poly.Points[i].X, poly.Points[i].Y, poly.Points[nextPointIndex].X, poly.Points[nextPointIndex].Y, _distance);
            var lastPointsPair = GetPerpendicularPoint(poly.Points[lastPointIndex].X, poly.Points[lastPointIndex].Y, poly.Points[i].X, poly.Points[i].Y, _distance);

            canvas.Children.Add(CreateLine(pointsPair.Item1, pointsPair.Item2));
            canvas.Children.Add(CreateArc(lastPointsPair.Item2, pointsPair.Item1, _distance));
        }

    }

    private Tuple<Point, Point> GetPerpendicularPoint(double startX, double startY, double stopX, double stopY, double distance)
    {
        Point p = new Point(startX - stopX, startY - stopY);
        Point n = new Point(p.Y, -p.X);
        double norm_length = Math.Sqrt((n.X * n.X) + (n.Y * n.Y));
        n.X /= norm_length;
        n.Y /= norm_length;
        return new Tuple<Point, Point>(new Point(startX + (distance * n.X), startY + (distance * n.Y)), new Point(stopX + (distance * n.X), stopY + (distance * n.Y)));
    }

结果

更新非凸多边形

如果多边形是非凸的,则不应添加圆弧。要检查是否添加圆弧,我们可以使用凸多边形的特征,它的所有顶点都在 2D 平面的一侧,由线划分,由每 2 个相邻顶点定义。 因此,如果多边形顶点按顺时针顺序给出,那么我们必须检查下一个点是否在右侧,并且只有在这种情况下才绘制弧线。

代码:

if (IsRight(poly.Points[lastPointIndex], poly.Points[i], poly.Points[nextPointIndex]))
{
    canvas.Children.Add(CreateArc(lastPointsPair.Item2, pointsPair.Item1, _distance));
}

...

public bool IsRight(Point a, Point b, Point c)
{
    return ((b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X)) > .0;
}