Как разделить полигон путания путем пересеченного сегмента линии

StackOverflow https://stackoverflow.com/questions/3200241

Вопрос

У меня есть пунгометрия, которую я построил из куча линейныхментов, и я хочу разделить его на два пути, разделенные на линию, пересекающую в середину геометрии.Вот что я имею в виду под этой картинкой:

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

Я могу пройти через Linesegments и создать массив простых строчных объектов (простой объект w / a point1, point2 свойство, чтобы он представлял одну строку).Но мне нужно как-то понять, какие строки были на одном конце линии пересечения, и какие линии были на другом конце пересеченной линии ...

Это вроде как противоположность сочетающей методике геометрии, что-то вроде геометрии разделить метод, который я пытаюсь собрать вместе.

Любые идеи?

Спасибо!

Это было полезно?

Решение

Ну, это было весело, вот что я сделал (честно понятия не имею, если это «правильный» способ, если есть более эффективный способ).

  1. Создайте преобразование, которое перемещает геометрию, чтобы разделительную линию на оси Y.
  2. для каждой строки в геометрии - если x <0 это слева, если x> 0, он справа, если линия пересекает, оси Y разделить ее на две строки.
  3. преобразовать оба списка строк, используя обратное преобразование от шага 1 и восстановить геометрию от них.
  4. Вот метод сплитгематора, который принимает геометрию и строку, определяемую двумя точками и возвращает две геометрии:

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

Другие советы

Способ выяснения, какие строки находятся на какой стороне линии пересечения состоит в том, чтобы вычислить знак определителя конечных точек линии относительно линии пересечения.Позитивная одна сторона, отрицательная, другая.

Если вы хотите иметь более сложное пересечение, скажем, внутри внутренней части линейного сегмента, то вам необходимо создать график вдвойне направленных края и вершины и вычислить пересечение линии пересекающейся линии и каждого края полигона.Затем вы вкладываете вершины, где линия пересекает кромки и вернуть график, построенный многоугольником из направленных ребер, когда вы следуете следующему другому.

Если вы ищете реализацию этого, проверьте Чистая топология Suite ,который, при использовании в первую очередь для ГИС, также полезен для общей вычислительной геометрии, таких как это.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top