Thanks Dan but I was looking for “under the hood” info on Section Planes. Nonetheless, I muddled through so below is my Script.
The idea here was to do sort of a Skalp Lite that makes a very remedial Section Plane we can use to distinguish between existing (EXIST) and proposed (PROP) geometry in our floor plans. We do a lot of renovation work and we can use a dedicated section view to overlay views to that end.
Obviously, we are working in a controlled environment where we can define and anticipate the names of groups, scenes, layers, etc. Something commercial like Skalp has to deal with many possible scenarios so needs to be much more sophisticated but also HEAVY. We had problems with it bogging down. Staff was going crazy.
One slightly hacky thing I had to do was to create a temporary circle entity we use as the cutting plane. Ideally, I would have just selected the Section Plane and used that to run intersect_with but that did not seem to be working out. Input welcome.
Anyway, hopefully this helps someone with Section Plane.
require 'sketchup.rb'
# TODO:
# remove inner faces - if some areas are completely enclosed, we will get multiple Z Section faces
# abort, exit, break, etc. for various cancels or fails
# REQUIRES:
# layers with names DEMO|EXIST|PROP
# groups in the model with instance names DEMO|EXIST|PROP that are the target objects to be cut
# section planes at different (at least one) levels with the name format "P" (for "plan") + "LEVEL_NUMBER" (P1,P2,P3 and so on)
# a folder containing styles named DEMO.style|EXIST.style|PROP.style
# a file name z_section_materials.skp containing materials DEMO|EXIST|PROP
# a component named "VIEWPORT" we use to set the view boundaries
module ZCode
module ZSectionModule
#################################################################
def self.z_section()
# start undo tracking
Sketchup.active_model.start_operation('ZSection', true)
# ask user for target level
prompts = ["PHASE:","LEVEL:"]
defaults = ["DEMO","1"]
list = ["DEMO|EXIST|PROP","1|2"]
response = UI.inputbox(prompts, defaults, list, "Z SECTION")
# catch "Cancel" button clicks
if(response == false)
return nil
else
$target_phase = response[0]
$target_level = response[1]
end
#set current layer to default
Sketchup.active_model.active_layer = Sketchup.active_model.layers["Layer0"]
# make sure the target layer is on
if(Sketchup.active_model.layers["#{$target_phase}"])
Sketchup.active_model.layers["#{$target_phase}"].visible = true
else
UI.messagebox('There are no matching layers in the model')
return nil
end
# get objects to be cut
$group_to_be_sectioned = false
Sketchup.active_model.entities.grep(Sketchup::Group).each{|g|
# look for target group
if(g.name == $target_phase)
$group_to_be_sectioned = g
if(g.hidden?)
g.hidden = false
end
# or delete prior sections
elsif(g.name == "#{$target_phase}#{$target_level}_CUT")
g.erase!
end
}
# catch missing group errors
if($group_to_be_sectioned == false)
UI.messagebox('There are no matching groups in the model')
return nil
end
# get section plane which is always named P for "plan level"
Sketchup.active_model.entities.grep(Sketchup::SectionPlane).each{|plane|
if(plane.name == "P#{$target_level}")
$su_section_plane = plane.get_plane
end
}
# get section plane elevation relative to origin
section_z = ORIGIN.project_to_plane($su_section_plane)
# define parameters of a circle large enough to capture anything in the model
$radius = [Sketchup.active_model.bounds.width,Sketchup.active_model.bounds.depth].max
center_xy = Sketchup.active_model.bounds.center
$center = [center_xy[0],center_xy[1],section_z[2]]
# create a group to receive the section circle geometry
z_section_circle = Sketchup.active_model.entities.add_group
z_section_circle.name = "Z_SECTION_CIRCLE"
z_section_circle.transformation = ORIGIN
# add the section geometry to the group
z_section_circle.entities.add_circle($center, Z_AXIS, $radius)
# fill in the section circle from its points
z_section_circle.entities.grep(Sketchup::Edge).each{|e|
e.find_faces
}
# create a group within the appropriate target group to receive the section geometry
$z_section_container = Sketchup.active_model.entities.add_group
$z_section_container_trans = $z_section_container.transformation
$z_section_container.name = "#{$target_phase}#{$target_level}_CUT"
$z_section_container.transformation = ORIGIN
$z_section_container.layer = "#{$target_phase}"
# create section points and edges
z_section_circle.entities.intersect_with(
false,
z_section_circle.transformation,
$z_section_container,
$z_section_container.transformation,
false,
$group_to_be_sectioned
)
# fill in the section plane from the section points
$z_section_container.entities.grep(Sketchup::Edge).each{|e|
e.find_faces
}
#remove inner faces
$z_section_container.entities.grep(Sketchup::Face).each{|f|
f.loops.each{|l|
if(l.outer?)
#outer_loop_array < l
else
#hole_array < l
#l.face.erase!
end
}
}
#test_array = face_a.loops[i].edges - face_b.outer_loop.edges
# load default materials from file
material_path = File.join(ENV['HOME'],'Dropbox/support/_sketchup/plugins/z_section_materials.skp')
Sketchup.active_model.definitions.load material_path
#apply a material to the section face
$z_section_container.material = $target_phase
#delete the section circle
z_section_circle.erase!
# zoom to the extents of viewport
z_zoom()
# load styles from file and set current style
style_path = File.join(ENV['HOME'],"Dropbox/support/_sketchup/styles/#{$target_phase}.style")
Sketchup.active_model.styles.add_style(style_path, true) # true sets loaded style as active
#Sketchup.active_model.styles.selected_style = Sketchup.active_model.styles["#{$target_phase}"]
# hide everything but the new $z_section_container
Sketchup.active_model.entities.each{|all_groups|
if(all_groups.is_a?(Sketchup::Group))
if(all_groups.name != "#{$target_phase}#{$target_level}_CUT")
all_groups.hidden = true
end
elsif(all_groups.is_a?(Sketchup::ComponentInstance))
if(all_groups.definition.name != "VIEWPORT")
all_groups.hidden = true
end
else
all_groups.hidden = true
end
}
# hide all non-target layers
Sketchup.active_model.layers.each{|l|
if((l.name != $target_phase)&&(l.name != "Layer0"))
l.visible = false
end
}
#create a new scene
new_page = Sketchup.active_model.pages.add("#{$target_phase}#{$target_level}_CUT")
#hide $z_section_container on all other scenes
Sketchup.active_model.pages.each{|op|
op.delay_time = 0
if(new_page != op)
Sketchup.active_model.pages.selected_page = op
$z_section_container.hidden = true
op.update(16)
end
}
#delete the old scene
Sketchup.active_model.pages.each{|p|
p.delay_time = 0
if((new_page != p)&&(p.name == "#{$target_phase}#{$target_level}_CUT"))
Sketchup.active_model.pages.erase(p)
end
}
#set the active page to the one just created
Sketchup.active_model.pages.selected_page = Sketchup.active_model.pages["#{$target_phase}#{$target_level}_CUT"]
# end undo tracking
Sketchup.active_model.commit_operation
end #def
#################################################################
def self.z_zoom()
# orient camera to plan view
z_plan_camera()
$viewport = false
Sketchup.active_model.entities.grep(Sketchup::ComponentInstance).each{|comp_instance|
if(comp_instance.definition.name == "VIEWPORT")
$viewport = comp_instance
if($viewport.definition.hidden?)
$viewport.definition.hidden = false
end
end
}
if($viewport)
#print "viewport found - zooming to viewport\n"
Sketchup.active_model.active_view.zoom($viewport)
else
#print "no viewport found - zooming to section extents\n"
Sketchup.active_model.active_view.zoom($z_section_container)
end
end #def
#################################################################
def self.z_plan_camera()
camera = Sketchup::Camera.new
status = camera.perspective = false
eye = [0,0,20000]
camera.set(eye, ORIGIN, Y_AXIS)
Sketchup.active_model.active_view.camera = camera
end #def
#################################################################
end # ZSectionModule
end # end of Module ZCode
# menus/toolbars ##############################################################
if( not file_loaded?("z_section.rb") )
# create menu items
UI.menu("Extensions").add_item("Z SECTION") {
ZCode::ZSectionModule::z_section()
}
UI.menu("Extensions").add_item("Z ZOOM") {
ZCode::ZSectionModule::z_zoom()
}
# create toolbar buttons
toolbar = UI::Toolbar.new "Z_Tools"
# set the path where icons are stored
icon_path = File.join(ENV['HOME'],'Dropbox/support/_sketchup/plugins/')
# create z_section button
command_z_section = UI::Command.new("Z Section") {
ZCode::ZSectionModule::z_section()
}
command_z_section.small_icon = "#{icon_path}z_section-small.png"
command_z_section.large_icon = "#{icon_path}z_section-large.png"
command_z_section.tooltip = "Z Section"
command_z_section.status_bar_text = "Create or update Z Section"
command_z_section.menu_text = "Z_Section"
toolbar = toolbar.add_item command_z_section
# create z_zoom button
command_z_zoom = UI::Command.new("Z Zoom") {
ZCode::ZSectionModule::z_zoom()
}
command_z_zoom.small_icon = "#{icon_path}z_zoom-small.png"
command_z_zoom.large_icon = "#{icon_path}z_zoom-large.png"
command_z_zoom.tooltip = "Z Zoom"
command_z_zoom.status_bar_text = "Zoom to viewport in plan orientation"
command_z_zoom.menu_text = "Z_Zoom"
toolbar = toolbar.add_item command_z_zoom
# show the Z_Tools toolbar
toolbar.show
end
file_loaded("z_section.rb")