Ruby+SketchUp技术咨询:如何通过API实现手动标注工具的测量功能
Replicating the French "Cotation" Measurement Tool with SketchUp Ruby API
Hey there! I get that trying to mirror that manual "cotation" tool behavior via the Ruby API can feel tricky at first—SketchUp's docs don't always spell out every UI tool's exact implementation. Let's break this down step by step to build a custom tool that lets you click points, preview measurements, and drag the text label into place.
Core Approach
The key here is creating a custom SketchUp Tool (since we need to handle mouse clicks, drags, and real-time previews). We'll use:
Sketchup::Toolto manage user input eventsSketchup::InputPointto capture click positions- The view's
drawmethod to render real-time previews of the measurement line and text - Model entities to create permanent geometry and text once the user finishes the operation
Full Code Example
class CotationTool < Sketchup::Tool def initialize @ip1 = Sketchup::InputPoint.new @ip2 = Sketchup::InputPoint.new @text_position = nil @dragging_text = false @distance = 0.0 end # Define cursor for different tool states def getCursor(_flags, _x, _y, _view) if @dragging_text UI::CURSOR_MOVE elsif @ip1.valid? && !@ip2.valid? UI::CURSOR_CROSSHAIR else UI::CURSOR_PICK end end # Handle left mouse button down def onLButtonDown(flags, x, y, view) if !@ip1.valid? # First click: capture first measurement point @ip1.pick(view, x, y) view.invalidate elsif !@ip2.valid? # Second click: capture second point, enter text drag mode @ip2.pick(view, x, y) if @ip2.valid? @distance = Geom::Vector3d.distance(@ip1.position, @ip2.position) # Initialize text position near the second point @text_position = @ip2.position.offset([1,1,0], 2) @dragging_text = true view.invalidate end elsif @dragging_text # Final click: place the text and create permanent entities create_permanent_cotation(view.model) # Reset tool state for next use reset_tool view.invalidate end end # Handle mouse movement for previews and dragging def onMouseMove(flags, x, y, view) if @ip1.valid? && !@ip2.valid? # Preview the second point and measurement line @ip2.pick(view, x, y) @distance = Geom::Vector3d.distance(@ip1.position, @ip2.position) if @ip2.valid? view.invalidate elsif @dragging_text # Update text position while dragging pick_helper = view.pick_helper pick_helper.do_pick(x, y) # Get a point on the same plane as the measurement plane = [@ip1.position, @ip1.position.vector_to(@ip2.position).cross(Z_AXIS)] @text_position = pick_helper.intersect_plane(plane) view.invalidate end end # Draw real-time previews def draw(view) # Draw measurement line if we have two valid points if @ip1.valid? && @ip2.valid? view.drawing_color = 'blue' view.line_width = 2 view.draw_line(@ip1.position, @ip2.position) end # Draw measurement text if we have a distance and position if @distance > 0 && @text_position view.drawing_color = 'red' # Format distance with current model units formatted_distance = Sketchup.format_length(@distance) view.draw_text(@text_position, formatted_distance) end end # Handle ESC to cancel the tool def onCancel(_reason, _view) reset_tool end private def create_permanent_cotation(model) return unless @ip1.valid? && @ip2.valid? && @text_position model.start_operation("Cotation Measurement", true) # Create the measurement line model.entities.add_line(@ip1.position, @ip2.position) # Create the text label formatted_distance = Sketchup.format_length(@distance) model.entities.add_text(formatted_distance, @text_position) model.commit_operation end def reset_tool @ip1.clear @ip2.clear @text_position = nil @dragging_text = false @distance = 0.0 end end # Add the tool to a menu for easy access unless file_loaded?(__FILE__) menu = UI.menu("Plugins").add_submenu("Cotation Tool") menu.add_item("Start Cotation") { Sketchup.active_model.select_tool(CotationTool.new) } file_loaded(__FILE__) end
Key Details Explained
- Tool State Management: We use instance variables (
@ip1,@ip2,@dragging_text) to track where the user is in the workflow (selecting first point, second point, dragging text). - Real-Time Previews: The
drawmethod runs every time the view refreshes, so we can render the temporary line and text as the user moves their mouse. - Unit Formatting:
Sketchup.format_lengthautomatically uses the model's current unit settings (meters, millimeters, inches, etc.), matching the native cotation tool's behavior. - Text Dragging: After selecting the two measurement points, we switch to a drag mode where the user can position the text label anywhere on the same plane as the measurement line.
Customization Tips
- Adjust the text offset in
onLButtonDown(theoffset([1,1,0], 2)part) to change where the text starts relative to the second point. - Modify colors and line width in the
drawmethod to match the native cotation tool's styling. - Add support for different measurement planes or axis-aligned measurements if needed.
内容的提问来源于stack exchange,提问作者user1803095




