You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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::Tool to manage user input events
  • Sketchup::InputPoint to capture click positions
  • The view's draw method 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 draw method 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_length automatically 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 (the offset([1,1,0], 2) part) to change where the text starts relative to the second point.
  • Modify colors and line width in the draw method to match the native cotation tool's styling.
  • Add support for different measurement planes or axis-aligned measurements if needed.

内容的提问来源于stack exchange,提问作者user1803095

火山引擎 最新活动