import java.awt.*; /** * * An abstract canvas object which serves the purpose of insulating the * mathematical part of the program (Panorama object below) from the * graphics (DrawPanel object above). The Panorama object does its * drawing by making calls to the KaliCanvas object, which in turn * translates them into the appropriate graphics calls for drawing on * the DrawPanel object. * *

* * (It might be more efficient to have the Panorama object make the * graphics calls directly, but for now we try it this way.) * *

* * Coordinate systems: * *

* * Kali uses 3 different coordinate systems for the image in the DrawPanel: * *

*
Raw Screen Coordinates *
This is the original screen coordinate system of the * drawing area, which goes from (0,0) in the upper left to * (screenWidth, screenHeight) in the lower right (in * pixels). Y increases DOWN in this system. *

* Mouse events happen in this coordinate system. *

* *

Screen Coordinates *
This system is the result of translating the raw screen * system so that (0,0) is at the center of the screen; so it * goes from (-screenWidth/2, -screenHeight/2) in the upper * left to (screenWidth/2, screenHeight/2) in the lower * right. Y increases DOWN in this system too. *

* Drawing happens in this coordinate system; the * KaliCanvas.setGraphics() method calls g.translate() to * move the Graphics object's origin from the upper left (the * default) to the center of the screen. Also, the * translation computations in the Panorama object happen in * this system. *

* *

Internal Coordinates *
This system goes from (-internalWidth, internalHeight) in * the upper left to (internalWidth, -internalHeight) in the * lower right; so (0,0) is at the center of the screen. Y * increases UP in this system. *

* The coordinates of drawn segments are stored in this * system. Also, the Panorama object does some of the group * action math (reflection and rotation) in this system. *

* Also, in the future, scaling and translation may be * implemented by transforming this system. *

*

* * * @see Panorama * @see DrawPanel */ class KaliCanvas { /** * screenWidth and screenHeight record the size, in pixels, of the * current screen. We initialize these to reasonable values here so * that we can do the initial updateCoordinateSystems() call without * risk of division by zero; they get set to actual screen values * before any actual drawing is done, by the call to setGraphics(). */ int screenWidth=500, screenHeight=500; /** * internalWidth and internalHeight record the dimensions of of * internal coordinate system (-internalWidth,-internalHeight) to * (+internalWidth,+internalHeight). In the current version these * numbers are fixed, but future versions might allow for scaling * and/or translations by modifying these values. */ double internalWidth=-2.5, internalHeight=2.5; /** * position and positionInverse are used for converting * between the internal and screen coordinate systems: * position * internal = screen; * positionInverse * screen = internal */ DMatrix position, positionInverse; /** * screenLeft,screenRight,screenBottom, and screenTop hold the * bounds of the screen coordinate system */ int screenLeft = -250; int screenRight = 250; int screenBottom = -250; int screenTop = 250; /** * The graphics context that we use for actual drawing. */ Graphics g; public KaliCanvas() { super(); updateCoordinateSystems(); } /** * Causes the KaliCanvas object to do the internal updating that * is necessary after a new coordinate system has been set. */ private void updateCoordinateSystems() { double xfactor = 2 * internalWidth / screenWidth; double yfactor = -2 * internalHeight / screenHeight; positionInverse = new DMatrix(xfactor, 0, 0, yfactor); position = positionInverse.inverse(); } /** * Convert raw screen coordinates to internal coordinates. */ public DVector rawScreenToInternal(int x, int y) { return positionInverse.times(new DVector(x - screenWidth/2, y - screenHeight/2)); } /** * Convert internal coordinates to screen coordinates. */ public DVector internalToScreen(DVector v) { return position.times(v); } /** * Set the graphics context for future drawing; this results in * a new screen coordinate system being computed based on the * current size of this graphics context. */ public void setGraphics(Graphics g, int w, int h) { this.g = g; Rectangle area = g.getClipRect(); screenWidth = w; screenHeight = h; updateCoordinateSystems(); screenLeft = -screenWidth/2; screenRight = screenWidth/2; screenBottom = -screenHeight/2; screenTop = screenHeight/2; g.translate(screenWidth/2, screenHeight/2); } /** * Draw a single line segment. */ public void drawSegment(Segment s, Color c) { g.setColor(c); g.drawLine((int)(s.p[0].c[0]+0.5), (int)(s.p[0].c[1]+0.5), (int)(s.p[1].c[0]+0.5), (int)(s.p[1].c[1]+0.5)); } }