What am I doing wrong here?

I’m trying to subtract one group from another and I’m not understanding why it isn’t working.

SKETCHUP_CONSOLE.clear
# Default code, use or delete...
mod = Sketchup.active_model # Open model
ents = mod.entities # All entities in model
sel = mod.selection # Current selection

o_width= 26.0 # outer width 
o_depth= 24.25 # inner depth 

i_width= 22.0 # inner width
i_depth= 23.25 # inner depth

top_opening_width = 18.75
top_opening_depth = 0.5

bottom_opening_width = top_opening_width
bottom_opening_depth = top_opening_depth

top_height= 29 # height of top cavity
bottom_height = 60 # height of bottom cavity
top_opening_height = 26.5
bottom_opening_height = 59.5

def upright(face)
  if face.normal.z == -1
    face.reverse!
  end
end

pts=[0,0,0],[0,o_depth,0],[o_width,o_depth,0],[o_width,0,0]
# create substrate
cabinet = ents.add_group # add substrate group
cabinet.name = "cabinet" # name substrate group
cabinet_face = cabinet.entities.add_face pts
upright(cabinet_face)
cabinet_face.pushpull 94


offset_x = (o_width-i_width) / 2
offset_y = (o_depth-i_depth) / 2

pts=[0,0,0],[0,i_depth,0],[i_width,i_depth,0],[i_width,0,0]
vector_bottom=Geom::Vector3d.new(offset_x,offset_y,0.5)
vector_top = Geom::Vector3d.new(offset_x,offset_y,61)

bottom = ents.add_group
bottom.name= "bottom"
bottom_face = bottom.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_bottom}
upright(bottom_face)
bottom_face.pushpull bottom_height

top = ents.add_group
top.name= "top"
top_face = top.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_top}
upright(top_face)
top_face.pushpull top_height

pts=[0,0,0],[0,top_opening_depth,0],[top_opening_width,top_opening_depth,0],[top_opening_width,0,0]
offset_x= (o_width-top_opening_width)/ 2
vector_top = Geom::Vector3d.new(offset_x,0,61)
top_face2 = top.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_top}
upright(top_face2)
top_face2.pushpull top_opening_height

vector_bottom=Geom::Vector3d.new(offset_x,0,0.5)
bottom_face2 = bottom.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_bottom}
upright(bottom_face2)
bottom_face2.pushpull bottom_opening_height

cabinet = top.subtract(cabinet)
cabinet = bottom.subtract(cabinet)


The problem is that neither top nor bottom is a SketchUp solid (test using #manifold?), so subtract is failing. That also causes cabinet to become nil (the return when subtract fails), which will by itself cause the subtract from bottom to fail.

Edit: The source of the issue is that the inner surface of the doors on both the top and bottom form interior faces on those groups. Interior faces are not allowed in SketchUp solids.

1 Like

Thanks! I figured it out. I just made the two peices into different groups then unioned them and used that to subtract from the cabinet.

SKETCHUP_CONSOLE.clear
# Default code, use or delete...
mod = Sketchup.active_model # Open model
ents = mod.entities # All entities in model
sel = mod.selection # Current selection

o_width= 26.0 # outer width 
o_depth= 24.25 # inner depth 

i_width= 22.0 # inner width
i_depth= 23.25 # inner depth

top_opening_width = 18.75
top_opening_depth = 0.5

bottom_opening_width = top_opening_width
bottom_opening_depth = top_opening_depth

top_height= 29 # height of top cavity
bottom_height = 60 # height of bottom cavity
top_opening_height = 26.5
bottom_opening_height = 59.5

def upright(face)
  if face.normal.z == -1
    face.reverse!
  end
end

pts=[0,0,0],[0,o_depth,0],[o_width,o_depth,0],[o_width,0,0]
# create substrate
cabinet = ents.add_group # add substrate group
cabinet.name = "cabinet" # name substrate group
cabinet_face = cabinet.entities.add_face pts
upright(cabinet_face)
cabinet_face.pushpull 94


offset_x = (o_width-i_width) / 2
offset_y = (o_depth-i_depth) / 2

pts=[0,0,0],[0,i_depth,0],[i_width,i_depth,0],[i_width,0,0]
vector_bottom=Geom::Vector3d.new(offset_x,offset_y,0.5)
vector_top = Geom::Vector3d.new(offset_x,offset_y,61)

bottom_main = ents.add_group
bottom_main.name= "bottom_main"
bottom_face = bottom_main.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_bottom}
upright(bottom_face)
bottom_face.pushpull bottom_height

top_main = ents.add_group
top_main.name= "top_main"
top_face = top_main.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_top}
upright(top_face)
top_face.pushpull top_height

pts=[0,0,0],[0,top_opening_depth,0],[top_opening_width,top_opening_depth,0],[top_opening_width,0,0]
offset_x= (o_width-top_opening_width)/ 2
vector_top = Geom::Vector3d.new(offset_x,0,61)
top_opening = ents.add_group
top_opening.name= "top_opening"
top_face2 = top_opening.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_top}
upright(top_face2)
top_face2.pushpull top_opening_height

vector_bottom=Geom::Vector3d.new(offset_x,0,0.5)
bottom_opening = ents.add_group
bottom_opening.name= "bottom_opening"
bottom_face2 = bottom_opening.entities.add_face pts.map{|pt| Geom::Point3d.new(pt)+vector_bottom}
upright(bottom_face2)
bottom_face2.pushpull bottom_opening_height

bottom = bottom_opening.union(bottom_main)
bottom.name = "bottom"
top = top_opening.union(top_main)
top.name = "top"
cabinet = top.subtract(cabinet)
cabinet = bottom.subtract(cabinet)

Probably clearer to use Geom::Point3d#offset here …

Ie …

bottom_face = bottom.entities.add_face(pts.map {|pt| pt.offset(vector_bottom) })

… and further down for top_face.

Meaning it is clunky to explicitly call a class constructor method when the class has many methods that return new objects. (You’ll usually see in Ruby that the bang methods, like offset! change the receiver object whilst the non-bang methods create new objects.)