Animations and the Undo Stack with Transforms

I decided it might be cool to animate the opening and closing of (sliding) doors. Here is a snippet of code that opens a door, its actually very simple, I’m just moving the door in incremental steps :

@Model_operation = 'Open Door'

if @Animeoption_db == 'YES'

		@model1.start_operation(@Model_operation, true, true, false)

		view = @model1.active_view
		steps = 10.0
		cycles = 0
		stepsize = transx/steps
									
		anim_timer = UI.start_timer(0.02, true) { 

			trans1 =  Geom::Transformation.new([stepsize, 0, 0])
 			door.transform! trans1

			view.refresh
			cycles += 1

			if cycles >= steps
					UI.stop_timer(anim_timer)
			end
	
		}
else
		@model1.start_operation(@Model_operation, true, false, false)
		trans1 =  Geom::Transformation.new([transx, 0, 0])
 		door.transform! trans1
end

@model1.commit_operation

I’ve tried setting the various parameters of the start_operation method but no combination seems to work. I consistently get an undo stack full of move commands (ie. my step sizes). Maybe this isn’t possible or maybe I am just missing something.

2 Likes

As you can see the non-animated option just makes the translation in one transform so no issues there.

Should I just use a simple for or while loop instead of going to all the trouble with the timer business. The problem I see with that is that the animation will no longer be visible, it will happen too fast.

I’m kind of new to this kind of thing, having never really tried this before so I’m a little unsure on what is the best path forward.

It does seem to work pretty good with the code listed above, just the issue with the stack filling up…

versus the non-animated option:

After mucking around with the code for another hour or so this is what I came up with. It seems a bit clunky to me but it seems to work:

@Model_operation = 'Open Door'

if @Animeoption_db == 'YES'

  view = @model1.active_view
  steps = 10.0
  cycles = 0
  stepsize = transx/steps
  flag3 = false
									
  anim_timer = UI.start_timer(0.02, true) { 

    @model1.start_operation(@Model_operation, true, false, flag3)

    trans1 =  Geom::Transformation.new([stepsize, 0, 0])
    door.transform! trans1

    view.refresh
    cycles += 1
    flag3 = true

    if cycles >= steps
      wall_group.set_attribute libstate, opening_group_name, open_angle
      @model1.commit_operation
      UI.stop_timer(anim_timer)
    else
      @model1.commit_operation
    end
	
  }
else
  @model1.start_operation(@Model_operation, true, false, false)

  trans1 =  Geom::Transformation.new([transx, 0, 0])
  door.transform! trans1

  wall_group.set_attribute libstate, opening_group_name, open_angle

  @model1.commit_operation
end
1 Like

You are.

The API has the abstract Animation class for things like this.

I tried the move method and it gave me some strange results. For some reason it also translated in the Z as well as the X.

Also I actually do want the transformations to be added to the stack just not individually, so in for that reason alone the move method will probably not work.

So far the only thing that seems to work reliably is the last iteration of my code above.

Then you need to start the operation (a normal one with the flag3 set to false) on only the first transform. Thereafter each successive transform would need to have the flag3 set true so all the operations are appended together.

Also, it is not necessary to recreate a transformation object in every iteration.
A single transformation based upon a vector, created before a loop, can be used for each iteration.

1 Like

I just realized that with my transformation, your right it can be created once prior to the loop since it itself is not changing over the entire course.

1 Like

That is because the transform method uses the transformation incrementally, while the move method replaces the existing transformation with the argument.

The equivalent is to:

door.move!  trans1 * door.transformation
2 Likes

I use move for all the incremental moves, then prior to the final move, put the component back at the original location, and the do a single transformation to the final position. It happens fast enough that you can’t see it, and leaves one item on the undo stack.

tr = @inst.transformation
@inst.move!(@original_transformation)
@model.start_operation('Move', true)
@inst.transformation = tr

... a bunch of other code

@model.commit_operation

1 Like

Interesting way to handle the problem. I figured there was always more than one to skin this cat.