//############################################################################################################## #macro InterpolateControlPointsFrom (InputPoints) // macro receives an array of 4 data points (vectors - ) with 2 empty spaces between each // macro returns an array with 6 new control points filled in to make a continuous spline // SAMPLE INPUT ARRAY: // #declare Given_data = array[10] {<60, 60, 0>, <0,0,0>, <0,0,0>, <220, 300, 0>, <0,0,0>, <0,0,0>, <420, 300, 0>, <0,0,0>, <0,0,0>, <700, 240, 0>}; // SAMPLE USAGE COMMAND: // #declare Interpolated_data = InterpolateControlPointsFrom (Given_data); #local NoV = false; #local NoSE = false; #ifndef (Verbose) #declare Verbose = false; #local NoV = true; #end #ifndef (ShowEquations) #declare ShowEquations = false; #local NoSE = true; #end //#debug "###############################################################################\n" //#debug concat("ShowEquations = ", str(ShowEquations, 3, 1), " \n") //#declare S = array[4]; #local K = array[4]; // working array for control point x, y, and z components #local CPX = array[6]; // intermediate collection array for control point x components #local CPY = array[6]; // intermediate collection array for control point y components #local CPZ = array[6]; // intermediate collection array for control point z components // Split vector data point array into separate x, y, and z component arrays // data points are at array elements |0--3--6--9| #local X = array[4] {InputPoints[0].x, InputPoints[3].x, InputPoints[6].x, InputPoints[9].x}; #local Y = array[4] {InputPoints[0].y, InputPoints[3].y, InputPoints[6].y, InputPoints[9].y}; #local Z = array[4] {InputPoints[0].z, InputPoints[3].z, InputPoints[6].z, InputPoints[9].z}; #macro computeControlPoints(K) //computes control points given knots K, this is the brain of the operation #local squared = chr(178); #local cubed = chr(179); #local Tx = 0; #local Tz = 0; #local TextLine = 10; #local p1 = array[4]; #local p2 = array[4]; #local n = dimension_size (K, 1) - 1; // 4 points, so dimension size is 4, and so n=3 (array elements 0 to 3) //rhs vector #local a = array[n]; // n=3 #local b = array[n]; // n=3 #local c = array[n]; // n=3 #local r = array[n]; // n=3 //left most segment #local a[0] = 0; #local b[0] = 2; #local c[0] = 1; #local r[0] = K[0] + 2 * K[1]; // first component times twice the second //#if (ShowEquations = true) //text {ttf "arial.ttf" "First Segment - between points 1 and 2 " 0.01, 0 pigment {Blue} translate } //#local TextLine = TextLine - 1; #debug "\n Equations: \n" #debug "###############################################################################\n" #debug "First Segment - between points 1 and 2 \n" #debug concat("a[0]=0, b[0]=2, c[0]=1, r[0] = <1st point {", str(K[0], 3, 0), "}> + 2 * <2nd point {", str(K[1], 3, 0), "}> = ", str(r[0], 3, 0), " \n \n") //text{ttf "arial.ttf" concat("a[0]=0, b[0]=2, c[0]=1, r[0]=<1st point {", str(K[0], 3, 1), "}> + 2 * <2nd point {", str(K[1], 3, 1), "}> \n") 0.01, 0 pigment {Gray50} translate } //#local TextLine = TextLine - 1; //#end //middle segment #debug "Middle Segment - \n" #for (i, 0, n-2) // for i = 0 to 1 | n=3 | n - 2 = 1 #local a[i] = 1; #local b[i] = 4; #local c[i] = 1; #local r[i] = 4 * K[i] + 2 * K[i+1]; #debug concat("a[", str(i, 3, 0), "]=1, b[", str(i, 3, 0), "]=4, c[", str(i, 3, 0), "]=1, r[", str(i, 3, 0), "] = 4 * + 2 * = ", str(r[i], 3, 0), "\n \n") #end //right segment #local a[n-1] = 2; #local b[n-1] = 7; #local c[n-1] = 0; #local r[n-1] = 8 * K[n-1] + K[n]; #debug "Last Segment - between points 3 and 4 \n" #debug concat ("a[", str(n-1, 3, 0), "]=2, b[", str(n-1, 3, 0), "]=7, c[", str(n-1, 3, 0), "]=0, r[", str(n-1, 3, 0), "] = 8 * + = ", str(r[n-1], 3, 0), "\n \n") //------------------------------------------------------------ //solves Ax=b with the Thomas algorithm (from Wikipedia) #for (i, 1, n-1) // for i = 1 to 2 | n=3 | n - 1 = 2 #local m = a[i] / b[i-1]; #local b[i] = b[i] - m * c[i - 1]; #local r[i] = r[i] - m * r[i-1]; #debug concat ("m = a[", str(i, 3, 0), "]{", str(a[i], 3, 0), "} / b[", str(i-1, 3, 0), "]{", str(b[i-1], 3, 0), "} = ", str(m, 3, 0), " \n \n") #debug concat ("b[", str(i, 3, 0), "]= b[", str(i, 3, 0), "] - m{", str(m, 3, 0), "} * c[", str(i-1, 3, 0), "]{", str(c[i-1], 3, 0), "} = ", str(b[i], 3, 0), " \n \n") #debug concat ("r[", str(i, 3, 0), "]= r[", str(i, 3, 0), "] - m{", str(m, 3, 0), "} * r[", str(i-1, 3, 0), "]{", str(r[i-1], 3, 0), "} = ", str(r[i], 3, 0), " \n \n") #end #local p1[n-1] = r[n-1] / b[n-1]; #debug concat ("Defining p1. n-1 = ", str((n-1), 3, 0), "\n") #debug concat ("p1[", str(n-1, 3, 0), "] = r[", str(n-1, 3, 0), "] / b[", str(n-1, 3, 0), "]{", str(b[n-1], 3, 0), "} = ", str(p1[n-1], 3, 0), " \n \n") #for (i, n-2, 0, -1) //#for (i = n - 2; i >= 0; --i) #local p1[i] = (r[i] - c[i] * p1[i+1]) / b[i]; #debug concat ("Defining p1. i = ", str(i, 3, 0), " Defining p1. i+1 = ", str((i+1), 3, 0),"\n") #debug concat ("p1[", str(i, 3, 0), "] = (r[", str(i, 3, 0), "]{", str(r[i], 3, 0), "} - c[", str(i, 3, 0), "]{", str(c[i], 3, 0), "} * p1[", str(i+1, 3, 0), "]{", str(p1[i], 3, 0), "}) / b[", str(i, 3, 0), "]{", str(b[i], 3, 0), "} = ", str(p1[i], 3, 0), " \n \n") #end //we have p1, now compute p2 #for (i, 0, n-2) //#for (i=0;i - p1[", str(i+1, 3, 0), "]{", str(p1[i+1], 3, 0), "} = ", str(p2[i], 3, 0), " \n \n") #end #local p2[n-1] = 0.5 * (K[n] + p1[n-1]); #debug concat ("p2[", str(n-1, 3, 0), "] = 0.5 * + p1[", str(n-1, 3, 0), "]{", str(p1[n-1], 3, 0), "} = ", str(p2[n-1], 3, 0), " \n \n") // Interpolated control points for left segment | Interpolated control points for middle segment | Interpolated control points for right segment #debug concat( "p1[0] = ", str(p1[0], 3, 0), " p1[1] = ", str(p1[1], 3, 0), " p1[2] = ", str(p1[2], 3, 0), "\n") #debug concat( "p2[0] = ", str(p2[0], 3, 0), " p2[1] = ", str(p2[1], 3, 0), " p2[2] = ", str(p2[2], 3, 0), "\n") // first calculated for X components, then for Y components, then for Z. // output array of component interpolation macro #local P = array[6] {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2]}; P // return components stored in the array P[] to outer macro #end // call macro to Interpolate control point components for Bezier spline segments // Sets of p1 and p2 for Right, Middle, and left segments - 6 components in each array #if (Verbose = true) #debug "Interpolating Control Point x components \n" #end #local CPX = computeControlPoints(X); #for (i, 0, 5) // for i = 0 to 5 #debug concat( "CPX [", str(i, 3, 0), "] = ", str(CPX[i], 3, 0), " ") #end #debug " \n" #if (Verbose = true) #debug "Interpolating Control Point y components \n" #end #local CPY = computeControlPoints(Y); #for (i, 0, 5) // for i = 0 to 5 #debug concat( "CPY [", str(i, 3, 0), "] = ", str(CPY[i], 3, 0), " ") #end #debug " \n" #if (Verbose = true) #debug "Interpolating Control Point z components \n" #end #local CPZ = computeControlPoints(Z); #for (i, 0, 5) // for i = 0 to 5 #debug concat( "CPZ [", str(i, 3, 0), "] = ", str(CPZ[i], 3, 0), " ") #end #debug " \n" #declare Computed_spline = array [10] { InputPoints[0], , , InputPoints[3], , , InputPoints[6], , , InputPoints[9]}; #if (Verbose = true) #debug "Interpolated data = " #for (i, 0, 9) #debug concat("<", vstr(3, Computed_spline[i], ", ", 3, 0), ">, ") #end #debug " \n" #end #if (NoV = true) #undef Verbose #end #if (NoSE = true) #undef ShowEquations #end Computed_spline // return spline from macro to SDL --- NEEDS TO BE THE LAST LINE BEFORE #END #end // end main macro //#################################################################################################################################################################