home HinoADO
Menu

レイヤ関連

共通事項

冒頭に

model = Sketchup.active_model
layers = model.layers

の記述をお忘れなく。

レイヤを追加するメソッド

  def add_layer(layer_name)
    layers = Sketchup.active_model.layers
    layers.add layer_name unless layers.include?(layer_name)
  end #def

アクティブレイヤ(書き込みレイヤ)の変更

model.active_layer = layers["レイヤ名"]

要素を指定レイヤに描画・移動

entities.layer = "レイヤ名"

レイヤの可視・不可視

不可視化

layers["レイヤ名"].visible = false

可視化

layers["レイヤ名"].visible = true

マテリアル関連

テクスチャマテリアル登録メソッド

マテリアル名が既に存在している場合は登録せずに終了する。

  def add_textured_material(material_name ,texture_file ,texture_size ,alpha)
    materials = Sketchup.active_model.materials
    check = false
    for mt in materials
      check = true if material_name == mt.name
    end #for
    if check == false
      material = materials.add material_name
      material.texture = texture_file
      material.texture.size = texture_size
      material.alpha = alpha
    end #if
  end #def

カラーマテリアル登録メソッド

マテリアル名が既に存在している場合は登録せずに終了する。

  def add_color_material(material_name ,r ,g ,b ,alpha)
    materials = Sketchup.active_model.materials
    check = false
    for mt in materials
      check = true if material_name == mt.name
    end #for
    if check == false
      material = materials.add material_name
      material.color=Sketchup::Color.new [ r , g , b ]
      material.alpha = alpha
    end #if
  end #def

マテリアルを面に適用

  face.material = clr1

裏面は

 face.back_material = clr1

両面に適用する場合は

  face.material = face.back_material = clr1

マテリアル名がskp内に定義されていない場合はエラーで停止する。

全てのマテリアルに対してテクスチャを色に変更してファイルサイズを軽くする一行メソッド

  def materials_to_colors
    Sketchup.active_model.materials.each{|tmp|tmp.texture=nil}
  end #def

コンポーネント

コンポーネントを選択・尺度

  def flip_component
    model = Sketchup.active_model
    entities = model.active_entities
    ss = model.selection
    for tmp in ss
      if tmp.typename=="ComponentInstance"
        point=tmp.transformation.origin
        transform = Geom::Transformation.scaling point,-1,-1,1
        tmp.transform!(transform)
      end # if
    end # of for
  end # of def

コンポーネントを選択・回転

  def turn_component
    model = Sketchup.active_model
    entities = model.active_entities
    ss = model.selection
    for tmp in ss
      if tmp.typename=="ComponentInstance"
        point=tmp.transformation.origin
        vector = Geom::Vector3d.new 0,0,1
        transform = Geom::Transformation.rotation point,vector,3.14159265
        tmp.transform!(transform)
      end # if
    end # of for
  end # of def

上記の vector は回転軸。

平面上で回転させる時はZ軸となる Vector3d を指定する。

コンポーネントの位置

 point=tmp.transformation.origin

編集関連

同一平面のエッジを整理

erase_coplanar_edges改
  planer_edge = []
    for tmp in entities
    if tmp.typename=="Edge" && tmp.faces.length==2 
      if tmp.faces[0].material == tmp.faces[1].material && tmp.faces[0].normal == tmp.faces[1].normal
        planer_edge.push(tmp)
      end
    end
  end
  for tmp in planer_edge
    tmp.erase!
  end

モデルと交差_1行スクリプト

  entities.intersect_with(true,[0,0,0],entities, [0,0,0],true,entities.collect)

面の表裏反転

面をオブジェクトに格納して

例:
 face=entities.add_face pt

このfaceオブジェクトに対して

 face.reverse!

で面の表裏を反転。

  • 「!」は破壊的メソッドの宣言用フッタ

元図の消去

メソッドの最後に

 entities.erase_entities ss

ソフトニング

      for j in entities
        if j.typename=="Edge"
          j.soft=true
          j.smooth=true
        end#if
      end # for

みたいな感じ。
softだけではエッジが消えるだけでスムージングはされない。
smoothとセットで使うといわゆるソフトニング効果。

グループ化

冒頭に

model = Sketchup.active_model

と記述してアクティブモデルを「model」に格納してあるとして。

entities=model.active_entities.add_group.entities

と書いた以降に生成されるエンティティはグループ化される。
今のところグループの階層化のやりかたは不明。
数カ所に上記コードを入れた場合は各々が別々にグループ化される。

注意
要素をP&Pで立体化する際、複数の条件で正負が決定されているようだが、これの規則が要素毎のグループ化で乱れてしまう。
これを制御するためにはP&Pではなく、ベクトルを具体的に指定できるFollwMeを使用する以外にはなさそうだ。

エラー処理

begin
+対象の処理
rescue
+エラー処理
end

モデリング系

PushPull

上記と同様に

 face=entities.add_face pt

としてptオブジェクトから構成された面をfaceオブジェクトに格納して

 face.pushpull 100.cm

でプッシュプル完了。

面を張る一行スクリプト

所謂make_faceのようなもの

 entities.each {|tmp| tmp.find_faces if tmp.typename == "Edge"}

面の構成

座標の追い掛けは線と同様だが、同一平面上にないとエラーが出て処理中断

コードは上記の線を書く場合とほぼ同じで

 entities.add_face pt

でOK

幾つかの面構成パターーン

  def add_vert_square_face(z1,z2,x1,y1,x2,y2,mat)
    +垂直な矩形の面
    pt=[]
    pt<<[ x1 , y1 , z1 ]
    pt<<[ x1 , y1 , z2 ]
    pt<<[ x2 , y2 , z2 ]
    pt<<[ x2 , y2 , z1 ]
    face = Sketchup.active_model.active_entities.add_face pt
    face.material=face.back_material=mat
  end#def
  def add_horiz_face(z,x1,y1,x2,y2,x3,y3,x4,y4,mat)
    +水平な面
    pt=[]
    pt<<[ x1 , y1 , z ]
    pt<<[ x2 , y2 , z ]
    pt<<[ x3 , y3 , z ]
    pt<<[ x4 , y4 , z ]
    face = Sketchup.active_model.active_entities.add_face pt
    face.material=face.back_material=mat
  end#def
  def add_slant_face(z1,z2,x1,y1,x2,y2,x3,y3,x4,y4,mat)
    +傾斜面
    pt=[]
    pt<<[ x1 , y1 , z1 ]
    pt<<[ x2 , y2 , z1 ]
    pt<<[ x3 , y3 , z2 ]
    pt<<[ x4 , y4 , z2 ]
    face = Sketchup.active_model.active_entities.add_face pt
    face.material=face.back_material=mat
  end#def

上の2つを組み合わせてボックス生成

  def add_box(z1,z2,x1,y1,x2,y2,x3,y3,x4,y4,mat)
    +箱
    add_horiz_face(z1,x1,y1,x2,y2,x3,y3,x4,y4,mat)
    add_horiz_face(z2,x1,y1,x2,y2,x3,y3,x4,y4,mat)
    add_vert_square_face(z1,z2,x1,y1,x2,y2,mat)
    add_vert_square_face(z1,z2,x3,y3,x2,y2,mat)
    add_vert_square_face(z1,z2,x3,y3,x4,y4,mat)
    add_vert_square_face(z1,z2,x1,y1,x4,y4,mat)
  end#def

 i=0;pt=[]
 x=-;y=*;z=*
 pt[i]=[x,y,z];i=i+1
 x=*
 pt[i]=[x,y,z];i=i+1
 y=*
 pt[i]=[x,y,z]
 entities.add_line pt

で線。座標はいくつでも可。

↑この書き方がメジャーなのかと思って使っていたけど

 pt=[]
 x=-;y=*;z=*;pt<<[x,y,z]
 x=-;pt<<[x,y,z]
 y=-;pt<<[x,y,z]
 entities.add_line pt

という記述でも構わない。

セミコロンを使うのはケースバイケースとして、要素数を数える必要がない時にはこちらの方がシンプルかつRubyらしくて良い気がする。

 entities.add_circle(pt, Z_AXIS, 2.cm, 16)

左から・中心座標,鉛直な軸,半径,演習分割数

このままでは円の輪郭のみ

 circle = entities.add_circle($ptz, Z_AXIS, 2.cm, 16)

で格納してあとは面を張るなりそれをPushPullするなり

'既存face上に描いたcircleは、faceとしての取り扱いがうまくいかないっぽい''

FollowMe

線又はエッジに沿って立体を構成するので
仮に線を「line」面を「face」とすると

 face.followme line

で完了

'followmeはlineではうまくいかないことが多いのでEdgeを使う''

その他

最初に書くこと

まずはSketchUpのRubyを宣言

  require 'sketchup.rb'

取り扱うデータの宣言として

  model=Sketchup.active_model

アクティブなエンティティを流用するために

  entities=model.active_entities

マテリアルを使うとき

  materials = model.materials

ビュー系を使うとき

  view =model.active_view

レイヤを使うとき

  layers = model.layers

選択要素を参照するとき(下記ではssに選択要素を格納)

  ss = model.selection
  for tmp in ss
  end#of for
  • 保存時に文字コードをUTF-8(BOM無し)にしておくと日本語が文字化けしない

透かし文字を配置する

 model = Sketchup.active_model
 + Add a note 1/10 ways down the screen and 1/10 ways right from the
 + upper left corner of model window.
 note = Sketchup.active_model.add_note "Hello World", 0.1, 0.1

座標はx,yの順。各値はウィンドウサイズを基準に01。
文字側の基点は左中。JWWで言うと「3」
程良い左上なら

note = Sketchup.active_model.add_note "Hello World", 0.02, 0.04

ぐらい。
レイヤを指定するなら

  note = Sketchup.active_model.add_note "Hello World", 0.02, 0.04
  note.layer="RSlayers_radio_1"

で可。RSlayersで使いたい。

メッセージボックスあれこれ

詳細はhttp://code.google.com/intl/ja/apis/sketchup/docs/ourdoc/ui.html

 result = UI.messagebox "Do you like cheese?", MB_YESNO
 if result == 6 # Yes
   UI.messagebox("Sketchup likes cheese, too.")
 end

でYes,Noの返事待。

WebDialog

rbファイルで起動したhtmlダイアログはSUの制御下に置かれる。
htmlダイアログ内で操作された情報はjavascriptのfunctionを介して自身を呼び出したrbに送られる。
rbはadd_action_callbackで情報を受け取り、情報ごとに定義されたメソッドを実行する。

rbでは

    dlg.add_action_callback('RS_layer_check1') {|d,p|RSlayers.new.RS_layer_check1}

として「RS_layer_check1」というコールバックを受けて「RSlayers.new.RS_layer_check1」というメソッドを実行するように指定。

htmlでは

<script>
function RS_layer_check1() {window.location = 'skp:RS_layer_check1';}
</script>

というようにhead部分にscriptタグで囲んで定義。
上記では「RS_layer_check1()」というファンクションで「 'skp:RS_layer_check1'」としてSUに「RS_layer_check1」を渡している。
上記例ではファンクションとコールバックの名前が「RS_layer_check1」で同じだが、同一である必要はなし。
ファンクションを実行するためのフォームは、チェックボックスで例えると

<input type="checkbox" id="ch1"  onClick='RS_layer_check1();' checked><label for="ch1">外構 </label>

で、肝心なのは「onClick='RS_layer_check1();'」。ここでファンクションを返す。

ステータスバーメッセージ

statusbar_message = Sketchup.set_status_text "メッセージ"

1行InputBox

  num=UI.inputbox(["先頭の数字を指定"],[$number],"StereoGram")[0]

単位

デフォルトで数値を記入するとインチになる。

よってmmやcm等を使う場合には

 foo=2.cm
 hoo=20.mm

と記述する。

分割ダイアログ

ダイアログは二段構えで組めた。
RS階段では金物手摺を描くフラグを設定していたので、そのフラグ(金物手摺の高さがゼロより大)の場合だけ金物手摺の設定ダイアログが開くようにした。
デフォルトデータの受け渡し部分の記述に注意が必要だと感じてる。
XGAでは入力ボックスが19個で縦方向のピクセルサイズが760程度になるのでこれ以上は分岐する事。

アンドゥ制御

 model.start_operation "******"

をアンドゥ制御の始点に記述し、

 model.commit_operation

をアンドゥ制御の終点に記述。

FaceからEdgeを取得

 edges = face.edges

以上で格納完了。

 for outline in edges
 end

で全てを呼び出せる。

要素を隠す

  status = ss[lines].hidden = true

要注意:ここで指定できるのは単一のEntityであること。

複数のEntityは出来ないっぽい。

面の複製

ここでは「ss[i]」で選択要素を格納している

  if( ss[i].typename == "Face" )
    getface=[]
    ss[i].vertices.each {|p| 
      getface << p.position + [0,0,takasa]
    }
    face=entities.add_face getface
    face.material = face.back_material = clr0
  end

最後の方では表裏に色を塗っている為ここは無くても良し。

線に接する面の数

lineにEdgeが格納されているとして

 a=line.faces.length

でaにFaceの数が格納される

Ruby基本

実数

.to_f

整数

.to_i

classを設定する

スクリプト先頭で

 class hoge
 .
 .
 end

変数

 $hoge

はグローバル関数。SUが再起動するまで継承される。
使いすぎるのはよろしくないもよう。

n乗

 x--n

でxのn乗

三角関数

 Math.sin(n)
 Math.cos(n)
 Math.tan(n)

など。 詳しくはこちら

乱数

 a = rand

で0~1未満の実数を返す。

 a = rand(100)

で0~100未満までの整数を返す。

値を入れ替える

 a , b = b , a

関数系

線分の角度を求める

 ss = model.selection
 for outline in ss
   if outline.typename == "Edge"
     p1 = outline.start.position
     p2 = outline.end.position
     angle = Math.atan2(p2.y-p1.y,p2.x-p1.x)
   end # of if
 end

これが基本。y/x のアークタンジェントを ラジアン[-π, π] の範囲で返す組み込み関数。

ss[i]にエッジが格納されていたとして、両端点の座標を取得するには

 pts = ss[i].vertices
 p1 = pts[0].position
 p2 = pts[1].position

又は

 p1=ss[i].start.position
 p2=ss[i].end.position

と記述。この2点から角度を求めるためにp1座標を原点に変換し、atan2に流し込む。

 Math.atan2(p2.y-p1.y,p2.x-p1.x)

これでXY平面上での角度が求められる。

点と点の距離

  p1 = Geom::Point3d.new 1,1,1
  p2 = Geom::Point3d.new 10,10,10
  d = p1.distance p2

2次元ベクトルの延長点

P1(x1,y1),P2(x2,y2)からなる線分のP2端からex延長した点P3(x3,y3)

      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      x3=x1+ex*(x1-x2)/vl)
      y3=y1+ex*(y1-y2)/vl)

P1からの延長点は

      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      x3=x1+ex*(x2-x1)/vl)
      y3=y1+ex*(y2-y1)/vl)

メソッド化

  def get_extend_point_x(x1,y1,x2,y2,ex)#p1延長
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return x1+ex*(x2-x1)/vl
  end #def
  def get_extend_point_y(x1,y1,x2,y2,ex)#p1延長
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return y1+ex*(y2-y1)/vl
  end #def

複数の戻り値を配列で返す

  def get_extend_point(x1,y1,x2,y2,ex)#p1延長
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return x1+ex*(x2-x1)/vl,y1+ex*(y2-y1)/vl
  end #def

線端点からの鉛直点

※方向は制御し難い

  def get_vert_point_x(x1,y1,x2,y2,ex)
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return x1+ex*(y2-y1)/vl)
  end #def
  def get_vert_point_y(x1,y1,x2,y2,ex)
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return y1-ex*(x2-x1)/vl)
  end #def
  def get_vert_point_x2(x1,y1,x2,y2,ex)
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return x1-ex*(y2-y1)/vl)
  end #def
  def get_vert_point_y2(x1,y1,x2,y2,ex)
      vl=Math.sqrt((x2-x1)**2+(y2-y1)**2)
      return y1+ex*(x2-x1)/vl)
  end #def

点と線分の距離

  def get_distance_p_l(xx, yy, x1, y1, x2, y2)
    dx = (x2 - x1)
    dy = (y2 - y1)
    a = dx**2 + dy**2
    b = dx * (x1 - xx) + dy * (y1 - yy)
    t = -b / a
    t = 0 if t < 0
    t = 1 if t > 1
    tx = x1 + dx * t
    ty = y1 + dy * t
    distance = Math.sqrt((xx - tx)**2 + (yy - ty)**2)
    return distance
  end #def

ファイル系

ファイルを開いて処理して閉じる

  File::open("index.html") {|f|
    while line = f.gets
      print line
    end
  }

ファイルに書きこむ

  foo = File.open("foo.txt",'w')
  foo.puts 'bar'
  foo.close

フォルダ名を取得する

File.dirname("/usr/local/bin/ruby") #=> "/usr/local/bin"

属性辞書

基本的な使い方

 model = Sketchup.active_model
 value = model.set_attribute "testdictionary", "test", 115

上記では「testdictionary」という辞書のカテゴリを作成し、「test」という項目に「115」という値を与えている。

 attrdicts = model.attribute_dictionaries
 attrdict = attrdicts["testdictionary"]

「attrdicts」にモデル内の属性辞書を格納し、「attridict」に「testdictionary」を格納している。

value = attrdict["test"]

「testdictionary」内の「test」の値を取得。

SU7.1で再現する問題

中身が空でタイトルだけのdictionaryを作成したファイルは二度と開けないもよう