チュートリアル - 面領域 xView チェッカーの開発 - 第 3 部

チュートリアル > 面領域 xView チェッカーの開発 - 第 3 部

このチュートリアルでは、第 1 部および第 2 部で作成したスクリプト方式の xView チェックを、INI ファイルの保持設定を使用して拡張します。

xView チェッカーは、 3ds Max 2010 以降で使用可能です。

関連トピック:

xView ジオメトリ チェッカーへのアクセス

インタフェース: XViewChecker

全体の流れ:

設定ダイアログ ボックスの各設定を INI ファイルに保存する機能を追加します。

INI ファイルからロードするすべての設定のリストを作成します。

スクリプトが評価されたときに INI ファイルから各設定をロードします。

スクリプト:

(
global FaceAreaChecker
struct FaceAreaCheckerStruct
(
FaceAreaThresholdMin = 1,
FaceAreaThresholdMax = 10,
FaceAreaMode = 1,
faceAreaDialog = undefined,
InteractiveUpdates = true,
iniFileName = (getDir #plugcfg +"\\FaceAreaXViewChecker.ini"),
resultColors = #(green, blue+green*0.5, red+yellow*0.5, blue, yellow, red),
 
fn geomCheck theTime theNode theResults =
(
  local theCount =case classof theNode of
  (
    Editable_Poly: getNumFaces theNode
    Editable_Mesh: theNode.numfaces
  )
  local theAreaMethod =case classof theNode of
  (
    Editable_Poly: polyOp.getFaceArea
    Editable_Mesh: meshOp.getFaceArea
  )
  
  for f = 1 to theCount do
  (
    local theArea = theAreaMethod theNode f
    case FaceAreaChecker.FaceAreaMode of
    (
      default: if theArea >= FaceAreaChecker.FaceAreaThresholdMin and theArea <= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
      2: if theArea <= FaceAreaChecker.FaceAreaThresholdMin do append theResults f
      3: if theArea >= FaceAreaChecker.FaceAreaThresholdMin do append theResults f
      4: if theArea <= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
      5: if theArea >= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
      6: if theArea <= FaceAreaChecker.FaceAreaThresholdMin or theArea >= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
    ) 
  ) 
3
),
 
fn supportedCheck theNode =
(
  classof theNode == Editable_Mesh or classof theNode == Editable_Poly
),
 
fn configDlg =
(
  try(destroyDialog FaceAreaChecker.faceAreaDialog)catch()
  rollout faceAreaDialog "Face Area Checker"
  (
    dropdownlist ddl_FaceAreaMode width:150 align:#left offset:[-10,-3] items:#("Between Min. and Max","Less Than Min.","Greater Than Min.","Less Than Max.","Greater Than Max.","Not Between Min. and Max") selection:FaceAreaChecker.FaceAreaMode across:2
    colorpicker clr_resultsColor fieldwidth:10 align:#right offset:[7,-3] color:FaceAreaChecker.resultColors[FaceAreaChecker.FaceAreaMode]
    spinner spn_FaceAreaThresholdMin "Min. Threshold:" range:[0,1000000,FaceAreaChecker.FaceAreaThresholdMin] offset:[7,-3] type:#worldUnits
    spinner spn_FaceAreaThresholdMax "Max. Threshold:" range:[0,1000000,FaceAreaChecker.FaceAreaThresholdMax] offset:[7,-3] type:#worldUnits
    checkbox chk_InteractiveUpdates "Interactive" checked:FaceAreaChecker.InteractiveUpdates offset:[0,-3] across:2
    button btn_selectResults "Selection" align:#right width:72 height:18 offset:[7,-3]
   
    fn updateDisplay =
    (
      if FaceAreaChecker.InteractiveUpdates do
      (
        XViewChecker.runCheck CurrentTime
        max views redraw
      )
    )
    on ddl_FaceAreaMode selected itm do
    (
      FaceAreaChecker.FaceAreaMode = itm
      updateDisplay()
      setIniSetting FaceAreaChecker.iniFileName "Settings" "FaceAreaMode" (itm as string)
      clr_resultsColor.color = FaceAreaChecker.resultColors[itm]
    )
    on clr_resultsColor changed val do
    (
      FaceAreaChecker.resultColors[ddl_FaceAreaMode.selection] = val
      updateDisplay()
      setIniSetting FaceAreaChecker.iniFileName"Colors" ("Color_"+ddl_FaceAreaMode.selection as string) (val as string)
    )
    on chk_InteractiveUpdates changed state do
    (
      FaceAreaChecker.InteractiveUpdates = state
      updateDisplay()
      setIniSetting FaceAreaChecker.iniFileName "Settings" "InteractiveUpdates" (state as string)
    ) 
    on spn_FaceAreaThresholdMin changed val do
    (
      FaceAreaChecker.FaceAreaThresholdMin = val
      updateDisplay()
      setIniSetting FaceAreaChecker.iniFileName "Settings" "FaceAreaThresholdMin" (val as string)
    ) 
    on spn_FaceAreaThresholdMax changed val do
    (
      FaceAreaChecker.FaceAreaThresholdMax = val
      updateDisplay()
      setIniSetting FaceAreaChecker.iniFileName "Settings" "FaceAreaThresholdMax" (val as string)
    )   
    on btn_selectResults pressed do
    (
      XViewChecker.selectResults CurrentTime
      max views redraw
    ) 
    on faceAreaDialog moved pos do setIniSetting FaceAreaChecker.iniFileName "Dialog" "Position" (pos as string)
  )--end rollout
  
  local thePos = execute (getIniSetting FaceAreaChecker.iniFileName "Dialog" "Position")
  if classof thePos != Point2 do thePos = mouse.screenpos
  createDialog faceAreaDialog 170 82 thePos.x thePos.y
  FaceAreaChecker.faceAreaDialog = faceAreaDialog
),
 
fn textOverride =
(
  case FaceAreaChecker.FaceAreaMode of
  (
    1: "Between "+FaceAreaChecker.FaceAreaThresholdMin as string +" and "+FaceAreaChecker.FaceAreaThresholdMax as string
    2: "Less Than "+FaceAreaChecker.FaceAreaThresholdMin as string
    3: "Greater Than "+FaceAreaChecker.FaceAreaThresholdMin as string
    4: "Less Than "+FaceAreaChecker.FaceAreaThresholdMax as string
    5: "Greater Than "+FaceAreaChecker.FaceAreaThresholdMax as string
    6: "Not Between "+FaceAreaChecker.FaceAreaThresholdMin as string +" and "+FaceAreaChecker.FaceAreaThresholdMax as string
  )
),
 
fn dispOverride theTime theNode theHwnd theResults =
(
  local theColor = FaceAreaChecker.resultColors[FaceAreaChecker.FaceAreaMode]
  XViewChecker.displayResults theColor theTime theNode theHwnd 3 theResults
)
)--end struct
 
try(destroyDialog FaceAreaChecker.faceAreaDialog)catch()
FaceAreaChecker = FaceAreaCheckerStruct()
 
local valuesToLoad = #(
  #("Settings","FaceAreaMode", &FaceAreaChecker.FaceAreaMode,0),
  #("Settings","InteractiveUpdates", &FaceAreaChecker.InteractiveUpdates,0), 
  #("Settings","FaceAreaThresholdMin", &FaceAreaChecker.FaceAreaThresholdMin,0), 
  #("Settings","FaceAreaThresholdMax", &FaceAreaChecker.FaceAreaThresholdMax,0), 
  #("Colors","Color_1", FaceAreaChecker.resultColors, 1), 
  #("Colors","Color_2", FaceAreaChecker.resultColors, 2), 
  #("Colors","Color_3", FaceAreaChecker.resultColors, 3), 
  #("Colors","Color_4", FaceAreaChecker.resultColors, 4), 
  #("Colors","Color_5", FaceAreaChecker.resultColors, 5), 
  #("Colors","Color_6", FaceAreaChecker.resultColors, 6)
)
for i in valuesToLoad do
(
  local theVal = execute (getIniSetting FaceAreaChecker.iniFileName i[1] i[2])
  if theVal != OK do
    if i[4] > 0 then i[3][i[4]] = theVal else *i[3] = theVal
)--end i loop 
 
xViewChecker.unRegisterChecker "Face Area Checker"
xViewChecker.registerChecker FaceAreaChecker.geomCheck FaceAreaChecker.supportedCheck #Faces "Face Area Checker" FaceAreaChecker.configDlg FaceAreaChecker.textOverride FaceAreaChecker.dispOverride
)--end script
--code in italic has not changed since Part 2 (
global FaceAreaChecker
struct FaceAreaCheckerStruct
(
FaceAreaThresholdMin = 1,
FaceAreaThresholdMax = 10,
FaceAreaMode = 1,
faceAreaDialog = undefined,
InteractiveUpdates = true,
iniFileName = (getDir #plugcfg +"\\FaceAreaXViewChecker.ini"),
resultColors = #(green, blue+green*0.5, red+yellow*0.5, blue, yellow, red),
fn geomCheck theTime theNode theResults =
(
local theCount = case classof theNode of
(
Editable_Poly: getNumFaces theNode
Editable_Mesh: theNode.numfaces
)
local theAreaMethod = case classof theNode of
(
Editable_Poly: polyOp.getFaceArea
Editable_Mesh: meshOp.getFaceArea
)
for f = 1 to theCount do
(
local theArea = theAreaMethod theNode f
case FaceAreaChecker.FaceAreaMode of
(
default: if theArea >= FaceAreaChecker.FaceAreaThresholdMin and theArea <= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
2: if theArea <= FaceAreaChecker.FaceAreaThresholdMin do append theResults f
3: if theArea >= FaceAreaChecker.FaceAreaThresholdMin do append theResults f
4: if theArea <= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
5: if theArea >= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
6: if theArea <= FaceAreaChecker.FaceAreaThresholdMin or theArea >= FaceAreaChecker.FaceAreaThresholdMax do append theResults f
) 
) 
3
),

fn supportedCheck theNode =
(
classof theNode == Editable_Mesh or classof theNode == Editable_Poly
),

fn configDlg =
(
try (destroyDialog FaceAreaChecker.faceAreaDialog)catch()
rollout faceAreaDialog "Face Area Checker"
(
dropdownlist ddl_FaceAreaMode width:150 align:#left offset:[-10,-3] items:#("Between Min. and Max","Less Than Min.", "Greater Than Min.","Less Than Max.", "Greater Than Max.","Not Between Min. and Max") selection:FaceAreaChecker.FaceAreaMode across:2
colorpicker clr_resultsColor fieldwidth:10 align:#right offset:[7,-3] color:FaceAreaChecker.resultColors[FaceAreaChecker.FaceAreaMode]
spinner spn_FaceAreaThresholdMin "Min. Threshold:" range:[0,1000000,FaceAreaChecker.FaceAreaThresholdMin] offset:[7,-3] type:#worldUnits
spinner spn_FaceAreaThresholdMax "Max. Threshold:" range:[0,1000000,FaceAreaChecker.FaceAreaThresholdMax] offset:[7,-3] type:#worldUnits
checkbox chk_InteractiveUpdates "Interactive" checked:FaceAreaChecker.InteractiveUpdates offset:[0,-3] across:2
button btn_selectResults "Selection" align:#right width:72 height:18 offset:[7,-3]  

fn updateDisplay =
(
if FaceAreaChecker.InteractiveUpdates do
(
XViewChecker.runCheck CurrentTime
max views redraw
)
)
on ddl_FaceAreaMode selected itm do
(
FaceAreaChecker.FaceAreaMode = itm
updateDisplay() setIniSetting FaceAreaChecker.iniFileName "Settings" "FaceAreaMode" (itm as string)

モードが変更されたら、現在の選択を INI ファイルのカテゴリ「Settings」の下およびキー「FaceAreaMode」の下に保存します。

clr_resultsColor.color = FaceAreaChecker.resultColors[itm]
)
on clr_resultsColor changed val do
(
FaceAreaChecker.resultColors[ddl_FaceAreaMode.selection] = val
updateDisplay() setIniSetting FaceAreaChecker.iniFileName "Colors" ("Color_"+ddl_FaceAreaMode.selection as string) (val as string)

カラーが変更されたら、新しいカラーを INI ファイルのカテゴリ「Colors」の下およびキー「Color_N (N は現在のモード)」の下に保存します。

)
on chk_InteractiveUpdates changed state do
(
FaceAreaChecker.InteractiveUpdates = state
updateDisplay() setIniSetting FaceAreaChecker.iniFileName "Settings" "InteractiveUpdates" (state as string)

インタラクティブ モード チェックボックスの状態が変更されたら、現在の状態を INI ファイルのカテゴリ「Settings」の下およびキー「InteractiveUpdates」の下に保存します。

) 
on spn_FaceAreaThresholdMin changed val do
(
FaceAreaChecker.FaceAreaThresholdMin = val
updateDisplay() setIniSetting FaceAreaChecker.iniFileName "Settings" "FaceAreaThresholdMin" (val as string)

最小しきい値のスピナーの値が変更されたら、現在の値を INI ファイルのカテゴリ「Settings」の下およびキー「FaceAreaThresholdMin」の下に保存します。

) 
on spn_FaceAreaThresholdMax changed val do
(
FaceAreaChecker.FaceAreaThresholdMax = val
updateDisplay() setIniSetting FaceAreaChecker.iniFileName "Settings" "FaceAreaThresholdMax" (val as string)

最大しきい値のスピナーの値が変更されたら、現在の値を INI ファイルのカテゴリ「Settings」の下およびキー「FaceAreaThresholdMax」の下に保存します。

)   
on btn_selectResults pressed do
(
XViewChecker.selectResults CurrentTime
max views redraw
) 
on faceAreaDialog moved pos do setIniSetting FaceAreaChecker.iniFileName "Dialog" "Position" (pos as string)
)--end rollout
  
local thePos = execute (getIniSetting FaceAreaChecker.iniFileName "Dialog" "Position")
if classof thePos != Point2 do thePos = mouse.screenpos
createDialog faceAreaDialog 170 82 thePos.x thePos.y
FaceAreaChecker.faceAreaDialog = faceAreaDialog
),

fn textOverride =
(
case FaceAreaChecker.FaceAreaMode of
(
1: "Between "+FaceAreaChecker.FaceAreaThresholdMin as string +" and " +FaceAreaChecker.FaceAreaThresholdMax as string
2: "Less Than "+FaceAreaChecker.FaceAreaThresholdMin as string
3: "Greater Than "+FaceAreaChecker.FaceAreaThresholdMin as string
4: "Less Than "+FaceAreaChecker.FaceAreaThresholdMax as string
5: "Greater Than "+FaceAreaChecker.FaceAreaThresholdMax as string
6: "Not Between "+FaceAreaChecker.FaceAreaThresholdMin as string +" and " +FaceAreaChecker.FaceAreaThresholdMax as string
)
),

fn dispOverride theTime theNode theHwnd theResults=
(
local theColor = FaceAreaChecker.resultColors[FaceAreaChecker.FaceAreaMode]
XViewChecker.displayResults theColor theTime theNode theHwnd 3 theResults
)
)--end struct

try (destroyDialog FaceAreaChecker.faceAreaDialog)catch()
FaceAreaChecker = FaceAreaCheckerStruct()
 
local valuesToLoad = #(

INI ファイル設定のロードを簡単にするため、設定するカテゴリ、キー、プロパティ、およびカラーの場合はカラーのインデックスを定義する配列の配列を宣言します。

#("Settings", "FaceAreaMode", &FaceAreaChecker.FaceAreaMode,0),
#("Settings", "InteractiveUpdates", &FaceAreaChecker.InteractiveUpdates,0),
#("Settings", "FaceAreaThresholdMin", &FaceAreaChecker.FaceAreaThresholdMin,0), 
#("Settings", "FaceAreaThresholdMax", &FaceAreaChecker.FaceAreaThresholdMax,0), 

これらの設定をロードするため、カテゴリ名、キー名、プロパティへの参照、およびインデックス 0 (サブインデックスを使わないことを意味します) を含む配列を定義します。プロパティは、& 演算子を使用して、値ではなくプロパティへのポインタが格納された参照プロパティとして取得します。これにより、プロパティは評価されず、そのポインタと参照解除演算子 * を使用してこれに値を書き戻すことができます。

#("Colors", "Color_1", FaceAreaChecker.resultColors, 1), 
#("Colors", "Color_2", FaceAreaChecker.resultColors, 2), 
#("Colors", "Color_3", FaceAreaChecker.resultColors, 3), 
#("Colors", "Color_4", FaceAreaChecker.resultColors, 4), 
#("Colors", "Color_5", FaceAreaChecker.resultColors, 5), 
#("Colors", "Color_6", FaceAreaChecker.resultColors, 6)

これらのカラー設定をロードするため、カテゴリ名、キー名、プロパティへの参照、およびカラーの配列内での対応するカラーのインデックスを含む配列を定義します。このプロパティは配列であり、配列は常に暗黙的に参照として扱われるため、ここでは参照を使用する必要はありません。

)
for i in valuesToLoad do
(

ロードする設定のリストをループします。

local theVal = execute (getIniSetting FaceAreaChecker.iniFileName i[1] i[2])

INI ファイルからカテゴリとキー名に基づいて値をロードし、文字列を評価して適切な MAXScript 値に変換します。

if theVal != OK do
if i[4] > 0 then i[3][i[4]] = theVal else *i[3] = theVal

評価の結果が値 OK でなかった場合 (getIniSetting から返された文字列が空であった場合に返されます)、サブ配列の 4 番目 の要素がゼロよりも大きいかどうかをチェックします。そうであれば、カラー配列の対応するインデックスの項目にこの値を割り当てます。そうでない場合は、単に参照解除されたプロパティにこの値を割り当てます。

 )--end i loop 
 

xViewChecker.unRegisterChecker "Face Area Checker"
xViewChecker.registerChecker FaceAreaChecker.geomCheck FaceAreaChecker.supportedCheck #Faces "Face Area Checker" FaceAreaChecker.configDlg FaceAreaChecker.textOverride FaceAreaChecker.dispOverride
)--end script

スクリプトの使い方

これで、面領域 xView チェッカーのすべての機能が完成しました。最後のチュートリアル第 4 部では、これをビューポート メニューに組み込んでアクセスを容易にする方法を説明します。

設定ダイアログ ボックスの設定はセッション間で保持されるようになります。残りの機能は、前の第 2 部と同じです。

チュートリアル - 面領域 xView チェッカーの開発 - 第 2 部

チュートリアル - 面領域 xView チェッカーの開発 - 第 4 部

関連事項