最近家の棚を全部自作してるんですが、SketchUpで3Dモデルを作るまでは楽しいものの、出来上がったモデルを構成する木の寸法やら枚数のリストを作るのが面倒になりました。のでRubyプラグインで作ってみました。ちなみにRubyを書いたのは人生で2度目くらいなのでしょうもない書き方している可能性大ですが、ご自由にお使いください。
Sketchupでのプラグインの使い方は本家の解説ページを見れば分かりますが、4行でまとめると以下の通りです。
- rbファイルをSketchUp所定のフォルダに入れる
- SketchUpを起動し、適当な.skpファイルを開く
- メニューのウィンドウ>Rubyコンソールを開く
- rbファイルに定義している関数をタイプする(下のスクリプトの場合はcuboidlistとタイプする)と結果がもらえる
モデル内の直方体をサイズ毎に集計して表示するスクリプト
def cuboidlist
model = Sketchup.active_model
# モデル中の直方体を再起的に発見して種類ごとにまとめる
printf("[finding]\n")
cuboids = findCuboids(model) # モデル中の全直方体をリストアップする
cuboids.sort! # ソートを追加
cuboidSet = {}
cuboids.each_with_index do |cuboid, c|
printf(" cuboid #%02d %s\n", c, sizestr(cuboid))
# 同一形状でカウントする
if cuboidSet[cuboid] == nil then
cuboidSet[cuboid] = 1
else
cuboidSet[cuboid] += 1
end
end
# 結果の表示
printf("[summary]\n")
cuboidSet.each_with_index do |(cuboid, count), c|
printf(" cuboid #%02d %s * %d\n", c, sizestr(cuboid), count)
end
return cuboidSet
end
def findCuboids(container)
cuboids = []
# 現在のcontainerにfaceが6枚あれば、それが直方体かどうかをチェックする
cuboid = faces2cuboid(getTypes(container, Sketchup::Face))
if cuboid!= nil then
cuboids << cuboid
end
# 現在のcontainerの下にgroupがあれば、それを探索する
getTypes(container, Sketchup::Group).each_with_index do |subgroup, g|
cuboids.concat(findCuboids(subgroup))
end
# 現在のcontainerの下にcomponentがあれば、それを探索する
getTypes(container, Sketchup::ComponentInstance).each_with_index do |cmp, g|
cuboids.concat(findCuboids(cmp.definition))
end
return cuboids
end
def faces2cuboid(faces)
# 直方体の条件: faceが6枚, 全edgeの長さは1or2or3通りであること
if faces.length != 6
return nil
end
# 辺を探索して長さ->出現回数の辞書を作成する
# これが1通り24個 = 立方体, 2通り8,16個 = 正方形直方体, 3通り8,8,8個 = 一般の直方体
edges = {} # 長さ -> 出現数
faces.each_with_index do |face, f|
face.edges.each_with_index do |edge, e|
length = (edge.length * 25.4).round # inch->mili
# 辺長さ辞書に追加する
if edges[length] == nil then
edges[length] = 1
else
edges[length] += 1
end
end
end
if (edges.length.between?(1,3)) then
# 直方体の3辺の長さのリストを作る
cuboid = []
edges.each{|length, count|
for num in 0...(count / 8) do
cuboid << length
end
}
return cuboid.sort()
else
return nil
end
end
def getTypes(container, type)
# sketchupのcontainerから特定タイプのentityをリスト形式で取り出す
ret = []
for g_ent in container.entities do
if g_ent.kind_of?(type) then
ret << g_ent
end
end
return ret
end
def sizestr(cuboid)
return sprintf("[%4d, %4d, %4d]", cuboid[0], cuboid[1], cuboid[2])
end
実行例
最終的にこんなリストが得られます。後はこのリストをもとに木取り図まで自動で作れたら完璧なんですが、それは未完です。
[summary]
cuboid #00 [ 4, 71, 400] * 26
cuboid #01 [ 15, 71, 150] * 18
cuboid #02 [ 4, 158, 400] * 9
cuboid #03 [ 24, 300, 315] * 3
cuboid #04 [ 15, 71, 230] * 8
cuboid #05 [ 4, 238, 400] * 4
cuboid #06 [ 15, 300, 480] * 3
注意点
- 面6枚をグループ化/コンポーネント化したものだけを抜粋します。三角柱など6面でないものは無視されます。
- 直方体かどうかの判定に「辺の長さが1or2or3種類だったら直方体」という適当ルールを用いているので、平行四辺形の柱などがあるとその辺の長さをもつ直方体として認識されます。
- グループやコンポーネントにした後で拡大縮小をしていると表示されるサイズが正しくないようです。一度グループ化を解除するなどしてどの面も後から拡大縮小をされていない状態にすれば正しい数値が出ます。
- 単位はミリメートルです(内部データがインチ単位っぽいので×25.4しています)。
書き換えてリロードする場合は
例えば上のスクリプトをtest.rbという名前でpluginフォルダに入れていた場合、SketchUpのRubyコンソールで
load "test.rb"
とすれば最新の状態をリロードしてくれるようです。