Author Topic: Offset any Closed Boundary  (Read 5022 times)

0 Members and 1 Guest are viewing this topic.

Lee Mac

  • Seagull
  • Posts: 12912
  • London, England
Offset any Closed Boundary
« on: June 13, 2015, 01:38:37 PM »
I was recently contacted with a question asking whether it was possible to offset a closed boundary formed of objects such as splines & ellipses, which could obviously not be joined to form a continuous closed polyline.

As far as I was aware, there is no standard AutoCAD command or Visual LISP method which will allow you to simultaneously offset multiple objects forming a closed boundary, whilst retaining the continuous boundary edge – each object forming the boundary would need to be offset separately, which would consequently result in the object endpoints no longer being coincident and the continuous boundary would be broken.

My alternative solution was to convert the closed boundary (or a copy of the closed boundary) to a region (REGION command), convert the region to a surface (CONVTOSURFACE command), offset the edge of the surface (OFFSETEDGE command), and then delete the surface and explode the region.

I attempted to automate the process in LISP, however, it doesn't appear to be possible to automate the OFFSETEDGE command, as the following program still requires the user to select the surface created by the program:

Code - Auto/Visual Lisp: [Select]
  1. ;; Boundary Offset  -  Lee Mac
  2.  
  3. (defun c:boffset ( / *error* ent idx lst reg sel sur )
  4.  
  5.     (defun *error* ( msg )
  6.         (if (= 'ename (type sur)) (entdel sur))
  7.         (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
  8.             (princ (strcat "\nError: " msg))
  9.         )
  10.         (princ)
  11.     )
  12.    
  13.     (if (setq sel (ssget "_:L" '((0 . "LINE,*POLYLINE,CIRCLE,ARC,ELLIPSE,SPLINE"))))
  14.         (progn
  15.             (repeat (setq idx (sslength sel))
  16.                 (setq lst (cons (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))) lst))
  17.             )
  18.             (if
  19.                 (vl-catch-all-error-p
  20.                     (setq reg
  21.                         (vl-catch-all-apply 'vlax-invoke
  22.                             (list
  23.                                 (vlax-get-property (vla-get-activedocument (vlax-get-acad-object))
  24.                                     (if (= 1 (getvar 'cvport))
  25.                                         'paperspace
  26.                                         'modelspace
  27.                                     )
  28.                                 )
  29.                                 'addregion lst
  30.                             )
  31.                         )
  32.                     )
  33.                 )
  34.                 (princ (strcat "\nUnable to create region: " (vl-catch-all-error-message reg)))
  35.                 (progn
  36.                     (setq ent (entlast))
  37.                     (command "_.convtosurface" (vlax-vla-object->ename (car reg)) "")
  38.                     (if (not (eq ent (setq sur (entlast))))
  39.                         (progn
  40.                             (command "_.offsetedge")
  41.                             (while (< 0 (getvar 'cmdactive)) (command "\\"))
  42.                             (entdel sur)
  43.                         )
  44.                     )
  45.                 )
  46.             )
  47.         )
  48.     )
  49.     (princ)
  50. )

A quick demo:



The following questions remain:
  • Have I perhaps overlooked a better way to achieve this result?
  • Is there a way to automate the OFFSETEDGE command?

Nevertheless, I hope the above proves useful to someone.

Lee

GP

  • Newt
  • Posts: 83
  • Vercelli, Italy
Re: Offset any Closed Boundary
« Reply #1 on: June 13, 2015, 09:00:30 PM »
...a closed boundary formed of objects such as splines & ellipses, which could obviously not be joined to form a continuous closed polyline...

Hi Lee,
however, you can join to form a continuous closed spline...

GP

  • Newt
  • Posts: 83
  • Vercelli, Italy
Re: Offset any Closed Boundary
« Reply #2 on: June 13, 2015, 10:07:29 PM »
  • Is there a way to automate the OFFSETEDGE command?

Maybe...  :-)

Code: [Select]
(defun c:boffset ( / *error* ent idx lst reg sel sur pt)

    (defun *error* ( msg )
        (if (= 'ename (type sur)) (entdel sur))
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        )
        (princ)
    )
   
    (if (setq sel (ssget "_:L" '((0 . "LINE,*POLYLINE,CIRCLE,ARC,ELLIPSE,SPLINE"))))
        (progn
            (repeat (setq idx (sslength sel))
                (setq lst (cons (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))) lst))
            )
            (if
                (vl-catch-all-error-p
                    (setq reg
                        (vl-catch-all-apply 'vlax-invoke
                            (list
                                (vlax-get-property (vla-get-activedocument (vlax-get-acad-object))
                                    (if (= 1 (getvar 'cvport))
                                        'paperspace
                                        'modelspace
                                    )
                                )
                                'addregion lst
                            )
                        )
                    )
                )
                (princ (strcat "\nUnable to create region: " (vl-catch-all-error-message reg)))
                (progn
                    (setq ent (entlast))                   
                    (setq pt
                             (vlax-safearray->list
                                 (vlax-variant-value
                                     (vla-get-centroid (car reg))
                                 )
                             )
                    )
                    (command "_.convtosurface" (vlax-vla-object->ename (car reg)) "")
                    (if (not (eq ent (setq sur (entlast))))
                        (progn
                            (command "_.offsetedge" pt)
                            (while (< 0 (getvar 'cmdactive)) (command "\\"))
                            (entdel sur)
                        )
                    )
                   
                )
            )
        )
    )
    (princ)
)
(vl-load-com) (princ)

Lee Mac

  • Seagull
  • Posts: 12912
  • London, England
Re: Offset any Closed Boundary
« Reply #3 on: June 14, 2015, 07:05:44 AM »
...a closed boundary formed of objects such as splines & ellipses, which could obviously not be joined to form a continuous closed polyline...
Hi Lee,
however, you can join to form a continuous closed spline...

Thank you GP - I wasn't aware that the JOIN command could be used in this way - that certainly simplifies the task!

  • Is there a way to automate the OFFSETEDGE command?

Maybe...  :-)

Code: [Select]
...
                            (command "_.offsetedge" pt)
...

Excellent  :-)

I had tried supplying the entity name, and I had tried supplying a list containing the entity name & region centroid, but hadn't considered trying just the centroid!  :oops:

ribarm

  • Gator
  • Posts: 3255
  • Marko Ribar, architect
Re: Offset any Closed Boundary
« Reply #4 on: June 14, 2015, 07:32:14 AM »
Lee, your original code was better... Centroid of region may not always lie inside region boundary...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3255
  • Marko Ribar, architect
Re: Offset any Closed Boundary
« Reply #5 on: June 14, 2015, 07:57:14 AM »
I've also noticed that you may actually use JOIN command to join source boundary and then perform normal OFFSET, but for my surprise it's worse than your original approach as now offset boundary may collapse into several boundaries that may touch each other... With converting to surface firstly I had no problem to get single boundary as like it should be processed...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3255
  • Marko Ribar, architect
Re: Offset any Closed Boundary
« Reply #6 on: July 28, 2015, 09:15:52 AM »
I think this is better - it uses point obtained as intersection with bounding box of curve - first(last) (ssname sel 0) object in selection set and that curve...

I've tested it and it satisfies my needs for automation (I think some steps are still necessity)...

Code - Auto/Visual Lisp: [Select]
  1. ;; Boundary Offset  -  Lee Mac  -  mod by M.R. (used Stefan's subs for spline bounding box)
  2.  
  3. (defun c:boffset ( / *error* getSplineBoundingBox pp sp GetBoundingBox bb bbox ch ent idx int lst pt reg sel si sur val )
  4.  
  5.     (vl-load-com)
  6.  
  7.     (defun *error* ( msg )
  8.         (if (and sur (= 'ename (type sur)) (entget sur))
  9.             (entdel sur)
  10.         )
  11.         (if msg (prompt msg))
  12.         (princ)
  13.     )
  14.  
  15.   (defun getSplineBoundingBox ( e / p1 p2 d ax bb ) (vl-load-com)
  16.     (vla-getboundingbox (vlax-ename->vla-object e) 'p1 'p2)
  17.     (setq p1 (vlax-safearray->list p1)
  18.           p2 (vlax-safearray->list p2)
  19.           d  (distance p1 p2)
  20.           p1 (mapcar '- p1 (list d d d))
  21.           p2 (mapcar '+ p2 (list d d d))
  22.           ax (mapcar '(lambda ( n ) (sp e n)) '((t nil nil) (nil t nil) (nil nil t)))
  23.           bb (mapcar
  24.                (function
  25.                  (lambda ( p )
  26.                    (mapcar
  27.                      (function
  28.                        (lambda ( f a n )
  29.                          ((eval f) (vlax-curve-getclosestpointto a (pp p n)))
  30.                        )
  31.                      )
  32.                    '(car cadr caddr)
  33.                    ax
  34.                    '((t nil nil) (nil t nil) (nil nil t))
  35.                    )
  36.                  )
  37.                )
  38.                (list p1 p2)
  39.              )
  40.     )
  41.     (mapcar 'entdel ax)
  42.     bb
  43.   )
  44.  
  45.   ;point projection on axis line
  46.   (defun pp ( p n ) (mapcar 'if n p '(0.0 0.0 0.0)))
  47.  
  48.   ;spline projection on axis line
  49.   (defun sp ( e n )
  50.     (entmakex
  51.       (mapcar
  52.         (function
  53.           (lambda (x)
  54.             (if
  55.               (eq (car x) 10)
  56.               (cons (car x) (pp (cdr x) n))
  57.               x
  58.             )
  59.           )
  60.         )
  61.         (vl-remove-if '(lambda ( x ) (vl-position (car x) '(-1 5 330 67 410 8 210 62 11))) (entget e))
  62.       )
  63.     )
  64.   )
  65.  
  66.   (defun GetBoundingBox ( e / p1 p2 ) (vl-load-com)
  67.     (if (eq (cdr (assoc 0 (entget e))) "SPLINE")
  68.       (getSplineBoundingBox e)
  69.       (progn
  70.         (vla-getboundingbox (vlax-ename->vla-object e) 'p1 'p2)
  71.         (setq p1 (vlax-safearray->list p1)
  72.               p2 (vlax-safearray->list p2)
  73.         )
  74.         (list p1 p2)
  75.       )
  76.     )
  77.   )
  78.  
  79.     (setq sel (ssget "_:L" '((0 . "LINE,*POLYLINE,CIRCLE,ARC,ELLIPSE,SPLINE"))))
  80.     (while (or (not sel) (not (vl-every '(lambda ( x ) (equal (caddr x) 0.0 1e-6)) (apply 'append (mapcar 'GetBoundingBox (vl-remove-if 'listp (mapcar 'cadr (ssnamex sel))))))))
  81.         (prompt "\nEmpty sel.set or selected curves not planar or in WCS plane... Please select 2D curves for processing boundary offset again...")
  82.         (setq sel (ssget "_:L" '((0 . "LINE,*POLYLINE,CIRCLE,ARC,ELLIPSE,SPLINE"))))
  83.     )
  84.     (if sel
  85.         (progn
  86.             (setq bb (GetBoundingBox (ssname sel 0)))
  87.             (setq bbox (entmakex (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") '(90 . 4) '(70 . 1) '(38 . 0.0) (cons 10 (car bb)) (cons 10 (list (caadr bb) (cadar bb))) (cons 10 (cadr bb)) (cons 10 (list (caar bb) (cadadr bb))) (list 210 0.0 0.0 1.0))))
  88.             (setq int (vlax-invoke (vlax-ename->vla-object (ssname sel 0)) 'intersectwith (vlax-ename->vla-object bbox) acextendnone))
  89.             (setq pt (trans (list (car int) (cadr int) (caddr int)) 0 1))
  90.             (entdel bbox)
  91.             (repeat (setq idx (sslength sel))
  92.                 (setq lst (cons (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))) lst))
  93.             )
  94.             (if
  95.                 (vl-catch-all-error-p
  96.                     (setq reg
  97.                         (vl-catch-all-apply 'vlax-invoke
  98.                             (list
  99.                                 (vlax-get-property (vla-get-activedocument (vlax-get-acad-object))
  100.                                     (if (= 1 (getvar 'cvport))
  101.                                         'paperspace
  102.                                         'modelspace
  103.                                     )
  104.                                 )
  105.                                 'addregion lst
  106.                             )
  107.                         )
  108.                     )
  109.                 )
  110.                 (princ (strcat "\nUnable to create region: " (vl-catch-all-error-message reg)))
  111.                 (progn
  112.                     (setq ent (entlast))
  113.                     (command "_.convtosurface" (vlax-vla-object->ename (car reg)) "")
  114.                     (initget 6)
  115.                     (setq ch (getdist "\nPick or specify offset distance <ENTER - Dynamic> : "))
  116.                     (if (numberp ch)
  117.                         (progn
  118.                             (prompt "\nPress <+> - outside; Press <-> - inside")
  119.                             (while (not (or (eq (setq si (cadr (grread nil))) 43) (eq si 45))))
  120.                             (if (eq si 45)
  121.                                 (setq val (strcat "-" (rtos ch 2 50)))
  122.                                 (setq val (strcat "+" (rtos ch 2 50)))
  123.                             )
  124.                             (if (not (eq ent (setq sur (entlast))))
  125.                                 (progn
  126.                                     (command "_.offsetedge" "_non" pt "_D" val)
  127.                                     (while (< 0 (getvar 'cmdactive)) (command ""))
  128.                                     (entdel sur)
  129.                                 )
  130.                             )
  131.                         )
  132.                         (if (not (eq ent (setq sur (entlast))))
  133.                             (progn
  134.                                 (command "_.offsetedge" "_non" pt "\\")
  135.                                 (while (< 0 (getvar 'cmdactive)) (command ""))
  136.                                 (entdel sur)
  137.                             )
  138.                         )
  139.                     )
  140.                 )
  141.             )
  142.         )
  143.     )
  144.     (*error* nil)
  145. )
  146.  

HTH, M.R.
« Last Edit: July 28, 2015, 01:57:48 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3255
  • Marko Ribar, architect
Re: Offset any Closed Boundary
« Reply #7 on: July 28, 2015, 12:20:26 PM »
Last code refined once more... Regards, M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3255
  • Marko Ribar, architect
Re: Offset any Closed Boundary
« Reply #8 on: July 28, 2015, 02:30:03 PM »
Now I think I won't modify it further more... Regards, M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

nobody

  • Swamp Rat
  • Posts: 861
  • .net stuff
Re: Offset any Closed Boundary
« Reply #9 on: July 31, 2015, 12:36:26 AM »
You, sir, are still a badass

ribarm

  • Gator
  • Posts: 3255
  • Marko Ribar, architect
Re: Offset any Closed Boundary
« Reply #10 on: July 31, 2015, 08:33:59 AM »
You, sir, are still a badass

I strongly suggest that you make silly jokes on your account and not on someone else... Maybe you need a hospital here on Earth to cure your thoughts ab someones personality if you don't have already one in your space ship...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Lee Mac

  • Seagull
  • Posts: 12912
  • London, England
Re: Offset any Closed Boundary
« Reply #11 on: July 31, 2015, 01:01:34 PM »
You, sir, are still a badass

I strongly suggest that you make silly jokes on your account and not on someone else... Maybe you need a hospital here on Earth to cure your thoughts ab someones personality if you don't have already one in your space ship...

I'm not sure who the comment was aimed at, but rest assured that in western culture the comment is mostly considered a compliment  :wink:

BlackBox

  • King Gator
  • Posts: 3770
Re: Offset any Closed Boundary
« Reply #12 on: July 31, 2015, 02:33:32 PM »
You, sir, are still a badass

I strongly suggest that you make silly jokes on your account and not on someone else... Maybe you need a hospital here on Earth to cure your thoughts ab someones personality if you don't have already one in your space ship...

I'm not sure who the comment was aimed at, but rest assured that in western culture the comment is mostly considered a compliment  :wink:

1+

Generally speaking, the severity of the 'negative', and strength of the expletive used, are indicators of how 'good' the compliment is intended to be.

As I understand it, the use of the antithesis (instead of just saying what we actually mean; use your words?), started with the baby boomers to be cool, or somehow ironic. This generation's 'millennials' (there just has to be a name for it *sigh*, and not that Alien is one) seem to run a muck pushing the envelope on their example. *sigh again*
"How we think determines what we do, and what we do determines what we get."

AIberto

  • Guest
Re: Offset any Closed Boundary
« Reply #13 on: July 31, 2015, 08:52:44 PM »
You, sir, are still a badass

I strongly suggest that you make silly jokes on your account and not on someone else... Maybe you need a hospital here on Earth to cure your thoughts ab someones personality if you don't have already one in your space ship...

I'm not sure who the comment was aimed at, but rest assured that in western culture the comment is mostly considered a compliment  :wink:


See your comments, I smiled . marko ,You are too wise and farsighted.

I support you forever.

I think Lee said also makes sense.


nobody

  • Swamp Rat
  • Posts: 861
  • .net stuff
Re: Offset any Closed Boundary
« Reply #14 on: August 01, 2015, 01:26:05 AM »
You, sir, are still a badass

I strongly suggest that you make silly jokes on your account and not on someone else... Maybe you need a hospital here on Earth to cure your thoughts ab someones personality if you don't have already one in your space ship...

I'm not sure who the comment was aimed at, but rest assured that in western culture the comment is mostly considered a compliment  :wink:

1+

Generally speaking, the severity of the 'negative', and strength of the expletive used, are indicators of how 'good' the compliment is intended to be.

As I understand it, the use of the antithesis (instead of just saying what we actually mean; use your words?), started with the baby boomers to be cool, or somehow ironic. This generation's 'millennials' (there just has to be a name for it *sigh*, and not that Alien is one) seem to run a muck pushing the envelope on their example. *sigh again*

With humility, lesson learned :)  My compliments to everyone on this forum :) You wouldn't be here if you weren't incredibly talented.