/* * GRAPH, Version 1.00 - 4 August 1989 * * Copyright 1989, David Gay. All Rights Reserved. * This software is freely redistrubatable. */ /* Set up a coordinate system in a Rastport */ /* Copyright 1989, David Gay */ #include #include #include #include #include #include #include #include "coords.h" #include "tracker.h" extern int _FPERR; /* Actual structure used */ struct RWin { struct RWindow rw; double xmin, xscale, ymin, yscale; double xoffset, yoffset; struct Region *clip, *oldRegion; int lostpos; }; /*-------------------------------------------------------------------------*/ /* RWindow definition */ /*-------------------------------------------------------------------------*/ /* convert double to integer, round down. cf floor */ long ftol(double x) { if (x >= 0) return (long)x; else return (long)floor(x); } /* Do Move/Draw style operation func, checking for overflow, etc */ static void rdo_RWin(struct RWin *this, void (*func)(struct RastPort *rp, long sx, long sy), double x, double y) { double sx, sy; if (this->lostpos) func = Move; _FPERR = 0; sx = this->rw.sx((struct RWindow *)this, x); sy = this->rw.sy((struct RWIndow *)this, y); /* Move, Draw only accept shorts */ this->lostpos = (_FPERR != 0 || fabs(sx) > SHRT_MAX || fabs(sy) > SHRT_MAX) ; if (!this->lostpos) func(this->rw.rp, ftol(sx), ftol(sy)); } /* The various conversion routines, to/from ints, for lin orr log scales, x or y ax */ static double sx_lin(struct RWin *this, double x) { return (x - this->xmin) * this->xscale + this->xoffset; } static double sx_log(struct RWin *this, double x) { return (log10(x) - this->xmin) * this->xscale + this->xoffset; } static double sy_lin(struct RWin *this, double y) { return (y - this->ymin) * this->yscale + this->yoffset; } static double sy_log(struct RWin *this, double y) { return (log10(y) - this->ymin) * this->yscale + this->yoffset; } static double x_lin(struct RWin *this, long sx) { return (sx - this->xoffset) / this->xscale + this->xmin; } static double x_log(struct RWin *this, long sx) { return pow(10.0, (sx - this->xoffset) / this->xscale + this->xmin); } static double y_lin(struct RWin *this, long sy) { return (sy - this->yoffset) / this->yscale + this->ymin; } static double y_log(struct RWin *this, long sy) { return pow(10.0, (sy - this->yoffset) / this->yscale + this->ymin); } /* Delete a member of this class */ static void delete_RWin(struct RWin *this) { if (this->clip) { InstallClipRegion(this->rw.rp->Layer, this->oldRegion); DisposeRegion(this->clip); } FreeMem(this, sizeof(struct RWin)); } /* Create a coordinate system in Rastport rp (w by h pixels), {...}offset : offset in rp at which coords starts (normally > 0) {x,y}{min,max} : limits for coords logx, logy : logarithmic scale ? clip : setup clipping to {...}offset boundaries ? */ struct RWindow *new_RWindow(struct RastPort *rp, long w, long h, long leftoffset, long bottomoffset, long rightoffse t, long topoffset, double xmin, double ymin, double xmax, double ymax, long logx, long logy, long clip) { long width, height; struct Rectangle rect; struct Region *r; struct RWin *this = AllocMem(sizeof(struct RWin), 0L); if (this) { /* Setup class methods, and private data */ this->rw.delete = (void *)delete_RWin; this->rw.rdo = (void *)rdo_RWin; /* Setup scaling */ this->rw.rp = rp; this->xoffset = leftoffset; this->yoffset = h - bottomoffset - 1; width = w - leftoffset - rightoffset - 1; height = h - bottomoffset - topoffset - 1; if (logx) { this->xmin = log10(xmin); this->xscale = width / (log10(xmax) - this->xmin); this->rw.sx = (void *)sx_log; this->rw.x = (void *)x_log; } else { this->xmin = xmin; this->xscale = width / (xmax - this->xmin); this->rw.sx = (void *)sx_lin; this->rw.x = (void *)x_lin; } if (logy) { this->ymin = log10(ymin); this->yscale = height / (this->ymin - log10(ymax)); this->rw.sy = (void *)sy_log; this->rw.y = (void *)y_log; } else { this->ymin = ymin; this->yscale = height / (this->ymin - ymax); this->rw.sy = (void *)sy_lin; this->rw.y = (void *)y_lin; } if (clip) { /* Setup clipping */ if (r = NewRegion()) { rect.MinX = leftoffset; rect.MaxX = w - rightoffset - 1; rect.MinY = topoffset; rect.MaxY = h - bottomoffset - 1; if (OrRectRegion(r, &rect)) { this->clip = r; /* Remark: Due to a bug(?) in InstallClipRegion, make sure that the currently installed region when EndRefresh is called is not NULL (trashed windows otherwise...). */ this->oldRegion = InstallClipRegion(rp->Layer, r); } else { DisposeRegion(r); r = NULL; } } if (!r) { FreeMem(this, sizeof(struct RWin)); this = NULL; } } else this->clip = NULL; } /* Return the newly allocated instance */ return (struct RWindow *)this; }