PickHelper.window_pick bug inside a group/component

Hi, I am trying to write a selection tool and when using the window_pick method, there was a problem.
The PickHelper.window_pick method works well outside the model but when I use it inside an object it works wrong. I’m using it the wrong way?
Check out the code below in the onLButtonUp method.
Thanks

class SelectTool
  def initialize(*_args)
    @model = Sketchup.active_model
    @selection = Sketchup.active_model.selection
    @ip_mouse = Sketchup::InputPoint.new
  end

  def activate
    reset
  end

  def deactivate(view)
    view.invalidate
  end

  def reset; end

  def onCancel(reason, _view)
    if reason == 0
      @model.close_active if @model.active_path
    end
  end

  def onMouseMove(_flags, x, y, view)
    @mouse = [x, y]
    onSetCursor
    set_statusbar
    view.invalidate
  end

  def onLButtonDown(_flags, x, y, _view)
    @click_times = 1
    @drag = true
    @mouse_down = [x, y]
  end

  def dragging?
    @drag && @mouse_down && @mouse.distance(@mouse_down) > 10
  end

  def onLButtonUp(_flags, x, y, view)
    ph = view.pick_helper
    ph.do_pick(x, y)
    @best_entity = ph.best_picked

    if dragging?
      pick_type = if @mouse.x > @mouse_down.x
                    Sketchup::PickHelper::PICK_INSIDE
                  else
                    Sketchup::PickHelper::PICK_CROSSING
                  end

      num_picked = ph.window_pick(@mouse_down, @mouse, pick_type)
      if num_picked > 0
        @selection.clear
        @selection.add(ph.all_picked)
      end
    else
      @selection.clear
      @selection.add(@best_entity) if @best_entity
    end

    @drag = false
    @mouse_down = nil

    view.invalidate
  end

  def onLButtonDoubleClick(_flags, x, y, view)
    @click_times += 1
    p "onLButtonDoubleClick: @click_times = #{@click_times}"

    ph = view.pick_helper
    ph.do_pick(x, y)
    @best_entity = ph.best_picked

    if object?(@best_entity)
      active_path = @model.active_path || []
      unless @best_entity.locked?
        @model.active_path = active_path + [@best_entity]
      end
    elsif @best_entity
      if geometry?(@best_entity)
        # select connected
        if @best_entity.is_a?(Sketchup::Edge)
          @selection.add(@best_entity.faces)
        else
          # Face
          @selection.add(@best_entity.edges)
        end

        @selection.add(@best_entity.all_connected) if @click_times > 2
      else
        # API cant edit Dimension and Text
        # Sketchup.send_action('selectSelectionTool:')
      end
    elsif @model.active_path
      @model.close_active 
    end
  end

  def object?(entity)
    return unless entity

    entity.is_a?(Sketchup::Group) ||
      entity.is_a?(Sketchup::ComponentInstance)
  end 
  
  def geometry?(entity)
    return unless entity

    entity.is_a?(Sketchup::Edge) ||
      entity.is_a?(Sketchup::Face)
  end

  def onSetCursor
    # UI.set_cursor(@cursor)
  end

  def set_statusbar
    status_text = 'Select objects. Shift to extend select. Drag mouse to select multiple.'
    Sketchup.set_status_text(status_text)
  end

  def draw(view)
    if dragging?
      rect = [
        @mouse_down,
        [@mouse_down.x, @mouse.y],
        @mouse,
        [@mouse.x, @mouse_down.y]
      ]

      inside = @mouse.x > @mouse_down.x

      view.line_width = 1
      view.line_stipple = inside ? '' : '_'
      view.drawing_color = 'black'
      view.draw2d(GL_LINE_LOOP, rect)
    end
  end
end

Sketchup.active_model.select_tool(SelectTool.new)

Yes I see it acts weird. Does ThomThom’s PickHelper Guide help ?

1 Like

The window_pick method has been added since 2016’s SketchUp, Thom Thom’s document has not added this method yet.
The boundingbox_pick method has the same problem.

Okay I got it picking from the active entities …

… but it can’t tell the difference from a crossing and an inside pick.

EDIT: Actually that was my error. I had messed with the if statement just after the if dragging? statement and I’ve since fixed that.

BUT: The problems now seem to be that the window pick will ONLY return one pick path for any primitive entities even though more than 1 are window selected and OFTEN only during a crossing select. (Ie, occasionally an inside window select will also grab a random primitive edge or face.) It doesn’t matter how many groups or component instances are also selected (along with the primitives,) the window pick only returns a single pick path for one of the primitives (seemly chosen at random) in the selection along with the pick paths for groups and/or component instances.

Also … we don’t need to do ph.do_pick(x,y) with a window pick pattern so I moved that down into the else (not dragging) clause.

class SelectTool
  def initialize(*_args)
    @model = Sketchup.active_model
    @selection = Sketchup.active_model.selection
    @ip_mouse = Sketchup::InputPoint.new
  end

  def activate
    reset
  end

  def deactivate(view)
    view.invalidate
  end

  def reset
    @drag = false
  end

  def onCancel(reason, _view)
    if reason == 0
      if @model.active_path
        @model.close_active
      else
        reset()
      end
    end
  end

  def onMouseMove(_flags, x, y, view)
    @mouse = [x, y]
    onSetCursor
    set_statusbar
    view.invalidate
  end

  def onLButtonDown(_flags, x, y, _view)
    @click_times = 1
    @drag = true
    @mouse_down = [x, y, 0]
  end

  def dragging?
    @drag && @mouse_down && @mouse.distance(@mouse_down) > 10
  end

  def onLButtonUp(_flags, x, y, view)
    ph = view.pick_helper

    if dragging?
      if x > @mouse_down.x
        pick_type = Sketchup::PickHelper::PICK_INSIDE
      else
        pick_type = Sketchup::PickHelper::PICK_CROSSING
      end

      #num_picked = ph.window_pick(@mouse_down, @mouse, pick_type)
      num_picked = ph.window_pick(@mouse_down, [x,y,0], pick_type)
      if num_picked > 0
        puts "Number picked: #{num_picked}"
        picked = []
        context = @model.active_entities
        ph.count.times { |pick_path_index|
          path = ph.path_at(pick_path_index)
          found = path.find { |ent| context == ent.parent.entities }
          picked << found if found
        }
        picked.uniq!
        puts "Picked: "<<picked.inspect
        @selection.clear
        @selection.add(picked)
      else
        UI.beep
      end

      @drag = false

    else
      # Moved these 2 statements inside the else:
      ph.do_pick(x, y)
      @best_entity = ph.best_picked
      #
      @selection.clear
      @selection.add(@best_entity) if @best_entity
    end

    @mouse_down = nil

    view.invalidate
  end

  def onLButtonDoubleClick(_flags, x, y, view)
    @click_times += 1
    p "onLButtonDoubleClick: @click_times = #{@click_times}"

    ph = view.pick_helper
    ph.do_pick(x, y)
    @best_entity = ph.best_picked

    if object?(@best_entity)
      active_path = @model.active_path || []
      unless @best_entity.locked?
        @model.active_path = active_path + [@best_entity]
      end
    elsif @best_entity
      if geometry?(@best_entity)
        # select connected
        if @best_entity.is_a?(Sketchup::Edge)
          @selection.add(@best_entity.faces)
        else
          # Face
          @selection.add(@best_entity.edges)
        end

        @selection.add(@best_entity.all_connected) if @click_times > 2
      else
        # API cant edit Dimension and Text
        # Sketchup.send_action('selectSelectionTool:')
      end
    elsif @model.active_path
      @model.close_active 
    end
  end

  def object?(entity)
    return unless entity

    entity.is_a?(Sketchup::Group) ||
      entity.is_a?(Sketchup::ComponentInstance)
  end 
  
  def geometry?(entity)
    return unless entity

    entity.is_a?(Sketchup::Edge) ||
      entity.is_a?(Sketchup::Face)
  end

  def onSetCursor
    # UI.set_cursor(@cursor)
  end

  def set_statusbar
    status_text = 'Select objects. Shift to extend select. Drag mouse to select multiple.'
    Sketchup.set_status_text(status_text)
  end

  def draw(view)
    if dragging?
      rect = [
        @mouse_down,
        [@mouse_down.x, @mouse.y],
        @mouse,
        [@mouse.x, @mouse_down.y]
      ]

      inside = @mouse.x > @mouse_down.x

      view.line_width = 1
      view.line_stipple = inside ? '' : '_'
      view.drawing_color = 'black'
      view.draw2d(GL_LINE_LOOP, rect)
    end
  end
end
1 Like
1 Like

5 years have passed and nothing has changed. No one has a way to select elements from active_entities using a rectangle???

True. @CraigTrickett this is an example of the API team not correcting existing bugs, in favor of supporting new features. (Likely because marketing thinks new features will drive more sales.)

Hi @DanRathbun, thank you for bringing this to my attention.
I can certainly ask the team about this particular issue and try to come back to you.

In regards to bugs vs new features, I would highlight that a number of bugs have actually been fixed as well as new features added. Sadly, its usually easier for people to see which bug’s haven’t been fixed but that will always be the case. 5 years is a long time for any bug to go unfixed and I’m not trying to make excuses for that.

Let me see what I can find out.

Kind regards,

Craig

Sometimes we cannot help but voice our frustrations. It is not lost on us how much emphasis goes into new features. That said, this was once a new API feature, that apparently was not 100% finished.

There are “bug” issues older, up to 8 years old: