本文介绍了如何剪辑非封闭几何的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到一个问题,同时实施削波(请参见)。

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,139525976465​​7L2; 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 的结束,这意味着数字是关闭的。

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.

这篇关于如何剪辑非封闭几何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 16:24