1

一連のLineSegmentsから作成したPathGeometryがあり、ジオメトリの中央を交差する線で分割された2つのPathGeometriesに分割したいと思います。この写真の意味は次のとおりです。

http://i30.tinypic.com/2noyvm.png

LineSegmentsを調べて、単純な線オブジェクトの配列を作成できます(1本の線を表すようにPoint1、Point2プロパティを持つ単純なオブジェクト)。しかし、どの線が交差線の一方の端にあり、どの線が交差線のもう一方の端にあるかをどうにかして把握する必要があります...

これは、ジオメトリ結合メソッドの反対のようなもので、私がまとめようとしているジオメトリ分割メソッドのようなものです。

何か案は?

ありがとう!

4

2 に答える 2

1

どの線が交線のどちら側にあるかを把握する方法は、交線に対する線の端点の行列式の符号を計算することです。ポジティブは一方の側であり、ネガティブはもう一方の側です。

たとえば、線分の内部など、より洗練された交差点が必要な場合は、二重に向けられたエッジと頂点のグラフを作成し、交差する線と各ポリゴンエッジの交差点を計算する必要があります。次に、線がエッジと交差する場所に頂点を挿入し、グラフを再トレースして、一方を他方にたどりながら、有向エッジからポリゴンを構築します。

これの実装を探している場合は、Net Topology Suiteをチェックしてください。これは、主にGISに使用されますが、このような一般的な計算幾何学の問題にも役立ちます。

于 2010-07-08T02:17:38.310 に答える
0

まあ、それは楽しかったです、これが私がしたことです(これがより効率的な方法があるかどうかの「正しい」方法であるかどうか正直にわかりません)。

  1. 分割線がY軸上になるようにジオメトリを移動する変換を作成します。
  2. ジオメトリ内の各線について-X<0の場合は左側にあり、X> 0の場合は右側にあり、線がY軸と交差する場合は2本の線に分割します。
  3. 手順1の変換の逆を使用して両方の線のリストを変換し、それらからジオメトリを再構築します。

これは、2つのポイントで定義されたジオメトリとラインを取得し、2つのジオメトリを返すSplitGeometryメソッドです。

    private void SplitGeometry(Geometry geo, Point pt1, Point pt2, out PathGeometry leftGeo, out PathGeometry rightGeo)
    {
        double c = 360.0 + 90.0 - (180.0 / Math.PI * Math.Atan2(pt2.Y - pt1.Y, pt2.X - pt1.X));
        var t = new TransformGroup();
        t.Children.Add(new TranslateTransform(-pt1.X, -pt1.Y));
        t.Children.Add(new RotateTransform(c));
        var i = t.Inverse;
        leftGeo = new PathGeometry();
        rightGeo = new PathGeometry();
        foreach (var figure in geo.GetFlattenedPathGeometry().Figures)
        {
            var left = new List<Point>();
            var right = new List<Point>();
            var lastPt = t.Transform(figure.StartPoint);
            foreach (PolyLineSegment segment in figure.Segments)
            {
                foreach (var currentPtOrig in segment.Points)
                {
                    var currentPt = t.Transform(currentPtOrig);
                    ProcessLine(lastPt, currentPt, left, right);
                    lastPt = currentPt;
                }
            }
            ProcessFigure(left, i, leftGeo);
            ProcessFigure(right, i, rightGeo);
        }
    }

    private void ProcessFigure(List<Point> points, GeneralTransform transform, PathGeometry geometry)
    {
        if (points.Count == 0) return;
        var result = new PolyLineSegment();
        var prev = points[0];
        for (int i = 1; i < points.Count; ++i)
        {
            var current = points[i];
            if (current == prev) continue;
            result.Points.Add(transform.Transform(current));
            prev = current;
        }
        if (result.Points.Count == 0) return;
        geometry.Figures.Add(new PathFigure(transform.Transform(points[0]), new PathSegment[] { result }, true));
    }

    private void ProcessLine(Point pt1, Point pt2, List<Point> left, List<Point> right)
    {
        if (pt1.X >= 0 && pt2.X >= 0)
        {
            right.Add(pt1);
            right.Add(pt2);
        }
        else if (pt1.X < 0 && pt2.X < 0)
        {
            left.Add(pt1);
            left.Add(pt2);
        }
        else if (pt1.X < 0)
        {
            double c = (Math.Abs(pt1.X) * Math.Abs(pt2.Y - pt1.Y)) / Math.Abs(pt2.X - pt1.X);
            double y = pt1.Y + c * Math.Sign(pt2.Y - pt1.Y);
            var p = new Point(0, y);
            left.Add(pt1);
            left.Add(p);
            right.Add(p);
            right.Add(pt2);
        }
        else
        {
            double c = (Math.Abs(pt1.X) * Math.Abs(pt2.Y - pt1.Y)) / Math.Abs(pt2.X - pt1.X);
            double y = pt1.Y + c * Math.Sign(pt2.Y - pt1.Y);
            var p = new Point(0, y);
            right.Add(pt1);
            right.Add(p);
            left.Add(p);
            left.Add(pt2);
        }
    }
于 2010-07-08T10:44:07.897 に答える