ADOBE AFTER EFFECTS: Forum Expressions Tutorials Creative Cloud

# correct scaling for in/out tangents in a mask-related script

FAQ   •   VIEW ALL
 correct scaling for in/out tangents in a mask-related script on Oct 29, 2011 at 3:41:12 pm

Hello,
i'm writing my first script, which is intended to draw various types of spiral-shaped pathes on a mask.
It's working fine, until i try to implement custom tangents: the direction is ok but the length is really puzzling me and i don't know how to normalize them.

Let's say the ideal (continuous) path has coordinates (X(u), Y(u)), the parameter u running from 0 to infinity. The script takes a finite number of points in that curve and set them as vertices of the path.
Setting only the vertices gives a linear-by-part path, and to mimic the ideal curve one has to implement the tangents.
The in- and out- tangents at point (X(u),Y(u)) are both proportionnal to (X'(u),Y'(u)) (the derivative of the position) but i can't figure out what is the scale to use. I have tested lots of things and apparently it depends on how far are the next and previous vertices in the path.

Someone knows how it works ?

 Re: correct scaling for in/out tangents in a mask-related scripton Oct 29, 2011 at 6:21:12 pm

I haven't worked out the math for a spiral, but if you look at the way that Illustrator creates them, it appears to put all the vertices on two lines that are at right angles to each other. Adjacent tangents also seem to be at right angles to each other with the handles at some fixed percentage (looks like about 57%) of the distance from the vertex to the corner of the right angle. It seems like you should be able to work it out from there.

Dan

 Re: correct scaling for in/out tangents in a mask-related scripton Oct 29, 2011 at 7:07:27 pm

Thank you for the answer, but it doesnt solve my problem.
The script, as i plan it, should be able to handle an arbitray number of vertices per cycle, or even have them in random distribution (so when rotobezier is off it looks like a regular or irregular spider net.), and also be able to play with tangents orientation and length.
But for I this should know what are the smoothest values for the tangents (the ones that reproduce the most the original curve). I tried to have them autocalculated by AE like this:

myPath.vertices = V_Array; //the array of vertices
myPath.rotoBezier = true;

it returns no error but doesnt work, the mask is a concatenation of segments... I'd love to know the correct syntax !

 Re: correct scaling for in/out tangents in a mask-related scripton Oct 30, 2011 at 12:36:12 am

I think it won't work unless you give it some tangents. This seems to work:

``` { var V_Array = [[100,100],[200,50],[300,150],[175,210],[150,120],[220,125]]; var IT_Array = [[1,0],[1,0],[1,0],[1,0],[1,0],[1,0]]; var OT_Array = [[-1,0],[-1,0],[-1,0],[-1,0],[-1,0],[-1,0]]; var myLayer = app.project.activeItem.layer(1); var myMask = myLayer.Masks.addProperty("ADBE Mask Atom"); myProperty = myMask.property("ADBE Mask Shape"); myPath = myProperty.value; myPath.vertices = V_Array; myPath.inTangents = IT_Array; myPath.outTangents = OT_Array; myPath.closed = false; myProperty.setValue(myPath); myMask.rotoBezier = true; } ```

Dan

 Re: correct scaling for in/out tangents in a mask-related scripton Nov 2, 2011 at 12:47:33 pm

Thank you, this indeed turns rotobezier ON.
However rotobezier gives poor result unless one inputs some already good enough values for the tangents.

In case someone faces the same problem in the future, I post below a short script based on some doc on Bezier interpolation found there: http://people.sc.fsu.edu/~jburkardt/html/bezier_interpolation.html. (sorry, can't figure out how the link tool is working !)

This script assumes that what AE calls Bezier interpolation is really a Bezier interpolation (there are many other types of interpolations similar to Bézier). But it works very well so it should be the case, and the algorythm will vectorize properly most curves (smooth enough, curves with sharp variation like sin with very high frenquency require more vertices).
It creates 3 times more points than the number of vertices of the path (2/3 of these points are here to make sure that the path will walk through them). The funny numbers have their explanation in the doc linked above.

Note: this is just the bit of code needed to get the Vertex and Tangents arrays. The script won't run as it is. To run it, one has to complete the input and add lines like:
var myLayer = app.project.activeItem.layer(1);
myPath = myProperty.value;
myPath.vertices = V_Array; myPath.inTangents = IT_Array; myPath.outTangents = OT_Array;
myPath.closed = CloseBoolean;
myProperty.setValue(myPath);
(etc.)

```function CurvePoint(u) { // the curve function var x; var y; x = ; // input function there y = ; // input function there return([x,y]); } function VectorNorm(X){ // optionnal, for more smoothing return(Math.sqrt(X[0]*X[0]+X[1]*X[1])) } function Average(X,weightX,Y,weightY){ // optionnal, for more smoothing var pX=weightX /(weightX+weightY); var pY=weightY /(weightX+weightY); return ( pX * X + pY * Y ); } var Nvertex =....; // the number of vertex you want in your path var u_min = ... ; // the min value for the curve parameter var u_max = ... ; // the max value for the curve parameter // some other parameters for the curve var CloseBoolean = false; // true for a closed path, false for open var SmoothBoolean = false; var rotoBezierBoolean = false; // var P_Array=new Array(); var V_Array=new Array(); // the array of vertices var iT_Array=new Array(); // the array of inTangents var oT_Array=new Array(); // the array of outTangents var newP=new Array(); for (i=0; i <= 3*Nvertex; i++) { // creates the array of ALL POINTS (the actual vertices + intermediary hidden control points) u = u_min + i * (u_max-u_min)/(3*(Nvertex)); // for uniform parameter set. This should be adapted to the need. P_Array[i] = CurvePoint(u); } for (i=0; i < Nvertex ; i++) { // builds the Vertex, inTangents and OutTangents arrays // builds the Vertex Array V_Array[i] = P_Array[3*i]; // builds the IN Tangents Array if (i < 0) iT_Array[i] = ( 2*P_Array[3*i-3] - 9* P_Array[3*i-2] + 18*P_Array[3*i-1] - 11*P_Array[3*i] ) /6; else{ if (CloseBoolean == false) iT_Array[0] = [0,0]; else iT_Array[0] = (2*P_Array[3*(Nvertex)-3] - 9* P_Array[3*(Nvertex)-2] + 18*P_Array[3*(Nvertex)-1] - 11*P_Array[0])/6; } // builds the OUT Tangents Array if (i < Nvertex-1) oT_Array[i] = (-11* P_Array[3*i] + 18*P_Array[3*i+1] - 9*P_Array[3*i+2] + 2*P_Array[3*i+3])/6; else{ if (CloseBoolean == false) oT_Array[Nvertex-1]=[0,0]; else oT_Array[Nvertex-1] = ( -11* P_Array[3*(Nvertex-1)] + 18*P_Array[3*(Nvertex-1)+1] - 9*P_Array[3*(Nvertex-1)+2] + 2*P_Array[0] ) /6; } } //some optionnal smoothing if (SmoothBoolean == true){ Temp= new Array(); var o_norm; var i_norm; for (i=0; i &lt; Nvertex ; i++) { o_norm=VectorNorm(oT_Array[i]); i_norm=VectorNorm(iT_Array[i]); if (o_norm+i_norm > 0){ Temp= Average(oT_Array[i],o_norm,-iT_Array[i],i_norm) oT_Array[i]=(1+(o_norm-i_norm)/(o_norm+i_norm)) * Temp; iT_Array[i]= -(1-(o_norm-i_norm)/(o_norm+i_norm)) * Temp; } } } ```