【问题标题】:Draw polygon from unordered points从无序点绘制多边形
【发布时间】:2020-10-01 09:08:59
【问题描述】:

所以,我知道有类似的问题,我在输入代码并提出这个问题之前进行了很多搜索。

在我的例子中,用户点击屏幕上的一个地方来添加一个点。当用户添加完点后,右击说点没问题,然后绘制多边形。

A点不规则放置,我必须计算中心点和每个点的角度来排序点列表。

然后,当我移动一个点时,我用新位置重新计算角度并重新绘制多边形。

它可以工作,但是当我将一个点移到其他两个之外时,有时它不会绘制 plygon。我找不到问题所在。

这是我的代码和两张图片来解释问题:

public class CustomPoint3D
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
    public int Angle { get; set; }
    public CustomPoint3D()
    {

    }

    public CustomPoint3D(double x, double y, double z)
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }
}



    private void AddZoneSurface(List<CustomPoint3D> customPoints, string guid)
    {

        //Calculates angles and orders / sorts the list of points
        List<Point2D> points = From3DTo2D(customPoints);

        //Draws a polygon in Eyeshot but it can be any tool to create a polygon.
        var polygon = devDept.Eyeshot.Entities.Region.CreatePolygon(points.ToArray());


        polygon.ColorMethod = colorMethodType.byEntity;
        polygon.EntityData = "tool-surface-" + guid;
        polygon.Color = System.Drawing.Color.FromArgb(80, 0, 0, 0);
        sceneLeft.Entities.Add(polygon);

       
        sceneLeft.Invalidate();
    }

    private List<Point2D> From3DTo2D(List<CustomPoint3D> points)
    {
        List<Point2D> retVal = new List<Point2D>();
        var minX = points.Min(ro => ro.X);
        var maxX = points.Max(ro => ro.X);
        var minY = points.Min(ro => ro.Y);
        var maxY = points.Max(ro => ro.Y);

        var center = new CustomPoint3D()
        {
            X = minX + (maxX - minX) / 2,
            Y = minY + (maxY - minY) / 2
        };

        // precalculate the angles of each point to avoid multiple calculations on sort
        for (var i = 0; i < points.Count; i++)
        {
            points[i].Angle = (int)(Math.Acos((points[i].X - center.X) / lineDistance(center, points[i])));

            if (points[i].Y > center.Y)
            {
                points[i].Angle = (int)(Math.PI + Math.PI - points[i].Angle);
            }
        }
        //points.Sort((a, b) => a.Angle - b.Angle);
        points = points.OrderBy(ro => ro.Angle).ToList();
        foreach (var item in points)
        {
            retVal.Add(new Point2D() { X = item.X, Y = item.Y });
        }
        return retVal;
    }


    double lineDistance(CustomPoint3D point1, CustomPoint3D point2)
    {
        double xs = 0;
        double ys = 0;

        xs = point2.X - point1.X;
        xs = xs * xs;

        ys = point2.Y - point1.Y;
        ys = ys * ys;

        return Math.Sqrt(xs + ys);
    }

在第一张图片上,我将点从其初始位置移动到指定位置,它不绘制多边形。

【问题讨论】:

  • 使用这种角度排序,你将得到一个所谓的星形多边形,它的一种特殊情况是凸的(取决于顶点到质心的距离)。这是你想要的吗?
  • 伊夫,这就是我想要的。如果我将角度计算为两倍,它会起作用。如果我将它们计算为 int,则在某些情况下它不起作用。最后,我可以让它工作。感谢您的评论。

标签: c# wpf computational-geometry eyeshot


【解决方案1】:

您应该阅读the Wikipedia page on convex hull algorithms 并选择一种您觉得可以轻松实现且同时满足您的 O(n) 复杂度要求的算法。

如果凸包不是您所追求的,那么您需要更具体地说明您希望点如何定义形状。一种(可能是次优的)解决方案是计算凸包find the center,选择一个点作为“起点”,然后从起点按角度对剩余点进行排序。

【讨论】:

  • 感谢您的回复,我找到了,我应该将 Angle 属性声明为 double。
【解决方案2】:

所以如果有人需要一个有效的样本,我就发现了问题。 我应该像这样声明 CustomPoint3D 对象的角度属性 由于属性是整数,所以角度 0,3 或 0,99 将 0 作为角度。

 public class CustomPoint3D
 {
  public double X { get; set; }
  public double Y { get; set; }
  public double Z { get; set; }
  public double Angle { get; set; }
  public CustomPoint3D()
 {

}

  public CustomPoint3D(double x, double y, double z)
  {
    this.X = x;
    this.Y = y;
    this.Z = z;
  }
}

并将此值计算为双精度

     private List<Point2D> From3DTo2D(List<CustomPoint3D> points)
{
    List<Point2D> retVal = new List<Point2D>();
    var minX = points.Min(ro => ro.X);
    var maxX = points.Max(ro => ro.X);
    var minY = points.Min(ro => ro.Y);
    var maxY = points.Max(ro => ro.Y);

    var center = new CustomPoint3D()
    {
        X = minX + (maxX - minX) / 2,
        Y = minY + (maxY - minY) / 2
    };

    // precalculate the angles of each point to avoid multiple calculations on sort
    for (var i = 0; i < points.Count; i++)
    {
        points[i].Angle = Math.Acos((points[i].X - center.X) / lineDistance(center, points[i]));

        if (points[i].Y > center.Y)
        {
            points[i].Angle = Math.PI + Math.PI - points[i].Angle;
        }
    }
    //points.Sort((a, b) => a.Angle - b.Angle);
    points = points.OrderBy(ro => ro.Angle).ToList();
    foreach (var item in points)
    {
        retVal.Add(new Point2D() { X = item.X, Y = item.Y });
    }
    return retVal;
}

And 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 2023-03-14
    • 2020-11-10
    • 2013-04-20
    • 1970-01-01
    • 2011-12-30
    相关资源
    最近更新 更多