本文经原作者授权以原创方式二次分享,欢迎转载、分享。
原文作者:唐宋元明清
原文地址: 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没?