// Persistence of Vision Ray Tracer version 3.7.1-beta.2 // Scene Description Language (SDL) // File: GraphFunction.pov // Version: 1.0 // Last updated: 24-May-2017 // Description: Graph a function in a box and label the axes with tick marks // Axis numbering code adapted from NICE NUMBERS FOR GRAPH LABELS by Paul S. Heckbert University of California // in: Graphics Gems II edited by ANDREW S. GLASSNER (1990) // // Author: Bill Walker "Bald Eagle", 2017 // email: see posts in news.povray.org // //------------------------------------------------------------------------ #version 3.7; global_settings { assumed_gamma 1.0 } #include "colors.inc" #declare Feet = 12; #declare PHI = (1+sqrt(5))/2; #declare phi = (sqrt(5)-1)/2; #declare Camera_Orthographic = true; #declare Camera_Position = <0, 0, -300> ; // front view #declare Camera_Look_At = <0, 0, 0> ; #declare Fraction = 1; // functions as a zoom for the orthographic view: 4 zooms in 4x, 8 zooms in 8x, etc. // ########################################### camera { #if (Camera_Orthographic = true) orthographic right x*image_width/(Fraction) up y*image_height/(Fraction) #else right x*image_width/image_height up y #end location Camera_Position look_at Camera_Look_At} // ########################################### background {White} light_source {<0, 10, -500> color White*0.5} #declare Origin = sphere {0, 1 pigment {Black}} //object {Origin} //box {<-image_width/4, -image_height/4, -1>, < image_width/4, image_height/4, -2> pigment {Green}} #macro GraphFunction (Label, PercentWidth, PercentHeight, Function, Start, End, Step, P1, P2, TickX, TickY, MoveX, MoveY, MarkZero, Verbose) // define sub-macros used in lower main macro #macro NiceNum (X, Round) // Code adapted from Graphics Gems, Section II.2 - NICE NUMBERS FOR GRAPH LABELS by Paul S. Heckbert University of California pp 61-63 //nicenum: find a “nice” number approximately equal to x. //Round the number if round = true, take ceiling if round = false. //exp: int; exponent of x //f: real; fractional part of x //nf: real; nice, rounded fraction //begin #local Exp = floor (log(X)); #local F = X / pow (10, Exp); // between 1 and 10 #if (Round) #if (F < 1.5) #local NF = 1; #elseif (F < 3) #local NF = 2; #elseif (F < 7) #local NF = 5; #else #local NF = 10; #end #else #if (F <= 1) #local NF = 1; #elseif (F <= 2) #local NF = 2; #elseif (F <= 5) #local NF = 5; #else #local NF = 10; #end #end NF*pow (10, Exp); #end // end macro NiceNum #macro LooseLabel (VStart, VEnd, Ticks, Axis) // Code adapted from Graphics Gems, Section II.2 - NICE NUMBERS FOR GRAPH LABELS by Paul S. Heckbert University of California pp 61-63 // rounding #local Range = NiceNum (VEnd-VStart, true); #local D = NiceNum (Range/(Ticks-1), true); #local graphmin = floor (VStart/D)*D; #if (Axis = 0) #local Modifier = -1; #else #local Modifier = 0; #end #local graphmax = (Modifier) + ceil (VEnd/D)*D; // added -1 to keep labels inside box - BW #local nfrac = max (-floor(log(D)), 0); //number of fractional digits to show #if (Axis = 0) #for (X, graphmin, graphmax + 0*(0.5*D), D) #if (MarkZero & X = 0) cylinder {<(X-Start)*Abscissa/(End-Start), 0, 0>, <(X-Start)*Abscissa/(End-Start), Ordinate, 0> 0.75 pigment {Green}} #end // put tick mark at x, with a numerical label showing nfrac fraction digits cylinder {<(X-Start)*Abscissa/(End-Start), 0, 0>, <(X-Start)*Abscissa/(End-Start), Ordinate/10, 0> 1 pigment {Red}} text {ttf "arial.ttf", str (X, 2, nfrac), 0.01, 0.0 scale Ordinate/15 translate <(X-Start)*Abscissa/(End-Start), Ordinate/10, 0> pigment {Black}} #end #else #for (Y, graphmin, graphmax + 1*(0.5*D), D) #if (MarkZero & Y = 0) cylinder {<0, (Y-Min)*Ordinate/(Max-Min), 0>, 0.75 pigment {Red}} #end #debug concat ( "YLabel = ", str (Y, 3, 1), "\n") // put tick mark at x, with a numerical label showing nfrac fraction digits cylinder {<0, (Y-Min)*Ordinate/(Max-Min), 0>, 1 pigment {Green}} text {ttf "arial.ttf", str (Y, 1, nfrac), 0.01, 0.0 scale Ordinate/15 translate pigment {Black}} #end #end #end // end macro LooseLabel //--------------------------------------------------------------------------------------------------------------------------- #local Abscissa = PercentWidth*image_width; #local Ordinate = PercentHeight*image_height; #if (Step = 0) #local Step = (End-Start)/Abscissa; #end #local Values = (End-Start)/Step; // Number of values that will be plotted #if (Verbose) #debug concat ( "Creating Graph: ", str (PercentWidth*100, 3, 1), "% Wide x ", str (PercentHeight*100, 3, 1), "% High \n") #debug concat ( "From ", str (Start, 3, 1), " to ", str (End, 3, 1), "in steps of ", str (Step, 3, 1), " (", str (Values, 3, 1), " values) \n") #end #local Data = array [Values+1]; #local Calc = 0; #local Min = 0; #local Max = 0; // generate data #for (T, Start, End, Step) //#local F_of_T = abs(mod(T, P1)-3)+P2; #local F_of_T = Function (T); #declare Min = min (F_of_T, Min); #declare Max = max (F_of_T, Max); //#debug concat ( "Calc = ", str (Calc, 3, 1), "\n") #local Data [Calc] = F_of_T; #local Calc = Calc + 1; #end #if (Verbose) #debug concat ( "Min = ", str (Min, 3, 1), "\n") #debug concat ( "Max = ", str (Max, 3, 1), "\n") #end union { text {ttf "arial.ttf", Label, 0.01, 0.0 pigment {Black} scale Ordinate/10 translate y*0.9*Ordinate} cylinder {<0, 0, 0>, 1 pigment {Red}} cylinder {<0, 0, 0>, <0, Ordinate, 0> 1 pigment {Green}} cylinder {<0, Ordinate, 0>, 1 pigment {Gray50}} cylinder {, 1 pigment {Gray50}} #for (T, 0, Values) #local XX = T*(Abscissa/Values); #local YY = (Data [T] - Min) * (Ordinate/(Max-Min)); sphere { 1 pigment {Black}} #if (T > 0) cylinder {LastPoint, 1 pigment {Black}} #end #local LastPoint = ; #end // Label Axes LooseLabel (Start, End, TickX, 0) LooseLabel (Min, Max, TickY, 1) translate } #end // end macro GraphFunction // Usage: GraphFunction (Label, PercentWidth, PercentHeight, Function, Start, End, Step, P1, P2, MoveX, MoveY, MarkZero, Verbose) GraphFunction ("f(x) = sin (x)", 0.5, 0.25, function (T) {sin (T)}, -12, 13, 0, 2, 0, 10, 5, -0.5, 0.25, no, off) GraphFunction ("f(x) = cos (x)", 0.5, 0.25, function (T) {cos (T)}, -tau, tau, 0, 2, 0, 10, 5, -0.5, 0.00, no, off) GraphFunction ("f(x) = sqrt (x)", 0.5, 0.25, function (T) {sqrt (T)}, -12, 13, 0, 2, 0, 10, 5, 0.0, -0.25, no, off) GraphFunction ("f(x) = pow (x,2)", 0.5, 0.125, function (T) {pow (T,2)}, -2, 3, 0, 2, 0, 10, 5, 0, 0, no, on) GraphFunction ("f(x) = sin (5x)/5x", 0.5, 0.5, function (T) {sin (5*T)/(5*T)}, -tau, tau, 0, 2, 0, 10, 5, -0.5, -0.5, no, off) GraphFunction ("f(x) = abs(mod(x,6)-3)", 0.25, 0.125, function (T) {abs(mod(T,6)-3)}, -12, 24, 0, 2, 0, 10, 5, 0.125, 0.25, no, off)