diff --git a/Body.class b/Body.class
new file mode 100644
index 0000000..2ef4398
Binary files /dev/null and b/Body.class differ
diff --git a/Body.java b/Body.java
new file mode 100644
index 0000000..a56d01f
--- /dev/null
+++ b/Body.java
@@ -0,0 +1,152 @@
+public class Body {
+
+ public static final double G = 6.673e-11;
+ private double mass;
+ private double px;
+ private double py;
+ private double vx;
+ private double vy;
+ private double fx;
+ private double fy;
+
+ public Body(double mass, double px, double py, double vx, double vy){
+ this.px = px;
+ this.py = py;
+ this.vx = vx;
+ this.vy = vy;
+ this.mass = mass;
+ }
+
+
+ @Override
+ public String toString() {
+ return "";
+ }
+
+ public double getDistance(Body otherBody){
+
+ double x1 = this.getXpos();
+ double x2 = otherBody.getXpos();
+ double y1 = this.getYpos();
+ double y2 = otherBody.getYpos();
+
+
+ double distance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
+
+
+ return distance;
+ }
+
+ public double getSpeed(){
+
+ return Math.sqrt((this.getXvelo() * this.getXvelo()) + (this.getYvelo() * this.getYvelo()));
+ }
+
+ public double getForceScalar(Body otherBody){
+
+ double distance = this.getDistance(otherBody);
+ double m1 = this.getMass();
+ double m2 = otherBody.getMass();
+
+ double force = G * ((m1 * m2) / distance);
+
+ return force;
+ }
+
+ public double getXforce(Body otherBody){
+
+ double distance = otherBody.getXpos() - this.getXpos();
+ double m1 = this.getMass();
+ double m2 = otherBody.getMass();
+
+ double force = G * ((m1 * m2) / distance);
+
+ return force;
+
+
+ }
+
+ public double getYforce(Body otherBody){
+
+ double distance = otherBody.getYpos() - this.getYpos();
+ double m1 = this.getMass();
+ double m2 = otherBody.getMass();
+
+ double force = G * ((m1 * m2) / distance);
+
+ return force;
+ }
+
+ public void calcNetForce(Body[] bodies){
+ double netXForce = 0;
+ double netYForce = 0;
+ for(int i = 0; i < bodies.length; i ++){
+ if(this != bodies[i]){
+ netXForce = netXForce + this.getXforce(bodies[i]);
+ netYForce = netYForce + this.getYforce(bodies[i]);
+ }
+ }
+
+ this.fx = netXForce;
+ this.fy = netYForce;
+ }
+
+ public void updateVelocity(){
+ // TODO: Implament updateVelocity
+ }
+
+ public double getXpos(){
+ return this.px;
+ }
+
+ public double getYpos(){
+ return this.py;
+ }
+
+ public double getXvelo(){
+ return this.vx;
+ }
+
+ public double getYvelo(){
+ return this.vy;
+ }
+
+ public double getMass(){
+ return this.mass;
+ }
+
+ public double getNetXforce(){
+ return this.fx;
+ }
+
+ public double getNetYforce(){
+ return this.fy;
+ }
+
+ public static void main(String[] args){
+
+ // Body testBody = new Body(15000, 0, 0, 10, 10);
+ // Body testBody2 = new Body(27000, 2, 1, 10, 10);
+ // Body testBody3 = new Body(29530, 4, 2, 10, 10);
+ // Body testBody4 = new Body(29530000, -4, 4, 10, 10);
+ // Body[] bodies = new Body[4];
+ // bodies[0] = testBody;
+ // bodies[1] = testBody2;
+ // bodies[2] = testBody3;
+ // bodies[3] = testBody4;
+
+ // System.out.println(testBody.getSpeed());
+ // System.out.println(testBody.getDistance(testBody2));
+ // System.out.println(testBody.getXforce(testBody2));
+ // System.out.println(testBody.getYforce(testBody2));
+
+ // testBody.calcNetForce(bodies);
+ // System.out.println(testBody.fx);
+ // System.out.println(testBody.fy);
+
+
+
+
+ }
+
+}
diff --git a/Space.class b/Space.class
new file mode 100644
index 0000000..163a248
Binary files /dev/null and b/Space.class differ
diff --git a/Space.java b/Space.java
new file mode 100644
index 0000000..2271346
--- /dev/null
+++ b/Space.java
@@ -0,0 +1,50 @@
+public class Space {
+
+ Body[] bodies;
+ double height;
+ double width;
+
+ public Space(Body[] bodies, double height, double width){
+
+ this.bodies = bodies;
+ this.height = height;
+ this.width = width;
+ }
+
+ public void calculateForces(){
+
+ //double runningTotal = 0;
+ for(int i = 0; i < this.bodies.length; i ++){
+ this.bodies[i].calcNetForce(this.bodies);
+ }
+ }
+
+ public static void main(String args[]){
+
+ Body testBody = new Body(15000, 0, 0, 10, 10);
+ Body testBody2 = new Body(27000, 2, 1, 10, 10);
+ Body testBody3 = new Body(29530, 4, 2, 10, 10);
+ Body testBody4 = new Body(29530000, -4, 4, 10, 10);
+ Body[] bodies = new Body[4];
+ bodies[0] = testBody;
+ bodies[1] = testBody2;
+ bodies[2] = testBody3;
+ bodies[3] = testBody4;
+
+ Space space = new Space(bodies, 500, 500);
+ space.calculateForces();
+
+ System.out.println(space.bodies[0].getNetXforce());
+ System.out.println(space.bodies[0].getNetYforce());
+
+ System.out.println(space.bodies[1].getNetXforce());
+ System.out.println(space.bodies[1].getNetYforce());
+
+ System.out.println(space.bodies[2].getNetXforce());
+ System.out.println(space.bodies[2].getNetYforce());
+
+ System.out.println(space.bodies[3].getNetXforce());
+ System.out.println(space.bodies[3].getNetYforce());
+
+ }
+}
diff --git a/StdDraw.class b/StdDraw.class
new file mode 100644
index 0000000..ef0fcc4
Binary files /dev/null and b/StdDraw.class differ
diff --git a/StdDraw.java b/StdDraw.java
new file mode 100644
index 0000000..dd93791
--- /dev/null
+++ b/StdDraw.java
@@ -0,0 +1,1118 @@
+/*************************************************************************
+ * Compilation: javac StdDraw.java
+ * Execution: java StdDraw
+ *
+ * Standard drawing library. This class provides a basic capability for
+ * creating drawings with your programs. It uses a simple graphics model that
+ * allows you to create drawings consisting of points, lines, and curves
+ * in a window on your computer and to save the drawings to a file.
+ *
+ * Todo
+ * ----
+ * - Add support for gradient fill, etc.
+ *
+ * Remarks
+ * -------
+ * - don't use AffineTransform for rescaling since it inverts
+ * images and strings
+ * - careful using setFont in inner loop within an animation -
+ * it can cause flicker
+ *
+ *************************************************************************/
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.io.*;
+import java.net.*;
+import java.util.LinkedList;
+import java.util.TreeSet;
+import javax.imageio.ImageIO;
+import javax.swing.*;
+
+/**
+ * Standard draw. This class provides a basic capability for
+ * creating drawings with your programs. It uses a simple graphics model that
+ * allows you to create drawings consisting of points, lines, and curves
+ * in a window on your computer and to save the drawings to a file.
+ *
+ * For additional documentation, see Section 1.5 of
+ * Introduction to Programming in Java: An Interdisciplinary Approach by Robert Sedgewick and Kevin Wayne.
+ *
+ * @author Robert Sedgewick
+ * @author Kevin Wayne
+ */
+public final class StdDraw implements ActionListener, MouseListener, MouseMotionListener, KeyListener {
+
+ // pre-defined colors
+ public static final Color BLACK = Color.BLACK;
+ public static final Color BLUE = Color.BLUE;
+ public static final Color CYAN = Color.CYAN;
+ public static final Color DARK_GRAY = Color.DARK_GRAY;
+ public static final Color GRAY = Color.GRAY;
+ public static final Color GREEN = Color.GREEN;
+ public static final Color LIGHT_GRAY = Color.LIGHT_GRAY;
+ public static final Color MAGENTA = Color.MAGENTA;
+ public static final Color ORANGE = Color.ORANGE;
+ public static final Color PINK = Color.PINK;
+ public static final Color RED = Color.RED;
+ public static final Color WHITE = Color.WHITE;
+ public static final Color YELLOW = Color.YELLOW;
+
+ /**
+ * Shade of blue used in Introduction to Programming in Java.
+ * It is Pantone 300U. The RGB values are approximately (9, 90, 166).
+ */
+ public static final Color BOOK_BLUE = new Color( 9, 90, 166);
+ public static final Color BOOK_LIGHT_BLUE = new Color(103, 198, 243);
+
+ /**
+ * Shade of red used in Algorithms 4th edition.
+ * It is Pantone 1805U. The RGB values are approximately (150, 35, 31).
+ */
+ public static final Color BOOK_RED = new Color(150, 35, 31);
+
+ // default colors
+ private static final Color DEFAULT_PEN_COLOR = BLACK;
+ private static final Color DEFAULT_CLEAR_COLOR = WHITE;
+
+ // current pen color
+ private static Color penColor;
+
+ // default canvas size is DEFAULT_SIZE-by-DEFAULT_SIZE
+ private static final int DEFAULT_SIZE = 512;
+ private static int width = DEFAULT_SIZE;
+ private static int height = DEFAULT_SIZE;
+
+ // default pen radius
+ private static final double DEFAULT_PEN_RADIUS = 0.002;
+
+ // current pen radius
+ private static double penRadius;
+
+ // show we draw immediately or wait until next show?
+ private static boolean defer = false;
+
+ // boundary of drawing canvas, 5% border
+ private static final double BORDER = 0.05;
+ private static final double DEFAULT_XMIN = 0.0;
+ private static final double DEFAULT_XMAX = 1.0;
+ private static final double DEFAULT_YMIN = 0.0;
+ private static final double DEFAULT_YMAX = 1.0;
+ private static double xmin, ymin, xmax, ymax;
+
+ // for synchronization
+ private static Object mouseLock = new Object();
+ private static Object keyLock = new Object();
+
+ // default font
+ private static final Font DEFAULT_FONT = new Font("SansSerif", Font.PLAIN, 16);
+
+ // current font
+ private static Font font;
+
+ // double buffered graphics
+ private static BufferedImage offscreenImage, onscreenImage;
+ private static Graphics2D offscreen, onscreen;
+
+ // singleton for callbacks: avoids generation of extra .class files
+ private static StdDraw std = new StdDraw();
+
+ // the frame for drawing to the screen
+ private static JFrame frame;
+
+ // mouse state
+ private static boolean mousePressed = false;
+ private static double mouseX = 0;
+ private static double mouseY = 0;
+
+ // queue of typed key characters
+ private static LinkedList keysTyped = new LinkedList();
+
+ // set of key codes currently pressed down
+ private static TreeSet keysDown = new TreeSet();
+
+
+ // singleton pattern: client can't instantiate
+ private StdDraw() { }
+
+
+ // static initializer
+ static { init(); }
+
+ /**
+ * Set the window size to the default size 512-by-512 pixels.
+ */
+ public static void setCanvasSize() {
+ setCanvasSize(DEFAULT_SIZE, DEFAULT_SIZE);
+ }
+
+ /**
+ * Set the window size to w-by-h pixels.
+ *
+ * @param w the width as a number of pixels
+ * @param h the height as a number of pixels
+ * @throws a IllegalArgumentException if the width or height is 0 or negative
+ */
+ public static void setCanvasSize(int w, int h) {
+ if (w < 1 || h < 1) throw new IllegalArgumentException("width and height must be positive");
+ width = w;
+ height = h;
+ init();
+ }
+
+ // init
+ private static void init() {
+ if (frame != null) frame.setVisible(false);
+ frame = new JFrame();
+ offscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ onscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ offscreen = offscreenImage.createGraphics();
+ onscreen = onscreenImage.createGraphics();
+ setXscale();
+ setYscale();
+ offscreen.setColor(DEFAULT_CLEAR_COLOR);
+ offscreen.fillRect(0, 0, width, height);
+ setPenColor();
+ setPenRadius();
+ setFont();
+ clear();
+
+ // add antialiasing
+ RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ offscreen.addRenderingHints(hints);
+
+ // frame stuff
+ ImageIcon icon = new ImageIcon(onscreenImage);
+ JLabel draw = new JLabel(icon);
+
+ draw.addMouseListener(std);
+ draw.addMouseMotionListener(std);
+
+ frame.setContentPane(draw);
+ frame.addKeyListener(std); // JLabel cannot get keyboard focus
+ frame.setResizable(false);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // closes all windows
+ // frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // closes only current window
+ frame.setTitle("Standard Draw");
+ frame.setJMenuBar(createMenuBar());
+ frame.pack();
+ frame.requestFocusInWindow();
+ frame.setVisible(true);
+ }
+
+ // create the menu bar (changed to private)
+ private static JMenuBar createMenuBar() {
+ JMenuBar menuBar = new JMenuBar();
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+ JMenuItem menuItem1 = new JMenuItem(" Save... ");
+ menuItem1.addActionListener(std);
+ menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ menu.add(menuItem1);
+ return menuBar;
+ }
+
+
+ /*************************************************************************
+ * User and screen coordinate systems
+ *************************************************************************/
+
+ /**
+ * Set the x-scale to be the default (between 0.0 and 1.0).
+ */
+ public static void setXscale() { setXscale(DEFAULT_XMIN, DEFAULT_XMAX); }
+
+ /**
+ * Set the y-scale to be the default (between 0.0 and 1.0).
+ */
+ public static void setYscale() { setYscale(DEFAULT_YMIN, DEFAULT_YMAX); }
+
+ /**
+ * Set the x-scale (a 10% border is added to the values)
+ * @param min the minimum value of the x-scale
+ * @param max the maximum value of the x-scale
+ */
+ public static void setXscale(double min, double max) {
+ double size = max - min;
+ synchronized (mouseLock) {
+ xmin = min - BORDER * size;
+ xmax = max + BORDER * size;
+ }
+ }
+
+ /**
+ * Set the y-scale (a 10% border is added to the values).
+ * @param min the minimum value of the y-scale
+ * @param max the maximum value of the y-scale
+ */
+ public static void setYscale(double min, double max) {
+ double size = max - min;
+ synchronized (mouseLock) {
+ ymin = min - BORDER * size;
+ ymax = max + BORDER * size;
+ }
+ }
+
+ /**
+ * Set the x-scale and y-scale (a 10% border is added to the values)
+ * @param min the minimum value of the x- and y-scales
+ * @param max the maximum value of the x- and y-scales
+ */
+ public static void setScale(double min, double max) {
+ double size = max - min;
+ synchronized (mouseLock) {
+ xmin = min - BORDER * size;
+ xmax = max + BORDER * size;
+ ymin = min - BORDER * size;
+ ymax = max + BORDER * size;
+ }
+ }
+
+ // helper functions that scale from user coordinates to screen coordinates and back
+ private static double scaleX(double x) { return width * (x - xmin) / (xmax - xmin); }
+ private static double scaleY(double y) { return height * (ymax - y) / (ymax - ymin); }
+ private static double factorX(double w) { return w * width / Math.abs(xmax - xmin); }
+ private static double factorY(double h) { return h * height / Math.abs(ymax - ymin); }
+ private static double userX(double x) { return xmin + x * (xmax - xmin) / width; }
+ private static double userY(double y) { return ymax - y * (ymax - ymin) / height; }
+
+
+ /**
+ * Clear the screen to the default color (white).
+ */
+ public static void clear() { clear(DEFAULT_CLEAR_COLOR); }
+ /**
+ * Clear the screen to the given color.
+ * @param color the Color to make the background
+ */
+ public static void clear(Color color) {
+ offscreen.setColor(color);
+ offscreen.fillRect(0, 0, width, height);
+ offscreen.setColor(penColor);
+ draw();
+ }
+
+ /**
+ * Get the current pen radius.
+ */
+ public static double getPenRadius() { return penRadius; }
+
+ /**
+ * Set the pen size to the default (.002).
+ */
+ public static void setPenRadius() { setPenRadius(DEFAULT_PEN_RADIUS); }
+ /**
+ * Set the radius of the pen to the given size.
+ * @param r the radius of the pen
+ * @throws IllegalArgumentException if r is negative
+ */
+ public static void setPenRadius(double r) {
+ if (r < 0) throw new IllegalArgumentException("pen radius must be nonnegative");
+ penRadius = r;
+ float scaledPenRadius = (float) (r * DEFAULT_SIZE);
+ BasicStroke stroke = new BasicStroke(scaledPenRadius, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
+ // BasicStroke stroke = new BasicStroke(scaledPenRadius);
+ offscreen.setStroke(stroke);
+ }
+
+ /**
+ * Get the current pen color.
+ */
+ public static Color getPenColor() { return penColor; }
+
+ /**
+ * Set the pen color to the default color (black).
+ */
+ public static void setPenColor() { setPenColor(DEFAULT_PEN_COLOR); }
+
+ /**
+ * Set the pen color to the given color. The available pen colors are
+ * BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA,
+ * ORANGE, PINK, RED, WHITE, and YELLOW.
+ * @param color the Color to make the pen
+ */
+ public static void setPenColor(Color color) {
+ penColor = color;
+ offscreen.setColor(penColor);
+ }
+
+ /**
+ * Set the pen color to the given RGB color.
+ * @param red the amount of red (between 0 and 255)
+ * @param green the amount of green (between 0 and 255)
+ * @param blue the amount of blue (between 0 and 255)
+ * @throws IllegalArgumentException if the amount of red, green, or blue are outside prescribed range
+ */
+ public static void setPenColor(int red, int green, int blue) {
+ if (red < 0 || red >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255");
+ if (green < 0 || green >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255");
+ if (blue < 0 || blue >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255");
+ setPenColor(new Color(red, green, blue));
+ }
+
+ /**
+ * Get the current font.
+ */
+ public static Font getFont() { return font; }
+
+ /**
+ * Set the font to the default font (sans serif, 16 point).
+ */
+ public static void setFont() { setFont(DEFAULT_FONT); }
+
+ /**
+ * Set the font to the given value.
+ * @param f the font to make text
+ */
+ public static void setFont(Font f) { font = f; }
+
+
+ /*************************************************************************
+ * Drawing geometric shapes.
+ *************************************************************************/
+
+ /**
+ * Draw a line from (x0, y0) to (x1, y1).
+ * @param x0 the x-coordinate of the starting point
+ * @param y0 the y-coordinate of the starting point
+ * @param x1 the x-coordinate of the destination point
+ * @param y1 the y-coordinate of the destination point
+ */
+ public static void line(double x0, double y0, double x1, double y1) {
+ offscreen.draw(new Line2D.Double(scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1)));
+ draw();
+ }
+
+ /**
+ * Draw one pixel at (x, y).
+ * @param x the x-coordinate of the pixel
+ * @param y the y-coordinate of the pixel
+ */
+ private static void pixel(double x, double y) {
+ offscreen.fillRect((int) Math.round(scaleX(x)), (int) Math.round(scaleY(y)), 1, 1);
+ }
+
+ /**
+ * Draw a point at (x, y).
+ * @param x the x-coordinate of the point
+ * @param y the y-coordinate of the point
+ */
+ public static void point(double x, double y) {
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double r = penRadius;
+ float scaledPenRadius = (float) (r * DEFAULT_SIZE);
+
+ // double ws = factorX(2*r);
+ // double hs = factorY(2*r);
+ // if (ws <= 1 && hs <= 1) pixel(x, y);
+ if (scaledPenRadius <= 1) pixel(x, y);
+ else offscreen.fill(new Ellipse2D.Double(xs - scaledPenRadius/2, ys - scaledPenRadius/2,
+ scaledPenRadius, scaledPenRadius));
+ draw();
+ }
+
+ /**
+ * Draw a circle of radius r, centered on (x, y).
+ * @param x the x-coordinate of the center of the circle
+ * @param y the y-coordinate of the center of the circle
+ * @param r the radius of the circle
+ * @throws IllegalArgumentException if the radius of the circle is negative
+ */
+ public static void circle(double x, double y, double r) {
+ if (r < 0) throw new IllegalArgumentException("circle radius must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*r);
+ double hs = factorY(2*r);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+ /**
+ * Draw filled circle of radius r, centered on (x, y).
+ * @param x the x-coordinate of the center of the circle
+ * @param y the y-coordinate of the center of the circle
+ * @param r the radius of the circle
+ * @throws IllegalArgumentException if the radius of the circle is negative
+ */
+ public static void filledCircle(double x, double y, double r) {
+ if (r < 0) throw new IllegalArgumentException("circle radius must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*r);
+ double hs = factorY(2*r);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+
+ /**
+ * Draw an ellipse with given semimajor and semiminor axes, centered on (x, y).
+ * @param x the x-coordinate of the center of the ellipse
+ * @param y the y-coordinate of the center of the ellipse
+ * @param semiMajorAxis is the semimajor axis of the ellipse
+ * @param semiMinorAxis is the semiminor axis of the ellipse
+ * @throws IllegalArgumentException if either of the axes are negative
+ */
+ public static void ellipse(double x, double y, double semiMajorAxis, double semiMinorAxis) {
+ if (semiMajorAxis < 0) throw new IllegalArgumentException("ellipse semimajor axis must be nonnegative");
+ if (semiMinorAxis < 0) throw new IllegalArgumentException("ellipse semiminor axis must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*semiMajorAxis);
+ double hs = factorY(2*semiMinorAxis);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+ /**
+ * Draw an ellipse with given semimajor and semiminor axes, centered on (x, y).
+ * @param x the x-coordinate of the center of the ellipse
+ * @param y the y-coordinate of the center of the ellipse
+ * @param semiMajorAxis is the semimajor axis of the ellipse
+ * @param semiMinorAxis is the semiminor axis of the ellipse
+ * @throws IllegalArgumentException if either of the axes are negative
+ */
+ public static void filledEllipse(double x, double y, double semiMajorAxis, double semiMinorAxis) {
+ if (semiMajorAxis < 0) throw new IllegalArgumentException("ellipse semimajor axis must be nonnegative");
+ if (semiMinorAxis < 0) throw new IllegalArgumentException("ellipse semiminor axis must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*semiMajorAxis);
+ double hs = factorY(2*semiMinorAxis);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+
+ /**
+ * Draw an arc of radius r, centered on (x, y), from angle1 to angle2 (in degrees).
+ * @param x the x-coordinate of the center of the circle
+ * @param y the y-coordinate of the center of the circle
+ * @param r the radius of the circle
+ * @param angle1 the starting angle. 0 would mean an arc beginning at 3 o'clock.
+ * @param angle2 the angle at the end of the arc. For example, if
+ * you want a 90 degree arc, then angle2 should be angle1 + 90.
+ * @throws IllegalArgumentException if the radius of the circle is negative
+ */
+ public static void arc(double x, double y, double r, double angle1, double angle2) {
+ if (r < 0) throw new IllegalArgumentException("arc radius must be nonnegative");
+ while (angle2 < angle1) angle2 += 360;
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*r);
+ double hs = factorY(2*r);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.draw(new Arc2D.Double(xs - ws/2, ys - hs/2, ws, hs, angle1, angle2 - angle1, Arc2D.OPEN));
+ draw();
+ }
+
+ /**
+ * Draw a square of side length 2r, centered on (x, y).
+ * @param x the x-coordinate of the center of the square
+ * @param y the y-coordinate of the center of the square
+ * @param r radius is half the length of any side of the square
+ * @throws IllegalArgumentException if r is negative
+ */
+ public static void square(double x, double y, double r) {
+ if (r < 0) throw new IllegalArgumentException("square side length must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*r);
+ double hs = factorY(2*r);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+ /**
+ * Draw a filled square of side length 2r, centered on (x, y).
+ * @param x the x-coordinate of the center of the square
+ * @param y the y-coordinate of the center of the square
+ * @param r radius is half the length of any side of the square
+ * @throws IllegalArgumentException if r is negative
+ */
+ public static void filledSquare(double x, double y, double r) {
+ if (r < 0) throw new IllegalArgumentException("square side length must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*r);
+ double hs = factorY(2*r);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+
+ /**
+ * Draw a rectangle of given half width and half height, centered on (x, y).
+ * @param x the x-coordinate of the center of the rectangle
+ * @param y the y-coordinate of the center of the rectangle
+ * @param halfWidth is half the width of the rectangle
+ * @param halfHeight is half the height of the rectangle
+ * @throws IllegalArgumentException if halfWidth or halfHeight is negative
+ */
+ public static void rectangle(double x, double y, double halfWidth, double halfHeight) {
+ if (halfWidth < 0) throw new IllegalArgumentException("half width must be nonnegative");
+ if (halfHeight < 0) throw new IllegalArgumentException("half height must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*halfWidth);
+ double hs = factorY(2*halfHeight);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+ /**
+ * Draw a filled rectangle of given half width and half height, centered on (x, y).
+ * @param x the x-coordinate of the center of the rectangle
+ * @param y the y-coordinate of the center of the rectangle
+ * @param halfWidth is half the width of the rectangle
+ * @param halfHeight is half the height of the rectangle
+ * @throws IllegalArgumentException if halfWidth or halfHeight is negative
+ */
+ public static void filledRectangle(double x, double y, double halfWidth, double halfHeight) {
+ if (halfWidth < 0) throw new IllegalArgumentException("half width must be nonnegative");
+ if (halfHeight < 0) throw new IllegalArgumentException("half height must be nonnegative");
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(2*halfWidth);
+ double hs = factorY(2*halfHeight);
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
+ draw();
+ }
+
+
+ /**
+ * Draw a polygon with the given (x[i], y[i]) coordinates.
+ * @param x an array of all the x-coordindates of the polygon
+ * @param y an array of all the y-coordindates of the polygon
+ */
+ public static void polygon(double[] x, double[] y) {
+ int N = x.length;
+ GeneralPath path = new GeneralPath();
+ path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));
+ for (int i = 0; i < N; i++)
+ path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));
+ path.closePath();
+ offscreen.draw(path);
+ draw();
+ }
+
+ /**
+ * Draw a filled polygon with the given (x[i], y[i]) coordinates.
+ * @param x an array of all the x-coordindates of the polygon
+ * @param y an array of all the y-coordindates of the polygon
+ */
+ public static void filledPolygon(double[] x, double[] y) {
+ int N = x.length;
+ GeneralPath path = new GeneralPath();
+ path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));
+ for (int i = 0; i < N; i++)
+ path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));
+ path.closePath();
+ offscreen.fill(path);
+ draw();
+ }
+
+
+
+ /*************************************************************************
+ * Drawing images.
+ *************************************************************************/
+
+ // get an image from the given filename
+ private static Image getImage(String filename) {
+
+ // to read from file
+ ImageIcon icon = new ImageIcon(filename);
+
+ // try to read from URL
+ if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {
+ try {
+ URL url = new URL(filename);
+ icon = new ImageIcon(url);
+ } catch (Exception e) { /* not a url */ }
+ }
+
+ // in case file is inside a .jar
+ if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {
+ URL url = StdDraw.class.getResource(filename);
+ if (url == null) throw new IllegalArgumentException("image " + filename + " not found");
+ icon = new ImageIcon(url);
+ }
+
+ return icon.getImage();
+ }
+
+ /**
+ * Draw picture (gif, jpg, or png) centered on (x, y).
+ * @param x the center x-coordinate of the image
+ * @param y the center y-coordinate of the image
+ * @param s the name of the image/picture, e.g., "ball.gif"
+ * @throws IllegalArgumentException if the image is corrupt
+ */
+ public static void picture(double x, double y, String s) {
+ Image image = getImage(s);
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ int ws = image.getWidth(null);
+ int hs = image.getHeight(null);
+ if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
+
+ offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);
+ draw();
+ }
+
+ /**
+ * Draw picture (gif, jpg, or png) centered on (x, y),
+ * rotated given number of degrees
+ * @param x the center x-coordinate of the image
+ * @param y the center y-coordinate of the image
+ * @param s the name of the image/picture, e.g., "ball.gif"
+ * @param degrees is the number of degrees to rotate counterclockwise
+ * @throws IllegalArgumentException if the image is corrupt
+ */
+ public static void picture(double x, double y, String s, double degrees) {
+ Image image = getImage(s);
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ int ws = image.getWidth(null);
+ int hs = image.getHeight(null);
+ if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
+
+ offscreen.rotate(Math.toRadians(-degrees), xs, ys);
+ offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);
+ offscreen.rotate(Math.toRadians(+degrees), xs, ys);
+
+ draw();
+ }
+
+ /**
+ * Draw picture (gif, jpg, or png) centered on (x, y), rescaled to w-by-h.
+ * @param x the center x coordinate of the image
+ * @param y the center y coordinate of the image
+ * @param s the name of the image/picture, e.g., "ball.gif"
+ * @param w the width of the image
+ * @param h the height of the image
+ * @throws IllegalArgumentException if the width height are negative
+ * @throws IllegalArgumentException if the image is corrupt
+ */
+ public static void picture(double x, double y, String s, double w, double h) {
+ Image image = getImage(s);
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ if (w < 0) throw new IllegalArgumentException("width is negative: " + w);
+ if (h < 0) throw new IllegalArgumentException("height is negative: " + h);
+ double ws = factorX(w);
+ double hs = factorY(h);
+ if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+ else {
+ offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),
+ (int) Math.round(ys - hs/2.0),
+ (int) Math.round(ws),
+ (int) Math.round(hs), null);
+ }
+ draw();
+ }
+
+
+ /**
+ * Draw picture (gif, jpg, or png) centered on (x, y), rotated
+ * given number of degrees, rescaled to w-by-h.
+ * @param x the center x-coordinate of the image
+ * @param y the center y-coordinate of the image
+ * @param s the name of the image/picture, e.g., "ball.gif"
+ * @param w the width of the image
+ * @param h the height of the image
+ * @param degrees is the number of degrees to rotate counterclockwise
+ * @throws IllegalArgumentException if the image is corrupt
+ */
+ public static void picture(double x, double y, String s, double w, double h, double degrees) {
+ Image image = getImage(s);
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ double ws = factorX(w);
+ double hs = factorY(h);
+ if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
+ if (ws <= 1 && hs <= 1) pixel(x, y);
+
+ offscreen.rotate(Math.toRadians(-degrees), xs, ys);
+ offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),
+ (int) Math.round(ys - hs/2.0),
+ (int) Math.round(ws),
+ (int) Math.round(hs), null);
+ offscreen.rotate(Math.toRadians(+degrees), xs, ys);
+
+ draw();
+ }
+
+
+ /*************************************************************************
+ * Drawing text.
+ *************************************************************************/
+
+ /**
+ * Write the given text string in the current font, centered on (x, y).
+ * @param x the center x-coordinate of the text
+ * @param y the center y-coordinate of the text
+ * @param s the text
+ */
+ public static void text(double x, double y, String s) {
+ offscreen.setFont(font);
+ FontMetrics metrics = offscreen.getFontMetrics();
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ int ws = metrics.stringWidth(s);
+ int hs = metrics.getDescent();
+ offscreen.drawString(s, (float) (xs - ws/2.0), (float) (ys + hs));
+ draw();
+ }
+
+ /**
+ * Write the given text string in the current font, centered on (x, y) and
+ * rotated by the specified number of degrees
+ * @param x the center x-coordinate of the text
+ * @param y the center y-coordinate of the text
+ * @param s the text
+ * @param degrees is the number of degrees to rotate counterclockwise
+ */
+ public static void text(double x, double y, String s, double degrees) {
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ offscreen.rotate(Math.toRadians(-degrees), xs, ys);
+ text(x, y, s);
+ offscreen.rotate(Math.toRadians(+degrees), xs, ys);
+ }
+
+
+ /**
+ * Write the given text string in the current font, left-aligned at (x, y).
+ * @param x the x-coordinate of the text
+ * @param y the y-coordinate of the text
+ * @param s the text
+ */
+ public static void textLeft(double x, double y, String s) {
+ offscreen.setFont(font);
+ FontMetrics metrics = offscreen.getFontMetrics();
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ int hs = metrics.getDescent();
+ offscreen.drawString(s, (float) (xs), (float) (ys + hs));
+ draw();
+ }
+
+ /**
+ * Write the given text string in the current font, right-aligned at (x, y).
+ * @param x the x-coordinate of the text
+ * @param y the y-coordinate of the text
+ * @param s the text
+ */
+ public static void textRight(double x, double y, String s) {
+ offscreen.setFont(font);
+ FontMetrics metrics = offscreen.getFontMetrics();
+ double xs = scaleX(x);
+ double ys = scaleY(y);
+ int ws = metrics.stringWidth(s);
+ int hs = metrics.getDescent();
+ offscreen.drawString(s, (float) (xs - ws), (float) (ys + hs));
+ draw();
+ }
+
+
+
+ /**
+ * Display on screen, pause for t milliseconds, and turn on
+ * animation mode: subsequent calls to
+ * drawing methods such as line(), circle(), and square()
+ * will not be displayed on screen until the next call to show().
+ * This is useful for producing animations (clear the screen, draw a bunch of shapes,
+ * display on screen for a fixed amount of time, and repeat). It also speeds up
+ * drawing a huge number of shapes (call show(0) to defer drawing
+ * on screen, draw the shapes, and call show(0) to display them all
+ * on screen at once).
+ * @param t number of milliseconds
+ */
+ public static void show(int t) {
+ defer = false;
+ draw();
+ try { Thread.sleep(t); }
+ catch (InterruptedException e) { System.out.println("Error sleeping"); }
+ defer = true;
+ }
+
+ /**
+ * Display on-screen and turn off animation mode:
+ * subsequent calls to
+ * drawing methods such as line(), circle(), and square()
+ * will be displayed on screen when called. This is the default.
+ */
+ public static void show() {
+ defer = false;
+ draw();
+ }
+
+ // draw onscreen if defer is false
+ private static void draw() {
+ if (defer) return;
+ onscreen.drawImage(offscreenImage, 0, 0, null);
+ frame.repaint();
+ }
+
+
+ /*************************************************************************
+ * Save drawing to a file.
+ *************************************************************************/
+
+ /**
+ * Save onscreen image to file - suffix must be png, jpg, or gif.
+ * @param filename the name of the file with one of the required suffixes
+ */
+ public static void save(String filename) {
+ File file = new File(filename);
+ String suffix = filename.substring(filename.lastIndexOf('.') + 1);
+
+ // png files
+ if (suffix.toLowerCase().equals("png")) {
+ try { ImageIO.write(onscreenImage, suffix, file); }
+ catch (IOException e) { e.printStackTrace(); }
+ }
+
+ // need to change from ARGB to RGB for jpeg
+ // reference: http://archives.java.sun.com/cgi-bin/wa?A2=ind0404&L=java2d-interest&D=0&P=2727
+ else if (suffix.toLowerCase().equals("jpg")) {
+ WritableRaster raster = onscreenImage.getRaster();
+ WritableRaster newRaster;
+ newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2});
+ DirectColorModel cm = (DirectColorModel) onscreenImage.getColorModel();
+ DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
+ cm.getRedMask(),
+ cm.getGreenMask(),
+ cm.getBlueMask());
+ BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
+ try { ImageIO.write(rgbBuffer, suffix, file); }
+ catch (IOException e) { e.printStackTrace(); }
+ }
+
+ else {
+ System.out.println("Invalid image file type: " + suffix);
+ }
+ }
+
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void actionPerformed(ActionEvent e) {
+ FileDialog chooser = new FileDialog(StdDraw.frame, "Use a .png or .jpg extension", FileDialog.SAVE);
+ chooser.setVisible(true);
+ String filename = chooser.getFile();
+ if (filename != null) {
+ StdDraw.save(chooser.getDirectory() + File.separator + chooser.getFile());
+ }
+ }
+
+
+ /*************************************************************************
+ * Mouse interactions.
+ *************************************************************************/
+
+ /**
+ * Is the mouse being pressed?
+ * @return true or false
+ */
+ public static boolean mousePressed() {
+ synchronized (mouseLock) {
+ return mousePressed;
+ }
+ }
+
+ /**
+ * What is the x-coordinate of the mouse?
+ * @return the value of the x-coordinate of the mouse
+ */
+ public static double mouseX() {
+ synchronized (mouseLock) {
+ return mouseX;
+ }
+ }
+
+ /**
+ * What is the y-coordinate of the mouse?
+ * @return the value of the y-coordinate of the mouse
+ */
+ public static double mouseY() {
+ synchronized (mouseLock) {
+ return mouseY;
+ }
+ }
+
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mouseClicked(MouseEvent e) { }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mouseEntered(MouseEvent e) { }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mouseExited(MouseEvent e) { }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mousePressed(MouseEvent e) {
+ synchronized (mouseLock) {
+ mouseX = StdDraw.userX(e.getX());
+ mouseY = StdDraw.userY(e.getY());
+ mousePressed = true;
+ }
+ }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mouseReleased(MouseEvent e) {
+ synchronized (mouseLock) {
+ mousePressed = false;
+ }
+ }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mouseDragged(MouseEvent e) {
+ synchronized (mouseLock) {
+ mouseX = StdDraw.userX(e.getX());
+ mouseY = StdDraw.userY(e.getY());
+ }
+ }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void mouseMoved(MouseEvent e) {
+ synchronized (mouseLock) {
+ mouseX = StdDraw.userX(e.getX());
+ mouseY = StdDraw.userY(e.getY());
+ }
+ }
+
+
+ /*************************************************************************
+ * Keyboard interactions.
+ *************************************************************************/
+
+ /**
+ * Has the user typed a key?
+ * @return true if the user has typed a key, false otherwise
+ */
+ public static boolean hasNextKeyTyped() {
+ synchronized (keyLock) {
+ return !keysTyped.isEmpty();
+ }
+ }
+
+ /**
+ * What is the next key that was typed by the user? This method returns
+ * a Unicode character corresponding to the key typed (such as 'a' or 'A').
+ * It cannot identify action keys (such as F1
+ * and arrow keys) or modifier keys (such as control).
+ * @return the next Unicode key typed
+ */
+ public static char nextKeyTyped() {
+ synchronized (keyLock) {
+ return keysTyped.removeLast();
+ }
+ }
+
+ /**
+ * Is the keycode currently being pressed? This method takes as an argument
+ * the keycode (corresponding to a physical key). It can handle action keys
+ * (such as F1 and arrow keys) and modifier keys (such as shift and control).
+ * See KeyEvent.java
+ * for a description of key codes.
+ * @return true if keycode is currently being pressed, false otherwise
+ */
+ public static boolean isKeyPressed(int keycode) {
+ synchronized (keyLock) {
+ return keysDown.contains(keycode);
+ }
+ }
+
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void keyTyped(KeyEvent e) {
+ synchronized (keyLock) {
+ keysTyped.addFirst(e.getKeyChar());
+ }
+ }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void keyPressed(KeyEvent e) {
+ synchronized (keyLock) {
+ keysDown.add(e.getKeyCode());
+ }
+ }
+
+ /**
+ * This method cannot be called directly.
+ */
+ public void keyReleased(KeyEvent e) {
+ synchronized (keyLock) {
+ keysDown.remove(e.getKeyCode());
+ }
+ }
+
+
+
+
+ /**
+ * Test client.
+ */
+ public static void main(String[] args) {
+ StdDraw.square(.2, .8, .1);
+ StdDraw.filledSquare(.8, .8, .2);
+ StdDraw.circle(.8, .2, .2);
+
+ StdDraw.setPenColor(StdDraw.BOOK_RED);
+ StdDraw.setPenRadius(.02);
+ StdDraw.arc(.8, .2, .1, 200, 45);
+
+ // draw a blue diamond
+ StdDraw.setPenRadius();
+ StdDraw.setPenColor(StdDraw.BOOK_BLUE);
+ double[] x = { .1, .2, .3, .2 };
+ double[] y = { .2, .3, .2, .1 };
+ StdDraw.filledPolygon(x, y);
+
+ // text
+ StdDraw.setPenColor(StdDraw.BLACK);
+ StdDraw.text(0.2, 0.5, "black text");
+ StdDraw.setPenColor(StdDraw.WHITE);
+ StdDraw.text(0.8, 0.8, "white text");
+ }
+
+}
\ No newline at end of file