-- VegetationTools.ms -- 2013 Andy Davis -- Rockstar London -- Description: Collection of tools to manage vegetation related geometry tasks filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") --wildwest header filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/RSL_dotNetUIOps.ms") --RS_dotNetPreset structure RsCollectToolUsageData (getThisScriptFilename()) global VegToolsUI struct CustomTreeData ( ObjectName, --the RSRefObject.objectName value PivotOffset = [0,0,0], --the value to offset the pivot so that it is placed at the base of the tree Radius --radius of the base of the tree ) struct TreePlacementStruct ( tolerance = 0.5, maxTrunkRadius = 1, padding = 0.01, groundPlane = undefined, objSet = #(), debug = false, progress = 0, CustomTreeList = #(), fn PlaceObjects = ( local originalSelection = selection as array for obj in originalSelection do ( if (classOf obj.baseObject == RSrefObject) and (obj != this.groundPlane) then ( local numModifiers = obj.modifiers.count this.FixRSRef obj append this.objSet obj ) ) select objSet local GroundPlanes = this.GetGroundPlanes selection for obj in objSet do ( local ZRotation = this.GetZRotation obj local RandomRotation = VegToolsUI.RandomSpinner.text as float if (RandomRotation > 0.0) then ZRotation += (random -180 180) * RandomRotation this.SetRotation obj (eulerAngles 0 0 0) local downVector = [0,0,-1] local verticalPad = 3 --height to add to the z value of the ray in order to replant trees local PivotOffset = [0,0,0] local treeRadius = 0.03 local IsCustom = false --check to see if the object is in the CustomTreeList for item in this.CustomTreeList do ( if obj.objectName == item.ObjectName then ( PivotOffset = item.PivotOffset treeRadius = item.Radius IsCustom = true ) ) if (IsCustom) then ( obj.pivot -= PivotOffset ) local PivotRay = ray [obj.pivot.x, obj.pivot.y, (obj.pivot.z + verticalPad)] downVector --used to calculate slope angle local intersection = this.GetIntersection GroundPlanes PivotRay if intersection != undefined then ( local ZPoint = intersection.pos.z local dropHeight = obj.pivot.z - ZPoint + 0.15 --rotate the object to fit it in the direction of the slope --get the slope angle local slopeRay = intersection.dir local slantVector = this.GetProportionalVector slopeRay [0,0,1] (VegToolsUI.slopeSpinner.text as float) -- print slopeRay local slantAngle = this.GetAngleFromVector slantVector rotate obj slantAngle this.SetZRotation obj ZRotation --angle between two vectors for slant vector and vertical to determine the extra drop height obj.position.z -= (dropHeight + this.GetDropHeight slopeRay treeRadius) ) else ( local infoString = ("No ground plane found for " + obj.name) messagebox infoString title:"Tree Placement" ) --reset the pivot to the original position if the pivot has been offset if (IsCustom) then ( local RotationBuffer = obj.rotation as eulerAngles this.SetRotation obj (eulerAngles 0 0 0) obj.Pivot += PivotOffset this.SetRotation obj RotationBuffer ) this.progress += 100 / objSet.count ) return objSet.count ), fn InitCustomTreeList = ( append this.CustomTreeList (CustomTreeData ObjectName:"Prop_Bush_Lrg_04b" PivotOffset:[-1.0, -0.45, 2.3] Radius:1.65) -- print this.CustomTreeList ), --calculates the vertical shift an object must drop by to compensate for a tilt from the vertical fn GetDropHeight SlopeVector Radius = ( local AngleToVertical = acos(dot (normalize SlopeVector) [0,0,1]) local DropHeight = sin(AngleToVertical) * Radius return DropHeight ), fn GetZRotation InObject = ( toolMode.coordsys #world rot = InObject.Rotation as eulerangles -- messagebox (rot.z as string) return rot.z ), fn SetZRotation InObject ZValue = ( toolMode.coordsys #world rot = InObject.Rotation as eulerangles pos = InObject.Position InObject.Rotation = (eulerangles rot.x rot.y ZValue) InObject.Position = pos ), fn GetIntersection TestPlanes InRay = ( local numPlanes = TestPlanes.count local found = false local intersection = undefined for thisPlane in TestPlanes where found == false do ( intersection = intersectRay thisPlane InRay if (intersection != undefined) then found = true ) return intersection ), --function collects candidates for ground planes to match a set of passed in nodes fn GetGroundPlanes InObject = ( GroundPlanes = for item in geometry where ClassOf item != RSrefObject collect item GroundPlanes = for item in GroundPlanes where (item.max.x > InObject.min.x) and (item.max.y > InObject.min.y) collect item GroundPlanes = for item in GroundPlanes where (item.min.x < InObject.max.x) and (item.min.y < InObject.max.y) collect item GroundPlanes = for item in GroundPlanes where not (getAttr item (getAttrIndex "Gta Object" "Dont Export")) collect item GroundPlanes = for item in GroundPlanes where not (RSIsLod item) collect item return GroundPlanes ), fn SetRotation obj eulerRotation = ( local objPosition = obj.position obj.rotation = eulerRotation obj.position = objPosition ), fn FixRSRef rsref = ( local numModifiers = rsref.modifiers.count if numModifiers > 0 then ( for i = 1 to numModifiers do ( deleteModifier rsref rsref.modifiers[1] ) ) ), --function gets an eulerAngles value for a corresponding vector fn GetAngleFromVector theNormal = ( local theZ = normalize theNormal --this is the original vector if (dot theZ [0,0,1]) > 0.99999 then --if the vector is nearly parallel to Z, assume 0 eulerangles 0 0 0 else ( local theY = normalize (cross [0,0,1] theZ ) --this is the Y axis orthogonal to the Normal and Up local theX = normalize (cross theY theZ) --this is the X orthogonal to Normal and Y local theTM = matrix3 theX theY theZ [0,0,0] --this is the matrix3 describing the orientation of the Normal theTM.rotationpart as eulerangles --return its Euler rotation ) ), --finds the vector that is proportionally aligned to the targetVector from a starting reference vector --amount: number from 0 to 1 representing the proportion --amount 0 is the refVector, amount 1 is the targetVector fn GetProportionalVector targetVector refVector amount = ( return (normalize (amount * targetVector + (1 - amount) * refVector)) ), fn IsNoExportSet obj = ( local noExport = false if (getAttr obj (getAttrIndex "Gta Object" "Dont Export")) or (getAttr $ (getAttrIndex "Gta Object" "Dont Add To IPL")) then noExport = true return noExport ), --function prints out the parameters of the struc fn PrintDetails = ( clearListener() format "Tolerance: %\n" this.tolerance if (this.GroundPlane == undefined) then format "Ground Plane: undefined\n" else format "Ground Plane: %\n" this.groundPlane.name ) ) --struct to handle the geometry operations struct TreeBaseGeneratorStruct ( --treegen varaibles size = 2, numSides = 8, --must be 4 or more sides fill = 0.75, inset = 0.125, devMode = false, jig = undefined, refPoly = undefined, topObj = undefined, infoString, --function returns the closest of the four edge verts to the mid-point of verts a and b fn GetClosestEdgeVert obj a b = ( local midPoint = (obj.verts[a].position + obj.verts[b].position) / 2 local closestVert = 1 local vertDist = distance midPoint obj.verts[1].position for i = 2 to 4 do ( if (distance midPoint obj.verts[i].position) < vertDist then ( closestVert = i vertDist = distance midPoint obj.verts[i].position ) ) return closestVert ), --places the jig to the location of the selected polygon fn PlaceTreeBase = ( --Check that selection matches criteria local objList = for this in selection where superClassOf this == GeometryClass collect this if (objList.count == 1) then ( local obj = objList[1] if obj.modifiers.count > 0 then print "Warning - about to collapse stack" convertToPoly objList[1] subObjectLevel = 4 if (obj.selectedFaces.count == 1) then ( local faceID = obj.selectedFaces[1].index local vertIDs = polyOp.GetFaceVerts obj faceID if vertIDs.count == 4 then ( this.CreateBaseMesh() select this.jig --set the smoothing groups local smoothingGroups = RSGeom_GetSmoothingGroups obj faceID for face = 1 to this.jig.faces.count do RSGeom_SetSmoothingGroups this.jig face smoothingGroups --set the order for the ffd control points to be translated to match the polygon local ffdCPPairs = #(#(1,2), #(5,6), #(7,8), #(3,4)) local ffd = FFD_2x2x2() addModifier this.jig ffd animateAll ffd --required to get access to ffd control points clearListener() -- ffdOps = FFDWrapper() for i = 1 to 4 do ( RSFFD_SetWorldPos this.jig this.jig.FFD_2x2x2 ffdCPPairs[i][1] obj.verts[vertIDs[i]].position RSFFD_SetWorldPos this.jig this.jig.FFD_2x2x2 ffdCPPairs[i][2] obj.verts[vertIDs[i]].position ) --extract quad from mesh polyop.detachFaces obj obj.faces[faceID] delete:true asNode:true name:"transfer" this.topObj = obj this.infoString = "Polygon processed." true ) else ( this.infoString = "Please select a quad." false ) ) else ( this.infoString = "Please select a single face." false ) ) else ( this.infoString = "Please select a polygon on an object." false ) ), --callback script for the projection modifier used to transfer the mapping data to the treeBase fn ProjectionCallback = ( local hwnd = dialogMonitorOps.getWindowHandle() if (uiAccessor.getWindowText hwnd == "Add Objects") then ( --the control IDs below are correct for 3dsMax 2012 --may need to refigure the IDs if the dialog box changes in future versions --use windows.getChildHWND to get a list of controls local dotNetPressEnter = dotNetClass "System.Windows.Forms.SendKeys" local toolStripID = 5 local addButtonID = 19 local editButtonID = 12 local VK_RETURN = 0x0D local MAXHWND = windows.getMAXHWND() local AddObjectsHWNDList = UIAccessor.GetChildWindows hwnd local AddObjectsControls = windows.getChildrenHWND hwnd local toolStripHWNDControls = windows.getChildrenHWND AddObjectsHWNDList[toolStripID] UIAccessor.SetWindowText toolStripHWNDControls[editButtonID][1] this.jig.name dotNetPressEnter.Send "{ENTER}" ) true ), --attach the jig to the original object, after transferring the material and mapping fn AttachTreeBase = ( local source = objects[objects.count] --copy materials and transfer mapping this.jig.material = source.material addModifier source (Projection()) select source dialogMonitorOps.unRegisterNotification id:#test dialogMonitorOps.enabled = true dialogMonitorOps.interactive = false dialogMonitorOps.registerNotification ProjectionCallback id:#test commandHWND = (windows.getChildHWND #max "Pick List") UIAccessor.pressButtonByName commandHWND[2] "Pick List" commandHWND = (windows.GetChildHWND #max "Add") UIAccessor.pressButtonByName commandHWND[2] "Add" commandHWND = (windows.GetChildHWND #max "Project All") UIAccessor.pressButtonByName commandHWND[2] "Project All" dialogMonitorOps.enabled = false --combine base mesh with original mesh convertToMesh #(this.topObj, this.jig) meshop.attach this.topObj this.jig convertToPoly this.topObj --weld the vertices this.topObj.weldThreshold = 0.01 local outerEdges = polyop.getOpenEdges this.topObj local edgeVerts = polyop.getVertsUsingEdge this.topObj outerEdges polyop.weldVertsByThreshold this.topObj edgeVerts delete source select this.topobj ), fn CreateBaseMesh = ( local originalSelection = selection as array local selectionMode = subObjectLevel this.CreateJig() try ( select originalSelection subObjectLevel = selectionMode ) catch(clearSelection()) ), fn CreateJig = ( if (devMode) then for this in objects where (this.name == "jig") do delete this this.jig = Plane width:this.size length:this.size name:"jig" lengthsegs:1 widthsegs:1 local radiusValue = this.jig.width * this.fill * 0.5 local insetValue = radiusValue * this.inset local base = Cylinder radius:radiusValue height:0.5 sides:this.numSides convertToMesh base local baseVerts = for item in base.verts where item.position.z == 0 and item.position != [0,0,0] collect item.position append baseVerts [0,0,0] delete base select this.jig this.jig.backfacecull = true convertToMesh this.jig meshop.setNumVerts this.jig (5 + numSides) for i = 1 to (numSides + 1) do ( this.jig.verts[i + 4].position = baseVerts[i] ) subObjectLevel = 1 for i = 1 to (numSides - 1) do ( meshop.createPolygon this.jig #(i+4, i+5, numSides + 5) local edgeVert = GetClosestEdgeVert this.jig (i+4) (i+5) meshop.createPolygon this.jig #(i+5, i+4, edgeVert) ) -- create the final center poly meshop.createPolygon this.jig #(numSides + 4, 5, numSides + 5) meshOp.createPolygon this.jig #(5, numSides + 4, (GetClosestEdgeVert jig 5 (numSides + 4))) meshop.deleteFaces this.jig #{1,2} --delete the initial two faces -- create the final edge polys -- first get the vertex ids for each of the four triangles local openEdgeList = meshop.GetOpenEdges this.jig local nonCornerVerts = #() local finalEdgePolys = #() for item in openEdgeList as array do ( local verts = (meshop.getVertsUsingEdge this.jig item) as array local innerVert, outerVert if (verts[1] > 4) then ( innerVert = verts[1] outerVert = verts[2] ) else ( innerVert = verts[2] outerVert = verts[1] ) if finalEdgePolys.count > 0 then ( local found = false for poly in finalEdgePolys do ( if innerVert == poly[1] then ( found = true append poly outerVert ) ) if (not found) then ( append finalEdgePolys #(innerVert, outerVert) ) ) else ( append finalEdgePolys #(innerVert, outerVert) ) ) -- now create the polys for item in finalEdgePolys do ( if (item[1] == 5) then meshop.createPolygon jig #(item[1], item[3], item[2]) else meshop.createPolygon jig item ) --translate the centre vertex so that the ffd is not flat --this is necessary so that the ffd is not 2-dimensional jig.verts[jig.verts.count].position.z += 0.2 --inset the centre convertToPoly jig subObjectLevel = 4 local centerFaces = polyop.getFacesUsingVert jig #{jig.verts.count} polyop.setFaceSelection jig centerFaces jig.insetAmount = insetValue jig.buttonOp #Inset polyop.setFaceSelection jig #{} jig ), fn SetCommandPanelRedraw State = ( Args = 0 if( State == on ) then Args = 1 WM_SETREDRAW=0xB CommandHWND = (Windows.GetChildHWND #Max "Command Panel") Windows.Sendmessage (CommandHWND[1]) WM_SETREDRAW Args 0 ), fn Process = ( with undo off ( this.SetCommandPanelRedraw false try ( local success = this.PlaceTreeBase() if (success) then this.AttachTreeBase() this.SetCommandPanelRedraw true ) catch ( format "Error: problem during execution" this.SetCommandPanelRedraw true ) ) return this.infoString ) ) --struct for the UI struct VegetationToolsUI ( Form, ToolTip, InfoPanel, NumSidesSpinner, FillSpinner, InsetSpinner, SlopeSpinner, RandomSpinner, ProgBar, IniFilePath = (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/RSL_Tools.ini"), TreeGen = TreeBaseGeneratorStruct(), TreePlacement = TreePlacementStruct(), numSidesMin = 4, fillMin = 0.25, insetMin = 0.05, ProcessingRollout, TitleColor = RS_dotNetPreset.ARGB 48 48 48, ButtonPadding = dotNetObject "System.Windows.Forms.Padding" 2, ------------------------------------------------------------------------------------------------------------------------------------------ --GENERAL FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------ fn GenerateTreeBase s e = ( rollout temprollout "Tree Base Generator" ( label myLabel "Processing" ) VegToolsUI.TreeGen.numsides = VegToolsUI.NumSidesSpinner.Text as integer VegToolsUI.TreeGen.fill = VegToolsUI.FillSpinner.Text as float VegToolsUI.TreeGen.inset = VegToolsUI.InsetSpinner.Text as float theNewFloater = createDialog temprollout 200 30 VegToolsUI.InfoPanel.Text = "Processing..." VegToolsUI.InfoPanel.Text = VegToolsUI.TreeGen.Process() destroyDialog temprollout ), fn PlaceTrees s e = ( rollout temprollout "Tree Placement" ( label myLabel "Processing" ) theNewFloater = createDialog temprollout 200 30 VegToolsUI.TreePlacement.objSet = #() local time = TimeStamp() local numTrees = VegToolsUI.TreePlacement.PlaceObjects() local timeTaken = (TimeStamp() - time) / 1000.0 -- print ("Time taken is " + timeTaken as string + " seconds") if numTrees != undefined then ( if numTrees == 1 then VegToolsUI.InfoPanel.Text = "1 tree placed." else VegToolsUI.InfoPanel.Text = (numTrees as string + " trees placed.") ) destroyDialog temprollout ), ------------------------------------------------------------------------------------------------------------------------------------------ --LOAD/SAVE FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------ fn SaveIniFile = ( setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocX" (VegToolsUI.Form.Location.x as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocY" (VegToolsUI.Form.Location.y as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinWidth" (VegToolsUI.Form.Width as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinHeight" (VegToolsUI.Form.Height as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "NumSides" (VegToolsUI.NumSidesSpinner.Text as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "Fill" (VegToolsUI.FillSpinner.Text as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "Inset" (VegToolsUI.InsetSpinner.Text as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "Slope" (VegToolsUI.SlopeSpinner.Text as string) setINISetting VegToolsUI.IniFilePath "VegToolsUI" "RandomRotation" (VegToolsUI.RandomSpinner.Text as string) ), fn LoadIniFile = ( --default values local WinLocX = 100 local WinLocY = 100 local WinWidth = 200 local WinHeight = 200 local NumSides = 8 local Fill = 0.8 local Inset = 0.15 local Slope = 0.0 local RandomRotation = 0.0 try ( WinLocX = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocX" as integer WinLocY = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocY" as integer WinWidth = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinWidth" as integer WinHeight = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinHeight" as integer NumSides = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "NumSides" as integer Fill = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "Fill" as float Inset = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "Inset" as float Slope = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "Slope" as float RandomRotation = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "RandomRotation" as float ) catch() VegToolsUI.Form.Location = dotNetObject "system.drawing.point" WinLocX WinLocY VegToolsUI.Form.Size = dotNetObject "System.Drawing.Size" WinWidth WinHeight -- print VegToolsUI.numSidesMin -- print VegToolsUI.fillMin -- print VegToolsUI.insetMin if (NumSides < VegToolsUI.numSidesMin) then NumSides = 8 if (Fill < VegToolsUI.fillMin) then Fill = 0.75 if (Inset < VegToolsUI.insetMin) then Inset = 0.1 VegToolsUI.NumSidesSpinner.Value = NumSides VegToolsUI.FillSpinner.Value = Fill VegToolsUI.InsetSpinner.Value = Inset VegToolsUI.SlopeSpinner.Value = Slope VegToolsUI.RandomSpinner.Value = RandomRotation VegToolsUI.TreePlacement.InitCustomTreeList() ), ------------------------------------------------------------------------------------------------------------------------------------------ --UI ------------------------------------------------------------------------------------------------------------------------------------------ fn CreateUI = ( -- form setup Form = dotNetObject "maxCustomControls.maxForm" Form.Text = "Vegetation Tools" Form.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").manual Form.Location = dotNetObject "system.drawing.point" 200 200 Form.MaximumSize = dotNetObject "System.Drawing.Size" 230 376 Form.MinimumSize = dotNetObject "System.Drawing.Size" 230 376 Form.FormBorderStyle = RS_dotNetPreset.FB_Sizable dotNet.AddEventHandler Form "Load" LoadIniFile dotNet.AddEventHandler Form "Closing" SaveIniFile --content ToolTip = dotnetobject "ToolTip" Table = dotNetObject "TableLayoutPanel" Table.Dock = RS_dotNetPreset.DS_Fill Table.RowCount = 3 Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 40) --banner Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 135) --tree base generator Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 116) --tree placement Table.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 100) --info panel Table.ColumnCount = 1 Table.ColumnStyles.add (RS_dotNetObject.columnStyleObject "absolute" 160) Table.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100) Table.Margin = RS_dotNetPreset.Padding_None Form.Controls.Add Table RSBannerPanel = dotNetObject "System.Windows.Forms.Panel" RSBannerPanel.borderstyle = RS_dotNetClass.borderStyleClass.FixedSingle RSBannerPanel.dock = RS_dotNetPreset.DS.Fill local banner = makeRsBanner dn_Panel:RSBannerPanel width:395 studio:"london" mail:"andy.davis@rockstarlondon.com" wiki:"Map_Art_Tech" banner.setup() Table.Controls.Add RSBannerPanel 0 0 Table.SetColumnSpan RSBannerPanel 2 RS_dotNetPreset.Font_Main = dotNetObject "System.Drawing.Font" "Futura" 10 ------------------------------------------------------------------------------- --TREE BASE GENERATOR ------------------------------------------------------------------------------- TreeGenTable = dotNetObject "TableLayoutPanel" TreeGenTable.Dock = RS_dotNetPreset.DS_Fill TreeGenTable.RowCount = 5 TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25) TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25) TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25) TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25) TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25) TreeGenTable.ColumnCount = 2 TreeGenTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "absolute" 160) TreeGenTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100) Table.Controls.Add TreeGenTable 0 1 TreeGenLabel = RS_dotNetUI.InitLabel "Tree Base Generator" RS_dotNetPreset.TA.MiddleLeft TreeGenLabel.BackColor = this.TitleColor TreeGenLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 ToolTip.SetToolTip TreeGenLabel "Create radial geometry for tree bases." TreeGenTable.Controls.Add TreeGenLabel 0 0 TreeGenTable.SetColumnSpan TreeGenLabel 2 NumSidesLabel = RS_dotNetUI.InitLabel "Number Of sides" RS_dotNetPreset.TA.MiddleLeft NumSidesLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 TreeGenTable.Controls.Add NumSidesLabel 0 1 NumSidesSpinner = dotNetObject "NumericUpDown" NumSidesSpinner.Dock = RS_dotNetPreset.DS.Fill NumSidesSpinner.value = 4 NumSidesSpinner.Minimum = VegToolsUI.numSidesMin NumSidesSpinner.Maximum = 32 TreeGenTable.Controls.Add NumSidesSpinner 1 1 FillLabel = RS_dotNetUI.InitLabel "Fill" RS_dotNetPreset.TA.MiddleLeft FillLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 TreeGenTable.Controls.Add FillLabel 0 2 FillSpinner = dotNetObject "NumericUpDown" FillSpinner.Dock = RS_dotNetPreset.DS.Fill FillSpinner.Minimum = VegToolsUI.fillMin FillSpinner.Maximum = 0.95 FillSpinner.Increment = 0.05 FillSpinner.Value = 0.75 FillSpinner.DecimalPlaces = 2 TreeGenTable.Controls.Add FillSpinner 1 2 InsetLabel = RS_dotNetUI.InitLabel "Inset" RS_dotNetPreset.TA.MiddleLeft InsetLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 TreeGenTable.Controls.Add InsetLabel 0 3 InsetSpinner = dotNetObject "NumericUpDown" InsetSpinner.Dock = RS_dotNetPreset.DS.Fill InsetSpinner.Minimum = VegToolsUI.insetMin InsetSpinner.Maximum = 0.2 InsetSpinner.Increment = 0.05 InsetSpinner.Value = 0.1 InsetSpinner.DecimalPlaces = 2 TreeGenTable.Controls.Add InsetSpinner 1 3 TreeGenButton = RS_dotNetUI.InitButton "Generate Tree Base" TreeGenButton.Margin = this.ButtonPadding dotNet.AddEventHandler TreeGenButton "Click" GenerateTreeBase TreeGenTable.SetColumnSpan TreeGenButton 2 TreeGenTable.Controls.Add TreeGenButton 0 4 ------------------------------------------------------------------------------- --TREE PLACEMENT ------------------------------------------------------------------------------- TreePlacementTable = dotNetObject "TableLayoutPanel" TreePlacementTable.Dock = RS_dotNetPreset.DS_Fill TreePlacementTable.RowCount = 4 TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28) TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28) TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28) TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28) TreePlacementTable.ColumnCount = 2 TreePlacementTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "absolute" 160) TreePlacementTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100) Table.Controls.Add TreePlacementTable 0 2 TreePlacementLabel = RS_dotNetUI.InitLabel "Tree Placement" RS_dotNetPreset.TA.MiddleLeft TreePlacementLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 TreePlacementLabel.BackColor = this.TitleColor ToolTip.SetToolTip TreePlacementLabel "Vertically place trees on ground planes below." TreePlacementTable.Controls.Add TreePlacementLabel 0 0 TreePlacementTable.SetColumnSpan TreePlacementLabel 2 SlopeLabel = RS_dotNetUI.InitLabel "Inherit Slope Angle" RS_dotNetPreset.TA.MiddleLeft SlopeLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 TreePlacementTable.Controls.Add SlopeLabel 0 1 SlopeSpinner = dotNetObject "NumericUpDown" SlopeSpinner.Dock = RS_dotNetPreset.DS.Fill SlopeSpinner.value = 0 SlopeSpinner.Minimum = 0 SlopeSpinner.Maximum = 1 SlopeSpinner.Increment = 0.1 SlopeSpinner.DecimalPlaces = 2 TreePlacementTable.Controls.Add SlopeSpinner 1 1 RandomLabel = RS_dotNetUI.InitLabel "Random Rotation" RS_dotNetPreset.TA.MiddleLeft RandomLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4 TreePlacementTable.Controls.Add RandomLabel 0 2 RandomSpinner = dotNetObject "NumericUpDown" RandomSpinner.Dock = RS_dotNetPreset.DS.Fill RandomSpinner.value = 0 RandomSpinner.Minimum = 0 RandomSpinner.Maximum = 1 RandomSpinner.Increment = 0.1 RandomSpinner.DecimalPlaces = 2 TreePlacementTable.Controls.Add RandomSpinner 1 2 TreePlacementButton = RS_dotNetUI.InitButton "Place Selected Trees" TreePlacementButton.Margin = this.ButtonPadding dotNet.AddEventHandler TreePlacementButton "Click" PlaceTrees TreePlacementTable.Controls.Add TreePlacementButton 0 3 TreePlacementTable.SetColumnSpan TreePlacementButton 2 ------------------------------------------------------------------------------- --INFO PANEL ------------------------------------------------------------------------------- InfoPanel = RS_dotNetUI.InitLabel "Vegetation tools" RS_dotNetPreset.TA.MiddleLeft InfoPanel.Padding = dotNetObject "System.Windows.Forms.Padding" 8 InfoPanel.BackColor = RS_dotNetPreset.ColorClass.black Table.Controls.Add InfoPanel 0 3 --draw form Form.ShowModeless() Form ) ) if VegToolsUI != undefined then VegToolsUI.Form.Close() VegToolsUI = VegetationToolsUI() VegToolsUI.CreateUI()