Как разделить полигон PathGeometry на пересекающийся сегмент линии
Автор вопроса: softwarequestioneerОтветов: 2
У меня есть PathGeometry, который я построил из набора LineSegments, и я хочу разделить его на два PathGeometry, разделенных линией, пересекающей середину геометрии. Вот что я имею в виду под этой картинкой:
http://i30.tinypic.com/2noyvm.png
Я могу просмотреть LineSegments и создать массив простых линейных объектов (простой объект со свойством Point1, Point2, чтобы он представлял одну линию). Но мне нужно как-то выяснить, какие линии были на одном конце линии пересечения, а какие на другом конце линии пересечения...
Это что-то вроде противоположности метода комбинирования геометрии, что-то вроде метода разделения геометрии, который я пытаюсь собрать.
Что ж, это было весело, вот что я сделал (честно говоря, я понятия не имею, является ли это "правильным" способом или есть ли более эффективный способ).
Создайте преобразование, которое перемещает геометрию так, чтобы разделительная линия находилась на оси Y.
Для каждой линии в геометрии - если X‹0, то слева, если X>0, то справа, если линия пересекает ось Y, разделите ее на две линии.
Преобразуйте оба списка линий, используя обратное преобразование из шага 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);
}
}
Ответ 2 · рейтинг 1 · codekaizen
Способ выяснить, какие линии находятся на какой стороне линии пересечения, состоит в том, чтобы вычислить знак определителя конечных точек линии относительно линии пересечения. Положительный - одна сторона, отрицательный - другая.
Если вы хотите иметь более сложное пересечение, скажем, внутри отрезка линии, вам нужно построить граф двунаправленных ребер и вершин и вычислить пересечение пересекающейся линии и каждого ребра многоугольника. Затем вы вставляете вершины там, где линия пересекает ребра, и повторяете график, строя многоугольник из направленных ребер, следуя от одного к другому.
Если вам нужна реализация этого, ознакомьтесь с Net Topology Suite, который, хотя и используемый в основном для ГИС, также полезен для решения общих задач вычислительной геометрии, подобных этой.