I’m trying to figure out how to let the user of my extension select an edge AND one of the endpoints of the edge in order to construct some geometry with respect to that selected point.
A dialog with 4 options (left / right / top / bottom) would do the trick as I’m working in 2D only. However, I would like to implement a slightly improved variation of that which involves the user selecting the edge and then having a mechanism to color the endpoints. Thus, the dialog would only present the user 2 options instead of 4.
To this end, I was considering adding construction points via the Ruby API but I was unable to customize them via the material and layer attributes. I would ideally like to change the tiny plus that’s barely visible with some sort of filled dot of a given color. Is that even possible?
Or is there a better way to solve my original problem?
This means coding a custom Ruby tool that leverages a PickHelper or InputPoint object. A tool can draw to the viewport (your little endpoint bulbs) or just use SketchUp’s native endpoint inferencing.
Currently I have a Command instead of a Tool as the user is supposed to first select the edge and then invoke the command via a menu item. It sounds like I have to transition all that code into a Tool object instead, right?
Yes, because you want both the edge and a specific endpoint, and the GUI selection tool can’t do that. To make a more refined selection you need to create a Tool.
The first thing is to let your tool code know it by setting a state variable. It can be as simply named as @state which would be initialized in the activate() callback to 0 and then after the vertex is selected it would be incremented to 1. (Again see the example line tool.)
Normally your callbacks will have a conditional branching construct based upon the value of @state. Ie, when == 0 then pick a vertex, when 1 do the next step, etc.
To let the user know, the tool can draw virtually to the view and highlight the edge and/or draw a little box around the vertex. See:
You’ve been super helpful once again! My idea was to create a shape that lives in the z = 0.01 plane to create the illusion that the user has selected their desired point… But the View#draw() method solves this problem a lot more elegantly.
I’ve also leveraged the view.camera.height attribute to maintain the size of the point constant even when the user zooms in and out. The one thing that took me a bit of time to figure out was calling the view.invalidate method inside onLButtonDown(...). Without that the draw function wouldn’t get triggered and thus my vertex marker wouldn’t show up when left-clicking.
Here’s the implementation I came up with:
class PointHighlighter
NO_POINTS = 24
def activate
@vertex = nil
end
def onLButtonDown(flags, x, y, view)
@vertex = view.inputpoint(x, y).vertex
view.invalidate
end
def highlight_point(view)
# Display a point that keeps the same size to the user.
x, y = @vertex.position[0], @vertex.position[1]
r = view.camera.height / 250.0
points = []
(0...NO_POINTS).each do |i|
angle = (2.0 * Math::PI * i) / NO_POINTS
points << [x + r * Math.cos(angle), y + r * Math.sin(angle)]
end
# Fill the dot.
view.drawing_color = Sketchup::Color.new(0, 0, 255)
view.draw(GL_POLYGON, points)
end
def draw(view)
return if @vertex.nil?
highlight_point(view)
end
end
def activate_tool
Sketchup.active_model.select_tool(PointHighlighter.new)
end
activate_tool
For example in my move tool I want the arrows to stay the same size relative to the model, but the text and the box around it I want to be a continuous size in 2D. The view.screen_coords method is useful for converting a 3d point in the model to a 2d position on the screen.
Thanks for your input, Neil! What you describe seems to be a generalization of what I did, right? Note that I’m not planning to use my extension in 3D, so I guess that querying the view.camera.height should be just fine. The only thing I really want is to have point markers that have the same size irrespective of how big/small my 2D polygons are.