1

我有一个从一堆 LineSegments 构建的 PathGeometry,我想将它分成两个 PathGeometry,由一条与几何图形中间相交的线划分。这就是我说这张照片的意思:

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

我可以通过 LineSegments 并创建一组简单的线对象(带有 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 轴相交,则将其分成两条线。
  3. 使用步骤 1 中的变换的逆变换来变换两个线列表,并从中重建几何。

这是一个 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 回答