Intersect Method problem

I have some Solid groups touching each other. But when using Intersect method to check with their BoundingBoxs, I can not receive any result from this process. Please kindly let me know the reason of this issue and how I can deal with it. Thanks a lot!
There is my file:
test.skp (348.0 KB)

mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
p sel[0].bounds.intersect(sel[1].bounds).empty?
1 Like

Whether something touching at their boundaries is considered intersection or not is context dependent. SketchUp logic’s for bounding box is that touching boundaries are not intersections, the boundingboxes must actually overlap in 3D space.

You can also observe that the returned boundingbox is not valid:

sel[0].bounds.intersect(sel[1].bounds).valid? # => false

So for your case you have to perform your own comparison.

Note that Geom::BoundingBox is not the same as the selection boundingbox in the UI. If you rotate the instances off-axis they will not match. You can see how Draw Bounding Box computes the real boundingbox corners that matches the selection boundingbox: https://github.com/thomthom/draw-boundingbox/blob/master/src/tt_draw_bb/core.rb#L46

2 Likes

Here is method I cobbled together to test interference of 3D objects.
(I don’t know how it might work on flat objects where 1 one the dimensions is 0.)

# Test whether the bounds of two objects interfere.
#
# @param [obj1] The 1st object to test.
# @param [obj2] The 2nd object to test.
#
# @return [false] Non-interfering.
# @return [true] Overlapping in all 3 axis.
# @return [Geom::Vector3d] touching along the returned axis.
#
def interfere?(obj1, obj2)
  # Get the bounds of the two test objects:
  b1 = obj1.bounds
  b2 = obj2.bounds

  # We create a virtual compound bounding box containing the
  # bounds of the two objects that we need to check:
  bb = Geom::BoundingBox.new(b1,b2)

  # If the two object's bounds are overlapping then the sum of each of
  # their corresponding dimensions must be more than that dimension of
  # the compound bounding box. Ie, there cannot be any spacing at all
  # in any of the 3 axis between the test object's bounding boxes.

  # If the two object's bounds are not overlapping but touching in one
  # of the 3 axis, then one of the sums of their corresponding dimensions
  # must be exactly equal to that dimension of the compound bounding box,
  # AND the other two dimensions of the compound bounding box must be less
  # than sums of that corresponding dimension of the test object's bounds.

  # If the two object's bounds are not intersecting (nor touching) then
  # one of the compound bounding box's dimensions must be greater than
  # the sums of that corresponding dimension of the test object's bounds.
  # Ie, there must be spacing between the test object's bounding boxes
  # in at least one of the axis. (There might be spacing in multiple
  # axis between the test object's bounds.)

  # So we create a hash of the X (width,) Y (height) and Z (depth) axis
  # sums of the two object's under test:
  sum = Hash[
    :width,  b1.width  + b2.width,
    :height, b1.height + b2.height,
    :depth,  b1.depth  + b2.depth
  ]

  if bb.width > sum[:width] || bb.height > sum[:height] || bb.depth > sum[:depth]
    # non-interfering:
    return false
  else
    # Either overlapping or touching:
    # Use Length#== to compare within Sketchup's tolerance.
    touching = sum.keys.find {|key| bb.call(key) == sum[key] }
    if touching
      i = [:width,:height,:depth].index(touching)
      return [X_AXIS,Y_AXIS,Z_AXIS].at(i)
    else
      # Overlapping:
      return true
    end
  end

end ### interfere?
1 Like

Thanks for your kind support, Thomas. It’s really helpful, I’ve understood alreadly and had a better mind about how Boundingbox works.

Thanks a lot Dan. Your method is great, I applied it to deal with my problem and it works.

1 Like

I think sketchup needs to allow for planes that touch another plane or object to intersect with each other and show the result, instead of having to have to pass through an object. Just recently I could have used this if it was a feature available to the intersect options in sketchup. Hopefully this kind of thing can be added.

1 Like

Yes, i think so too.

This can be done using Sketchup::Entities#intersect_with, however it modifies the model hence the undo operation. Since SU2020 or so, “objects” refer collectively to groups or component instances …

  # Create a group of intersect edges between two instances.
  #
  # @param inst1 [Sketchup::Group,Sketchup::ComponentInstance]
  # @param inst2 [Sketchup::Group,Sketchup::ComponentInstance]
  # @return [Sketchup::Group,nil] A group with intersect edges.
  def intersect_objects(inst1, inst2)
    unless inst1.parent == inst2.parent
      fail(ArgumentError,'argument instances are not in same context.',caller)
    end
    model = inst1.model
    model.start_operation('Intersect Objects',false)
      group = inst1.parent.entities.add_group
      edges = inst1.entities.intersect_with(
        false, inst1.transformation, group.entities, IDENTITY, false, inst2
      )
    model.commit_operation
    return nil if !edges || edges.empty?
    group
  end

From the resultant intersect group, … or any group you know has only planar edges …
… to get an array describing a plane per the Geom model Overview

  # For a group containing edges, returns a "best fit" plane array
  # matched to as many of the vertex positions of the edges as possible.
  #
  # Does not determine if all edge vertices are planar!
  #
  # @param group [Sketchup::Group] A group containing intersect edges.
  # @return [Array] An array describing the best fit plane.
  def intersect_plane(group)
    edges = group.entities.grep(Sketchup::Edge)
    pts = edges.flat_map(&:vertices).uniq.map(&:position)
    # Get best fit plane:
    Geom::fit_plane_to_points(pts)
  end
1 Like

It’s really great! It takes time for me to understand methods which you use! It’s much more concise and effective than the method I’m using. Thanks a lot Dan!

1 Like