Точка пересечения в Silverlight / WPF - PullRequest
2 голосов
/ 07 апреля 2010

Задан такой путь:

<Path Stretch="Fill" Stroke="#FFD69436" Data="M 0,20 L 22.3,20 L 34,0 L 44.7,20 L 68,20 L 55.8,40 L 68,60 L 44.7,60 L 34,80 L 22.3,60 L 0,60 L 11.16,40 L 0,20 Z">
            <Path.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="#FFFFFF" Offset="0" />
                        <GradientStop Color="Orange" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Path.Fill>
        </Path>

Как я могу получить точку, которая находится на краю этой фигуры под любым углом? Допустим, я хочу, чтобы точка пересечения между краем этой фигуры и линией, проходящей через центр этой фигуры, под углом 30 градусов к оси OX?

спасибо.

Ответы [ 2 ]

5 голосов
/ 08 апреля 2010

Существует несколько различных способов сделать это в зависимости от требуемой производительности и точности, а также объема геометрического кода, который вы готовы написать.

1. Использование FillContains

Один из способов - построить последовательную геометрию линии и использовать path.Data.FillContains (геометрия), чтобы определить, пересекают ли они фигуру. Что-то вроде этого:

Transform rotation = new RotateTransform { Angle = 30 };

double max = path.Width + path.Height;
double current = 0;
for(double delta = max/2; delta > 0.25; delta = delta/2)
{
  var line = new LineGeometry(
                  new Point(centerX + current, centerY),
                  new Point(centerX + max, centerY),
                  rotation);
  if(path.Data.FillContains(line))
    current += delta;
}
var intersectPoint = rotation.Transform(new Point(current, 0));

2. Использование GetFlattenPathGeometry

Другой способ - использовать GetFlattenPathGeometry:

var flattened = path.Data.GetFlattenedPathGeometry();
var segment = pg.Figures[0].Segments[0] as PolyLineSegment;
Point[] points = segment.Points;
for(int i=0; i<points.Count-1; i++)
{
  ... check for intersection with the line from points[i] to points[i+1] ...
}

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

3. Использование PathGeometry.CreateFromGeometry

Самый эффективный способ - преобразовать данную геометрию в PathGeometry, а затем вручную выполнить итерации по фигурам и сегментам в геометрии:

var geo = PathGeometry.CreateFromGeometry (path.Data); foreach (var figure in geo.Figures) foreach (var сегмент на рисунке. Сегменты) if (сегмент это LineSegment) ... иначе, если (сегмент является ArcSegment) ... иначе, если (сегмент является BezierSegment) ... иначе, если (сегмент является QuadraticBezierSegment) ... иначе, если (сегмент является PolyLineSegment) ... иначе, если (сегмент является PolyBezierSegment) ... иначе, если (сегмент является PolyQuadraticBezierSegment) ...

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

Примечание по GetWidenedPathGeometry

Все, что я сказал до сих пор, даст вам пересечения между данными геометрического пути и вашей пересекающейся линией: оно не учитывает ширину линии, концевые заглавные буквы и т. Д. Чтобы принять это во внимание, вам необходимо GetWidenedPathGeometry следующим образом:

var widenedData = path.Data.GetWidenedPathGeometry(new Pen { ... });

Где параметры Pen задаются из path.Stroke, path.StrokeWidth и т. Д.

После этого используйте один из вышеперечисленных приемов, заменив «path.Data» на «widenedData».

1 голос
/ 24 октября 2010

Ребята, вы знаете, что эквивалентно этому в Silverlight 3?Я пытаюсь сделать это для WP7, и похоже, что это Paths.Data - простой объект Geometry, который не отображает рисунки или методы, которые вы упоминаете.

Отличный ответ, кстати, это действительно помогло мне, я пытаюсь получить коллекцию Point из Path, и это все, она просто не работает для мобильных устройств:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...