How To - Practical Examples >

# How To ... Flatten a SplineShape

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
Package the code as macroScript to be able to use as a button, menu item or shortcut.
Enable the script only when a single Editable Spline without modifiers has been selected.
When executed, go through all splines in the shape
For each spline, go through all knots (vertices)
For each knot, set the Z coordinate of the In and Out tangent to the shape’s Z position
For each knot, set knot’s Z coordinate to the shape’s Z position
When ready with all splines and knots, update the shape.

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 $ )--end execute

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 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