我有两个巨大的(> 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,因此创建其他东西也没有问题。但我需要一个函数来创建这些几何中的两个(不是相互添加)的交集,以获得两个几何所覆盖的区域,例如此图中的红色区域:
答案 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
)可以分解为:
在从数据库中读取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
方法。
答案 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