自贡黄明儒 发表于 2013-10-26 14:21:58

多段线偏移,弧曲率不变,弧长为offset下的长度

本帖最后由 自贡黄明儒 于 2013-10-26 16:22 编辑

多段线偏移,弧曲率不变,弧长为offset下的长度
请各位高手帮帮忙

edata 发表于 2013-10-26 14:21:59

熬了两个晚上,终于像样了。
写在前面的话,对于保证半径不改变,如果用计算方式出的结果总是不满意,所以还是改成了command函数,最近在研究entmake偏移线,正好要算圆弧,所以才加班加点的改写代码,想早日弄出来。
注意,这样的偏移线是建立在偏移后新圆弧的两点不大于原来直径的情况下,才能得到结果,否则无效。




(defun c:tt(/ ent lst arclst en arclst i sk_pt ds newent bulgelst arcc )
(if
(and (setq en(if (setq ss(ssget "_+.:E:S" '((0 . "LWPOLYLINE"))))(ssname ss 0)))
       (if en (progn (redraw en 3) t))
       (setq ds(getdist "\n指定偏移数值:"))
       (setq sk_pt(getpoint"\n指定偏移方向")))
(progn

(setq ent(entget en))
(setq lst '())
(while (car ent)
    (if(member (car(car ent)) '(10 40 41 42))
      (setq lst (cons (car ent)lst))
      )
    (setq ent(cdr ent))
    )
(setq lst (reverse lst))
(setq i 0 arclst '())
(while (car lst)
    (if (and (= (car (car lst)) 42)(/=(zerop (cdr (car lst))) t))
      (setq arclst(cons (list i (cdr (car lst))) arclst))
    )
    (if (= (car (car lst)) 10)(setq i(1+ i)))
    (setq lst(cdr lst))
    )
(setq arclst (reverse arclst))
(setvar "cmdecho" 0)
(command "offset" ds en sk_pt "")
(while (and (car arclst)(sk_indexpt1 (entget en) (1+ (car(car arclst)))))
(setq newent(entget(entlast)))
   
(setq bulgelst (sk_bulge2arc(sk_indexpt1 (entget en) (car(car arclst)))(sk_indexpt1 (entget en) (1+ (car(car arclst)))) (cadr(car arclst))))
    (setq newds(distance(sk_indexpt1 (entget en) (car(car arclst))) (sk_indexpt1 (entget en) (1+ (car(car arclst))))))
    (if (<newds (* (last bulgelst) 2))
      (progn
    (command "_.arc" "non"(sk_indexpt1 newent (car(car arclst)))"e""non"(sk_indexpt1 newent (1+ (car(car arclst)))) "r" (last bulgelst))   
(setq arcc(entget(entlast)))
(entdel(entlast))
(setq bulges(sk_arc2bulge (cdr (assoc 10 arcc))
                            (cdr (assoc 50 arcc))
                            (cdr (assoc 51 arcc))
                            (cdr (assoc 40 arcc))))
(if (< (cadr(car arclst)) 0)   
(entmod (sk_newent newent (car(car arclst)) (* -1 (cadr bulges))))
    (entmod (sk_newent newent (car(car arclst)) (cadr bulges)))
)))
    (setq arclst(cdr arclst ))
)
(setvar "cmdecho" 1)
)
(princ "\n没有选择对象.")
)
(princ)
)

; 按点表顺序更新多段线顶点,无须更换的顶点用nil代替。by:langjs
; 例:(entmod (reent (entget (car (entsel "\n选多段线:"))) '(nil (0.0 0.0) (100.0 100.0))))更新多段线第二第三点。
(defun sk_newent (ent index new43/ i nent x)
    (setq i 0nent '())
    (foreach x ent
      (setq nent (if (and (= (car x) 42) (= (setq i (1+ i)) index ))
       (appendnent (list (cons 42 new43)))
       (appendnent (list x))
               )
      )
    )
   
)
(defun sk_indexpt1(ent ptindex / i pt)
(setq i 1)
(while (car ent)
    (if (and (= (car(car ent)) 10) )
      (progn
(if (= i ptindex)
      (setq pt (cdr(car ent))))
      (setq i (1+ i))
      ))
    (setq ent (cdr ent))
    )
pt
)


(defun sk_arc2bulge ( c a1 a2 r )
    (list
      (polar c a1 r)
      (   (lambda ( a ) (/ (sin a) (cos a)))
            (/ (rem (+ pi pi (- a2 a1)) (+ pi pi)) 4.0)
      )
      (polar c a2 r)
    )
)

(defun sk_bulge2arc ( p1 p2 b / a c r )
    (setq a (* 2 (atan b))
          r (/ (distance p1 p2) 2 (sin a))
          c (polar p1 (+ (- (/ pi 2) a) (angle p1 p2)) r)
    )
    (if (minusp b)
      (list c (angle c p2) (angle c p1) (abs r))
      (list c (angle c p1) (angle c p2) (abs r))
    )
)

q3_2006 发表于 2013-10-26 14:29:06

能看下楼主最终的图啥样吗??

自贡黄明儒 发表于 2013-10-26 14:31:17

q3_2006 发表于 2013-10-26 14:29 static/image/common/back.gif
能看下楼主最终的图啥样吗??

如图片所见,就是弧的半径不变,但长度是要变化的。弧长是正常offset下的长度

q3_2006 发表于 2013-10-26 14:41:27

自贡黄明儒 发表于 2013-10-26 14:31 static/image/common/back.gif
如图片所见,就是弧的半径不变,但长度是要变化的。弧长是正常offset下的长度

你说的曲率不变是不是等于复制?

q3_2006 发表于 2013-10-26 16:45:39

本帖最后由 q3_2006 于 2013-10-26 19:17 编辑


没看DWG图,理解有误

nzl1116 发表于 2013-10-26 18:35:00

q3_2006 发表于 2013-10-26 16:45 static/image/common/back.gif
代码很糙,楼主是高手,看我的思路就行,自己完善,我是新手,全当好玩了!

楼主的问题,还有一个条件没交代清楚,即然是多段线,那圆弧有可能是多段线的第一段,也有可能是中间段,当然了,也有可能是最后一段,如此的话,问题就出来了,按逆时针方向,不知道楼主要求的,是以圆弧的起点为标准还是以圆弧的终点为标准?

自贡黄明儒 发表于 2013-10-26 19:16:50

nzl1116 发表于 2013-10-26 18:35 static/image/common/back.gif
楼主的问题,还有一个条件没交代清楚,即然是多段线,那圆弧有可能是多段线的第一段,也有可能是中间段, ...

不管哪里为起点,均可。最好与offset的起点一样

edata 发表于 2013-10-26 23:15:11

有趣的方案,和我最近思路有些相关,等有弄出来了在来。。

nzl1116 发表于 2013-10-27 00:26:02

本帖最后由 nzl1116 于 2013-10-27 02:44 编辑

(defun c:tt (/ Pline Pldata mData Pnt0 Pnt1 Ang Ang0 Ang1 Dist D nData Bulge Bulge1 r0 r1 L cen)
(vl-load-com)
(if (setq Pline (car (entsel "\n选择多段线:")))
    (progn
      (setq Pldata (entget Pline))
      (if (member (cdr (assoc 0 Pldata)) '("LWPOLYLINE" "POLYLINE"))
      (progn
          (setq mData (vl-remove-if-not (function (lambda (x) (member (car x) '(10 42)))) Pldata))
          (if (setq Pnt0 (getpoint "\n指定偏移方向"))
            (progn
            (setq Pnt1 (vlax-curve-getClosestPointTo Pline Pnt0)
                  Ang(angle '(0.0 0.0 0.0) (vlax-curve-getFirstDeriv Pline (vlax-curve-getParamAtPoint Pline Pnt1)))
                  Ang(- (angle Pnt1 Pnt0) Ang)
            )
            (if (setq Dist (getreal "\n指定偏移距离"))
                (progn
                  (setq Pnt0(cdar mData)
                        Ang0(angle '(0.0 0.0 0.0) (vlax-curve-getFirstDeriv Pline (vlax-curve-getParamAtPoint Pline Pnt0)))
                        Pnt1(polar Pnt0 (+ Ang0 Ang) Dist)
                        nData (list (cons 10 Pnt1))
                  )
                  (while mData
                  (setq Pnt2 (cdar mData)
                        Pnt3 (cdaddr mData)
                        D    (distance Pnt2 Pnt3)
                  )
                  (if (= (setq Bulge (cdadr mData)) 0)
                      (progn
                        (setq nData (cons '(42 . 0) nData)
                              Pnt1(polar Pnt1 Ang0 D)
                              nData (cons (cons 10 Pnt1) nData)
                        )
                      )
                      (progn
                        (setq Ang1 (* (atan Bulge) 4)
                              r0   (abs (/ D 2 (sin (/ Ang1 2))))
                        )
                        (if (> (* Ang1 Ang) 0)
                        (setq r1 (- r0 Dist))
                        (setq r1 (+ r0 Dist))
                        )
                        (if (> Bulge 0)
                        (setq Ang1 (+ Ang0 (* pi 0.5)))
                        (setq Ang1 (- Ang0 (* pi 0.5)))
                        )
                        (setq cen (polar Pnt1 Ang1 r0))
                        (setq L   (* (abs Ang1) r1)
                              Ang1(/ L r0)
                        )
                        (if (> Bulge 0)
                        (setq Pnt1 (polar cen (+ (angle cen Pnt1) Ang1) r0)
                              Ang0 (- (angle cen Pnt1) (* pi 0.5))
                        )
                        (setq Pnt1 (polar cen (- (angle cen Pnt1) Ang1) r0)
                              Ang0 (+ (angle cen Pnt1) (* pi 0.5))
                        )
                        )
                        (setq Ang1   (/ Ang1 4)
                              Bulge1 (/ (sin Ang1) (cos Ang1))
                        )
                        (if (< Bulge 0)
                        (setq Bulge1 (* Bulge1 -1))
                        )
                        (setq nData (cons (cons 42 Bulge1) nData)
                              nData (cons (cons 10 Pnt1) nData)
                        )
                      )
                  )
                  (setq mData (cddr mData))
                  )
                  (setq nData (reverse nData))
                  (entmakex
                  (append
                      (vl-remove-if
                        (function (lambda (x)
                                    (member (car x) '(10 40 41 42 90))
                                  )
                        )
                        Pldata
                      )
                      nData
                      (list (cons 90 (/ (1+ (length nData)) 2)))
                  )
                  )
                )
            )
            )
          )
      )
      (princ "\n选择的图元不是多段线")
      )
    )
    (princ "\n没有选择图元")
)
(princ)
)夜深了,没时间调试了,先发码
页: [1] 2
查看完整版本: 多段线偏移,弧曲率不变,弧长为offset下的长度