如何剪辑非封闭几何 [英] How to clip non-closed geometry

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

问题描述

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

I noticed an issue while implementing clipping (see this).

它看起来像UIElement.Clip仍然呈现看不见的地方

It looks like UIElement.Clip still render invisible parts

渲染相对小尺寸(行只的填写的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; ...

{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​​ ...

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

F1 手段非零填写

规则,确定一个点是否是在路径的填充区域由在任何方向拉伸,从该点的射线为无穷大并且随后检查形状的段穿过射线的地点。为零的计数开始,每一个段从左边穿过射线一次添加一个到右,每个路径段从右到左穿过射线时间减去一个。计数道口,如果结果是零后那么点的路径之外。否则,它是内在的。

Rule that determines whether a point is in the fill region of the path by drawing a ray from that point to infinity in any direction and then examining the places where a segment of the shape crosses the ray. Starting with a count of zero, add one each time a segment crosses the ray from left to right and subtract one each time a path segment crosses the ray from right to left. After counting the crossings, if the result is zero then the point is outside the path. Otherwise, it is inside.

和我完全不知道这意味着什么。但也许是很重要的?

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}

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

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆