Pergunta

Eu tenho um PathGeometry que eu tenho construído a partir de um monte de LineSegments, e quero dividi-lo em dois PathGeometries dividido por uma linha de interseção para o meio da geometria.Aqui está o que eu quero dizer com essa imagem:

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

Eu posso passar o LineSegments e criar uma matriz de simples objetos de linha (simple object w/ a Point1, Point2 propriedade, de modo que ele representa uma linha).Mas eu preciso de alguma forma a descobrir quais Linhas foram em uma final de interseção da linha, e quais as linhas que estavam na outra extremidade da interseção da linha de...

Isso é meio que o oposto de uma geometria combinar método, algo como uma geometria dividir método que eu estou tentando colocar juntos.

Qualquer idéias?

Obrigado!

Foi útil?

Solução

Bem, isso foi divertido, aqui está o que eu fiz (eu sinceramente não tenho idéia se esse é o jeito "certo" de se existe uma maneira mais eficiente).

  1. Criar uma transformação que move a geometria, de modo que a linha divisória é sobre o eixo Y.
  2. Para cada linha na geometria - se X<0 é na esquerda, se X>0 é o da direita, se a linha cruza o eixo Y, dividi-lo em duas linhas.
  3. Transformação de ambas as listas de linhas usando o inverso da transformação a partir do passo 1 e reconstruir uma geometria a partir deles.

Aqui está um SplitGeometry método que leva uma geometria e uma linha definida por dois pontos e retorna as duas geometrias:

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

Outras dicas

A maneira de descobrir quais linhas estão em que lado da linha de interseção é calcular o sinal do determinante dos endpoints da linha em relação à linha de interseção.Positivo é um lado, negativo é o outro.

Se você quiser ter mais interseção sofisticado, digamos, dentro do interior de um segmento de linha, então você precisa construir um gráfico de bordas e vértades dirigidas duplamente e calcular a interseção da linha de interseção e cada borda de polígono.Você então insere os vérticos onde a linha intercepta bordas e refaça o gráfico, construindo um polígono das bordas dirigidas como você segue um para o outro.

Se você estiver procurando por uma implementação disso, confira net topology suite ,que, embora usado principalmente para o GIS, também é útil para problemas gerais de geometria computacional como este.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top