#version 3.8; // Prism designer // Bill Walker "Bald Eagle" October 2019 // Major.Minor.Patch http://semver.org/ // Version 0.1.0 // +GDPrismDesigner.txt +GP (to enable appending instead of overwrite) // To do: // export prism to #debug stream and/or write to .inc file // Secondary gridlines, circle center and Bezier endpoint markers // line intersection checking and warning + red dot // dimensioning macros (center markers, esp radius, dist between centers, angles) // ruler for when printing out and verifying proper scale, squareness, aspect, angles, etc // screen.inc global_settings { assumed_gamma 1.0 } // Epsilon - for fixing various issues in need of "nudging" #declare E = 0.000001; #declare _Eps = E; // just a 4-digit name for neatness in array definitions //######################################################################### // CONTROL PANEL for adjusting various scene parameters //######################################################################### // provide feedback in #debug stream. Comment-out to shut off. Changing value does nothing. #declare Verbose = yes; #declare ShowGrid = yes; #declare GridLabels = yes; #declare Endpoints = no; #declare ShowImage = yes; #declare ImageFilename = "Hammer.png"; #declare LM = 2; // multiplier for line width for finished outline #declare ShowGhostLines = no; #declare PrismHeight = 2; #declare ShowPrism = yes; #declare ShowSmallPrisms = yes; // If there are only 2 circles or if the circles form a path // *** not yet implemented for prism #declare ArrayIsLinear = 0; // --------------------------------------------------- // for use in labeling desired tangent path for spline // with P_Tangent array #declare _All = 0; #declare _Blu = 1; #declare _Cyn = 2; #declare _Red = 3; #declare _Grn = 4; // for use in labeling desired circular arc for spline // with P_Arc array #declare _Both = 0; #declare _Wht = 1; #declare _Blk = 2; // for use in switching direction of points in segment // _Both is already declared #declare _Fwd = 1; #declare _Rev = 2; // --------------------------------------------------- // {x, y, z, rad, # sides, rot of polygon, T color, Arc by color} // need to add a mechanism to do forward/backward #declare OldCircleArray = array [2][10]{ {0.00, 0.00, 0.00, 0.50, 0, 0, _All, _Fwd, _Both, _Fwd}, {0.00, 0.00, 2.50, 1.00, 0, 0, _All, _Fwd, _Both, _Fwd} } // {x, y, z, rad, # sides, rotation of polygon, Tangent by color, dir, Arc by color, dir} #declare CircleArray = array [12][10]{ // x y z r - - tan dir arc dir { 0.00, 0, 0.00, 0.10, 0, 0, _Red, _Fwd, _Blk, _Fwd}, { 1.75, 0, 2.25, 0.50, 0, 0, _Grn, _Fwd, _Wht, _Rev}, { 2.00, 0, 0.50, 0.15, 0, 0, _Red, _Fwd, _Blk, _Fwd}, { 5.50, 0, 3.00, 0.25, 0, 0, _Grn, _Fwd, _Wht, _Rev}, { 2.50, 0, -1.00, 1.00, 0, 0, _Red, _Fwd, _Blk, _Fwd}, { 1.00, 0, -2.00, 0.25, 0, 0, _Grn, _Fwd, _Wht, _Rev}, { 0.50, 0, -1.00, 0.25, 0, 0, _Red, _Fwd, _Blk, _Fwd}, {-1.00, 0, -1.50, 0.50, 0, 0, _Cyn, _Fwd, _Wht, _Rev}, {-3.00, 0, 0.00, 0.50, 0, 0, _Cyn, _Fwd, _Wht, _Rev}, {-2.50, 0, 2.00, 0.10, 0, 0, _Grn, _Fwd, _Wht, _Rev}, {-1.25, 0, -0.25, 0.20, 0, 0, _Red, _Fwd, _Blk, _Fwd}, {-1.00, 0, 3.00, 0.30, 0, 0, _Grn, _Fwd, _Wht, _Rev}, } // DS_parameter indicates dimension_size (1 to N), the number of items in an array // EL_parameter indicates element number (0 to N-1), the position of the item in the array #declare DS_Circles = dimension_size (CircleArray, 1); #declare EL_Circles = DS_Circles-1; //######################################################################### #include "colors.inc" #include "math.inc" #include "shapes.inc" #include "shapes2.inc" #include "shapes3.inc" #declare Aspect = image_width/image_height; //######################################################################### // Need to convert this to orthographic and use screen.inc #declare Xoffset = 3; // <----- Camera Offset #declare Zoffset = 0; #declare Zoom = 60; camera { orthographic right x*image_width/Zoom up y*image_height/Zoom location look_at } //######################################################################### light_source {<0, 25, 0> color White} // Size of text in scene #declare TextScale = 0.125; // radius of lines drawn in scene #declare Line = 0.017; plane {y, -Line*5 pigment {White*0.1}} cylinder {<-10, 0, 0>, <10, 0, 0> Line pigment {Red*0.2}} cylinder {<0, 0, -10>, <0, 0, 10> Line pigment {Blue*0.2}} //---------------------------------------------------------------------------------------------- // Sized image Map - 1 unit thick box #declare XSize = 2; #declare ImageMap = pigment {image_map {png ImageFilename once transmit all 0.5} }; #declare Resolution = max_extent (ImageMap); #declare Resolution = Resolution + <0, 0, 1>; #declare ImageMappedBox = box {0, 1 texture { pigment {ImageMap} finish {diffuse 1} } translate <-0.5, -0.5, 0> scale Resolution*(1/Resolution.x)*XSize //translate y*(Resolution.y / Resolution.x)*XSize/2 } #declare Offset = <0.00, -Line, 0.00>; //<---------- OFFSET OF BACKGROUND IMAGE // For centering pivot holes on origin, etc. #declare ImageScale = 3; #if (ShowImage) object {ImageMappedBox rotate x*90 translate Offset scale ImageScale} #end //---------------------------------------------------------------------------------------------- // Define pigments and textures //------------------------------------------------------------------------ // P_parameter indicates pigment // T_parameter indicates texture // CM_parameter indicates color_map #declare LinePigment = pigment {Yellow+White/2} #if (ShowGhostLines) #declare P_Ghost = pigment {rgb 0.5} #else #declare P_Ghost = pigment {rgbt 1.0} #end #declare Separator = 0.01; #declare CM_GreenRedGradient = color_map { [0.0 rgb 0] [Separator rgb 0] [Separator rgb <0.0, 1.0, 0.0>] [1/6 rgb <0.0, 0.5, 0.0>*2] [5/6 rgb <0.5, 0.0, 0.0>*2] [1-Separator rgb <1.0, 0.0, 0.0>] [1-Separator rgb 0] [1.0 rgb 0] } #declare _CM_GreenRedGradient = color_map { [0.0 rgb <0.0, 1.0, 0.0>] [1/4 rgb <0.0, 0.0, 0.0>] [3/4 rgb <0.0, 0.0, 0.0>] [1.0 rgb <1.0, 0.0, 0.0>] } #declare P_GreenRedLine = pigment {gradient x color_map {CM_GreenRedGradient}} #declare Tan = texture {pigment {rgb <0.92, 0.60, 0.20>} finish {diffuse 0.7 specular 0.2 reflection 0.02}} #declare Brn = texture {pigment {rgb <0.92, 0.60, 0.20>*0.5} finish {diffuse 0.7 specular 0.2 reflection 0.02}} #declare Angle = function (XX,ZZ) {atan2 (XX, ZZ)-(pi/2)} #declare Adjusted = function (XX,ZZ) {select (Angle(XX,ZZ), Angle(XX,ZZ)+tau, Angle(XX, ZZ))} #declare FreqPhase = function (XX, ZZ, F, P) {mod ((P*tau+Adjusted (XX, ZZ))*F, tau)/tau} #declare Radial = function (XX, ZZ, F, P) {select (XX*ZZ, FreqPhase (XX,ZZ,F,P), 0, FreqPhase (XX,ZZ,F,P))} #declare P_Text = array [8] { pigment {White}, pigment {Red}, pigment {Orange}, pigment {Yellow} pigment {Green}, pigment {Blue}, pigment {Violet}, pigment {Black} } #declare P_Tangent = array [4] { pigment {Blue}, pigment {Cyan}, pigment {Red}, pigment {Green} } #declare P_Arc = array [2] { pigment {Black}, pigment {White}, } // Define arrays and macros //------------------------------------------------------------------------ // array for displaying signed values in #debug output #declare Sign = array [3] {"-", "0", "+"}; // shorthand macro for sending numeric output to #debug stream #macro N (_N) str(_N, 0, 2) #end #macro PlaceText (_Text, _Type, _Position, _Size, _Color) #if (_Type) // if number, then use str(), employing _Type-1 value as # of decimal places #local _Label1 = text {ttf "cyrvetic.ttf", str(_Text, 0, _Type-1), 0.04, <0, 0> scale TextScale*_Size pigment {P_Text[_Color]} rotate x*90} #else #local _Label1 = text {ttf "cyrvetic.ttf", _Text, 0.04, <0, 0> scale TextScale*_Size pigment {P_Text[_Color]} rotate x*90} #end #local _L1M = max_extent (_Label1); object {_Label1 translate <-_L1M.x/2, 0, -_L1M.z/2> translate _Position} #end // Grid for parts layout #if (ShowGrid)// P_parameter indicates pigment union { #declare Gridline = Line/2; #declare XSpan = 12; #declare ZSpan = 7; #declare GridStep = 0.5; #for (X, -XSpan/2, XSpan/2, GridStep) cylinder {, Gridline} PlaceText (X, 2, , 1, 7) #end #for (Z, -ZSpan/2, ZSpan/2, GridStep) cylinder {<-XSpan/2, 0, Z>, Gridline} PlaceText (Z, 2, , 1, 7) #end pigment {rgb 0.0} no_shadow } #end #macro Angle2D (vA, vB) // from Tor Olav Kristensen // http://news.povray.org/povray.newusers/message/%3Cweb.5d9f7b4becd82d81ed4479290%40news.povray.org%3E/#%3Cweb.5d9f7b4becd82d81ed4479290%40news.povray.org%3E #local AngleA = atan2 (vA.z, vA.x); #local AngleB = atan2 (vB.z, vB.x); #local dAngle = AngleB - AngleA; // degrees(dAngle) // For result from -180 to +180 degrees degrees (mod (dAngle + 2*pi, 2*pi)) // For result from 0 to +360 degrees #end // macro Angle2D #macro ArcAngle (_Center, _T1, _T4) // This macro should not be invoked until the tangents are chosen, // since there are 4 tangents, and this macro only uses 2 points #local _T1vector = _T1 - _Center; #local _T4vector = _T4 - _Center; #local _Start = atan2 (_T1vector.z, _T1vector.x); #local _End = atan2 (_T4vector.z, _T4vector.x); #local _CCWArc = degrees (mod (_End - _Start + 2*pi, 2*pi)); #local _S = degrees (mod (_Start + 2*pi, 2*pi)); #local _E = degrees (mod (_End + 2*pi, 2*pi)); #ifdef (Verbose) #debug concat ( "Counterclockwise Calculated Angle = ", str (_CCWArc, 0, 2), "\n") #end array [3] {_S, _E, _CCWArc} // start, end, counterclockwise angle #end #macro BezierArcs (_Center, _T1, _T4) #local _Angle = ArcAngle (_Center, _T1, _T4) #local NumSegments = ceil (abs(_Angle)/90); #ifdef (Verbose) #debug concat ( " NumSegments = ", str (NumSegments, 0, 1), "\n") #end #local Segments = array; //[NumSegments*4] #local PCurrent = 0; #for (S, 0, NumSegments-1) #local Quadrant = S*90; #debug concat ( " Quadrant = ", str (Quadrant, 0, 1), "\n") #if (S = NumSegments-1) #local T4 = _T4; #else #local End = transform {translate -Center rotate -y*(Quadrant+90) translate Center } #local T4 = vtransform (_T1, End); #end #local Start = transform {translate -Center rotate -y*Quadrant translate Center } #local T1 = vtransform (_T1, Start); // Equations are in terms of x-y, so swap prism z values into y. ;) #local x1 = T1.x; #local y1 = T1.z; #local x4 = T4.x; #local y4 = T4.z; #ifdef (Verbose) #debug concat ( " x1 = ", str (x1, 0, 2), "\n") #debug concat ( " y1 = ", str (y1, 0, 2), "\n") #debug concat ( " x4 = ", str (x4, 0, 2), "\n") #debug concat ( " y4 = ", str (y4, 0, 2), "\n") #end // https://pdfs.semanticscholar.org/1639/0db1a470bd13fe428e0896671a9a5745070a.pdf #local ax = x1 - xc; #local ay = y1 - yc; #local bx = x4 - xc; #local by = y4 - yc; #local q1 = ax*ax + ay*ay; #local q2 = q1 + ax*bx + ay*by; #local k2 = 4/3 * (sqrt(2*q1*q2)-q2)/(ax*by-ay*bx); // (4/3) // original equations // #local x2 = xc + x1 - k2*y1; // #local y2 = yc + y1 + k2*x1; // #local x3 = xc + x4 - k2*y4; // #local y4 = yc + y4 + k2*x4; // corrections to original equations from // https://hansmuller-flex.blogspot.com/2011/10/more-about-approximating-circular-arcs.html?showComment=1498749617507#c2109832351939371205 #local x2 = xc + ax - k2*ay; #local y2 = yc + ay + k2*ax; #local x3 = xc + bx + k2*by; // needed to change sign from: bx - k2*by #local y3 = yc + by - k2*bx; // needed to change sign from: by + k2*bx #debug concat ( " x2 = ", str (x2, 0, 2), "\n") #debug concat ( " y2 = ", str (y2, 0, 2), "\n") #debug concat ( " x3 = ", str (x3, 0, 2), "\n") #debug concat ( " y3 = ", str (y3, 0, 2), "\n") #local P1 = ; #local P2 = ; #local P3 = ; #local P4 = ; #local Segments[PCurrent] = P1; #local PCurrent = PCurrent +1; #local Segments[PCurrent] = P2; #local PCurrent = PCurrent +1; #local Segments[PCurrent] = P3; #local PCurrent = PCurrent +1; #local Segments[PCurrent] = P4; #local PCurrent = PCurrent +1; #end #end #macro AnalyticalTangents (_C1, _R1, _C2, _R2) // http://ambrsoft.com/TrigoCalc/Circles2/Circles2Tangent_.htm // http://ambrsoft.com/Equations/Examples/AnalyticGeometry/AnalyticGeometry.htm#ex2 #local a = _C1.x; #local b = _C1.z; #local r0 = _R1; #local c = _C2.x; #local d = _C2.z; #local r1 = _R2; #local _vector = _C2 - _C1; #local _D = vlength (_vector); #if (r0 = r1) #local r0 = r0 + E; #end // display equations #ifdef (Verbose) #if (_D < abs(r0 - r1) ) #debug "One circle is interior to the other - no tangents \n" #end #if (_D = abs(r0 - r1) ) #debug "One circle is interior and tangent to the other - one tangent \n" #end #if (_D > abs(r0 - r1) & _D < r0+r1 ) #debug "Circle overlap each other - two tangents \n" #end #if (_D = r0 + r1 ) #debug "Circles are exterior and tangent to each other - 3 tangents \n" #end #if (_D > r0 + r1 ) #debug "Circles are exterior to each other - 4 tangents \n" #end #debug "Calculating tangents for circles \n" #debug concat ("pow (x", Sign[-sgn(a)+1], N(abs(a)), ", 2) + " ) #debug concat ("pow (y", Sign[-sgn(b)+1], N(abs(b)), ", 2) = " ) #debug concat ("pow (", N(r0), ", 2) \n" ) #debug " and \n" #debug concat ("pow (x", Sign[-sgn(c)+1], N(abs(c)), ", 2) + " ) #debug concat ("pow (y", Sign[-sgn(d)+1], N(abs(d)), ", 2) = " ) #debug concat ("pow (", N(r1), ", 2) \n\n" ) #debug "Outer tangent lines intersect at point p" #debug concat ("Xp = c * r0 - a * r1 / r0 - r1 = ") #debug concat (N(c), "*", N(r0), " - ", N(a), "*", N(r1), " / ", N(r0), " - ", N(r1), " = ") #debug N((c*r0 - a*r1) / (r0-r1) ) #debug "\n" #debug concat ("Yp = d * r0 - b * r1 / r0 - r1 = ") #debug concat (N(d), "*", N(r0), " - ", N(b), "*", N(r1), " / ", N(r0), " - ", N(r1), " = ") #debug N((d*r0 - b*r1) / (r0-r1) ) #debug "\n" #end // compute coordinates for the intersection of outer tangent lines #local Xpo = (c*r0 - a*r1) / (r0-r1); #local Ypo = (d*r0 - b*r1) / (r0-r1); // compute values for tangents // Outer tangents on r0 #local Xto1 = (pow(r0,2)*(Xpo-a) + r0*(Ypo-b)*sqrt(pow(Xpo-a,2)+pow(Ypo-b,2)-pow(r0,2)) ) / (pow(Xpo-a,2)+pow(Ypo-b,2))+a; #local Xto2 = (pow(r0,2)*(Xpo-a) - r0*(Ypo-b)*sqrt(pow(Xpo-a,2)+pow(Ypo-b,2)-pow(r0,2)) ) / (pow(Xpo-a,2)+pow(Ypo-b,2))+a; #local Yto1 = (pow(r0,2)*(Ypo-b) + r0*(Xpo-a)*sqrt(pow(Xpo-a,2)+pow(Ypo-b,2)-pow(r0,2)) ) / (pow(Xpo-a,2)+pow(Ypo-b,2))+b; #local Yto2 = (pow(r0,2)*(Ypo-b) - r0*(Xpo-a)*sqrt(pow(Xpo-a,2)+pow(Ypo-b,2)-pow(r0,2)) ) / (pow(Xpo-a,2)+pow(Ypo-b,2))+b; #local s = (b-Yto1)*(Ypo-Yto1)/(Xto1-a)*(Xto1-Xpo); #if (s != 1) // check if correct coordinates are paired - if not, swap tangent y-values #local TempY = Yto1; #local Yto1 = Yto2; #local Yto2 = TempY; #end // Outer tangents on r1 #local Xto3 = (pow(r1,2)*(Xpo-c) + r1*(Ypo-d)*sqrt(pow(Xpo-c,2)+pow(Ypo-d,2)-pow(r1,2)) ) / (pow(Xpo-c,2)+pow(Ypo-d,2))+c; #local Xto4 = (pow(r1,2)*(Xpo-c) - r1*(Ypo-d)*sqrt(pow(Xpo-c,2)+pow(Ypo-d,2)-pow(r1,2)) ) / (pow(Xpo-c,2)+pow(Ypo-d,2))+c; #local Yto3 = (pow(r1,2)*(Ypo-d) + r1*(Xpo-c)*sqrt(pow(Xpo-c,2)+pow(Ypo-d,2)-pow(r1,2)) ) / (pow(Xpo-c,2)+pow(Ypo-d,2))+d; #local Yto4 = (pow(r1,2)*(Ypo-d) - r1*(Xpo-c)*sqrt(pow(Xpo-c,2)+pow(Ypo-d,2)-pow(r1,2)) ) / (pow(Xpo-c,2)+pow(Ypo-d,2))+d; #local s = (b-Yto1)*(Ypo-Yto1)/(Xto1-a)*(Xto1-Xpo); #if (s != 1) // check if correct coordinates are paired - if not, swap tangent y-values #local TempY = Yto3; #local Yto3 = Yto4; #local Yto4 = TempY; #end #ifdef (Verbose) #debug "Points of tangency are: \n" #debug concat ( "t1 = ", vstr(3, , ", ", 0, 2), " \n") #debug concat ( "t2 = ", vstr(3, , ", ", 0, 2), " \n") #debug concat ( "t3 = ", vstr(3, , ", ", 0, 2), " \n") #debug concat ( "t4 = ", vstr(3, , ", ", 0, 2), " \n") #debug concat ("s-check: \n") #end // Inner tangents // compute coordinates for the intersection of inner tangent lines #local Xpi = (c*r0 + a*r1) / (r0+r1); #local Ypi = (d*r0 + b*r1) / (r0+r1); // compute values for tangents // Inner tangents on r0 #local Xti1 = (pow(r0,2)*(Xpi-a) + r0*(Ypi-b)*sqrt(pow(Xpi-a,2)+pow(Ypi-b,2)-pow(r0,2)) ) / (pow(Xpi-a,2)+pow(Ypi-b,2))+a; #local Xti2 = (pow(r0,2)*(Xpi-a) - r0*(Ypi-b)*sqrt(pow(Xpi-a,2)+pow(Ypi-b,2)-pow(r0,2)) ) / (pow(Xpi-a,2)+pow(Ypi-b,2))+a; #local Yti1 = (pow(r0,2)*(Ypi-b) + r0*(Xpi-a)*sqrt(pow(Xpi-a,2)+pow(Ypi-b,2)-pow(r0,2)) ) / (pow(Xpi-a,2)+pow(Ypi-b,2))+b; #local Yti2 = (pow(r0,2)*(Ypi-b) - r0*(Xpi-a)*sqrt(pow(Xpi-a,2)+pow(Ypi-b,2)-pow(r0,2)) ) / (pow(Xpi-a,2)+pow(Ypi-b,2))+b; #local s = (b-Yti1)*(Ypo-Yti1)/(Xti1-a)*(Xti1-Xpo); #if (s != 1) // check if correct coordinates are paired - if not, swap tangent y-values #local TempY = Yti1; #local Yti1 = Yti2; #local Yti2 = TempY; #end // Inner tangents on r1 #local Xti3 = (pow(r1,2)*(Xpi-c) + r1*(Ypi-d)*sqrt(pow(Xpi-c,2)+pow(Ypi-d,2)-pow(r1,2)) ) / (pow(Xpi-c,2)+pow(Ypi-d,2))+c; #local Xti4 = (pow(r1,2)*(Xpi-c) - r1*(Ypi-d)*sqrt(pow(Xpi-c,2)+pow(Ypi-d,2)-pow(r1,2)) ) / (pow(Xpi-c,2)+pow(Ypi-d,2))+c; #local Yti3 = (pow(r1,2)*(Ypi-d) + r1*(Xpi-c)*sqrt(pow(Xpi-c,2)+pow(Ypi-d,2)-pow(r1,2)) ) / (pow(Xpi-c,2)+pow(Ypi-d,2))+d; #local Yti4 = (pow(r1,2)*(Ypi-d) - r1*(Xpi-c)*sqrt(pow(Xpi-c,2)+pow(Ypi-d,2)-pow(r1,2)) ) / (pow(Xpi-c,2)+pow(Ypi-d,2))+d; #local s = (b-Yti1)*(Ypo-Yti1)/(Xti1-a)*(Xti1-Xpo); #if (s != 1) // check if correct coordinates are paired - if not, swap tangent y-values #local TempY = Yti3; #local Yti3 = Yti4; #local Yti4 = TempY; #end // output of macro is in the form of an array: array [10] { // Outer tangent data // Xto[N] "X tangent {point}, outer #N" 1 ( B ) 2 , // | 6 | 7 | , // | \|/ | , // -------|------- , // | /|\ | // Inner tangent data | 9 | 8 | , // Yto[N] "Y tangent {point}, outer #N" 3 ( A ) 4 , // , // , // // } #end #macro BezierArc (_Center, _T1, _T4) // Input: center of circle and 2 endpoints to make an arc between - going counterclockwise (LH system) // output: 4 points per 90 degree or less segment. #declare xc = _Center.x; #declare yc = _Center.z; #local CurrentAngle = ArcAngle (_Center, _T1, _T4); #local CA = CurrentAngle [2]; #local NumSegments = ceil (abs(CA)/90); #ifdef (Verbose) #debug concat ( " NumSegments = ", str (NumSegments, 0, 1), "\n") #end #local Partial = abs(CA)/90 - int (abs(CA)/90); #local Segments = array; //[NumSegments*4] #local PCurrent = 0; #for (S, 0, NumSegments-1) #local Quadrant = S*90; // multiples of 90 degrees: 0, 1, 2, 3 #ifdef (Verbose) #debug concat ( " Quadrant = ", str (Quadrant, 0, 1), "\n") #end #if (S = NumSegments-1) // if we're in the last segment, then T4 for this 4-point spline is the specified endpoint _T4 #local T4 = _T4; #else // if we're NOT in the last segment, then T4 for this 4-point spline is 90 degrees // from this 90-degree quadrant's starting point - which is a multiple of 90 deg from _T1 #local End = transform {translate -_Center rotate -y*(Quadrant+90) translate _Center } #local T4 = vtransform (_T1, End); #end // for any quadrant, the starting point is a multiple of 90 degrees from _T1 #local Start = transform {translate -_Center rotate -y*Quadrant translate _Center } #local T1 = vtransform (_T1, Start); // I'm thinking in x-y, so swap z values into y. ;) #local x1 = T1.x; #local y1 = T1.z; #local x4 = T4.x; #local y4 = T4.z; #ifdef (Verbose) #debug concat ( " x1 = ", str (x1, 0, 2), "\n") #debug concat ( " y1 = ", str (y1, 0, 2), "\n") #debug concat ( " x4 = ", str (x4, 0, 2), "\n") #debug concat ( " y4 = ", str (y4, 0, 2), "\n") #end // source: // https://pdfs.semanticscholar.org/1639/0db1a470bd13fe428e0896671a9a5745070a.pdf #local ax = x1 - xc; #local ay = y1 - yc; #local bx = x4 - xc; #local by = y4 - yc; #local q1 = ax*ax + ay*ay; #local q2 = q1 + ax*bx + ay*by; #local k2 = 4/3 * (sqrt(2*q1*q2)-q2)/(ax*by-ay*bx); // (4/3) // original equations // #local x2 = xc + x1 - k2*y1; // #local y2 = yc + y1 + k2*x1; // #local x3 = xc + x4 - k2*y4; // #local y4 = yc + y4 + k2*x4; // corrections to original equations from // https://hansmuller-flex.blogspot.com/2011/10/more-about-approximating-circular-arcs.html?showComment=1498749617507#c2109832351939371205 #local x2 = xc + ax - k2*ay; #local y2 = yc + ay + k2*ax; #local x3 = xc + bx + k2*by; // needed to change sign from: bx - k2*by | because of POV-Ray's #local y3 = yc + by - k2*bx; // needed to change sign from: by + k2*bx | LH coordinate system? #ifdef (Verbose) #debug concat ( " x2 = ", str (x2, 0, 2), "\n") #debug concat ( " y2 = ", str (y2, 0, 2), "\n") #debug concat ( " x3 = ", str (x3, 0, 2), "\n") #debug concat ( " y3 = ", str (y3, 0, 2), "\n") #end // These are the coordinates for the current 4-point segment of the loop #local P1 = ; #local P2 = ; #local P3 = ; #local P4 = ; #local Segments[PCurrent] = P1; #local PCurrent = PCurrent +1; #local Segments[PCurrent] = P2; #local PCurrent = PCurrent +1; #local Segments[PCurrent] = P3; #local PCurrent = PCurrent +1; #local Segments[PCurrent] = P4; #local PCurrent = PCurrent +1; #end Segments #end #macro LinearSegment (_Point1, _Point2) #local Vector = _Point2 - _Point1; #local Length = vlength (Vector); #local NVector = vnormalize (Vector); array [4] { _Point1 + 0/3*Vector, _Point1 + 1/3*Vector, _Point1 + 2/3*Vector, _Point1 + 3/3*Vector } #end // *** these are fine for place-holders in the 2D drawing, however the prism Bezier splines // are going to need DIRECTIONALITY in order for start and end control points to be in the proper positions // so that there isn't a head-to-head and tail-to-tail pairing, which will create wild looping instead of // a smooth convex curve // Maybe handle this in the conversion from point-array to prism with _Forward and _Backward flags // test gradient line //cylinder { <0, 0, -3>, <6, 0, -3> Line pigment {P_GreenRedLine scale <6, 1, 1>} translate -x*3} #macro GreenRedArc (_Angle, _Flip) pigment {radial frequency 360/_Angle color_map {CM_GreenRedGradient} rotate x*180*_Flip rotate -y*_Angle} #end #macro P_GreenRedArc (_Angle, _Temp) pigment {function {Radial (x, z, 360/_Angle, 0)} color_map {CM_GreenRedGradient}} #end // test gradient arc /* #for (A, 1, 20) torus {0.2, Line*2 P_GreenRedArc ((21-A)*18, 0) translate -x*4 translate x*0.5*(A-1) translate -z*3 } PlaceText (360/((21-A)*18), 3, <-4+0.5*(A-1), 0.02, -3.375>, 1, 7) //#declare Label1 = text {ttf "cyrvetic.ttf", str(360/((21-A)*18), 0, 2), 0.04, <0, 0> scale TextScale pigment {Black} rotate x*90} //#declare L1M = max_extent (Label1); //object {Label1 translate -x*L1M.x/2 rotate x*0 translate <-4, 0.02, -3.375> translate x*0.5*(A-1)} #end */ // Create a dynamic array to hold all of the line and arc segments, // each of which is 4 points // Prism itself will be number of PrismArray elements +1 to include second start point to close the prism // first each segment will be _directionally_ transcribed from the arrays output from the macros // then the master array will be transcribed into the prism {} declaration #declare PrismArray = array; #declare CurrentElement = 0; // Global element counter. Increment after each point addition #declare DebugArray = array; #declare CurrentDebug = 0; // Draw elements composing the prism outline #for (Tangent, 0, EL_Circles-ArrayIsLinear) #local ElementL = Tangent - 1; //mod(Tangent-1, DS_Circles); #if (ElementL < 0) #local ElementL = EL_Circles; #end #local ElementA = mod(Tangent , DS_Circles+1); #local ElementB = mod(Tangent+1, DS_Circles+1); #if (ElementB > EL_Circles) #local ElementB = 0; #end #local CenterL = ; #local RadiusL = CircleArray [ElementL][3]; #local CenterA = ; #local RadiusA = CircleArray [ElementA][3]; #local CenterB = ; #local RadiusB = CircleArray [ElementB][3]; // get data for 4 tangent lines from #debug concat ( "\n\n ***** TANGENTS FROM CIRCLE ", str (ElementL, 2, 0), " to ", str (ElementA, 2, 0), " ***** \n\n") #local LastTangent = AnalyticalTangents (CenterL, RadiusL, CenterA, RadiusA); #debug concat ( "\n\n ***** TANGENTS FROM CIRCLE ", str (ElementA, 2, 0), " to ", str (ElementB, 2, 0), " ***** \n\n") #local CurrentTangent = AnalyticalTangents (CenterA, RadiusA, CenterB, RadiusB); // intersection, Outer tangent 1, 2, 3, 4, intersection, inner tangent 1, 2, 3, 4 union { // Arc angles are calculated counterclockwise. // this is right for "concave" arcs, but reversed for "convex" ones // use selected tangent colors for circles A and B to determine // endpoints of arc, and added flags for _which arc_ and direction #if (CircleArray [ElementL][6] & CircleArray [ElementA][6]) // if 2 tangents are chosen #local TangentList = array [9] {0, 1, 2, 6, 7, 3, 4, 8, 9} #local CT1 = CurrentTangent[TangentList[CircleArray[ElementA][6]]]; // Chosen Tangent point #local CT2 = LastTangent[TangentList [CircleArray[ElementL][6]+4]]; // Chosen Tangent point #local Anglearray = ArcAngle (CenterA, CT1, CT2); #local _Start = Anglearray[0]; #local _End = Anglearray[1]; #local _Angle1 = Anglearray[2]; object { Segment_of_Torus ( RadiusA, // radius major, Line*LM, // radius minor, _Angle1 // segment angle (in degrees) ) #if (CircleArray[ElementA][8]) #if (CircleArray[ElementA][8] = 1) #debug "\n\n ***** FORWARD ARC ***** \n\n" #if (CircleArray [ElementA][9] = 1) P_GreenRedArc (_Angle1, 0) // directional color gradient #local ThisArc = BezierArc (CenterA, CT1, CT2) #declare DebugArray [CurrentDebug] = ; #declare CurrentDebug = CurrentDebug + 1; #for (EL, 0, dimension_size (ThisArc, 1)-1) // forward #declare PrismArray [CurrentElement] = ThisArc [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisArc [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #elseif (CircleArray [ElementA][9] = 2) P_GreenRedArc (-_Angle1, 0) // directional color gradient #local ThisArc = BezierArc (CenterA, CT1, CT2) #declare DebugArray [CurrentDebug] = <-(Tangent + CircleArray[ElementA][9]/10), 0, 0>; // use sign to indicate direction of arc #declare CurrentDebug = CurrentDebug + 1; #for (EL, dimension_size (ThisArc, 1)-1, 0, -1) // reverse #declare PrismArray [CurrentElement] = ThisArc [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisArc [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #else #warning "Invalid arc direction declared in CircleArray." #declare ValidPrism = false; #end #else pigment {P_Ghost} #end #else pigment {White} // pigment {P_Arc[0]} need to define this array #end no_shadow scale <1, 1, -1> rotate -y*_Start translate CenterA } // if tangents are chosen, then arcs are defined and can be colored // once a colored arc is chosen, then the other arc can be greyed out // THEN the direction of#declare CurrentElement = the arc needs to be chosen to apply a directional gradient object { Segment_of_Torus ( RadiusA, // radius major, Line*LM, // radius minor, (360-_Angle1) // segment angle (in degrees) ) #if (CircleArray[ElementA][8]) #if (CircleArray[ElementA][8] = 2) #debug "\n\n ***** REVERSE ARC ***** \n\n" #if (CircleArray [ElementA][9] = 1) P_GreenRedArc ( (360-_Angle1), 0) // directional color gradient #local ThisArc = BezierArc (CenterA, CT2, CT1) #declare DebugArray [CurrentDebug] = ; #declare CurrentDebug = CurrentDebug + 1; #for (EL, 0, dimension_size (ThisArc, 1)-1) // forward #declare PrismArray [CurrentElement] = ThisArc [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisArc [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #elseif (CircleArray [ElementA][9] = 2) P_GreenRedArc (-(360-_Angle1), 0) // directional color gradient #local ThisArc = BezierArc (CenterA, CT2, CT1) #declare DebugArray [CurrentDebug] = <-(Tangent + CircleArray[ElementA][9]/10), 0, 0>; // use sign to indicate direction of arc #declare CurrentDebug = CurrentDebug + 1; #for (EL, dimension_size (ThisArc, 1)-1, 0, -1) // reverse #declare PrismArray [CurrentElement] = ThisArc [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisArc [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #else #warning "Invalid arc direction declared in CircleArray." #declare ValidPrism = false; #end #else pigment {P_Ghost} #end #else pigment {Black} // pigment {P_Arc[1]} need to define this array #end no_shadow scale <1, 1, -1> rotate -y*_End translate CenterA } #else // no tangents are chosen so there are no ARCS to choose and apply a color to torus {RadiusA, Line translate CenterA no_shadow} #end // LABEL CIRCLES with position in array #if (RadiusA*2 > TextScale*2) PlaceText (Tangent, 1, CenterA, 2, 0) #end // 0 1 2 3 4 5 6 7 8 9 // {x, y, z, rad, # sides, rotation of polygon, Tangent by color, dir, Arc by color, dir} // ***** Code to include Bezier Arc points into prism definition ***** /* Already took care of this above.... #if (CircleArray [ElementA][8]) #if (CircleArray [ElementA][9] = 1) // Forward #local ThisArc = BezierArc (CenterA, CT1, CT2) #elseif (CircleArray [ElementA][9] = 2) // Reverse #local ThisArc = BezierArc (CenterA, CT2, CT1) #else #warning "Invalid arc segment declared in CircleArray." #declare ValidPrism = false; #end #end */ //------------------------------------------------------------------ #declare TVector = CurrentTangent[3] - CurrentTangent[1]; #declare TLength = vlength (TVector); #declare TAngle = Angle2D (x, TVector); //cylinder {CurrentTangent[1], CurrentTangent[3] Line cylinder {0, <1, 0, 0> #if (CircleArray[ElementA][6]) #if (CircleArray[ElementA][6] = 1) //pigment {P_Tangent[CircleArray[ElementA][6]-1]} Line*LM pigment {P_GreenRedLine} #local ThisLine = LinearSegment (CurrentTangent[1], CurrentTangent[3]) #declare DebugArray [CurrentDebug] = <1, 0, 3>; #for (EL, 0, dimension_size (ThisLine, 1)-1) // forward #declare PrismArray [CurrentElement] = ThisLine [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisLine [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #else Line pigment {P_Ghost} #end #else Line pigment {P_Tangent[0]} #end no_shadow scale rotate -y*TAngle translate CurrentTangent[1] // <----- } #if (Endpoints) sphere {CurrentTangent[1] Line*2 pigment {Black}} sphere {CurrentTangent[3] Line*2 pigment {Black}} #end //------------------------------------------------------------------ #declare TVector = CurrentTangent[4] - CurrentTangent[2]; #declare TLength = vlength (TVector); #declare TAngle = Angle2D (x, TVector); //cylinder {CurrentTangent[2], CurrentTangent[4] Line cylinder {0, <1, 0, 0> #if (CircleArray[ElementA][6]) #if (CircleArray[ElementA][6] = 2) //pigment {P_Tangent[CircleArray[ElementA][6]-1]} Line*LM pigment {P_GreenRedLine} #local ThisLine = LinearSegment (CurrentTangent[2], CurrentTangent[4]) #declare DebugArray [CurrentDebug] = <2, 0, 4>; #for (EL, 0, dimension_size (ThisLine, 1)-1) // forward #declare PrismArray [CurrentElement] = ThisLine [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisLine [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #else Line pigment {P_Ghost} #end #else Line pigment {P_Tangent[1]} #end no_shadow scale rotate -y*TAngle translate CurrentTangent[2] // <----- } #if (Endpoints) sphere {CurrentTangent[2] Line*2 pigment {Black}} sphere {CurrentTangent[4] Line*2 pigment {Black}} #end //------------------------------------------------------------------ #declare TVector = CurrentTangent[8] - CurrentTangent[6]; #declare TLength = vlength (TVector); #declare TAngle = Angle2D (x, TVector); //cylinder {CurrentTangent[6], CurrentTangent[8] Line cylinder {0, <1, 0, 0> #if (CircleArray[ElementA][6]) #if (CircleArray[ElementA][6] = 3) //pigment {P_Tangent[CircleArray[ElementA][6]-1]} Line*LM pigment {P_GreenRedLine} #local ThisLine = LinearSegment (CurrentTangent[6], CurrentTangent[8]) #declare DebugArray [CurrentDebug] = <6, 0, 8>; #for (EL, 0, dimension_size (ThisLine, 1)-1) // forward #declare PrismArray [CurrentElement] = ThisLine [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisLine [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #else Line pigment {P_Ghost} #end #else Line pigment {P_Tangent[2]} #end no_shadow scale rotate -y*TAngle translate CurrentTangent[6] // <----- } #if (Endpoints) sphere {CurrentTangent[6] Line*2 pigment {Black}} sphere {CurrentTangent[8] Line*2 pigment {Black}} #end //----------------------------LinearFlag = 0-------------------------------------- #declare TVector = CurrentTangent[9] - CurrentTangent[7]; #declare TLength = vlength (TVector); #declare TAngle = Angle2D (x, TVector); //cylinder {CurrentTangent[7], CurrentTangent[9] Line cylinder {0, <1, 0, 0> #if (CircleArray[ElementA][6]) #if (CircleArray[ElementA][6] = 4) //pigment {P_Tangent[CircleArray[ElementA][6]-1]} #declare LinearFlag = 1; Line*LM pigment {P_GreenRedLine} #local ThisLine = LinearSegment (CurrentTangent[7], CurrentTangent[9]) #declare DebugArray [CurrentDebug] = <7, 0, 9>; #for (EL, 0, dimension_size (ThisLine, 1)-1) // forward #declare PrismArray [CurrentElement] = ThisLine [EL]; #declare CurrentElement = CurrentElement + 1; #declare DebugArray [CurrentDebug] = ThisLine [EL]; #declare CurrentDebug = CurrentDebug + 1; #end #else Line pigment {P_Ghost} #end #else Line pigment {P_Tangent[3]} #end no_shadow scale rotate -y*TAngle translate CurrentTangent[7] // <----- } #if (Endpoints) sphere {CurrentTangent[7] Line*2 pigment {Black}} sphere {CurrentTangent[9] Line*2 pigment {Black}} #end //------------------------------------------------------------------ #if (ArrayIsLinear & Tangent = EL_Circles-ArrayIsLinear) torus {RadiusB, Line translate CenterB no_shadow} #end pigment {LinePigment} } #end // Make prism :) #declare PrismArraySize = dimension_size (PrismArray, 1); #debug concat ( " ArraySize = ", str (PrismArraySize, 0, 2), "\n") #debug concat ( " Segments = ", str (PrismArraySize/4, 0, 2), "\n") #debug concat ( "First Point = ", vstr(3, PrismArray [0], ", ", 3, 2), " \n") #debug concat ( " Last Point = ", vstr(3, PrismArray [PrismArraySize-1], ", ", 3, 2), " \n") #declare PRISM = prism { linear_sweep bezier_spline 0.00, PrismHeight, PrismArraySize #debug "===================================\n" #declare EL = 0; #for (S, 1, PrismArraySize/4) #for (P, 1, 4) , #debug concat ( "Current Point = ", vstr(3, PrismArray [EL], ", ", 3, 2), " \n") #declare EL = EL + 1; #end #debug "===================================\n" #end // close prism // } #debug concat ( "First Point = ", vstr(3, PrismArray [0], ", ", 3, 2), " \n") #debug concat ( " Last Point = ", vstr(3, PrismArray [PrismArraySize-1], ", ", 3, 2), " \n") /* // plot out all control points #declare EL = 0; #for (S, 1, PrismArraySize/4) #for (P, 1, 4) #if (EL < PrismArraySize-1) cylinder {PrismArray [EL], PrismArray [EL+1]+E Line*1.5 pigment {White}} #end sphere {PrismArray [EL] Line*2 pigment {P_Text [5-P]}} #declare EL = EL + 1; #end #end */ #if (ShowPrism) object {PRISM texture {pigment {Cyan transmit 0.8}} scale <1, Line/PrismHeight, 1> no_shadow} #end #declare O_AllCircles = union { #for (O, 0, EL_Circles) torus {CircleArray [O][3], Line*LM translate } #end } //object {O_AllCircles pigment {Black}} #declare P_AllCircles = pigment { object { sphere { <0,0,0>, 0.5 } color rgb 1, color rgb 0 } } #declare F_AllCircles = function {pigment {P_AllCircles}} #declare T_AllCircles = texture { // give function pigment an infinite y scaling function {F_AllCircles (x, 0, z).red} texture_map { [0.0 Brn] [1.0 Tan] } } //box {<-10, 0, -10>, <10, -1, 10> pigment {P_AllCircles} translate y*1} #if (ShowSmallPrisms) //Tan object {PRISM texture {Tan} scale 1/5 rotate x*90 translate <8, 1, 0>} object {PRISM texture {Tan} scale 1/5 rotate x*45 translate <8, 1, -2>} #end #debug "\n\n\n ======================DEBUGGING=========================== \n\n" #declare DebugArraySize = dimension_size (DebugArray, 1)-1; #for (D, 0, DebugArraySize) #debug concat (vstr(3, DebugArray [D], ", ", 3, 2), " \n") #end /* #declare T = AnalyticalTangents (<-4, -2>, 3, <3, 4>, 1); union { torus {3, Line translate <-4, 0, -2>} torus {1, Line translate < 3, 0, 4>} cylinder {T[1], T[3] Line} cylinder {T[2], T[4] Line} cylinder {T[6], T[8] Line} cylinder {T[7], T[9] Line} pigment {LinePigment} } */ /* need line intersection macro need bezier spline macros - linear and [correct] circular arc 1. define array of "pulleys" { <0, 0, 0.00>, R1, sides, angle <1, 0, 0.50>, R2, sides, angle <2, 0, -0.25>, R3, sides, angle } 2. test pulleys in triplets - create a line from 1 to 3, if perpendicular diameter of 2 intersects this line, then there are 2 possible routes. is whole circle is angled (-y) then convex - use outer tangent, if (+y) then concave - use inner tangent 3. based on flag, use programmatically determined defaults if array error (convex vs concave) or exclude pulley 3a. reinterpret circles as [rotated] polygons if applicable 4. define second array of belt paths (internal or external tangents) [cylinders] and circular arcs [tori] 5. plot discs and belt path as base for prism 6. create a series of Bezier spline segments to follow path 7. plot prism {} object on base create 3D pulleys and linked belts / chains, gears, sprockets */ /* #for (A, 0, tau, tau/180) #local X = cos (A); #local Z = sin (A); #local _vector = ; //#local T = VAngleD (_vector, x); #local T = degrees(atan2(Z,X)); cylinder {0, <1, 0, 0> Line rotate y*T pigment {Green} } #end */ /* // given two circles with centers c1 and c2, and radii r1 and r2, // find the coordinates of the points of tangency of [up to] 4 tangent lines // t1[n] and t2[n] for n=1...4 // if one circle is interior to the other, there are 0 tangent points // if one is inside but tangent, there is 1 tangent point // if the circles intersect each other at 2 points, then there are 2 tangents (4 points) // if the circles are tangent and exterior to each other, there are 3 tangents (5 points) // if the circles are exterior to each other, there are 4 tangents (8 points) // solve 4 simultaneous equations: (t2-c2)o(t2-t1) = 0 // equation (1) r2 is perpendicular to the tangent (t1-c1)o(t2-t1) = 0 // equation (2) r1 is perpendicular to the tangent |t1-c1|^2 = r1^2 // equation (3) |t2-x2|^2 = r2^2 // equation (4) // c1 = , c2 = , t1 = , t2 = //the radius of circle 2 is perpendicular to the tangent, and so the slopes are negative inverses (f-b)/(e-a) = -(c-e)/(d-f) // or expressed as a vector dot product (equation 1 in coordinate representation): (f-b)(d-f) + (e-a)(c-e) = 0 //the radius of circle 1 is perpendicular to the tangent, and so the slopes are negative inverses (d-y)/(c-x) = -(c-e)/(d-f) // or expressed as a vector dot product (equation 2 in coordinate representation): (d-y)(d-f) + (c-x)(c-e) = 0 // the distance between the point of tangency and the center of c1 is r1 (d-y)^2 + (c-x)^2 = r1^2 // the distance between the point of tangency and the center of c2 is r2 (f-b)^2 + (e-a)^2 = r2^2 dot product AoB = |A| |B| cos theta if A and B are perpendicular (theta = pi/2), then cos theta = 0 and so the whole dot product equals 0 o = ax+by+cz old way #macro OuterTangent (_C1, _R1, _C2, _R2) // coordinates of pulley centers are in x-z plane for final prism, so use .u and .v designations // so that there's no confusion with .x and .y dot notation // calculate distance between circle centers - the hypotenuse of the triangle we will use #local _h = sqrt ( pow(_C1.x - _C2.x, 2) + pow(_C1.z - _C2.z, 2)); // calculate Difference in circle radii - the opposite side of the triangle we will use #local _o = _R1 - _R2; // Calculate angle _alpha, between tangent and centerline of circles // sin _alpha = _o / _h, so: #local _alpha = degrees(asin(_o/_h)); // expressed in degrees // tangent length // adjacent^2 + opposite^2 = hypotenuse^2, so adjacent^2 = = hypotenuse^2 - opposite^2 , and: #local _length = sqrt ( pow (_h, 2) - pow (_o, 2) ); // #local _Xdiff = _C2.x - _C1.x; #local _Zdiff = _C2.z - _C1.z; #local _vector = <_Xdiff, 0, _C1.z - _C2.z>; // Because of LH coordinate system #local _Yangle = degrees (atan2 (_vector.z, _vector.x)); // calculates angle around y the line connecting C1 and C2 is at #local _Tdir = sgn(_Xdiff); // sign of xdiff to direct direction of translation // return length and angle as a vector //<_length, _alpha, _Yangle, _Tdir> array [5] { _length, _alpha, _Yangle, _Xdiff, _Zdiff } // segment angles and lengths //#local Sector1 = 180 + (2 * _alpha); // Major sector (pi + 2 alpha) //#local Sector2 = 180 - (2 * _alpha); // Minor sector (pi - 2 alpha) //#local Arc1 = (Sector1/360) * (2*pi) * R1; // Calculate chain lengths in direct contact with pulleys //#local Arc2 = (Sector2/360) * (2*pi) * R2; // (fraction of a circle) x 2 pi radians x Radius = arc length // total length //#local Belt = (2*Linear) + Arc1 + Arc2; // Add linear and curved sections to get total chain length //#local LengthPerLink = Total_Length / Links; // Divide total chain length by number of links #end // end macro CalcTangent */ /* rotate y*CurrentTangent[2] // align with 2-circle axis rotate y*(CurrentTangent[1]) // adjust for tangent angle translate CenterA translate x * sin (radians (CurrentTangent[2])) * min(RadiusA, RadiusB) translate z * cos (radians (CurrentTangent[1]+CurrentTangent[2])) * RadiusA } #local XS = sgn(CurrentTangent[3])+1; #local ZS = sgn(CurrentTangent[4])+1; #local A = CurrentTangent[2]; text {ttf "cyrvetic.ttf", concat (Sign[XS], "x ", Sign[ZS], "z ", str (A, 0, 2)), Line, <0, 0> scale 0.1 rotate x*90 translate y*0.01 translate (CenterA+CenterB)/2 } */