C# 笔迹擦除8边形

本文经原作者授权以原创方式二次分享,欢迎转载、分享。

原文作者:唐宋元明清

原文地址:   https://www.cnblogs.com/kybs0/p/16593146.html

 C# 笔迹擦除8边形

擦除区域与橡皮大小不一致

  • 测试反馈,擦除区域与真实的橡皮大小不一致;

04a66aa6dde5d6f7ff651c28fb9d8535.png
  • 上图中,橡皮显示是圆形的,但擦除效果是一个8边形区域。

  • 找了一台8K屏,确实是能复现的;

cd341dd451b58bdef9908cd2b6d4c0b8.png
  • 看到这个诡异的8边形,一开始我是以为是逗逼小伙伴在手势识别模块写出来的BUG

  • 但开发肯定不会弄这么规整的形状出来,所以还是要看下擦除模块、看下具体问题在哪

  • 擦除模块流程&定位

  • StrokeCollection类下面,有个GetIncrementalStrokeHitTester方法,根据擦除图形来创建擦除命中测试的处理类;

b2ed6cdfa9e882cd0e3df6263b048199.png
  • 所以我们创建了一个100*100大小的圆形 ,用于擦除操作;

var stylusShape = new EllipseStylusShape(100,100);
     var hitTester = InkStrokes.GetIncrementalStrokeHitTester(stylusShape);
  • 既然是Ellipse,那肯定不存在8边形

  • 我们再看看具体的擦除操作:

private void CreateStrokeHitTester()
    {
        var stylusShape = new EllipseStylusShape(100, 100);
        var hitTester = InkStrokes.GetIncrementalStrokeHitTester(stylusShape);
        hitTester.AddPoints(points);
        hitTester.StrokeHit += StrokeHitTester;
    }
    private void StrokeHitTester1(object sender, StrokeHitEventArgs e)
    {
        var hitStroke = e.HitStroke;
        var eraseResults = e.GetPointEraseResults();
    }
  • hitTester.AddPoints(points) -- 为命中测试处理类,添加点集。

  • hitTester.StrokeHit += StrokeHitTester -- 添加点集时,hitTester内部会根据点集形成一条路径,然后获取路径对应的矩形Bounds。

  • 使用路径Bounds与笔迹Strokes做相交判断,确认相交的话,触发StrokeHit命中事件并生成擦除后的Strokes

81d567854ffb4db475adbb79ed21d4fc.png
  • 可以看到StrokeHitEventArgs构造有俩个参数,一个是HitStroke(擦除操作命中的笔迹),另一个是擦除后的笔迹集合(可能是一个stroke,也可能是多个)

  • 我们回到擦除8边形的问题上。所以,上面擦除操作中的代码并没有所谓的8边形相关异常,我们去看看其它的代码

  • 上图中有个参数_erasingStroke,_erasingStroke = new ErasingStroke(eraserShape),而eraserShape就是我们上面说的擦除形状。

  • 我们一步步跟下去,可以看到StrokeNodeOperations初始化时,去调用了StylusShape抽象类的内部方法GetVerticesAsVectors()

ede0870fc9f4d79ede8d816dc52fd6a9.png
  • StylusShape内部,如果是矩形形状则直接在构造函数初始化形状的顶点数据。如果是圆形则会延迟初始化,在有需要时获取顶点数据_vertices

Point[] bezierControlPoints = this.GetBezierControlPoints();
     vertices = new Vector[bezierControlPoints.Length];
     for (int index = 0; index < vertices.Length; ++index)
       ertices[index] = (Vector) bezierControlPoints[index];
  • 圆形是通过执行GetBezierControlPoints来获取内部的点集,我们来看GetBezierControlPoints函数:

138269e554319e7bd9e9092c9a34b681.png
  • 如上图所标示,顶点一共12个,其实应该叫12边形,只不过因为上下左右的折角是180度,所以看起来是8边形

  • 0.552284749830793这个系数是8边形折线的水平/竖直位置计算系数。

  • 根据这12个点,生成12个向量。然后以12个向量组合为Bounds,这个Bounds就是擦除命中测试的图形。

  • 根据上面描述,我们可以确定,8边形问题源头就是这个StylusShape类,源码设计如此。

  • 至于为何是8边形,而不是其它的形状。应该是不想用太复杂的图形去做计算,毕竟真要实现完整的圆形,数学几何里圆也是多边形,所以要用N多边形的话性能会有影响。

  • 而在一个正方形的基础上,搞四个边角,能实现擦除功能也能保障擦除性能,这个设计没毛病。

  • WPF为框架的白板/批注等应用,都有这个BUG所以,测试同学有给你报这个BUG没?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值