home HinoADO
Menu

#author("2017-11-26T23:28:01+09:00","","")
-[[公式サイト>http://www.sketchup.com/intl/en/developer/?hl=ja]]
#contents
*レイヤ関連 [#e160a11d]
**共通事項 [#xb453a19]
冒頭に

 model = Sketchup.active_model
 layers = model.layers

の記述をお忘れなく。

**レイヤを追加するメソッド [#l98d7905]

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


**アクティブレイヤ(書き込みレイヤ)の変更 [#w28b17fc]

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



**要素を指定レイヤに描画・移動 [#mf0ad97b]

 entities.layer = "レイヤ名"


**レイヤの可視・不可視 [#baac9c75]
不可視化

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


可視化

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


*マテリアル関連 [#y045b208]
**テクスチャマテリアル登録メソッド [#g95475f4]
マテリアル名が既に存在している場合は登録せずに終了する。

   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

**カラーマテリアル登録メソッド [#mc67d0cb]
マテリアル名が既に存在している場合は登録せずに終了する。

   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

**マテリアルを面に適用 [#l9656e30]

   face.material = clr1

裏面は

  face.back_material = clr1

両面に適用する場合は

   face.material = face.back_material = clr1

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

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

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


*コンポーネント [#hf9a808b]

**コンポーネントを選択・尺度 [#ea8fefa6]

   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


**コンポーネントを選択・回転 [#f5c8b640]

   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 を指定する。

**コンポーネントの位置 [#f636c1c4]

  point=tmp.transformation.origin


*編集関連 [#j8d8b54f]

**同一平面のエッジを整理 [#t6d4c1c1]

 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行スクリプト [#j99dc62a]

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


**面の表裏反転 [#q7032249]
面をオブジェクトに格納して
 例:

  face=entities.add_face pt

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

  face.reverse!

で面の表裏を反転。

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

**元図の消去 [#t019a99d]
メソッドの最後に

  entities.erase_entities ss


**ソフトニング [#e736e6a1]

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

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

**グループ化 [#lee45af6]
冒頭に

 model = Sketchup.active_model

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

 entities=model.active_entities.add_group.entities

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

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

**エラー処理 [#p1928efe]

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


*モデリング系 [#df0201bb]

**PushPull [#yaa167a1]
上記と同様に

  face=entities.add_face pt

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

  face.pushpull 100.cm

でプッシュプル完了。

**面を張る一行スクリプト [#ddda47d8]
所謂make_faceのようなもの

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

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

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

  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


**線 [#ka79f86a]

  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らしくて良い気がする。

**円 [#d5051ae8]

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

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

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

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

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

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

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

  face.followme line

で完了

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


*その他 [#f6cbb1e9]

**最初に書くこと [#ne799678]
まずは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無し)にしておくと日本語が文字化けしない

**透かし文字を配置する [#nabb7981]

  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で使いたい。

**メッセージボックスあれこれ [#g1eb1b57]
詳細は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 [#j6522965]
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();'」。ここでファンクションを返す。

**ステータスバーメッセージ [#u8c018bb]

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


**1行InputBox [#f8d17489]

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


**単位 [#efb0a95a]

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

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

  foo=2.cm
  hoo=20.mm

と記述する。

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

**アンドゥ制御 [#h20cba19]

  model.start_operation "******"

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

  model.commit_operation

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

**FaceからEdgeを取得 [#r2866d78]

  edges = face.edges

以上で格納完了。

  for outline in edges
  end

で全てを呼び出せる。

**要素を隠す [#t32d5ec9]

   status = ss[lines].hidden = true

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

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

**面の複製 [#r8de3806]

ここでは「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

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

**線に接する面の数 [#y1175f2a]

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

  a=line.faces.length

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


* Ruby基本 [#za493538]

**実数 [#oc6aceae]

 .to_f


**整数 [#fafa29a2]

 .to_i


**classを設定する [#z4476fdb]

スクリプト先頭で

  class hoge
  .
  .
  end


**変数 [#f823983f]

  $hoge

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

**n乗 [#m17b1e63]

  x--n

でxのn乗

**三角関数 [#cc1302f4]

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

など。 詳しくは[[こちら>http://www.ruby-lang.org/ja/man/?cmd=view;name=Math]]

**乱数 [#d8f68fce]

  a = rand

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

  a = rand(100)

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

**値を入れ替える [#z6ed4e30]

  a , b = b , a


** [#y8e00188]

*関数系 [#o3420fcb]
**線分の角度を求める [#o6908a58]

  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平面上での角度が求められる。

**点と点の距離 [#nc919d52]

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


**2次元ベクトルの延長点 [#l418a42b]
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



**線端点からの鉛直点 [#xf9f844f]
※方向は制御し難い

   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


**点と線分の距離 [#a394d195]

   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


*ファイル系 [#c20d2f4b]
**ファイルを開いて処理して閉じる [#aca51c83]

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

**ファイルに書きこむ [#of4bd6b6]

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

**フォルダ名を取得する [#s133cc85]

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


*属性辞書 [#l90e5c48]
**基本的な使い方 [#ef7d50d8]

  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で再現する問題 [#x816a1fa]
中身が空でタイトルだけのdictionaryを作成したファイルは二度と開けないもよう