Script With Lisp Skips (say 5 times fast !)

Script With Lisp Skips (say 5 times fast !)

loren_routh
Enthusiast Enthusiast
1,613 Views
13 Replies
Message 1 of 14

Script With Lisp Skips (say 5 times fast !)

loren_routh
Enthusiast
Enthusiast

Hello,

I am trying to create a script that contains a lisp based on one that selects the largest and smallest polyline. I changed it to only select the largest mpolygon, then delete it. The original inspiration is here (thanks to @Kent1Cooper

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/lisp-to-select-the-biggest-poyline/m...

 

The lisp executes fine, but when I try to continue with an explode command, it does NOT delete the largest mpolygon and goes on to explode into polylines.  The end result I am looking for is just regular lines with no duplicates, overlaps, etc.


Here is what I have now.  It works until the commented-out section:

 

-XREF D *
-LAYER SET LNK_SPC_UA

-LAYER OFF "Q_TXT_SPC,LNK_DOOR_IDEN,LNK_FLR,DEFPOINTS,0"

(defun getlen (ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
(foreach pl (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
  (cond
    ((not shortest) (setq shortest pl longest pl))
    ((> (getlen pl) (getlen longest)) (setq longest pl))
  ); cond
); foreach
(setq extremes (ssadd longest))
(sssetfirst extremes)
(command "_.Erase" extremes "")
(setvar "qaflags" 17)
;;;(command "explode" "all" "")
;;;(command "explode" "all" "")
;;;(setvar "qaflags" 0)
;;;
;;;-OVERKILL
;;;ALL
;;;
;;;T
;;;Y
;;;E
;;;Y

 

 Any help is appreciated.  Using AutoCAD 2021
Thanks, L

0 Likes
Accepted solutions (1)
1,614 Views
13 Replies
Replies (13)
Message 2 of 14

Kent1Cooper
Consultant
Consultant

I don't immediately see any reason that it shouldn't work.  But it seems to me you don't need the 'extremes' selection set, if it contains only one thing and you're going to Erase it immediately.  The Erase command will take an entity name -- it doesn't need to be a selection set variable.  I think you could replace this much:

(setq extremes (ssadd longest))
(sssetfirst extremes)
(command "_.Erase" extremes "")

 with just this:

(command "_.Erase" longest "")

[which may not solve the other problem].

 

I'm always a little leery of mixing complex AutoLisp functions into Scripts.  Simple things like (getvar) may be fine, but not all AutoLisp functions can be used in command macros and Scripts, and I don't know where the limit is [nor do I know whether that can be the problem here].  Could you do it entirely as a defined command via AutoLisp, instead of as a Script?

 

But if it's a Script, I think [without testing] that you can skip messing with QAFLAGS if you do the Exploding "straight out" instead of inside AutoLisp (command) functions -- I believe it's only inside those that Explode can't work on more than one thing at a time without changing QAFLAGS.  Try eliminating the Erasing in a (command) function above, and the QAFLAGS settings, and replacing all the above stuff and this much:

(command "explode" "all" "")
(command "explode" "all" "")

with direct command-line Erase and Explode commands:

 

_.ERASE !longest

{blank line}

_.EXPLODE ALL

{blank line}

_.EXPLODE ALL

{blank line}

Kent Cooper, AIA
0 Likes
Message 3 of 14

loren_routh
Enthusiast
Enthusiast

Hi @Kent1Cooper 

Well, the simplification of the lisp worked in isolation, including:

(command "_.Erase" longest "")

And the direct commands also worked, but still got the same behavior when run with the explode command(s).  It didn't matter whether the "Erase" was lisp or direct command.  It always skipped the "Erase" and went to the "Explode" no matter how many permutations of spaces, or enters.

 

I agree it's not the best to combine lisp and script in one file (even though they say you can).  Tried to make GETLEN a command, but it gave an error:

Del_Big_MPError.PNG

 

Here is the Call Stack just in case:

 

<1> :ERROR-BREAK (Unknown Source:0)
[2] (GETLEN <Entity name: 1fe6dac3970>) (Unknown Source:0)
[3] (FOREACH ...) (Unknown Source:0)
[4] (#<USUBR @000001f660cad1d8 -top->) (c:\Users\Del_Big_MP.lsp:5)
<5> :TOP-COMMAND (Unknown Source:0)
<6> :CALLBACK-ENTRY (Unknown Source:0)
[7] (C:VLDEBUG) (Unknown Source:0)
<8> :CALLBACK-ENTRY (Unknown Source:0)
<9> :ARQ-SUBR-CALLBACK (Unknown Source:0)

 

In AutoCAD itself when I entered the command, it returned:

 Command: GETLEN
; error: too few arguments

If that issue can be solved, then we are (theoretically) home free.  So close!

What do you think?  I am at the "Cobble and Hack" level, which only gets me so far.  Always willing to learn though.

 

Thanks for your help,

Loren

 

 

 

 

0 Likes
Message 4 of 14

Kent1Cooper
Consultant
Consultant

For one thing, (getlen) is not a command, but a function that takes an argument.  If it were

  (defun C:getlen...

it would be a Command you can type in at the command line, but as a function with an argument, the use of it needs to be in parentheses along with an entity name as the argument:

  (getlen entityname)

 

I have a guess possibility of a source of the problem, or part of it.  A disadvantage of using something with (setq) involved but not within a defined command is that you can't localize variables.  In a command definition, you would have:
  (defun C:Whatever (/ ent pl shortest longest) ....

and that list following the / would be localized variable names, which would make them disappear when the command finished.  But without that, the variables remain.  So if it has been run before, then there's an entity name stored in the 'shortest' variable still around for the next run.  That entity won't exist any more if the first run was successful, but its entity name would still be in the variable.  That would throw off the length comparisons.

 

To avoid that [if that's the trouble -- no promises], try adding this line before the (foreach) function:

  (setq shortest nil longest nil)

Kent Cooper, AIA
0 Likes
Message 5 of 14

loren_routh
Enthusiast
Enthusiast

Still having trouble. 

This, by itself, works fine:

(defun getlen(ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
(setq shortest nil longest nil)
(foreach pl (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
  (cond
    ((not shortest) (setq shortest pl longest pl))
    ((> (getlen pl) (getlen longest)) (setq longest pl))
  ); cond
); foreach
(command "_.Erase" longest "")

 

In the script it works if nothing goes after it.  Once you add  _.EXPLODE , it has the same behavior, skipping the _.Erase longest.  Both using the command version and this one:

-XREF D *
-LAYER SET LNK_SPC_UA

-LAYER OFF "Q_TXT_SPC,LNK_DOOR_IDEN,LNK_FLR,DEFPOINTS,0"

(defun getlen (ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
(setq shortest nil longest nil)
(foreach pl (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
(cond
((not shortest) (setq shortest pl longest pl))
((> (getlen pl) (getlen longest)) (setq longest pl))
  ); cond
); foreach
(command "_.Erase" longest "")
_.EXPLODE ALL

;;;_.EXPLODE ALL
;;;
;;;-OVERKILL
;;;ALL
;;;
;;;T
;;;Y
;;;E
;;;Y

 Adding blanks has no effect other than calling the previous function (-LAYER):

Del_Big_MPErrorLA.PNG

To be clear, it deleted the longest, but then stopped .

 

Had no luck with making a command either:

(defun c:getlen(/ ent pl shortest longest) (vla-get-perimeter (vlax-ename->vla-object ent)))
(setq shortest nil longest nil)
(foreach pl (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
  (cond
    ((not shortest) (setq shortest pl longest pl))
    ((> (getlen pl) (getlen longest)) (setq longest pl))
  ); cond
); foreach
(command "_.Erase" longest "")

Returned:   ; error: no function definition: GETLEN

 

If I can get it to work as a command, great. 

Otherwise maybe do .NET, VB or...Python instead?     This routine needs to happen regardless.

 

Thank you for your time,

Loren

 

0 Likes
Message 6 of 14

Kent1Cooper
Consultant
Consultant

@loren_routh wrote:

....

Had no luck with making a command either:

(defun c:getlen(/ ent pl shortest longest) (vla-get-perimeter (vlax-ename->vla-object ent)))
(setq shortest nil longest nil)
(foreach pl (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
  (cond
    ((not shortest) (setq shortest pl longest pl))
    ((> (getlen pl) (getlen longest)) (setq longest pl))
  ); cond
); foreach
(command "_.Erase" longest "")

Returned:   ; error: no function definition: GETLEN

....


I have no idea why adding the Exploding would make it skip the Erasing.  As for the above, you still need the (getlen) function as a non-command, since it is called for in the length comparison.  The C: command should be called something else, and include that function definition.  And if all done with AutoLisp, the QAFLAGS thing re-enters the picture [though I don't know whether 17 is the right value -- I just kept it from your original].  [Also, in your circumstances, you don't need the 'shortest' object found.]  Try this:

(defun C:ELEE ; = Erase Longest, Explode Everything
  (/ getlen longest); localized variables [including function definition]
  (defun getlen (ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
  (foreach pl
    (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
    (cond
      ((not longest) (setq longest pl))
      ((> (getlen pl) (getlen longest)) (setq longest pl))
    ); cond
  ); foreach
  (setvar "qaflags" 17)
  (command
    "_.Erase" longest ""
    "_.explode" "all" ""
    "_.explode" "all" ""
  ); command
  (setvar "qaflags" 0)
); defun

One thing I recall is that when QAFLAGS is not set to allow Exploding more than one thing at once, Explode in a (command) function takes an entity name and does not require completing the selection with the typical Enter "".  I don't know whether the "" should also be omitted from the Explode commands in this situation [with QAFLAGS changed], but if this doesn't work, try it without those.

 

Ultimately, if this works, *error* handling should be added, to ensure that QAFLAGS gets reset if anything goes wrong.

Kent Cooper, AIA
0 Likes
Message 7 of 14

loren_routh
Enthusiast
Enthusiast

The ELEE command executes, but the end result is the same as previous (mpolygons exploded but longest remains). 

 

I noticed a few things that may be clues to figuring this out:

  • When stepping through undo, you can see it erase the longest mpolygon.  It seems to put back the longest right before exploding.
  • When taking out the "" in each EXPLODE and also the _Erase longest:

 #1

 "_.Erase" longest ""
"_.explode" "all" ""
"_.explode" "all"          Ends with exploded lines selected.  Longest put back before being exploded.

 

#2

"_.Erase" longest ""
"_.explode" "all"
"_.explode" "all" ""     Ends with longest erased and one EXPLODE executed, but longest returns as soon as you hit enter or escape!

Here the text window:

Command: ELEE
_.Erase
Select objects: 1 found

Select objects:
Command: _.explode
Select objects: all 440 found
1 was not able to be exploded.

Select objects: _.explode

*Invalid selection*
Expects a point or Window/Last/Crossing/BOX/ALL/Fence/WPolygon/CPolygon/Group/Add/Remove/Multiple/Previous/Undo/AUto/SIngle
; error: Function cancelled

 

 #3

"_.Erase" longest ""
"_.explode" "all"
"_.explode" "all"    Same as #2

 

#4

"_.Erase" longest 
"_.explode" "all" ""
"_.explode" "all" ""   Same as #2. Oh well

 

 

re:  QAFLAGS, I got that from here: 

 visual-lisp-autolisp-and-general/explode-all-does-not-work-in-script

It also references this page, but doesn't specifically show QAFLAGS 17: 

 https://www.manusoft.com/resources/acadexposed/sysvars.html 

 

Don't know what else to say but, this is maddening!  Can we escalate this?   Would track down Jim Quanci himself if I thought he could solve it.  You have done a lot already (and I learned a few things) so I am willing to do any legwork or research to solve this.

 

Again, thanks for your time and happy holidays,

 

Loren

 

 

0 Likes
Message 8 of 14

Kent1Cooper
Consultant
Consultant

Does it work if, instead of this:

  (command "_.erase" longest "")

you do this instead?

  (entdel longest)

 

Kent Cooper, AIA
0 Likes
Message 9 of 14

loren_routh
Enthusiast
Enthusiast

Here is what I am running:

(defun C:ELEE ; = Erase Longest, Explode Everything
  (/ getlen longest); localized variables [including function definition]
  (defun getlen (ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
  (foreach pl
    (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
    (cond
      ((not longest) (setq longest pl))
      ((> (getlen pl) (getlen longest)) (setq longest pl))
    ); cond
  ); foreach
  (setvar "qaflags" 17)
  (command
    (entdel longest)
    "_.explode" "all" ""
    "_.explode" "all" ""
  ); command
  (setvar "qaflags" 0)
); def

 

Slightly different behavior but same end result.  See >>>note <<<:

Command: ELEE
<Entity name: 46729A90>
>>>>Script stops here and looks done (no pickbox), but if you click anywhere on the model space, it rolls back the (entdel longest) and explodes everything.<<<<<<<<
Command:
ELEE
Unknown command "ELEE".  Press F1 for help.

Command: _.explode
Select objects: all 326 found
1 was not able to be exploded.

Select objects:
Command: _.explode
Select objects: all 1174 found
1015 were not able to be exploded.

Select objects:
Command: 0

 

I tried deleting a few  ""   but no effect.  Also tried within a script:

-XREF D *
-LAYER SET LNK_SPC_UA

-LAYER OFF "Q_TXT_SPC,LNK_DOOR_IDEN,LNK_FLR,DEFPOINTS,0"

ELEE
_.OVERKILL
ALL
T
Y
E
Y

 

Once again the Explode messed everything up, see note<<<<:

Command: _SCRIPT
Enter script file name <C:\Users\AZ0052.04.scr>: "C:\Users\CAD_Prep_LNK_SPACE_UA MPOLY2.scr"

Command: -XREF
Enter an option [?/Bind/Detach/Path/pathType/Unload/Reload/Overlay/Attach] <Attach>: D
Enter xref name(s) to detach: *

Command: -LAYER
Current layer:  "0"
Enter an option [?/Make/Set/New/Rename/ON/OFF/Color/Ltype/LWeight/TRansparency/MATerial/Plot/Freeze/Thaw/LOck/Unlock/stAte/Description/rEconcile/Xref]: SET
Enter layer name to make current or <select object>: LNK_SPC_UA
Enter an option [?/Make/Set/New/Rename/ON/OFF/Color/Ltype/LWeight/TRansparency/MATerial/Plot/Freeze/Thaw/LOck/Unlock/stAte/Description/rEconcile/Xref]:

Command: -LAYER
Current layer:  "LNK_SPC_UA"
Enter an option [?/Make/Set/New/Rename/ON/OFF/Color/Ltype/LWeight/TRansparency/MATerial/Plot/Freeze/Thaw/LOck/Unlock/stAte/Description/rEconcile/Xref]: OFF
Enter name list of layer(s) to turn off or <select objects>: "Q_TXT_SPC,LNK_DOOR_IDEN,LNK_FLR,DEFPOINTS,0"
Enter an option [?/Make/Set/New/Rename/ON/OFF/Color/Ltype/LWeight/TRansparency/MATerial/Plot/Freeze/Thaw/LOck/Unlock/stAte/Description/rEconcile/Xref]:

Command: ELEE
<Entity name: 36584A90>

Command: _.OVERKILL

Select objects: _.explode  <<<<this showed up late

*Invalid selection*
Expects a point or Window/Last/Crossing/BOX/ALL/Fence/WPolygon/CPolygon/Group/Add/Remove/Multiple/Previous/Undo/AUto/SIngle
; error: Function cancelled

 

0 Likes
Message 10 of 14

Kent1Cooper
Consultant
Consultant

@loren_routh wrote:

Here is what I am running:

....
  (command
    (entdel longest)
    "_.explode" "all" ""
    "_.explode" "all" ""
  ); command
....

....


I should have been clearer....  That (entdel longest) shouldn't be in place of the Erase part within that (command) function, only in place of it if it were in its own (command) function as in some earlier attempts.  That is, pull it out of the command function and put it before that.

....
  (entdel longest)
  (command
    "_.explode" "all" ""
    "_.explode" "all" ""
  ); command
....

Does that help?

Kent Cooper, AIA
0 Likes
Message 11 of 14

loren_routh
Enthusiast
Enthusiast

Yes, I tried that as well, same result (explode w/o deleting longest):

(defun C:ELEE ; = Erase Longest, Explode Everything
  (/ getlen longest); localized variables [including function definition]
  (defun getlen (ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
  (foreach pl
    (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
    (cond
      ((not longest) (setq longest pl))
      ((> (getlen pl) (getlen longest)) (setq longest pl))
    ); cond
  ); foreach
  (setvar "qaflags" 17)
  (entdel longest)
  (command
    "_.explode" "all" ""
    "_.explode" "all" ""
  ); command
  (setvar "qaflags" 0)
); defun

 

0 Likes
Message 12 of 14

Kent1Cooper
Consultant
Consultant

Could it possibly have something to do with the particular QAFLAGS setting?  Since it's undocumented for us mere mortals, we can't look up what a value of 17 means in Help for System Variables.  Maybe someone else out there knows.  But I'm inclined to suggest trying, say, 1 instead, just to see whether it makes any difference.

Kent Cooper, AIA
0 Likes
Message 13 of 14

loren_routh
Enthusiast
Enthusiast

I came across a post about that earlier:  

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/lisp-to-select-all-blocks-amp-explod... 

 

No difference, I'm afraid.  You may still be right about qaflags.  Who knows?

 

The fact that it deletes and then restores the mpolygon makes me wonder if _.explode all  inadvertently retrieves everything in the database, even deleted objects?

 

What about vla-?  I have no clue

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/vla-explode/m-p/1724955/highlight/tr... 

0 Likes
Message 14 of 14

loren_routh
Enthusiast
Enthusiast
Accepted solution

Hi @Kent1Cooper ,

Wanted to post this before I forgot.   Apparently, the cause of the reanimated lines was due to another layer with identical geometry, but yellow line color (which happened to be the perimeter boundary).  It was turned OFF, but not FROZEN.  My guess is when "_.explode all"  ran, it brought that yellow layer into the current one.   That shouldn't happen, should it?    At any rate, it's a xmas miracle !!!

 

Here is the script that works:

-XREF D *
-LAYER SET LNK_SPC_UA

-LAYER OFF "Q_TXT_SPC,LNK_DOOR_IDEN,LNK_FLR,DEFPOINTS,0"

-LAYER F "Q_TXT_SPC,LNK_DOOR_IDEN,LNK_FLR,DEFPOINTS,0"

(defun getlen(ent) (vla-get-perimeter (vlax-ename->vla-object ent)))
(setq shortest nil longest nil)
(foreach pl (mapcar 'cadr (ssnamex (ssget "_X" '((0 . "MPOLYGON") (8 . "LNK_SPC_UA")))))
  (cond
    ((not shortest) (setq shortest pl longest pl))
    ((> (getlen pl) (getlen longest)) (setq longest pl))
  ); cond
); foreach
(command "_.Erase" longest "")
_.explode all

_.explode all

-OVERKILL ALL

T
Y
E
Y

save

 

Thanks again for working with me on this.  I bet you have gotten a few (hundred?) of these "in plain sight" problems.

Happy holidays!

 

Loren

 

0 Likes