如何通过相交线段分割 PathGeometry 多边形

发布于 2024-09-08 18:01:59 字数 394 浏览 14 评论 0原文

我有一个由一堆 LineSegment 构建的 PathGeometry,我想将其分成两个 PathGeometry,并用一条与几何图形中间相交的线划分。这就是我对这张图片的意思:

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

我可以遍历 LineSegments 并创建一组简单的线对象(带有 Point1、Point2 属性的简单对象,以便它代表一条线)。但我需要以某种方式找出哪些线位于相交线的一端,哪些线位于相交线的另一端......

这有点像几何组合方法的相反,类似于几何我正在尝试组合的除法方法。

有什么想法吗?

谢谢!

I've got a PathGeometry that I've built from a bunch of LineSegments, and I want to split it into two PathGeometries divided by a line intersecting down the middle of the geometry. Here's what I mean by this picture:

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

I can go through the LineSegments and create an array of simple line objects (simple object w/ a Point1, Point2 property so that it represents one line). But i need to somehow figure out which Lines were on one end of the intersect line, and which lines were on the other end of the intersect line...

This is sort of like the opposite of a geometry combine method, something like a geometry divide method that I'm trying to put together.

Any ideas?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

够钟 2024-09-15 18:01:59

确定哪些线位于相交线的哪一侧的方法是计算线端点相对于相交线的行列式的符号。积极的是一方面,消极的是另一方面。

如果您想要在线段内部实现更复杂的交集,那么您需要构建双向边和顶点的图,并计算相交线和每个多边形边的交集。然后,您可以在线与边相交的位置插入顶点,并回溯图形,当您沿着一个边到另一个边时,从有向边构建一个多边形。

如果您正在寻找此方法的实现,请查看 Net Topology Suite,主要用于 GIS,对于像这样的一般计算几何问题也很有用。

The way to figure out which lines are on which side of the intersection line is to compute the sign of the determinant of the line endpoints relative to the intersection line. Positive is one side, negative is the other.

If you want to have more sophisticated intersection, say, within the interior of a line-segment, then you need to build a graph of doubly-directed edges and vertexes and compute the intersection of the intersecting line and each polygon edge. You then insert vertexes where the line intersects edges and retrace the graph, building a polygon from the directed edges as you follow one to the other.

If you are looking for an implementation of this, check out Net Topology Suite, which, while used primarily for GIS, is also useful for general computational-geometry problems like this.

意中人 2024-09-15 18:01:59

嗯,这很有趣,这就是我所做的(老实说,我不知道这是否是“正确”的方式,是否有更有效的方式)。

  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);
        }
    }

Well, that was fun, here's what I did (I honestly have no idea if this is the "right" way of if there is a more efficient way).

  1. Create a transform that moves the geometry so that the dividing line is on the Y axis.
  2. For each line in the geometry - if X<0 it's on the left, if X>0 it's on the right, if the line crosses the the Y axis divide it into two lines.
  3. Transform both lists of lines using the inverse of the transform from step 1 and rebuild a geometry from them.

Here's a SplitGeometry method that takes a geometry and a line defined by two points and returns the two geometries:

    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);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文