PathGeometry的非GUI替代方案?

时间:2012-09-25 08:47:07

标签: c# wpf .net-4.0 pathgeometry

我有两个巨大的(> 100000项)PathGeometry集合,我需要使用PathGeometry.Combine进行比较:

List<PathGeometry> firstList;
List<PathGeometry> secondList;
[...]

foreach (PathGeometry pg1 in firstList)
  foreach (PathGeometry pg2 in secondList)
  {
    PathGeometry intergeo = PathGeometry.Combine(pg1, pg2, GeometryCombineMode.Intersect, null);
    if (intergeo.GetArea() > 0)
    {
      // do whatever with intergeo.GetArea()
    }
  }

令我惊讶的是,PathGeometry是GUI的一部分并使用调度程序,它有时会导致问题,因为我的计算在没有使用GUI的一些后台线程中运行使用Parallel.ForEach()

所以我正在寻找一种没有连接到GUI的PathGeometry的替代品 我的数字非常复杂,并为PathGeometry.Figures添加了很多PathFigures。

我自己从一些臃肿的政府xml文件中创建了这些PathGeometries,因此创建其他东西也没有问题。但我需要一个函数来创建这些几何中的两个(不是相互添加)的交集,以获得两个几何所覆盖的区域,例如此图中的红色区域:

enter image description here

3 个答案:

答案 0 :(得分:3)

如何使用the geometry "mini-langauge"而不是使用Path.Data对象将PathGeometry解析为字符串呢?

例如,不要创建这样的东西:

<Path Stroke="Black">
    <Path.Data>
        <PathGeometry>
            <PathFigure IsClosed="true" StartPoint="10,100">
                <LineSegment Point="100,100" />
                <LineSegment Point="100,50" />
            </PathFigure>
        </PathGeometry>
    </Path.Data>
</Data>

你可以创建

<Path Stroke="Black" Data="M 10 100 L 100 100 L 100 50 Z" />

或者在您的情况下,XAML可能看起来像这样:

<Path Stroke="Black" Data="{Binding MyPathProperty}" />

Path.Data是一个预期采用特定格式的字符串,是绘制路径几何图形的较短方式。

以下是从上面的链接中获取的字母含义以及预期参数的列表:

  
      
  • F值 - 设置Geometry.FillRule属性。使用0表示EvenOdd,或1表示NonZero。此命令必须出现在字符串的开头(如果您决定使用它)。

  •   
  • M x,y - 为几何创建新的PathFigure并设置其起点。必须在除F之外的任何其他命令之前使用此命令。   但是,您也可以在绘图过程中使用它来移动   坐标系的起源。 (M代表移动)。

  •   
  • L x,y - 创建指定点的LineSegment。

  •   
  • H x - 使用指定的X值创建水平LineSegment并保持Y值不变。

  •   
  • V y - 使用指定的Y值创建垂直LineSegment并保持X值不变。

  •   
  • radiusx,radiusY,degrees isLargeArch,isClockwise x,y - 创建指定点的ArcSegment。您指定的半径   描述弧的椭圆,弧的度数   旋转,以及设置IsLargeArc和SweepDirection的布尔标志   属性。

  •   
  • C x1,y1 x2,y2 x,y - 使用(x1,y1)和(x2,y2)处的控制点创建指定点的BezierSegment。

  •   
  • Q x1,y1 x,y - 在指定点创建QuadraticBezierSegment,其中一个控制点位于(x1,y1)。

  •   
  • S x2,y2 x,y - 使用前一个BezierSegment中的第二个控制点作为第一个控件创建一个平滑的BezierSegment   指向新的BezierSegment。

  •   
  • Z - 结束当前的PathFigure并将IsClosed设置为true。如果您不想将IsClosed设置为true,则无需使用此命令 -   相反,如果你想开始一个新的PathFigure或结束,只需使用M.   字符串。

  •   

例如,上面示例中使用的字符串(M 10 100 L 100 100 L 100 50 Z)可以分解为:

  • M 10 100 - 10,100
  • 的起始路径
  • L 100 100 - 画一条线到100,100
  • L 100 50 - 画一条线到100,50
  • Z - 结束字符串

在从数据库中读取Path.Data的情况下,首先要创建一个包含M x y的字符串,其中x y是路径的x,y起始位置,并且然后一次读取一个片段并使用上面的速记将它们附加到字符串,然后用Z结束字符串

请注意,大写和小写字母具有不同的含义。大写字母表示您为路径段提供绝对值,而小写字母表示它应该相对于最后一个段。

例如,如果您的细分显示"L 10 10",则意味着在网格上绘制一条线到位置10,10,而"l 10 10"表示从当前位置向上和向右画一条线10。 / p>

如果从数据库中读取PathGeometry,则需要将每个PathGeometry转换为字符串,然后组合字符串。

这里有一些粗略的代码作为例子。我知道它不起作用,但希望它可以指出你正确的方向

修改

根据您编辑过的问题,听起来您的数据项存储为PathGeometry,因此您可能需要将PathGeometry对象转换为字符串,然后只需将字符串组合

这是一个非常粗略的例子。我很确定我有一些语法错误,可能还有一些逻辑,因为我不熟悉PathGeometry对象,但希望它可以指出你正确的方向

foreach (PathGeometry pg1 in firstList)
    foreach (PathGeometry pg2 in secondList)
    {
        var s1 = ConvertGeometryToString(pg);
        var s2 = ConvertGeometryToString(pg2);

        // Ideally you probably wouldn't want this until you have your 
        // full PathGeometry string built, but I'm not sure what you're doing
        // with the object so left it in anyways
        PathGeometry intergeo = Geometry.Parse(s1 + s2);

    }
}


string ConvertGeometryToString(PathGeometry pg)
{
    StringBuilder sb = new StringBuilder();

    foreach(var figure in pg.PathFigures)
    {
        sb.Append("M " + figure.StartPoint);

        foreach(var seg in figure.Segments)
        {
            if (seg is LineSegment)
                sb.Append(" L " + ((LineSegment)seg).Point);

            else if (seg is ArcSegment)
            ... etc

        }

        if (figure.IsClosed)
            sb.Append(" Z");
    }

    return sb.ToString();
}

答案 1 :(得分:3)

System.Windows.Media还包含一个类StreamGeometry,它是PathGeometry的“轻量级选择”。它不支持数据绑定,动画或修改,但由于它派生自Geometry,因此它应该有Combine方法。

请参阅StreamGeometry @ MSDN

答案 2 :(得分:0)

我只是玩过它,但是NetTopologySuite看起来它会做你想要的。

下面的代码创建了两个多边形,检查它们是否相交,找到它们的区域并计算它们的交点。

var gf = new GeometryFactory();

var c1 = new[] { new Coordinate(0, 0), new Coordinate(2, 0),
                 new Coordinate(2, 2), new Coordinate(0, 2),
                 new Coordinate(0, 0) };
var lr1 = gf.CreateLinearRing(c1);
var p1 = gf.CreatePolygon(lr1, new ILinearRing[0]);

var c2 = c1.Select(c => new Coordinate(c.X + 1, c.Y + 1)).ToArray();
var lr2 = gf.CreateLinearRing(c2);
var p2 = gf.CreatePolygon(lr2, new ILinearRing[0]);

var intersects = p1.Intersects(p2);        // true
var intersection = p1.Intersection(p2);    // another polygon
var area = intersection.Area;              // 1.0