马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 Highflybird 于 2017-8-11 21:17 编辑
在下面的这个帖子中讨论了椭圆的曲率和转弯半径
http://bbs.xdcad.net/thread-667933-1-1.html
现在我把这个主题深化一下,讨论一下曲线的两个函数:
vlax-curve-getSecondDeriv
vlax-curve-getFirstDeriv
这两个函数是什么意思呢?
我们考察AutoCAD里面的曲线类,主要是圆,椭圆,弧和样条曲线,多段线由这几种组合而成。
椭圆和样条曲线实际上都是由参数形成,因此,对于这类曲线,它们每点的坐标可以由参数方程表达:
譬如椭圆 x=a*cos(t); y=b*sin(t);
样条曲线也有方程,假设 X= f(t); Y=g(t);
因此可以对参数方程求导,得到每一点的切线矢量,曲线上每一点对应于一个参数 t0 ,
这个切线矢量的 的X值就是 f(t)在t0处的一阶导数,Y值就是g(t)在t0处的一阶导数,因而我们就理解了
vlax-curve-getFirstDeriv 函数返回值的意义,
对于vlax-curve-getSecondDeriv的意义类似,只不过这次换成了二阶导数。
那么如何求样条曲线或者椭圆的每一点的曲率及其半径呢?
根据参数方程的求曲率公式:
我们可以得到相应的LISP代码:
- ;;;=============================================================
- ;;; 一般平面曲线参数方程的曲率离心公式
- ;;; 功能: 获取曲线上一点处的离心半径和离心圆圆心
- ;;; 参数: 曲线实体和曲线上的一点
- ;;; 返回: 此处离心圆圆心、离心半径
- ;;;=============================================================
- (defun CUR:GetCurvature (en pt / px v1 v2 v3 x1 y1 x2 y2 cen rad d1 d2)
- (setq pt (vlax-curve-getclosestpointto en pt)) ;保证此点在曲线上
- (setq px (vlax-curve-getParamAtPoint en pt)) ;此点的曲线参数
- (setq v1 (vlax-curve-getFirstDeriv en px)) ;此点的一阶矢量
- (setq v2 (vlax-curve-getSecondDeriv en px)) ;此点的二阶矢量
- (setq v3 (list (- (cadr v1)) (car v1) (caddr v1))) ;此点的切线矢量
- (setq x1 (car v1)) ;一阶导数的 X值
- (setq y1 (cadr v1)) ;一阶导数的 Y值
- (setq x2 (car v2)) ;二阶导数的 X值
- (setq y2 (cadr v2)) ;二阶导数的 Y值
- (setq d1 (expt (+ (* y1 y1) (* x1 x1)) 1.5))
- (setq d2 (- (* x1 y2) (* x2 y1))) ;转弯内外的判定
- (if (/= d2 0) ;如果不为直线段
- (progn
- (setq rad (/ d1 d2))
- (list (polar pt (angle '(0 0 0) v3) rad) (abs rad)) ;圆心及半径
- )
- )
- )
关于椭圆可以用如下代码:
- ;;;=============================================================
- ;;;功能: 获取椭圆上一点处的曲率和离心半径(适用于单次利用此法)
- ;;;参数: 椭圆实体和椭圆上的一点
- ;;;返回: 此处离心圆圆心、离心半径及其曲率(离心率)
- ;;;说明: 如果要在CAD中几何作图,可以参考此贴:
- ;;; http://bbs.mjtd.com/thread-62980-1-1.html
- ;;;=============================================================
- (defun ELL:GetCurvature (en pt / obj a b px x y v1 v2 rad cen)
- (setq obj (vlax-ename->vla-object en))
- (setq a (vla-get-MajorRadius obj)) ;椭圆的半长轴
- (setq b (vla-get-MinorRadius obj)) ;椭圆的半短轴
- (setq pt (vlax-curve-getclosestpointto en pt)) ;保证此点在椭圆上
- (setq px (vlax-curve-getParamAtPoint en pt)) ;此点的椭圆参数
- (setq v1 (vlax-curve-getFirstDeriv en px)) ;此点的一阶矢量
- (setq v2 (list (- (cadr v1)) (car v1) (caddr v1))) ;此点的切线矢量
- (setq x (* a (sin px)))
- (setq y (* b (cos px)))
- (setq rad (/ (expt (+ (* x x) (* y y)) 1.5) (* a b))) ;得到转弯半径
- (setq cen (polar pt (angle '(0 0 0) v2) rad)) ;圆心
- (list cen rad) ;圆心及半径
- )
- ;;;=============================================================
- ;;; 利用参数方程的求椭圆的曲率及其离心半径(适用于多次利用此法)
- ;;; 功能: 获取椭圆上一点处的转弯半径和离心圆圆心
- ;;; 参数: 椭圆实体和曲线上的一点
- ;;; 返回: 此处离心圆圆心、离心半径
- ;;;=============================================================
- (defun ELL:GetCurvature1 (en a b pt / px v1 v2 x y rad cen)
- (setq pt (vlax-curve-getclosestpointto en pt)) ;保证此点在椭圆上
- (setq px (vlax-curve-getParamAtPoint en pt)) ;此点的椭圆参数
- (setq v1 (vlax-curve-getFirstDeriv en px)) ;此点的一阶矢量
- (setq v2 (list (- (cadr v1)) (car v1) (caddr v1))) ;此点的切线矢量
- (setq x (* a (sin px)))
- (setq y (* b (cos px)))
- (setq rad (/ (expt (+ (* x x) (* y y)) 1.5) (* a b))) ;得到转弯半径
- (setq cen (polar pt (angle '(0 0 0) v2) rad)) ;圆心
- (list cen rad) ;圆心及半径
- );;;=============================================================
- ;;;功能: 获取椭圆上一点处的曲率和离心半径(适用于单次利用此法)
- ;;;参数: 椭圆实体和椭圆上的一点
- ;;;返回: 此处离心圆圆心、离心半径及其曲率(离心率)
- ;;;说明: 如果要在CAD中几何作图,可以参考此贴:
- ;;; http://bbs.mjtd.com/thread-62980-1-1.html
- ;;;=============================================================
- (defun ELL:GetCurvature (en pt / obj a b px x y v1 v2 rad cen)
- (setq obj (vlax-ename->vla-object en))
- (setq a (vla-get-MajorRadius obj)) ;椭圆的半长轴
- (setq b (vla-get-MinorRadius obj)) ;椭圆的半短轴
- (setq pt (vlax-curve-getclosestpointto en pt)) ;保证此点在椭圆上
- (setq px (vlax-curve-getParamAtPoint en pt)) ;此点的椭圆参数
- (setq v1 (vlax-curve-getFirstDeriv en px)) ;此点的一阶矢量
- (setq v2 (list (- (cadr v1)) (car v1) (caddr v1))) ;此点的切线矢量
- (setq x (* a (sin px)))
- (setq y (* b (cos px)))
- (setq rad (/ (expt (+ (* x x) (* y y)) 1.5) (* a b))) ;得到转弯半径
- (setq cen (polar pt (angle '(0 0 0) v2) rad)) ;圆心
- (list cen rad) ;圆心及半径
- )
- ;;;=============================================================
- ;;; 利用参数方程的求椭圆的曲率及其离心半径(适用于多次利用此法)
- ;;; 功能: 获取椭圆上一点处的转弯半径和离心圆圆心
- ;;; 参数: 椭圆实体和曲线上的一点
- ;;; 返回: 此处离心圆圆心、离心半径
- ;;;=============================================================
- (defun ELL:GetCurvature1 (en a b pt / px v1 v2 x y rad cen)
- (setq pt (vlax-curve-getclosestpointto en pt)) ;保证此点在椭圆上
- (setq px (vlax-curve-getParamAtPoint en pt)) ;此点的椭圆参数
- (setq v1 (vlax-curve-getFirstDeriv en px)) ;此点的一阶矢量
- (setq v2 (list (- (cadr v1)) (car v1) (caddr v1))) ;此点的切线矢量
- (setq x (* a (sin px)))
- (setq y (* b (cos px)))
- (setq rad (/ (expt (+ (* x x) (* y y)) 1.5) (* a b))) ;得到转弯半径
- (setq cen (polar pt (angle '(0 0 0) v2) rad)) ;圆心
- (list cen rad) ;圆心及半径
- )
附上几个测试程序:
完整代码请见附件:
- ;;;=============================================================
- ;;;测试程序1: 获取曲线一点处的曲率和离心半径
- ;;;=============================================================
- (defun c:tt1 (/ ent pnt ret)
- (setq ent (car (entsel "\n请选取曲线:")))
- (while (setq pnt (getpoint "\n点取一点"))
- (setq pnt (trans pnt 1 0))
- (setq pnt (vlax-curve-getclosestpointto ent pnt))
- (setq ret (CUR:GetCurvature ent pnt))
- (princ "\n离心半径是:")
- (princ ret)
- (and ret (apply 'Ent:Make_Circle ret))
- )
- )
- ;;;=============================================================
- ;;;测试程序2: 获取椭圆一点处的曲率和离心半径,并比较两种方法
- ;;;=============================================================
- (defun c:tt2 ( / ent obj a b pnt par lst 2st r1 r2 r3)
- (if (and (setq ent (car (entsel "\n请选取椭圆:")))
- (setq obj (vlax-ename->vla-object ent))
- (vlax-property-available-p obj 'MajorRadius) ;这个地方应该加出错处理
- (setq a (vla-get-MajorRadius obj))
- (setq b (vla-get-MinorRadius obj))
- )
- (while (setq pnt (getpoint "\n点取一点"))
- (setq pnt (trans pnt 1 0))
- (setq pnt (vlax-curve-getclosestpointto ent pnt))
- (setq par (vlax-curve-getparamatpoint ent pnt))
- (setq 2st (vlax-curve-getSecondDeriv ent par))
- (setq 1st (vlax-curve-getFirstDeriv ent par))
- (setq r1 (distance '(0 0) 2st)) ;这个secondDeriv并不意味着半径
- (setq r2 (cadr (ELL:GetCurvature1 ent a b pnt)))
- (setq r3 (cadr (CUR:getcurvature ent pnt)))
- (princ "\nRadius 1 is:")
- (princ r1)
- (princ "\nRadius 2 is:")
- (princ r2)
- (princ "\nRadius 3 is:")
- (princ r3)
- (UTI:Bench
- 10000
- (list
- (list 'ELL:GetCurvature1 ent a b pnt)
- (list 'CUR:getcurvature ent pnt)
- )
- )
- )
- )
- )
- ;;;=============================================================
- ;;;测试程序3: 由曲线的离心半径描绘其轨迹
- ;;;=============================================================
- (defun c:tt (/ ent lst par px1 px2 pxn pnt Inf cen)
- (if (setq ent (car (entsel "\n请选取曲线:")))
- (progn
- (setq px1 (vlax-curve-getStartParam ent))
- (setq px2 (vlax-curve-getendparam ent))
- (setq pxn (* (- px2 px1) 0.05))
- (setq par px1)
- (while (<= par px2)
- (setq pnt (vlax-curve-getpointatparam ent par))
- ;(setq Inf (ELL:GetCurvature1 ent a b pnt))
- (setq Inf (CUR:GetCurvature ent pnt))
- (setq cen (car Inf))
- (and cen (setq lst (cons cen lst)))
- (setq par (+ par pxn))
- ;(apply 'ent:make_circle Inf)
- )
- (setq lst (reverse lst))
- (Ent:Make_LWPoly lst 1)
- )
- )
- )
|