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

Animating objects by turning layers on and off

15 REPLIES 15
SOLVED
Reply
Message 1 of 16
Anonymous
1350 Views, 15 Replies

Animating objects by turning layers on and off

I wrote this program a few years ago which simply turned a given set of layers on and off which gives the appearance of animation.  Basically I wrote a program which creates 20 layers with the names PPM_1, PPM_2, ...PPM_20 and grabs the blocks (which have a similar name) which are laid out in linear fashion and one by one puts the blocks on a unique layer, if there are more than 20 blocks it just repeats the cycle 'til they're all put on a layer.

 

Then I run another program which animates the layers simply by turning them on and off at a given speed and duration.

While running this program I used a screen capture utility to make a movie.  This all worked fine with acad 2007 but it doesn't with 2010.  Below is the area that worked with 2007 but not 2010.   When the program starts and all the PPM* layers are on, they will all turn off but none turn on.  Is this a buffer issue?  Any idea how to make them turn on while the programs' running?  Unfortunately, I unloaded 2007 a few months ago and I may end up putting it back on just for this reason.

 

      ;(command "_.layer" "off" "PPM*" "on" (strcat "PPM_" (itoa num)) "")

     or
      (command "_.layer" "off" "PPM*" "")
      (command "_.layer" "on" (strcat "PPM_" (itoa num)) "")

 

 

 

Thanks

15 REPLIES 15
Message 2 of 16
Anonymous
in reply to: Anonymous

I did a quick test with these routines to turn on and off 3 layers PPM_1 , 2 , 3 and it works fien on my AutoCAD 2011. Do you get any feedback in the text window when running this (my routines failed first because one of the 3 layers was the current layer) ?

 

 

 

(defun ton ( / )
 (command "-layer" "s" "0" "")
 (setq num 1)
 (while (>= 3 num)
  (command "_.layer" "on" (strcat "PPM_" (itoa num)) "")
  (setq num (1+ num))
 )
)

(defun tof ( / )
 (command "-layer" "s" "0" "")
 (setq num 1)
 (while (>= 3 num)
  (command "_.layer" "off" (strcat "PPM_" (itoa num)) "")
  (setq num (1+ num))
 )
)

Message 3 of 16
Anonymous
in reply to: Anonymous

No, the command line is blank while it's running, and if I change cmdecho to 1 that verifies that it is.  The current layer didn't matter.  Thanks for trying.

Message 4 of 16
pbejse
in reply to: Anonymous

Granting these conditions

Layers PPM_1 to PPM_20 are existing
Blocks with same name as layers  are existing

 

(defun c:test (/ Rolling num)
(defun Rolling (prcnt)
(repeat prcnt	
		(setq prcnt_1 (1+ prcnt))
		(prompt "\r|")(prompt "\r/")
		(prompt "\r|")(prompt "\r\\")
		(princ)
			)
      )
	(setq num 21)    
	(command "_.layer" "off" "PPM*" "")
		(repeat (1- num) 
		(command "_.layer" "_On" (strcat "PPM_" (itoa (setq num (1- num))))"")
		(rolling 1000)              
		    )
      )

 
The duration of the delay can be controlled  by prnct argument (rolling 1000)<---- this value

 

Limited testing

 

Hope this helps

 

 

 

Message 5 of 16
CADaSchtroumpf
in reply to: Anonymous

Hi,

 

A generic code what is work's with any layer's state.

I hope that can help you !

 

 

(defun eplerr (ch)
	(cond
		((eq ch "Function cancelled") nil)
		((eq ch "quit / exit abort") nil)
		((eq ch "console break") nil)
		(T (princ ch))
	)
	(command "_.undo" "_end")
	(if (<= sv_und 3) (command "_.undo" "_control" "_one"))
	(command "_.undo" "1")
	(setq *error* olderr)
	(setvar "expert" drap)	
	(setvar "cmdecho" 1)
	(princ)
)
(defun input-choice (list-of-strings flag / pointer key ll)
	(setq pointer 0 ll (length list-of-strings))
	(princ "\n<+/-> for choice; <Enter>/[Space] for exit!.")
	(print (nth pointer list-of-strings))
	(while (not (member (setq key (grread nil 2 1)) '((2 13) (2 32))))
		(cond
			((eq (cadr key) 43)
			       (setq pointer (rem (1+ pointer) ll))
			)
			((eq (cadr key) 45)
				(setq pointer (1- pointer))
				(if (< pointer 0) (setq pointer (+ ll pointer)))
			)
		)
		(command "_.-layer" "_off" "*" "_on" (nth pointer list-of-strings) "")
		(princ (strcat "\nSelect layer " (nth pointer list-of-strings)))
	)
	(if flag (setvar "clayer" (nth pointer list-of-strings)))
)
(defun c:examine_layer ( / curr_layer layer list_layers flag_stat_lay drap sv_und olderr flag_stat_lay)
	(setvar "cmdecho" 0)
	(setq drap (getvar "expert"))
	(setvar "expert" 5)
	(if (<= (setq sv_und (getvar "undoctl")) 3)
		(command "_.undo" "_control" "_all")
	)
	(command "_.undo" "_group")
	(setq olderr *error* *error* eplerr)
	(princ "\nCAUTION! Re-initialized layers's state")
	(command "_.-layer" "_thaw" "*" "_unlock" "*"  "_off" "*" "")
	(initget "Select Explorer")
	(if (eq (getkword "\nMode Select *DESTROYED* - Explorer+XRefs *NEUTRAL* [Select/Explorer]<Explorer>: ") "Select")
		(progn
			(setq flag_stat_lay T)
			(command "_.-layer" "_on" (getvar "clayer") "")
		)
		(progn
			(setq flag_stat_lay nil)
			(command "_.-layer" "_on" "0" "_set" "0" "")
		)
	)
	(setq
		curr_layer (getvar "clayer")
	  layer (tblnext "layer" t))
	(while layer
		(if (zerop (boole 1 (if flag_stat_lay 49 64) (cdr (assoc 70 layer))))
		     (setq list_layers (cons (cdr (assoc 2 layer)) list_layers))
		)
		(setq layer (tblnext "layer"))
	)
	(setq list_layers
		(append
			(member (getvar "clayer") list_layers)
			(reverse (cdr (member (getvar "clayer") (reverse list_layers))))
		)
	)
	(input-choice list_layers flag_stat_lay)
	(command "_.undo" "_end")
	(if (<= sv_und 3) (command "_.undo" "_control" "_one"))
	(if (not flag_stat_lay)
		(progn (princ "\n->Go back to the initial state <-")(command "_.undo" "1"))
	)
	(setq *error* olderr)
	(setvar "expert" drap)	
	(setvar "cmdecho" 1)
	(princ)
)

 

 

Message 6 of 16
Anonymous
in reply to: pbejse

thanks pbejse, that works tho' I had to adjust it slightly.  I moved the all layers off after (repeat (1- num).

 

(setq num 21)   
(repeat (1- num)

   (command "_.layer" "off" "PPM*" "")
   (command "_.layer" "_On" (strcat "PPM_" (itoa (setq num (1- num))))"")
   (rolling 1000)             

 

This is my code which I'll need to modify later, I'm tied up with something else right now.

 

(defun PartPathLoop ( / Cycles Duration i j num QtyLayers)
   (command "undo" "begin")
   (setq num 0 Cycles 0 QtyLayers 0)
   (initget "1 2 3 4 5 6 7 8 9 10")
   (setq Duration (atoi (getkword "\n Enter A Number For Duration: 1-10, 1 For Shortest, 10 For Longest: ")))
   (initget "1 2 3 4 5 6 7 8 9 10")
   (setq Speed (atoi (getkword "\n Enter A Number For Speed: 1-10, 1 For Fastest, 10 For Slowest: ")))
   (setq Speed (* 1000 (expt 2 Speed)))
   (while (< Cycles (* 50 (expt 2 Duration)))
      (setq i 0 j Speed)
      (while (< i j) (setq i (+ i 1)))
      (if (= num 0)
  (setq num (- QtyLayers 1))
  (setq num (- num 1))
      );endif
      ;(command "_.layer" "off" "PPM*" "on" (strcat "PPM_" (itoa num)) "")
      (command "_.layer" "off" "PPM*" "")
      (command "_.layer" "on" (strcat "PPM_" (itoa num)) "")
      (setq Cycles (+ Cycles 1))
   );wend
  (command "undo" "end")
);endPPL

(PartPathLoop)


  
;;; =1000*2^#                                  =50*2^#
;;;#    Speed                                Duration
;;;1     2,000 Fastest                      100 Shortest
;;;2     4,000                                   200
;;;3     8,000                                   400
;;;4    16,000                                  800
;;;5    32,000                               1,600
;;;6    64,000                               3,200
;;;7   128,000                              6,400
;;;8   256,000                            12,800
;;;9   512,000                            25,600
;;;10 1,024,000 Slowest           51,200 Longest

Message 7 of 16
pbejse
in reply to: Anonymous

You are welcome KimBurns

 

Moving "layers off" inside the repeat is a nice idea, I like it.

 

Glad i could help.

Cheers

Message 8 of 16
Kent1Cooper
in reply to: Anonymous

I wondered about some different ways of doing some of those things -- you may find some of them worthwhile, and not others.  Consider this:

 

(defun C:ANIM-PPM (/ lay laylist del cycles cmde script); = ANIMation of things on PPM* Layers
  (while (setq lay (cdadr (tblnext "layer" (not lay))))

    (if (= (substr lay 1 3) "PPM")
      (setq laylist (cons lay laylist)); list of all PPM* Layers
    ); end if
  ); end while
  (while
    (not
      (and
        (setq del (getint "\nSpeed [1=fastest, 10=slowest]: "))
        (< 0 del 11); within range
      ); end and
    ); end not
    (prompt "\nOutside of allowable range --")
  ); end while
  (initget 7); no Enter, no 0, no negative
  (setq
    cycles (getint "Number of animation cycles: ")
    laylist (vl-sort laylist '<); Layer names in order of end number
    cmde (getvar 'cmdecho)
  ); end setq
  (setvar 'cmdecho 0)
  (command "_.layer" "_set" "0" "_off" "PPM*" ""); start condition
  (repeat cycles
    (foreach lay laylist
      (command
        "_.layer" "_off" "PPM*" "_on" lay ""
        "_.delay" (* del 10); <--- adjust 10 multiplier basis as desired
      ); end command
    ); end foreach
  ); end repeat
  (setvar 'cmdecho cmde)
  (princ)
); end defun
 

The first part makes a list of all Layer names starting with "PPM".  That means there's no need to have a particular number of them built in to the drawing or the routine [it could be different in different drawings], and you don't need to count through that number in the animation, so you don't need to increment a variable for that, nor construct Layer names to turn on using the ""PPM_" prefix and the number variable that needs to be converted to text -- the (foreach) later on just steps through for you.

 

The next part, setting the 'del' variable for the speed, is maybe no better than your approach.  I was just trying something that didn't require the long (initget) to spell out all the possibilities, nor the conversion of the User's input from text to a number.

 

The 'cycles' variable is just an alternative approach to how long to run it, which seemed to me more direct and simpler to work with, using a simple (repeat) function, than the duration approach, but again, not necessarily better.

 

Finally, the DELAY command is described in Help as being for use in Scripts, but it does also work in Lisp (command) functions, at least for me back here in 2004 and for others in the Discussion Group history.  Your other way of causing a frame-to-frame delay is a kind of "workaround" approach, basically built to force the computer to waste some time, but Delay is very straightforward.

Kent Cooper, AIA
Message 9 of 16
stevesfr
in reply to: Kent1Cooper

Ok, how about we turn on all layers when finished ?

Message 10 of 16
Anonymous
in reply to: Kent1Cooper

Kent, thanks for your input, your program works great!!.  Your code is certainly more intelligent, compact, and flexible than mine.  Nice job.

 

 

  

Message 11 of 16
Kent1Cooper
in reply to: stevesfr


@stevesfr wrote:

Ok, how about we turn on all layers when finished ?


That would be very easy to do:

 

....

    ); end foreach
  ); end repeat

  (command "_.layer" "_on" "*" "")
  (setvar 'cmdecho cmde)
  (princ)
); end defun
 

But that may or may not be wanted.  A user might start the routine when some but not all other Layers, unrelated to the routine, are turned off, and want to return to that condition.  Saving a Layer State is iffy, depending on what options it's set to look at.  But since the routine doesn't change any objects other than the display of them, or add or remove any objects, putting an UNDO Mark at the beginning and an UNDO Back at the end would take it back to whatever the state of things was:

 

(defun C:ANIM-PPM (/ lay laylist del cycles cmde script); = ANIMation of things on PPM* Layers

  (command "_.undo" "_mark")
  (while (setq lay (cdadr (tblnext "layer" (not lay))))

....

  ); end repeat

  (command "_.undo" "_back")
  (setvar 'cmdecho cmde)
  (princ)
); end defun

Kent Cooper, AIA
Message 12 of 16
stevesfr
in reply to: Kent1Cooper

Kent, thanks for the reply and the options to think about.

Steve

Message 13 of 16
Anonymous
in reply to: Kent1Cooper

Kent, I did make one small change, I commented out the vl-sort.  If you have more than 10 layers than the sort order ends of being incorrect (see below) which makes the parts (blocks) appear to jump around.  So as long as the layers were created in numerical order they will be acquired in that order (at least from my observation). Now I know we could force a sort on the list of strings and ensure it comes out right, but the only thing I can think of is to separate the numbers from the PPM_ , convert them, sort them, convert them, than put 'em back together again.

 

 

("PPM_0" "PPM_1" "PPM_10" "PPM_11" "PPM_12" "PPM_13" "PPM_14" "PPM_15" "PPM_16" "PPM_17" "PPM_18" "PPM_19" "PPM_2" "PPM_20" "PPM_21" "PPM_22" "PPM_23" "PPM_24" "PPM_25" "PPM_26" "PPM_27" "PPM_28" "PPM_29" "PPM_3" "PPM_30" "PPM_31" "PPM_32" "PPM_33" "PPM_34" "PPM_35" "PPM_36" "PPM_37" "PPM_38" "PPM_39" "PPM_4" "PPM_5" "PPM_6" "PPM_7" "PPM_8" "PPM_9")

 

(setq
    cycles (getint "Number of animation cycles: ")
    ;;;laylist (vl-sort laylist '<); Layer names in order of end number
    cmde (getvar 'cmdecho)
  ); end setq

Message 14 of 16
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

Kent, I did make one small change, I commented out the vl-sort.  If you have more than 10 layers than the sort order ends of being incorrect .... So as long as the layers were created in numerical order they will be acquired in that order (at least from my observation). ....


Ah, yes....  The things you don't think of when you try a simple test -- I did it with only five Layers.  I agree, creation order is how (tblnext) steps through things.

 

EDIT 1:  If you might not always make them strictly in order, you could use double-digit number endings for all of them, e.g. PPM_00, PPM_01, etc., and keep the sorting function.

 

EDIT 2:  The way it makes the list of Layer names, they'll be in reverse order from the order of creation, so if that matters, you'll want to (reverse) the list, rather than (vl-sort) it.

Kent Cooper, AIA
Message 15 of 16
Kent1Cooper
in reply to: Kent1Cooper


@Kent1Cooper wrote:
....  If you might not always make them strictly in order, you could use double-digit number endings for all of them, e.g. PPM_00, PPM_01, etc., and keep the sorting function.

....


Or, you could sort them more intelligently, to account for the variable-numbers-of-digits Layer-name-ending possibility, for instance like this [see also other notes following]:

 

(defun C:ANIM-PPM (/ *error* lay laylist del cycles cmde script); = ANIMation of things on PPM* Layers
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break"))
      (princ (strcat "\nError: " errmsg))
    ); end if
;    (command "_.undo" "_back"); didn't work, somehow
    (command "_.undo" "_end" "_u")
    (setvar 'cmdecho cmde)
    (princ)
  ); end defun - *error*
;  (command "_.undo" "_mark"); didn't work, somehow
  (command "_.undo" "_begin")
  (setq cmde (getvar 'cmdecho))
  (while (setq lay (cdadr (tblnext "layer" (not lay))))
    (if (= (substr lay 1 3) "PPM")
      (setq laylist (cons lay laylist)); list of all PPM* Layers
    ); end if
  ); end while
  (while
    (not
      (and
        (setq del (getint "\nSpeed [1=fastest, 10=slowest]: "))
        (< 0 del 11); within range
      ); end and
    ); end not
    (prompt "\nOutside of allowable range --")
  ); end while
  (initget 7); no Enter, no 0, no negative
  (setq
    cycles (getint "Number of animation cycles: ")
;    laylist (vl-sort laylist '<); Layer names in too-simple order of end number
;    laylist (reverse laylist); Layer names in order of creation
    laylist
      (vl-sort
; Layer names in intelligent order of end number, regardless of creation order
        laylist
        '(lambda (x y) (< (atoi (substr x 5)) (atoi (substr y 5))))
          ; depends on "PPM_" [or other 4-character] beginning for all names, and integer ending
      ); end vl-sort & laylist
  ); end setq
  (setvar 'cmdecho 0)
  (command "_.layer" "_set" "0" "_off" "PPM*" ""); start condition
  (repeat cycles
    (foreach lay laylist
      (command
        "_.layer" "_off" "PPM*" "_on" lay ""
        "_.delay" (* del 10); <--- adjust 10 multiplier basis as desired
      ); end command
    ); end foreach
  ); end repeat
;  (command "_.undo" "_back"); didn't work, somehow
  (command "_.undo" "_end" "_u")
  (setvar 'cmdecho cmde)
  (princ)
); end defun
 

I incorporated the return of the initial Layer conditions as discussed with stevesfr, but for some reason I can't figure out, using Undo Mark and Undo Back didn't work -- it told me I needed to enter Undo End to go back further, even though I hadn't used Undo Begin anywhere.  If anyone can identify why it wouldn't work with the commented-out lines, I'd be interested.  It may also be affected by the AutoCAD version [I'm back in 2004].  But I found a way around it, using Begin/End and another U to undo the grouped operations.

 

And I put in error handling, so that if, for instance, someone has a long one going and decides they don't want to see it through to the end, they can hit Escape to get out of it, and it will still return the Layer situation as it was when they started.

Kent Cooper, AIA
Message 16 of 16
pbejse
in reply to: Kent1Cooper

 


@Kent1Cooper wrote:
      (command
        "_.layer" "_off" "PPM*" "_on" lay ""
        "_.delay" (* del 10); <--- adjust 10 multiplier basis as desired
      ); end command
   
_delay, thats brilliant Kent

 

 

 

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

Post to forums  

Forma Design Contest


Autodesk Design & Make Report