本文经原作者授权以原创方式二次分享,欢迎转载、分享。
原文作者:唐宋元明清
原文地址: https://www.cnblogs.com/kybs0/p/16593146.html
C# 笔迹擦除8边形
擦除区域与橡皮大小不一致
测试反馈,擦除区域与真实的橡皮大小不一致;
上图中,橡皮显示是圆形的,但擦除效果是一个8边形区域。
找了一台8K屏,确实是能复现的;
看到这个诡异的8边形,一开始我是以为是逗逼小伙伴在手势识别模块写出来的BUG;
但开发肯定不会弄这么规整的形状出来,所以还是要看下擦除模块、看下具体问题在哪
擦除模块流程&定位
StrokeCollection类下面,有个GetIncrementalStrokeHitTester方法,根据擦除图形来创建擦除命中测试的处理类;
所以我们创建了一个
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
:
可以看到
StrokeHitEventArgs
构造有俩个参数,一个是HitStroke
(擦除操作命中的笔迹),另一个是擦除后的笔迹集合(可能是一个stroke
,也可能是多个)我们回到擦除
8边形
的问题上。所以,上面擦除操作中的代码并没有所谓的8边形
相关异常,我们去看看其它的代码上图中有个参数
_erasingStroke,_erasingStroke = new ErasingStroke(eraserShape)
,而eraserShape
就是我们上面说的擦除形状。我们一步步跟下去,可以看到
StrokeNodeOperations
初始化时,去调用了StylusShape
抽象类的内部方法GetVerticesAsVectors()
;
而
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
函数:
如上图所标示,顶点一共
12
个,其实应该叫12边形
,只不过因为上下左右的折角是180度
,所以看起来是8边形
。0.552284749830793
这个系数是8边形
折线的水平/竖直位置计算系数。根据这
12
个点,生成12
个向量。然后以12
个向量组合为Bounds
,这个Bounds
就是擦除命中测试的图形。根据上面描述,我们可以确定,
8边形
问题源头就是这个StylusShape
类,源码设计如此。至于为何是
8边形
,而不是其它的形状。应该是不想用太复杂的图形去做计算,毕竟真要实现完整的圆形,数学几何里圆也是多边形,所以要用N多边形
的话性能会有影响。而在一个正方形的基础上,搞四个边角,能实现擦除功能也能保障擦除性能,这个设计没毛病。
以
WPF
为框架的白板/批注等应用,都有这个BUG
所以,测试同学有给你报这个BUG
没?