簡體   English   中英

給定一個多邊形列表,構造帶孔的多邊形

[英]Given a list of polygons, construct Polygon with Holes

對於多邊形,點以逆時針方式給出。 對於孔,點以順時針方式給出。 那么給定一個多邊形列表,如何構建所有帶孔的多邊形?

以下是多邊形列表的一些先決條件:

  1. 一個多邊形可以包含多個孔,但一個孔必須包含在一個多邊形內。
  2. 一個洞不能包含一個或多個多邊形。
  3. 所有孔必須位於多邊形內,而不是位於多邊形之外
  4. 孔的邊緣可以接觸多邊形的邊緣。
  5. 並且所有的多邊形和孔都不能與其他多邊形/孔相交,盡管它們可以相互接觸。
  6. 多邊形/孔可以是凸面凹面。

如何設計一種算法來構造帶孔的多邊形?

我正在尋找通用算法,因此歡迎任何 C#、C++ 和 matlab 形式的代碼。

編輯:這是我的輸入(在 C# 中)

public class PolygonWithHoles
{
   public List<Point> OuterBoundary;
   public List<List<Point>> Holes;
}


//input: a list of point list. If the point list constructs a polygon in Counter clock wise, then it is a general polygon, else it is a holes
public List<PolygonWithHoles> ConstuctPolyHoles(List<List<Point>> Polys)
{
}

由於浮點舍入錯誤,多邊形測試中的點很容易受到攻擊。 它們通常僅適用於非平凡多邊形。

一種更可靠的方法應基於掃描線算法,其中首先根據頂點的x和y值對其進行排序。 然后,掃描(或掃描)線移動。 從左到右。 然后,該算法通常維護一條與掃描線相交的線的列表,方法是在左頂點“擊中”掃描線時添加一條線,而在其右頂點擊中該線時將其刪除。

每次掃描線移動后,將更新當前線與掃描線的交點,並根據交點的y值對行進行重新排序。 每當在排序操作期間需要對兩行進行重新排序時,這意味着它們具有交點,然后可以對其進行記錄。

找到所有交叉點后,便可以可靠地識別出輪廓和孔。

以下項目使用此方法:

還有其他一些,下面的站點(該站點促進了PolyBoolean庫)比較了最重要的站點: http : //www.complex-a5.ru/polyboolean/comp.html

就像一個警告:我本人已經實現了一個支持布爾運算以及孔檢測的多邊形庫。 該庫正用於商業產品,我花了幾年時間(!)來微調算法,以確保在任何短時間內對任何給定的輸入多邊形都能獲得正確的結果(其他庫的速度可能要快幾%,但由於輸入數據而失敗)。 實際上,單一方法算法可能無法解決所有可能的問題,因此我不得不實施多個方法。

祝好運!

也許您正在尋找類似於以下內容的簡單解決方案:

public sealed class PolygonWithHoles : Shape
{

    #region Constructors
    
    /// <summary>
    /// Instantiates a new instance of a polygon.
    /// </summary>
    public PolygonWithHoles()
    {
    }

    #endregion Constructors

    #region Dynamic Properties
    
    /// <summary>
    /// Holes property
    /// </summary>
    public static readonly DependencyProperty HolesProperty = DependencyProperty.Register(
            "Holes", typeof(List<PointCollection>), typeof(PolygonWithHoles),
            new FrameworkPropertyMetadata(new List<PointCollection>(), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)
        );

    /// <summary>
    /// Holes property
    /// </summary>
    public List<PointCollection> Holes
    {
        get
        {
            return (List<PointCollection>)GetValue(HolesProperty);
        }
        set
        {
            SetValue(HolesProperty, value);
        }
    }

    /// <summary>
    /// Points property
    /// </summary>
    public static readonly DependencyProperty PointsProperty = DependencyProperty.Register(
            "Points", typeof(PointCollection), typeof(PolygonWithHoles),
            new FrameworkPropertyMetadata(new PointCollection(), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)
        );

    /// <summary>
    /// Points property
    /// </summary>
    public PointCollection Points
    {
        get
        {
            return (PointCollection)GetValue(PointsProperty);
        }
        set
        {
            SetValue(PointsProperty, value);
        }
    }

    /// <summary>
    /// FillRule property
    /// </summary>
    public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
        "FillRule",
        typeof(FillRule),
        typeof(PolygonWithHoles),
        new FrameworkPropertyMetadata(
            FillRule.EvenOdd,
            FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)
        );

    /// <summary>
    /// FillRule property
    /// </summary>
    public FillRule FillRule
    {
        get
        {
            return (FillRule)GetValue(FillRuleProperty);
        }
        set
        {
            SetValue(FillRuleProperty, value);
        }
    }

    #endregion Dynamic Properties

    #region Protected Methods and properties

    /// <summary>
    /// Get the polygon that defines this shape
    /// </summary>
    protected override Geometry DefiningGeometry
    {
        get
        {
            return _polygonGeometry;
        }
    }

    #endregion

    #region Protected Methods

    /// <summary>
    /// Updates DesiredSize of the shape.  Called by parent UIElement during is the first pass of layout.
    /// </summary>
    /// <param name="constraint">Constraint size is an "upper limit" that should not exceed.</param>
    /// <returns>Shape's desired size.</returns>
    protected override Size MeasureOverride(Size constraint)
    {
        CacheDefiningGeometry();

        return base.MeasureOverride(constraint);
    }

    #endregion

    #region Internal Methods

    internal void CacheDefiningGeometry()
    {
        PointCollection pointCollection = Points;
        
        if (pointCollection == null)
        {
            _polygonGeometry = Geometry.Empty;
            return;
        }

        PathFigure pathFigure = new PathFigure();
        if (pointCollection.Count > 0)
        {
            pathFigure.StartPoint = pointCollection[0];

            if (pointCollection.Count > 1)
            {
                Point[] array = new Point[pointCollection.Count - 1];

                for (int i = 1; i < pointCollection.Count; i++)
                {
                    array[i - 1] = pointCollection[i];
                }

                pathFigure.Segments.Add(new PolyLineSegment(array, true));
            }

            pathFigure.IsClosed = true;
        }

        PathGeometry polygonGeometry = new PathGeometry();
        polygonGeometry.Figures.Add(pathFigure);
        polygonGeometry.FillRule = FillRule.Nonzero;

        GeometryGroup geometryGroup = new GeometryGroup();
        // Set FillRule
        geometryGroup.FillRule = FillRule;
        geometryGroup.Children.Add(polygonGeometry);

        // Holes
        List<PointCollection> holesCollection = Holes;
        if (holesCollection != null)
        {
            foreach (PointCollection holePointCollection in holesCollection)
            {
                PathFigure holePathFigure = new PathFigure();

                if (holePointCollection.Count > 0)
                {
                    holePathFigure.StartPoint = holePointCollection[0];

                    if (holePointCollection.Count > 1)
                    {
                        Point[] array = new Point[holePointCollection.Count - 1];

                        for (int i = 1; i < holePointCollection.Count; i++)
                        {
                            array[i - 1] = holePointCollection[i];
                        }

                        holePathFigure.Segments.Add(new PolyLineSegment(array, true));
                    }

                    holePathFigure.IsClosed = true;
                }

                PathGeometry holePolygonGeometry = new PathGeometry();
                holePolygonGeometry.Figures.Add(holePathFigure);
                holePolygonGeometry.FillRule = FillRule.Nonzero;

                geometryGroup.Children.Add(holePolygonGeometry);
            }

        }
        

        _polygonGeometry = geometryGroup;
    }

    #endregion Internal Methods

    #region Private Methods and Members

    private Geometry _polygonGeometry;

    #endregion
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM