lisp to select newest entities

I have a short lisp that copies a selection set to the current layer. (Is there a built-in Bricscad command for this?)

I have to create two global selection sets using (ssget "x"),

one before and one after the copy command, and then subtract the first from the second in order to select the newest entities created by the copy command (more than one entity).

(defun c:kl( ) 
(setq #s (ssget))
(command "undo""begin")
(setvar "cmdecho" 0)
(setq #old (ssget "x"))
(command "copy" #s "" "0,0" "0,0")
(setq #new (ssget "x"))
(foreach &o (%sslist #old)
(ssdel &o #new)
)
(command "chprop" #new "" "la" (getvar "CLAYER") "")
(setvar "cmdecho" 1)
(command "undo""end")
(command "redraw")
(setq #s nil #old nil #new nil)
)

(defun %sslist (#s / $s @n)
(if (eq 'PICKSET (type #s))
(progn
(setq @n 0
$s nil
)
(repeat (sslength #s)
(setq $s (cons (ssname #s @n) $s)
@n (1+ @n)
)
)
)
)
$s
)

In Autocad R14 and 2000 I don't notice much of a delay, but in Bricscad V10 it's very slow, in a medium-sized drawing, several seconds at least.

 

I can't help thinking that there must be a more elegant method of selecting the new entities created by a copy command or the like (mirror, array, etc.)

where more than one new object has been created.

 

(It would be ideal if it could be one of the inbuilt selection methods, like "P" for previous or "L" for last, call it "N" for new)

(Now that seems like a good idea, so I think I'll make a support request for this feature)

 

I thought of simply running a (while ...)  loop that would copy each entity one by one from the selection set,

then using (entlast) after each copy command in order to build up the selection set I need (with error trapping, of course).

It would probably be faster in Bricscad, but it seems like an awful kludge. I'm sure there must be a better way.

 

(I know I could select "Previous",  but I want the new objects on top.

Hm, one thing I could do, is I could copy-in-place, change the "previous" selection set's layer, then copy-in-place again, then erase the "previous" selection set.

The new objects would then be on top, but they wouldn't be available to the "previous" selection method. heck.)

(Oh, and I don't trust draworder)

 

I hope I'm not being too difficult to understand  :-)

Comments

  • There was a suggestion over at The Swamp for something similar, posted by Keith, which should work.

    Before running copy execute

    (setq startentity (entlast))

    Run your copy command then run

    (setq sset (ssadd))
    (setq nextent (entnext startentity))
    (while (/= nil nextent)
     (setq sset (ssadd nextent sset))
     (setq nextent (entnext nextent))
    )

    I have not tried this in Bricscad, but it is a much simpler approach.

  • Good find Martin, you could probably embed that in an event

    (setq *startentity* nil)
    (defun getNewEnts (/ nextent)
      (setq sset (ssadd))
      (setq nextent (entnext *startentity*))
      (while (/= nil nextent)
        (setq sset (ssadd nextent sset))
        (setq nextent (entnext nextent))
      )
      sset
    )

    (defun load__command_reactors ()
      (vl-load-com)
      (if _reactor_start
        (vlr-remove _reactor_start)
      )
      (setq _reactor_start
         (vlr-command-reactor nil
           '((:vlr-commandWillStart . start_command)))
      )
      (princ "\nLoading command reactors")
    )
    (load__command_reactors)
    (defun start_command (calling-reactor start_command_info / the_command_start)
      (setq Current_Layer_setting (getvar "CLAYER")
     the_command_start (car start_command_info)
      )
      (cond
        ((= the_command_start "COPY")
          (setq *startentity* (entlast))
        )
        ((= the_command_start "MIRROR")
          (setq *startentity* (entlast))
        )
      )
      (princ)
    )
  • oops without the CLAYER   : 0

  • *facepalm*

    do (entlast) first! that's it!

    Sometimes I overcomplicate myself.

    Thanks a lot!

     

    I bet I could  make some kind of reactor to implement the "New" selection set option.

    It just has to call (setq &last (entlast)) when a command starts.

    Then run your defun afterwards to set the new stuff as "previous".

     

    (I'm just starting to mess around with reactors, watch me blow up my computer. :-)

  • I found this information on a German Forum (http://ww3.cad.de/foren/ubb/Forum145/HTML/002916.shtml#000002):
    Should the last element in the drawing be an insert with attributes (or an old-style polyline) then (entnext (entlast)) would find the first attribute belonging to the insert (or the first vertex belonging to the polyline). Adding these entities to your selection set would be undesirable. Using the code from the link will solve this.

  • You might want to review this thread before using entlast / entnext...

    http://www.bricscad.com/common/support/forumthread.jsp?id=10780

    Greg

  • Thanks!

    Right, I know I'll have to do some error trapping to avoid catching subentities of complex objects.

    That business with other layouts, though, looks difficult.

    I'll try to build a good subroutine for this that I can use generally.

    I'll post it here when I can.

  • A reply I got from the support people suggested I use copybase, then pasteblock, then explode to get the same functionality without messing around with (entnext).

    Here's my new lisp:

    (defun c:kl( ) 
    (setq #s (ssget)
    &last (entlast)
    )
    (command "undo" "begin")
    (setvar "cmdecho" 0)
    (command "_copybase" "0,0" #s "")
    (command "pasteblock" "0,0")
    (if (not (eq &last (setq &b (entlast))))(progn
    (setq *b (cdr (assoc 2 (entget &b))))
    (command "explode" &b)
    (command "purge" "b" *b "n")
    (command "chprop" "p" "" "la" (getvar "CLAYER") "")
    ))
    (setvar "cmdecho" 1)
    (command "undo" "end")
    (setq #s nil)
    (princ)
    )

    It seems to work okay.

    (I still use (entlast) to check that the copy, etc. worked)

  • Here's another lisp that uses this trick, it matches properties from another entity to the copied set:

    (defun c:mk( )
    (setq &s (entsel "\n from: "))
    (princ "\n to: ")
    (setq #s (ssget)
    &last (entlast)
    )
    (command "undo" "begin")
    (setvar "cmdecho" 0)
    (command "_copybase" "0,0" #s "")
    (command "pasteblock" "0,0")
    (if (not (eq &last (setq &b (entlast))))(progn
    (setq *b (cdr (assoc 2 (entget &b))))
    (command "explode" &b)
    (command "purge" "b" *b "n")
    (command "matchprop" &s "p" "")
    ))
    (setvar "cmdecho" 1)
    (command "undo" "end")
    (setq #s nil)
    (princ)
    )

    Oh, and I replied to Daniel Marcotte below:

    "I bet I could  make some kind of reactor ..."

    I'd forgotten to scroll down in your reply, I see that you already built a reactor. Thanks!

This discussion has been closed.