This is related to my previous post about editing dimensions for a wall panel.
I am currently working on a simple tool that will allow the user to select a dimension. As I mouse over the dimension I would like my tool to detect which dimension I am hovering over.
As you can see below I have some dimensions (stacked):
All four of these dimensions are contained within a sub-group that is within the main group/assembly of the wall. When I move my mouse over the dimensions because they are stacked I am only able to select the main wall dimension. My single line of code to detect which dimension I am hovering over is:
if dimi.bounds.contains?(@iptrans)
Where iptrans is the @ip.position of the cursor transformed into the wall group coordinates.
I think the problem is that using the bounds of the dimension will not work since the stacked dimensions (bounds) overlap and I will always get the larger of the two or even a random sort of behavior. I am wondering if there is a more reliable or precise way of having the tool detect the dimension I am hovering over.
I’m wondering if anyone else has encountered this problem/programming puzzle before and how did they deal with it?
I am thinking there may be some other reference point of the DimensionLinear class that I can utilize to aid in my selection other than just the bounds.
My first thought would be to look for the position of the dimension text and then set some minimum distance between this point and the cursor, however I don’t see any methods to get the actual text position in the model (however I’m assuming one could calculate this given the start and end points and the dimension offset).
Here is a sample that picks dimensions that are inside a group.
class DimensionSelectTool
def onMouseMove(_flags, x, y, view)
pick_helper = view.pick_helper
pick_helper.do_pick(x, y)
cnt = pick_helper.all_picked.count
dimension = nil
if cnt > 0
(0..cnt).each do |idx|
next unless pick_helper.leaf_at(idx).is_a? Sketchup::DimensionLinear
dimension = pick_helper.leaf_at(idx)
end
end
Sketchup.active_model.selection.clear
Sketchup.active_model.selection.add(dimension) if dimension
end
end
tool = DimensionSelectTool.new
Sketchup.active_model.tools.push_tool tool
However dimensions are unlike groups in that to select them you need to carefully place your mouse directly on the lines or text.
For someone as fat fingered as myself this may be a bit challenging and that is why I was thinking of using some sort of proximity test to aid in the selection/highlighting, if this makes sense. You wouldn’t have to be so careful in order to select the dimension, just get reasonably close.
Maybe the following, which seems to work, isn’t using reentrant code, and may create a few less objects to be gc’d in a loop that runs frequently…
# frozen_string_literal: true
# Base class for tool entity selection. Initialize with the entity class to be
# selected. Calls into the subclass via `post_select`.
#
class EntitySelectToolBase
APERTURE_START = 60
APERTURE_STEP = 5
def initialize(entity_class)
@entity_class = entity_class
end
def onMouseMove(_flags, x, y, view)
pick_helper = view.pick_helper
aperture = APERTURE_START
begin
pick_helper.do_pick x, y, aperture
entities_picked = pick_helper.all_picked.grep @entity_class
break if entities_picked.empty?
if entities_picked.count > 1 && aperture >= APERTURE_STEP
aperture -= APERTURE_STEP
end
end until aperture < APERTURE_STEP || entities_picked.length == 1
post_select entities_picked.first
end
end
class DimensionSelectTool < EntitySelectToolBase
def post_select(entity)
Sketchup.active_model.selection.clear
if entity
Sketchup.active_model.selection.add entity
Sketchup.vcb_value = entity.text
else
Sketchup.vcb_value = ''
end
end
def enableVCB?
return true
end
def onUserText(text, view)
@distance = text.to_l
@dimension.text = @distance.to_s
rescue ArgumentError
view.tooltip = 'Invalid length'
end
end
tool = DimensionSelectTool.new Sketchup::DimensionLinear
Sketchup.active_model.tools.push_tool tool
I updated the code above to use a base class. Also, yesterday I had my ruby console obstructing some of the SU GUI, and the updated code removes the ‘fluttering’ in the VCB, along with clearing the selection in possibly a better manner.
Thanks @greg. I just did a quick and dirty proof of concept. I figured @medeek has enough experience to take it from there. Your code is a lot cleaner.
I assumed as much. GUI apps don’t have a lot of ‘hot’ code paths, but onMouseMove might qualify.
So, I wanted to show possible optimizations. JFYI, I try to avoid reentrant code unless it’s really necessary, as rewinding it can involve a lot of resources…