Jump to content

Offset with list (like Multiple Offset on the appstore)


3dwannab

Recommended Posts

Hi all,

 

I was looking if there was an existing routine to do the same as this on the appstore whereby you can input to the commandline this for instance '200 500 555' and it will offset to those 3 distances?

 

 

https://apps.autodesk.com/ACD/en/Detail/Index?id=7131157146074921574&appLang=en&os=Win32_64#:~:text=MOffset fills this gap by,is the integration with AutoCAD.

Link to comment
Share on other sites

@3dwannab Here is the simplest way - no minimal error checking:

(defun c:moff (/ *error* _Strparse cnt dstr en go op s tl)
   
   (defun *error* (msg)(if oc (setvar "cmdecho" oc))(princ msg))
   
   (setq oc (getvar "cmdecho"))
   (setvar "cmdecho" 0)
   (command "._undo" "_BE")
   
   (defun _StrParse (str del / pos)
     (if (and str del)
        (if (setq pos (vl-string-search del str))
          (cons (substr str 1 pos) (_StrParse (substr str (+ pos 1 (strlen del))) del))
          (list str)
        )
     )
   ) 

   (if (and
         (setq dstr (getstring t "\nEnter Distances separated by spaces: "))
         (setq s (entsel "\nSelect a curve to offset: "))
         (setq en (car s) cnt 0)
         (setq go (wcmatch (cdr (assoc 0 (entget en))) "LINE,*POLYLINE,SPLINE,XLINE,CIRCLE,ARC,ELLIPSE"))
         (setq op (getpoint (cadr s) "\nSelect side to Offset: "))
      )
      (if (setq tl (_Strparse dstr " "))
         (foreach n tl
           (command "._offset" (nth cnt tl) en "_non" op "")
           (setq cnt (1+ cnt))
         )
      )
      (if (not go)(princ "\nInvalid Object Selected."))
   )

   (command "._undo" "_E")
   (setvar "cmdecho" oc)
   (princ)
)

 

Edited by pkenewell
  • Thanks 1
Link to comment
Share on other sites

@pkenewell, nice code. I was sure there was something like this out in the wild somewhere but I couldn't find it. I like the portability of LISPs' without having to install for future versions like appstore apps.

 

Thanks very much.

Link to comment
Share on other sites

On 1/24/2024 at 10:30 AM, 3dwannab said:

I was sure there was something like this out in the wild somewhere but I couldn't find it.

@3dwannab Glad you like it! LOL - there probably is something out there, but I just wrote it for you on the fly since it was a fairly simple task.

Link to comment
Share on other sites

I have another trying to find it, if you use VLA-Offset you can supply +ve and -ve values so will go left and right without need for direction pick, with open plines and lines select near an end implies the direction of the linework so goes right with +ve values. 

 

Arcs and circles reduce or increase radius.

Edited by BIGAL
  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

@3dwannab I'm have been working on a solution that doesn't use command, but it is not as easy as it seems. Determining the side to offset is a different challenge depending on the object selected and whether it is closed or open. I haven't determined a version that works for everything yet. It's MUCH less code just to use the offset command.

  • Like 1
Link to comment
Share on other sites

1 hour ago, pkenewell said:

Lee Macs Dynamic Offset offsets to both sides, so there is no method of determining which side to offset.

 

Read the instructions again, you hit Tab to switch between either side or both. 

 

Quote

Offset Mode     Can be changed by pressing Tab, the user has the ability to offset the set of objects to either side, or both sides simultaneously

 

Link to comment
Share on other sites

6 hours ago, SLW210 said:

 

Read the instructions again, you hit Tab to switch between either side or both. 

 

 

 

@SLW210 Sorry you're right. It conveniently gives you a preview to determine which side. That's something I hadn't thought of!

 

@3dwannab FWIW. I did figure out something with some ingenious ideas from both LeeMac and RonjonP, that make the code pretty short. It may not work perfectly in every instance unless you set your "select offset side" point well out past all the distances you enter (EDIT - I think I solved this). See the code below:

;|==============================================================
moff.lsp by Phil Kenewell - 2/23/2024

Description:
  This routine contain command MOFF, or Multiple Offset. It allows
  you to enter multiple offset distances, separated by spaces and
  will offset all those distances to the side you specify.
  
Some code Inspired by:
   RonJonP: https://www.theswamp.org/index.php?topic=24688.msg297553#msg297553
   Lee Mac: https://www.theswamp.org/index.php?topic=32743.0

Last Update:
   - 2/23/2024: changed using "atof" to "distof" to allow fractions, etc.

===============================================================|;
(defun c:moff (/ _strparse ds ob op s t1 t2 tl)

   ;; Sub function to Parse a string by the specified delimiter.
   (defun _StrParse (str del / pos)
     (if (and str del)
        (if (setq pos (vl-string-search del str))
          (cons (substr str 1 pos) (_StrParse (substr str (+ pos 1 (strlen del))) del))
          (list str)
        )
     )
   )

   
   (if
      (and
         (setq ds (getstring t (strcat "\nEnter Distances separated by spaces: <" (if pjk:offdist pjk:offdist "") ">"))
               ds (if (= ds "") pjk:offdist (setq pjk:offdist ds))
         )
         (/= ds "")
         (setq tl (_Strparse ds " "))
         (> (apply '+ (mapcar 'distof tl)) 0.0)
      )
      (if (and
            (setq s  (entsel "\nSelect a curve to offset: "))
            (setq ob (vlax-ename->vla-object (car s)))
         )
         (if (not (vlax-method-applicable-p ob 'Offset))
           (princ "\nInvalid object for Offset. ")
           (if (setq op (getpoint (cadr s) "\nSelect side to Offset: "))
               (progn
                  ;; Make sure the offset side point at the outside of the offset zone.
                  (setq op (polar (cadr s) (angle (cadr s) op) (apply '+ (mapcar 'atof tl))))
                  ;; iterate for each dist
                  (foreach n (mapcar 'distof tl)
                     (setq t1 (car (vlax-invoke ob "offset" n))
      	                  t2 (car (vlax-invoke ob "offset" (- n)))
                     )
                     (if
                        (< (distance op (vlax-curve-getclosestpointto t1 op))
      	                  (distance op (vlax-curve-getclosestpointto t2 op))
      	               )
                        (vla-delete t2)
                        (vla-delete t1)
                     )
                  )
               )
            )
         )
      )
      (progn
         (setq pjk:offdist nil)
         (princ "\nInvalid Distances Entered.")
      )
   )
   (princ)
)

 

Edited by pkenewell
Change program flow to add better handling of errors, such as an invalid string entered for distances. EDIT 2: changed "atof" to "distof" to allow fractions, etc.
  • Like 1
Link to comment
Share on other sites

20 minutes ago, 3dwannab said:

Brilliant stuff @pkenewell, this is brilliant for footpaths, cavity walls and other things I can't think off atm.

 

👏

@3dwannab Thanks!

NOTE: I updated the code in my previous post to have better error handling if someone enters an invalid string for the distances. Please re-copy it.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

@3dwannab FYI - I changed the code above again to allow different units, like fractions, architectural, etc. Simple change from using "atof" to convert the strings to using "distof".

Edited by pkenewell
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Just a comment or 2,

 

a closed object when offset to outside the area will be bigger than original so a +v or -ve can be implied, just check and erase if required uses VLA-offset. Hint recent post forums/autodesk.

 

an open object like a line or pline you pick near an end this implies the direction of the line a simple little defun can check. You get used to it, yes vertical lines etc.

 

Just for illustration needs line or pline handled differently.

(setq ent1 (entsel "\nPick line 1 TP end "))
(setq pt1 (cadr ent1))
(setq ent1g (entget (car ent1)))
(setq pt10 (cdr (assoc 10 ent1g)))
(setq pt11 (cdr (assoc 11 ent1g)))
(setq d1 (distance pt1 pt10))
(setq d2 (distance pt1 pt11))
(if (> d1 d2)
; swap offset +ve -ve value
......
)

 

  • Like 1
Link to comment
Share on other sites

  • 7 months later...
On 2/23/2024 at 8:36 PM, pkenewell said:

@3dwannab FYI - I changed the code above again to allow different units, like fractions, architectural, etc. Simple change from using "atof" to convert the strings to using "distof".

 

I've just tried to change this to offset from the original line. If I enter 100 200 as the offset, i was looking for the first offset to be 100 and then the other 300 (100+200). 

 

So, if I enter 100 150 100 it will draw me a cavity wall with 100 inner leaf/150 cavity/100 outer leaf.

 

I thought by adding (setq n (+ n n) in the foreach loop it would do that.

 

(foreach n (mapcar 'distof tl) 

  ;; Not worky
    (setq n (+ n n))

  (setq t1 (car (vlax-invoke ob "offset" (+ n n)))
        t2 (car (vlax-invoke ob "offset" (- n)))
  )
  (if 
    (< (distance op (vlax-curve-getclosestpointto t1 op)) 
        (distance op (vlax-curve-getclosestpointto t2 op))
    )
    (vla-delete t2)
    (vla-delete t1)
  )
)

 

 

Fixed it. Added revision edit in the header. Thanks again @pkenewell for this. It's a huge timesaver.

 

;|==============================================================
moff.lsp by Phil Kenewell - 2/23/2024

Description:
  This routine contains the command MOFF, or Multiple Offset. It allows
  you to enter multiple offset distances, separated by spaces and
  will offset all those distances to the side you specify.

Some code Inspired by:
   RonJonP: https://www.theswamp.org/index.php?topic=24688.msg297553#msg297553
   Lee Mac: https://www.theswamp.org/index.php?topic=32743.0

Last Update:
   - 2024.02.23: Changed using "atof" to "distof" to allow fractions, etc.
   - 2024.10.23: (Edit by 3dwannab)
      - Change the offset to offset incrementally.
        - Entering 100 150 100 will draw a cavity wall with a 100 inner leaf/150 cavity/100 outer leaf.
      - Command is now moffi to reflect the change to an incremental multiple offset.
      - Added undo handling.

===============================================================|;
(defun c:moffi (/ *error* _strparse ds ob op s t1 t2 tl inc) 

  (defun *error* (errmsg) 
    (and acDoc (vla-EndUndoMark acDoc))
    (and errmsg 
         (not (wcmatch (strcase errmsg) "*CANCEL*,*EXIT*"))
         (princ (strcat "\n<< Error: " errmsg " >>\n"))
    )
    (setvar 'cmdecho var_cmdecho)
    (setvar 'osmode var_osmode)
  )

  ;; Start the undo mark here
  (setq acDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (or (vla-EndUndoMark acDoc) (vla-StartUndoMark acDoc))

  ;; Sub function to Parse a string by the specified delimiter.
  (defun _StrParse (str del / pos) 
    (if (and str del) 
      (if (setq pos (vl-string-search del str)) 
        (cons (substr str 1 pos) (_StrParse (substr str (+ pos 1 (strlen del))) del))
        (list str)
      )
    )
  )

  (if 
    (and 
      (setq ds (getstring t (strcat "\nEnter Distances separated by spaces: <" (if pjk:offdist pjk:offdist "") ">"))
            ds (if (= ds "") pjk:offdist (setq pjk:offdist ds))
      )
      (/= ds "")
      (setq tl (_Strparse ds " "))
      (> (apply '+ (mapcar 'distof tl)) 0.0)
    )
    (if 
      (and 
        (setq s (entsel "\nSelect a curve to offset: "))
        (setq ob (vlax-ename->vla-object (car s)))
      )
      (if (not (vlax-method-applicable-p ob 'Offset)) 
        (princ "\nInvalid object for Offset. ")
        (if (setq op (getpoint (cadr s) "\nSelect side to Offset: ")) 
          (progn 
            ;; Make sure the offset side point at the outside of the offset zone.
            (setq op (polar (cadr s) (angle (cadr s) op) (apply '+ (mapcar 'atof tl))))
            (setq inc 0.0) ; Initial value of i as a float

            ;; iterate for each dist
            (foreach n (mapcar 'distof tl) 

              (setq inc (+ inc n)) ; Increment n by each element in the list so the offset happens incrementally

              (setq t1 (car (vlax-invoke ob "offset" inc))
                    t2 (car (vlax-invoke ob "offset" (- inc)))
              )
              (if 
                (< (distance op (vlax-curve-getclosestpointto t1 op)) 
                   (distance op (vlax-curve-getclosestpointto t2 op))
                )
                (vla-delete t2)
                (vla-delete t1)
              )
            )
          )
        )
      )
    )
    (progn 
      (setq pjk:offdist nil)
      (princ "\nInvalid Distances Entered.")
    )
  )
  (vla-EndUndoMark acDoc)
  (*error* nil)
  (princ)
)

;;(c:moffi) ;;; Unblock for testing

 

Edited by 3dwannab
  • Like 1
Link to comment
Share on other sites

The reason for the edit was I am working on a cavity wall 102.5 outer brick leaf / 150 cavity / 215 inner leaf / 18mm plaster so that would translate to 102.5 252.5 467.5 485.5.

 

That would give an aspirin a headache trying to remember that, well me anyway!! 🤣

  • Like 1
Link to comment
Share on other sites

Why not use a Mline then can draw walls as in plural. 

 

This is a make mline.

; make mline 
; By alan H oct 2020
; Set to bylayer at moment
; Thanks to FIXO for original code

(defun c:makml ( / lst1 lst2 lst desc MLINE_STYLE_NAME )
(setq 	MLINE_STYLE_NAME (getstring "\nEnter mline name ")
		desc (getstring "\nEnter description ")
)
(while (setq off (getreal "\Enter offset Enter to finish " ))
	(setq lst (cons off lst))
)
(if (= desc nil)(setq desc MLINE_STYLE_NAME))
(setq lst1
	(list '(0 . "MLINESTYLE")
		'(100 . "AcDbMlineStyle")
		(cons 2 MLINE_STYLE_NAME)
		(cons 70 (+ 272))
		(cons 3 desc)
		'(62 . 256)
		(cons 51 (/ pi 2.))
		(cons 52 (/ pi 2.))
		'(71 . 4)
    '(72 . 4)
   	)
)
(setq x (length lst))
(repeat x
	(setq lst2 (list 
		(cons 49 (nth (setq x (- x 1)) lst))
		(cons 62 256)
		(cons 6 "BYLAYER")
		)
	)
	(setq lst1 (append lst1 lst2))
)
(if
	(not (dictadd
		(cdar (dictsearch (namedobjdict) "ACAD_MLINESTYLE"))
		MLINE_STYLE_NAME
		(entmakex lst1)
		)
	)
	(Alert "Impossible to create mline style\n perhaps this was exist earlier")
)
(setvar 'cmlstyle MLINE_STYLE_NAME)
(princ)
)
(c:makml)

 

Edited by BIGAL
Link to comment
Share on other sites

15 hours ago, 3dwannab said:

The reason for the edit was I am working on a cavity wall 102.5 outer brick leaf / 150 cavity / 215 inner leaf / 18mm plaster so that would translate to 102.5 252.5 467.5 485.5.

 

That would give an aspirin a headache trying to remember that, well me anyway!! 🤣

@3dwannab That's cool - I completely understand. Glad you could alter the code to fit your needs! 😀👍

  • Thanks 1
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...