How To > Develop A Face Area xView Checker - Part 2 |
The following tutorial extends the scripted xView Check created in Part 1 with custom text and display overrides and more test options.
The xView Checker is available in 3ds Max 2010 and higher.
--code in italic has not changed since Part 1 ( global FaceAreaChecker struct FaceAreaCheckerStruct ( FaceAreaThresholdMin = 1, FaceAreaThresholdMax = 10, FaceAreaMode = 1,
We will introduce six different modes to the checker, so we will need a property to store the current mode.
A new property will control whether the changes to the UI controls will trigger an update to the checker and the viewports. When working with heavy meshes, it might be a good idea to disable the updates.
We will store the last known location of the configuration dialog in an INI file.
Each check mode will display its results in a different color via the display override function we will implement in this step. This property contains an array of the six colors to use for display. Note that we can create cyan by adding 50% green to blue and orange by adding 50% yellow to red. We could use the predefined global 'orange' to do the same, but this way we have better control over the shade of the color, as we could easily change it to red+yellow*0.75 to make it brighter. There is no predefined global for cyan.
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 )
We extend the checker with 6 modes to compare the face area values relatively to each of the thresholds. The default mode is the original one - we flag faces whose area lies between the two thresholds. The other modes will flag if the area is blow the minimum, above the minimum but ignoring the maximum, below the maximum but ignoring the minimum, above the maximum and not between the thresholds (either below minimum or above maximum).
) 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
This drop-down list exposes the 6 checker modes to the configuration dialog. We initialize it to the current value of the struct instance's property.
colorpicker clr_resultsColor fieldwidth:10 align:#right offset:[7,-3] color:FaceAreaChecker.resultColors[FaceAreaChecker.FaceAreaMode]
Next to the drop-down list, we place a small color picker to control the color for the current mode.
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
This checkbox will control the interactive behavior of the tool.
This button will perform the conversion of checker flags to sub-object selection on the stack directly from the dialog without the need to navigate to the checker menus.
fn updateDisplay = ( if FaceAreaChecker.InteractiveUpdates do ( XViewChecker.runCheck CurrentTime max views redraw )
To implement the interactive/non-interactive mode, we simply add a test to see whether the property is true or false. If it is false, we just don't update the test and viewports.
) on ddl_FaceAreaMode selected itm do ( FaceAreaChecker.FaceAreaMode = itm updateDisplay() clr_resultsColor.color = FaceAreaChecker.resultColors[itm] )
When the drop-down list selection has been changed, we store the new selection index in the new property in the struct instance, update the display and also update the color picker to the color matching the current mode.
on clr_resultsColor changed val do ( FaceAreaChecker.resultColors[ddl_FaceAreaMode.selection] = val updateDisplay() )
If the color picker was changed, we update the current color inside the array in the struct instance and also update the display.
on chk_InteractiveUpdates changed state do ( FaceAreaChecker.InteractiveUpdates = state updateDisplay() )
If the interactive mode was changed, we store the current state in the struct instance's property and update the display.
on spn_FaceAreaThresholdMin changed val do ( FaceAreaChecker.FaceAreaThresholdMin = val updateDisplay() ) on spn_FaceAreaThresholdMax changed val do ( FaceAreaChecker.FaceAreaThresholdMax = val updateDisplay() ) on btn_selectResults pressed do ( XViewChecker.selectResults CurrentTime max views redraw )
If the new button was pressed, we call the method for selecting the results at the current time. This method is implemented by the XView Checker interface and we don’t have to do anything more except for redrawing the viewports to actually see the changes in the selection.
on faceAreaDialog moved pos do setIniSetting FaceAreaChecker.iniFileName "Dialog" "Position" (pos as string)
If the user modes the configuration dialog, we store the new position in the INI file.
)--end rollout
local thePos = execute (getIniSetting FaceAreaChecker.iniFileName "Dialog" "Position")
Before opening the dialog, we read the last known position from the INI file.
If the value returned is not an actual position value (meaning that the INI file has not been created yet or was deleted), we assume the screen position of the mouse.
We open the dialog at the last known position or the mouse position. We also provide the exact size of the dialog in the first two arguments.
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 ) ),
The text override function expects no arguments and returns a string to be displayed in the viewport next to the name of the current Checker. In our case, we just return the current mode and relevant threshold values.
fn dispOverride theTime theNode theHwnd theResults= ( local theColor = FaceAreaChecker.resultColors[FaceAreaChecker.FaceAreaMode] XViewChecker.displayResults theColor theTime theNode theHwnd 3 theResults )
The display override function can be used to implement a user-defined display for the Checker. It expects four arguments, the time, the node, the window handle of the current viewport and the results array which was generated by the checker function.
We call the displayResults method in the XView Checker interface with 6 arguments - the color to display the result in based on the array of colors and the current mode, the time, node and window handle as passed to our function, the type of display (3 for faces) and the array of results.
)--end struct try (destroyDialog FaceAreaChecker.faceAreaDialog)catch()
FaceAreaChecker = FaceAreaCheckerStruct()
xViewChecker.unRegisterChecker "Face Area Checker"
xViewChecker.registerChecker FaceAreaChecker.geomCheck FaceAreaChecker.supportedCheck #Faces "Face Area Checker" FaceAreaChecker.configDlgFaceAreaChecker.textOverride FaceAreaChecker.dispOverride
When registering the Checker, we have to add the two new functions for text and display overrides.
Our Face Area xView Checker has all checking modes, but its settings are not sticky. In the next Part 3 of the Tutorial, we will look adding sticky settings using an INI file.
To use the new checker, once again click on the Shading viewport menu (the third from the left) and under xView, select any of the standard xView Checkers. Then click in the checker name at the bottom of the viewport and select the Face Area instead. We will learn how to register our xView checker with the Viewport Menus in Part 4 of this tutorials.
To open the Configuration dialog and switch the various modes, click the [Click Here To Configure] label at the bottom of the viewport.
Here is an example of a Teapot with radius 40 and 4 segments collapsed to Editable Poly with all six modes of the Face Area xView checker applied to it: