问题描述
我注意到一个问题,同时实施削波(请参见)。
I noticed an issue while implementing clipping (see this).
它看起来像UIElement.Clip仍然呈现看不见的地方
渲染相对小尺寸(行只的填写的1920x1200的区域〜2000年垂直线)采取了大量的时间。当使用剪辑
和移动的是几何屏幕外(这样裁剪应该删除它显著一部分)仍是需要的相同时间(约1秒)。
Rendering relatively small geometry (lines to only fill 1920x1200 area ~ 2000 vertical lines) take a lot of time. When using Clip
and moving that geometry offscreen (so that clipping should remove significant part of it) it is still take same time (around 1 sec).
好吧,我发现什么用 Geometry.Combine
会做剪辑(渲染时间是按比例缩小的几何剪裁后拆除)。完美!
Ok, I found what using Geometry.Combine
will do a clip (render time is reduced proportionally to removed after clipping geometry). Perfect!
Geometry.Combine
没有按非封闭的几何形状正确'T的工作。它产生封闭的几何形状。而且相貌丑陋,连接第一和最后一点:
Geometry.Combine
doesn't work with non-closed geometry properly. It produce closed geometry. And it looks ugly, connecting first and last point:
我怎么能执行限幅(减少几何图形的数量是渲染)非封闭式的数字?
How can I perform clipping (reducing amount of geometry to be rendered) for non-closed figures?
下面是前(上图所示的小和平几何)
Here is geometry before (small peace of shown on picture)
{M0; 50L0,50L1; 53,1395259764657L2; 56,2666616782152L3; 59,3690657292862L4; 62,4344943582427L5; 65,4508497187474L6; 68,4062276342339L7; 71,2889645782536L8; ...
和后
{F1M54,9999923706055; 34,5491371154785L53,9999885559082; 37,5655174255371 53,0000114440918; 40,6309471130371 52,0000076293945; 43,7333335876465 ...
在开始通知的变化,是 M 0; 50升...
,成为˚F1M的55; 34升...
Notice change at beginning, was M 0;50 L ...
, become F 1 M 55;34 L ...
的手段非零
填写
规则,确定一个点是否是在路径的填充区域由在任何方向拉伸,从该点的射线为无穷大并且随后检查形状的段穿过射线的地点。为零的计数开始,每一个段从左边穿过射线一次添加一个到右,每个路径段从右到左穿过射线时间减去一个。计数道口,如果结果是零后那么点的路径之外。否则,它是内在的。
和我完全不知道这意味着什么。但也许是很重要的?
And I have absolutely no clue what that means. But maybe it is important?
我一直在寻找的字符串的结束。有以Z
在 Path.Data code>的结束,这意味着数字是关闭的。
I should have been looking at the end of strings. There is z
at the end of Path.Data
, which means figure is closed.
奇怪的是,试图删除以Z
(使用 Geometry.ToString()
/ Geometry.Parse()
组合)不工作。经过一番调查,我发现了什么联合
产生物理封闭的数字(命令长x; Y
,其中 X; Y
是最左边的点)。而最糟糕的事情是什么它并不总是最后一个点,于是干脆去掉最后长x; Y
解析之前没有任何工作。 =(
Strangely enough, trying to remove z
(by using Geometry.ToString()
/Geometry.Parse()
combo) doesn't works. After some investigation I found what Combine
produces physically enclosing figures (commands L x;y
, where x;y
is the leftmost point). And the worst thing is what it's not always the last point, so simply removing last L x;y
before parsing doesn't works either. =(
样品展示问题:
XAML中:
<Path x:Name="path" Stroke="Red"/>
代码:
var geometry1 = new RectangleGeometry(new Rect(100, 100, 100, 100));
var geometry2 = new PathGeometry(new[] { new PathFigure(new Point(0,0), new[] {
new LineSegment(new Point(300, 300), true),
new LineSegment(new Point(300, 0), true),
}, false) });
//path.Data = geometry1;
//path.Data = geometry2;
//path.Data = Geometry.Combine(geometry1, geometry2, GeometryCombineMode.Intersect, null);
图片和 geometry2
:
致使结合
:
正如你可以看到两行剪裁后变成3,调试证明了这一点:
As you can see 2 lines become 3 after clipping, debugging proves it:
{F1M100; 100L200; 100 200 200 100; 100Z}
注意,它不仅ž
,也 100; 100
点底,连接起点
Notice, it's not only z
, but also 100;100
point at the end, connecting starting point.
推荐答案
我试图实现的基础上的线的交点算法
I attempted to implement a clipping solutions for non closed geometry based on this line intersection algorithm
代码
public static PathGeometry ClipGeometry(PathGeometry geom, Rect clipRect)
{
PathGeometry clipped = new PathGeometry();
foreach (var fig in geom.Figures)
{
PathSegmentCollection segments = new PathSegmentCollection();
Point lastPoint = fig.StartPoint;
foreach (LineSegment seg in fig.Segments)
{
List<Point> points;
if (LineIntersectsRect(lastPoint, seg.Point, clipRect, out points))
{
LineSegment newSeg = new LineSegment(points[1], true);
PathFigure newFig = new PathFigure(points[0], new[] { newSeg }, false);
clipped.Figures.Add(newFig);
}
lastPoint = seg.Point;
}
}
return clipped;
}
static bool LineIntersectsRect(Point lineStart, Point lineEnd, Rect rect, out List<Point> points)
{
points = new List<Point>();
if (rect.Contains(lineStart) && rect.Contains(lineEnd))
{
points.Add(lineStart);
points.Add(lineEnd);
return true;
}
Point outPoint;
if (Intersects(lineStart, lineEnd, rect.TopLeft, rect.TopRight, out outPoint))
{
points.Add(outPoint);
}
if (Intersects(lineStart, lineEnd, rect.BottomLeft, rect.BottomRight, out outPoint))
{
points.Add(outPoint);
}
if (Intersects(lineStart, lineEnd, rect.TopLeft, rect.BottomLeft, out outPoint))
{
points.Add(outPoint);
}
if (Intersects(lineStart, lineEnd, rect.TopRight, rect.BottomRight, out outPoint))
{
points.Add(outPoint);
}
if (points.Count == 1)
{
if (rect.Contains(lineStart))
points.Add(lineStart);
else
points.Add(lineEnd);
}
return points.Count > 0;
}
static bool Intersects(Point a1, Point a2, Point b1, Point b2, out Point intersection)
{
intersection = new Point(0, 0);
Vector b = a2 - a1;
Vector d = b2 - b1;
double bDotDPerp = b.X * d.Y - b.Y * d.X;
if (bDotDPerp == 0)
return false;
Vector c = b1 - a1;
double t = (c.X * d.Y - c.Y * d.X) / bDotDPerp;
if (t < 0 || t > 1)
return false;
double u = (c.X * b.Y - c.Y * b.X) / bDotDPerp;
if (u < 0 || u > 1)
return false;
intersection = a1 + t * b;
return true;
}
目前解决方案适用于基于线几何,其他类型也许需要包括如果必要的。
currently solution works for line based geometry, other types perhaps need to be included if needed.
测试XAML
<UniformGrid Columns="2"
Margin="250,250,0,0">
<Grid>
<Path x:Name="pathClip"
Fill="#22ff0000" />
<Path x:Name="path"
Stroke="Black" />
</Grid>
<Path x:Name="path2"
Margin="100,0,0,0"
Stroke="Black" />
</UniformGrid>
测试代码1
void test()
{
var geometry = new PathGeometry(new[] { new PathFigure(new Point(0,0), new[] {
new LineSegment(new Point(300, 300), true),
new LineSegment(new Point(300, 0), true),
}, false) });
Rect clipRect= new Rect(10, 10, 180, 180);
path.Data = ClipGeometry(geometry, clipRect);
path2.Data = geometry;
pathClip.Data = new RectangleGeometry(clipRect);
}
结果
result
测试代码2
void test()
{
var radius = 1.0;
var figures = new List<LineSegment>();
for (int i = 0; i < 2000; i++, radius += 0.1)
{
var segment = new LineSegment(new Point(radius * Math.Sin(i), radius * Math.Cos(i)), true);
segment.Freeze();
figures.Add(segment);
}
var geometry = new PathGeometry(new[] { new PathFigure(figures[0].Point, figures, false) });
Rect clipRect= new Rect(10, 10, 180, 180);
path.Data = ClipGeometry(geometry, clipRect);
path2.Data = geometry;
pathClip.Data = new RectangleGeometry(clipRect);
}
结果
result
试一试,看看如何关闭是的。
give it a try and see how close it is.
这篇关于如何剪辑非封闭几何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!