Author Topic: Selection by Handle greater than  (Read 7192 times)

0 Members and 1 Guest are viewing this topic.

qwrtz

  • Mosquito
  • Posts: 19
Selection by Handle greater than
« on: April 24, 2015, 12:06:46 PM »
I want to execute a command within a lisp routine, and then select all entities created by the command.

I know I can get the handle of the last entity created before the command:
Code - Auto/Visual Lisp: [Select]
  1. (setq Handle1 (cdr (assoc 5 (entget (entlast)))))

After the command I should be able to use (ssget "X") to select all entities with a handle greater than Handle1, but I've tried a lot of things and can't find code that works.

Can anyone help me? Logical operators always confuse me, and I'm not that good with filter lists either, but I think this would probably be very simple for many people on this forum.

ronjonp

  • Needs a day job
  • Posts: 7339
Re: Selection by Handle greater than
« Reply #1 on: April 24, 2015, 12:10:02 PM »
I want to execute a command within a lisp routine, and then select all entities created by the command.
...
You could just keep track of the entities you're creating in your routine, then you don't have to select them again?
BTW .. welcome to TheSwamp :)

Windows 10 x64 - AutoCAD /C3D 2020

Custom Build PC

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Selection by Handle greater than
« Reply #2 on: April 24, 2015, 12:25:58 PM »
Code: [Select]
(defun _SSAfter ( ename / ss d e )

    (if (eq 'ename (type ename))
        (progn
            (setq
                ss (ssadd)
                e  (entnext ename)
            )
            (while e
                (if
                    (and
                        (setq d (entget e))
                        (null (member (cdr (assoc 0 data)) '("VERTEX" "ATTRIB" "SEQEND")))
                    )
                    (ssadd e ss)
                )
                (setq e (entnext e))
            )
            (if
                (and
                    (eq 'pickset (type ss))
                    (< 0 (sslength ss))
                )
                ss
            )
        )
    )
)

Syntax:

(setq ss (_ssafter some_ename))

Edit: Revised to harvest only prime entities.
« Last Edit: April 25, 2015, 12:30:16 PM by MP »
Engineering Technologist CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.com http://cadanalyst.slack.com http://linkedin.com/in/cadanalyst

Lee Mac

  • Seagull
  • Posts: 12549
  • London, England
Re: Selection by Handle greater than
« Reply #3 on: April 24, 2015, 12:32:21 PM »
As noted in the documentation, you cannot use an ssget filter list to filter for the DXF handle group 5.

Instead, I would suggest retrieving the last entity in the database before issuing your command, and then stepping through all entities created by the command by using entnext to step through the drawing database one entity at a time.

You can retrieve the last entity added to the database using the following function:
Code - Auto/Visual Lisp: [Select]
  1. (defun lastent ( / rtn tmp )
  2.     (setq rtn (entlast))
  3.     (while (setq tmp (entnext rtn)) (setq rtn tmp))
  4.     rtn
  5. )

You can then step over the entities created by the command in the following way:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ( / ent new )
  2.     (setq ent (lastent)
  3.           new (ssadd)
  4.     )
  5.     (command
  6.         "_.line"   "_non" '(0 -1) "_non" '(0 1) ""
  7.         "_.line"   "_non" '(-1 0) "_non" '(1 0) ""
  8.         "_.circle" "_non" '(0  0) 0.5
  9.     )
  10.     (while (setq ent (entnext ent))
  11.         (ssadd ent new)
  12.     )
  13.     (sssetfirst nil new)
  14.     (princ)
  15. )

In before MP :P

Lee Mac

  • Seagull
  • Posts: 12549
  • London, England
Re: Selection by Handle greater than
« Reply #4 on: April 24, 2015, 12:36:26 PM »
Further to the above, to account for subentities (excluding them from the resulting set):
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ( / ent new )
  2.     (setq ent (lastent)
  3.           new (ssadd)
  4.     )
  5.     (command
  6.         "_.line"   "_non" '(0 -1) "_non" '(0 1) ""
  7.         "_.line"   "_non" '(-1 0) "_non" '(1 0) ""
  8.         "_.circle" "_non" '(0  0) 0.5
  9.     )
  10.     (while (setq ent (entnext ent))
  11.         (ssadd ent new)
  12.         (if (= 1 (cdr (assoc 66 (entget ent))))
  13.             (while (/= "SEQEND" (cdr (assoc 0 (entget ent))))
  14.                 (setq ent (entnext ent))
  15.             )
  16.         )
  17.     )
  18.     (sssetfirst nil new)
  19.     (princ)
  20. )

David Bethel

  • Swamp Rat
  • Posts: 656
Re: Selection by Handle greater than
« Reply #5 on: April 24, 2015, 01:16:41 PM »
I don't think you can use handles in a ( ssget ) filter.  I'll look

From 2004 autolisp help -> ssget

Quote
An entity filter list is an association list that uses DXF group codes in the same format as a list returned by entget. (See the DXF Reference for a list of group codes.) The ssget function recognizes all group codes except entity names (group 1), handles (group 5), and xdata codes (groups greater than 1000). If an invalid group code is used in a filterlist, it is ignored by ssget.
« Last Edit: April 24, 2015, 01:25:03 PM by David Bethel »
R12 Dos - A2K

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: Selection by Handle greater than
« Reply #6 on: April 24, 2015, 01:20:22 PM »
Alternatively, create a selection set before and after modification; the delta between the two will be whatever was added.  But first priority would be for actively logging entities as they were created.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

roy_043

  • Water Moccasin
  • Posts: 1879
  • BricsCAD 18
Re: Selection by Handle greater than
« Reply #7 on: April 24, 2015, 05:21:24 PM »
@ MP:
You are probably using (entget e) in your code to check if the entity has not been erased.
It is my understanding that (entnext) does not find erased entities. So this check is not required.

qwrtz

  • Mosquito
  • Posts: 19
Re: Selection by Handle greater than
« Reply #8 on: April 24, 2015, 05:46:04 PM »
Thanks, everyone, for all the replies at lightning speed. I'm amazed that MP and Lee Mac read my post, designed a solution, wrote the code, tested it, and posted it, all in 15 or 20 minutes. I worked on it all day and got nowhere.

I should have clarified in the original post that I didn't want to write a routine that creates specific new entities. I wanted the routine to execute a normal COPY or MIRROR command (with the selection set and displacement or mirror line specified at run time), except that when it's done all the newly created entities are selected for use in the next command.

I was able to do that by calling MP's routine. I still don't understand how that routine works, but it does what I need and it'll be a big help to me. Again, thanks very much.

Code - Auto/Visual Lisp: [Select]
  1. (defun c:mpcopy ()
  2. (setq EntName1 (cdr (assoc -1 (entget (entlast)))))
  3. (setvar "COPYMODE" 1)
  4. (setq ss1 (ssget))
  5. (command "COPY" ss1 "" pause pause)
  6. (setvar "COPYMODE" 0)
  7. (setq ss1 (_ssafter EntName1))
  8. (sssetfirst nil ss1)
  9. )

Code - Auto/Visual Lisp: [Select]
  1. (defun c:mpmirror ()
  2. (setq EntName1 (cdr (assoc -1 (entget (entlast)))))
  3. (princ "Select objects to be mirrored...")
  4. (setq ss1 (ssget) )
  5. (setq s1 (getvar "orthomode") )
  6. (setvar "orthomode" 1)
  7. (setq p1 (getpoint "Start of mirror line...") )
  8. (setq p2 (getpoint p1 "...end of mirror line...") )
  9. (setvar "orthomode" s1)
  10. (initget "Yes No")
  11. (setq s2 (getkword "Delete the original? <N>") )
  12. (if (not s2) (setq s2 "no") )
  13. (command "Mirror" ss1 "" p1 p2 s2 )
  14. (setq ss1 (_ssafter EntName1))
  15. (sssetfirst nil ss1)
  16. )

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Selection by Handle greater than
« Reply #9 on: April 25, 2015, 09:57:55 AM »
You're welcome, glad it helped. On the "fast response", I wrote that function 10 or more years ago. Your original post was rather serendipitous as I happened to reference said function not 5 minutes before your inquiry.
Engineering Technologist CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.com http://cadanalyst.slack.com http://linkedin.com/in/cadanalyst

Lee Mac

  • Seagull
  • Posts: 12549
  • London, England
Re: Selection by Handle greater than
« Reply #10 on: April 25, 2015, 10:49:43 AM »
You're most welcome qwrtz  :-)

A few points to note:

Since the value of DXF Group -1 is a pointer to the entity itself, observe that:
Code - Auto/Visual Lisp: [Select]
  1. (cdr (assoc -1 (entget (entlast))))

Is equivalent to just:
Code - Auto/Visual Lisp: [Select]



Be careful when stepping through the entities following a call to (entlast) since, if the entity returned by (entlast) is a complex entity (such as an attributed block or 3D polyline), the subsequent calls to (entnext) will return the subentities which follow the parent entity (i.e. the attribute references or 3D polyline vertices respectively). For this reason, I suggested the lastent function that I posted above, which will return the last entity in the drawing database for which a call to (entnext) will return nil.

The same logic applies to MP's _SSAfter function: note that this function will attempt to add subentities to the returned selection set; since it is not possible to add the terminating SEQEND entity to a selection set, the ssadd function will consequently return nil, causing the ss variable to become nil within the while loop, and so the function will always return nil if complex entities have been added to the database after the entity supplied to the function.



I should have clarified in the original post that I didn't want to write a routine that creates specific new entities. I wanted the routine to execute a normal COPY or MIRROR command (with the selection set and displacement or mirror line specified at run time), except that when it's done all the newly created entities are selected for use in the next command.

Perhaps my example was confusing since the example was creating entirely new objects, but please note that the same method may be applied to any command for which you want to obtain the set of all entities potentially created by the command, e.g.:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:lmcopy ( / cpm ent new sel )
  2.    
  3.     (if ;; If the following expression returns a non-nil value
  4.         ;; (i.e. if the user makes a valid selection)
  5.         (setq sel (ssget)) ;; Prompt the user for a selection
  6.         (progn
  7.            
  8.             (setq ent (lastent) ;; Retrieve the last entity added to the database
  9.                   new (ssadd)   ;; Create an empty selection set for the new entities
  10.                   cpm (getvar 'copymode) ;; Store the value of the COPYMODE sys var
  11.             ) ;; end setq
  12.            
  13.             (setvar 'copymode 1)
  14.             ;; Set the COPYMODE sys var as appropriate
  15.            
  16.             (command "_.copy" sel "" "\\" "\\") ;; Invoke the COPY command
  17.            
  18.             (setvar 'copymode cpm)
  19.             ;; Reset the COPYMODE sys var
  20.             ;; (always store/restore the original sys var value, don't assume that you know what that value should be)
  21.            
  22.             (while (setq ent (entnext ent)) ;; While there is another entity in the database
  23.                 (ssadd ent new) ;; Add it to the new selection set
  24.                
  25.                 ;; If subentities follow this entity
  26.                 (if (= 1 (cdr (assoc 66 (entget ent))))
  27.                    
  28.                     ;; Iterate over them until we reach the terminating SEQEND entity:
  29.                     (while (/= "SEQEND" (cdr (assoc 0 (entget ent))))
  30.                         (setq ent (entnext ent))
  31.                     ) ;; end while
  32.                 ) ;; end if
  33.             ) ;; end while
  34.  
  35.             ;; Highlight the new objects
  36.             (sssetfirst nil new)
  37.            
  38.         ) ;; end progn
  39.     ) ;; end if
  40.    
  41.     ;; Supress the return of the last evaluated expression
  42.     (princ)
  43. ) ;; end defun
  44.  
  45. (defun lastent ( / rtn tmp )
  46.     (setq rtn (entlast))
  47.     (while (setq tmp (entnext rtn)) (setq rtn tmp))
  48.     rtn
  49. )

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Selection by Handle greater than
« Reply #11 on: April 25, 2015, 11:48:34 AM »
Good eye and commentary regarding attempts to grab seqends. When I wrote that function it was to harvest entities created by flattening processes by reverse engineered dxb files or wmfin exploits (essentially all simple primitives). Revised function to harvest only primary entities. Thanks Lee.
Engineering Technologist CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.com http://cadanalyst.slack.com http://linkedin.com/in/cadanalyst

Lee Mac

  • Seagull
  • Posts: 12549
  • London, England
Re: Selection by Handle greater than
« Reply #12 on: April 25, 2015, 11:59:57 AM »
Good eye and commentary regarding attempts to grab seqends. When I wrote that function it was to harvest entities created by flattening processes by reverse engineered dxb files or wmfin exploits (essentially all simple primitives). Revised function to harvest only primary entities. Thanks Lee.

No worries - of course, there is no need for superfluous error checking if it doesn't befit the task  :-)

I like the clean solution to excluding subentities - perhaps ATTRIB should be added to the list?

Lee

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Selection by Handle greater than
« Reply #13 on: April 25, 2015, 12:12:21 PM »
Yep, attribs should be there, was in my brain when I started to do the mod, I blame my distracting cat, lol.
Engineering Technologist CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.com http://cadanalyst.slack.com http://linkedin.com/in/cadanalyst

qwrtz

  • Mosquito
  • Posts: 19
Re: Selection by Handle greater than
« Reply #14 on: April 25, 2015, 05:38:22 PM »
Lee Mac, thanks so much for the revised function, which does exactly what I want, and especially for the remarks included with it.

I tried to adapt it to make an equivalent Mirror command, but this always terminates with nothing selected. What did I do wrong?

Code - Auto/Visual Lisp: [Select]
  1. (defun c:lmMirror ( / otm ent new sel )
  2.  
  3.     (if ;; If the following expression returns a non-nil value
  4.         ;; (i.e. if the user makes a valid selection)
  5.         (setq sel (ssget)) ;; Prompt the user for a selection
  6.         (progn
  7.  
  8.             (setq ent (lastent) ;; Retrieve the last entity added to the database
  9.                   new (ssadd)   ;; Create an empty selection set for the new entities
  10.                   otm (getvar 'orthomode) ;; Store the value of the ORTHOMODE sys var
  11.             ) ;; end setq
  12.  
  13.             (setvar 'orthomode 1)
  14.             ;; Set the ORTHOMODE sys var as appropriate
  15.  
  16.             (command "_.mirror" sel "" "\\" "\\") ;; Invoke the MIRROR command
  17.  
  18.             (setvar 'orthomode otm)
  19.             ;; Reset the ORTHOMODE sys var
  20.             ;; (always store/restore the original sys var value, don't assume that you know what that value should be)
  21.  
  22.             (while (setq ent (entnext ent)) ;; While there is another entity in the database
  23.                 (ssadd ent new) ;; Add it to the new selection set
  24.  
  25.                 ;; If subentities follow this entity
  26.                 (if (= 1 (cdr (assoc 66 (entget ent))))
  27.  
  28.                     ;; Iterate over them until we reach the terminating SEQEND entity:
  29.                     (while (/= "SEQEND" (cdr (assoc 0 (entget ent))))
  30.                         (setq ent (entnext ent))
  31.                     ) ;; end while
  32.                 ) ;; end if
  33.             ) ;; end while
  34.  
  35.             ;; Highlight the new objects
  36.             (sssetfirst nil new)
  37.  
  38.         ) ;; end progn
  39.     ) ;; end if
  40.  
  41.     ;; Supress the return of the last evaluated expression
  42.     (princ)
  43. ) ;; end defun
  44.  

And I hate to be greedy, but there are a couple of things I still don't understand:

1.
....if the entity returned by (entlast) is a complex entity (such as an attributed block or 3D polyline), the subsequent calls to (entnext) will return the subentities which follow the parent entity (i.e. the attribute references or 3D polyline vertices respectively). For this reason, I suggested the lastent function that I posted above, which will return the last entity in the drawing database for which a call to (entnext) will return nil.
Does that mean that (lastent) returns the last non-complex entity? If so, what if there's a newer entity that is complex? What keeps that newer complex entity from being included in the final selection set? I see where you skip over the sub-entities, but where do you skip over a complex entity that's newer than the last non-complex entity?

2. What's that rtn all by itself at the end of the (lastent) function) It's not part of any expression other than the (defun) function, so I'm surprised it's even allowed in (defun sym ([arguments] [/ variables ...]) expr ...). And what does it do?