レコードフォーマットの名前とレコードフィールドの取得

ホーム フォーラム マリオネット レコードフォーマットの名前とレコードフィールドの取得

  • このトピックには4件の返信、2人の参加者があり、最後にs_ryoにより2ヶ月前に更新されました。
3件の返信スレッドを表示中
  • 投稿者
    投稿
    • #10941
      s_ryo
      参加者

      お世話になります。いつも御社BLOGで
      楽しく学ばせてもらっております。

      さて、この度BIMを本格的に学ぶにあたり、
      その環境作りが重要かと思うにいたりました。

      そこで、各種データを表計算ソフトでも
      管理できるようにしようと考え、今まで扱ったことのない
      マリオネット(あるいはVS)に着目しました。
      (最終的にはフォーラムにて有志が作成したWS系を扱うオリジナルノードを用いて
      外部出力を試みるつもりです。)

      ノードリファレンスを一通り見たところ、本題のレコードフォーマットの名前
      とレコードフィールドの取得に関するノードが見つからなかったので、
      VS:GetFldNameを利用しノードをカスタマイズしようと考えております。

      Get class listノードのようにSeriesノードからリスト
      を作成すると自動的にレコードフォーマットの名前を取得するかと
      思ったのですが、取得する値が”不明な値”となりうまくいきません。

      レコードフォーマット群の名前とレコードフィールドを取得する上手い
      方法はないでしょうか?

      よろしくお願いいたします。

      <以下GetFldNameを用いた自作ノードのpythonコードです>

      #Modified by MFarrell May 2017
      @Marionette.NodeDefinition
      class Params(metaclass = Marionette.OrderedClass):
      #APPEARANCE
      #Name
      this = Marionette.Node( 'Get Fld Name' )
      this.SetDescription( 'レコードフィールドの名前を返します。' )#説明

      #Input Ports
      input = Marionette.PortIn( 'index' )
      input.SetDescription( 'レコードフィールド番号(1からnの範囲)' )#説明

      #OIP Controls

      #Output Ports
      output = Marionette.PortOut('s_FName')
      output.SetDescription( 'Get Fld Name' )#説明

      #BEHAVIOR

      def RunNode(self):
      #libraries
      import operator

      #inputs
      input = self.Params.input.value

      #script
      s_FName = vs.GetFldName('index')
      #return STRING

      #outputs
      self.Params.output.value = s_FName

    • #10942
      木原 和信
      参加者

      s_ryo様

      いつもお世話になっております。エーアンドエー研究開発部です。

      マリオネットご活用いただきありがとうございます。ノードのカスタマイズにも挑戦されているとのことで大変嬉しく思います。

      VectorworksでのBIMではレコードの活用が必要不可欠なものとなります。プログラムでレコードの管理を自動化することによって、VectorworksのBIMをより強力することができますが、ご存知の通りマリオネットではレコードフォーマットを含めリソース関連のノードが充実していません。

      レコードフォーマット群の名前とレコードフィールドを取得する方法

      については、やはり自作のノードを作成する必要があります。

      1. フィールド名の一覧の取得

      s_ryo様が作成された自作ノードをベースに考えます。指定したレコードフォーマットに含まれるフィールドの名前を1つ取得する場合、GetFldName関数を使用します。GetFldNameには引数を2つ用意する必要があります。

      • 第1引数:レコードフォーマットのハンドル
      • 第2引数:フィールドの番号

      まずは、レコードの名前を入力するためのポートを追加します

      #Input Portsの中に追加
      recName = Marionette.PortIn( '', 'sRecName' )

      レコードのハンドルとフィールドの番号がGetFldNameに渡るように修正します。

      s_FName = vs.GetFldName('index')

      ↓↓↓

      h_RecHandle = vs.GetObject( recName ) #名前からハンドルを取得します
      
      s_FName = vs.GetFldName( h_RecHandle, index )

      2. レコードフォーマットの名前の取得

      レコードフォーマットの名前の取得については少し考える必要があるかもしれません。プログラムを書けばドキュメントに含まれるすべての「レコードフォーマット」の一覧を取得することができますが、その中にはプラグインオブジェクト固有のフォーマットなど管理したくないものまで含まれてしまいますので、管理がより面倒になる可能性があります。

      おすすめの方法としては、ワークシート等に管理したいレコードフォーマット名の一覧を記録しておき、ワークシートから名前を取得して利用するというやり方です。

      ワークシートから値を取得する場合はGet Cell Value(Get Cell String)ノードが利用できます。

      やはり、すべてのレコードを動的に取得したいという場合は以下のpythonコードを参考にされてください。

      kTypeRec = 47
      folderIndex = 0 #アクティブファイル
      subFolderName = ''
      listID,numItems = vs.BuildResourceList( kTypeRec, folderIndex, subFolderName)
      recNameList=[]
      for ii in range( numItems ):
          rechandle = vs.GetResourceFromList( listID,ii+1 )
          recNameList.append( rechandle.name )
      print( recNameList )

       

      以上となります。ご参考になれば幸いです。

    • #10979
      s_ryo
      参加者

      返信いただきましてありがとうございます。

      おかげさまでレコード名の取得について、
      いただいたコードで実装ができました。

      不要なレコード名まで取り込んでしまいますが、
      そこは直接WSを編集するということで良しとしました。

      + + + + + + + + + + + + + + + +
      レコード名が無事に取得できたので、
      最終目標である各レコード名に紐ずくレコードフィールド値を取得し、
      SetWSCellFormulaNを用いてWSに書き込もうと考えております。

      ノードを用いたリスト型データの一括処理に関してどのようなデータの挙動をするか、
      確信が持てなかったので、リスト型のデータはthis.SetListAbsorb()を設定することで、
      繰り返し処理については純粋にpythonスクリプト内で行うことを目指しました。

      コード設計としては、
      レコード名を入れたリスト型の変数recNamesをfor文に渡します。
      レコード名ごとに各レコードフィールド値を取得するためにさらにfor文をネストし、
      indexごとに1づつ取り出します。

      enumerate関数を使って各リストの要素と繰り返しの順番を示す変数iを設定しました。
      変数iはSetWSCellFormulaN関数の際にループごとに値をセットするために使用しています。

      下記のようなコードとしましたが、アップロードしたpdfの実行結果のように
      うまくレコードフィールド値をWSに記載できずにおります。

      細かな箇所をマイナーチェンジして試すもうまくいかず
      正直手詰まりの状況です。。。

      どこかバグが生じている箇所や考え方が間違っている箇所等
      ヒントをいただけますと大変助かります。

      
      @Marionette.NodeDefinition
      class Params(metaclass = Marionette.OrderedClass):
      #APPEARANCE
      	#Name
      	this = Marionette.Node( 'Get Fld Name ver2' )
      	#Input Ports  
      	recNames = Marionette.PortIn('', 'sRecNames')
      	worksheet = Marionette.PortIn(None)
      
      	#Output Ports
      	#output = Marionette.PortOut('s_FName')	
      
      	#BEHAVIOR
      	this.SetListAbsorb()
      	
      def RunNode(self):
      	#inputs
      	recNames=self.Params.recNames.value
      	worksheet=self.Params.worksheet.value
      
      	#script
      	index=[1,2,3,4,5,6] #レコードフィールド値の最大個数分を手動でリストに入れます。
      	for h,recName in enumerate(recNames): 
      
      '''#レコード名をリストから1つづつ取り出し。WSに書き込むための繰り返し回数を取得したいのでpython組み込み関数のenumerateを使用'''
      
      		for i in index :#'レコード名の各レコードフィールド値を1つづつ取り出す準備。
      			h_RecHandle = vs.GetObject( recName )  #レコード名からハンドルを取得
      			Field_Name = vs.GetFldName( h_RecHandle, i)#i番目のレコードフィールド値を取得
      			vs.SetWSCellFormulaN(worksheet, i+1, h , i+1, h , Field_Name)	
              #変数hはレコード名を取り出した回数、iはレコードフィールド値を取り出した回数。
               上記を利用して、WSに記載するセル番地を指定
      	print('done')	
      
      • #10985
        木原 和信
        参加者

        s_ryo様

        いつもお世話になっております。エーアンドエー研究開発部です。

        カスタマイズの内容拝見させていただきました。コード設計についてはしっかり考えられており問題ありません。以下3点を修正いただくことで動作するようになりますのでお試しください。

        1. ワークシートハンドルのリストを解除

        今回ListAbsorbを使用されております。レコード名の一括処理に対しては効果的ですが、ワークシートのハンドルのように単一で入力されたデータもリスト化されます。ハンドルがリスト形式のままですとSetWSCellFormulaN関数でエラーになりますので次のとおりリストを解除します。

        worksheet=self.Params.worksheet.value[0]

        ここでは、リストの0番目の要素を取り出すことで解除しています。

        2. 列番号の修正

        ワークシートは行番号、列番号共に1から始まります。enumerateの番号は0から始まりますので、hを列番号とする場合は1を足します。

        vs.SetWSCellFormulaN(worksheet, i+1, h+1 , i+1, h+1 , Field_Name)

        3. フィールド参照番号の修正

        レコードフィールドの最大数を静的に指定している箇所について、

        index=[1,2,3,4,5,6]

        フィールドの最大数が6以下の場合は問題ありませんが、フィールドが6個に満たない場合、存在しないデータを参照しようとしてエラーが発生しています。

        エラーを回避するには、フィールド数を動的に取得する必要があります。フィールド数はNumFields関数で取得できます。

        例1:

        index = list( range( vs.NumFields(レコードのハンドル) ) )

        例2:

        index = list( range( 1, vs.NumFields(レコードのハンドル)+1 ) ) #1始まりにする

        例3:

        index = list( range( 1, min( 6, vs.NumFields(レコードのハンドル) )+1 ) ) #最大で6までのリストにする

        以上となります。ご参考になりましたら幸いです。

    • #11030
      s_ryo
      参加者

      木原様
      ご返信ありがとうございます。

      1. ワークシートハンドルのリストを解除
      完全に盲点でした。ListAbsorbを使う際に0番目のインデックスを指定するというのは
      今後他にもコードをいじる際に応用が効きそうです。

      2,3についてもご助言ありがとうございます。
      レコードフィールドを最も多く持つ数値を動的に取得しようと思い
      ‘Record name with the most record field values’ノードで入れたレコード名を
      再利用して下記にまとめてみました。

      #'Get Fld Name ver3' ノード
      h_RecHandle = vs.GetObject( t_MaxFieldName ) 
      	MaxlistNum=int(vs.NumFields(h_RecHandle))

      おかげさまで表題の目標を達成できました。

      今後の運用次第では、
      例えば添付データレコード名:”test_record”、フィールド値”用途地域”の
      popup属性の各要素(商業地域等)
      などの値も取得したいなど欲が出てきそうですが、
      そもそも上記についてはスクリプトでとってこれるのでしょうか?
      (各要素と記しましたがこれら任意に設定できる値は正式名称あるのでしょうか?)

      レコードフィールド、フィールド値をWSで管理したいと
      思ってる方の参考としてこちらにデータを挙げておきます。
      https://forum.vectorworks.net/index.php?/files/file/309-get-recordname_andrecordfield/
      ※VWXファイルはアップロード規制があったのでVectorworksのフォーラムにあげ直しております。

      なお、コードはコメントアウトしているものも多々残しており
      汚いのですがご勘弁ください。

3件の返信スレッドを表示中
  • このトピックに返信するにはログインが必要です。