How To ... Flatten a SplineShape

The following tutorial shows how to access and modify the splines and their knots (vertices) and tangents in a SplineShape. The resulting macroScript will move all knots to the Z height defined by the shape’s Z position, thus aligning them to a plane parallel to the ground XY world construction plane.

Related Topics:

Defining MacroScripts

SplineShape : Shape

Spline Shape Common Properties, Operators, and Methods

Natural Language:

MAXScript:

macroscript FlattenSpline category:"HowTo" tooltip:"Flatten Spline"

(

on isEnabled return

(

selection.count == 1 and \

(classof selection[1] == SplineShape or \

classof selection[1] == Line) \

and selection[1].modifiers.count == 0

)

on execute do

(

new_z = $.pos.z

for s = 1 to (numSplines $) do

(

for k = 1 to (numKnots $ s) do

(

knt = getKnotPoint $ s k

in_vec = getInVec $ s k

out_vec = getOutVec $ s k

knt.z = in_vec.z = out_vec.z = new_z

setInVec $ s k in_vec

setOutVec $ s k out_vec

setKnotPoint $ s k knt

)--end k loop

)--end s loop

updateshape $

)--end execute

)--end script

Step-By-Step

macroscript FlattenSpline category:"HowTo" tooltip:"Flatten Spline"

(

The macroScript will be called FlattenSpline. To use the script, you can go to Customize... and drag the script from the category "HowTo" to a toolbar, a menu, a quad menu or assign to a keyboard shortcut.

Defining Macro Scripts

 

on isEnabled return

(

selection.count == 1 and \

(classof selection[1] == SplineShape or \

classof selection[1] == Line) \

and selection[1].modifiers.count == 0

)

The macroScript ActionItem (button, menu item, shortcut) will only be enabled when the scene selection contains a single object AND this one object is either a SplineShape class (in other words an EditableSpline) without any modifiers as MAXScript cannot modify a spline with modifiers on top. The result of the expression after the return statement evaluates to true or false. When true, the script becomes enabled.

In these lines we compare the count of the current scene selection with 1, then the class of the first selected object to the class SplineShape. Then once again we compare the class of the first selected object with the class Line as a newly drawn line would be an exception – we can modify it, but the class is not SplineShape until collapsed to EditableSpline. Lastly, we check the number of modifiers and compare to 0.

If the first AND either the second OR the third, AND the fourth condition are true, the selected object is valid and can be modified by the script!

Macroscript_Body_Event_Handlers

ClassOf

ModifierArray Values

 

on execute do

(

The on execute handler contains the actual code. It will be executed whenever the script is started by clicking the button, selecting the item from a menu, using the keyboard shortcut etc.

Macroscript_Body_Event_Handlers

new_z = $.pos.z

We will need the Z coordinate of the splineShape in order to move all Knots and Tangents to that position. We store the Z component of the position of the scene selection in the user variable new_z. Because we already checked in the isEnabled handler that there is only one object selected, we don’t need to use selected[1] to access the first selected object – we are completely sure the $ representing the current selection is actually a single object!

Node Transform Properties

for s = 1 to (numSplines $) do

(

A splineShape can contain any number of splines (a Donut shape for example contains two circles!). To change every single spline, we will create a for loop which counts from 1 to the number of splines in the selected object.

For Loop

SplineShape : Shape

for k = 1 to (numKnots $ s) do

(

Each spline in the shape can contain any number of knots. To change every single knot, we will create another for loop which counts from 1 to the number of knots in the s-th spline – the index of the spline is controlled by the outer for loop. Note that the for k... loop will be executed again and again for each repetition of the for s loop. So these are nested loops!

For Loop

SplineShape : Shape

 

knt = getKnotPoint $ s k

Using getKnotPoint, we read the K-th knot in the S-th spline in the selected splineShape. We store its Point3 world coordinates in the user variable knt.

SplineShape : Shape

in_vec = getInVec $ s k

Then we read the in vector of the K-th knot in the S-th spline in the selected splineShape. We store its Point3 world coordinates in the user variable in_vec.

SplineShape : Shape

out_vec = getOutVec $ s k

We read the out vector of the K-th knot in the S-th spline in the selected splineShape. We store its Point3 world coordinates in the user variable out_vec.

SplineShape : Shape

knt.z = in_vec.z = out_vec.z = new_z

Now we can set the Z coordinate of both vectors and the knot to the new value stored in the new_z variable. Note we can assign the same value to multiple variables as MAXScript processes the expression by evaluating the right-hand side of the assignment first then assigning the result to the left-hand side and so on.

Variable Assignment

setInVec $ s k in_vec

setOutVec $ s k out_vec

Now we can assign the new in and out vectors back to the respective knot and spline.

SplineShape : Shape

setKnotPoint $ s k knt

Then we assign the new knot position back to the respective knot and spline.

SplineShape : Shape

)--end k loop

)--end s loop

updateshape $

Finally, it is very important to update the splineShape. This makes all changes visible by updating the internal data structures. Failing to do so could cause instabilities in 3ds Max.

SplineShape : Shape

)--end execute

)--end script

 

Using the Script

Evaluate the script. To use it, you can use Customize... to drag the script from the category "HowTo" to a toolbar, a menu, a quad menu or to assign to a keyboard shortcut.

Select a single spline in the scene and execute the script. All knots should move to become aligned to the XY plane in the height of the spline’s pivot.

Where to go from here

You could add an UI with options to align to other construction planes or to move the knots to the ground plane (by just using 0.0 instead of new_Z)

Back to

"How To" Tutorials Index Page