|
|
So, Rick S's little zig-zag function got my brain churning, and I figured that a
mod() function would be just the thing that he wants.
I could imagine that such a reversing function would be of use in constructing
scenes and animations, and it would be useful to work that out into a macro to
make it a bit easier and faster to get the desired behaviour.
Working with functions is easier when you can see what's going on, and so it
needs to get graphed. I'd likely want to see lots of graphs with small
modifications, so I could compare them.
And that of course led to writing a macro to graph a function.
inside a bounded area that is easily scaled
easily positioned anywhere on the screen
over a user-defined interval
with tick marks and numeric labels and x & y axes
So, since I still have a lot astronomical stuff to look up and decipher, that's
what I did last night instead of watching a video on the pin-and slot gears in
the Antikythera mechanism or watching the Srinivasa Ramanujan movie.
Here ya go, kids.
Feedback, questions, comments and suggestions for improvements welcome as
always.
###################################################################
// 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
//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>, <Abscissa,
(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>, <Abscissa/100,
(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 <Abscissa/100, 0.95*(Y-Min)*Ordinate/(Max-Min), 0> 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>, <Abscissa, 0, 0> 1 pigment {Red}}
cylinder {<0, 0, 0>, <0, Ordinate, 0> 1 pigment {Green}}
cylinder {<0, Ordinate, 0>, <Abscissa, Ordinate, 0> 1 pigment {Gray50}}
cylinder {<Abscissa, 0, 0>, <Abscissa, Ordinate, 0> 1 pigment {Gray50}}
#for (T, 0, Values)
#local XX = T*(Abscissa/Values);
#local YY = (Data [T] - Min) * (Ordinate/(Max-Min));
sphere {<XX, YY, -1> 1 pigment {Black}}
#if (T > 0)
cylinder {LastPoint, <XX, YY, -1> 1 pigment {Black}}
#end
#local LastPoint = <XX, YY, -1>;
#end
// Label Axes
LooseLabel (Start, End, TickX, 0)
LooseLabel (Min, Max, TickY, 1)
translate <MoveX*image_width, MoveY*image_height, 0>
}
#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)
Post a reply to this message
Attachments:
Download 'graphfunction.png' (87 KB)
Preview of image 'graphfunction.png'
|
|