简体   繁体   English

Silverlight / WPF中的交点

[英]Intersection point in silverlight/wpf

Given a path like this one : 给定这样的路径:

<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>

How can I get the point that is at the edge of this figure at any angle? 如何获得该图的任意角度上的点? Lets say that I want the intersection point between the edge of this figure and a line passing through the center of this figure, at the 30 degrees angle with the OX axe? 可以说,我想要这个图形的边缘和一条穿过该图形中心的线之间的交点,并且与OX轴成30度角吗?

thanks. 谢谢。

There are quite a few different ways to do this, depending on the performance and accuracy you need and how much geometric code you're willing to write. 有许多不同的方法可以执行此操作,具体取决于您需要的性能和准确性以及您愿意编写多少几何代码。

1. Using FillContains 1.使用FillContains

One way is to construct successive line geometries and use path.Data.FillContains(geometry) to determine whether they intersect the figure. 一种方法是构造连续的线几何并使用path.Data.FillContains(geometry)确定它们是否与图形相交。 Something along these lines: 遵循以下原则:

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. Using GetFlattenedPathGeometry 2.使用GetFlattenedPathGeometry

Another way is to use GetFlattenedPathGeometry: 另一种方法是使用GetFlattenedPathGeometry:

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] ...
}

This can be faster because the geometry is only processed once but requires you to code your own line intersection algorithm (which is very simple). 这可能会更快,因为几何图形仅处理一次,但需要您编写自己的直线相交算法(非常简单)。

3. Using PathGeometry.CreateFromGeometry 3.使用PathGeometry.CreateFromGeometry

The most efficient way of all is to convert the given geometry into a PathGeometry and then manually iterate through the Figures and Segments in the geometry: 最有效的方法是将给定的几何图形转换为PathGeometry,然后手动遍历几何图形中的图形和线段:

var geo = PathGeometry.CreateFromGeometry(path.Data); var geo = PathGeometry.CreateFromGeometry(path.Data); foreach(var figure in geo.Figures) foreach(var segment in figure.Segments) if(segment is LineSegment) ... else if(segment is ArcSegment) ... else if(segment is BezierSegment) ... else if(segment is QuadraticBezierSegment) ... else if(segment is PolyLineSegment) ... else if(segment is PolyBezierSegment) ... else if(segment is PolyQuadraticBezierSegment) ... foreach(geo.Figures中的可变段)foreach(figure.segments中的可变段)if(segment是LineSegment)... else if(segment是ArcSegment)... else if(segment是BezierSegment)... else if(段是QuadraticBezierSegment ... ...否则if(该段是PolyLineSegment)... else if(该段是PolyBezierSegment)... else if(该段是PolyQuadraticBezierSegment)...

This approach requires quite a lot of geometric analysis code but is extremely fast because WPF doesn't have to construct a flattened geometry or do repeated intersections. 这种方法需要大量的几何分析代码,但速度非常快,因为WPF不必构造平坦的​​几何图形或进行重复的相交。 This is the technique I generally use when I need my code to run very fast. 当我需要我的代码非常快速地运行时,我通常使用这种技术。

Note on GetWidenedPathGeometry 关于GetWidenedPathGeometry的说明

Everything I've said so far will give you intersections between the geometric path data and your intersecting line: It does not take into account line width, end caps, etc. To take these into account as well you will need to use GetWidenedPathGeometry as follows: 到目前为止,我所说的所有内容都将为您提供几何路径数据和相交线之间的交集:它不考虑线宽,端帽等。要同时考虑这些,您将需要使用GetWidenedPathGeometry ,如下所示:

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

Where the Pen parameters are set from path.Stroke, path.StrokeWidth, etc. 从path.Stroke,path.StrokeWidth等设置Pen参数的位置

After doing this, use one of the above techniques replacing "path.Data" with "widenedData". 完成此操作后,使用上述技术之一将“ path.Data”替换为“ widenedData”。

Do you guys know what the equivalent to this would be in Silverlight 3? 你们知道在Silverlight 3中相当于什么吗? I'm trying to do this for WP7, and it looks like it's Paths.Data is a plain Geometry object, which doesn't expose Figures or the methods you mention. 我正在尝试对WP7进行此操作,它看起来像是Paths.Data是一个普通的Geometry对象,它没有公开Figures或您提到的方法。

Great answer by the way, this really helped me, I'm trying to get the Point collection from a Path, and this is it, it just doesnn't work for mobile :) 顺便说一句,很好的答案,这确实对我有帮助,我正在尝试从Path获取Point集合,仅此而已,它对移动设备无效:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM