I decided to delve into the scripting aspects of Sketchup to see if it would be possible to build a dynamically generated stone structure. What a large "can o' worms" it has turned out to be! Not only do I not have experience programming in Ruby, the scripting language of Sketchup, but I have never had to program in three-dimensions. Ruby is not like any language I have used before, sure the functions are the same but the syntax is completely foreign to me. It will take some time to learn it and understand its capabilities. I am still trying to wrap my mind around programming in three-dimensions...I could almost smell the smoke from the gears churning in my brain as I pondered it ;-)
I decided to start out simple by creating a box based on user input. This worked well and was relatively easy to code. Initially I thought I would just build a wall and place a "stone-like" mesh over top of it; but I thought it might look more authentic if I actually built each stone individually. After banging away on the keyboard for a bit I eventually figured it out.
Basically the script grabs the user input (wall length, stone height, stone depth, and whether or not to group the final product), and builds the wall to the users specifications. I wanted to give the stones a more natural feel, so I decided to randomly generate each block size while remaining within the length constraints. This proved the most difficult. I came up with a preliminary solution, but it's not really where I want it to be. As the code generates random stone sizes it keeps a running total length of all the blocks. If the final block created turns out to be too large, it then subtracts the total length from the user-input length and builds a stone based on the remainder. I tried to just loop through until it generated a stone that was the exact size, but ended up locking the program up completely. I have a few ideas about how to fix it but I will have to revisit it another time.
It is still quite rudimentary, but I feel I have learned quite a lot already!
Future challenges include: building the wall up on the y axis, creating a rectangular structure with the walls, and generating Bézier curves on all edges to give it a more natural look.
I pasted the code below if anyone is interested in checking it out.
To use the code:
1) copy the text into notepad (not word or wordpad) or, preferably notepad++(
http://notepad-plus.sourceforge.net/uk/site.htm)
2) save file as stone_wall.rb in c:\\program files\google\sketchup 7\plugins
3) open sketchup
4) under the "Windows" menu, select Ruby Console
5) in the command prompt type: load 'stone_wall.rb'
6) hit enter
7) under the draw menu, select "Stone Wall"
8) enter the dimensions and press enter
I didn't comment the code...if you are interested in understanding what it does feel free to comment. Enjoy
++++++++++Copy Code Below++++++++++++++
# Build Stone Wall - Andrew Kimball
# ANTH-258
# 9/27/09
#-----------------------------------------------------------------------------
require 'sketchup.rb'
#-----------------------------------------------------------------------------
# This script will build a stone wall
def create_stone_wall
prompts = [$exStrings.GetString("Wall Length"), $exStrings.GetString("Stone Height"), $exStrings.GetString("Wall Depth"), "Grouped?"]
values = [5.feet, 1.feet, 1.feet, "Yes"]
grouped_yn = ["", "", "", "Yes|No"]
results = inputbox prompts, values, grouped_yn, $exStrings.GetString("Stone Dimensions")
return if not results
width, height, depth, grouped = results
model = Sketchup.active_model
model.start_operation $exStrings.GetString("Create Stone")
entities = model.active_entities
if grouped == "Yes"
group = entities.add_group
entities = group.entities
end
initial_stone = 0
total_width = 0
a = [9.inch,10.inch,11.inch,12.inch,13.inch,14.inch,15.inch,16.inch,17.inch,18.inch]
while total_width < width
block_width = a[rand(a.length)]
if total_width+block_width > width
model.commit_operation
final_width = width - total_width
#UI.messagebox(final_width)
ptsf = []
ptsf[0] = [total_width, 0, 0]
ptsf[1] = [total_width+final_width, 0, 0]
ptsf[2] = [total_width+final_width, depth, 0]
ptsf[3] = [total_width, depth, 0]
base = entities.add_face ptsf
height = -depth if( base.normal.dot(Z_AXIS) < 0 )
base.pushpull height
model.commit_operation
break
else
if initial_stone==0
pts = []
pts[0] = [0, 0, 0]
pts[1] = [block_width, 0, 0]
pts[2] = [block_width, depth, 0]
pts[3] = [0, depth, 0]
base = entities.add_face pts
initial_stone=1
else
ptsa = []
ptsa[0] = [total_width, 0, 0]
ptsa[1] = [total_width+block_width, 0, 0]
ptsa[2] = [total_width+block_width, depth, 0]
ptsa[3] = [total_width, depth, 0]
base = entities.add_face ptsa
end
height = -depth if( base.normal.dot(Z_AXIS) < 0 )
base.pushpull height
total_width=total_width+block_width
end
end
model.commit_operation
end
if( not file_loaded?("stone_wall.rb") )
# Add seperator to the Menu
add_separator_to_menu("Draw")
# Add the "Stone"
UI.menu("Draw").add_item($exStrings.GetString("Stone Wall")) { create_stone_wall }
end
#-----------------------------------------------------------------------------
file_loaded("stone_wall.rb")
++++++++++++++++++++++Copy Code Above+++++++++++++++