/* CartesianSystem.doc declares class CartesianSystem, * a class for graphical display using the * Carnegie-Mellon University Graphics library. * * Copyright Joel Adams, July 2001, All rights reserved. * * Note: many methods have an int parameter to define the drawing color, * and the valid colors are defined in CMUgraphics' file 127Graphics.h: * RED, GREEN, BLUE, YELLOW, PINK, PURPLE, BROWN, AQUA, * WHITE, BLACK, DKGREY, LTBLUE, ALMOND, LTGREY, TAN, DKGREEN */ #ifndef CARTESIAN_SYSTEM #define CARTESIAN_SYSTEM #include "Graphics.h" #include "127Graphics.h" #include <iomanip> #include <cassert> using namespace std; // CMU Graphics library headers // window + ops // Colors // setprecision() // assert() const int AXIS_MARGIN = 16, window edge AXIS_GAP = 50, DEFAULT_PRECISION = 3; // pixels btwn axis endpoints and typedef double FunctionOfX(double); drawFunction() draws // the kind of function // pixels between axis hash-marks // #decimal digits on axis labels class CartesianSystem : public window { public: /* default constructor * receive: axisVisible, a bool value. * POST: a CartesianSystem has been constructed and displayed, * with its axis showing if and only if axisVisible == true. */ CartesianSystem(bool axisVisible = true); /* explicit-value constructor * receive: minX, minY, maxX, maxY, all doubles; * axisVisible, a bool value. * PRE: minX < maxX && minY < maxY. * POST: a CartesianSystem has been constructed and displayed, * with lower-left corner (minX, minY), * with upper-right corner (maxX, maxY), and * with its axis showing if and only if axisVisible == true. */ CartesianSystem(double minX, double minY, double maxX, double maxY, bool axisVisible = true); /* clear the screen * receive: bgColor, the new background color; * axisVisible, a bool. * POST: the screen has been cleared; * and the axis redrawn if and only if axisVisible == true. */ void clear(int bgColor = WHITE, bool axisVisible = true); /* utility for drawing the axis * receive: axisColor, an int; * penSize, an int. * POST: The CartesianSystem's axis has been drawn using axisColor. */ void drawAxis(int axisColor = BLACK, int penSize = 1); /* drawing pen-width * receive: width, a * POST: the drawing */ void setPenWidth(int mutator positive int pen-width has been set to width. width); /* drawing font mutator * receive: size, style, and family, all ints; * PRE: size is a valid point-size * && style is one of: * {0 = plain, 1 = bold, 2 = italic, 4 = underline, 8 = outline, * 9 = shadow} (these can be added to achieve cumulative effects) * && family is a defined font family, e.g.: * {0 = chicago, 1 = applfont, 2 = newYork, 3 = geneva, 4 = monaco, * 5 = venice, 6 = london, 7 = athens, 8 = sanFran, 9 = toronto, * 11 = cairo, 12 = losAngeles, 20 = times, 21 = helvetica, * 22 = courier, 23 = symbol, 24 = mobile}. * POST: the drawing font's point-size == size && * its style == style && its family == family. */ void setFont(int size, int style, int family); /* draw a line * receive x0, y0, x1, y1, all doubles defining 2 CartesianSystem coordinates; * aColor, a color from 127Graphics.h in CMUgraphics. * POST: a line colored aColor has been drawn from (x0, y0) to (x1, y1). * To draw using a window coordinate, use window::DrawLine() in CMU Graphics.h */ void drawLine(double x0, double y0, double x1, double y1, int aColor = BLACK); /* make a pixel with a given color * receive x, y, doubles defining a CartesianSystem coordinate; * aColor, the color it is to be. * POST: a pixel colored aColor has been drawn at (x, y). * To color a pixel using a window coordinate, use window::DrawPixel() in * CMU Graphics.h */ void drawPixel(double x, double y, int aColor = BLACK); /* draw a rectangle with a given color * receive x0, y0, x1, y1, all doubles defining 2 CartesianSystem coordinates; * aColor, the color the rectangle is to be; * dsStyle, the style of the circle: {NONE, FILLED, FRAME, INVERTED}; * and iWidth and iHeight, two ints that define the rounded-ness of * corners. * POST: a rectangle colored aColor has been drawn from (x0, y0) to (x1, y1); * with style as specified by dsStyle, iWidth, and iHeight. * To draw a rectangle using a window coordinate, use window::DrawRectangle() * in CMU Graphics.h */ void drawRectangle(double x0, double y0, double x1, double y1, int color = BLACK, drawstyle dsStyle = FILLED, int iWidth = 0, int iHeight = 0); /* draw a circle with a given color * receive x, y, doubles defining a CartesianSystem coordinate; * itsRadius, a double defining a length in the CartesianSystem space; * aColor, the color the circle is to be; and * dsStyle, the style of the circle: {NONE, FILLED, FRAME, INVERTED}. * POST: a circle colored aColor has been drawn at (x, y) with radius * itsRadius, and styled as specified by dsStyle. * To draw a circle using a window coordinate, use window::DrawCircle() in * CMU Graphics.h */ void drawCircle(double x, double y, double itsRadius, int color = BLACK, drawstyle dsStyle = FILLED); /* draw an ellipse with a given color * receive x0, y0, x1, y1, all doubles defining 2 CartesianSystem coordinates; * aColor, the color the ellipse is to be; * dsStyle, the style of the ellipse: {NONE, FILLED, FRAME, INVERTED}. * POST: an ellipse colored aColor has been drawn in the box defined * by (x0, y0) to (x1, y1); with style as specified by dsStyle. * To draw an ellipse using a window coordinate, use window::DrawEllipse() in * CMU Graphics.h */ void drawEllipse(double x0, double y0, double x1, double y1, int aColor = BLACK, drawstyle dsStyle = FILLED); /* draw an arc with a given color * receive x, y, doubles defining a CartesianSystem coordinate; * itsRadius, a double defining a length in the CartesianSystem space; * startAtDegrees, an int defining the angle at which drawing starts * (e.g., 0 == 12-o'clock; 90 == 3 o'clock, 180 == 6 o'clock, ...); * arcDegrees, an int defining the number of degrees the arc should * * span; * aColor, the color the arc is to be; and * dsStyle, the style of the arc: {NONE, FILLED, FRAME, INVERTED}. * POST: an arc colored aColor has been drawn at (x, y) with radius itsRadius * and starting at angle startAtDegrees, encompassing arcDegrees; * and styled as specified by dsStyle. * To draw an arc using a window coordinate, use window::DrawArc() in * CMU Graphics.h */ void drawArc(double x, double y, double itsRadius, int startAtDegrees, int arcDegrees, int aColor = BLACK, drawstyle dsStyle = FRAME); /* draw a string with a given color * receive x, y, doubles defining a CartesianSystem coordinate; * aString, the string to be displayed; and * aColor, the color the circle is to be. * POST: aString has been drawn at (x, y) colored aColor, * To draw a string using a window coordinate, use window::DrawString() in CMU * Graphics.h */ void drawString(double x, double y, const string& aString, int aColor = BLACK); /* draw a number with a given color * receive x, y, doubles defining a CartesianSystem coordinate; * aNumber, the number to be displayed; and * aColor, the color the number is to be. * POST: aNumber has been drawn at (x, y) colored aColor, * To draw an integer using a window coordinate, use window::DrawInteger() in * CMU Graphics.h */ void drawNumber(double x, double y, double aNumber, int color = BLACK); /* draw a function's graph * receive: aFunction, a function mapping x -> y && * aColor, the color the function is to be. * POST: aFunction has been deen graphed colored aColor. */ void drawFunction(FunctionOfX aFunction, int color = BLACK); /* block until the mouse-button is pressed. * POST: The user has clicked the mouse */ void waitForMouseClick(); /* block until the mouse-button is pressed; return its coordinates. * receive x, y, double variables; * column, row int variables. * POST: The user has clicked the mouse && * its CartesianSystem coordinates are in (x, y) && * its window coordinates are in (column, row) * To just get the window coordinate, use window::WaitMouseClick() in CMU * Graphics.h */ void waitForMouseClick(double& x, double& y, int& column, int& row); /* return the current coordinates of the mouse. * receive x, y, double variables; * column, row int variables. * POST: the mouse's CartesianSystem coordinates are in (x, y) && * its window coordinates are in (column, row) * To just get the window coordinates, use window::GetMouseCoord() in CMU * Graphics.h */ void getMousePosition(double& x, double& y, int& column, int& row); /* return the key the user pressed (without blocking) * receive: aKey, a char variable. * POST: The user pressed a key and aKey == that key. * This method just calls window::GetKeyPress() from CMU Graphics.h */ void getKeyPress(char& aKey); // minimum and maximum x- and y-value accessors; // these retrieve the end-points of the axis. double minX() const; double minY() const; double maxX() const; double maxY() const; /* the amount x changes when we move 1 pixel * return: the number of x values corresponding to 1 column. */ double deltaX() const; /* the amount y changes when we move 1 pixel * return: the number of y values corresponding to 1 row. */ double deltaY() const; /* map a CartesianSystem x-value into a window column value * receive: x, a CartesianSystem x-value. * return: the window column-value corresponding to x. */ int xToColumn(double x) const; /* map a CartesianSystem y-value into a window row value * receive: y, a CartesianSystem y-value. * return: the window row-value corresponding to y. */ int yToRow(double y) const; /* map a window column value into a CartesianSystem x-value * receive: column, a window column number. * return: the CartesianSystem x-value corresponding to column. */ double columnToX(int column) const; /* map a window row value into a CartesianSystem y-value * receive: row, a window row number. * return: the CartesianSystem y-value corresponding to row. */ double rowToY(int row) const; /* map a CartesianSystem distance into a window distance * receive: distance, a length in CartesianSystem units * return: the equivalent distance in raw pixels. */ int distanceToPixels(double distance) const; /* get the window width in pixels * return: the number of columns in the window. */ int getWidthInPixels(); /* get the window height in pixels * return: the number of rows in the window. */ int getHeightInPixels(); private: /* utility method used by constructors * receive: minX, minY, maxX, maxY, all doubles defining the CartesianSystem; * and axisVisible, a bool indicating whether the axis is to be drawn. * POST: minX, minY, maxX, maxY have been stored in xMin, yMin, xMax, yMax, and * the axis has been drawn if and only if axisVisible == true. */ void initialize(double minX, double minY, double maxX, double maxY, bool axisVisible); /* utility to initialize attributes dependent on the window size * PRE: the width and height of the window are set * POST: all window size-dependent instance variables have been set */ void setSizeDependentAttributes(); double xMin, yMin, xMax, yMax, myColumnsPerX, myRowsPerY, xInterval, yInterval, myXRange, myYRange; int myRows, myColumns, myLastRow, myDecimalDigits; bool myAxisVisible; (false)? }; // // // // // // // // // our lower-left corner our upper-right corner mapping variables distance btwn axis hash-marks range of each dimension # of USEABLE rows, columns index of last row precision for axis labels draw axis (true) or not inline CartesianSystem::CartesianSystem(bool axisVisible) { initialize(-4.0, -2.0, 4.0, 2.0, axisVisible); // some default settings } inline CartesianSystem::CartesianSystem(double minX, double minY, double maxX, double maxY, bool axisVisible) { initialize(minX, minY, maxX, maxY, axisVisible); } inline void CartesianSystem::setPenWidth(int width) { assert(width > 0); SetPen(width); } inline void CartesianSystem::setFont(int size, int style, int family) { SetFont(size, style, family); } inline void CartesianSystem::drawLine(double x0, double y0, double x1, double y1, int aColor) { SetBrush(aColor); DrawLine(xToColumn(x0), yToRow(y0), xToColumn(x1), yToRow(y1)); } inline void CartesianSystem::drawPixel(double x, double y, int aColor) { SetBrush(aColor); DrawPixel(xToColumn(x), yToRow(y)); } inline void CartesianSystem::drawRectangle(double x0, double y0, double x1, double y1, int aColor, drawstyle dsStyle, int iWidth, int iHeight) { SetBrush(aColor); DrawRectangle(xToColumn(x0), yToRow(y0), xToColumn(x1), yToRow(y1), dsStyle, iWidth, iHeight); } inline int CartesianSystem::distanceToPixels(double distance) const { return int(distance * abs(xToColumn(1) - xToColumn(0))); // an ugly hack } inline void CartesianSystem::drawCircle(double x, double y, double radius, int aColor, drawstyle dsStyle) { SetBrush(aColor); DrawCircle(xToColumn(x), yToRow(y), distanceToPixels(radius), dsStyle); } inline void CartesianSystem::drawEllipse(double x0, double y0, double x1, double y1, int aColor, drawstyle dsStyle) { SetBrush(aColor); DrawEllipse(xToColumn(x0), yToRow(y0), xToColumn(x1), yToRow(y1), dsStyle); } inline void CartesianSystem::drawString(double x, double y, const string& aString, int aColor) { SetBrush(aColor); DrawString(xToColumn(x), yToRow(y), aString.data()); } inline void CartesianSystem::drawArc(double x, double y, double radius, int startAtDegrees, int arcDegrees, int aColor, drawstyle dsStyle) { SetBrush(aColor); DrawArc(xToColumn(x), yToRow(y), distanceToPixels(radius), startAtDegrees, arcDegrees, dsStyle); } inline int CartesianSystem::getWidthInPixels() { return GetWidth(); } inline int CartesianSystem::getHeightInPixels() { return GetHeight(); } inline void CartesianSystem::waitForMouseClick() { int column, row; WaitMouseClick(column, row); } inline void CartesianSystem::waitForMouseClick(double& x, double& y, int& column, int& row) { WaitMouseClick(column, row); x = columnToX(column); y = rowToY(row); } inline void CartesianSystem::getMousePosition(double& x, double& y, int& column, int& row) { GetMouseCoord(column, row); x = columnToX(column); y = rowToY(row); } inline void CartesianSystem::getKeyPress(char& key) { GetKeyPress(key); } inline int CartesianSystem::xToColumn(double x) const { return AXIS_MARGIN + std::round((x-xMin) * myColumns / myXRange); } inline int CartesianSystem::yToRow(double y) const { return AXIS_MARGIN + myLastRow - std::round((y - yMin) * myRows / myYRange); } inline double CartesianSystem::columnToX(int column) const { return xMin + (column - AXIS_MARGIN) * myXRange / myColumns; } inline double CartesianSystem::rowToY(int row) const { return yMin - (row - AXIS_MARGIN - myLastRow) * myYRange / myRows; } inline double CartesianSystem::deltaX() const { return myXRange / myColumns; } inline double CartesianSystem::deltaY() const { return myYRange / myRows; } inline double CartesianSystem::minX() const { return xMin; } inline double CartesianSystem::minY() const { return yMin; } inline double CartesianSystem::maxX() const { return xMax; } inline double CartesianSystem::maxY() const { return yMax; } #endif