I’m trying to add in an animation into my tool as the final step before it creates some geometry. However I’m not even sure this is possible.
Here is a snippet of the code:
def draw(view)
@drawn = false
# Show the current input point
if( @ip.valid? && @ip.display? )
@ip.draw(view)
@drawn = true
end
case @state
when STATE_PICK_FINAL_WALL
puts "draw final flooring animation"
if @perim_face && @Validfloor
unless @drawnonce
view.line_width = 1
color1 = Sketchup::Color.new(0x66ffff)
color1.alpha = 85
view.drawing_color = color1
# view.draw(GL_POLYGON, @perim_pts)
puts "draw final flooring animation2"
# view = Sketchup.active_model.active_view
steps = 10.0
cycles = 0
stepsize = @Wallhgt/steps
floorz = @Wallhgt
anim_timer = UI.start_timer(0.02, true) {
# view.refresh
# view.invalidate
face_pts = []
for index in 0 ... @perim_pts.size
pti = @perim_pts[index].clone
face_pts[index] = [pti.x, pti.y, floorz]
end
view.draw(GL_POLYGON, face_pts)
cycles += 1
floorz = floorz - stepsize
if cycles >= steps
puts "step #{cycles} final"
UI.stop_timer(anim_timer)
end
puts "step #{cycles}"
}
@drawnonce = true
puts "final_calc"
self.calculate_obj
# Sketchup.active_model.select_tool(nil)
end
end
@drawn = true
end
Sorry the indentation got all messed up somehow.
The timer seems to run asynchronously so it kind of messes things up somehow. I want the animation to finish before if makes the final call to the method: calculate_obj
I have never tried to do anything this crazy within the draw method of a tool, so I’m completely out of my comfort zone here and beyond my experience and knowledge, I’m just kind of throwing mud at the wall right now and maybe something might “work”.
class AnimationTool
def initialize(perim_pts, wall_height)
@perim_pts = perim_pts
@Wallhgt = wall_height
@state = :pick_final_wall
@drawnonce = false
end
def activate
@cycles = 0
@floorz = @Wallhgt
@steps = 10.0
@stepsize = @Wallhgt / @steps
# Start the animation timer to trigger continuous drawing
@anim_timer = UI.start_timer(0.02, true) do
puts "Timer triggered, calling draw"
Sketchup.active_model.active_view.invalidate
end
end
def deactivate(view)
# Stop the animation timer when the tool is deactivated
puts "Deactivating tool and stopping timer"
UI.stop_timer(@anim_timer) if @anim_timer
end
def draw(view)
puts "Drawing called with current floor height: #{@floorz}"
# Set up colors and line width for the animation
view.line_width = 1
color1 = Sketchup::Color.new(0x66ffff)
color1.alpha = 85
view.drawing_color = color1
if @state == :pick_final_wall
# Temporarily draw the animated polygon face at the current level
face_pts = @perim_pts.map { |pti| [pti.x, pti.y, @floorz] }
view.draw(GL_POLYGON, face_pts)
puts "Temporary face drawn at height #{@floorz}"
@cycles += 1
@floorz -= @stepsize
puts "Cycle #{@cycles} completed, new floor height: #{@floorz}"
if @cycles >= @steps
puts "Animation complete after #{@cycles} cycles"
UI.stop_timer(@anim_timer)
add_final_floor_face # Add a single, final face after animation
@state = :done
Sketchup.active_model.select_tool(nil) # Automatically deactivate the tool
end
end
end
def add_final_floor_face
# Add a single floor face at the final level in the model
final_face_pts = @perim_pts.map { |pti| [pti.x, pti.y, 0] } # Floor at ground level
model = Sketchup.active_model
entities = model.active_entities
entities.add_face(final_face_pts)
puts "Final floor face created at ground level"
calculate_obj
end
def calculate_obj
# Placeholder method for final calculation
puts "Final calculation executed"
end
end
# Test setup: define perimeter points and wall height
perim_pts = [
Geom::Point3d.new(0, 0, 0),
Geom::Point3d.new(10, 0, 0),
Geom::Point3d.new(10, 10, 0),
Geom::Point3d.new(0, 10, 0)
]
wall_height = 10.0
# Create and activate the tool
tool = AnimationTool.new(perim_pts, wall_height)
Sketchup.active_model.select_tool(tool)
I was alternatively just going to move the animation outside of the tool and actually animate the geometry itself (ie. translate it) since I have a pretty good handle on how to do that already but now I want to give this a further try. I learn something new ever day.
You should have a look at the Sketchup::Animation abstract class and its nextFrame method. This is the standard way to perform animation within an interactive tool (or even without).
Basically,
to start an animation, you do: view.animation = self (i.e. the interactive tool). You can instead use a dedicated class object if you wish, as the Sketchup::Animation class is abstract. It just needs to have the method nextFrame(view) implemented.
Then implement a method nextFrame(view) in your tool where you move the camera and objects and use view.show_frame to refresh the view
to stop the animation, just do: view.animation = nil
As to why the original didn’t work, the proc being called via UI.start_timer() is not executing within the tool’s draw() method.
Class: Sketchup::View
Overview
This class contains methods to manipulate the current point of view of the model. The drawing methods here (draw_line, draw_polyline, etc) are meant to be invoked within a tool’s Tool.draw method. Calling them outside Tool.draw will have no effect.
Normally, in a tool, the animation of proposed geometry is linked to the onMouseMove callback. As the mouse moves, in the callback the inputpoint would be used to calculate proposed position of say a face, and view.invalidate() is called from the onMouseMove callback after the calculations, which in turn triggers the draw() method to show the proposed geometry outline.