Jump to content

How to create boundary box with spline entity?


kwwong6

Recommended Posts

  • Replies 51
  • Created
  • Last Reply

Top Posters In This Topic

  • marko_ribar

    17

  • kwwong6

    12

  • Lee Mac

    9

  • MSasu

    6

Top Posters In This Topic

Posted Images

Yes I mean like the routine written by Lee Mac. But this Lisp cannot correctly make the bounding box for the spline. I need is really close to the spline ==> "mean no gap".

 

Thanks in advance.

Link to comment
Share on other sites

Indeed, the BoundingBox method is inaccurate for Splines.

 

An alternative approach might be to approximate the Spline using an appropriate point list, then calculate the bounds of such point list; though, this algorithm will undoubtedly be slower than the BoundingBox method.

 

Here is an example to demonstrate this method (you will need to download my Entity to Point List function):

 

(defun BoundingBox ( ent / l )
   (if (setq l (LM:Entity->PointList ent))
       (mapcar '(lambda ( a ) (apply 'mapcar (cons a l))) '(min max))
   )
)

Link to comment
Share on other sites

Alternatively may create a copy in place of the spline, apply FLATTEN command on it and use Lee’s routine for bounding box; remove helper polyline just after.

Link to comment
Share on other sites

Nice idea Mircea!

 

Here is another method (excuse the messy code):

 

(defun SplineBoundingBox ( ent / pt1 pt2 res var )
   (if (setq ent (entmakex (entget ent)))
       (progn
           (setq var (mapcar 'getvar '(peditaccept cmdecho)))
           (mapcar 'setvar '(peditaccept cmdecho) '(1 0))
           (command "_.pedit" ent 10 "")
           (mapcar 'setvar '(peditaccept cmdecho) var)
           (if (not (equal ent (setq ent (entlast))))
               (progn
                   (vla-getboundingbox (vlax-ename->vla-object ent) 'pt1 'pt2)
                   (setq res (mapcar 'vlax-safearray->list (list pt1 pt2)))
               )
           )
           (entdel ent)
       )
   )
   res
)

Test function:

(defun c:test ( / bb en )
   (princ "\nSelect a Spline: ")
   (if (setq en (ssget "_+.:E:S:L" '((0 . "SPLINE"))))
       (if (setq bb (SplineBoundingBox (ssname en 0)))
           (entmakex
               (list
                   (cons 0 "LWPOLYLINE")
                   (cons 100 "AcDbEntity")
                   (cons 100 "AcDbPolyline")
                   (cons 90 4)
                   (cons 70 1)
                   (list 10 (caar  bb) (cadar  bb))
                   (list 10 (caadr bb) (cadar  bb))
                   (list 10 (caadr bb) (cadadr bb))
                   (list 10 (caar  bb) (cadadr bb))
               )
           )
           (princ "\nUnable to retrieve Bounding Box.")
       )
   )
   (princ)
)
(vl-load-com) (princ)

Link to comment
Share on other sites

I think that Lee's code won't be correct for earlier versions of ACAD... If you don't need exactly but approx result, try this...

 

(defun SplineBoundingBox ( ent / xmin xmax ymin ymax res cmde )
   (setq cmde (getvar 'cmdecho))
   (setvar 'cmdecho 0)
   (vl-cmdf "_.ucs" "w")
   (vl-cmdf "_.plan" "")
   (vl-cmdf "_.zoom" "o" ent "")
   (setq ymin (- (cadr (getvar 'viewctr)) (/ (getvar 'viewsize) 2.0)) ymax (+ (cadr (getvar 'viewctr)) (/ (getvar 'viewsize) 2.0)))
   (vl-cmdf "_.ucs" "z" 90)
   (vl-cmdf "_.plan" "")
   (vl-cmdf "_.zoom" "o" ent "")
   (setq xmax (- (car (trans (getvar 'viewctr) 1 0)) (/ (getvar 'viewsize) 2.0)) xmin (+ (car (trans (getvar 'viewctr) 1 0)) (/ (getvar 'viewsize) 2.0)))
   (vl-cmdf "_.zoom" "p")
   (vl-cmdf "_.zoom" "p")
   (vl-cmdf "_.zoom" "p")
   (vl-cmdf "_.zoom" "p")
   (vl-cmdf "_.zoom" "p")
   (vl-cmdf "_.ucs" "p")
   (vl-cmdf "_.ucs" "p")
   (setvar 'cmdecho cmde)
   (setq res (list (list xmin ymin 0.0) (list xmax ymax 0.0)))
   res
)

(defun c:test ( / bb en )
   (princ "\nSelect a Spline: ")
   (if (setq en (ssget "_+.:E:S:L" '((0 . "SPLINE"))))
       (if (setq bb (SplineBoundingBox (ssname en 0)))
           (entmakex
               (list
                   (cons 0 "LWPOLYLINE")
                   (cons 100 "AcDbEntity")
                   (cons 100 "AcDbPolyline")
                   (cons 90 4)
                   (cons 70 1)
                   (list 10 (caar  bb) (cadar  bb))
                   (list 10 (caadr bb) (cadar  bb))
                   (list 10 (caadr bb) (cadadr bb))
                   (list 10 (caar  bb) (cadadr bb))
               )
           )
           (princ "\nUnable to retrieve Bounding Box.")
       )
   )
   (princ)
)

 

If you want exact results, consider converting SPLINE to POLYLINE like Mircea suggested or if you have A2010 or above (not sure for A2009) A2008 doesn't support - try SPLINEDIT -> Convert to polyline and obtain Bounding Box from pline - after remove dummy pline... If you have A2010 or above, then try also Lee's code - just checked on my A2012 and it worked...

Also check this thread from theswamp...

 

M.R.

Edited by marko_ribar
Link to comment
Share on other sites

Thank for Lee Mac and Marko Ribar Lisp. After try on my AutoCAD 2007, still cannot work well. Maybe my AutoCAD are version are too old. Both of your code cannot support. Anyway thank you both of you. I still need to find out how to break though it.

Link to comment
Share on other sites

Thank for Lee Mac and Marko Ribar Lisp. After try on my AutoCAD 2007, still cannot work well. Maybe my AutoCAD are version are too old. Both of your code cannot support. Anyway thank you both of you. I still need to find out how to break though it.

 

kwwong6,

 

As far as I know, the solution that I posted in reply#4 should work in AutoCAD 2007.

Link to comment
Share on other sites

Lee, I'm afraid that PEDIT command of version 2007 doesn't support spline as input.

Command: PEDIT

Select polyline or [Multiple]:

Object selected is not a polyline

I think the programmatically alternative is to parse the spline entity with an appropriate defame and trace it with a polyline. Not sure to how to establish that defame size.
Link to comment
Share on other sites

 
 (defun tracecurve ( obj di / cycle st )
   (defun cycle ( st stp seg l )
     (cond
       ( (< (+ st seg) stp )
         (cycle (+ seg st) stp seg
           (cons (vlax-curve-getPointAtParam obj st) l)
         )
       )
       ( t
         (and (< st stp)
           (setq l
             (cons (vlax-curve-getPointAtParam obj st) l)
           )
         )
         (reverse
           (cons (vlax-curve-getPointAtParam obj stp) l)
         )
       )
     )
   )
   (if
     (and (not (minusp di))(not (zerop di))
       (vl-position 
         (vla-get-objectname 
           (cond
             ( (eq 'ENAME (type obj))(vlax-ename->vla-object obj ))
             ( obj )
           )
         ) '("AcDbCircle" "AcDbArc" "AcDbEllipse" "AcDbSpline")
       )
     )
     (cycle 
       (setq st (vlax-curve-getStartParam obj))
       (vlax-curve-getEndParam obj)
       (- (vlax-curve-getParamAtDist obj 0.125) st)
       nil
     )
   )
 )

 

Modifying Lee Mac's suggestion, though I don't know why his way wouldn't work for you.

 
(defun BoundingBox ( ent / l )
   (if (setq l (tracecurve ent 0.125))
       (mapcar '(lambda ( a ) (apply 'mapcar (cons a l))) '(min max))
   )
)

Link to comment
Share on other sites

@kwwong6 and Lt Dan's legs: Are you both saying that Lee's code from post 6 is working on your AutoCAD 2007?!?

 

Yes, no problem running on AutoCAD 2007. Just having small gap as I upload the attached drawing from post 12.

 

Thank you very much for LT Dan's Legs. Your code really work!!!!! But if for multi select the spline, Can you modify your code?

Link to comment
Share on other sites

Lee, I'm afraid that PEDIT command of version 2007 doesn't support spline as input.

I think the programmatically alternative is to parse the spline entity with an appropriate defame and trace it with a polyline. Not sure to how to establish that defame size.

 

MSasu,

 

I was referring to post#4 in my last post, this solution does not involve the use of PEDIT

Link to comment
Share on other sites

Modifying Lee Mac's suggestion' date=' though I don't know why his way wouldn't work for you.

 
(defun BoundingBox ( ent / l )
   (if (setq l (tracecurve ent 0.125))
       (mapcar '(lambda ( a ) (apply 'mapcar (cons a l))) '(min max))
   )
)

[/quote']

 

But your 'tracecurve' is using linear steps; this will be far less accurate than the method used in my Entity to Point List function :?

Link to comment
Share on other sites

Ya! Lee Mac of course can work. But result are having small gap. I attach a drawing for you so see.

 

Thanks.

 

kwwong,

 

You could never achieve an exact bounding box using this method since this method is approximating a continuous curve with a discrete number of points; for true accuracy, you would need an infinite number of points. You could of course increase the accuracy by increasing the number of points in the approximation, but at a severe loss in performance.

Link to comment
Share on other sites

Thank you Lee Mac for you information. But code done by Lt Dan's legs really can work well for me. Anybody can make this code to multi select spline?

 

Thanks in advance.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...