// Last edited on 2011-09-12 03:31:05 by stolfilocal // _*_ latin-1 _*_ // C1-smooth Tubes built with Bézier patches. // The tube consists of rings. Each ring consists of two // Bezier patches, /top/ and /bottom/, controlled // by 2x2 arrays {T,B} of points. These are the middle // Bézier points of each patch (excluding the 4 corner points // and the 8 edge points). // Points {T[0][0]} and {T[1][0]} are closer to one edge of the ring; // Points {T[0][1]} and {T[1][1]} are closer to the other edge. // Point {B[i][j]} is topologically the mirror image of {T[i][j]}. #macro bztube_ring2(T0,B0,T1,B1,T2,B2, txT, txB, rad, txg) // A 2-patch ring of the tube, given the 2x2 control arrays // {T0,B0} of the previous ring (or posfork, or reversed cap) // {T1,B1} of this ring // {T2,B2} of the next ring (or reversed posfork, or cap). // Control points for top patch, minus the lateral seams: #local PT = array[4][4]; #local PT[1][0] = (T0[0][1] + T1[0][0])/2; #local PT[2][0] = (T0[1][1] + T1[1][0])/2; #local PT[1][1] = T1[0][0]; #local PT[2][1] = T1[1][0]; #local PT[1][2] = T1[0][1]; #local PT[2][2] = T1[1][1]; #local PT[1][3] = (T1[0][1] + T2[0][0])/2; #local PT[2][3] = (T1[1][1] + T2[1][0])/2; // Control points for bottom patch, minus the lateral seams: #local PB = array[4][4]; #local PB[1][0] = (B0[0][1] + B1[0][0])/2; #local PB[2][0] = (B0[1][1] + B1[1][0])/2; #local PB[1][1] = B1[0][0]; #local PB[2][1] = B1[1][0]; #local PB[1][2] = B1[0][1]; #local PB[2][2] = B1[1][1]; #local PB[1][3] = (B1[0][1] + B2[0][0])/2; #local PB[2][3] = (B1[1][1] + B2[1][0])/2; // Control points along the lateral seams: #local PT[0][0] = (PT[1][0] + PB[1][0])/2; #local PB[0][0] = PT[0][0]; #local PT[0][1] = (PT[1][1] + PB[1][1])/2; #local PB[0][1] = PT[0][1]; #local PT[0][2] = (PT[1][2] + PB[1][2])/2; #local PB[0][2] = PT[0][2]; #local PT[0][3] = (PT[1][3] + PB[1][3])/2; #local PB[0][3] = PT[0][3]; #local PT[3][0] = (PT[2][0] + PB[2][0])/2; #local PB[3][0] = PT[3][0]; #local PT[3][1] = (PT[2][1] + PB[2][1])/2; #local PB[3][1] = PT[3][1]; #local PT[3][2] = (PT[2][2] + PB[2][2])/2; #local PB[3][2] = PT[3][2]; #local PT[3][3] = (PT[2][3] + PB[2][3])/2; #local PB[3][3] = PT[3][3]; union{ object{ bzpatch(PT, txT, rad, txg) } object{ bzpatch(PB, txB, rad, txg) } } #end #macro bztube_cap2(T0,B0,T1,B1, txT, txB, rad, txg) // A cap for the 2-patch tube, given the 2x2 control arrays {T0,B0} of the // previous ring, and {T1,B1} of the cap. Only the points // {T1[i][0]} and {B1[i][0]} are used in the latter. // Control points for top patch, minus the lateral and extremal seams: #local PT = array[4][4]; #local PT[1][0] = (T0[0][1] + T1[0][0])/2; #local PT[2][0] = (T0[1][1] + T1[1][0])/2; #local PT[1][1] = T1[0][0]; #local PT[2][1] = T1[1][0]; #local PT[1][2] = (T1[0][0] + T1[1][0])/2; #local PT[2][2] = (T1[0][0] + T1[1][0])/2; // Control points for bottom patch, minus the lateral and extremal seams: #local PB = array[4][4]; #local PB[1][0] = (B0[0][1] + B1[0][0])/2; #local PB[2][0] = (B0[1][1] + B1[1][0])/2; #local PB[1][1] = B1[0][0]; #local PB[2][1] = B1[1][0]; #local PB[1][2] = (B1[0][0] + B1[1][0])/2; #local PB[2][2] = (B1[0][0] + B1[1][0])/2; // Control points along the lateral seams: #local PT[0][0] = (PT[1][0] + PB[1][0])/2; #local PB[0][0] = PT[0][0]; #local PT[0][1] = (PT[1][1] + PB[1][1])/2; #local PB[0][1] = PT[0][1]; #local PT[0][2] = (PT[1][2] + PB[1][2])/2; #local PB[0][2] = PT[0][2]; #local PT[3][0] = (PT[2][0] + PB[2][0])/2; #local PB[3][0] = PT[3][0]; #local PT[3][1] = (PT[2][1] + PB[2][1])/2; #local PB[3][1] = PT[3][1]; #local PT[3][2] = (PT[2][2] + PB[2][2])/2; #local PB[3][2] = PT[3][2]; // Control points along the extremal seam: #local PT[1][3] = PT[0][2]; #local PB[1][3] = PT[1][3]; #local PT[2][3] = PT[3][2]; #local PB[2][3] = PT[2][3]; // Control points at extremal corner: #local PT[0][3] = PT[0][2]; #local PB[0][3] = PT[0][3]; #local PT[3][3] = PT[3][2]; #local PB[3][3] = PT[3][3]; union{ object{ bzpatch(PT, txT, rad, txg) } object{ bzpatch(PB, txB, rad, txg) } } #end #macro bztube_ring4(Ta0,Ba0,Tb0,Bb0, Ta1,Ba1,Tb1,Bb1, Ta2,Ba2,Tb2,Bb2, txT, txB, rad, txg) // A 4-patch ring of the tube, given the 2x2 control arrays // {Ta0,Ba0} {Tb0,Bb0} of the previous 4-patch ring (or reversed prefork), // {Ta1,Ba1} {Tb1,Bb1} of this 4-patch ring, // {Ta2,Ba2} {Tb2,Bb2} of the following 4-patch ring (or prefork). // Control points for top patches, minus the lateral seams: #local PTa = array[4][4]; #local PTa[1][0] = (Ta0[0][1] + Ta1[0][0])/2; #local PTa[2][0] = (Ta0[1][1] + Ta1[1][0])/2; #local PTa[1][1] = Ta1[0][0]; #local PTa[2][1] = Ta1[1][0]; #local PTa[1][2] = Ta1[0][1]; #local PTa[2][2] = Ta1[1][1]; #local PTa[1][3] = (Ta1[0][1] + Ta2[0][0])/2; #local PTa[2][3] = (Ta1[1][1] + Ta2[1][0])/2; #local PTb = array[4][4]; #local PTb[1][0] = (Tb0[0][1] + Tb1[0][0])/2; #local PTb[2][0] = (Tb0[1][1] + Tb1[1][0])/2; #local PTb[1][1] = Tb1[0][0]; #local PTb[2][1] = Tb1[1][0]; #local PTb[1][2] = Tb1[0][1]; #local PTb[2][2] = Tb1[1][1]; #local PTb[1][3] = (Tb1[0][1] + Tb2[0][0])/2; #local PTb[2][3] = (Tb1[1][1] + Tb2[1][0])/2; // Control points for bottom patches, minus the lateral seams: #local PBa = array[4][4]; #local PBa[1][0] = (Ba0[0][1] + Ba1[0][0])/2; #local PBa[2][0] = (Ba0[1][1] + Ba1[1][0])/2; #local PBa[1][1] = Ba1[0][0]; #local PBa[2][1] = Ba1[1][0]; #local PBa[1][2] = Ba1[0][1]; #local PBa[2][2] = Ba1[1][1]; #local PBa[1][3] = (Ba1[0][1] + Ba2[0][0])/2; #local PBa[2][3] = (Ba1[1][1] + Ba2[1][0])/2; #local PBb = array[4][4]; #local PBb[1][0] = (Bb0[0][1] + Bb1[0][0])/2; #local PBb[2][0] = (Bb0[1][1] + Bb1[1][0])/2; #local PBb[1][1] = Bb1[0][0]; #local PBb[2][1] = Bb1[1][0]; #local PBb[1][2] = Bb1[0][1]; #local PBb[2][2] = Bb1[1][1]; #local PBb[1][3] = (Bb1[0][1] + Bb2[0][0])/2; #local PBb[2][3] = (Bb1[1][1] + Bb2[1][0])/2; // Control points along the lateral seams, minus singular corners: #local PTa[0][0] = (PTa[1][0] + PBa[1][0])/2; #local PBa[0][0] = PTa[0][0]; #local PTa[0][1] = (PTa[1][1] + PBa[1][1])/2; #local PBa[0][1] = PTa[0][1]; #local PTa[0][2] = (PTa[1][2] + PBa[1][2])/2; #local PBa[0][2] = PTa[0][2]; #local PTa[0][3] = (PTa[1][3] + PBa[1][3])/2; #local PBa[0][3] = PTa[0][3]; #local PTa[3][0] = (PTa[2][0] + PTb[1][0])/2; #local PTb[0][0] = PTa[3][0]; #local PTa[3][1] = (PTa[2][1] + PTb[1][1])/2; #local PTb[0][1] = PTa[3][1]; #local PTa[3][2] = (PTa[2][2] + PTb[1][2])/2; #local PTb[0][2] = PTa[3][2]; #local PTa[3][3] = (PTa[2][3] + PTb[1][3])/2; #local PTb[0][3] = PTa[3][3]; #local PBa[3][0] = (PBa[2][0] + PBb[1][0])/2; #local PBb[0][0] = PBa[3][0]; #local PBa[3][1] = (PBa[2][1] + PBb[1][1])/2; #local PBb[0][1] = PBa[3][1]; #local PBa[3][2] = (PBa[2][2] + PBb[1][2])/2; #local PBb[0][2] = PBa[3][2]; #local PBa[3][3] = (PBa[2][3] + PBb[1][3])/2; #local PBb[0][3] = PBa[3][3]; #local PTb[3][0] = (PTb[2][0] + PBb[2][0])/2; #local PBb[3][0] = PTb[3][0]; #local PTb[3][1] = (PTb[2][1] + PBb[2][1])/2; #local PBb[3][1] = PTb[3][1]; #local PTb[3][2] = (PTb[2][2] + PBb[2][2])/2; #local PBb[3][2] = PTb[3][2]; #local PTb[3][3] = (PTb[2][3] + PBb[2][3])/2; #local PBb[3][3] = PTb[3][3]; union{ #debug "\nring4 Ta\n" object{ bzpatch(PTa, txT, rad, txg) } #debug "\nring4 Tb\n" object{ bzpatch(PTb, txT, rad, txg) } #debug "\nring4 Ba\n" object{ bzpatch(PBa, txB, rad, txg) } #debug "\nring4 Bb\n" object{ bzpatch(PBb, txB, rad, txg) } } #end #macro bztube_prefork42(Ta0,Ba0,Tb0,Bb0, Ta1,Ba1,Tb1,Bb1, Ta2,Ba2,Tb2,Bb2, txT, txB, rad, txg) // The first part of a fork in the tube, connecting a 4-patch ring to two 2-patch rings. // Given the 2x2 control arrays // {Ta0,Ba0} {Tb0,Bb0} of the previous 4-patch ring, // {Ta1,Ba1} {Tb1,Bb1} of the prefork's 4-patch ring, // {Ta2,Ba2} {Tb2,Bb2} of the posfork's 2-patch rings. // Control points for top patches, minus the lateral seams: #local PTa = array[4][4]; #local PTa[1][0] = (Ta0[0][1] + Ta1[0][0])/2; #local PTa[2][0] = (Ta0[1][1] + Ta1[1][0])/2; #local PTa[1][1] = Ta1[0][0]; #local PTa[2][1] = Ta1[1][0]; #local PTa[1][2] = Ta1[0][1]; #local PTa[2][2] = Ta1[1][1]; #local PTa[1][3] = (Ta1[0][1] + Ta2[0][0])/2; #local PTa[2][3] = (Ta1[1][1] + Ta2[1][0])/2; #local PTb = array[4][4]; #local PTb[1][0] = (Tb0[0][1] + Tb1[0][0])/2; #local PTb[2][0] = (Tb0[1][1] + Tb1[1][0])/2; #local PTb[1][1] = Tb1[0][0]; #local PTb[2][1] = Tb1[1][0]; #local PTb[1][2] = Tb1[0][1]; #local PTb[2][2] = Tb1[1][1]; #local PTb[1][3] = (Tb1[0][1] + Tb2[0][0])/2; #local PTb[2][3] = (Tb1[1][1] + Tb2[1][0])/2; // Control points for bottom patches, minus the lateral seams: #local PBa = array[4][4]; #local PBa[1][0] = (Ba0[0][1] + Ba1[0][0])/2; #local PBa[2][0] = (Ba0[1][1] + Ba1[1][0])/2; #local PBa[1][1] = Ba1[0][0]; #local PBa[2][1] = Ba1[1][0]; #local PBa[1][2] = Ba1[0][1]; #local PBa[2][2] = Ba1[1][1]; #local PBa[1][3] = (Ba1[0][1] + Ba2[0][0])/2; #local PBa[2][3] = (Ba1[1][1] + Ba2[1][0])/2; #local PBb = array[4][4]; #local PBb[1][0] = (Bb0[0][1] + Bb1[0][0])/2; #local PBb[2][0] = (Bb0[1][1] + Bb1[1][0])/2; #local PBb[1][1] = Bb1[0][0]; #local PBb[2][1] = Bb1[1][0]; #local PBb[1][2] = Bb1[0][1]; #local PBb[2][2] = Bb1[1][1]; #local PBb[1][3] = (Bb1[0][1] + Bb2[0][0])/2; #local PBb[2][3] = (Bb1[1][1] + Bb2[1][0])/2; // Control points along the lateral seams, minus singular corners: #local PTa[0][0] = (PTa[1][0] + PBa[1][0])/2; #local PBa[0][0] = PTa[0][0]; #local PTa[0][1] = (PTa[1][1] + PBa[1][1])/2; #local PBa[0][1] = PTa[0][1]; #local PTa[0][2] = (PTa[1][2] + PBa[1][2])/2; #local PBa[0][2] = PTa[0][2]; #local PTa[0][3] = (PTa[1][3] + PBa[1][3])/2; #local PBa[0][3] = PTa[0][3]; #local PTa[3][0] = (PTa[2][0] + PTb[1][0])/2; #local PTb[0][0] = PTa[3][0]; #local PTa[3][1] = (PTa[2][1] + PTb[1][1])/2; #local PTb[0][1] = PTa[3][1]; #local PTa[3][2] = (PTa[2][2] + PTb[1][2])/2; #local PTb[0][2] = PTa[3][2]; #local PBa[3][0] = (PBa[2][0] + PBb[1][0])/2; #local PBb[0][0] = PBa[3][0]; #local PBa[3][1] = (PBa[2][1] + PBb[1][1])/2; #local PBb[0][1] = PBa[3][1]; #local PBa[3][2] = (PBa[2][2] + PBb[1][2])/2; #local PBb[0][2] = PBa[3][2]; #local PTb[3][0] = (PTb[2][0] + PBb[2][0])/2; #local PBb[3][0] = PTb[3][0]; #local PTb[3][1] = (PTb[2][1] + PBb[2][1])/2; #local PBb[3][1] = PTb[3][1]; #local PTb[3][2] = (PTb[2][2] + PBb[2][2])/2; #local PBb[3][2] = PTb[3][2]; #local PTb[3][3] = (PTb[2][3] + PBb[2][3])/2; #local PBb[3][3] = PTb[3][3]; // Control points at singular corners: #local Psing = (PTa[2][3] + PTb[1][3] + PBa[2][3] + PBb[1][3])/4; #local PTa[3][3] = Psing; #local PTb[0][3] = Psing; #local PBa[3][3] = Psing; #local PBb[0][3] = Psing; union{ #debug "\nprefork Ta\n" object{ bzpatch(PTa, txT, rad, txg) } #debug "\nprefork Tb\n" object{ bzpatch(PTb, txT, rad, txg) } #debug "\nprefork Ba\n" object{ bzpatch(PBa, txB, rad, txg) } #debug "\nprefork Bb\n" object{ bzpatch(PBb, txB, rad, txg) } } #end #macro bztube_posfork42(Ta0,Ba0,Tb0,Bb0, Ta1,Ba1,Tb1,Bb1, Ta2,Ba2,Tb2,Bb2, txT, txB, rad, txg) // The second part of a fork in the tube, connecting a 4-patch ring to two 2-patch rings. // Given the 2x2 control arrays // {Ta0,Ba0} {Tb0,Bb0} of the prefork's 4-patch ring, // {Ta1,Ba1} {Tb1,Bb1} of the posfork's 4-patch ring, // {Ta2,Ba2} {Tb2,Bb2} of the following 2-patch rings. // Control points for top patches, minus the lateral seams: #local PTa = array[4][4]; #local PTa[1][0] = (Ta0[0][1] + Ta1[0][0])/2; #local PTa[2][0] = (Ta0[1][1] + Ta1[1][0])/2; #local PTa[1][1] = Ta1[0][0]; #local PTa[2][1] = Ta1[1][0]; #local PTa[1][2] = Ta1[0][1]; #local PTa[2][2] = Ta1[1][1]; #local PTa[1][3] = (Ta1[0][1] + Ta2[0][0])/2; #local PTa[2][3] = (Ta1[1][1] + Ta2[1][0])/2; #local PTb = array[4][4]; #local PTb[1][0] = (Tb0[0][1] + Tb1[0][0])/2; #local PTb[2][0] = (Tb0[1][1] + Tb1[1][0])/2; #local PTb[1][1] = Tb1[0][0]; #local PTb[2][1] = Tb1[1][0]; #local PTb[1][2] = Tb1[0][1]; #local PTb[2][2] = Tb1[1][1]; #local PTb[1][3] = (Tb1[0][1] + Tb2[0][0])/2; #local PTb[2][3] = (Tb1[1][1] + Tb2[1][0])/2; // Control points for bottom patches, minus the lateral seams: #local PBa = array[4][4]; #local PBa[1][0] = (Ba0[0][1] + Ba1[0][0])/2; #local PBa[2][0] = (Ba0[1][1] + Ba1[1][0])/2; #local PBa[1][1] = Ba1[0][0]; #local PBa[2][1] = Ba1[1][0]; #local PBa[1][2] = Ba1[0][1]; #local PBa[2][2] = Ba1[1][1]; #local PBa[1][3] = (Ba1[0][1] + Ba2[0][0])/2; #local PBa[2][3] = (Ba1[1][1] + Ba2[1][0])/2; #local PBb = array[4][4]; #local PBb[1][0] = (Bb0[0][1] + Bb1[0][0])/2; #local PBb[2][0] = (Bb0[1][1] + Bb1[1][0])/2; #local PBb[1][1] = Bb1[0][0]; #local PBb[2][1] = Bb1[1][0]; #local PBb[1][2] = Bb1[0][1]; #local PBb[2][2] = Bb1[1][1]; #local PBb[1][3] = (Bb1[0][1] + Bb2[0][0])/2; #local PBb[2][3] = (Bb1[1][1] + Bb2[1][0])/2; // Control points along the lateral seams, minus singular corners: #local PTa[0][0] = (PTa[1][0] + PBa[1][0])/2; #local PBa[0][0] = PTa[0][0]; #local PTa[0][1] = (PTa[1][1] + PBa[1][1])/2; #local PBa[0][1] = PTa[0][1]; #local PTa[0][2] = (PTa[1][2] + PBa[1][2])/2; #local PBa[0][2] = PTa[0][2]; #local PTa[0][3] = (PTa[1][3] + PBa[1][3])/2; #local PBa[0][3] = PTa[0][3]; #local PTa[3][1] = (PTa[2][1] + PBa[2][1])/2; #local PBa[3][1] = PTa[3][1]; #local PTa[3][2] = (PTa[2][2] + PBa[2][2])/2; #local PBa[3][2] = PTa[3][2]; #local PTa[3][3] = (PTa[2][3] + PBa[2][3])/2; #local PBa[3][3] = PTa[3][3]; #local PTb[0][1] = (PTb[1][1] + PBb[1][1])/2; #local PBb[0][1] = PTb[0][1]; #local PTb[0][2] = (PTb[1][2] + PBb[1][2])/2; #local PBb[0][2] = PTb[0][2]; #local PTb[0][3] = (PTb[1][3] + PBb[1][3])/2; #local PBb[0][3] = PTb[0][3]; #local PTb[3][0] = (PTb[2][0] + PBb[2][0])/2; #local PBb[3][0] = PTb[3][0]; #local PTb[3][1] = (PTb[2][1] + PBb[2][1])/2; #local PBb[3][1] = PTb[3][1]; #local PTb[3][2] = (PTb[2][2] + PBb[2][2])/2; #local PBb[3][2] = PTb[3][2]; #local PTb[3][3] = (PTb[2][3] + PBb[2][3])/2; #local PBb[3][3] = PTb[3][3]; // Control points at singular corners: #local Psing = (PTa[2][0] + PTb[1][0] + PBa[2][0] + PBb[1][0])/4; #local PTa[3][0] = Psing; #local PTb[0][0] = Psing; #local PBa[3][0] = Psing; #local PBb[0][0] = Psing; union{ #debug "\nposfork Ta\n" object{ bzpatch(PTa, txT, rad, txg) } #debug "\nposfork Tb\n" object{ bzpatch(PTb, txT, rad, txg) } #debug "\nposfork Ba\n" object{ bzpatch(PBa, txB, rad, txg) } #debug "\nposfork Bb\n" object{ bzpatch(PBb, txB, rad, txg) } } #end