Hi everyone!
I am unsure if this is the correct place for this post; however, I need a script that does the following:
For all extruded faces in the model, I need a line drawn parallel to the face/perpendicular to the edge.
The first line (from the bottom to the top - going up the blue axis) is 4.5 meters from the ground. After that, it is drawn every 3 meters.
If I am able to do this successfully with your script and instructions, I will gladly send a donation for your helpful support!
I’ve been up all night and kind of need this done
Please someone be my angel.
To begin, please clarify what you are requesting. An image or a manually created SketchUp example model would help a great deal. Some words about what you are modeling would also help clarify the technical specs. - there could even be a better way to accomplish your goal.
Here are things I find unclear in your post:
- How to identify “all extruded faces”? There is not an explicit thing in SketchUp called an “extruded face”; SketchUp does not keep any record of what faces were or were not created using the push-pull tool. So either the user will need to select them or you will need to specify some logic to test for what this means.
- How to identify what you mean by “the edge”? A face can have any number of edges.
- Please rephrase and expand on what you mean by “parallel to the face/perpendicular to the edge”. That does not strike me as enough information to determine a unique new edge. For example, if the new line is to start at an existing edge of the face, at what point along that edge?
- Please rephrase and expand on your third sentence (starting with “The first line”). I don’t understand what you mean. How does “going up the blue axis” relate to the parallel/perpendicular requirement? What do you mean by “drawn every 3 meters”?
Hey!
thanks for the reply! I have zero experience with ruby and scripting so I will try my best to explain this with pictures.
For context, I am working on a massing model for an urban design project.
Now, I am tasked to represent every storey for each building. The first storey height is to be 4.5 meters, with every other storey of the building being 3 meters onward.
Example: A 10 storey building - first/ground floor is 4.5 meters, and now the other 9 storey’s above are each 3 meters tall. so 4.5 + 3*9 = 31.5m.

The image shows an example. The faces of each building must show the building storey lines. Currently, I have each building pulled to the required height. Also note how the lines are flush with the building.
If this is still a bit unclear, im really sorry! Ill try again
Your basic goal is now much clearer. Thanks for the images! Based on them, here are some more questions:
- Are the buildings already groups or components (as they really should be)?
- Does the operation only apply to things that have already been extruded to their final height? There are a lot of unextruded faces on the ground as well.
- Can we assume that the as-extruded height of every building fits the (4.5+n*3) forumula? If not, what to do with buildings that don’t?
thanks! i’m glad its clearer!
First, the buildings are not components, unfortunately 
Second, exactly, the operation only applies to things that already has been extruded. Un extruded faces do not apply. Just for context, these unextruded faces are existing buildings or green space. They are not required to be extruded.
Third, every building should be extruded to fit that formula. The only scenario where it might be a problem is if the building height was accidentally pulled to a wrong height that didn’t fit the (4.5+n*3) formula. Although chances of that may be low.
Try cut and paste the following into the SketchUp Ruby Console window (the bottom panel) and let me know if it works. It is wrapped as an undoable operation in case it makes a mess.
module SLB
module Massing
def self.massing
model = Sketchup.active_model
ents = model.entities
horiz_faces = ents.grep(Sketchup::Face).find_all {|f| f.normal == Z_AXIS && f.edges[0].start.position.z != 0}
model.start_operation("massing", true)
horiz_faces.each do |face|
#puts "***** process face #{face} *****"
top_height = face.edges[0].start.position.z
#puts "top height = #{top_height}"
#UI.messagebox("face #{face}, top at #{top_height}")
# TODO: validate the height formula top_height == 4.5 + n * 3.0
corners = face.vertices.uniq.map {|v| v.position}
#puts "corners = #{corners}"
# TODO: use meters explicitly
#puts "first storey 4.5.m"
corners.each {|c| c.z = 4.5.m}
ents.add_edges([corners, corners[0]].flatten!)
#UI.messagebox("added first storey")
storey_height = 7.5.m
while storey_height < top_height
#puts "storey at #{storey_height}"
corners.each {|c| c.z=storey_height}
ents.add_edges([corners, corners[0]].flatten!)
#UI.messagebox("added storey at height #{storey_height}")
storey_height += 3.0.m
end
#puts "***** finished face *****"
end
model.commit_operation
end
end
end
SLB::Massing.massing
3 Likes
Hey!
thank you, certainly on the right direction! 
interestingly, it works on some, but not all. I measured some of the buildings and it meets the required height to meet the formula’s criteria (EX. 10 storey = 31.5m).
That is strange! I deliberately did not test whether the buildings tops matched the criteria, just did as many storeys as would fit in each. Could it be that the tops of those buildings are not flat and horizontal? For example, the left edge of this one looks like it is curved or perhaps has gambrel-like slopes at the edges:

If that is the case, the code probably drew nice storey lines for the horizontal part of the roof, but inside the building where they are not visibile! Could you check by turning on x-ray to see whether there are interior storey edges?
For example, here’s a simple test case I created:
Perhaps fire a ray from the bb.center of the top face (downward) to find the bottom face, and use that bottom face’s vertices (for the copy operation) instead ?
That would fix the problem with mansard-style roofs with sloping edges causing interior lines, but gabled roofs would still be missed because they don’t have any horizontal top face!
I investigated what you suggested and it seems it isn’t the case. I uploaded images for reference:
Also, the none of the buildings have a curvature on the roof, only rounded on the faces (idk if that makes sense). the roof should be flat.
Also, would it be easier if I just gave you the file?
It’s always easier working from a sample file so I can see exactly what you see.
would mediafire work? I can upload over a mediafire link
I’ve never used mediafire, so I would have to check it out. If it is like other web-based file sharing services, it would probably work if you posted a link here.
yep, http://www.mediafire.com/file/qlzrbfooa1s4ugd/Massing_FINAL_ModelwithStoreyLine_Test.skp
I can’t upload it through here due to the file limit.
Also, thank you and everyone who contributed so far! I really appreciate it
Got it! Will take a look.
1 Like
Wow! Amazing coding skills. That really sped up the drawing process. You’re making me want to learn Ruby.
1 Like
Your selected style is masking the fact that the buildings that fail all have reversed exterior faces, that is, the “back” surfaces are oriented outward. You can see this if you set an obnoxious color in the style and choose monochrome:
My code finds the top by looking for a face with its “front” surface facing upward, so it misses all these buildings. You really should fix those reversals, though that could get tedious! I think I can fix the code to tolerate this issue. Give me a few to try it and test…
thats what happens in a group of 6, if it is possible to fix, man…you would be unbelievable. Ill pm you after as well.
Yep, that was the problem:
Here’s the revised version:
module SLB
module Massing
def self.massing
model = Sketchup.active_model
ents = model.entities
up = Z_AXIS
down = Z_AXIS.reverse
horiz_faces = ents.grep(Sketchup::Face).find_all {|f| (f.normal == up || f.normal == down) && f.edges[0].start.position.z != 0}
model.start_operation("massing", true)
horiz_faces.each do |face|
#puts "***** process face #{face} *****"
top_height = face.edges[0].start.position.z
#puts "top height = #{top_height}"
#UI.messagebox("face #{face}, top at #{top_height}")
# TODO: validate the height formula top_height == 4.5 + n * 3.0
corners = face.vertices.uniq.map {|v| v.position}
#puts "corners = #{corners}"
#puts "first storey 4.5.m"
corners.each {|c| c.z = 4.5.m}
ents.add_edges([corners, corners[0]].flatten!)
#UI.messagebox("added first storey")
storey_height = 7.5.m
while storey_height < top_height
#puts "storey at #{storey_height}"
corners.each {|c| c.z=storey_height}
ents.add_edges([corners, corners[0]].flatten!)
#UI.messagebox("added storey at height #{storey_height}")
storey_height += 3.0.m
end
#puts "***** finished face *****"
end
model.commit_operation
end
end
end
SLB::Massing.massing
Edits: fixed single colon in the last line, should have been double. Silly typo!
1 Like