Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Implied selection set and joining help

7 REPLIES 7
Reply
Message 1 of 8
Jonathan_Bell82GXG
427 Views, 7 Replies

Implied selection set and joining help

I'm writing a script to join and then offset various entities on certain layers. It works perfectly when running the command OFFSETAUTO without a selection set already made, but I want it to work for an implied selection set as well. Currently, it results in an "invalid selection" error for implied selection sets. Any tips on what I could improve on? You can see I've tried to clean up the selection set before feeding it to joinSegments (where I believe the error is), but no luck so far. Thanks in advance

 

(defun c:OFFSETAUTO ( / ss)  ;;;;;; add all local vars
    ; better ss handling: delete and add entities to ss as needed
  
    ; add more detailed error handling
    ; advanced undo mark: named undo's, option to undo joining, all offsets, and/or a single offset (ordered in a certain way, like left to right & top to bottom)
    
    ; load all ActiveX and reactor support extended functions
    (vl-load-com)
  
    ; general error handler
    (defun *error* (errMessage)
        
        ; if not standard error (due to hitting ESC, for instance), print error
        (if (not (wcmatch errMessage "Function cancelled,quit / exit abort,console break"))
            (princ (strcat "\nError: " errMessage))
        )
       
        (vla-endundomark doc)
      
        (princ)
    )
  
    ; turn CMDECHO off if needed
    (if (/= (getvar "CMDECHO") 0)
        (progn 
            (setq cmdEcho (getvar "CMDECHO"))
            (setvar "CMDECHO" 0)
        )
    )
  
    ; getting ACAD object and active document for use with (vl-startundomark) and (vl-endundomark)
    (setq acadObj (vlax-get-acad-object))
    (setq doc (vla-get-ActiveDocument acadObj))

    ; misc. obstructions offset vars
    (setq miscOffset 4) ; 4 inch misc. obstructions offset 
    (setq miscOSLayer "PV VENTS SKYLIGHTS ROOF DRAINS") ; layer of misc. obstructions offset
  
    ; mech. obstructions offset vars
    (setq mechOffset 6) ; 6 inch mech. obstructions offset 
    (setq mechOSLayer "PV MECH EQUIP SETBACK") ; layer of misc. obstructions offset
  
    ; get current layer, color, lineweight, linetype to change back to after command   ;;;;;;;;;;;;;;; method for getting current color, lweight/style
    ; maybe could get current color by accessing last made entity (might have issues if entlast doesn't work for a new drawing session)
    ; (setq cLayer (getvar "CLAYER"))   ;;;;;;;;;;;; change depending on final offset method
    ; (princ cLayer)

    ;; get ent data tester: (entget (car (entsel)))


    ; processing selecton set
    (if (not (ssget "_I")) 
        ; if no currently active selection set:
        (progn 
            (setq pt1 (getpoint "\nSpecify first corner: "))
            (setq pt2 (getcorner pt1 "\nSpecify opposite corner: "))
            (setq ss (ssget "_C" 
                            pt1
                            pt2
                     )
            )
        )

        ; else there is an active (implied) selection set:
        (progn 
            
            ; get implied selection set
            (setq ss (ssget "_I"))
          
            ; loop through selection set entities
            (setq ssnum 0)
            (setq pointList (list))
          
            (repeat (sslength ss)
              
                ; get each entity
                (setq entList (entget (ssname ss ssnum)))
              
                ; add list of x & y coords to list of points
                (setq fullPt (assoc '10 entList))
                (setq x (nth 1 fullPt))
                (setq y (nth 2 fullPt))
                (setq pointList (cons (list x y) pointList))
              
                ; increment indexing var
                (setq ssnum (1+ ssnum))
            )
        )
    )

    

    ; start joinSegments undo mark
    (vla-startundomark doc)
    
    ; filter out anything that's not pline, line, or arc from ss before feeding to joinSegments
    ; then add those elements back into ss after joinSegments
    (setq ssDelList (list))
  
    (setq ssnum 0)
    (repeat (sslength ss)

        (setq eName (ssname ss ssnum))
        (setq entList (entget eName))
        
        (if (not 
                (wcmatch 
                    (cdr (assoc '0 entList))
                    "LWPOLYLINE,LINE,ARC"
                )
            )
          
            (setq ssDelList (cons eName ssDelList))
        )
      
        (setq ssnum (1+ ssnum))
    )
  
    (foreach eNameDel ssDelList 
      
        (ssdel eNameDel ss)
    )
  
    ; join all unconnected entity groups into polylines
    (princ ss)
    (if ss
        (joinSegments ss)
    )
    (princ ss)
  
    (foreach eNameDel ssDelList 
      
        (ssadd eNameDel ss)
    )
     
    
    ; end joinSegments undo mark
    (vla-endundomark doc)
    
    ; update selection set - fix to work w/ implied set
    
    ; if implied selection set
    (if (ssget "_I")
        (princ "\nHERE!\n")
      
        ; else update previous crossing selection
        (setq ss (ssget "_C" pt1 pt2))
    )
        ; get list of all entities on points from previous list
        ; remove duplicates
        ; set ss as this list
    ; else:
        
    
    
    ; DEBUGGING - print length of selection set
    ; (princ
    ;     (strcat "\nSSLENGTH: "
    ;             (itoa (sslength ss))
    ;     )
    ; )

    ; loop through entities in selection set
    (setq ssnum 0)
    (repeat (sslength ss) 

        ; start individual offset undo mark
        (vla-startundomark doc)
      
        ; Get entity name and assoc list for each entity
        (setq ename (ssname ss ssnum))
        (setq entList (entget ename))
      
        ; DEBUGGING - Print ename of each entity in ss
        ; (princ "\nEname:\n")
        ; (princ ename)
        
        ; DEBUGGING - Print elist of each entity in ss
        ; (princ "\nEntity:\n")
        ; (princ entList)

        ; if entity is on "PV Misc Obstructions" layer and is CIRCLE/LWPOLYLINE, offset it
        (offsetHandler entList "PV Misc Obstructions" miscOffset miscOSLayer)
      
        ; if entity is on "PV Mechanical Obstructions" layer and is CIRCLE/LWPOLYLINE
        (offsetHandler entList "PV Mechanical Obstructions" mechOffset mechOSLayer)

        ; end individual offset undo mark
        (vla-endundomark doc)
      
        ; increment ssnum
        (setq ssnum (1+ ssnum))
      )

      ; set all of selection set to "BYLAYER" styles
      (setq ss (ssget "_C" pt1 pt2)) ; update ss
      (setq setByLayerMode (getvar "SETBYLAYERMODE")) ; get SETBYLAYERMODE default
      (setvar "SETBYLAYERMODE" 7) ; set color, linetype, lineweight to "BYLAYER"
      (command-s "_.SETBYLAYER" ss "" "YES" "NO") ; set all entity styles to "BYLAYER", excluding blocks 
          ; (note "._" ensures command works in non-English versions of ACAD and in case command was redefined)
      (setvar "SETBYLAYERMODE" setByLayerMode) ; reset default

      ; turn CMDECHO back on if needed
      (if (= (getvar "CMDECHO") 0)
          (setvar "CMDECHO" cmdEcho)
      )

      ; exit quietly
      (princ)
    )



    ;;; HELPER FUNCTIONS ;;;

    ; OFFSETHANDLER - checks that entity is on correct layer and is CIRCLE/LWPOLYLINE, then offsets
    (defun offsetHandler (entList entLayer osDist osLayer / entEname)

        ; VARLIST
        ;; INPUTS
        ;;; entList - offset entity definition (ASSOC LIST)
        ;;; entLayer - correct entity layer of entity to offset (STR)
        ;;; osDist - amount to offset by (INT)
        ;;; osLayer - layer of offset entity (STR)
        ;; LOCAL VARS
        ;;; entEname - entity name of entity to offset (ENAME)
        
      
        ; get ename of entity
        (setq entEname (cdr (car entList)))
      
        ; if entity is on correct layer and is CIRCLE/LWPOLYLINE, offset
        (if 
            (and 
                (equal 
                    (cdr (assoc '8 entList))
                    entLayer
                )
                (or 
                    (equal 
                        (cdr (assoc '0 entList))
                        "CIRCLE"
                    )
                    (equal
                        (cdr (assoc '0 entList))
                        "LWPOLYLINE"
                    )
                )
            )
            
            ; offset entity (if error in offset, run offsetOuterError func)
            (progn 
                  (setq errObject (vl-catch-all-apply 'offsetOuter 
                                                    (list entEname osDist osLayer)
                                )
                  )
                
                  (if (vl-catch-all-error-p errObject)
                      (offsetOuterError entEname osDist osLayer)
                  )
            )
        )
      
    )

    ; OFFSETOUTERERROR - for handling error of inner offset on entity too small, offsets given polyline or circle entity by given amount and on given layer & color
    (defun offsetOuterError (eName osDist osLayer / offsetEList)
      
        ; VARLIST
        ;; INPUTS
        ;;; eName - entity name of entity to offset (ENAME)
        ;;; osDist - amount to offset by (INT)
        ;;; osLayer - offset layer (STR)        
        ;; LOCAL VARS
        ;;; offsetEList - offset entity definition (ASSOC LIST)
      
        ; error handling version if vla-offset attempts to inner-offset an entity too small (offset wouldn't fit inside entity)
        ; convert entity name to vla-object, then offset by negative osDist amount 
        (vla-offset (vlax-ename->vla-object eName) (- osDist))
      
        ; get offset assoc list
        (setq offsetEList (entget (entlast)))
      
        ; change offset layer
        (setq offsetEList (subst (cons '8 osLayer) 
                                 (assoc '8 offsetEList)
                                 offsetEList
                          )
        )
        (entmod offsetEList)
    )

    ; OFFSETOUTER - offsets given polyline or circle entity by given amount and on given layer & color
    (defun offsetOuter (eName osDist osLayer / originalArea offsetEName offsetArea offsetEList) 

        ; VARLIST
        ;; INPUTS
        ;;; eName - entity name of entity to offset (ENAME)
        ;;; osDist - amount to offset by (INT)
        ;;; osLayer - offset layer (STR)        
        ;; LOCAL VARS
        ;;; originalArea - area of entity to offset (REAL)
        ;;; offsetEName - entity name of offset entity (ENAME)
        ;;; offsetArea - area offset entity (REAL)
        ;;; offsetEList - offset entity definition (ASSOC LIST)
      
        ; inspired by Kent Cooper's offset subroutine (comparing offset area with entity area): https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/offset-multiple-objects-at-once/m-p/8172189/highlight/true#M372175

        ; convert entity name to vla-object, then offset by osDist amount
        (vla-offset (vlax-ename->vla-object eName) osDist)
      
        ; get area of original entity
        ;; NOTE: For open entities, vla-get-area draws line between 2 unaligned points
        ;;;;;;;; If points are aligned, vla-get-area assumes rectangle
        ;;;;;;;; Algorithm should still work though
        (setq originalArea (vla-get-area (vlax-ename->vla-object eName)))
      
        ; get area of offset
        (setq offsetEName (entlast))
        (setq offsetArea (vla-get-area (vlax-ename->vla-object offsetEName)))

        ; compare area of offset to area of original, delete and redo offset if offset area is smaller
        (if (< offsetArea originalArea) 
            (progn
                (entdel offsetEName)
                (vla-offset (vlax-ename->vla-object eName) (- osDist))
            )
        )

        ; get new offset assoc list
        (setq offsetEList (entget (entlast)))
      
        ; change offset layer
        (setq offsetEList (subst (cons '8 osLayer) 
                                 (assoc '8 offsetEList)
                                 offsetEList
                          )
        )
        (entmod offsetEList)
    )

    ; JOINSEGMENTS - joins groups of polylines, lines, arcs together into single polylines (works best if touching entity groups are on different layers)
    (defun joinSegments (ss /) 

        ; VARLIST
        ;; INPUTS
        ;;; ss - input selection set of any type (SEL SET)
        ;; LOCAL VARS - NONE

        ; join all segments into polylines
        (setvar "PEDITACCEPT" 1)
      
        ; using PEDIT command to join all entity groups into polylines
        (command-s "_.PEDIT" "MULTIPLE" ss "" "JOIN" "" "")
    )


; last statement to display (quietly loading)
(princ)

 

script I'm using to load in a couple layers:

; command to load and save to defaults (if necessary) PV Vents/Misc Obstructions & PV Mech Obstructions
; could add support for customized display styles vs plot styles

; layerLoad - auto-loads "PV MECHANICAL OBSTRUCTIONS" and "PV VENTS SKYLIGHTS ROOF DRAINS OBSTRUCTIONS" layers

; turn off CMDECHO (stops commands from being printing to command line)
(setq cmdEcho (getvar "CMDECHO"))
(if (= cmdEcho 1) (setvar "CMDECHO" 0))

; load "PV Mechanical Obstructions"
(setq layername "PV Mechanical Obstructions")
(command "-LAYER" "N" layername "COLOR" "TRUECOLOR" "0,0,0"  layername "LTYPE" "CONTINUOUS" layername "LWEIGHT" "DEFAULT" layername "TRANSPARENCY" "0" layername "")

; load "PV Misc Obstructions"
(setq layername "PV Misc Obstructions")
(command "-LAYER" "N" layername "COLOR" "TRUECOLOR" "0,0,0"  layername "LTYPE" "CONTINUOUS" layername "LWEIGHT" "DEFAULT" layername "TRANSPARENCY" "0" layername "")

; release LAYERNAME from memory
(setq layername nil)

; set turn CMDECHO back on if needed
(if (= cmdEcho 0) (setvar "CMDECHO" 1))

; exit quietly 
(princ)
7 REPLIES 7
Message 2 of 8

Some thoughts:

In the Layer business at the end, except for the Truecolor, the properties you're setting to them are defaults, so you don't need to set them.  And if you're setting CMDECHO to 0 regardless and at the end to 1 regardless, just do that -- no need to test the value, nor to use a variable.  And since the properties you're setting to the Layers are the same, you can do that to more than one Layer together with a comma-delimited string of Layer names.  I think this is all you need:

(setq layernames "PV Mechanical Obstructions,PV Misc Obstructions")
(setvar 'cmdecho 0)
(command "_.layer" "_new" layernames "_color" "_truecolor" "0,0,0" layernames "")
(setvar 'cmdecho 1)

Do you really need a Truecolor version of Black?  If you work with a white background, color 7 is the same, and it's the default for new Layers, so you don't need to assign it, so you can do just:

(setvar 'cmdecho 0)
(command "_.layer" "_new" "PV Mechanical Obstructions,PV Misc Obstructions" "")
(setvar 'cmdecho 1)

Only if those Layers may already exist with non-default color or transparency or lineweight, and you want to correct those properties, do you need to assign them.

Likewise with CMDECHO outside the Layer part, the only place you use your cmdEcho variable is here:

      (if (= (getvar "CMDECHO") 0)
          (setvar "CMDECHO" cmdEcho)
      )

so you "reset" it only if it's 0.  But it will always be 0 at that point, because either you set it that way earlier if it was 1, or it was already 0.  You set it into the variable only if it was 1.  Presumably after you're done you will want command-echoing to operate.  So again, I would simply set it to 0 at the beginning regardless, and set it to 1 at the end, and forget the variable.

This:

(setq pointList (list))

does nothing for you.  A "list" with nothing in it is not even a list at all -- it's nothingness, nonexistent [i.e. nil].  You could set it to nil instead of to (list), but don't bother -- just put it in the localized variables list at the top and it will be nil to begin with for purposes of the routine.  BUT you don't build the equivalent pointlist if there's no pre-selection, only if there is, but in any case, I don't see that you use the pointlist variable anywhere, so....?

 

You don't need to step through an any-kind-of-thing selection and check the entity type of each thing to decide whether to remove it.  You can limit selection to only those kinds of things you want:

(if (ssget "_I") ; if there is a currently active selection set:
  ; then, get only wanted things from it:
  (setq ss (ssget "_I" '((0 . "LINE,LWPOLYLINE,ARC"))))
  (progn ; else
    (setq
      pt1 (getpoint "\nSpecify first corner: ")
      pt2 (getcorner pt1 "\nSpecify opposite corner: ")
    )
    (setq ss (ssget "_C" pt1 pt2 '((0 . "LINE,LWPOLYLINE,ARC"))))
  )
)

 

Kent Cooper, AIA
Message 3 of 8

Thanks for the feedback, I've implemented your suggestions. However, if there's an active selection set and then OFFSETAUTO is run, I need a way to update the selection set to reflect changes (lines being joined into polylines, for instance), or just take out the chunk of code shown below and change each offset entity's styles to BYLAYER within the helper functions. This is the part I struggled with. Do you have any suggestions for ways I might accomplish this?

 

 

; set all of selection set to "BYLAYER" styles
      (setq ss (ssget "_C" pt1 pt2)) ; update ss
      (setq setByLayerMode (getvar "SETBYLAYERMODE")) ; get SETBYLAYERMODE default
      (setvar "SETBYLAYERMODE" 7) ; set color, linetype, lineweight to "BYLAYER"
      (command-s "_.SETBYLAYER" ss "" "_YES" "_NO") ; set all entity styles to "BYLAYER", excluding blocks 
          ; (note "._" ensures command works in non-English versions of ACAD and in case command was redefined)
      (setvar "SETBYLAYERMODE" setByLayerMode) ; reset default

 

 

Message 4 of 8

How about doing that SetByLayer thing to the original selection set, before you go through it to Offset etc.?

Kent Cooper, AIA
Message 5 of 8

There still has to be a way to update the selection set to reflect the changed entities. Wherever I place the SETBYLAYER command I don't think is relevant-- I need to first input the filtered selection set to joinSegments then get the new selection set (whether the original selection set was implied or not) which reflects the now joined entities to be put into the chunk of code handling offsetting

Message 6 of 8


@Jonathan_Bell82GXG wrote:

There still has to be a way to update the selection set to reflect the changed entities. ....


Not if everything in the selection you want to update was already processed before any of the joining/offsetting changes happen -- you won't need to do anything more to them, so you won't need to update the selection.

Kent Cooper, AIA
Message 7 of 8

Maybe I'm missing something, but here's what I'm currently working with:

autoOffset.lsp:

 

(defun c:OFFSETAUTO ( / ss)  ;;;;;; add all local vars
    ; better ss handling: delete and add entities to ss as needed
    ; add more detailed error handling
    ; advanced undo mark: named undo's, option to undo joining, all offsets, and/or a single offset (ordered in a certain way, like left to right & top to bottom)
    
    ; load all ActiveX and reactor support extended functions
    (vl-load-com)
  
    ; general error handler
    (defun *error* (errMessage)
        
        ; if not standard error (due to hitting ESC, for instance), print error
        (if (not (wcmatch errMessage "Function cancelled,quit / exit abort,console break"))
            (princ (strcat "\nError: " errMessage))
        )
       
        (vla-endundomark doc)
      
        (princ)
    )
  
    ; turn CMDECHO off 
    (setvar "CMDECHO" 0)
  
    ; getting ACAD object and active document for use with (vl-startundomark) and (vl-endundomark)
    (setq acadObj (vlax-get-acad-object))
    (setq doc (vla-get-ActiveDocument acadObj))

    ; misc. obstructions offset vars
    (setq miscOffset 4) ; 4 inch misc. obstructions offset 
    (setq miscOSLayer "PV VENTS SKYLIGHTS ROOF DRAINS") ; layer of misc. obstructions offset
  
    ; mech. obstructions offset vars
    (setq mechOffset 6) ; 6 inch mech. obstructions offset 
    (setq mechOSLayer "PV MECH EQUIP SETBACK") ; layer of misc. obstructions offset
  
    ; get current layer, color, lineweight, linetype to change back to after command   ;;;;;;;;;;;;;;; method for getting current color, lweight/style
    ; maybe could get current color by accessing last made entity (might have issues if entlast doesn't work for a new drawing session)
    ; (setq cLayer (getvar "CLAYER"))   ;;;;;;;;;;;; change depending on final offset method
    ; (princ cLayer)

    ;; get ent data tester: (entget (car (entsel)))

    
    ; processing selecton set
    ; if currently active (implied) selection set:
    (if (ssget "_I")
        ; then filter ss to only allow LINE, LWPOLYLINE, ARC
        (setq ss (ssget "_I" '((0 . "LINE,LWPOLYLINE,ARC"))))
      
        ; else, prompt user for selection set
        (progn
            (setq 
                pt1 (getpoint "\nSpecify first corner: ")
                pt2 (getcorner pt1 "\nSpecify opposite corner: ")
            )
            (setq ss (ssget "_C" pt1 pt2 '((0 . "LINE,LWPOLYLINE,ARC"))))
        )
    )

    ; (setq setByLayerMode (getvar "SETBYLAYERMODE")) ; get SETBYLAYERMODE default
    (setvar "SETBYLAYERMODE" 7) ; set color, linetype, lineweight to "BYLAYER"
    (command-s "_.SETBYLAYER" ss "" "_YES" "_NO") ; set all entity styles to "BYLAYER", excluding blocks 
        ; (note "._" ensures command works in non-English versions of ACAD and in case command was redefined)
    ; (setvar "SETBYLAYERMODE" setByLayerMode) ; reset default
  
    ; start joinSegments undo mark
    ; (vla-startundomark doc)
  
    ; (if (ssget "_I")
            
    ;         ; only allow LINE, LWPOLYLINE, ARC
    ;         (setq filteredSS (ssget "_I" '((0 . "LINE,LWPOLYLINE,ARC"))))
          
    ;         ; else, 
    ;         (setq filteredSS (ssget "_C" pt1 pt2 '((0 . "LINE,LWPOLYLINE,ARC"))))
    ; )
  
    ; join all unconnected entity groups into polylines
    
    ; (if filteredSS (joinSegments filteredSS))
    (joinSegments ss)
    
    
    ; end joinSegments undo mark
    ; (vla-endundomark doc)
    
    ; update selection set
    ; (if (ssget "_I")
    ;     (progn 
    ;         (setq ss (ssget "_C" pt1 pt2))
    ;         (princ "\nHERE!\n")
    ;     )
    ; )
    
    
    
    ; DEBUGGING - print length of selection set
    ; (princ
    ;     (strcat "\nSSLENGTH: "
    ;             (itoa (sslength ss))
    ;     )
    ; )

    ; loop through entities in selection set
    (setq ssnum 0)
    (repeat (sslength ss) 

        ; start individual offset undo mark
        ; (vla-startundomark doc)
      
        ; Get entity name and assoc list for each entity
        (setq ename (ssname ss ssnum))
        (setq entList (entget ename))
      
        ; DEBUGGING - Print ename of each entity in ss
        ; (princ "\nEname:\n")
        ; (princ ename)
        
        ; DEBUGGING - Print elist of each entity in ss
        ; (princ "\nEntity:\n")
        ; (princ entList)

        ; if entity is on "PV Misc Obstructions" layer and is CIRCLE/LWPOLYLINE, offset it
        (offsetHandler entList "PV Misc Obstructions" miscOffset miscOSLayer)
      
        ; if entity is on "PV Mechanical Obstructions" layer and is CIRCLE/LWPOLYLINE
        (offsetHandler entList "PV Mechanical Obstructions" mechOffset mechOSLayer)

        ; end individual offset undo mark
        ; (vla-endundomark doc)
      
        ; increment ssnum
        (setq ssnum (1+ ssnum))
      )

      ; set all of selection set to "BYLAYER" styles
      ; (setq ss (ssget "_C" pt1 pt2)) ; update ss
      ; (setq setByLayerMode (getvar "SETBYLAYERMODE")) ; get SETBYLAYERMODE default
      ; (setvar "SETBYLAYERMODE" 7) ; set color, linetype, lineweight to "BYLAYER"
      ; (command-s "_.SETBYLAYER" ss "" "_YES" "_NO") ; set all entity styles to "BYLAYER", excluding blocks 
      ;     ; (note "._" ensures command works in non-English versions of ACAD and in case command was redefined)
      ; (setvar "SETBYLAYERMODE" setByLayerMode) ; reset default

      ; turn CMDECHO back on 
      (setvar "CMDECHO" 1)

      ; exit quietly
      (princ)
    )



    ;;; HELPER FUNCTIONS ;;;

    ; OFFSETHANDLER - checks that entity is on correct layer and is CIRCLE/LWPOLYLINE, then offsets
    (defun offsetHandler (entList entLayer osDist osLayer / entEname)

        ; VARLIST
        ;; INPUTS
        ;;; entList - offset entity definition (ASSOC LIST)
        ;;; entLayer - correct entity layer of entity to offset (STR)
        ;;; osDist - amount to offset by (INT)
        ;;; osLayer - layer of offset entity (STR)
        ;; LOCAL VARS
        ;;; entEname - entity name of entity to offset (ENAME)
        
      
        ; get ename of entity
        (setq entEname (cdr (car entList)))
      
        ; if entity is on correct layer and is CIRCLE/LWPOLYLINE, offset
        (if 
            (and 
                (equal 
                    (cdr (assoc '8 entList))
                    entLayer
                )
                (or 
                    (equal 
                        (cdr (assoc '0 entList))
                        "CIRCLE"
                    )
                    (equal
                        (cdr (assoc '0 entList))
                        "LWPOLYLINE"
                    )
                )
            )
            
            ; offset entity (if error in offset, run offsetOuterError func)
            (progn 
                  (setq errObject (vl-catch-all-apply 'offsetOuter 
                                                    (list entEname osDist osLayer)
                                )
                  )
                
                  (if (vl-catch-all-error-p errObject)
                      (offsetOuterError entEname osDist osLayer)
                  )
            )
        )
      
    )

    ; OFFSETOUTERERROR - for handling error of inner offset on entity too small, offsets given polyline or circle entity by given amount and on given layer & color
    (defun offsetOuterError (eName osDist osLayer / offsetEList offsetEName)
      
        ; VARLIST
        ;; INPUTS
        ;;; eName - entity name of entity to offset (ENAME)
        ;;; osDist - amount to offset by (INT)
        ;;; osLayer - offset layer (STR)        
        ;; LOCAL VARS
        ;;; offsetEList - offset entity definition (ASSOC LIST)
      
        ; error handling version if vla-offset attempts to inner-offset an entity too small (offset wouldn't fit inside entity)
        ; convert entity name to vla-object, then offset by negative osDist amount 
        (vla-offset (vlax-ename->vla-object eName) (- osDist))
      
        ; get offset assoc list
        (setq offsetEList (entget (entlast)))
      
        ; change offset layer
        (setq offsetEList (subst (cons '8 osLayer) 
                                 (assoc '8 offsetEList)
                                 offsetEList
                          )
        )
        (entmod offsetEList)
      
        ; get offset ename
        (setq offsetEName (cdr (car offsetEList)))
      
        ; ; change offset color to "BYLAYER"
        ; (command-s "CHPROP" offsetEName "" "_COLOR" "BYLAYER" "")

        
    )

    ; OFFSETOUTER - offsets given polyline or circle entity by given amount and on given layer & color
    (defun offsetOuter (eName osDist osLayer / originalArea offsetEName offsetArea offsetEList) 

        ; VARLIST
        ;; INPUTS
        ;;; eName - entity name of entity to offset (ENAME)
        ;;; osDist - amount to offset by (INT)
        ;;; osLayer - offset layer (STR)        
        ;; LOCAL VARS
        ;;; originalArea - area of entity to offset (REAL)
        ;;; offsetEName - entity name of offset entity (ENAME)
        ;;; offsetArea - area offset entity (REAL)
        ;;; offsetEList - offset entity definition (ASSOC LIST)
      
        ; inspired by Kent Cooper's offset subroutine (comparing offset area with entity area): https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/offset-multiple-objects-at-once/m-p/8172189/highlight/true#M372175

        ; convert entity name to vla-object, then offset by osDist amount
        (vla-offset (vlax-ename->vla-object eName) osDist)
      
        ; get area of original entity
        ;; NOTE: For open entities, vla-get-area draws line between 2 unaligned points
        ;;;;;;;; If points are aligned, vla-get-area assumes rectangle
        ;;;;;;;; Algorithm should still work though
        (setq originalArea (vla-get-area (vlax-ename->vla-object eName)))
      
        ; get area of offset
        (setq offsetEName (entlast))
        (setq offsetArea (vla-get-area (vlax-ename->vla-object offsetEName)))

        ; compare area of offset to area of original, delete and redo offset if offset area is smaller
        (if (< offsetArea originalArea) 
            (progn
                (entdel offsetEName)
                (vla-offset (vlax-ename->vla-object eName) (- osDist))
            )
        )

        ; get new offset assoc list
        (setq offsetEList (entget (entlast)))
      
        ; change offset layer
        (setq offsetEList (subst (cons '8 osLayer) 
                                 (assoc '8 offsetEList)
                                 offsetEList
                          )
        )
        (entmod offsetEList)
      
        ; ; change offset color to "BYLAYER"
        ; (command-s "CHPROP" offsetEName "" "_COLOR" "BYLAYER" "")
        
    )

    ; JOINSEGMENTS - joins groups of polylines, lines, arcs together into single polylines (works best if touching entity groups are on different layers)
    (defun joinSegments (ss / ) 

        ; VARLIST
        ;; INPUTS
        ;;; ss - input selection set of any type (SEL SET)
        ;; LOCAL VARS - NONE

        ; join all segments into polylines
        (setvar "PEDITACCEPT" 1)
      
        
      
        
      
        ; using PEDIT command to join all entity groups into polylines
        (command "_.PEDIT" "_MULTIPLE" filteredSS "" "_JOIN" "" "")
        ; (command "_.JOIN" ss "")
    )


; last statement to display (quietly loading)
(princ)

 

 

layerLoad.lsp (loaded to startup suite):

 

; command to load and save to defaults (if necessary) PV Vents/Misc Obstructions & PV Mech Obstructions
; could add support for customized display styles vs plot styles

; layerLoad - auto-loads "PV MECHANICAL OBSTRUCTIONS" and "PV VENTS SKYLIGHTS ROOF DRAINS OBSTRUCTIONS" layers

; turn off CMDECHO (stops commands from being printing to command line)
(setvar "CMDECHO" 0)

; load "PV Mechanical Obstructions" and "PV Misc Obstructions"
(setq layernames "PV Mechanical Obstructions,PV Misc Obstructions")

; NOTE: COLOR: 7 (black on white background, white on black background), LTYPE: CONTINUOUS, LWEIGHT: DEFAULT, TRANSPARENCY: 0 are defaults
(command "_.LAYER" "_NEW" layernames "")

; release LAYERNAMES from memory
(setq layernames nil)

; set turn CMDECHO back on 
(setvar "CMDECHO" 1)

; exit quietly 
(princ)

 

 

OFFSETAUTO needs to be able to work with all the entities in the drawing aside from the MTEXT, and it should work both when a user selects one, multiple, or zero (error handling) entities, with the selection happening either before using the OFFSETAUTO command or after when the function prompts for a selection set. (I know there are issues with circles as the code now stands, but that's part of what I'm trying to work out). The code should not make any changes to the already existing entities aside from joining them. Right now, I'm getting an "invalid selection" error for both an implied selection set and one created via the function prompts.

 

Message 8 of 8


@Jonathan_Bell82GXG wrote:

.... The code should not make any changes to the already existing entities aside from joining them. ....


As for that, I assumed otherwise from this line in the original:

(setq ss (ssget "_C" pt1 pt2)) ; update ss

Using the same selection area, without filtering the selection at all, would find all the source things as well as the new ones, and it then goes into the ByLayer setting operation on everything in that set.

 

But if that's now commented out....  I suspect the easiest thing would be to collect the Offset-result objects as you go -- make an initially empty selection set with (ssadd), and after each successful Offset, use (ssadd) again to put (entlast) into that set.

Kent Cooper, AIA

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report