Notifications
Clear all

[Closed] How to optimize this code

in your algorithm I see some logical mistake…
you want to smooth edges and you use NURMS Subdivision for that. It’s subdivides whole mesh but you actually need to subdivide only chamfered edges. The right way is to use polyop.meshSmoothByEdge

Hi Denis…Thanks again
I accept your suggestion
This is the script interface.
This may explain what I want to achieve.


 if deRoll  != undefined do try (destroyDialog deRoll) catch()
  rollout deRoll " Deformed Edges"
  (
  	fn filtObj obj = (isKindOf obj Editable_Poly and obj.modifiers.count == 0)
  		
  	label deLbl0 " ••• Pick and Prepare Object •••" pos:[0,0] width:160 height:16 style_sunkenedge:true
  	pickbutton deBtn0 "Pick E-Poly Object" pos:[2,18] width:136 height:18 tooltip:"Pick Editable Poly Object" filter:filtObj
  	button deBtn1 "C" pos:[140,18] width:18 height:18 tooltip:"Clear"
  	button deBtn2 "Select Hard Edges" pos:[2,38] width:136 height:18 tooltip:"Pick Editable Poly Object"
  	button deBtn3 "R" pos:[140,38] width:18 height:18 tooltip:"Reset Spinners"
  	spinner deSpn0 "MinAngle:			" pos:[3,58] fieldwidth:60 height:16 range:[-360,360,60] type:#float
  	spinner deSpn1 "MaxAngle:		   " pos:[2,76] fieldwidth:60 height:16 range:[-360,360,120] type:#float
  	label deLbl1 "		••• Deform Options ••• " pos:[0,94] width:160 height:16 style_sunkenedge:true
  	button deBtn4 "Click to Analize Topology" pos:[2,112] width:156 height:18 tooltip:"Pick Editable Poly Object"
  	label deLbl2 " > object need to be analized!" pos:[0,132] width:160 height:16
  	spinner deSpn2 "Chamfer Amount:" pos:[2,150] fieldwidth:60 height:16 range:[0.001,1e3,1] type:#float
  	spinner deSpn3 "Edge Division:	  " pos:[2,168] fieldwidth:60 height:16 range:[1,10,3] type:#float
  	spinner deSpn4 "Vertex Offset:	 " pos:[2,186] fieldwidth:60 height:16 range:[0,1e4,0.1] type:#float
  	button deBtn5 "Random Seed" pos:[2,204] width:85 height:16 tooltip:"Pick Editable Poly Object"
  	spinner deSpn5 "" pos:[87,204] fieldwidth:60 height:16 range:[0e6,9e6,123456] type:#integer
  	checkbox deCb0 "Use Interactive Mode" pos:[2,222] width:156 height:16 
  	button deBtn6 "Revert Object Topology" pos:[2,240] width:156 height:18
  	button deBtn7 "Deform Hard Edges" pos:[2,260] width:156 height:18
  	
  )
  createdialog deRoll 160 280 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow) 

With button “Click to Analize Topology” pressed i will get next info:

–> Poly Count (with this info the script decide when the user can use “interactive mode”
and disable or enable checkbox ) and number of elements (if obj have multiple element)

–> Number of selected edges and longest edge in selection
(i think that is smart move to lighter up main function)

–>Do a snapshot as mash of picked object (for Revert object topology)
I’ll add funcions and events later.
What do you think?

originally posted by DenisT
you want to smooth edges and you use NURMS Subdivision for that. It’s subdivides whole mesh but you actually need to subdivide only chamfered edges. The right way is to use polyop.meshSmoothByEdge

Use NURMS Subdivision is only for preview.
Look script interface. I remove that.

Here is my work in progress.


 global deRoll
 if deRoll  != undefined do try (destroyDialog deRoll) catch()
 rollout deRoll " Deformed Edges v1.0"
 (
 	local defObj, selEdges, backupObj
 	local IneractiveMode = false
 	local divisionsArr = #()
 	local backupObj 
 	fn filtObj obj = (isKindOf obj Editable_Poly and obj.modifiers.count == 0)
 	fn edgeFacesAngle dir1 dir2 = (acos (dot (normalize dir2) (normalize dir1)))
 	fn getSnapshot obj =
 	(
 		smesh = (p = convertToPoly (snapshot obj)).mesh
 		delete p ; smesh
 	)
 	fn selectHardEdges obj minAngle maxAngle =
 	(
 		local edgelist = #{} 
 		getedgefaces = polyOp.getEdgeFaces
 		getFnormal = polyop.getFaceNormal
 		edgeCnt = polyop.getNumEdges obj
 		for ed in 1 to edgeCnt where (getedgefaces obj ed).count == 2 do
 		(
 			facesArr = (getedgefaces obj ed)
 			dir1 = (getFnormal obj facesArr[1])
 			dir2 = (getFnormal obj facesArr[2])
 			theAngle = edgeFacesAngle dir1 dir2
 			if theAngle >= minAngle and theAngle <= maxAngle do append edgelist ed
 		)
 		if edgelist.numberSet != 0 do
 		(
 			obj.selectededges = edgelist
 			if getCommandPanelTaskMode() != #modify do setCommandPanelTaskMode mode:#modify
 			modPanel.setCurrentObject obj	; subobjectLevel = 2
 		)
 	)	
 	fn calculateDivisions obj edgeslist divVal =
 	(
 		getedgeverts = polyOp.getEdgeVerts
 		getvertpos = polyOp.getVert
 		edgeLenghts = for edge in edgeslist collect
 		(
 			vv = getedgeverts obj edge
 			distance (getvertpos obj vv[1]) (getvertpos obj vv[2])
 		)
 		maxEdgesLength = amax edgeLenghts
 		for eLength in edgeLenghts collect ((ceil (eLength / (maxEdgesLength/divVal)))-1) as integer
 	)
 	fn deformEdges obj edgelist divideArr chamferAmount: rand: seedValue: =
 	(
 		seed seedValue ; id = 0
 		chamferedges = polyOp.chamferEdges
 		getedgeverts = polyOp.getEdgeVerts 
 		movevert = polyOp.moveVert 
 		divideedge = polyOp.divideEdge
 		getnumedges = polyOp.getNumEdges
 		getvertpos = polyOp.getVert
 		
 		for edge in edgelist do --divide edges
 		(
 			divideIdx = divideArr[id += 1]
 			if divideIdx != 0 do ( for d = divideIdx to 1 by -1.0 do divideedge obj edge (1 - 1/(d+1)) )
 	   )	
 		chamferedges obj obj.selectededges chamferAmount -- chamfer edge with given a value
 		verts = polyOp.getVertsUsingEdge obj obj.selectededges
 		for v in verts do movevert obj v (random -rand rand)
 		polyOp.retriangulate obj obj.faces -- retriangulate faces
 		polyOp.setFaceSmoothGroup obj obj.faces 0 -- clear SmoothGroup
 	)
 
 	label deLbl0 " ••• Pick and Prepare Object •••" pos:[0,0] width:160 height:16 style_sunkenedge:true
 	pickbutton deBtn0 "Pick E-Poly Object" pos:[2,18] width:136 height:18 tooltip:"Pick Editable Poly Object" filter:filtObj
 	button deBtn1 "C" pos:[140,18] width:18 height:18 tooltip:"Clear"
 	button deBtn2 "Select Hard Edges" pos:[2,38] width:136 height:18 tooltip:"Pick Editable Poly Object"
 	button deBtn3 "R" pos:[140,38] width:18 height:18 tooltip:"Reset Angle Spinners"
 	spinner deSpn0 "MinAngle:			" pos:[3,58] fieldwidth:60 height:16 range:[-360,360,60] type:#float
 	spinner deSpn1 "MaxAngle:		   " pos:[2,76] fieldwidth:60 height:16 range:[-360,360,120] type:#float
 	label deLbl1 "		••• Deform Options ••• " pos:[0,94] width:160 height:16 style_sunkenedge:true
 	button deBtn4 "Click to Analize Topology" pos:[2,112] width:156 height:18 tooltip:"Pick Editable Poly Object"
 	label deLbl2 " > object need to be analized!" pos:[0,132] width:160 height:16
 	spinner deSpn2 "Chamfer Amount:" pos:[2,150] fieldwidth:60 height:16 range:[0.001,1e3,1] type:#float
 	spinner deSpn3 "Edge Division:	  " pos:[2,168] fieldwidth:60 height:16 range:[1,10,3] type:#float
 	spinner deSpn4 "Vertex Offset:	 " pos:[2,186] fieldwidth:60 height:16 range:[0,1e4,0.1] type:#float
 	button deBtn5 "Random Seed" pos:[2,204] width:85 height:16 tooltip:"Pick Editable Poly Object"
 	spinner deSpn5 "" pos:[87,204] fieldwidth:60 height:16 range:[0e6,9e6,123456] type:#integer
 	checkbox deCb0 "Use Interactive Mode" pos:[2,222] width:156 height:16 enabled:false
 	button deBtn6 "Revert Object Topology" pos:[2,240] width:156 height:18 enabled:false
 	button deBtn7 "Deform Hard Edges" pos:[2,260] width:156 height:18 enabled:false
 	
 	/*
 	on deSpn2 changed val do --Chamfer Amount
 	(
 		if deCb0.checked == true do
 		(
 			--REVERT OBJECT HERE
 			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
 			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
 			undo off deformEdges defObj selEdges divisionsArr chamferAmount:val rand:offset seedValue:deSpn5.value
 		)
 	)
 	on deSpn3 changed val do --Edge Division
 	(
 		if deCb0.checked == true do
 		(
 			--REVERT OBJECT HERE
 			divisionsArr = calculateDivisions defObj selEdges val
 			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
 			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
 			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
 		)
 	)
 	on deSpn4 changed val do --Vertex Offset
 	(
 		if deCb0.checked == true do
 		(	
 			--REVERT OBJECT HERE
 			offset = [val,val,val]
 			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
 			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
 		)			
 	)
 	on deSpn5 changed val do --Random Seed
 	(
 		if deCb0.checked == true do
 		(	
 			--REVERT OBJECT HERE
 			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
 			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
 			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:val
 		)
 	)*/	
 	on deBtn0 picked obj do --Pick E-Poly Object
 	(
 		if isValidNode obj == true do
 		(
 			deBtn0.text = obj.name
 			defObj = obj
 			backupObj = getSnapshot obj
 		)
 	)
 	on deBtn1 pressed do (deBtn0.text = "Pick E-Poly Object" ; defObj = undefined) --Clear
 	on deBtn2 pressed do --Select Hard Edges
 	(
 		if isValidNode defObj do (selectHardEdges defObj deSpn0.value deSpn1.value)
 	)
 	on deBtn3 pressed do (deSpn0.value = 60 ; deSpn1.value = 120) --Reset Angle Spinners
 	on deBtn4 pressed do --Click to Analize Topology
 	(
 		if isValidNode defObj do 
 		(
 			selEdges = defObj.selectededges as bitarray
 			if selEdges.numberSet == 0 then (#abort ; messageBox "Select edges first!" title:"Warning" beep:false) else
 			(
 				
 				deBtn7.enabled = true
 				deLbl2.text = " > ready for deformation!"
 				divisionsArr = calculateDivisions defObj selEdges deSpn3.value
 				polyCount = polyOp.getNumEdges defObj
 				if polyCount >= 1e6 do (messageBox ("Object polygon count is "+polyCount as string+"
Not recommended to use interactive mode") title:"Warning" beep:false)
 			)
 		)
 	)
 	on deBtn5 pressed do (deSpn5.value = random 100000.0 999999) --Random Seed
 	on deBtn6 pressed do --Revert Object Topology
 	(
 		if isValidNode defObj and classof backupObj == TriMesh do 
 		(
 			defObj.baseobject = backupObj
 			deBtn7.enabled = true
 			deBtn6.enabled = deCb0.enabled = deCb0.checked = false 
 		)
 	)
 	on deBtn7 pressed do
 	(
 		if isValidNode defObj and selEdges.numberSet != 0 do
 		(
 			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
 			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
 			t1 = timestamp() ; m1 = heapfree
 			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
 			format "time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
 			deBtn6.enabled = deCb0.enabled = true
 			deBtn7.enabled = false
 		)
 	)		
 )
 createdialog deRoll 160 280 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)
  

Changes:
–Main function is optimized by removing division calculation.
–I decide to separately calculate divisions for each selected edge
and place result in array by using function “calculateDivisions”.
–Performing the test on the same model i got this result (time:49 memory:20832L)
–The settings I used are shown in the image below

The following are the things where I got stuck.
1st “Revert Object Topology” button, and 2nd “Use Interactive Mode”.:shrug:
I try with this in Lisener:


     originalObj = $Box001 --(already converted to editpoly)
     beckupObj = node
     --Now i use this function
     fn getSnapshot obj &backupObj =
(
	backupObj = (p = copy obj).mesh
	delete p
)
     beckupObj = getSnapshot originalObj
     --Then i deform and change topology of the "Box001"
     --To back to original shape (form), I used
     originalObj.baseobject = beckupObj
 This work fine in listener but when i use this in the script then i recive this:

     -- Error occurred in deBtn6.pressed(); filename: D:\Temp\Deformed Edges.ms; position: 5531; line: 126
     --  [color=Blue]Frame:[/color]
     >> MAXScript Rollout Handler Exception:
     -- Unknown system exception <<
 Any new suggestion or method for *Reverting object topology* and *Interactive Mode*?
 Thanks in advance

Work in progress (part2)
Hi guys,
I solved *Reverting object topology* problem for returning the model to it’s original state.
Also Interactive Mode now works, but is not recommended to be used on high poly models.
Added use NURMS subdivision only as preview mode.
I use timer control to reset all paremeters to default when the model is removed from the script or deleted from the scene.
Any suggestion for optimization or upgrade are welcome.
All credits go Denis Trofimov (Denis T) that helped me to solve this “puzzle”.
Regards!

global deRoll
   if deRoll  != undefined do try (destroyDialog deRoll) catch()
   rollout deRoll " Deformed Edges v1.0a"
   (
   	global backupObj = undefined
   	local defObj, selEdges, polyCount, ctrlState
   	local divisionsArr = #()
   	
   	fn filtObj obj = (isKindOf obj Editable_Poly and obj.modifiers.count == 0)
   	fn edgeFacesAngle dir1 dir2 = (acos (dot (normalize dir2) (normalize dir1)))
   	fn getSnapshot obj &backupObj =
   	(
   		backupObj = (p = copy obj).baseobject
   		delete p
   	)
   	fn selectHardEdges obj minAngle maxAngle =
   	(
   		local edgelist = #{} 
   		getedgefaces = polyOp.getEdgeFaces
   		getFnormal = polyop.getFaceNormal
   		edgeCnt = polyop.getNumEdges obj
   		for ed in 1 to edgeCnt where (getedgefaces obj ed).count == 2 do
   		(
   			facesArr = (getedgefaces obj ed)
   			dir1 = (getFnormal obj facesArr[1])
   			dir2 = (getFnormal obj facesArr[2])
   			theAngle = edgeFacesAngle dir1 dir2
   			if theAngle >= minAngle and theAngle <= maxAngle do append edgelist ed
   		)
   		if edgelist.numberSet != 0 do
   		(
   			obj.selectededges = edgelist
   			if getCommandPanelTaskMode() != #modify do setCommandPanelTaskMode mode:#modify
   			modPanel.setCurrentObject obj ; subobjectLevel = 2
   		)
   	)	
   	fn calculateDivisions obj edgeslist divVal =
   	(
   		getedgeverts = polyOp.getEdgeVerts
   		getvertpos = polyOp.getVert
   		edgeLenghts = for edge in edgeslist collect
   		(
   			vv = getedgeverts obj edge
   			distance (getvertpos obj vv[1]) (getvertpos obj vv[2])
   		)
   		maxEdgesLength = amax edgeLenghts
   		for eLength in edgeLenghts collect ((ceil (eLength / (maxEdgesLength/divVal)))-1) as integer
   	)
   	fn deformEdges obj edgelist divideArr chamferAmount: rand: seedValue: =
   	(
   		seed seedValue ; id = 0
   		chamferedges = polyOp.chamferEdges
   		getedgeverts = polyOp.getEdgeVerts 
   		movevert = polyOp.moveVert 
   		divideedge = polyOp.divideEdge
   		getnumedges = polyOp.getNumEdges
   		getvertpos = polyOp.getVert
   		
   		for edge in edgelist do --divide edges
   		(
   			divideIdx = divideArr[id += 1]
   			if divideIdx != 0 do ( for d = divideIdx to 1 by -1.0 do divideedge obj edge (1 - 1/(d+1)) )
   	   )	
   		chamferedges obj obj.selectededges chamferAmount -- chamfer edge with given a value
   		verts = polyOp.getVertsUsingEdge obj obj.selectededges
   		for v in verts do movevert obj v (random -rand rand)
   		polyOp.retriangulate obj obj.faces -- retriangulate faces
   		polyOp.setFaceSmoothGroup obj obj.faces 0 -- clear SmoothGroup
   	)
   
   	label deLbl0 " ••• Pick and Prepare Object •••" pos:[0,0] width:160 height:16 style_sunkenedge:true
   	pickbutton deBtn0 "Pick E-Poly Object" pos:[2,18] width:136 height:18 tooltip:"Pick Editable Poly Object" filter:filtObj
   	button deBtn1 "C" pos:[140,18] width:18 height:18 tooltip:"Clear"
   	button deBtn2 "Select Hard Edges" pos:[2,38] width:136 height:18 tooltip:"Pick Editable Poly Object"
   	button deBtn3 "R" pos:[140,38] width:18 height:18 tooltip:"Reset Angle Spinners"
   	spinner deSpn0 "MinAngle:			" pos:[3,58] fieldwidth:60 height:16 range:[-360,360,60] type:#float
   	spinner deSpn1 "MaxAngle:		   " pos:[2,76] fieldwidth:60 height:16 range:[-360,360,120] type:#float
   	label deLbl1 "		••• Deform Options ••• " pos:[0,94] width:160 height:16 style_sunkenedge:true
   	button deBtn4 "Click to Analize Topology" pos:[2,112] width:156 height:18 tooltip:"Pick Editable Poly Object"
   	label deLbl2 " > object need to be analized!" pos:[0,132] width:160 height:16
   	spinner deSpn2 "Chamfer Amount:" pos:[2,150] fieldwidth:60 height:16 range:[0.001,1e3,1] type:#float
   	spinner deSpn3 "Edge Division:	  " pos:[2,168] fieldwidth:60 height:16 range:[1,10,3] type:#integer
   	spinner deSpn4 "Vertex Offset:	 " pos:[2,186] fieldwidth:60 height:16 range:[0,1e4,0.1] type:#float
   	button deBtn5 "Random Seed" pos:[2,204] width:85 height:16 tooltip:"Pick Editable Poly Object"
   	spinner deSpn5 "" pos:[87,204] fieldwidth:60 height:16 range:[0e6,9e6,123456] type:#integer
   	checkbutton deBtn6 "Preview UNS" pos:[2,222] width:85 height:16 tooltip:"Use NURMS Sudivision"
   	spinner deSpn6 "" pos:[87,222] fieldwidth:60 height:16 range:[0,5,2] type:#integer tooltip:"Display Iterations"
   	checkbox deCb0 "Use Interactive Mode" pos:[2,240] width:156 height:16 enabled:false
   	button deBtn7 "Revert Object Topology" pos:[2,260] width:156 height:18 enabled:false
   	button deBtn8 "Deform Hard Edges" pos:[2,280] width:156 height:18 enabled:false
   	timer clock "Reseter" interval:100 active:false
   
   	fn resetAllCtrls = 
   	(
   		deBtn0.text = "Pick E-Poly Object"
   		deLbl2.text = " > object need to be analized!"
   		deSpn0.value = 60
   		deSpn1.value = 120
   		deSpn2.value = 1
   		deSpn3.value = 3
   		deSpn4.value = 0.1
   		deSpn5.value = 123456
   		deSpn6.value = 2
   		deBtn6.checked = deCb0.checked = deCb0.enabled = deBtn7.enabled = deBtn8.enabled = false
   		defObj = undefined ; backupObj = undefined
   		free selEdges ; free divisionsArr ; gc()
   	)
   	on deBtn0 picked obj do --Pick E-Poly Object
   	(
   		if isValidNode obj == true do
   		(
   			deBtn0.text = obj.name
   			getSnapshot obj &backupObj
   			defObj = obj
   			clock.active = true
   		)
   	)
   	on deBtn1 pressed do (resetAllCtrls())--Clear
   	on deBtn2 pressed do --Select Hard Edges
   	(
   		if isValidNode defObj do (selectHardEdges defObj deSpn0.value deSpn1.value)
   	)
   	on deBtn3 pressed do (deSpn0.value = 60 ; deSpn1.value = 120) --Reset Angle Spinners
   	on deBtn4 pressed do --Click to Analize Topology
   	(
   		if isValidNode defObj do 
   		(
   			selEdges = defObj.selectededges as bitarray
   			if selEdges.numberSet == 0 then (#abort ; messageBox "Select edges first!" title:"Warning" beep:false) else
   			(
   				deBtn8.enabled = true
   				deLbl2.text = " > ready for deformation!"
   				divisionsArr = calculateDivisions defObj selEdges deSpn3.value
   				polyCount = polyOp.getNumEdges defObj
   				if polyCount >= 1e4 do (messageBox ("Object polygon count is "+polyCount as string+"
Not recommended to use interactive mode") title:"Warning" beep:false)
   			)
   		)
   	)
   	on deSpn2 changed val do --Chamfer Amount
   	(
   		if deCb0.checked == true do
   		(
   			if polyOp.getNumEdges defObj != polyCount do 
   			(
   				defObj.baseobject = backupObj
   				getSnapshot defObj &backupObj
   				defObj.selectededges = selEdges
   			)
   			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
   			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
   			undo off deformEdges defObj selEdges divisionsArr chamferAmount:val rand:offset seedValue:deSpn5.value
   		)
   	)
   	on deSpn3 changed val do --Edge Division
   	(
   		if deCb0.checked == true do
   		(
   			if polyOp.getNumEdges defObj != polyCount do 
   			(
   				defObj.baseobject = backupObj
   				getSnapshot defObj &backupObj
   				defObj.selectededges = selEdges
   			)
   			divisionsArr = calculateDivisions defObj selEdges val
   			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
   			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
   			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
   		)
   	)
   	on deSpn4 changed val do --Vertex Offset
   	(
   		if deCb0.checked == true do
   		(	
   			if polyOp.getNumEdges defObj != polyCount do 
   			(
   				defObj.baseobject = backupObj
   				getSnapshot defObj &backupObj
   				defObj.selectededges = selEdges
   			)
   			offset = [val,val,val]
   			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
   			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
   		)			
   	)	
   	on deBtn5 pressed do --Random Seed
   	(
   		deSpn5.value = random 100000.0 999999
   		if deCb0.checked == true do
   		(	
   			if polyOp.getNumEdges defObj != polyCount do 
   			(
   				defObj.baseobject = backupObj
   				getSnapshot defObj &backupObj
   				defObj.selectededges = selEdges
   			)
   			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
   			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
   			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
   		)		
   	)
   	on deSpn5 changed val do --Random Seed
   	(
   		if deCb0.checked == true do
   		(	
   			if polyOp.getNumEdges defObj != polyCount do 
   			(
   				defObj.baseobject = backupObj
   				getSnapshot defObj &backupObj
   				defObj.selectededges = selEdges
   			)
   			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
   			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
   			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:val
   		)
   	)	
   	on deBtn6 changed state do -- Preview: Use NURMS Sudivision
   	(
   		if isValidNode defObj do 
   		(
   			local ctrlArr = #(deCb0,deBtn7,deBtn8)
   			if state == on then 
   			(
   				defObj.surfSubDivide = on ; defObj.iterations = deSpn6.value
   				ctrlState = for c in ctrlArr collect (c.enabled) ; append ctrlState ctrlArr[1].checked
   				format "%
" ctrlState
   				deCb0.enabled = deCb0.checked = deBtn7.enabled = deBtn8.enabled = false
   			)
   			else 
   			(
   				defObj.surfSubDivide = off
   				for i in 1 to 3 do (ctrlArr[i].enabled = ctrlState[i])
   				ctrlArr[1].checked = ctrlState[4]
   			)
   		)
   	)	
   	on deSpn6 changed val do --Display Iterations
   	(
   		if isValidNode defObj and deBtn6.checked == true do defObj.iterations = val
   	)
   	on deBtn7 pressed do --Revert Object Topology
   	(
   		if isValidNode defObj do 
   		(
   			format "%
" backupObj
   			defObj.baseobject = backupObj
   			getSnapshot defObj &backupObj
   			defObj.selectededges = selEdges
   			setCommandPanelTaskMode mode:#modify
   			subobjectLevel = 2 ; deBtn8.enabled = true
   			deBtn7.enabled = deCb0.enabled = deCb0.checked = false 
   		)
   	)
   	on deBtn8 pressed do
   	(
   		if isValidNode defObj and selEdges.numberSet != 0 do
   		(
   			offset = [deSpn4.value,deSpn4.value,deSpn4.value]
   			if getCommandPanelTaskMode() != #create do setCommandPanelTaskMode mode:#create
   			t1 = timestamp() ; m1 = heapfree
   			undo off deformEdges defObj selEdges divisionsArr chamferAmount:deSpn2.value rand:offset seedValue:deSpn5.value
   			format "time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
   			deBtn7.enabled = deCb0.enabled = true
   			deBtn8.enabled = false
   		)
   	)
   	on clock tick do (if not isValidNode (getNodeByName deBtn0.text) do (resetAllCtrls() ; clock.active = false))
   	on deRoll close do (backupObj = undefined ; gc() ; clearListener())
   )
   createdialog deRoll 160 300 10 110 style:#(#style_titlebar, #style_sysmenu, #style_toolwindow)

Cool stuff you have going here.

Thanks John.

I think this tool will be useful to someone.
I would like to see your comment or criticism after all.
Finished script Deformed Edges can be found at this address:
http://www.scriptspot.com/3ds-max/scripts/deformed-edges
Cheers!

Script is updated to version 1.1
Version 1.1 New Features:

  • now you can use BEVEL operation to create a stitches
    NOTE: To disable bevel option just set Bevel Height value to ZERO.
  • added Preview Checker Map options for cheking the model UV’s.
    Link: Deformed Edges v1.1
Page 4 / 8