How to lock inference when the inference line is pink?

def clear_lock_inference(view, ip1, ip2)
  direction = ip1.position.vector_to(ip2.position).normalize
  end_point_pos = ip2.position.offset(direction, 10000)

  start_ip = Sketchup::InputPoint.new(ip2.position)
  end_ip = Sketchup::InputPoint.new(end_point_pos)
  view.lock_inference(start_ip, end_ip)
  puts "locked: #{view.inference_locked?}"
end

The code above tries to lock the inference based on the current direction. This method calls when user presses Shift key. The puts value would be true when the current inference line is red or green, otherwise would be fasle even if the inference line is pink, and can not restrict the line direction when user moves mouse.

So why doese view.inference_locked? return false after view.lock_inference(start_ip, end_ip)?
How can I lock the line direction when the inference line to be pink?

I think ip2 needs to reference ip1, using either ip2.pick(view, x, y, ip1) or ip2.copy!(some_ip) where some_ip is picked with ip1 as reference.

Yes, but I already using ip2.pick(view, x, y, ip1) in onMove method.

The #lock_inference method …“with two arguments, it locks inference along an axis.”

That means the method can lock only if the desired direction parallel to one of the axes.

Thy something like this:

def my_lock_inference(view, direction, start_ip, end_ip)
  # record current axes
  orig_origin, orig_xaxis, orig_yaxis, orig_zaxis = view.model.axes.to_a
  
  # set the model axes to arbitrary, where one of the axes
  #  parallel to the desired lock direction
  view.model.axes.set(ORIGIN, *direction.axes)
  
  # now, you can lock the inference
  view.lock_inference(start_ip, end_ip)
  
  # set back the axes
  view.model.axes.set(orig_origin, orig_xaxis, orig_yaxis, orig_zaxis)
  
  # return the status
  status = view.inference_locked?
end

Yes, but in your code you’re calling:

not lock_inference(ip1, ip2).

That approach modifies the model axes, which changes the model state and may require wrapping in an operation. I think it’s unnecessary just to lock the direction.

clear_lock_inference method is called in onKeyDown method, ip2.pick(view, x, y, ip1) is called in onMouseMove method.

I see, thanks. I just want to create a tool like the original Line tool in Sketchup, the Line tool could lock the direction when the inference line color is pink.

Yes, once you create instance variables like @ip1 or @ip2, you can access them anywhere in the class.

Take a look at this quick demo tool I made with GPT:

class DemoLockInferenceTool
  def initialize
    @model = Sketchup.active_model
    @ip = Sketchup::InputPoint.new
    @ip1 = Sketchup::InputPoint.new
    @ip2 = Sketchup::InputPoint.new
    @state = 0
  end

  def activate
    @model.active_view.lock_inference 
  end

  def onMouseMove(flags, x, y, view)
    @ip.pick(view, x, y, @ip1)
    if @state == 0
      @ip1.copy!(@ip)
    else
      @ip2.copy!(@ip)
    end
    view.invalidate
  end

  def onLButtonDown(flags, x, y, view)
    if @state == 0
      @state = 1
    else
      Sketchup.active_model.active_entities.add_line(@ip1.position, @ip2.position)
      reset(view)
    end
    view.invalidate
  end

  def onKeyDown(key, repeat, flags, view)
    if @state == 1
      point = @ip1.position

      # Lock inference direction based on arrow key
      case key
      when VK_UP, VK_DOWN
        end_point = point.offset(@model.axes.zaxis)
        ip = Sketchup::InputPoint.new(end_point)
        view.lock_inference(ip, @ip1)
      when VK_RIGHT
        end_point = point.offset(@model.axes.xaxis)
        ip = Sketchup::InputPoint.new(end_point)
        view.lock_inference(ip, @ip1)
      when VK_LEFT
        end_point = point.offset(@model.axes.yaxis)
        ip = Sketchup::InputPoint.new(end_point)
        view.lock_inference(ip, @ip1)
      when CONSTRAIN_MODIFIER_KEY
        # Toggle lock/unlock
        if view.inference_locked?
          view.lock_inference
        elsif @ip2.valid?
          view.lock_inference(@ip2, @ip1)
        end
      end

      view.invalidate
    elsif key == CONSTRAIN_MODIFIER_KEY && @state == 0 && @ip1.valid?
      view.lock_inference(@ip1)
      view.invalidate
    end
  end

  def onKeyUp(key, repeat, flags, view)
    if key == CONSTRAIN_MODIFIER_KEY
      view.lock_inference # unlock
    end
  end

  def reset(view)
    @ip.clear
    @ip1.clear
    @ip2.clear
    @state = 0
    view.lock_inference # unlock
  end

  def draw(view)
    @ip.draw(view) if @ip.display?
    if @ip1.valid? && @ip.valid?
      view.line_width = view.inference_locked? ? 3 : 1
      view.set_color_from_line(@ip1, @ip)
      view.draw(GL_LINES, [@ip1.position, @ip.position])
    end
  end
end

# Activate the tool
Sketchup.active_model.select_tool(DemoLockInferenceTool.new)

You are right, change axes are only needed if you want to lock to any (an arbitrary) direction.

Here’s my solution:

def onMouseMove
  @ip2.pick(view, x, y, @ip1)
  if @shift
    pt1 = get_position(@ip2)
    pt2 = pt1.project_to_line(@current_line)
    @ip2 = Sketchup::InputPoint.new(pt2)
  end
end

def onKeyDown
  if (key == CONSTRAIN_MODIFIER_KEY && repeat == 1)
    view.lock_inference
    @shift = true
    @current_line = [@ip1.position, @ip1.position.vector_to(@ip2.position)] if @ip1.valid? && @ip2.valid?
  end
end

This solution could lock to any direction, but it also has a flaw: when Shift pressed, there’s no inference line color any more, it always black by default.

It is the responsibility of your tool to draw the colored axis line from @ip1 to the cursor within the tool’s draw() method.

You may want to look at eneroth’s mixin module in the following thread.

This lib does not support Parallel/Perpendicular lock, so it’s not I want, but thanks anyway.

You are right.

What I mean is that this method can not use set_color_from_line any more. And if want to set pink color when parallel or perpendicular some edges, maybe should write lots of codes.

WITHDRAWN ...

Not a lot more code. Something like this (not a working example.)
The onMouseMove callback would need to modify @pt2 if @ip1 was valid. (not shown)


  def activate
    @model = Sketchup.active_model
    @colors = get_tool_colors()
    @colors[:foreground]= @model.rendering_options["ForegroundColor"]
    reset()
  end

  def reset
    @ip1, @ip2, @pt1, @pt2 = nil
    @directional_inference = false
    @normal = nil
  end

  def get_tool_colors
    plugins = Sketchup.find_support_file("Plugins")
    filepath = File.join(File.dirname(plugins), "SharedPreferences.json")
    text = File.read(filepath) rescue nil
    require 'json' unless defined?(JSON)
    shared = text ? JSON.parse(text) : {}
    text = nil
    if shared
      prefs = shared["Shared for All Computers"]["Preferences"] rescue nil
    end
    if prefs
      # Use user's tool colors:
      colors = Hash[
        :x_axis, Sketchup::Color.new(*prefs["ColorX_RGB"].split),
        :y_axis, Sketchup::Color.new(*prefs["ColorY_RGB"].split),
        :z_axis, Sketchup::Color.new(*prefs["ColorZ_RGB"].split),
        :parallel, Sketchup::Color.new(*prefs["ColorParallelPerpendicular_RGB"].split),
        :tangent, Sketchup::Color.new(*prefs["ColorTangent_RGB"].split)
      ]
    else
      # Use default tool colors
      colors = Hash[
        :x_axis, 'red',
        :y_axis, 'green',
        :z_axis, 'blue',
        :parallel, 'magenta',
        :tangent, 'cyan'
      ]
    end
    return colors
  end


  def onKeyDown(key, repeat, flags, view)
    if key == VK_SHIFT
      # Set a boolean variable when SHIFT is clicked:
      @directional_inference = !@directional_inference
    end
  end

  # In one of the tool's methods:
  def onLButtonUp(flags, x, y, view)
    if @ip1.nil?
      @ip1 = view.inputpoint(x, y)
      if @ip1.degrees_of_freedom == 2 # on a face
        face = view.pick_helper(x,y).picked_face
        @normal = face.normal if face
      end
    else
      @ip2 = view.inputpoint(x, y, @ip1)
      @pt1, @pt2 = [@ip1.position, @ip2.position]
      @vector = @pt1.vector_to(@pt2)
      view.invalidate # calls draw() method
    end
  end

  # In the draw() method:
  def draw(view)
    if @directional_inference
      if [X_AXIS, Y_AXIS, Z_AXIS].any? { |axis| @vector.parallel?(axis) }
        view.set_color_from_line(@pt1, @pt2)
      elsif @normal && (@vector.parallel?(@normal) || @vector.perpendicular?(@normal))
        view.drawing_color = @colors[:parallel]
      else
        view.drawing_color = @colors[:foreground]
      end
      # draw the line:
      view.line_width= 3
      view.line_stipple= "" # solid
      view.draw_line(@pt1, @pt2)
    end
    #
    view.drawing_color = @colors[:foreground]
    ### Draw others stuff here
    #
  end

Just some ideas.

This solution does not act like the original Line Tool. It only show parallel/perpendicular when the first point(@ip1) is on a face. Original Line Tool has no such restriction, it can detect if there is a line parallel or perdicular with the current vector at almost any time.