To use the Dave method, you would multiply all the x and y values by a constant, create your groups at the enlarged size, and apply a scaling transformation all of them to restore the correct size.
I’ve updated my code but now I am not really sure how to run it.
SKETCHUP_CONSOLE.clear
module Practice
module Create_structure
extend self
# get model set up
model = Sketchup.active_model # Open model
manager = model.options
provider = manager["UnitsOptions"]
provider["LengthUnit"] = 2 # set default values to mm
ents = model.active_entities
layers_array = model.layers # create an array to store layer information
@substrate = ents.add_group # add substrate group
@via = ents.add_group # add group
@insulator = ents.add_group # adds insulator to group
@m1 = ents.add_group
# this makes the chosen face orient up
def face_up(face)
face.reverse! unless face.normal.z == 1
raise "face not on z plane" unless face.normal.z == 1
end
# this makes the chosen face orient down
def face_down(face)
face.reverse! unless face.normal.z == -1
raise "face not on z plane" unless face.normal.z == -1
end
# this gets the highest point in a group. (not used yet)
def get_highest_point_in_group(group)
max_pt = entities.flat_map(&:vertices).map(&:position).map(&:z).max
return max_pt
end
# set up initial variables
@sub_t = 2.mm # thickness of substrate
@via_t = 5.mm # thickness of via (i.e total height)
@via_into = 1.mm # penetration of via into thing below it.
@insulator_t = 2.mm # thickness of insulator layer
@m1_t = 2.mm # thickness of m1 layer
# This will be used to track the positions for adding edges off the previous layer
# think of it like a hill and a valley that we are building on.
@highest_pt = 0.mm # current highest (like a hill)
@highest_low_pt = 0.mm # this will be the lowest occupied point (like a valley)
# add layer tags to layers_array
substrate_tag = layers_array.add "substrate"
insulator_tag = layers_array.add "insulator"
via_tag = layers_array.add "via"
m1_tag = layers_array.add "m1"
# create substrate
def create_substrate
model = Sketchup.active_model # Open model
model.start_operation('Create Substrate', true)
@substrate = ents.add_group # add substrate group
sub_face = @substrate.entities.add_face [0,0,0], [5.mm,0,0], [5.mm,8.mm,0], [0,8.mm,0] # add face
face_down(subface) # make face down
sub_face.pushpull @sub_t # extrude 10mm below (no need to update lowest point at this part)
model.commit_operation
end
# now deposit the via layer
def create_via
model = Sketchup.active_model # Open model
model.start_operation('Create Via', true)
@via.name = "via" # name group (debugging)
@via.entities.add_face([1.mm,1.mm,@highest_low_pt], [4.mm,1.mm,@highest_low_pt], [4.mm,3.mm,@highest_low_pt], [1.mm,3.mm,@highest_low_pt]) # adds face to via group
@via.entities.add_face([1.mm,5.mm,@highest_low_pt], [4.mm,5.mm,@highest_low_pt], [4.mm,7.mm,@highest_low_pt], [1.mm,7.mm,@highest_low_pt]) # adds face to via group
via_faces = @via.entities.grep(Sketchup::Face) # find the via faces
points = via_faces.flat_map(&:vertices).uniq.map(&:position) # get all the positions of the
# go up by 25 mm
vector = Geom::Vector3d.new(0, 0, @via_t) # the vector will be used to generate the thickness of this layer.
top_face_pts=[] # empty array to push the via top face points into
via_faces.each{|f| top_face_pts.push(f.vertices.map(&:position).map{|p| p.offset(vector)})} # creates points that will be used to make the top face.
# There is probably a better way to do this with the push_pull function but I want to make a pyramidal shape later
# adds the top face (later version this will possibly be an offset)
top_face_pts.each{|pts| via.entities.add_face pts} # adds the top faces
# create a new edge for each point
points.each{|pt| via.entities.add_edges(pt,pt.offset(vector))} # add egdges from the bottom face points to the top face points.
@highest_pt += @via_t # update the highest point. (since we started at 0 we add the height of the extrusion
via_edges = @via.entities.grep(Sketchup::Edge) # find all the via groups edges.
via_edges.each(&:find_faces) # add faces using the edges found above.
move_via = Geom::Transformation.new([0,0,-@via_into]) # transformation to move the via so that it penetrates the substrate.
@via.transform! move_via # move the via into the substrate
@highest_pt -= @via_into # update highest point
@substrate=@via.trim(@substrate) # trim is non destructive method to remove the part of the substrate that the via penetrates into.
model.commit_operation
end
# Add the insulator layer
def create_insulator
model = Sketchup.active_model # Open model
model.start_operation('Create Insulator', true)
ins_face = @insulator.entities.add_face [0,0,@highest_low_pt], [5.mm,0,@highest_low_pt], [5.mm,8.mm,@highest_low_pt], [0,8.mm,@highest_low_pt] # adds face to insulator
face_up(ins_face) # makes the face upright
ins_face.pushpull @insulator_t # pulls the face up to the correct thickness starting at the insulator layer.
# update information
calc_total_height = @insulator_t + @highest_low_pt
if calc_total_height < @highest_pt # if this is the new highest low point
@highest_low_pt = calc_total_height # update highest low point
else # if this is now the highest point.
@highest_low_pt = @highest_pt # update highest low point to old highest point
@highest_pt = calc_total_height # overwrite highest point to be the new total height.
end
@insulator = @via.trim(@insulator) # trim the insulator using the via.
model.commit_operation
end
# deposit m1 uniformly
def Create_m1
model.start_operation('Create Insulator', true)
groups = ents.grep(Sketchup::Group)
#faces = groups.flat_map{|g| g.entities.grep(Sketchup::Face)}
positions = groups.flat_map{|g| g.entities.grep(Sketchup::Face)}.flat_map(&:vertices).map(&:position)
top_points = positions.find_all{|p| p.z >= @highest_low_pt && p.z <= @highest_pt}
top_points = top_points.map(&:to_a).uniq
vector = Geom::Vector3d.new(0, 0, m1_t)
top_points.each{|pt| @m1.entities.add_edges(pt,pt.offset(vector))}
m1_edges = @m1.entities.grep(Sketchup::Edge)
m1_edges.each(&:find_faces)
model.commit_operation
end
#name groups
@substrate.name = "substrate" # name substrate group
@via.name = "via"
@insulator.name = "insulator"
@m1.name = "m1"
# add layer tags
@via.layer = via_tag
@insulator.layer = insulator_tag
@substrate.layer=substrate_tag
@m1.layer = m1_tag
model.rendering_options['DisplayColorByLayer']= true # colors each layer
end
end
Again … all executing code needs to be in methods.
Only constants local to your extension submodule should be outside of the methods.
They’ll get defined when the module loads, which is when SketchUp first starts.
All of the instance references (ie @vars) are things that can change each time commands are run, and therefore could be on different models, or different components, etc.
In many cases it is better programming to pass data into methods rather then have a bunch of @vars.
You can also either use an OpenStruct
or a custom class, that holds this state data and promotes better reading code. Then you need only pass the reference to these data objects around.
SketchUp code is normally event driven by events caused by the user.
Common events would be clicking a menu item, clicking a toolbar button, activating a certain tool, etc.
For now (and testing) just create a menu items that fires off the creation of your model objects.
(Ie, it can serve temporarily as a placeholder for a GDS file import which is fired thru the menu and the import dialog.)
See: UI.menu
module method and Sketchup::Menu
class.
Just be sure to put the menu item creation with a block …
if !@loaded
@loaded = true
UI.menu("Extensions").add_item("My Thing") { do_my_thing() }
end
Lastly, do yourself and us a favor and write code more readable.
Try (in most cases) to put the explanation comment before the code that does the task.
(In code editors the comment color serves to help space the code into more readable chunks.)
Do not omit spaces, especially around operators.
Use the same spacing around {|
as you would if using do |
Try and keep lines to 80 characters or less. ie, learn to indent long blocks and long methods calls.
(It is no fun to be forced to do horizontal scrolling in the forums.)
A long block:
# Create points that will be used to make the top face.
via_faces.each { |f|
top_face_pts.push( f.vertices.map(&:position).map { |p| p.offset(vector) } )
}
A long method call:
# Add face to via group
@via.entities.add_face(
[1.mm, 5.mm, @highest_low_pt], [4.mm, 5.mm, @highest_low_pt],
[4.mm, 7.mm, @highest_low_pt], [1.mm, 7.mm, @highest_low_pt]
)
A long array definition …
# Points for via face
points = [
[1.mm, 5.mm, @highest_low_pt], [4.mm, 5.mm, @highest_low_pt],
[4.mm, 7.mm, @highest_low_pt], [1.mm, 7.mm, @highest_low_pt]
]
See this style guide: https://rubystyle.guide/
It is used by Rubocop and by the SketchUp extension GitHub - SketchUp/rubocop-sketchup: Rubocop cops for SketchUp - test against our Extension Warehouse technical requirements and other pitfalls
which the Trimble Extensibility team runs on all submissions to the Extension Warehouse.
Pay first attention to the format and spacing rules. (Not so much the use this method over that method stuff which is enforcing silly subjective preference.)
But the format rules really serve to reduce fatigue after a full day of staring at code.