前言  凸度(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) * ;
double angle = radian * / Math.PI;
arcSegment.RotationAngle =Math.Abs(angle);
//弧度的方向 顺时针还是逆时针
arcSegment.SweepDirection = bulge>? SweepDirection.Clockwise:SweepDirection.Counterclockwise;
//是否大于180度
arcSegment.IsLargeArc = Math.Abs(bulge) > ;
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) * ; //两点之间的距离
double pointLen = ImageHelper.CalPointLen(point1, point2);
//根据正玄值反推
double radius = (pointLen / ) / Math.Sin(cicleAngle / );
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>=);
if (lenRate == )
return pt2;
if (lenRate == )
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 == )
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[].X + removeAt.X, pts[].Y + removeAt.Y);
return result;
}
}

 后记:在二维坐标上画图,需要有一定的几何基础和空间想象能力。初始接触这类编程,还是有一定难度的。就需要我们补充一些几何知识,同时多思考,总有一天会感觉豁然开朗。

AutoCAD 凸度(bulge)的概念及使用WPF函数画图的更多相关文章

  1. 使用WPF创建画图箭头

    原文:使用WPF创建画图箭头 今天要给leader line画个箭头,所以就google一下,找到下面的文章,写的不错,可以实现我的需求,所以就摘录下来. 我把源代码中的arraw.cs加入到我的工程 ...

  2. WPF InkCanvas 画图 基础使用教程

    大家好,由于很多原因,我有很长一段时间没有在 CSDN 上分享我的学习成果了,如今终于可以回归分享之路了. 之前在做一个项目的时候,想在一个区域里绘制自己的图形,于是上网搜索资料,无意中找到了 Ink ...

  3. dll的概念 dll导出变量 函数 类

    1. DLL的概念 DLL(Dynamic Linkable Library),动态链接库,可以向程序提供一些函数.变量或类.这些可以直接拿来使用. 静态链接库与动态链接库的区别:   (1)静态链接 ...

  4. Javascript函数的基本概念+匿名立即执行函数

    函数声明.函数表达式.匿名函数 函数声明:function fnName () {…};使用function关键字声明一个函数,再指定一个函数名,叫函数声明. 函数表达式 var fnName = f ...

  5. JS高程3.基本概念(6)函数

    1.ECMAScript中的函数使用function关键字来声明. eg: function sum (num1,num2){ alert(num1+num2); } sum(3,7); 注意: 在有 ...

  6. WPF系列:画图

    Line 在两个坐标点之间画一条直线,通过四个属性设置它的起始和结束 <Line Stroke="Blue" StrokeThickness="3" X1 ...

  7. 读javascript高级程序设计01-基本概念、数据类型、函数

    一. javascript构成 1.javascript实现由三部分组成: ECMAScript:核心语言功能 DOM:文档对象模型,提供访问和操作网页内容的方法和接口 BOM:浏览器对象模型,提供与 ...

  8. Javascript基本概念(语句和函数)

    语句 for语句 for语句中的初始化表达式,控制表达式和循环后表达式都是可选的,将这三个表达式省略,就会创建一个无线循环. ECMAScript中不存在块级作用域,因此在循环内容部定义的变量也可以在 ...

  9. JS_高程3.基本概念(6)函数

    1.ECMAScript中的函数使用function关键字来声明. eg: function sum (num1,num2){ alert(num1+num2); } sum(3,7); 注意: 在有 ...

随机推荐

  1. Python数据分析--Pandas知识点(三)

    本文主要是总结学习pandas过程中用到的函数和方法, 在此记录, 防止遗忘. Python数据分析--Pandas知识点(一) Python数据分析--Pandas知识点(二) 下面将是在知识点一, ...

  2. webpack浅析---出口篇

    webpack有四个核心概念: 入口(entry) 输出(output) loader 插件(plugins) 输出: 在哪里输出创建的bundles,以及如何命名这些文件, 默认./dist fil ...

  3. RN与webview通讯

     一.RN给webview发送信息 this.webview.postMessage(message) 二.监听从React Native发过来的消息: window.document.addEven ...

  4. 20172306 2018-2019 《Java程序设计与数据结构》第一周学习总结

    20172306 2018-2019 <Java程序设计与数据结构(下)>第一周学习总结 教材学习内容总结 第一章 概述 (程序=数据结构+算法 软件=程序+软件工程) 1.1 软件质量 ...

  5. 20172306 2018-2019-2 《Java程序设计》第五周学习总结

    20172306 2018-2019-2 <Java程序设计>第五周学习总结 教材学习内容总结 查找 查找中,我们对这些算法的实现就是对某个Comparable对象的数组进行查找 泛型声明 ...

  6. Python:每日一题005

    题目: 输入三个整数x,y,z,请把这三个数由小到大输出. 程序分析: 我们想办法把最小的数放到x上,先将x与y进行比较,如果x>y则将x与y的值进行交换,然后再用x与z进行比较,如果x> ...

  7. java多线程系列6 synchronized 加强版 ReentrantLock

    ReentrantLock类是可重入.互斥.实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力.ReenreantLock类的常用方法有: Re ...

  8. AX_NumberSeq

    NumberSeq::newGetNum(NumberSeqReference::findReference(typeId2ExtendedTypeId(typeid(InventTransId))) ...

  9. Java8特性之Lambda、方法引用和Streams

    这里涉及三个重要特性: Lambda 方法引用 Streams ① Lambda 最早了解Lambda是在C#中,而从Java8开始,Lambda也成为了新的特性,而这个新的特性的目的,就是为了消除单 ...

  10. MSSQL语句学习(查询表的总记录数)

    如何高效查询表的总记录数(通用方法) SELECT COUNT(1) ROWS FROM product 野路子1:利用系统自带的存储过程SP_SPACEUSED,详细的使用方式推荐谷哥或度娘, EX ...