Catmull - Rom spline from lwpolyline

Catmull - Rom spline from lwpolyline

hak_vz
Advisor Advisor
2,771 Views
11 Replies
Message 1 of 12

Catmull - Rom spline from lwpolyline

hak_vz
Advisor
Advisor

If you want to create smooth polyline in Autocad you may use command "PEDIT" to create spline or fit curve (quadratic, qubic or Bezier surface). 

Fit curve will pass through points that define lwpolyline, but in spline this points will become manipulative vertexes. Since I use rather old  version of Autocad I don't know if there are any new options.

I have read somewhare that Catmull Rom spline will be implemented in newer versions (2018 or such).

 

For those of you that don't have that option here is my script that creates Catmull - Rom spline from a polyline. I wont explain maths behind, you may Google it, or read about Centripetal Catmull–Rom spline on Wikipedia.

 

If you have closed lwpolyline that consists only of line segments and you convert her to spline or fit curve you will get something like this.

 

catmull_1.jpgI have written an  autolisp tool that creates Catmull - Rom splines, files are in attachment.

After you start command "CROM" you will get something like this.

catmull_2.jpg

 You may copy code from here or download it from attachment. In atachment is also a version that use separate .lsp and .dcl files (catmull-rom.lsp and catmull.dcl -  no vlisp), and version that autocreates dcl file (catmull-rom-vl.lsp or in code section) .

 

(setq 
    interpoints 10 
    alpha 5 
    file "c:\\catmull.dcl"
    eraser 0
)
(defun keyValue (key el)(cdr (assoc key el)))
(defun equalPoints (pt1 pt2) (apply '= (mapcar '= pt1 pt2)))
(defun lwpolypoints (e / ent elev ptlist closed pt pt1)
    (setq
        ent  (entget e)
        elev   (keyValue 38 ent)
        closed (keyValue 70 ent)
        pt1 (keyValue 10 ent)
    )
    (while (setq ent (member (assoc 10 ent) ent) pt (car ent) ent (cdr ent))
            (setq p (list (cadr pt) (caddr pt) elev))
            (if (atom ptlist) (setq ptlist (cons p ptlist)))
            (if (and (listp ptlist) (not (equalPoints (car ptlist) p))) (setq ptlist (cons p ptlist)))	
    )
    (if (and (eq closed 1) (not (equalPoints (car ptlist) pt1))) (setq ptlist (cons pt1 ptlist)))
    (reverse ptlist)	 
)
(defun point2d (pt)(list (car pt) (cadr pt)))
(defun linsp (start stop n / i  ret step ret)(setq step (/ (- stop start) (float (- n 1 ))) i 0)
(repeat n (setq ret (cons (+ start (* i step)) ret) i (+ i 1))) (reverse ret)) (defun tval (tprev pt1 pt2 _alpha / x1 y1 x2 y2 )(+ (expt (expt (+ (expt (- (car pt2) (car pt1)) 2.0)
(expt (- (cadr pt2) (cadr pt1)) 2.0)) 0.5) _alpha) tprev)) (defun catmull_rom_spline (p0 p1 p2 p3 _alpha / t0 t1 t2 t3 tlin k1 k2 k3 m1 m2 m3
a1 a2 a3 r1 r2 s1 s2 b1 b2 g1 g2 c ret) (setq t0 0.0 t1 (tval t0 p0 p1 _alpha) t2 (tval t1 p1 p2 _alpha) t3 (tval t2 p2 p3 _alpha) tlin (linsp t1 t2 (+ interpoints 2)) ) (foreach tcur tlin (setq k1 (/ (- t1 tcur)(- t1 t0)) m1 (/ (- tcur t0)(- t1 t0)) k2 (/ (- t2 tcur)(- t2 t1)) m2 (/ (- tcur t1)(- t2 t1)) k3 (/ (- t3 tcur)(- t3 t2)) m3 (/ (- tcur t2)(- t3 t2)) a1 (mapcar '+ (mapcar '* (list k1 k1) p0) (mapcar '* (list m1 m1) p1)) a2 (mapcar '+ (mapcar '* (list k2 k2) p1) (mapcar '* (list m2 m2) p2)) a3 (mapcar '+ (mapcar '* (list k3 k3) p2) (mapcar '* (list m3 m3) p3)) r1 (/ (- t2 tcur)(- t2 t0)) s1 (/ (- tcur t0)(- t2 t0)) r2 (/ (- t3 tcur)(- t3 t1)) s2 (/ (- tcur t1)(- t3 t1)) b1 (mapcar '+ (mapcar '* (list r1 r1) a1) (mapcar '* (list s1 s1) a2)) b2 (mapcar '+ (mapcar '* (list r2 r2) a2) (mapcar '* (list s2 s2) a3)) g1 (/ (- t2 tcur)(- t2 t1)) g2 (/ (- tcur t1)(- t2 t1)) c (mapcar '+ (mapcar '* (list g1 g1) b1) (mapcar '* (list g2 g2) b2)) ret (cons c ret) ) ) (reverse ret) ) (defun getlwpolypoints (e / ent pts p1 npoints elev m lpt1 lpt2 spt1 spt2 d1 d2 a1 a2 fstart fend ); (setq ent (entget e)) (setq pts (lwpolypoints e) closed (keyValue 70 ent)) (if (eq closed 0) (progn (setq spt1 (car pts) spt2 (cadr pts) lpt2 (last pts) lpt1 (nth (- (length pts) 2) pts) d1 (distance spt1 spt2) d2 (distance lpt1 lpt2) a1 (+ (angle spt2 spt1)) a2 (angle lpt1 lpt2) fstart (polar spt1 a1 d1) fend (polar lpt2 a2 d2) pts (append (list fstart) pts) pts (append pts (list fend)) ) ) ) (if (eq closed 1) (progn (setq fend (nth 1 pts) fstart (nth (- (length pts) 2) pts) pts (append (list fstart) pts) pts (append pts (list fend)) ) ) ) pts ) (defun make_catmull_rom_spline (e / npoints i p0 p1 p2 p3 crom) (setq pts (mapcar 'point2d (getlwpolypoints e)) npoints (length pts) _alpha (/ alpha 10.0) i 0) (while (< i (- npoints 3 )) (setq p0 (nth i pts) p1 (nth (+ i 1) pts) p2 (nth (+ i 2) pts) p3 (nth (+ i 3) pts) crom (append crom (catmull_rom_spline p0 p1 p2 p3 _alpha)) i (+ i 1) ) ) (entmakex (apply 'append (cons (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 8 "0") (cons 90 (length crom)) '(67 . 0) '(410 . "Model") '(62 . 3) '(70 . 0) ) (mapcar 'list (mapcar '(lambda (a) (cons 10 a)) crom)) ) ) ) ) (defun C:crom ( / e dcl_id) (defun point_slider_action (val why) (if (or (= why 2) (= why 1)) (progn (set_tile "npoints" val) (setq interpoints (atoi val)) ) ) ) (defun alpha_slider_action (val why) (if (or (= why 2) (= why 1)) (progn (set_tile "alpha" val) (setq alpha (atoi val)) ) ) ) (defun ebox_action_points (val why) (if (or (= why 2) (= why 1)) (progn (set_tile "pointslider" val) (setq interpoints (atoi val)) ) ) ) (defun ebox_action_alpha (val why) (if (or (= why 2) (= why 1)) (progn (set_tile "alphaslider" val) (setq alpha (atoi val)) ) ) ) (defun toggle_action_eraser (val why) (if (or (= why 2) (= why 1)) (progn (set_tile "eraser" val) (setq eraser (atoi val)) ) ) ) (setq e (car(entsel "\nSelect polyline to smooth >"))) (make_catmull_rom_spline e) (setq dcl_id (load_dialog file))(if (not (new_dialog "crom" dcl_id)) (exit )) (set_tile "npoints" (itoa interpoints)) (set_tile "pointslider" (itoa interpoints)) (set_tile "eraser" (itoa eraser)) (action_tile "pointslider" "(point_slider_action $value $reason)") (action_tile "npoints" "(ebox_action_points $value $reason)") (set_tile "alpha" (itoa alpha)) (set_tile "alphaslider" (itoa alpha)) (action_tile "alphaslider" "(alpha_slider_action $value $reason)") (action_tile "alpha" "(ebox_action_alpha $value $reason)") (action_tile "eraser" "(toggle_action_eraser $value $reason)") (action_tile "apply" "(entdel(entlast))(make_catmull_rom_spline e)") (action_tile "accept" "(if (= eraser 1)(entdel e))(done_dialog)");action tile (action_tile "cancel" "(entdel(entlast))(done_dialog)");action_tile (start_dialog) (unload_dialog dcl_id) (princ) ) (princ "\nType CROM to create Catmull-Rom spline from lwpolyline (only line segments)") (princ)

After changing number of insertation points and tigthening value (0 0.5 or 1) hit apply button to see how it changes, and exit with OK button. If you apply this function to closed curve you must create it closed, otherwise you will get sharp end.

You may use Catmull Rom splines when spline curve must strictly pass through control points (vertices of the lwpolyline), or just to create more natural looking curve.

Any comment is welcome. Likes are welcome too.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Accepted solutions (1)
2,772 Views
11 Replies
Replies (11)
Message 2 of 12

devitg
Advisor
Advisor

 Hi hak_vz I tested your lisp catmull-rom-vl on a closed ply and the result it is not as expected.

 

0 Likes
Message 3 of 12

hak_vz
Advisor
Advisor

Because of some reason this works in one product (xxxcad) that I use at home, and it doesn't in Acad.

 

To make it work in  function lwpolypoints replace:

 

(if (and (eq closed 1) (not (equalPoints (car ptlist) pt1))) (setq ptlist (cons pt1 ptlist)))

 

with

 

(if (eq closed 1) (setq ptlist (cons pt1 ptlist)))

 

Original expression tests for equal points, since in that case we can't create spline.

But if you have a poly with equal first and last point, but you treat it as not closed curve must act that way.

 

 

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 4 of 12

CADaSchtroumpf
Advisor
Advisor

Hi,

 

And if you change !

(if (and (eq closed 1) (not (equalPoints (car ptlist) pt1))) (setq ptlist (cons pt1 ptlist)))

by:

(if (or (eq closed 1) (not (equalPoints (car ptlist) pt1))) (setq ptlist (cons pt1 ptlist)))

Seem to work in acad 2019

0 Likes
Message 5 of 12

hak_vz
Advisor
Advisor

Yes this seams to works. I don't know if there were changes in the way how entity points are stored i.e. you have key 70 that determins that polyline is open or closed, and if it stores last point  or not.

Question. 

Is Catmull Rom  spline implemented in newer versions of Acad?

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 6 of 12

marko_ribar
Advisor
Advisor

To my knowledge I don't think it's implemented in newer ACAD versions...

I had spare time though to revise and clean up more your routine as I see there were lacks reported in previous posts... I changed just a little what I thought was the problem and this is what I use now and I don't see that it will fail at any point while operating, so I am posting it now... However I would like that you mark your first post as a solution as it is all your contribution, I only changed it slightly as I wanted it to be without any lack... I hope you don't mind my intervention and many thanks from me and perhaps anyone who'll find this routine useful in his/her working activities... Regards, M.R.

 

(defun c:crom ( / *error* unique keyValue equalPoints lwpolypoints point2d linsp tval catmull_rom_spline getlwpolypoints create_dialog make_catmull_rom_spline point_slider_action alpha_slider_action ebox_action_points ebox_action_alpha toggle_action_eraser interpoints alpha file eraser e ex dcl_id )

    (vl-load-com)

    (defun *error* ( m )
      (if (and file (findfile file))
        (vl-file-delete (findfile file))
      )
      (if m
        (prompt m)
      )
      (princ)
    )

    (defun unique ( l ) (if l (cons (car l) (unique (vl-remove-if '(lambda ( x ) (equal (car l) x 1e-6)) l)))))

    (defun keyValue ( key el ) (cdr (assoc key el)))

    (defun equalPoints ( pt1 pt2 ) (apply 'and (mapcar '= pt1 pt2)))

    (defun lwpolypoints ( e / ent elev ptlist closed pt pt1 )
        (setq
            ent    (entget e)
            elev   (keyValue 38 ent)
            closed (keyValue 70 ent)
            pt1    (append (keyValue 10 ent) (list elev))
        )
        (while (setq ent (member (assoc 10 ent) ent) pt (car ent) ent (cdr ent))
               (setq p (list (cadr pt) (caddr pt) elev))
               (if (atom ptlist) (setq ptlist (cons p ptlist)))
               (if (and (listp ptlist) (not (equalPoints (car ptlist) p))) (setq ptlist (cons p ptlist)))
        )
        (if (and (= 1 (logand closed 1)) (not (equalPoints (car ptlist) pt1))) (setq ptlist (cons pt1 ptlist)))
        (reverse ptlist)
    )

    (defun point2d ( pt ) (list (car pt) (cadr pt)))

    (defun linsp ( start stop n / i ret step ret ) (setq step (/ (- stop start) (float (- n 1))) i 0) (repeat n (setq ret (cons (+ start (* i step)) ret) i (+ i 1))) (reverse ret)) 

    (defun tval ( tprev pt1 pt2 _alpha / x1 y1 x2 y2 ) (+ (expt (expt (+ (expt (- (car pt2) (car pt1)) 2.0) (expt (- (cadr pt2) (cadr pt1)) 2.0)) 0.5) _alpha) tprev))

    (defun catmull_rom_spline ( p0 p1 p2 p3 _alpha / t0 t1 t2 t3 tlin k1 k2 k3 m1 m2 m3 a1 a2 a3 r1 r2 s1 s2 b1 b2 g1 g2 c ret )
        (setq
            t0 0.0
            t1 (tval t0 p0 p1 _alpha)
            t2 (tval t1 p1 p2 _alpha)
            t3 (tval t2 p2 p3 _alpha)
            tlin (linsp t1 t2 (+ interpoints 2))
        )
        (foreach tcur tlin
            (setq
                k1 (/ (- t1 tcur) (- t1 t0)) m1 (/ (- tcur t0) (- t1 t0))
                k2 (/ (- t2 tcur) (- t2 t1)) m2 (/ (- tcur t1) (- t2 t1))
                k3 (/ (- t3 tcur) (- t3 t2)) m3 (/ (- tcur t2) (- t3 t2))
                a1 (mapcar '+ (mapcar '* (list k1 k1) p0) (mapcar '* (list m1 m1) p1))
                a2 (mapcar '+ (mapcar '* (list k2 k2) p1) (mapcar '* (list m2 m2) p2))
                a3 (mapcar '+ (mapcar '* (list k3 k3) p2) (mapcar '* (list m3 m3) p3))
                r1 (/ (- t2 tcur) (- t2 t0))
                s1 (/ (- tcur t0) (- t2 t0))
                r2 (/ (- t3 tcur) (- t3 t1))
                s2 (/ (- tcur t1) (- t3 t1))
                b1 (mapcar '+ (mapcar '* (list r1 r1) a1) (mapcar '* (list s1 s1) a2))
                b2 (mapcar '+ (mapcar '* (list r2 r2) a2) (mapcar '* (list s2 s2) a3))
                g1 (/ (- t2 tcur) (- t2 t1)) g2 (/ (- tcur t1) (- t2 t1))
                c (mapcar '+ (mapcar '* (list g1 g1) b1) (mapcar '* (list g2 g2) b2))
                ret (cons c ret)
            )
        )
        (reverse ret)
    )

    (defun getlwpolypoints ( e / pts p1 npoints elev m lpt1 lpt2 spt1 spt2 d1 d2 a1 a2 fstart fend ef )
        (if (vlax-erased-p e)
          (progn
            (entdel e)
            (setq ef t)
          )
        )
        (setq pts (lwpolypoints e) closed (keyValue 70 (entget e)))
        (if (not (eq (logand closed 1) 1))
            (progn
                (setq
                    spt1 (car pts) 
                    spt2 (cadr pts)
                    lpt2 (last pts)
                    lpt1 (nth (- (length pts) 2) pts)
                    d1 (distance spt1 spt2)
                    d2 (distance lpt1 lpt2)
                    a1 (+ (angle spt2 spt1))
                    a2 (angle lpt1 lpt2)
                    fstart (polar spt1 a1 d1)
                    fend (polar lpt2 a2 d2)
                    pts (append (list fstart) pts)
                    pts (append pts (list fend))
                )
            )
        )
        (if (eq (logand closed 1) 1)
            (progn
                (setq
                    fend (nth 1 pts)
                    fstart (nth (- (length pts) 2) pts)
                    pts (append (list fstart) pts)
                    pts (append pts (list fend))
                )
            )
        )
        (if ef
          (entdel e)
        )
        pts
    )

    (defun create_dialog ( / f )
        (setq f (open file "w"))
        (write-line "cr: dialog { label = \" Catmull - Rom polyline smoothing \"; : edit_box {key = \"npoints\";label = \" Interpolation points per segment: <<  coarse  smooth  >> \";edit_width = 9;}" f)
        (write-line ": slider { key = \"pointslider\"; max_value = 20;	 min_value = 1;  big_increment = 1; small_increment = 1; }" f)
        (write-line ": edit_box { key = \"alpha\"; label = \"Bulging << tight - loose >> \"; edit_width = 9; }" f)
        (write-line ": slider { key = \"alphaslider\"; max_value = 10; min_value = 0;  big_increment = 5; small_increment = 1; } " f)
        (write-line ": row {alignment =\"centered\";fixed_width = true; height = 4;" f)
        (write-line ": toggle {key =\"eraser\";label =\"Erase base polyline?\";}" f)
        (write-line ": button { key = \"apply\"; label = \"apply\"; is_default = false; is_cancel = false;is_default=true; width  = 5;  } } ok_cancel ; }"  f)
        (close f)
    )

    (defun make_catmull_rom_spline ( e / npoints i p0 p1 p2 p3 crom )
        (setq pts (mapcar 'point2d (getlwpolypoints e))
              npoints (length pts) 
              _alpha (/ alpha 10.0)
              i 0
        )
        (while (< i (- npoints 3))
            (setq
                p0 (nth i pts)
                p1 (nth (+ i 1) pts)
                p2 (nth (+ i 2) pts)
                p3 (nth (+ i 3) pts)
                crom (append crom (catmull_rom_spline p0 p1 p2 p3 _alpha))
                i (1+ i)
            )
        )
        (setq crom (unique crom))
        (entmakex
          (apply 'append
            (cons
              (list
                '(0 . "LWPOLYLINE")
                '(100 . "AcDbEntity")
                '(100 . "AcDbPolyline")
                (cons 90 (length crom))
                '(67 . 0)
                (cons 410 (if (= (getvar 'cvport) 1) (getvar 'ctab) "Model"))
                '(62 . 3)
                (assoc 70 (entget e))
              )
              (mapcar 'list (mapcar '(lambda ( a ) (cons 10 a)) crom))
            )
          )
        )
    )

    (defun point_slider_action ( val why )
      (if (or (= why 2) (= why 1))
          (progn
              (set_tile "npoints" val)
              (setq interpoints (atoi val))
          )
      )
    )

    (defun alpha_slider_action ( val why )
        (if (or (= why 2) (= why 1))
            (progn
                (set_tile "alpha" val)
                (setq alpha (atoi val))
            )
        )
    )

    (defun ebox_action_points ( val why )
        (if (or (= why 2) (= why 1))
            (progn
                (set_tile "pointslider" val)
                (setq interpoints (atoi val))
            )
        )
    )

    (defun ebox_action_alpha ( val why )
        (if (or (= why 2) (= why 1))
            (progn
                (set_tile "alphaslider" val)
                (setq alpha (atoi val))
            )
        )
    )

    (defun toggle_action_eraser ( val why )
        (if (or (= why 2) (= why 1))
            (progn
                (set_tile "eraser" val)
                (setq eraser (atoi val))
            )
        )
    )

    (setq
        interpoints 10
        alpha 5
        file (vl-filename-mktemp "catmul.dcl")
        eraser 0
    )
    (while
      (or
        (not (setq e (car (entsel "\nSelect polygonal lwpolyline (only line segments) to smooth >"))))
        (if e
          (or
            (/= (cdr (assoc 0 (setq ex (entget e)))) "LWPOLYLINE")
            (not (vl-every 'zerop (mapcar 'cdr (vl-remove-if '(lambda (x) (/= (car x) 42)) ex))))
          )
        )
      )
      (prompt "\nMissed or picked wrong entity type or picked lwpolyline has one or more segments not straight - segment(s) with bulge(s)...")
      (textscr)
    )
    (make_catmull_rom_spline e)
    (vla-regen (vla-get-activedocument (vlax-get-acad-object)) acactiveviewport)
    (create_dialog)
    (setq dcl_id (load_dialog file))
    (if (not (new_dialog "cr" dcl_id)) (exit))
    (set_tile "npoints" (itoa interpoints))
    (set_tile "pointslider" (itoa interpoints))
    (set_tile "eraser" (itoa eraser))
    (action_tile "pointslider" "(point_slider_action $value $reason)")
    (action_tile "npoints" "(ebox_action_points $value $reason)")
    (set_tile "alpha" (itoa alpha)) 
    (set_tile "alphaslider" (itoa alpha))
    (action_tile "alphaslider" "(alpha_slider_action $value $reason)")
    (action_tile "alpha" "(ebox_action_alpha $value $reason)")
    (action_tile "eraser" "(toggle_action_eraser $value $reason)")
    (action_tile "apply" "(entdel (entlast))(make_catmull_rom_spline e)(vla-regen (vla-get-activedocument (vlax-get-acad-object)) acactiveviewport)")
    (action_tile "accept" "(if (= eraser 1)(entdel e))(entdel(entlast))(make_catmull_rom_spline e)(done_dialog)")
    (action_tile "cancel" "(entdel (entlast))(done_dialog)")
    (start_dialog)
    (unload_dialog dcl_id)
    (*error* nil)
)

(princ "\nType CROM to create Catmull-Rom spline from lwpolyline (only line segments)")
(princ)
Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 7 of 12

hak_vz
Advisor
Advisor

@marko_ribar  Thank you so much for your efforts to improve this small and I would say useful tool. I'm using it to smooth contour polylines in geodetic maps. I don't care so much about whether would I collect solution point, split reward would do better in this case, so I will select best solution at the end . 

 

You have improved it a lot by adding error handler and function "unique" to remove point duplicates, and some other vl- stuff.

 

Maybe defining my function "equalpoints" as

(defun equalPoints (pt1 pt2 1e6) (apply '= (mapcar '(lambda (x y) (equal x y 1e6)) pt1 pt2))) 

would be sufficient.

 

I would add some additional functionality (and I will probably do):

 

  • Accept arc segments and calculate midpoint from a arc bulge
  • Variable number of interpolation points depending on distance between adjacent vertexes. You still will be defining number of interpolation points but when two adjacent points are too close this numbers minimizes to avoid overcrowding of unnecessary vertexes.

 

Suggestions are more than welcome!

 

@marko_ribar  Hvala na pomoći i utrošenom vremenu.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 8 of 12

marko_ribar
Advisor
Advisor

Milenko,

pogledaj bolje, promena je u : (defun equalpoints ( pt1 pt2 ) (apply 'and (mapcar '= pt1 pt2)))

 

Bez ovog 'and nece ti rutina funkcionisati kako treba (na pr. (apply '= '(nil nil)) => T sto je pogresno, treba (apply 'and '(nil nil)) => nil, isto tako (apply 'and '(nil T)) => nil, dok samo (apply 'and '(T T)) => T...

 

Uzgred, ako zelis da ti sve bude perfektno, treba promeniti i sledecu stvar da bi bilo funkcionalno i u 3D :

    (defun make_catmull_rom_spline ( e / npoints i p0 p1 p2 p3 crom )
        (setq pts (mapcar 'point2d (getlwpolypoints e))
              npoints (length pts) 
              _alpha (/ alpha 10.0)
              i 0
        )
        (while (< i (- npoints 3))
            (setq
                p0 (nth i pts)
                p1 (nth (+ i 1) pts)
                p2 (nth (+ i 2) pts)
                p3 (nth (+ i 3) pts)
                crom (append crom (catmull_rom_spline p0 p1 p2 p3 _alpha))
                i (1+ i)
            )
        )
        (setq crom (unique crom))
        (entmake
          (apply 'append
            (list
              (list
                '(0 . "LWPOLYLINE")
                '(100 . "AcDbEntity")
                '(100 . "AcDbPolyline")
                (cons 90 (length crom))
                '(67 . 0)
                (cons 410 (if (= (getvar 'cvport) 1) (getvar 'ctab) "Model"))
                '(62 . 3)
              )
              (mapcar '(lambda ( a ) (cons 10 a)) crom)
              (vl-remove-if-not '(lambda ( x ) (vl-position (car x) '(38 70 210))) (entget e))
            )
          )
        )
    )

Eto toliko od mene, nadam se da shvatas koji su nedostatci bili u originalu...

Sto se tice tvojih buducih intervencija, slazem se da moze jos bolje, ali mislim da su korisnici zadovoljni i ovakvom verzijom...

Hvala...

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 9 of 12

hak_vz
Advisor
Advisor

 

I'll implement @marko_ribar marko_ribar suggestions and post it as a final solution, respecting his view about final solution to this post.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 10 of 12

hak_vz
Advisor
Advisor
Accepted solution

Here is final version of Catmull- Rom spline generator, finalized thanks to  @marko_ribar , @CADaSchtroumpf ; @devitg ....

 

(defun c:crom ( / *error* unique keyValue equalPoints lwpolypoints point2d linsp tval catmull_rom_spline getlwpolypoints create_dialog make_catmull_rom_spline point_slider_action alpha_slider_action ebox_action_points ebox_action_alpha toggle_action_eraser interpoints alpha file eraser e ex dcl_id )
;; ;; CREATES 2D CATMULL-ROM SPLINE (SMOOTH CURVE) FROM LWPOLYLINE ;; ;; Concept and basic version: @hak_vz https://forums.autodesk.com/t5/user/viewprofilepage/user-id/5530556 ;; Updates and modifications: @marko_ribar https://forums.autodesk.com/t5/user/viewprofilepage/user-id/940934 ;; (vl-load-com) (defun *error* ( m ) (if (and file (findfile file)) (vl-file-delete (findfile file)) ) (if m (prompt m) ) (princ) ) (defun unique ( l ) (if l (cons (car l) (unique (vl-remove-if '(lambda ( x ) (equal (car l) x 1e-6)) l))))) (defun keyValue ( key el ) (cdr (assoc key el))) (defun equalPoints ( pt1 pt2 ) (apply 'and (mapcar '= pt1 pt2))) (defun lwpolypoints ( e / ent elev ptlist closed pt pt1 ) (setq ent (entget e) elev (keyValue 38 ent) closed (keyValue 70 ent) pt1 (append (keyValue 10 ent) (list elev)) ) (while (setq ent (member (assoc 10 ent) ent) pt (car ent) ent (cdr ent)) (setq p (list (cadr pt) (caddr pt) elev)) (if (atom ptlist) (setq ptlist (cons p ptlist))) (if (and (listp ptlist) (not (equalPoints (car ptlist) p))) (setq ptlist (cons p ptlist))) ) (if (and (= 1 (logand closed 1)) (not (equalPoints (car ptlist) pt1))) (setq ptlist (cons pt1 ptlist))) (reverse ptlist) ) (defun point2d ( pt ) (list (car pt) (cadr pt))) (defun linsp ( start stop n / i ret step ret ) (setq step (/ (- stop start) (float (- n 1))) i 0) (repeat n (setq ret (cons (+ start (* i step)) ret) i (+ i 1))) (reverse ret)) (defun tval ( tprev pt1 pt2 _alpha / x1 y1 x2 y2 ) (+ (expt (expt (+ (expt (- (car pt2) (car pt1)) 2.0) (expt (- (cadr pt2) (cadr pt1)) 2.0)) 0.5) _alpha) tprev)) (defun catmull_rom_spline ( p0 p1 p2 p3 _alpha / t0 t1 t2 t3 tlin k1 k2 k3 m1 m2 m3 a1 a2 a3 r1 r2 s1 s2 b1 b2 g1 g2 c ret ) (setq t0 0.0 t1 (tval t0 p0 p1 _alpha) t2 (tval t1 p1 p2 _alpha) t3 (tval t2 p2 p3 _alpha) tlin (linsp t1 t2 (+ interpoints 2)) ) (foreach tcur tlin (setq k1 (/ (- t1 tcur) (- t1 t0)) m1 (/ (- tcur t0) (- t1 t0)) k2 (/ (- t2 tcur) (- t2 t1)) m2 (/ (- tcur t1) (- t2 t1)) k3 (/ (- t3 tcur) (- t3 t2)) m3 (/ (- tcur t2) (- t3 t2)) a1 (mapcar '+ (mapcar '* (list k1 k1) p0) (mapcar '* (list m1 m1) p1)) a2 (mapcar '+ (mapcar '* (list k2 k2) p1) (mapcar '* (list m2 m2) p2)) a3 (mapcar '+ (mapcar '* (list k3 k3) p2) (mapcar '* (list m3 m3) p3)) r1 (/ (- t2 tcur) (- t2 t0)) s1 (/ (- tcur t0) (- t2 t0)) r2 (/ (- t3 tcur) (- t3 t1)) s2 (/ (- tcur t1) (- t3 t1)) b1 (mapcar '+ (mapcar '* (list r1 r1) a1) (mapcar '* (list s1 s1) a2)) b2 (mapcar '+ (mapcar '* (list r2 r2) a2) (mapcar '* (list s2 s2) a3)) g1 (/ (- t2 tcur) (- t2 t1)) g2 (/ (- tcur t1) (- t2 t1)) c (mapcar '+ (mapcar '* (list g1 g1) b1) (mapcar '* (list g2 g2) b2)) ret (cons c ret) ) ) (reverse ret) ) (defun getlwpolypoints ( e / pts p1 npoints elev m lpt1 lpt2 spt1 spt2 d1 d2 a1 a2 fstart fend ef ) (if (vlax-erased-p e) (progn (entdel e) (setq ef t) ) ) (setq pts (lwpolypoints e) closed (keyValue 70 (entget e))) (if (not (eq (logand closed 1) 1)) (progn (setq spt1 (car pts) spt2 (cadr pts) lpt2 (last pts) lpt1 (nth (- (length pts) 2) pts) d1 (distance spt1 spt2) d2 (distance lpt1 lpt2) a1 (+ (angle spt2 spt1)) a2 (angle lpt1 lpt2) fstart (polar spt1 a1 d1) fend (polar lpt2 a2 d2) pts (append (list fstart) pts) pts (append pts (list fend)) ) ) ) (if (eq (logand closed 1) 1) (progn (setq fend (nth 1 pts) fstart (nth (- (length pts) 2) pts) pts (append (list fstart) pts) pts (append pts (list fend)) ) ) ) (if ef (entdel e) ) pts ) (defun create_dialog ( / f ) (setq f (open file "w")) (write-line "cr: dialog { label = \" Catmull - Rom polyline smoothing \"; : edit_box {key = \"npoints\";label = \" Interpolation points per segment: << coarse smooth >> \";edit_width = 9;}" f) (write-line ": slider { key = \"pointslider\"; max_value = 20; min_value = 1; big_increment = 1; small_increment = 1; }" f) (write-line ": edit_box { key = \"alpha\"; label = \"Bulging << tight - loose >> \"; edit_width = 9; }" f) (write-line ": slider { key = \"alphaslider\"; max_value = 10; min_value = 0; big_increment = 5; small_increment = 1; } " f) (write-line ": row {alignment =\"centered\";fixed_width = true; height = 4;" f) (write-line ": toggle {key =\"eraser\";label =\"Erase base polyline?\";}" f) (write-line ": button { key = \"apply\"; label = \"apply\"; is_default = false; is_cancel = false;is_default=true; width = 5; } } ok_cancel ; }" f) (close f) ) (defun make_catmull_rom_spline ( e / npoints i p0 p1 p2 p3 crom ) (setq pts (mapcar 'point2d (getlwpolypoints e)) npoints (length pts) _alpha (/ alpha 10.0) i 0 ) (while (< i (- npoints 3)) (setq p0 (nth i pts) p1 (nth (+ i 1) pts) p2 (nth (+ i 2) pts) p3 (nth (+ i 3) pts) crom (append crom (catmull_rom_spline p0 p1 p2 p3 _alpha)) i (1+ i) ) ) (setq crom (unique crom)) (entmakex (apply 'append (cons (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 90 (length crom)) '(67 . 0) (cons 410 (if (= (getvar 'cvport) 1) (getvar 'ctab) "Model")) '(62 . 3) (assoc 70 (entget e)) ) (mapcar 'list (mapcar '(lambda ( a ) (cons 10 a)) crom)) ) ) ) ) (defun point_slider_action ( val why ) (if (or (= why 2) (= why 1)) (progn (set_tile "npoints" val) (setq interpoints (atoi val)) ) ) ) (defun alpha_slider_action ( val why ) (if (or (= why 2) (= why 1)) (progn (set_tile "alpha" val) (setq alpha (atoi val)) ) ) ) (defun ebox_action_points ( val why ) (if (or (= why 2) (= why 1)) (progn (set_tile "pointslider" val) (setq interpoints (atoi val)) ) ) ) (defun ebox_action_alpha ( val why ) (if (or (= why 2) (= why 1)) (progn (set_tile "alphaslider" val) (setq alpha (atoi val)) ) ) ) (defun toggle_action_eraser ( val why ) (if (or (= why 2) (= why 1)) (progn (set_tile "eraser" val) (setq eraser (atoi val)) ) ) ) (setq interpoints 10 alpha 5 file (vl-filename-mktemp "catmul.dcl") eraser 0 ) (while (or (not (setq e (car (entsel "\nSelect polygonal lwpolyline (only line segments) to smooth >")))) (if e (or (/= (cdr (assoc 0 (setq ex (entget e)))) "LWPOLYLINE") (not (vl-every 'zerop (mapcar 'cdr (vl-remove-if '(lambda (x) (/= (car x) 42)) ex)))) ) ) ) (prompt "\nMissed or picked wrong entity type or picked lwpolyline has one or more segments not straight - segment(s) with bulge(s)...") (textscr) ) (make_catmull_rom_spline e) (vla-regen (vla-get-activedocument (vlax-get-acad-object)) acactiveviewport) (create_dialog) (setq dcl_id (load_dialog file)) (if (not (new_dialog "cr" dcl_id)) (exit)) (set_tile "npoints" (itoa interpoints)) (set_tile "pointslider" (itoa interpoints)) (set_tile "eraser" (itoa eraser)) (action_tile "pointslider" "(point_slider_action $value $reason)") (action_tile "npoints" "(ebox_action_points $value $reason)") (set_tile "alpha" (itoa alpha)) (set_tile "alphaslider" (itoa alpha)) (action_tile "alphaslider" "(alpha_slider_action $value $reason)") (action_tile "alpha" "(ebox_action_alpha $value $reason)") (action_tile "eraser" "(toggle_action_eraser $value $reason)") (action_tile "apply" "(entdel(entlast))(make_catmull_rom_spline e)(vla-regen (vla-get-activedocument (vlax-get-acad-object)) acactiveviewport)") (action_tile "accept" "(if (= eraser 1)(entdel e))(done_dialog)");action tile (action_tile "cancel" "(entdel(entlast))(done_dialog)");action_tile (start_dialog) (unload_dialog dcl_id) (*error* nil) ) (princ "\nType CROM to create Catmull-Rom spline from lwpolyline (only line segments)") (princ)

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 11 of 12

marko_ribar
Advisor
Advisor

I don't know, maybe just slight change in *.dcl... I removed row : and changed little apply button :...

 

cr : dialog 
{ label = " Catmull - Rom polyline smoothing "; 
	: edit_box 
		{
			key = "npoints";
			label = " Interpolation points per segment: <<  coarse  smooth  >> ";
			edit_width = 9;
		}
	: slider 
		{ 
			key = "pointslider";
			max_value = 20;
			min_value = 1;
			big_increment = 1;
			small_increment = 1;
		}
	: edit_box 
		{
			key = "alpha";
			label = "Bulging << tight - loose >> ";
			edit_width = 9;
		}
	: slider
		{
			key = "alphaslider";
			max_value = 10;
			min_value = 0;
			big_increment = 5;
			small_increment = 1;
		} 
	: toggle 
		{
			key = "eraser";
			label = "Erase base polyline?";
		}
	: button 
		{
			key = "apply";
			label = "Apply";
			alignment = centered;
			fixed_width = true;
		}
	ok_cancel;
}
Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 12 of 12

leeminardi
Mentor
Mentor

@hak_vz a minor correction in your initial post.  The blue curve that you label as "lwpolyline cubic fit" is actually a series of arcs that are tangent where they meet.   It is created from the pedit fit option.  Typically two arc segment are created for each straight line segment of the polyline.  The red curve is a degree 3 B-spline.

lee.minardi
0 Likes