G2dGraphImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, July 2, 1992 5:09 pm PDT
Glassner, November 30, 1990 7:13 pm PST
DIRECTORY Controls, Draw2d, FileNames, G2dGraph, Imager, ImagerFont, IO, RealFns, Rope, ViewerClasses;
G2dGraphImpl: CEDAR PROGRAM
IMPORTS Controls, Draw2d, FileNames, Imager, ImagerFont, IO, RealFns, Rope
EXPORTS G2dGraph
~ BEGIN
Types
ROPE:   TYPE ~ Rope.ROPE;
GraphData: TYPE ~ G2dGraph.GraphData;
GraphProc: TYPE ~ G2dGraph.GraphProc;
Function:  TYPE ~ G2dGraph.Function;
Functions
Bump: PUBLIC GraphProc ~ {
xx: REAL ~ 1.0-ABS[1.0-x-x];
RETURN[xx*xx];
};
Gauss: PUBLIC GraphProc ~ {
mean: REAL ~ 0.5;
pi: REAL ~ 3.1415926535;
standardDeviation: REAL ~ 0.16;
factor1: REAL ~ 1.0/(2.0*standardDeviation*standardDeviation);
factor2: REAL ~ 1.0/(standardDeviation*RealFns.SqRt[2.0*pi]);
xx: REAL ~ x-mean;
RETURN[factor2*RealFns.Exp[-xx*xx*factor1]];
};
Poisson: PUBLIC GraphProc ~ {RETURN[g.a*x*RealFns.Exp[-g.a*x]]};
Power: PUBLIC GraphProc ~ {RETURN[RealFns.Power[x, g.a]]};
Sin: PUBLIC GraphProc ~ {RETURN[RealFns.Power[0.5+0.5*RealFns.Sin[x], g.a]]};
Ln: PUBLIC GraphProc ~ {RETURN[RealFns.Ln[x]]};
Log: PUBLIC GraphProc ~ {RETURN[RealFns.Log[g.a, x]]};
Exp: PUBLIC GraphProc ~ {
a: REAL ¬ IF g.a = 1.0 THEN 1.01 ELSE g.a;
RETURN[(RealFns.Power[a, x]-1.0)/(a-1.0)];
};
Perlin: PUBLIC GraphProc ~ {
IF x <= 0.0 OR g.a <= 0.0 THEN RETURN[0.0];
RETURN[RealFns.Power[0.5, RealFns.Log[0.5, x]*RealFns.Log[0.5, g.a]]];
};
WyvillData: TYPE ~ RECORD [R2, R4, R6: REAL];
Wyvill: PUBLIC GraphProc ~ {
w: REF WyvillData ¬ NARROW[g.clientData];
r2: REAL ~ x*x;
r4: REAL ~ r2*r2;
r6: REAL ~ r2*r4;
RETURN[w.R6*r6+w.R4*r4+w.R2*r2+1.0];
};
SlowInOut: PUBLIC GraphProc ~ {
RETURN[(3.0-2.0*x)*x*x];
};
Compress: PUBLIC GraphProc ~ {
RETURN[2.0*RealFns.Exp[-x*x*0.5]];
};
Pavicic: PUBLIC GraphProc ~ {
pi: REAL ~ 3.1415926535;
a: REAL ~ 0.5823997; -- a=(1-v2)/(v1-v2), v1=pi/3, v2=(pi/2)-(2/pi)
t1: REAL ¬ a*(1.0-x);
t2: REAL ¬ (1.0-a)*(1.0+RealFns.Cos[pi*x])/2.0;
RETURN[t1+t2];
};
PerspZ: PUBLIC GraphProc ~ {
d: REAL ¬ 10.0;
den: REAL ¬ x/d+1.0;
y ¬ IF ABS[den] < 0.0001 THEN 100.0 ELSE x/den;
};
SquashStretch: PUBLIC GraphProc ~ {
angle: REAL ¬ 2.0*3.14159256535*x;
dot: REAL ¬ RealFns.Cos[angle];
y ¬ ((1-g.a)*0.5)*RealFns.Cos[3.1415926535*dot]+((g.a+1)/2.0);
};
Ease: PUBLIC GraphProc ~ {
F: PROC [x, v: REAL] RETURNS [REAL] ~ { RETURN[1.0/(1.0+RealFns.Exp[-v*x])]; };
fMinus1: REAL ¬ F[-1.0, g.a];
RETURN[(F[(2.0*x)-1.0, g.a] - fMinus1)/(F[1.0, g.a] - fMinus1)];
};
Function Registration
functions: LIST OF Function ¬ NIL;
RegisterFunction: PUBLIC PROC [function: Function] ~ {
functions ¬ CONS[function, functions];
};
GetFunctions: PUBLIC PROC RETURNS [LIST OF Function] ~ {RETURN[functions]};
GetFunction: PUBLIC PROC [name: ROPE] RETURNS [f: Function] ~ {
FOR l: LIST OF Function ¬ GetFunctions[], l.rest WHILE l # NIL DO
IF Rope.Equal[l.first.name, name, FALSE] THEN RETURN[l.first];
ENDLOOP;
};
Graphing
Data:    TYPE ~ REF DataRep;
DataRep:   TYPE ~ RECORD [
outerData:    Controls.OuterData ¬ NIL,
ticks:      BOOL ¬ TRUE,
graphData:    GraphData ¬ NIL,
graphProc:    GraphProc ¬ NIL];
GraphFunction: PUBLIC PROC [
function: Function,
xMin: REAL ¬ 0.0,
xMax: REAL ¬ 1.0,
scale: REAL ¬ 1.0,
a: REAL ¬ 1.0,
clientData: REF ANY ¬ NIL]
RETURNS [error: ROPE]
~ {
g: GraphData ¬ NEW[G2dGraph.GraphDataRep ¬
[a: a, xMin: xMin, xMax: xMax, scale: scale, clientData: clientData]];
d: Data ¬ NEW[DataRep ¬ [graphData: g, graphProc: function.proc]];
IF ABS[xMax-xMin] < 0.0001 THEN RETURN["x range too small"];
IF d.graphProc = Wyvill THEN {
w: REF WyvillData ¬ g.clientData ¬ NEW[WyvillData];
aa: REAL ~ -4.0/9.0;
bb: REAL ~ 17.0/9.0;
cc: REAL ~ -22.0/9.0;
IF g.a = 0.0 THEN g.a ¬ 1.0;
w.R2 ¬ 1.0/(d.graphData.a*d.graphData.a);
w.R4 ¬ w.R2*w.R2;
w.R6 ¬ w.R2*w.R4;
w.R2 ¬ cc*w.R2;
w.R4 ¬ bb*w.R4;
w.R6 ¬ aa*w.R6;
};
d.outerData ¬ Controls.OuterViewer[
name: IO.PutFLR["2dGraph %g -xMin %g -xMax %g -scale %g -a %g",
LIST[IO.rope[function.name], IO.real[xMin], IO.real[xMax], IO.real[scale], IO.real[a]]],
graphicsHeight: 200,
drawProc: DrawProc,
typescriptHeight: 18,
buttons: LIST[
Controls.ClickButton["IPOut", IPOut, d],
Controls.ClickButton["Ticks: On", TicksToggle, d]],
clientData: d];
};
TicksToggle: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
Controls.ButtonToggle[d.outerData, d.ticks ¬ NOT d.ticks, "Ticks: On", "Ticks: Off"];
};
IPOut: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
r: Rope.ROPE ¬ Controls.TypescriptReadFileName[d.outerData.typescript];
IF r # NIL THEN Draw2d.IPOut[FileNames.ResolveRelativePath[r], DrawProc, clientData];
};
DrawProc: Controls.DrawProc ~ {
RealFunction: TYPE ~ PROC [v: REAL] RETURNS [REAL];
XToScreen: RealFunction ~ {RETURN[leftMargin+v*xToScreen]};
YToScreen: RealFunction ~ {RETURN[botMargin+v*yToScreen]};
XFromScreen: RealFunction ~ {RETURN[g.xMin+(v-leftMargin)*xFromScreen]};
YFromScreen: RealFunction ~ {RETURN[(v-botMargin)*yFromScreen]};
tick: INTEGER ~ 5;
leftMargin: INTEGER ~ 27;
botMargin: INTEGER ~ 17;
d: Data ~ NARROW[clientData];
g: GraphData ¬ d.graphData;
graphics: ViewerClasses.Viewer ¬ d.outerData.graphics;
xToScreen: REAL ~ (graphics.cw-leftMargin)/(g.xMax-g.xMin);
yToScreen: REAL ~ (graphics.ch-botMargin)*g.scale;
xFromScreen: REAL ~ 1.0/xToScreen;
yFromScreen: REAL ~ 1.0/yToScreen;
IF d.ticks THEN {
Imager.SetFont[context, ImagerFont.Find["xerox/tiogafonts/helvetica7"]];
Imager.MaskRectangle[context, [leftMargin, botMargin, graphics.cw, 1]];
Imager.MaskRectangle[context, [leftMargin, botMargin, 1, graphics.ch]];
FOR n: NAT ¬ botMargin, n+20 WHILE n < graphics.ch DO-- left edge ticks
y: REAL ~ YFromScreen[n];
Imager.MaskRectangle[context, [leftMargin-tick, n, tick, 1]];
Draw2d.Label[context, [3, n], IO.PutFR1["%3.2f", IO.real[y]]];
ENDLOOP;
FOR n: NAT ¬ leftMargin, n+40 WHILE n < graphics.cw DO-- bottom edge ticks
x: REAL ~ XFromScreen[n];
Imager.MaskRectangle[context, [n, botMargin-tick, 1, tick]];
Draw2d.Label[context, [n, 3], IO.PutFR1["%3.2f", IO.real[x]]];
ENDLOOP;
};
IF whatChanged # $IPOut
THEN
FOR i: NAT IN [leftMargin..graphics.cw] DO
y: REAL ~ d.graphProc[XFromScreen[i], g ! UNCAUGHT => LOOP];
! Real.RealException, Real.RealError, FloatingPointCommon.Error => LOOP];
Imager.MaskRectangle[context, [i, YToScreen[y], 1, 1]];
ENDLOOP
ELSE {
y0: REAL ¬ YToScreen[d.graphProc[XFromScreen[leftMargin], g]];
Imager.SetStrokeWidth[context, 2.0];
FOR i: NAT ¬ leftMargin+1, i+3 WHILE i <= graphics.cw DO
y: REAL ~ YToScreen[d.graphProc[XFromScreen[i], g ! UNCAUGHT => LOOP]];
Imager.MaskVector[context, [i, y0], [i+3, y]];
y0 ¬ y;
ENDLOOP;
};
};
Start Code
functions ¬ LIST[
["Bump",    Bump,    "\t\ta second order curve"],
["Gauss",    Gauss,    "\t\tthe normal distribution curve"],
["Poisson",    Poisson,    "\t\tthe poisson curve, with a the scalar"],
["Power",    Power,    "\t\ta power curve, with a the exponent"],
["Sin",     Sin,     "\t\t\ta sin curve raised to the a power"],
["Ln",     Ln,     "\t\t\tnatural logarithm"],
["Log",     Log,     "\t\t\tlogarithm to the base a"],
["Exp",     Exp,     "\t\t\tan exponential function"],
["Perlin",    Perlin,    "\t\tKen's curve, with a the scalar"],
["Wyvill",    Wyvill,    "\t\tWyvill's soft function"],
["SlowInOut",   SlowInOut,   "\tslow in and out curve"],
["Compress",   Compress,   "\t\tlike Gauss"],
["Pavicic",    Pavicic,    "\t\tPavicic's radial weighting filter"],
["PerspZ",   PerspZ,    "\t\ttransformed perspective Z"],
["SquashStretch", SquashStretch,  "squash/stretch ala JB + BW"],
["Ease",    Ease,     "\t\t\tGlassner's slow-in-out, a > 0: slower easing"]
];
END.