silverlight / wpf中的交点

时间:2010-04-07 19:39:15

标签: c# wpf silverlight

给出像这样的路径:

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

如何以任何角度获得此图边缘的点?让我们说我想要这个图的边缘和穿过这个图的中心的线之间的交点,与OX轴成30度角?

感谢。

2 个答案:

答案 0 :(得分:5)

根据您需要的性能和准确度以及您愿意编写的几何代码,有很多不同的方法可以做到这一点。

<强> 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。使用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] ...
}

这可以更快,因为几何体只处理一次,但需要您编写自己的线交叉算法(这非常简单)。

第3。使用PathGeometry.CreateFromGeometry

最有效的方法是将给定的几何转换为PathGeometry,然后手动迭代几何中的图形和分段:

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

这种方法需要相当多的几何分析代码,但速度非常快,因为WPF不必构建平面几何或重复交叉。当我需要我的代码运行得非常快时,这是我通常使用的技术。

关于GetWidenedPathGeometry的说明

到目前为止,我所说的所有内容都会为您提供几何路径数据与相交线之间的交叉点:它不考虑线宽,端盖等。要考虑这些因素,您还需要使用GetWidenedPathGeometry如下:

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

从path.Stroke,path.StrokeWidth等设置Pen参数的位置

执行此操作后,使用上述技术之一将“path.Data”替换为“widenedData”。

答案 1 :(得分:1)

你们知道Silverlight 3中的相同之处是什么吗?我正在尝试为WP7做这个,它看起来像是Paths.Data是一个普通的Geometry对象,它没有暴露数字或你提到的方法。

顺便说一句很好的答案,这真的对我很有帮助,我正试图从路径中获取Point系列,就是这样,它只是不适用于移动设备:)