(* ;;-*-LISP-*- KEEP EMACS HAPPY ******************************** * * PLOT * ****************************************************************) (* RECORD CURVE (BRUSH COLOR CLOSE KNOTS DASHED) (RECORD BRUSH (BRWIDTH . SHAPE))) (RECORD PLOTINFO (XAXIS YAXIS PATHS CURVES)) (RECORD AXIS (MIN MAX INCREMENT LABEL FONT)) (RECORD TRANSLATE (MU BU MV BV)) (* **************************************************************** * * The simplest way to call PLOT is to pass it a *(function or a path) and a window. * ****************************************************************) (DEFEXPR (PLOT.FN FN XMIN XMAX (OPTIONAL NPOINTS 100) (OPTIONAL WINDOW (CREATEW))) (PROG (YMIN YMAX K X Y PATH XAXIS YAXIS PLOTINFO) (SETQ YMIN MAX.FLOAT) (SETQ YMAX MIN.FLOAT) (FOR I FROM 0 TO NPOINTS DO (SETQ K (/$ I NPOINTS)) (SETQ X (+$ (x$ (-$ 1.0 K) XMIN) (x$ K XMAX))) (SETQ Y (APPLY* FN X)) (SETQ YMIN (MIN YMIN Y)) (SETQ YMAX (MAX YMAX Y)) (PUSH PATH (CREATE POSITION XCOORD ← X YCOORD ← Y))) (SETQ PATH (DREVERSE PATH)) (SETQ XAXIS (CREATE AXIS MIN ← XMIN MAX ← XMAX)) (SETQ YAXIS (CREATE AXIS MIN ← YMIN MAX ← YMAX)) (SETQ PLOTINFO (CREATE PLOTINFO XAXIS ← XAXIS YAXIS ← YAXIS PATHS ← (LIST PATH))) (PLOT PLOTINFO NIL WINDOW) )) (DEFEXPR (PLOT.PATH PATH (OPTIONAL WINDOW (CREATEW))) (PROG (XMIN XMAX YMIN YMAX XAXIS YAXIS PLOTINFO) (SETQ YMIN MAX.FLOAT) (SETQ YMAX MIN.FLOAT) (SETQ XMIN (POSITION.XCOORD (CAR PATH))) (FOR POINT IN PATH DO (SETQ YMIN (MIN (POSITION.YCOORD POINT) YMIN)) (SETQ YMAX (MAX (POSITION.YCOORD POINT) YMAX)) FINALLY (SETQ XMAX (POSITION.XCOORD POINT))) (SETQ XAXIS (CREATE AXIS MIN ← XMIN MAX ← XMAX)) (SETQ YAXIS (CREATE AXIS MIN ← YMIN MAX ← YMAX)) (SETQ PLOTINFO (CREATE PLOTINFO XAXIS ← XAXIS YAXIS ← YAXIS PATHS ← (LIST PATH))) (PLOT PLOTINFO NIL WINDOW) )) (DEFEXPR (PLOT PLOTINFO REGION (OPTIONAL WINDOW (CREATEW))) (PROG (XAXIS YAXIS TRANSLATE) (COND ((NULL REGION) (* Default REGION. *) (SETQ REGION (CREATE REGION LEFT ← 0 BOTTOM ← 0 WIDTH ← (WINDOWPROP WINDOW 'WIDTH) HEIGHT ← (WINDOWPROP WINDOW 'HEIGHT))))) (* Plot PLOTINFO. *) (SETQ XAXIS (PLOTINFO.XAXIS PLOTINFO)) (SETQ YAXIS (PLOTINFO.YAXIS PLOTINFO)) (SETQ TRANSLATE (\PLOT.TRANSLATE XAXIS YAXIS REGION)) (\PLOT.XAXIS XAXIS YAXIS TRANSLATE WINDOW) (\PLOT.YAXIS XAXIS YAXIS TRANSLATE WINDOW) (FOR PATH IN (PLOTINFO.PATHS PLOTINFO) DO (\PLOT.ADDPATH PATH TRANSLATE WINDOW)) (FOR CURVE IN (PLOTINFO.CURVES PLOTINFO) DO (\PLOT.ADDCURVE CURVE TRANSLATE WINDOW)) (* Return TRANSLATE in case user would like to call \PLOT.ADDPATH or \PLOT.ADDCURVE directly. *) (RETURN TRANSLATE) )) (DEFEXPR (\PLOT.XAXIS XAXIS YAXIS TRANSLATE WINDOW) (PROG (XMIN XMAX XINC YMIN YMAX UMIN UMAX VORIGIN UORIGIN U) (SETQ XMAX (AXIS.MAX XAXIS)) (SETQ XMIN (AXIS.MIN XAXIS)) (SETQ YMAX (AXIS.MAX YAXIS)) (SETQ YMIN (AXIS.MIN YAXIS)) (COND ((>$ (x$ YMIN YMAX) 0.0)(RETURN))) (* Coordinates of axis endpoints *) (SETQ UMIN (\PLOT.ROUND (\PLOT.TRANSLATE.XCOORD XMIN TRANSLATE))) (SETQ UMAX (\PLOT.ROUND (\PLOT.TRANSLATE.XCOORD XMAX TRANSLATE))) (SETQ UORIGIN (\PLOT.ROUND (\PLOT.TRANSLATE.XCOORD 0.0 TRANSLATE))) (SETQ VORIGIN (\PLOT.ROUND (\PLOT.TRANSLATE.YCOORD 0.0 TRANSLATE))) (* Extremes *) (\PLOT.TEXT XMAX (AXIS.FONT XAXIS) (CREATE POSITION XCOORD ← UMAX YCOORD ← VORIGIN) 'NNE WINDOW) (\PLOT.TEXT 0 (AXIS.FONT XAXIS) (CREATE POSITION XCOORD ← UORIGIN YCOORD ← VORIGIN) 'NW WINDOW) (\PLOT.TEXT XMIN (AXIS.FONT XAXIS) (CREATE POSITION XCOORD ← UMIN YCOORD ← VORIGIN) 'NNW WINDOW) (* Label .. do this before drawing line to avoid erasing *) (COND ((AXIS.LABEL XAXIS) (\PLOT.TEXT (AXIS.LABEL XAXIS) (AXIS.FONT XAXIS) (CREATE POSITION XCOORD ← UMAX YCOORD ← VORIGIN) 'SSE WINDOW))) (* Solid line *) (DRAWLINE UMIN VORIGIN UMAX VORIGIN NIL NIL WINDOW) (* Tic marks *) (SETQ XINC (AXIS.INCREMENT XAXIS)) (COND ((NULL XINC)(RETURN))) (FOR I FROM (\PLOT.CEILING (/$ XMIN XINC)) TO (\PLOT.FLOOR (/$ XMAX XINC)) DO (SETQ U (\PLOT.TRANSLATE.XCOORD (x$ I XINC) TRANSLATE)) (DRAWLINE U (1- VORIGIN) U (1+ VORIGIN) NIL NIL WINDOW)) )) (DEFEXPR (\PLOT.YAXIS XAXIS YAXIS TRANSLATE WINDOW) (PROG (XMIN XMAX YMIN YMAX YINC MAX VMIN UORIGIN VORIGIN V) (SETQ XMAX (AXIS.MAX XAXIS)) (SETQ XMIN (AXIS.MIN XAXIS)) (SETQ YMAX (AXIS.MAX YAXIS)) (SETQ YMIN (AXIS.MIN YAXIS)) (COND ((>$ (x$ XMIN XMAX) 0.0)(RETURN))) (* Coordinates of axis endpoints *) (SETQ VMIN (\PLOT.ROUND (\PLOT.TRANSLATE.YCOORD YMIN TRANSLATE))) (SETQ VMAX (\PLOT.ROUND (\PLOT.TRANSLATE.YCOORD YMAX TRANSLATE))) (SETQ VORIGIN (\PLOT.ROUND (\PLOT.TRANSLATE.YCOORD 0.0 TRANSLATE))) (SETQ UORIGIN (\PLOT.ROUND (\PLOT.TRANSLATE.XCOORD 0.0 TRANSLATE))) (* Extremes *) (\PLOT.TEXT YMAX (AXIS.FONT YAXIS) (CREATE POSITION XCOORD ← UORIGIN YCOORD ← VMAX) 'ENE WINDOW) (\PLOT.TEXT 0 (AXIS.FONT YAXIS) (CREATE POSITION XCOORD ← UORIGIN YCOORD ← VORIGIN) 'SE WINDOW) (\PLOT.TEXT YMIN (AXIS.FONT YAXIS) (CREATE POSITION XCOORD ← UORIGIN YCOORD ← VMIN) 'ESE WINDOW) (* Label *) (COND ((AXIS.LABEL YAXIS) (\PLOT.TEXT (AXIS.LABEL YAXIS) (AXIS.FONT YAXIS) (CREATE POSITION XCOORD ← UORIGIN YCOORD ← VMAX) 'WNW WINDOW))) (* Solid line *) (DRAWLINE UORIGIN VMIN UORIGIN VMAX NIL NIL WINDOW) (* Tic marks *) (SETQ YINC (AXIS.INCREMENT YAXIS)) (COND ((NULL YINC)(RETURN))) (FOR I FROM (\PLOT.CEILING (/$ YMIN YINC)) TO (\PLOT.FLOOR (/$ YMAX YINC)) DO (SETQ V (\PLOT.TRANSLATE.YCOORD (x$ I YINC) TRANSLATE)) (DRAWLINE (1- UORIGIN) V (1+ UORIGIN) V NIL NIL WINDOW)) )) (DEFEXPR (\PLOT.TEXT TEXT FONT POS (OPTIONAL DIRECTION 'SW) WINDOW) (* DIRECTION = compass direction of point at POS wrt position of TEXT *) (PROG (XCOORD YCOORD WIDTH HEIGHT) (SETQ XCOORD (POSITION.XCOORD POS)) (SETQ YCOORD (POSITION.YCOORD POS)) (SETQ WIDTH (STRINGWIDTH TEXT FONT)) (SETQ HEIGHT (FONTPROP FONT 'HEIGHT)) (SELECTQ DIRECTION ((NW NNW N NNE NE)(SETQ YCOORD (-$ YCOORD (+$ HEIGHT 3.0)))) ((WNW ENE)(SETQ YCOORD (-$ YCOORD HEIGHT))) ((W E)(SETQ YCOORD (-$ YCOORD (/$ HEIGHT 2.0)))) ((WSW ESE)(* Do nothing *)) ((SW SSW S SSE SE)(SETQ YCOORD (+$ YCOORD 3.0))) (SHOULDNT)) (SELECTQ DIRECTION ((NE ENE E ESE SE)(SETQ XCOORD (-$ XCOORD (+$ WIDTH 3.0)))) ((NNE SSE)(SETQ XCOORD (-$ XCOORD WIDTH))) ((N S)(SETQ XCOORD (-$ XCOORD (/$ WIDTH 2.0)))) ((NNW SSW)(* Do nothing *)) ((NW WNW W WSW SW)(SETQ XCOORD (+$ XCOORD 3.0))) (SHOULDNT)) (MOVETO XCOORD YCOORD WINDOW) (DSPFONT FONT WINDOW) (PRIN1 TEXT WINDOW) )) (DEFEXPR (\PLOT.ADDPATH POINTS TRANSLATE WINDOW) (PROG () (SETQ POINTS (\PLOT.TRANSLATE.POINTS POINTS TRANSLATE)) (FOR PT1 IN POINTS AS PT2 IN (CDR POINTS) WHEN PT2 DO (DRAWBETWEEN PT1 PT2 NIL NIL WINDOW)) )) (DEFEXPR (\PLOT.ADDCURVE CURVE TRANSLATE WINDOW) (PROG (POINTS) (SETQ POINTS (\PLOT.TRANSLATE.POINTS (CURVE.KNOTS CURVE) TRANSLATE)) (DRAWCURVE POINTS (CURVE.CLOSE CURVE) (CURVE.BRUSH CURVE) (CURVE.DASHED CURVE) WINDOW) )) (* **************************************************************** * * TRANSLATION * ****************************************************************) (DEFEXPR (\PLOT.TRANSLATE XAXIS YAXIS REGION) (* User = XY system and WINDOW = UV system *) (* U=MU*X+BU and V=MV*Y+BV *) (PROG (XMAX XMIN YMAX YMIN DELTAX DELTAY UMIN VMIN UMAX VMAX MU BU MV BV TRANSLATE) (* XY system. *) (SETQ XMAX (AXIS.MAX XAXIS)) (SETQ XMIN (AXIS.MIN XAXIS)) (SETQ YMAX (AXIS.MAX YAXIS)) (SETQ YMIN (AXIS.MIN YAXIS)) (SETQ DELTAX (-$ XMAX XMIN)) (SETQ DELTAY (-$ YMAX YMIN)) (* UV system. *) (SETQ UMIN (+$ (REGION.LEFT REGION) 0.5)) (SETQ VMIN (+$ (REGION.BOTTOM REGION) 0.5)) (SETQ UMAX (+$ (REGION.RIGHT REGION) 0.5)) (SETQ VMAX (+$ (REGION.TOP REGION) 0.5)) (* Calc TRANSLATE. *) (SETQ MU (/$ (-$ UMAX UMIN) DELTAX)) (SETQ BU (/$ (-$ (x$ XMAX UMIN) (x$ XMIN UMAX)) DELTAX)) (SETQ MV (/$ (-$ VMAX VMIN) DELTAY)) (SETQ BV (/$ (-$ (x$ YMAX VMIN) (x$ YMIN VMAX)) DELTAY)) (SETQ TRANSLATE (CREATE TRANSLATE MU ← MU BU ← BU MV ← MV BV ← BV)) (RETURN TRANSLATE) )) (DEFEXPR (\PLOT.TRANSLATE.POINTS POINTS TRANSLATE) (FOR POINT IN POINTS COLLECT (\PLOT.TRANSLATE.POINT POINT TRANSLATE))) (DEFEXPR (\PLOT.TRANSLATE.POINT POINT TRANSLATE) (CREATE POSITION XCOORD ← (\PLOT.TRANSLATE.XCOORD (POSITION.XCOORD POINT) TRANSLATE) YCOORD ← (\PLOT.TRANSLATE.YCOORD (POSITION.YCOORD POINT) TRANSLATE))) (DEFEXPR (\PLOT.TRANSLATE.XCOORD X TRANSLATE) (+$ (x$ (TRANSLATE.MU TRANSLATE) X) (TRANSLATE.BU TRANSLATE))) (DEFEXPR (\PLOT.TRANSLATE.YCOORD Y TRANSLATE) (+$ (x$ (TRANSLATE.MV TRANSLATE) Y) (TRANSLATE.BV TRANSLATE))) (* **************************************************************** * * ARITHMETIC FUNCTIONS * ****************************************************************) (DEFEXPR (\PLOT.ROUND N) (\PLOT.FLOOR (+$ N 0.5))) (DEFEXPR (\PLOT.FLOOR N) (COND ((OR (=$ N (FIX N))(>=$ N 0.0))(FIX N)) (T (1- (FIX N))))) (DEFEXPR (\PLOT.CEILING N) (- (\PLOT.FLOOR (- N)))) (DEFEXPR (\PLOT.MAX NS) (* Safer than MAX, which can't have more than 80 args *) (PROG (ANSWER) (SETQ ANSWER MIN.FLOAT) (FOR N IN NS WHEN (>$ N ANSWER) DO (SETQ ANSWER N)) (RETURN ANSWER))) (DEFEXPR (\PLOT.MIN NS) (* Safer than MIN, which can't have more than 80 args *) (PROG (ANSWER) (SETQ ANSWER MAX.FLOAT) (FOR N IN NS WHEN (<$ N ANSWER) DO (SETQ ANSWER N)) (RETURN ANSWER))) STOP