Notifications
Clear all

[Closed] Setting Curve Control tangents?

I am working with the Curve Control in MAXScript and am trying to save/load a curve with multiple points, each with custom tangents, unconstrained.
Saving is fine, and loading the values, too. But when I try setting the in/out tangents of curve points, things get weird.

I tried directly setting the .inTangent and .outTangent values of a point, e.g.

curveCtrl.curves[1].points[1].inTangent = <some Point2 value>

but afterwards the resulting tangents of the point have different values. It seems to ignore the X component of the outTangent, at least for the first point.

I also tried using

newPoint = ccPoint pos2 tIn tOut bezier:bez corner:cnr 
setPoint curveCtrl.curves[1] 1 newPoint

as explained in the online help but this produces an error:

Any ideas?

Edit: Here is a small demo script: https://pastebin.com/4AGF63fK
Run the script, open Listener, then click the button to see the problem.

11 Replies

what if you set points in reverse order like so


for i = numPts to 1 by -1 do (

5 Replies
(@martinb)
Joined: 10 months ago

Posts: 0

Yeah, tied that, too. Result are incorrect tangents, too, just slightly different.

(@serejah)
Joined: 10 months ago

Posts: 0

Not sure if it’s correct. It fails only at first inTangent and last outTangent.
max 2014

    fn createCurve = (
        local numPts = 5
        crv.numpoints = numPts      -- create the right number of points

        for i = numPts to 1 by -1 do (
--         for i = 1 to numPts do (
            local p2    = [(i-1)*25.0, (i-1)*25.0]
            local tIn   = [-10,-10]     -- inTangent is 45 degrees down to the left
            local tOut  = [10.0,10.0]         -- outTangent is 45 degrees up to the right
            local bez   = true
            local cnr   = true
 
            if true then (

                cp  = crv.points[i]        -- the current point

                cp.value = p2
                cp.noXConstraint = true
                cp.bezier = bez
                cp.corner = cnr
               
                cp.inTangent  = tIn
                cp.outTangent = tOut
                
                    
                format "--- % ---
" i
                format "tIn = % -- cp.inTangent = %   %
" tIn cp.inTangent (if cp.inTangent!=tIn then "NOT THE SAME VALUE" else "")
                format "tOut = % -- cp.outTangent = %   %
" tOut cp.outTangent (if cp.outTangent!=tOut then "NOT THE SAME VALUE" else "")

            )
         )

    )

(@martinb)
Joined: 10 months ago

Posts: 0

Hm. I swear I tried that in the very beginning without success. But anyway… going backwards seems to work fine, thanks for your help!!
The first and last curve point are somewhat special in CurveControl anyway, so it is probably OK that the in tangent of the first and the out tangent of the last point always have X==0. There are no curve segments in that direction anyway.

Any ideas why we need to start with the last point?

(@denist)
Joined: 10 months ago

Posts: 0

you don’t need to set them in reverse order. everything has to work in normal order. but you have to read my post more careful. instead of using setpoint you have to set the point directly using index access:


p = cc.points[<index>]
p.<param> = <value>
cc.points[<index>] = p

or


p = ccpoint <parameters>
cc.points[<index>] = p

(@martinb)
Joined: 10 months ago

Posts: 0

I see!
I was doing it one property at a time (e.g. first setting point.value, then .bezier, then .inTangent etc.) – it seems that curveControl tries to ‘optimize’ the curves upon each update, e.g. to make sure bezier handles are not too long to overlap with adjacent ones.
Just noticed that you can easily have a situation where you set/create a new point at a certain 2D location which will store that 2D location just fine but will automatically push it to a different 2D location to ‘make enough room’ for adjacent bezier handles…
Sigh…

Thanks for the help!

So setPoints is broken for curveControl because some other plugin overrides it?
I tried to set tangents directly, using curve.points[i].inTangent = <Point2D value> but that isn’t working either; for some points, the…x part of the Point2D value is wrong afterwards…
The script in my first post shows this.

1 Reply
(@martinb)
Joined: 10 months ago

Posts: 0

FWIW, I believe it is NURBS that overrides the setPoint function.

it might be helpful to take a look at one of my earlier snippets:
http://forums.cgsociety.org/showpost.php?p=7028972&postcount=11

Indeed!
Thanks, very useful (and too bad the mxs help is rather thin on these aspects, took me quite some time (and your help) to get things right…)