前言 凸度 (bulge) 是 AutoCAD 中一个非常重要的概念, 凸度控制着两点之间弧度大小, 弧度的方向. 各种复杂的图像有可能就是成百上千的弧线组成的. 从 AutoCAD 中导出的数据也有该值, 一般的形式为两个点坐标, 一个凸度值. 所以理解凸度的概念是处理 AutoCAD 文件重要的前提. 本文会简要介绍一下凸度的概念, 同时会给出如何根据点坐标和凸度划线.
凸度演示程序
1 凸度的概念
凸度有两个作用控制顶点弧度的大小和弧度的方向. 如果通过两个坐标点画弧, 会有无数种可能性, 所以必须引入第三个参数, 来确定经过这两点的唯一弧线, 这个参数就是凸度.
凸度反应了两点之间对应弧度的大小, 它的具体值为这段弧所包含角度的 1/4 角度的正切值. 两点对应的弧度最大值为无限接近 360 度, 凸度对应的值为接近 90 度的正切值, 所以凸度最大值为无穷大.
仔细观察上图, 图 B 的弧度大于图 A 的弧度, 但是图 B 的半径小于图 A.
为什么引入凸度值就能唯一确定弧线了? 当凸度确定了, 其实弧度对应的半径就确定了. 考察一下图 C, 红线标识的部分为一个等腰三角形, 等腰三角形底边长度和顶点角度确定了, 就能唯一确定一个三角形大小(属于初中几何知识). 等腰三角形的两个腰长度就是圆的半径.
2 根据凸度计算及画图
不同的画图函数需要的参数也不同, 我这里根据具体的画图函数来讲解, 如何画图.
WPF 绘图上下文类为 DrawingContext, 这个类有一个绘图函数
public abstract void DrawGeometry(Brush brush, Pen pen, Geometry geometry);
这个函数很简单, 但是这个函数可以画任意图形; 因为 Geometry 类功能太强大了, 这个类可以描述任意几何形状. 看一下如下代码:
- void AddArc(PathGeometry pathGeometry, System.Windows.Point point1, System.Windows.Point point2, double bulge, double radius)
- {
- PathFigure pathFigure = new PathFigure();
- pathFigure.StartPoint = point1;// 起点
- ArcSegment arcSegment = new ArcSegment();
- arcSegment.Point = point2; // 终点
- // 半径
- arcSegment.Size = new System.Windows.Size(radius, radius);
- // 对应的角度
- double radian = Math.Atan(bulge) * 4;
- double angle = radian * 180 / Math.PI;
- arcSegment.RotationAngle =Math.Abs(angle);
- // 弧度的方向 顺时针还是逆时针
- arcSegment.SweepDirection = bulge>0? SweepDirection.Clockwise:SweepDirection.Counterclockwise;
- // 是否大于 180 度
- arcSegment.IsLargeArc = Math.Abs(bulge)> 1;
- pathFigure.Segments.Add(arcSegment);
- pathGeometry.Figures.Add(pathFigure);
- }
上述代码根据两点, 凸度, 圆半径来实现画图.(半径是根据前三个计算出来的, 后面会讲该算法)
一个 PathGeometry 由一个或多个图形暨 PathFigure 组成. PathFigure 就是一系列封闭或不封闭的线段或弧线组成. ArcSegment 代表一个弧线, 将其加入到 PathFigure, 再将 PathFigure 加入到 Geometry , 这样就可以根据 DrawGeometry 画出弧线了. 函数有注释, 非常容易理解.
ArcSegment 还有一个参数就是圆的半径. 其实根据两点,'凸度就可推导出半径, 不知道为什么 ArcSegment 不替我们计算出来. 下面讲一下如何计算半径.
3 根据凸度计算半径
- public static double CalBulgeRadius(System.Windows.Point point1, System.Windows.Point point2, double bulge)
- {
- // 计算顶点角度
- double cicleAngle = Math.Atan(bulge) * 4;
- // 两点之间的距离
- double pointLen = ImageHelper.CalPointLen(point1, point2);
- // 根据正玄值反推
- double radius = (pointLen / 2) / Math.Sin(cicleAngle / 2);
- return Math.Abs(radius);
- }
看左图, 可知: 顶点对应的角度的一半的正玄值就是 两点之间的长度除以半径. 根据这一点就可以算出半径.
3 计算圆点
上述函数虽然可以画出圆弧, 但是我们还是不知道圆心坐标. 这里将一下如何推导出圆心坐标.
这里有一个概念就是旋转, 将求解圆心坐标分为两个步骤. 第一步在两点之间取一点(点 3), 该点到点 1 的长度为半径; 第二步, 将此点旋转一定角度, 就得到圆心坐标.
求点 3:
- // 两点之间的距离
- double pointLen = ImageHelper.CalPointLen(point1, point2);
- // 半径与两点之间距离的比值
- double lenRate = radius / pointLen;
- System.Windows.Point midPoint = ImageHelper.GetMidPoint(point1, point2, lenRate);
- internal static System.Windows.Point GetMidPoint(System.Windows.Point pt1, System.Windows.Point pt2, double lenRate)
- {
- Debug.Assert(lenRate>=0);
- if (lenRate == 1)
- return pt2;
- if (lenRate == 0)
- return pt1;
- System.Windows.Point result = new System.Windows.Point();
- result.X = pt1.X + lenRate * (pt2.X - pt1.X);
- result.Y = pt1.Y + lenRate * (pt2.Y - pt1.Y);
- return result;
- }
根据几何知识, 可以得知: 半径与两点之间的比率与点 3 的 X 坐标与两点的 X 坐标比率一样, 这样就能求出 X 坐标. 同理, 可以求出 Y 坐标.
旋转:
点 3 以点 1 位圆心, 旋转一定角度, 点 3 就落在圆心上了. 旋转的角度不难计算, 顶点角度已知, 又是等腰三角形, 所以三角形的底角很容易算出.
旋转计算涉及二维向量运算, 不过. NET 为我们提供了类 Matrix.
- public static System.Drawing.Point RotationAt(System.Drawing.Point pointMove, System.Drawing.Point removeAt,
- double rotateAngle, bool clockwise)
- {
- if (rotateAngle == 0)
- return pointMove;
- lock (matrix)
- {
- matrix.Reset();
- // 设置旋转的角度
- matrix.Rotate((float)(clockwise ? rotateAngle : -rotateAngle));
- // 相对于 removeAt 旋转
- System.Drawing.Point pt2 = new System.Drawing.Point(pointMove.X - removeAt.X, pointMove.Y - removeAt.Y);
- System.Drawing.Point[] pts = new System.Drawing.Point[] { new System.Drawing.Point(pt2.X, pt2.Y) };
- matrix.TransformPoints(pts);
- // 再变换到圆点位置
- System.Drawing.Point result = new System.Drawing.Point(pts[0].X + removeAt.X, pts[0].Y + removeAt.Y);
- return result;
- }
- }
后记: 在二维坐标上画图, 需要有一定的几何基础和空间想象能力. 初始接触这类编程, 还是有一定难度的. 就需要我们补充一些几何知识, 同时多思考, 总有一天会感觉豁然开朗.
来源: https://www.cnblogs.com/yuanchenhui/p/autocad_bulge.html