专栏首页林德熙的博客win2d 画出好看的图形

win2d 画出好看的图形

本文告诉大家,win2d 不需要从零开始做,以前做出来的很多库其实只需要做很小修改就可以做出好看的效果,而且用在 UWP 上。本文修改原先 大神写的 GDI 图形到 win2d 上,而且可以运行起来。

一开始先发一张图片给大家看,本文就是告诉大家如何做出下面这张图的效果。

本文的算法是学习 山人大大的博客 http://blog.csdn.net/johnsuna/article/details/7981521 ,在他上面做一点修改做出来的。

可以看到他的博客使用的方法就是 GDI ,这是古时候使用的技术,而现在的 UWP 可以在以前的技术上,做一点修改就可以使用。

如果需要使用 win2d ,我希望大家先看这篇文章,本文不会继续告诉大家如何安装 win2d 。

首先需要了解一个技术,从 point 数组画出来。

如果给了一个 point 数组,那么可以使用这个数组画出形状。

在 win2d 下,可以使用 DrawGeometry 方法画出来。

可以看到 DrawGeometry 的第一个参数是 CanvasGeometry ,第二个参数是可以选的 ,一般使用颜色就好了。

但是 CanvasGeometry 是没有构造方法,所以 UWP 需要使用 CanvasGeometry.CreatePolygon 等方法创建出来。

本文因为需要把 point 数组显示,所以就使用了 CanvasGeometry.CreatePolygon 。这个方法的第一个参数是 ICanvasResourceCreator ,获得 ICanvasResourceCreator 很简单,传入 draw.Device 。

所以代码如下。

        private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
        {
            var draw = args.DrawingSession;
            
            var canvasGeometry = CanvasGeometry.CreatePolygon(draw.Device,
                    point.Select(temp => new Vector2((float) temp.X, (float) temp.Y)).ToArray());
            draw.DrawGeometry(canvasGeometry, Color.FromArgb(255, 100, 100, 100));            
        }

那么 point 是如何得到,本文使用 http://blog.csdn.net/johnsuna/article/details/7981521 的方法获得。

        public static Point[] CreateStone(Point center, int outerRadius, int innerRadius, int arms)
        {
            int centerX = (int) center.X;
            int centerY = (int) center.Y;
            Point[] points = new Point[arms * 2];
            double offset = Math.PI / 2;
            double arc = 2 * Math.PI / arms;
            double half = arc / 2;
            for (int i = 0; i < arms; i++)
            {
                Random randomOuter = new Random((int) DateTime.Now.Ticks);
                outerRadius = outerRadius -
                              randomOuter.Next((int) (innerRadius * 0.06 * new Random().Next(-20, 20) / 30d),
                                  (int) (innerRadius * 0.08));
                Random randomInner = new Random(Guid.NewGuid().GetHashCode());
                innerRadius = innerRadius +
                              randomInner.Next((int) (innerRadius * 0.02 * new Random().Next(-100, 100) / 150d),
                                  (int) (innerRadius * 0.08));
                if (innerRadius > outerRadius)
                {
                    int temp = outerRadius;
                    outerRadius = innerRadius;
                    innerRadius = temp;
                }
                double angleTemp = arc * randomInner.Next(-5, 5) / 10d;
                var angle = i * arc;
                angle += angleTemp;
                points[i * 2].X = (float) (centerX + Math.Cos(angle - offset) * outerRadius) + 20;
                points[i * 2].Y = (float) (centerY + Math.Sin(angle - offset) * outerRadius) + 20;
                points[i * 2 + 1].X = (float) (centerX + Math.Cos(angle + half - offset) * innerRadius) + 20;
                points[i * 2 + 1].Y = (float) (centerY + Math.Sin(angle + half - offset) * innerRadius) + 20;
            }

            return points;
        }

如果需要画出来图形,那么需要两个成员属性

        private List<Point[]> _points = new List<Point[]>();

        private Dictionary<string, Stone> _stone;

_points 就是所有画出的点,_stone 就是告诉说,如何画,因为可以传入的数值 角度,长宽,胖瘦,微移间隙 等的不同,可以画出不同的图形,所以需要通过一个属性来告诉如何画

    public class Stone
    {
        public static Point[] CreateStone(Point center, int outerRadius, int innerRadius, int arms)
        {
            int centerX = (int) center.X;
            int centerY = (int) center.Y;
            Point[] points = new Point[arms * 2];
            double offset = Math.PI / 2;
            double arc = 2 * Math.PI / arms;
            double half = arc / 2;
            for (int i = 0; i < arms; i++)
            {
                Random randomOuter = new Random((int) DateTime.Now.Ticks);
                outerRadius = outerRadius -
                              randomOuter.Next((int) (innerRadius * 0.06 * new Random().Next(-20, 20) / 30d),
                                  (int) (innerRadius * 0.08));
                Random randomInner = new Random(Guid.NewGuid().GetHashCode());
                innerRadius = innerRadius +
                              randomInner.Next((int) (innerRadius * 0.02 * new Random().Next(-100, 100) / 150d),
                                  (int) (innerRadius * 0.08));
                if (innerRadius > outerRadius)
                {
                    int temp = outerRadius;
                    outerRadius = innerRadius;
                    innerRadius = temp;
                }
                double angleTemp = arc * randomInner.Next(-5, 5) / 10d;
                var angle = i * arc;
                angle += angleTemp;
                points[i * 2].X = (float) (centerX + Math.Cos(angle - offset) * outerRadius) + 20;
                points[i * 2].Y = (float) (centerY + Math.Sin(angle - offset) * outerRadius) + 20;
                points[i * 2 + 1].X = (float) (centerX + Math.Cos(angle + half - offset) * innerRadius) + 20;
                points[i * 2 + 1].Y = (float) (centerY + Math.Sin(angle + half - offset) * innerRadius) + 20;
            }

            return points;
        }

        public Func<float, float, int, int, Point> GetCenter;
        public Func<float, int> GetinnerRadius;
        public Func<float, int> GetouterRadius;
        public int maxCorners = 18;
        public int minCorners = 3;
    }

所以在构造使用下面代码

        public MainPage()
        {
            InitializeComponent();

            _stone = new Dictionary<string, Stone>()
            {
                {
                    "星", new Stone()
                    {
                        minCorners = 3,
                        maxCorners = 20,
                        GetCenter = (perX, perY, i, j) => new Point((int) (perX * j), (int) (perY * i)),
                        GetouterRadius = perX => (int) (perX * 0.18f),
                        GetinnerRadius = perX => (int) (perX * 0.06f)
                    }
                },
            };
        }

在界面弄个按钮

        <xaml:CanvasControl x:Name="canvas" Margin="10,10,10,100" Height="600" ClearColor="White" Draw="Canvas_OnDraw"></xaml:CanvasControl>

         <Button Margin="10,600,10,10" Content="星" Click="Button_OnClick"></Button>           

然后写他的点击代码

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            string str = ((Button) sender).Content?.ToString();

            _points = new List<Point[]>();

            int width = 500;
            int height = 500;
            int numX = 10;
            int numY = 10;
            float perX = width * 1f / numX;
            float perY = height * 1f / numY;

            int minCorners = _stone[str].minCorners;
            int maxCorners = _stone[str].maxCorners;

            int lastCorners = minCorners;
            Random random = new Random();
            for (int i = 0; i < numX; i++)
            {
                for (int j = 0; j < numY; j++)
                {
                    int corners = random.Next(minCorners, maxCorners);
                    if (Math.Abs(corners - lastCorners) < (maxCorners - minCorners) / 2)
                        corners = RetrievRandomCorners(minCorners, maxCorners);
                    lastCorners = corners;
                    Point point = _stone[str].GetCenter(perX, perY, i, j);
                    int outerRadius = _stone[str].GetouterRadius(perX);
                    int innerRadius = _stone[str].GetinnerRadius(perX);
                    var points = Stone.CreateStone(point, outerRadius,
                        innerRadius, corners);
                    _points.Add(points);
                }
            }

            canvas.Invalidate();
        }

尝试跑一下,点击一次按钮就会有不同的图形,是不是感觉世界都是假的。

是不是觉得这样已经完成?实际上不要忘记很重要一步,win2d在不使用需要自己手动把他从视觉树释放,所以在后台代码页面跳出使用下面代码

        private void Page_OnUnloaded(object sender, RoutedEventArgs e)
        {
            canvas.RemoveFromVisualTree();
            canvas = null;
        }

感觉这个星期的时间很快,我仔细想了从 2015 年开始 UWP 的研究到现在,实际我一个软件都没做出来,就是在写写博客。如果你觉得有哪个地方不想去看,或者垃圾微软写的不太好的,但你不想去研究的,就可以告诉我,我去研究一下,如果我学会了,我就会写一篇博客,虽然我写出来肯定比不上微软的。

代码:https://github.com/lindexi/UWP/tree/master/uwp/control/win2d/Dclutterpalan


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • WPF popup置顶 另外的已知问题

    http://www.cnblogs.com/Leaco/p/3164394.html

    林德熙
  • C# 快速释放内存的大数组

    本文告诉大家如何使用 Marshal 做出可以快速释放内存的大数组。 最近在做 3D ,需要不断申请一段大内存数组,然后就释放他,但是 C# 对于大内存不是立刻...

    林德熙
  • WPF 多指触摸拖拽窗口 拖动修改窗口坐标

    在 WPF 中,如果是鼠标点击拖动窗口坐标,可以调用 Window 的 DragMove 方法,但是如果是触摸,就需要自己调用 Win32 的方法实现

    林德熙
  • 编程填空:第i位替换 编程填空:第i位取反 编程填空:左边i位取反

    写出函数中缺失的部分,使得函数返回值为一个整数,该整数的第i位和m的第i位相同,其他位和n相同。

    Dar_Alpha
  • 洛谷P4841 城市规划(生成函数 多项式求逆)

    一开始想的是直接设 表示i个点的无向联通图个数,枚举最后一个联通块转移,发现有一种情况转移不到。。。

    attack
  • Educational Codeforces Round 67 (Rated for Div. 2) A~E 贪心,构造,线段树,树的子树

    Educational Codeforces Round 67 (Rated for Div. 2)

    用户2965768
  • 09:向量点积计算

    09:向量点积计算 总时间限制: 1000ms 内存限制: 65536kB描述 在线性代数、计算几何中,向量点积是一种十分重要的运算。 给定两个n维向量a=(...

    attack
  • 指针详解(一)

    C语言可谓是因为指针而拥有了其他的语言所不拥有的作用,但是却又因为指针导致它对于初学者而言是一个很难克服的难题。接下来我们直切主体——指针。

    石的三次方
  • LeetCode 1632. Rank Transform of a Matrix

    思路是贪心,将所有的元素从小到大排序。并且维护两个数组,一个数组代表每一行的当前已经填上的最大的rank,比如nrank[0]=2 表示第0行,目前已经填到了r...

    ShenduCC
  • Leetcode 周赛题解 220

    给你一个字符串形式的电话号码 number 。number 由数字、空格 ' '、和破折号 '-' 组成。

    ACM算法日常

扫码关注云+社区

领取腾讯云代金券