AutoCAD 中凸度(bulge)的概念及使用Canvas画图

1.概念解释

在解析Cad时,凸度(bulge)是一个比较重要的概念,它控制着弧线的凸起的方向和圆弧的半径,在WoutWare官网的API中,是这样解释bulge属性的:

The bulge is the tangent of one fourth the included angle for an arc segment, made negative if the arc goes clockwise from the start point to the endpoint. A bulge of 0 indicates a straight segment, and a bulge of 1 is a semicircle. 

简单翻译一下,意思为:
凸度是圆弧段四分之一夹角的正切值,如果圆弧从起点到终点顺时针移动,则凸出为负值。凸度为0表示直线段,凸度为1表示半圆。

根据属性的定义可知,不考虑正负值的情况下,凸度最小值为0(直线),最大值趋近于无穷大(接近于整圆)

2.canvas画图

在canvas中,画弧的API有两个,分别是arc和arcTo,这两个函数定义如下:

void ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
圆弧路径的圆心在 (x, y) 位置,半径为 r ,根据anticlockwise (默认为false表示顺时针)指定的方向从 startAngle 开始绘制,到 endAngle 结束。其中startAngle 和endAngle 的单位为弧度,即Math.PI表示180度。
void ctx.arcTo(x1, y1, x2, y2, radius);
根据控制点和半径绘制圆弧路径,使用当前的描点(前一个moveTo或lineTo等函数的止点)。根据当前描点与给定的控制点1连接的直线,和控制点1与控制点2连接的直线,作为使用指定半径的圆的切线,画出两条切线之间的弧线路径。

根据定义可知,arcTo只能画bulge<1的弧,arc或以画任意角度的弧,最初画图时,没有仔细查看bulge的定义,认为bulge<=1,所以采用了arcTo的方法,去计算控制点2,直到发现导出的数据中有bulge>1的时候,才发现arcTo的局限性,才通过计算圆心坐标采用arc方法去画图

2.1计算圆弧半径

 由图中可知,半径r = (d/2)/sin(a)

var a = Math.atan(p1.bulge)*2;
var d = Math.abs((p1.x==p2.x)?(p1.y-p2.y):((p1.y==p2.y)?(p1.x-p2.x):(p2.y-p1.y)/Math.sin(Math.atan((p2.y-p1.y)/(p2.x-p1.x)))));
var r = Math.abs((d / 2) / Math.sin(a));

在距离计算中,使用了三角函数,避免了开平方的运算

2.2通过计算辅助点p3画弧

 此处,引入坐标系,并将弧度做了一定的偏转,此时可得到以下计算公式:

tan(a+b)=(p1.y-p3.y)/(p1.x-p3.x)

tan(a-b)=(p2.y-p3.y)/(p3.x-p2.x)    =>

p1.y-p3.y = tan(a+b)*(p1.x-p3.x)

p2.y-p3.y=tan(a-b)*(p3.x-p2.x)    =>

p3.y = p1.y-tan(a+b)*(p1.x-p3.x) = p2.y-tan(a-b)*(p3.x-p2.x)    =>

p1.y-tan(a+b)*p1.x+tan(a+b)*p3.x=p2.y-tan(a-b)*p3.x+tan(a-b)*p2.x    =>

tan(a+b)*p3.x+tan(a-b)*p3.x=p2.y-p1.y+tan(a-b)*p2.x+tan(a+b)*p1.x    =>

p3.x = (p2.y-p1.y+tan(a-b)*p2.x+tan(a+b)*p1.x)/(tan(a+b)+tan(a-b))    =>

p3.y = p1.y-tan(a+b)*(p1.x-p3.x)

 至此,计算公式推导完成,上代码:

var b = Math.atan((p2.y-p1.y)/(p1.x-p2.x));
var tab = Math.tan(a+b);
var ta_b = Math.tan(a-b);
var p3 = {};
p3.x = (ta_b*p1.x+tab*p2.x+p2.y-p1.y)/(tab+ta_b);
p3.y = p1.y-tab*(p1.x-p3.x);
ctx.arcTo(p3.x, p3.y, p2.x, p2.y, r);

2.3通过计算圆心画弧

 看图可知,想要计算圆心o的坐标,可以先计算出p3,使p2-p3的距离=半径r,再将p3围绕p2旋转角b的度数即可得到圆心o的坐标

在2.1中,已经计算出的角度a和半径r,以及p1到p3的距离d,此处可直接应用

var p3 = {}, o = {};
p3.x = p2.x+(p1.x-p2.x)*r/d;
p3.y = p2.y+(p1.y-p2.y)*r/d;

p3的坐标计算出来了,下面该使用旋转来计算圆心o的坐标了,这里使用一个DOMMatrix对象,此对象在Chrome68版本才被引入,使用时要注意浏览器版本

var mat = new DOMMatrix();
mat = mat.rotate(-(90-a*180/Math.PI));
var o = mat.transformPoint(p3);

此处代码要注意,mat.rotate方法会返回一个新的对象,调用后原对象不变,所以要对mat变量进行重新赋值

rotate方法默认是按逆时针旋转,此处需要的是顺时针,所以角度b要取负值

对比arc方法的参数,目前还缺少起始角度和终止角度,下面使用getAngle方法来计算角度值

function getAngle(x, y){
    if(x==0){
        return (y>0?1:-1)*Math.PI/2;
    }
    else{
        return (x>0?1:-1)*Math.atan(x/y);
    }
}

下面是画弧的代码:

p1.angle = getAngle(p1.x-o.x, p1.y-o.y);
p2.angle = getAngle(p2.x-o.x, p2.y-o.y);
ctx.arc(o.x, o.y, r, p1.angle, p2.angle, p1.bulge>0);

3.结语

经过努力,终于将AutoCAD中的凸度换算为canvas中的圆弧,至此问题圆满解决,在使用计算机处理坐标计算的过程中,应该尽可能的使用三角函数进行处理,能够大大简化计算的工作量,同时也要使用一定的数学技巧去转变思路,简化计算过程。

参考文章:

Class DxfHatch.BoundaryPath.Polyline.Vertex http://www.woutware.com/doc/cadlib4.0/api/WW.Cad.Model.Entities.DxfHatch.BoundaryPath.Polyline.Vertex.htmlAutoCAD 凸度(bulge)的概念及使用WPF函数画图 - 源之缘 - 博客园前言 凸度(bulge)是AutoCAD 中一个非常重要的概念,凸度控制着两点之间弧度大小,弧度的方向。各种复杂的图像有可能就是成百上千的弧线组成的。从AutoCAD中导出的数据也有该值,一般的形式为https://www.cnblogs.com/yuanchenhui/p/autocad_bulge.html

猜你喜欢

转载自blog.csdn.net/shuaijie506/article/details/122487269
今日推荐