__polygon;
- private Boolean __isFill;
- private Boolean __isStamp;
- private Double __dotSize;
- private Color __dotColor;
- private Font __font;
- private String __text;
- private Integer __justification;
- private Point2D.Double __textOffset;
-
- /**
- * Makes a turtle at the center of the canvas at location (0, 0).
- *
- * Turtle t = new Turtle();
- *
- */
- public Turtle() {
- if (window == null) init();
- synchronized (turtleLock) {
- turtles.add(this);
- }
- long time = storeCurrentState();
- updateAll();
- }
-
- /**
- * Makes a turtle at the specified position.
- *
- * @param x x coordinate
- * @param y y coordinate
- */
- public Turtle(double x, double y) {
- if (window == null) init();
- location = new Point2D.Double(x, y);
- synchronized (turtleLock) {
- turtles.add(this);
- }
- long time = storeCurrentState();
- updateAll();
- }
-
- /**
- * This creates a cloned copy of a turtle.
- *
- * @return a cloned copy of a turtle
- */
- public Turtle clone() {
- Turtle t = new Turtle(0);
- t.location = (Point2D.Double) this.location.clone();
- t.direction = this.direction;
- t.shape = t.shape;
- t.image = this.image;
- t.shapeWidth = this.shapeWidth;
- t.shapeHeight = this.shapeHeight;
- t.tilt = this.tilt;
- t.penWidth = this.penWidth;
- t.penColor = this.penColor;
- t.outlineWidth = this.outlineWidth;
- t.outlineColor = this.outlineColor;
- t.fillColor = this.fillColor;
- t.speed = this.speed;
- t.isPenDown = this.isPenDown;
- t.isFilling = this.isFilling;
- t.isVisible = this.isVisible;
- if (window == null) init();
- synchronized (turtleLock) {
- turtles.add(t);
- }
- long time = t.storeCurrentState();
- return t;
- }
-
- /* .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
- * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
- * U U U U U U U U U U U U U U U U
- * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
- * _/___\/ _/___\/ _/___\/ STATE MANAGEMENT _/___\/ _/___\/ _/___\/
- * U U U U U U U U U U U U
- * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
- * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
- * U U U U U U U U U U U U U U U U
- */
-
- private long storeCurrentState() {
- return storeCurrentState(false, false, 0, null, null, null, 0, null);
- }
-
- private long storeAnimatedState() {
- return storeCurrentState(true, false, 0, null, null, null, 0, null);
- }
-
- private long storeCurrentState(boolean animate, boolean isStamp, double dotSize, Color dotColor, Font font, String text, int justification, Point2D.Double textOffset) {
- ArrayList state = new ArrayList();
- long time = System.nanoTime();
- synchronized (turtleLock) {
- state.add(0); //0
- state.add(this); //1
- state.add(location.clone());//2
- state.add(direction); //3
- state.add(shape); //4
- state.add(image); //5
- state.add(shapeWidth); //6
- state.add(shapeHeight); //7
- state.add(tilt); //8
- state.add(penWidth); //9
- state.add(penColor); //10
- state.add(outlineWidth); //11
- state.add(outlineColor); //12
- state.add(fillColor); //13
- state.add(speed); //14
- state.add(isPenDown); //15
- state.add(isFilling); //16
- state.add(isVisible); //17
- state.add(isStamp); //18
- state.add(dotSize); //19
- state.add(dotColor); //20
- state.add(font); //21
- state.add(text); //22
- state.add(justification); //23
- state.add(textOffset); //24
- if (!turtleStates.isEmpty() && turtleStates.lastKey() > time) time = turtleStates.lastKey() + 1;
- if (animate) time += (long) (speed * 1000000);
- state.set(0, time);
- turtleStates.put(time, state);
- redoStates.clear();
- }
- if (refreshMode == REFRESH_MODE_STATE_CHANGE) draw();
- if (refreshMode == REFRESH_MODE_ANIMATED) waitUntil(time);
- return time;
- }
-
- private static void clearStorage() {
- synchronized (turtleLock) {
- for (Turtle t : turtles) {
- t.__time = null;
- t.__location = null;
- t.__direction = null;
- t.__shape = null;
- t.__image = null;
- t.__shapeWidth = null;
- t.__shapeHeight = null;
- t.__tilt = null;
- t.__penWidth = null;
- t.__penColor = null;
- t.__outlineWidth = null;
- t.__outlineColor = null;
- t.__fillColor = null;
- t.__speed = null;
- t.__isPenDown = null;
- t.__isFilling = null;
- t.__isVisible = null;
- t.__isStamp = null;
- t.__dotSize = null;
- t.__dotColor = null;
- t.__font = null;
- t.__text = null;
- t.__justification = null;
- t.__textOffset = null;
- t._time = null;
- t._location = null;
- t._direction = null;
- t._shape = null;
- t._shapeWidth = null;
- t._shapeHeight = null;
- t._image = null;
- t._tilt = null;
- t._penWidth = null;
- t._penColor = null;
- t._outlineWidth = null;
- t._outlineColor = null;
- t._fillColor = null;
- t._speed = null;
- t._isPenDown = null;
- t._isFilling = null;
- t._isVisible = null;
- t._isStamp = null;
- t._dotSize = null;
- t._dotColor = null;
- t._font = null;
- t._text = null;
- t._justification = null;
- t._textOffset = null;
- }
- }
- }
-
- private static void retrieveState(long time) {
- synchronized (turtleLock) {
- Turtle t = getStateTurtle(turtleStates.get(time));
- t.__time = t._time;
- t.__location = t._location;
- t.__direction = t._direction;
- t.__shape = t._shape;
- t.__image = t._image;
- t.__shapeWidth = t._shapeWidth;
- t.__shapeHeight = t._shapeHeight;
- t.__tilt = t._tilt;
- t.__penWidth = t._penWidth;
- t.__penColor = t._penColor;
- t.__outlineWidth = t._outlineWidth;
- t.__outlineColor = t._outlineColor;
- t.__fillColor = t._fillColor;
- t.__speed = t._speed;
- t.__isPenDown = t._isPenDown;
- t.__isFilling = t._isFilling;
- t.__isVisible = t._isVisible;
- t.__isStamp = t._isStamp;
- t.__dotSize = t._dotSize;
- t.__dotColor = t._dotColor;
- t.__font = t._font;
- t.__text = t._text;
- t.__justification = t._justification;
- t.__textOffset = t._textOffset;
- ArrayList state = turtleStates.get(time);
- t._time = getStateTime(state);
- t._location = getStateLocation(state);
- t._direction = getStateDirection(state);
- t._shape = getStateShape(state);
- t._shapeWidth = getStateShapeWidth(state);
- t._shapeHeight = getStateShapeHeight(state);
- t._image = getStateImage(state);
- t._tilt = getStateTilt(state);
- t._penWidth = getStatePenWidth(state);
- t._penColor = getStatePenColor(state);
- t._outlineWidth = getStateOutlineWidth(state);
- t._outlineColor = getStateOutlineColor(state);
- t._fillColor = getStateFillColor(state);
- t._speed = getStateSpeed(state);
- t._isPenDown = getStateIsPenDown(state);
- t._isFilling = getStateIsFilling(state);
- t._isVisible = getStateIsVisible(state);
- t._isStamp = getStateIsStamp(state);
- t._dotSize = getStateDotSize(state);
- t._dotColor = getStateDotColor(state);
- t._font = getStateFont(state);
- t._text = getStateText(state);
- t._justification = getStateJustification(state);
- t._textOffset = getStateTextOffset(state);
- }
- }
-
- private static long getStateTime(ArrayList state) {
- return (Long) state.get(0);
- }
-
- private static Turtle getStateTurtle(ArrayList state) {
- return (Turtle) state.get(1);
- }
-
- private static Point2D.Double getStateLocation(ArrayList state) {
- return (Point2D.Double) ((Point2D.Double) state.get(2)).clone();
- }
-
- private static double getStateDirection(ArrayList state) {
- return (Double) state.get(3);
- }
-
- private static String getStateShape(ArrayList state) {
- return (String) state.get(4);
- }
-
- private static BufferedImage getStateImage(ArrayList state) {
- return (BufferedImage) state.get(5);
- }
-
- private static double getStateShapeWidth(ArrayList state) {
- return (Double) state.get(6);
- }
-
- private static double getStateShapeHeight(ArrayList state) {
- return (Double) state.get(7);
- }
-
- private static double getStateTilt(ArrayList state) {
- return (Double) state.get(8);
- }
-
- private static double getStatePenWidth(ArrayList state) {
- return (Double) state.get(9);
- }
-
- private static Color getStatePenColor(ArrayList state) {
- return (Color) state.get(10);
- }
-
- private static double getStateOutlineWidth(ArrayList state) {
- return (Double) state.get(11);
- }
-
- private static Color getStateOutlineColor(ArrayList state) {
- return (Color) state.get(12);
- }
-
- private static Color getStateFillColor(ArrayList state) {
- return (Color) state.get(13);
- }
-
- private static double getStateSpeed(ArrayList state) {
- return (Double) state.get(14);
- }
-
- private static boolean getStateIsPenDown(ArrayList state) {
- return (Boolean) state.get(15);
- }
-
- private static boolean getStateIsFilling(ArrayList state) {
- return (Boolean) state.get(16);
- }
-
- private static boolean getStateIsVisible(ArrayList state) {
- return (Boolean) state.get(17);
- }
-
- private static boolean getStateIsStamp(ArrayList state) {
- return (Boolean) state.get(18);
- }
-
- private static double getStateDotSize(ArrayList state) {
- return (Double) state.get(19);
- }
-
- private static Color getStateDotColor(ArrayList state) {
- return (Color) state.get(20);
- }
-
- private static Font getStateFont(ArrayList state) {
- return (Font) state.get(21);
- }
-
- private static String getStateText(ArrayList state) {
- return (String) state.get(22);
- }
-
- private static int getStateJustification(ArrayList state) {
- return (Integer) state.get(23);
- }
-
- private static Point2D.Double getStateTextOffset(ArrayList state) {
- return (Point2D.Double) state.get(24);
- }
-
- private static void restoreState(long time) {
- ArrayList state = turtleStates.get(time);
- Turtle t = getStateTurtle(turtleStates.get(time));
- t.location = getStateLocation(state);
- t.direction = getStateDirection(state);
- t.shape = getStateShape(state);
- t.shapeWidth = getStateShapeWidth(state);
- t.shapeHeight = getStateShapeHeight(state);
- t.image = getStateImage(state);
- t.tilt = getStateTilt(state);
- t.penWidth = getStatePenWidth(state);
- t.penColor = getStatePenColor(state);
- t.outlineWidth = getStateOutlineWidth(state);
- t.outlineColor = getStateOutlineColor(state);
- t.fillColor = getStateFillColor(state);
- t.speed = getStateSpeed(state);
- t.isPenDown = getStateIsPenDown(state);
- t.isFilling = getStateIsFilling(state);
- t.isVisible = getStateIsVisible(state);
- if (refreshMode == REFRESH_MODE_STATE_CHANGE) draw();
- }
-
- private void select() {
- selectedTurtle = this;
- }
-
- private void unselect() {
- if (selectedTurtle == this) selectedTurtle = null;
- }
-
- private void output(String message) {
- out.println("Instruction: " + message);
- out.printf("Current Pos: (%.3f, %.3f)\n", location.getX(), location.getY());
- }
-
- /**
- * Determines if a turtle is covering a screen position
- *
- * @param x x screen coordinate
- * @param y y screen coordinate
- * @return true if this turtle is at the indicated screen position.
- */
- public boolean contains(int x, int y) {
- Point2D.Double point = new Point2D.Double(x, y);
- if (_location == null) return false;
- AffineTransform m = offscreen.getTransform();
- double x1, y1, dir1;
- x1 = _location.x;
- y1 = _location.y;
- dir1 = _direction;
- m.translate(((x1 - centerX) * scale + width / 2), ((y1 - centerY) * (-scale) + height / 2));
- m.scale(scale, scale);
- if (image == null) {
- m.rotate(-Math.toRadians(dir1));
- m.scale(shapeWidth / 100.0, shapeHeight / 100.0);
- m.translate(-50, -50);
- Polygon p = shapes.get(shape);
- GeneralPath gp = new GeneralPath();
- gp.append(p.getPathIterator(m), false);
- return gp.contains(x, y);
- } else {
- int w = image.getWidth();
- int h = image.getHeight();
- m.rotate(-Math.toRadians(dir1));
- m.scale(shapeWidth / 1.0 / w, shapeHeight / 1.0 / h);
- m.translate(-w / 2, -h / 2);
- try {
- m.inverseTransform(point, point);
- } catch (Exception e) {
- return false;
- }
- x = (int) point.x;
- y = (int) point.y;
- try {
- //System.out.println((new Color(image.getRGB(x, y),true)).getAlpha());
- return (new Color(image.getRGB(x, y), true)).getAlpha() > 50;
- } catch (Exception e) {
- return false;
- }
- }
- }
-
- /* .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
- * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
- * U U U U U U U U U U U U U U U U
- * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
- * _/___\/ _/___\/ _/___\/ TURTLE METHODS _/___\/ _/___\/ _/___\/
- * U U U U U U U U U U U U
- * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
- * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
- * U U U U U U U U U U U U U U U U
- */
-
- /**
- * Gets the speed of the animation.
- * @return milliseconds it takes to do one action
- */
- public double getSpeed() {
- return speed;
- }
-
- /**
- * Sets the speed of the animation.
- *
- *
- * Turtle t = new Turtle();
- * t.speed(1000);
- * t.forward(100); // takes 1000 ms (1 second) to move forward 100 units
- * t.forward(5); // takes 1000 ms (1 second) to move forward 5 units
- * t.speed(100);
- * t.left(90); // takes 100 ms (0.1 second) to turn left 90 degrees
- *
- *
- * @param delay milliseconds it takes to do one action
- * @return state change timestamp
- */
- public long speed(double delay) {
- this.speed = delay;
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Moves the turtle forward by the given distance. Each unit of distance
- * is one pixel at the default zoom level.
- *
- * The example below constructs a turtle and moves it forward.
- * If the canvas is zoomed to the default zoom level, then the
- * distance moved is 50 pixels.
- *
- *
- * Turtle t = new Turtle();
- * t.forward(50);
- *
- *
- * @param distance number of units to move forward
- * @return state change timestamp
- */
- public long forward(double distance) {
- double angle = Math.toRadians(direction);
- Point2D.Double pastLocation = (Point2D.Double) location.clone();
- location.x += distance * Math.cos(angle);
- location.y += distance * Math.sin(angle);
- long timeStamp = storeAnimatedState();
-
- output("MOVE FORWARD " + distance);
- return timeStamp;
- }
-
- /**
- * Moves the turtle backward by the given distance. Each unit of distance is one
- * pixel at the default zoom level.
- *
- * @param distance number of units to move forward
- * @return state change timestamp
- */
- public long backward(double distance) {
- double angle = Math.toRadians(direction);
- Point2D.Double pastLocation = (Point2D.Double) location.clone();
- location.x -= distance * Math.cos(angle);
- location.y -= distance * Math.sin(angle);
- long timeStamp = storeAnimatedState();
-
- output("MOVE BACKWARD " + distance);
- return timeStamp;
- }
-
- /**
- * Turns the turtle left by the number of indicated degrees.
- *
- * @param angle angle in degrees
- * @return state change timestamp
- */
- public long left(double angle) {
- direction += angle;
- long timeStamp = storeAnimatedState();
-
- output("TURN LEFT " + angle);
- return timeStamp;
- }
-
- /**
- * Turns the turtle right by the number of indicated degrees.
- *
- * @param angle angle in degrees
- * @return state change timestamp
- */
- public long right(double angle) {
- direction -= angle;
- long timeStamp = storeAnimatedState();
-
- output("TURN RIGHT " + angle);
- return timeStamp;
- }
-
- /**
- * Gets the direction the turtle is facing neglecting tilt.
- *
- * @return state change timestamp
- */
- public double getDirection() {
- double a = direction;
- while (a >= 360) a -= 360;
- while (a < 0) a += 360;
- return a;
- }
-
- /**
- * Sets the direction the turtle is facing neglecting tilt.
- *
- * @param direction angle counter-clockwise from east
- * @return state change timestamp
- */
- public long setDirection(double direction) {
- double a = direction;
- while (this.direction - a > 180) a += 360;
- while (this.direction - a < -180) a -= 360;
- this.direction = a;
- //this.direction=direction;
- long timeStamp = storeAnimatedState();
-
- output("SET DIRECTION " + a);
- return timeStamp;
- }
-
- /**
- * Moves the turtle to (0,0) and facing east.
- *
- * @return state change timestamp
- */
- public long home() {
- output("MOVE HOME");
- return setPosition(0, 0, 0);
- }
-
- /**
- * Hides the turtle but it can still draw.
- *
- * @return state change timestamp
- */
- public long hide() {
- isVisible = false;
- output("HIDING TURTLE");
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Makes the turtle visible.
- *
- * @return state change timestamp
- */
- public long show() {
- isVisible = true;
- output("SHOWING TURTLE");
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the direction in such a way that it faces (x,y)
- *
- * @param x x coordinate of target location
- * @param y y coordinate of target location
- * @return state change timestamp
- */
- public long face(double x, double y) {
- return setDirection(towards(x, y));
- }
-
- /**
- * Gets direction towards (x,y)
- *
- * @param x x coordinate of target location
- * @param y y coordinate of target location
- * @return angle in degrees where 0 <= angle <
- */
- public double towards(double x, double y) {
- return Math.toDegrees(Math.atan2(y - location.y, x - location.x));
- }
-
- /**
- * Gets the distance to another position.
- *
- * @param x x coordinate of target location
- * @param y y coordinate of target location
- * @return distance between turtle's current location and another position
- */
- public double distance(double x, double y) {
- return Math.sqrt((y - location.y) * (y - location.y) + (x - location.x) * (x - location.x));
- }
-
- /**
- * Gets the x coordinate of the turtle.
- *
- * @return x coordinate
- */
- public double getX() {
- return location.x;
- }
-
- /**
- * Gets the y coordinate of the turtle.
- *
- * @return y coordinate
- */
- public double getY() {
- return location.y;
- }
-
- /**
- * Sets the position and direction of a turtle.
- *
- * @param x x coordinate
- * @param y y coordinate
- * @param direction angle counter-clockwise from east in degrees
- * @return state change timestamp
- */
- public long setPosition(double x, double y, double direction) {
- location.x = x;
- location.y = y;
- double a = direction;
- while (this.direction - a > 180) a += 360;
- while (this.direction - a < -180) a -= 360;
- this.direction = a;
- this.direction = direction;
-
- output(String.format("SET POSITION (%f, %f) DIRECTION %f", x, y, direction));
- long timeStamp = storeAnimatedState();
- return timeStamp;
- }
-
- /**
- * Sets the position of a turtle.
- *
- * @param x x coordinate
- * @param y y coordinate
- * @return state change timestamp
- */
- public long setPosition(double x, double y) {
- return setPosition(x, y, direction);
- }
-
- /**
- * Adds an additional angle to rotation of the turtle's shape when rendering.
- * This is useful when you need to face a different direction than the
- * direction you are moving in.
- *
- * @param angle angle in degrees
- * @return state change timestamp
- */
- public long tilt(double angle) {
- tilt += angle;
-
- output("ADD TILT " + angle);
-
- long timeStamp = storeAnimatedState();
- return timeStamp;
- }
-
- /**
- * Sets the angle to rotate the turtle's shape when rendering.
- * This is useful when you need to face a different direction than the
- * direction you are moving in.
- *
- * @param angle angle in degrees
- * @return state change timestamp
- */
- public long setTilt(double angle) {
- //double a=angle;
- //while(tilt-a>180)a+=360;
- //while(tilt-a<-180)a-=360;
- //tilt=a;
- tilt = angle;
-
- output("SET TILT " + angle);
-
- long timeStamp = storeAnimatedState();
- return timeStamp;
- }
-
- /**
- * Gets the rotation of the turtle's shape away from the turtle's direction.
- *
- * @return tilt in degrees (positive in counter-clockwise)
- */
- public double getTilt() {
- return tilt;
- }
-
- /**
- * Sets the width of the turtle's pen. Each unit of width corresponds to
- * 1 pixel at the default zoom level.
- *
- *
- * @param penWidth number of units wide
- * @return state change timestamp
- */
- public long width(double penWidth) {
- this.penWidth = penWidth;
-
- output("SET PEN WIDTH " + penWidth);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the width of the turtle's outline.
- *
- * @param width width of the turtle's outline
- * @return state change timestamp
- */
- public long outlineWidth(double width) {
- this.outlineWidth = width;
-
- output("SET OUTLINE WIDTH " + width);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Picks the turtle's pen up so it won't draw on the screen as it moves.
- *
- * @return state change timestamp
- */
- public long up() {
- this.isPenDown = false;
- output("LIFT PEN");
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Puts the turtle's pen down so it will draw on the screen as it moves.
- *
- * @return state change timestamp
- */
- public long down() {
- this.isPenDown = true;
- output("LOWER PEN");
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- public long stab() {
- Color c = Turtle.getColor("red");
- if (c != null) this.penColor = c;
- this.isPenDown = true;
-
- output("STAB");
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the turtle's path color.
- *
- * @param penColor Color of the turtle's path.
- * @return state change timestamp
- */
- public long penColor(String penColor) {
- Color c = Turtle.getColor(penColor);
- if (c != null) this.penColor = c;
- output("SET PEN COLOR " + c);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the turtle's path color.
- *
- * @param penColor Color of the turtle's path.
- * @return state change timestamp
- */
- public long penColor(Color penColor) {
- this.penColor = penColor;
-
- output("SET PEN COLOR " + penColor);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the turtle's outlineColor color.
- *
- * @param outlineColor Color of the turtle's outlineColor.
- * @return state change timestamp
- */
- public long outlineColor(String outlineColor) {
- Color c = Turtle.getColor(outlineColor);
- if (c != null) this.outlineColor = c;
-
- output("SET OUTLINE COLOR " + c);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the turtle's outlineColor color.
- *
- * @param outlineColor Color of the turtle's outlineColor.
- * @return state change timestamp
- */
- public long outlineColor(Color outlineColor) {
- this.outlineColor = outlineColor;
- output("SET OUTLINE COLOR " + outlineColor);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the turtle's fill color.
- *
- * @param fillColor Color of the turtle's fill.
- * @return state change timestamp
- */
- public long fillColor(String fillColor) {
- Color c = Turtle.getColor(fillColor);
- if (c != null) this.fillColor = c;
-
- output("SET FILL COLOR " + c);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the turtle's fill color.
- *
- * @param fillColor Color of the turtle's fill.
- * @return state change timestamp
- */
- public long fillColor(Color fillColor) {
- this.fillColor = fillColor;
-
- output("SET FILL COLOR " + fillColor);
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Sets the shape of the turtle using the built in shapes (turtle,square,
- * rectangle,triangle,arrow,circle) or to a image.
- *
- * @param shape shapename or filename of image
- * @return state change timestamp
- */
- public long shape(String shape) {
- try {
- image = ImageIO.read(new File(shape));
- output("SET SHAPE " + shape);
- this.shapeHeight = image.getHeight();
- this.shapeWidth = image.getWidth();
- } catch (Exception e) {
- if (shapes.containsKey(shape)) {
- output("SET SHAPE " + shape);
- this.shape = shape;
- this.shapeHeight = 33;
- this.shapeWidth = 33;
- image = null;
- } else {
- System.out.println("Unrecognized filename or shape name.");
- }
- }
- //if(refreshMode!=REFRESH_MODE_ON_DEMAND)updateAll();
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- public long shapeSize(int width, int height) {
- this.shapeHeight = height;
- this.shapeWidth = width;
- output(String.format("SET SHAPE SIZE (width=%d, height=%d)", width, height));
- long timeStamp = storeCurrentState();
- return timeStamp;
- }
-
- /**
- * Put a copy of the current turtle shape on the canvas.
- *
- * @return state change timestamp
- */
- public long stamp() {
- long timeStamp = storeCurrentState(true, true, 0, null, null, null, 0, null);
- output("LEAVING STAMP");
- return timeStamp;
- }
-
- /**
- * Put a dot 3 times the size of the penWidth on the canvas.
- *
- * @return state change timestamp
- */
- public long dot() {
- long timeStamp = storeCurrentState(true, false, penWidth * 3, penColor, null, null, 0, null);
- output("LEAVING DOT");
- return timeStamp;
- }
-
- /**
- * Put a dot 3 times the size of the penWidth on the canvas.
- *
- * @param color color of dot
- * @return state change timestamp
- */
- public long dot(String color) {
- Color c = Turtle.getColor(color);
- if (c == null) c = penColor;
- output("LEAVING DOT WITH COLOR " + c);
- long timeStamp = storeCurrentState(true, false, penWidth * 3, c, null, null, 0, null);
- return timeStamp;
- }
-
- /**
- * Put a dot 3 times the size of the penWidth on the canvas.
- *
- * @param color color of dot
- * @return state change timestamp
- */
- public long dot(Color color) {
- output("LEAVING DOT WITH COLOR " + color);
- long timeStamp = storeCurrentState(true, false, penWidth * 3, color, null, null, 0, null);
- return timeStamp;
- }
-
- /**
- * Put a dot on the canvas.
- *
- * @param color color of dot
- * @param dotSize diameter of the dot
- * @return state change timestamp
- */
- public long dot(String color, double dotSize) {
- Color c = Turtle.getColor(color);
- if (c == null) c = penColor;
-
- output("LEAVING DOT WITH COLOR " + c + " DOT SIZE " + dotSize);
- long timeStamp = storeCurrentState(true, false, dotSize, c, null, null, 0, null);
- return timeStamp;
- }
-
- /**
- * Put a dot on the canvas.
- *
- * @param color color of dot
- * @param dotSize diameter of the dot
- * @return state change timestamp
- */
- public long dot(Color color, double dotSize) {
- output("LEAVING DOT WITH COLOR " + color + " DOT SIZE " + dotSize);
- long timeStamp = storeCurrentState(true, false, dotSize, color, null, null, 0, null);
- return timeStamp;
- }
-
- public long write(String text, String fontName, int fontSize, int justification, double xOffset, double yOffset) {
- return 0;
- }
-
- /**
- * Undo turtle state changes.
- *
- * @param steps the number of state changes to remove
- */
- public void undo(int steps) {
- for (int i = 0; i < steps; i++) rollback();
- lastUpdate = 0;
-
- output("UNDOING LAST " + steps + " STEPS");
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- /**
- * Undo the last turtle state change.
- */
- public void undo() {
- output("UNDO LAST STEP");
- rollback();
- lastUpdate = 0;
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- /**
- * Redo turtle state changes.
- *
- * @param steps the number of state changes to restore
- */
- public void redo(int steps) {
- output("REDO " + steps + " STEPS");
- for (int i = 0; i < steps; i++) rollforward();
- lastUpdate = 0;
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- /**
- * Redo turtle state changes.
- */
- public void redo() {
- output("REDO STEP");
- rollforward();
- lastUpdate = 0;
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- /**
- * Clears all the drawing that a turtle has done but all the turtle
- * settings remain the same. (color, location, direction, shape)
- */
- public void clear() {
- output("CLEAR DRAWING");
- synchronized (turtleLock) {
- long removeKey = 0;
- TreeMap copy_turtleStates = (TreeMap) turtleStates.clone();
- for (Map.Entry entry : copy_turtleStates.entrySet()) {
- ArrayList state = entry.getValue();
- long time = entry.getKey();
- if (getStateTurtle(state) == this) {
- if (removeKey != 0) {
- turtleStates.remove(removeKey);
- }
- removeKey = time;
-
- }
- }
- redoStates.clear();
- restoreState(removeKey);
+@SuppressWarnings({ "unchecked", "deprecation", "removal" })
+public class Turtle
+ implements
+ Runnable,
+ ActionListener,
+ MouseListener,
+ MouseMotionListener,
+ KeyListener,
+ ComponentListener,
+ MouseWheelListener {
+
+ private static ArrayList turtles;
+ private static TreeMap turtleStates;
+ private static TreeMap redoStates;
+ private static JFrame window;
+ private static JApplet applet;
+ private static JLabel draw;
+ private static int width, height;
+ private static BufferedImage offscreenImage, midscreenImage, onscreenImage;
+ private static Graphics2D offscreen, midscreen, onscreen;
+ private static BufferedImage backgroundImage;
+ private static Color backgroundColor;
+ private static ImageIcon icon;
+ private static Turtle turtle;
+ private static HashMap shapes; //You can only add. Never remove.
+ private static HashMap colors;
+ private static HashMap> keyBindings;
+ private static HashMap> mouseBindings;
+ private static double centerX, centerY;
+ private static double scale;
+ private static TreeSet keysDown;
+ private static TreeSet processedKeys;
+ private static TreeSet unprocessedKeys;
+ private static long lastUpdate;
+ private static long fps;
+ private static final Object turtleLock = new Object();
+ private static int dragx = 0, dragy = 0, x = 0, y = 0, modifiers = 0;
+ private static final Object keyLock = new Object();
+ private static final int REFRESH_MODE_ANIMATED = 0;
+ private static final int REFRESH_MODE_STATE_CHANGE = 1;
+ private static final int REFRESH_MODE_ON_DEMAND = 2;
+ private static int refreshMode;
+ private static final int BACKGROUND_MODE_STRETCH = 0;
+ private static final int BACKGROUND_MODE_CENTER = 1;
+ private static final int BACKGROUND_MODE_TILE = 2;
+ private static final int BACKGROUND_MODE_CENTER_RELATIVE = 3;
+ private static final int BACKGROUND_MODE_TILE_RELATIVE = 4;
+ private static int backgroundMode;
+ private static Turtle selectedTurtle;
+ private static boolean running;
+
+ // Output if accessibility mode is turned on
+ private static PrintStream out;
+
+ static {
+ init();
+ }
+
+ /**
+ * This is an internal method that should never be called.
+ */
+ public void run() {
+ if (Thread.currentThread().getName().equals("render")) renderLoop();
+ else if (Thread.currentThread().getName().equals("listen")) eventLoop();
+ }
+
+ private void eventLoop() {
+ //System.out.println("EVENT LOOP STARTED");
+ long time = 0;
+ while (running) {
+ time = System.nanoTime();
+ processKeys();
+ waitUntil(time + 1000000000 / fps);
+ }
+ }
+
+ private void renderLoop() {
+ //System.out.println("RENDER LOOP STARTED");
+ long time = 0;
+ while (running) {
+ time = System.nanoTime();
+ //System.out.println(time);
+ if (refreshMode == REFRESH_MODE_ANIMATED) draw();
+ if (!waitUntil(time + 1000000000 / fps)) fps--;
+ else if (fps < 30) fps++;
+ }
+ }
+
+ private static boolean waitUntil(Long time) {
+ long now = System.nanoTime();
+ if (now < time) {
+ try {
+ Thread.sleep((time - now) / 1000000);
+ } catch (Exception e) {}
+ return true;
+ } else return false;
+ }
+
+ private static void init() {
+ //mouseBindings.put(null, new ArrayList());
+ turtles = new ArrayList();
+ turtleStates = new TreeMap();
+ redoStates = new TreeMap();
+ width = 500;
+ height = 500;
+ backgroundColor = Color.WHITE;
+ keyBindings = new HashMap>();
+ mouseBindings = new HashMap>();
+ centerX = 0;
+ centerY = 0;
+ scale = 1;
+ keysDown = new TreeSet();
+ processedKeys = new TreeSet();
+ unprocessedKeys = new TreeSet();
+ lastUpdate = 0;
+ fps = 30;
+ dragx = 0;
+ dragy = 0;
+ x = 0;
+ y = 0;
+ modifiers = 0;
+ refreshMode = REFRESH_MODE_ANIMATED;
+ backgroundMode = BACKGROUND_MODE_TILE_RELATIVE;
+ selectedTurtle = null;
+ running = true;
+
+ window = new JFrame("Turtle");
+ icon = new ImageIcon();
+ setupBuffering();
+ draw = new JLabel(icon);
+ window.setContentPane(draw);
+ //window.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
+ try {
+ window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ } catch (Exception e) {}
+
+ JMenuBar menuBar = new JMenuBar();
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+ JMenuItem menuItem1 = new JMenuItem("Save...");
+
+ menuItem1.setAccelerator(
+ KeyStroke.getKeyStroke(
+ KeyEvent.VK_S,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
+ )
+ );
+ menu.add(menuItem1);
+ window.setJMenuBar(menuBar);
+ window.pack();
+ window.requestFocusInWindow();
+
+ //! TODO: Fix this :)
+ try {
+ Thread.sleep(5000);
+ } catch (Exception e) {}
+
+ drawTurtleIcon();
+ window.setVisible(true);
+
+ makeShapes();
+ turtle = new Turtle(0);
+ draw.setFocusable(true);
+ menuItem1.addActionListener(turtle);
+ window.addComponentListener(turtle);
+ draw.addComponentListener(turtle);
+ draw.addMouseListener(turtle);
+ draw.addMouseMotionListener(turtle);
+ draw.addMouseWheelListener(turtle);
+ window.addKeyListener(turtle);
+ draw.addKeyListener(turtle);
+ draw.requestFocus();
+ initColors();
+
+ // Printing for accessibility default is off
+ accessiblePrinting(false);
+
+ // GraphicsEnvironment ge;
+ // ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ // String[] fontNames = ge.getAvailableFontFamilyNames();
+ // System.out.println(Arrays.toString(fontNames));
+
+ (new Thread(turtle, "render")).start();
+ (new Thread(turtle, "listen")).start();
+ }
+
+ /**
+ * Turn accessible printing on or off.
+ * When accessible printing is turned on, every turtle command that could result
+ * in a visual graphical upate will also be printed to the console as text.
+ *
+ * @param printToConsole true
to turn on accessible printing, or
+ * false
to turn off accessible printing
+ */
+ public static void accessiblePrinting(boolean printToConsole) {
+ if (printToConsole) {
+ if (out != System.out) {
+ out = System.out;
+ out.println(
+ "Printing instructions and position information," +
+ " with position information in two dimensional coordinates"
+ );
+ }
+ } else {
+ out = new PrintStream(
+ new OutputStream() {
+ public void write(int b) {
+ //DO NOTHING
+ }
}
- lastUpdate = 0;
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- private void rollback() {
- int steps = 0;
-
- synchronized (turtleLock) {
- long removeKey = 0;
- long restoreTime = 0;
- for (Map.Entry entry : turtleStates.descendingMap().entrySet()) {
- ArrayList state = entry.getValue();
- long time = entry.getKey();
- if (getStateTurtle(state) == this) {
- if (steps == 0) {
- removeKey = time;
- steps += 1;
- } else {
- restoreTime = time;
- break;
- }
- }
- }
- if (removeKey != 0 && restoreTime != 0) {
- restoreState(restoreTime);
- redoStates.put(removeKey, turtleStates.remove(removeKey));
- }
+ );
+ }
+ }
+
+ public static void exit() {
+ running = false;
+ window.setVisible(false);
+ window.dispose();
+ }
+
+ /**
+ * This is an experimental method that should allow you to make turtle
+ * applets in the future. For now, it doesn't work because the key and
+ * mouse bindings require reflection and applets think that allowing
+ * reflection would open a security hole. Theoretically in the init method
+ * of the applet you need to place Turtle.startApplet(this);
.
+ * This is not currently working.
+ *
+ * @param applet applet
+ */
+ public static void startApplet(JApplet applet) {
+ //turtleStates.clear();
+ //turtles.clear();
+ //init();
+ Turtle.applet = applet;
+ applet.setContentPane(window.getContentPane());
+ window.setVisible(false);
+ try {
+ (new Thread((Runnable) applet, "turtle")).start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void initColors() {
+ colors = new HashMap();
+ colors.put("aliceblue", new Color(0xf0f8ff));
+ colors.put("antiquewhite", new Color(0xfaebd7));
+ colors.put("aqua", new Color(0x00ffff));
+ colors.put("aquamarine", new Color(0x7fffd4));
+ colors.put("azure", new Color(0xf0ffff));
+ colors.put("beige", new Color(0xf5f5dc));
+ colors.put("bisque", new Color(0xffe4c4));
+ colors.put("black", new Color(0x000000));
+ colors.put("blanchedalmond", new Color(0xffebcd));
+ colors.put("blue", new Color(0x0000ff));
+ colors.put("blueviolet", new Color(0x8a2be2));
+ colors.put("brown", new Color(0xa52a2a));
+ colors.put("burlywood", new Color(0xdeb887));
+ colors.put("cadetblue", new Color(0x5f9ea0));
+ colors.put("chartreuse", new Color(0x7fff00));
+ colors.put("chocolate", new Color(0xd2691e));
+ colors.put("coral", new Color(0xff7f50));
+ colors.put("cornflowerblue", new Color(0x6495ed));
+ colors.put("cornsilk", new Color(0xfff8dc));
+ colors.put("crimson", new Color(0xdc143c));
+ colors.put("cyan", new Color(0x00ffff));
+ colors.put("darkblue", new Color(0x00008b));
+ colors.put("darkcyan", new Color(0x008b8b));
+ colors.put("darkgoldenrod", new Color(0xb8860b));
+ colors.put("darkgray", new Color(0xa9a9a9));
+ colors.put("darkgreen", new Color(0x006400));
+ colors.put("darkkhaki", new Color(0xbdb76b));
+ colors.put("darkmagenta", new Color(0x8b008b));
+ colors.put("darkolivegreen", new Color(0x556b2f));
+ colors.put("darkorange", new Color(0xff8c00));
+ colors.put("darkorchid", new Color(0x9932cc));
+ colors.put("darkred", new Color(0x8b0000));
+ colors.put("darksalmon", new Color(0xe9967a));
+ colors.put("darkseagreen", new Color(0x8fbc8f));
+ colors.put("darkslateblue", new Color(0x483d8b));
+ colors.put("darkslategray", new Color(0x2f4f4f));
+ colors.put("darkturquoise", new Color(0x00ced1));
+ colors.put("darkviolet", new Color(0x9400d3));
+ colors.put("deeppink", new Color(0xff1493));
+ colors.put("deepskyblue", new Color(0x00bfff));
+ colors.put("dimgray", new Color(0x696969));
+ colors.put("dodgerblue", new Color(0x1e90ff));
+ colors.put("firebrick", new Color(0xb22222));
+ colors.put("floralwhite", new Color(0xfffaf0));
+ colors.put("forestgreen", new Color(0x228b22));
+ colors.put("fuchsia", new Color(0xff00ff));
+ colors.put("gainsboro", new Color(0xdcdcdc));
+ colors.put("ghostwhite", new Color(0xf8f8ff));
+ colors.put("gold", new Color(0xffd700));
+ colors.put("goldenrod", new Color(0xdaa520));
+ colors.put("gray", new Color(0x808080));
+ colors.put("green", new Color(0x008000));
+ colors.put("greenyellow", new Color(0xadff2f));
+ colors.put("honeydew", new Color(0xf0fff0));
+ colors.put("hotpink", new Color(0xff69b4));
+ colors.put("indianred", new Color(0xcd5c5c));
+ colors.put("indigo", new Color(0x4b0082));
+ colors.put("ivory", new Color(0xfffff0));
+ colors.put("khaki", new Color(0xf0e68c));
+ colors.put("lavender", new Color(0xe6e6fa));
+ colors.put("lavenderblush", new Color(0xfff0f5));
+ colors.put("lawngreen", new Color(0x7cfc00));
+ colors.put("lemonchiffon", new Color(0xfffacd));
+ colors.put("lightblue", new Color(0xadd8e6));
+ colors.put("lightcoral", new Color(0xf08080));
+ colors.put("lightcyan", new Color(0xe0ffff));
+ colors.put("lightgoldenrodyellow", new Color(0xfafad2));
+ colors.put("lightgreen", new Color(0x90ee90));
+ colors.put("lightgrey", new Color(0xd3d3d3));
+ colors.put("lightpink", new Color(0xffb6c1));
+ colors.put("lightsalmon", new Color(0xffa07a));
+ colors.put("lightseagreen", new Color(0x20b2aa));
+ colors.put("lightskyblue", new Color(0x87cefa));
+ colors.put("lightslategray", new Color(0x778899));
+ colors.put("lightsteelblue", new Color(0xb0c4de));
+ colors.put("lightyellow", new Color(0xffffe0));
+ colors.put("lime", new Color(0x00ff00));
+ colors.put("limegreen", new Color(0x32cd32));
+ colors.put("linen", new Color(0xfaf0e6));
+ colors.put("magenta", new Color(0xff00ff));
+ colors.put("maroon", new Color(0x800000));
+ colors.put("mediumaquamarine", new Color(0x66cdaa));
+ colors.put("mediumblue", new Color(0x0000cd));
+ colors.put("mediumorchid", new Color(0xba55d3));
+ colors.put("mediumpurple", new Color(0x9370db));
+ colors.put("mediumseagreen", new Color(0x3cb371));
+ colors.put("mediumslateblue", new Color(0x7b68ee));
+ colors.put("mediumspringgreen", new Color(0x00fa9a));
+ colors.put("mediumturquoise", new Color(0x48d1cc));
+ colors.put("mediumvioletred", new Color(0xc71585));
+ colors.put("midnightblue", new Color(0x191970));
+ colors.put("mintcream", new Color(0xf5fffa));
+ colors.put("mistyrose", new Color(0xffe4e1));
+ colors.put("moccasin", new Color(0xffe4b5));
+ colors.put("navajowhite", new Color(0xffdead));
+ colors.put("navy", new Color(0x000080));
+ colors.put("oldlace", new Color(0xfdf5e6));
+ colors.put("olive", new Color(0x808000));
+ colors.put("olivedrab", new Color(0x6b8e23));
+ colors.put("orange", new Color(0xffa500));
+ colors.put("orangered", new Color(0xff4500));
+ colors.put("orchid", new Color(0xda70d6));
+ colors.put("palegoldenrod", new Color(0xeee8aa));
+ colors.put("palegreen", new Color(0x98fb98));
+ colors.put("paleturquoise", new Color(0xafeeee));
+ colors.put("palevioletred", new Color(0xdb7093));
+ colors.put("papayawhip", new Color(0xffefd5));
+ colors.put("peachpuff", new Color(0xffdab9));
+ colors.put("peru", new Color(0xcd853f));
+ colors.put("pink", new Color(0xffc0cb));
+ colors.put("plum", new Color(0xdda0dd));
+ colors.put("powderblue", new Color(0xb0e0e6));
+ colors.put("purple", new Color(0x800080));
+ colors.put("red", new Color(0xff0000));
+ colors.put("rosybrown", new Color(0xbc8f8f));
+ colors.put("royalblue", new Color(0x4169e1));
+ colors.put("saddlebrown", new Color(0x8b4513));
+ colors.put("salmon", new Color(0xfa8072));
+ colors.put("sandybrown", new Color(0xf4a460));
+ colors.put("seagreen", new Color(0x2e8b57));
+ colors.put("seashell", new Color(0xfff5ee));
+ colors.put("sienna", new Color(0xa0522d));
+ colors.put("silver", new Color(0xc0c0c0));
+ colors.put("skyblue", new Color(0x87ceeb));
+ colors.put("slateblue", new Color(0x6a5acd));
+ colors.put("slategray", new Color(0x708090));
+ colors.put("snow", new Color(0xfffafa));
+ colors.put("springgreen", new Color(0x00ff7f));
+ colors.put("steelblue", new Color(0x4682b4));
+ colors.put("tan", new Color(0xd2b48c));
+ colors.put("teal", new Color(0x008080));
+ colors.put("thistle", new Color(0xd8bfd8));
+ colors.put("tomato", new Color(0xff6347));
+ colors.put("turquoise", new Color(0x40e0d0));
+ colors.put("violet", new Color(0xee82ee));
+ colors.put("wheat", new Color(0xf5deb3));
+ colors.put("white", new Color(0xffffff));
+ colors.put("whitesmoke", new Color(0xf5f5f5));
+ colors.put("yellow", new Color(0xffff00));
+ colors.put("yellowgreen", new Color(0x9acd32));
+ }
+
+ private static Color getColor(String color) {
+ String origColor = color;
+ color = color.toLowerCase().replaceAll("[^a-z]", "");
+ if (colors.containsKey(color)) {
+ return colors.get(color);
+ } else {
+ return null;
+ }
+ }
+
+ private static void setupBuffering() {
+ synchronized (turtleLock) {
+ lastUpdate = 0;
+ offscreenImage = new BufferedImage(
+ width,
+ height,
+ BufferedImage.TYPE_INT_ARGB
+ );
+ midscreenImage = new BufferedImage(
+ width,
+ height,
+ BufferedImage.TYPE_INT_ARGB
+ );
+ onscreenImage = new BufferedImage(
+ width,
+ height,
+ BufferedImage.TYPE_INT_ARGB
+ );
+ offscreen = offscreenImage.createGraphics();
+ midscreen = midscreenImage.createGraphics();
+ onscreen = onscreenImage.createGraphics();
+ //offscreen.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
+ //offscreen.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ offscreen.setRenderingHint(
+ RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON
+ );
+ midscreen.setRenderingHint(
+ RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON
+ );
+ onscreen.setRenderingHint(
+ RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON
+ );
+ drawBackground(offscreen);
+ drawBackground(onscreen);
+ icon.setImage(onscreenImage);
+ }
+ }
+
+ private static void drawTurtleIcon() {
+ byte[] imageData = new byte[] {
+ 71,
+ 73,
+ 70,
+ 56,
+ 57,
+ 97,
+ 16,
+ 0,
+ 16,
+ 0,
+ -95,
+ 2,
+ 0,
+ 0,
+ -103,
+ 0,
+ 0,
+ -1,
+ 0,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ 33,
+ -7,
+ 4,
+ 1,
+ 10,
+ 0,
+ 2,
+ 0,
+ 44,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16,
+ 0,
+ 16,
+ 0,
+ 0,
+ 2,
+ 44,
+ -108,
+ -113,
+ -87,
+ -53,
+ -19,
+ -33,
+ -128,
+ 4,
+ 104,
+ 74,
+ 35,
+ 67,
+ -72,
+ 34,
+ -21,
+ 11,
+ 124,
+ 27,
+ -90,
+ -107,
+ -109,
+ 72,
+ 117,
+ -91,
+ -71,
+ 110,
+ 103,
+ -37,
+ 90,
+ -31,
+ -10,
+ -55,
+ -87,
+ 122,
+ -34,
+ 74,
+ 72,
+ -15,
+ 17,
+ -56,
+ -127,
+ 8,
+ 33,
+ 5,
+ 0,
+ 59,
+ };
+ try {
+ BufferedImage tmpicon = ImageIO.read(new ByteArrayInputStream(imageData));
+ window.setIconImage(tmpicon);
+ } catch (Exception e) {}
+ }
+
+ private static void makeShapes() {
+ shapes = new HashMap();
+ int[] xs = new int[] {
+ 66,
+ 65,
+ 63,
+ 61,
+ 53,
+ 44,
+ 33,
+ 24,
+ 23,
+ 19,
+ 17,
+ 14,
+ 9,
+ 8,
+ 8,
+ 10,
+ 13,
+ 11,
+ 10,
+ 2,
+ 9,
+ 11,
+ 15,
+ 11,
+ 11,
+ 10,
+ 12,
+ 18,
+ 20,
+ 22,
+ 23,
+ 26,
+ 35,
+ 44,
+ 53,
+ 61,
+ 62,
+ 64,
+ 66,
+ 71,
+ 77,
+ 78,
+ 77,
+ 76,
+ 72,
+ 77,
+ 81,
+ 86,
+ 91,
+ 94,
+ 97,
+ 98,
+ 97,
+ 95,
+ 92,
+ 87,
+ 82,
+ 77,
+ 72,
+ 74,
+ 77,
+ 78,
+ 76,
+ 70,
+ };
+ int[] ys = new int[] {
+ 18,
+ 19,
+ 21,
+ 25,
+ 23,
+ 22,
+ 23,
+ 27,
+ 25,
+ 21,
+ 20,
+ 21,
+ 27,
+ 30,
+ 32,
+ 34,
+ 37,
+ 42,
+ 47,
+ 50,
+ 53,
+ 59,
+ 65,
+ 68,
+ 69,
+ 71,
+ 74,
+ 79,
+ 80,
+ 80,
+ 78,
+ 74,
+ 77,
+ 78,
+ 77,
+ 75,
+ 79,
+ 81,
+ 82,
+ 81,
+ 76,
+ 73,
+ 71,
+ 69,
+ 66,
+ 59,
+ 60,
+ 61,
+ 60,
+ 58,
+ 54,
+ 50,
+ 46,
+ 42,
+ 40,
+ 39,
+ 40,
+ 41,
+ 34,
+ 32,
+ 28,
+ 27,
+ 24,
+ 19,
+ };
+ Polygon p = new Polygon(xs, ys, xs.length);
+ shapes.put("turtle", p);
+ xs = new int[] { 0, 100, 0, 20 };
+ ys = new int[] { 0, 50, 100, 50 };
+ p = new Polygon(xs, ys, xs.length);
+ shapes.put("arrow", p);
+ xs = new int[] { 0, 100, 100, 0 };
+ ys = new int[] { 0, 0, 100, 100 };
+ p = new Polygon(xs, ys, xs.length);
+ shapes.put("rectangle", p);
+ shapes.put("square", p);
+ xs = new int[] { 0, 100, 0 };
+ ys = new int[] { 0, 50, 100 };
+ p = new Polygon(xs, ys, xs.length);
+ shapes.put("triangle", p);
+ int divisions = 24;
+ xs = new int[divisions];
+ ys = new int[divisions];
+ for (int i = 0; i < divisions; i++) {
+ double angle = Math.toRadians((i * 360.0) / divisions);
+ xs[i] = (int) Math.round(50 + 50 * Math.cos(angle));
+ ys[i] = (int) Math.round(50 + 50 * Math.sin(angle));
+ }
+ p = new Polygon(xs, ys, xs.length);
+ shapes.put("circle", p);
+ }
+
+ /* .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U U U U U
+ * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ TURTLE CONSTRUCTION_/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U
+ * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U U U U U
+ */
+
+ /**
+ * This is a internal constuctor that makes a singleton that does the
+ * listening but is not added to the stack of turtles to be rendered.
+ * You don't need to use this outside of the Turtle.java file.
+ *
+ * @param i Pass this any integer. It doesn't do anything.
+ */
+ private Turtle(int i) {}
+
+ private Point2D.Double location = new Point2D.Double(0, 0);
+ private double direction = 0; //degrees
+ private String shape = "turtle"; //Stores a key to the shapes hashmap
+ private BufferedImage image = null;
+ private double shapeWidth = 33;
+ private double shapeHeight = 33;
+ private double tilt = 0;
+ private double penWidth = 2;
+ private Color penColor = Color.BLACK;
+ private double outlineWidth = 2;
+ private Color outlineColor = Color.BLACK;
+ private Color fillColor = new Color(0, 255, 0, 128);
+ private double speed = 50; //milliseconds to execute a move
+ private boolean isPenDown = true;
+ private boolean isFilling = false;
+ private boolean isVisible = true;
+ private ArrayList polygon = new ArrayList();
+ //temporary storage
+ private Long _time;
+ private Point2D.Double _location;
+ private Double _direction;
+ private String _shape;
+ private BufferedImage _image;
+ private Double _shapeWidth;
+ private Double _shapeHeight;
+ private Double _tilt;
+ private Double _penWidth;
+ private Color _penColor;
+ private Double _outlineWidth;
+ private Color _outlineColor;
+ private Color _fillColor;
+ private Double _speed;
+ private Boolean _isPenDown;
+ private Boolean _isFilling;
+ private Boolean _isVisible;
+ private ArrayList _polygon;
+ private Boolean _isFill;
+ private Boolean _isStamp;
+ private Double _dotSize;
+ private Color _dotColor;
+ private Font _font;
+ private String _text;
+ private Integer _justification;
+ private Point2D.Double _textOffset;
+
+ //secondary temporary storage
+ private Long __time;
+ private Point2D.Double __location;
+ private Double __direction;
+ private String __shape;
+ private BufferedImage __image;
+ private Double __shapeWidth;
+ private Double __shapeHeight;
+ private Double __tilt;
+ private Double __penWidth;
+ private Color __penColor;
+ private Double __outlineWidth;
+ private Color __outlineColor;
+ private Color __fillColor;
+ private Double __speed;
+ private Boolean __isPenDown;
+ private Boolean __isFilling;
+ private Boolean __isVisible;
+ private ArrayList __polygon;
+ private Boolean __isFill;
+ private Boolean __isStamp;
+ private Double __dotSize;
+ private Color __dotColor;
+ private Font __font;
+ private String __text;
+ private Integer __justification;
+ private Point2D.Double __textOffset;
+
+ /**
+ * Makes a turtle at the center of the canvas at location (0, 0).
+ *
+ * Turtle t = new Turtle();
+ *
+ */
+ public Turtle() {
+ if (window == null) init();
+ synchronized (turtleLock) {
+ turtles.add(this);
+ }
+ long time = storeCurrentState();
+ updateAll();
+ }
+
+ /**
+ * Makes a turtle at the specified position.
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ */
+ public Turtle(double x, double y) {
+ if (window == null) init();
+ location = new Point2D.Double(x, y);
+ synchronized (turtleLock) {
+ turtles.add(this);
+ }
+ long time = storeCurrentState();
+ updateAll();
+ }
+
+ /**
+ * This creates a cloned copy of a turtle.
+ *
+ * @return a cloned copy of a turtle
+ */
+ public Turtle clone() {
+ Turtle t = new Turtle(0);
+ t.location = (Point2D.Double) this.location.clone();
+ t.direction = this.direction;
+ t.shape = t.shape;
+ t.image = this.image;
+ t.shapeWidth = this.shapeWidth;
+ t.shapeHeight = this.shapeHeight;
+ t.tilt = this.tilt;
+ t.penWidth = this.penWidth;
+ t.penColor = this.penColor;
+ t.outlineWidth = this.outlineWidth;
+ t.outlineColor = this.outlineColor;
+ t.fillColor = this.fillColor;
+ t.speed = this.speed;
+ t.isPenDown = this.isPenDown;
+ t.isFilling = this.isFilling;
+ t.isVisible = this.isVisible;
+ if (window == null) init();
+ synchronized (turtleLock) {
+ turtles.add(t);
+ }
+ long time = t.storeCurrentState();
+ return t;
+ }
+
+ /* .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U U U U U
+ * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ STATE MANAGEMENT _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U
+ * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U U U U U
+ */
+
+ private long storeCurrentState() {
+ return storeCurrentState(false, false, 0, null, null, null, 0, null);
+ }
+
+ private long storeAnimatedState() {
+ return storeCurrentState(true, false, 0, null, null, null, 0, null);
+ }
+
+ private long storeCurrentState(
+ boolean animate,
+ boolean isStamp,
+ double dotSize,
+ Color dotColor,
+ Font font,
+ String text,
+ int justification,
+ Point2D.Double textOffset
+ ) {
+ ArrayList state = new ArrayList();
+ long time = System.nanoTime();
+ synchronized (turtleLock) {
+ state.add(0); //0
+ state.add(this); //1
+ state.add(location.clone()); //2
+ state.add(direction); //3
+ state.add(shape); //4
+ state.add(image); //5
+ state.add(shapeWidth); //6
+ state.add(shapeHeight); //7
+ state.add(tilt); //8
+ state.add(penWidth); //9
+ state.add(penColor); //10
+ state.add(outlineWidth); //11
+ state.add(outlineColor); //12
+ state.add(fillColor); //13
+ state.add(speed); //14
+ state.add(isPenDown); //15
+ state.add(isFilling); //16
+ state.add(isVisible); //17
+ state.add(isStamp); //18
+ state.add(dotSize); //19
+ state.add(dotColor); //20
+ state.add(font); //21
+ state.add(text); //22
+ state.add(justification); //23
+ state.add(textOffset); //24
+ if (!turtleStates.isEmpty() && turtleStates.lastKey() > time) time =
+ turtleStates.lastKey() + 1;
+ if (animate) time += (long) (speed * 1000000);
+ state.set(0, time);
+ turtleStates.put(time, state);
+ redoStates.clear();
+ }
+ if (refreshMode == REFRESH_MODE_STATE_CHANGE) draw();
+ if (refreshMode == REFRESH_MODE_ANIMATED) waitUntil(time);
+ return time;
+ }
+
+ private static void clearStorage() {
+ synchronized (turtleLock) {
+ for (Turtle t : turtles) {
+ t.__time = null;
+ t.__location = null;
+ t.__direction = null;
+ t.__shape = null;
+ t.__image = null;
+ t.__shapeWidth = null;
+ t.__shapeHeight = null;
+ t.__tilt = null;
+ t.__penWidth = null;
+ t.__penColor = null;
+ t.__outlineWidth = null;
+ t.__outlineColor = null;
+ t.__fillColor = null;
+ t.__speed = null;
+ t.__isPenDown = null;
+ t.__isFilling = null;
+ t.__isVisible = null;
+ t.__isStamp = null;
+ t.__dotSize = null;
+ t.__dotColor = null;
+ t.__font = null;
+ t.__text = null;
+ t.__justification = null;
+ t.__textOffset = null;
+ t._time = null;
+ t._location = null;
+ t._direction = null;
+ t._shape = null;
+ t._shapeWidth = null;
+ t._shapeHeight = null;
+ t._image = null;
+ t._tilt = null;
+ t._penWidth = null;
+ t._penColor = null;
+ t._outlineWidth = null;
+ t._outlineColor = null;
+ t._fillColor = null;
+ t._speed = null;
+ t._isPenDown = null;
+ t._isFilling = null;
+ t._isVisible = null;
+ t._isStamp = null;
+ t._dotSize = null;
+ t._dotColor = null;
+ t._font = null;
+ t._text = null;
+ t._justification = null;
+ t._textOffset = null;
+ }
+ }
+ }
+
+ private static void retrieveState(long time) {
+ synchronized (turtleLock) {
+ Turtle t = getStateTurtle(turtleStates.get(time));
+ t.__time = t._time;
+ t.__location = t._location;
+ t.__direction = t._direction;
+ t.__shape = t._shape;
+ t.__image = t._image;
+ t.__shapeWidth = t._shapeWidth;
+ t.__shapeHeight = t._shapeHeight;
+ t.__tilt = t._tilt;
+ t.__penWidth = t._penWidth;
+ t.__penColor = t._penColor;
+ t.__outlineWidth = t._outlineWidth;
+ t.__outlineColor = t._outlineColor;
+ t.__fillColor = t._fillColor;
+ t.__speed = t._speed;
+ t.__isPenDown = t._isPenDown;
+ t.__isFilling = t._isFilling;
+ t.__isVisible = t._isVisible;
+ t.__isStamp = t._isStamp;
+ t.__dotSize = t._dotSize;
+ t.__dotColor = t._dotColor;
+ t.__font = t._font;
+ t.__text = t._text;
+ t.__justification = t._justification;
+ t.__textOffset = t._textOffset;
+ ArrayList state = turtleStates.get(time);
+ t._time = getStateTime(state);
+ t._location = getStateLocation(state);
+ t._direction = getStateDirection(state);
+ t._shape = getStateShape(state);
+ t._shapeWidth = getStateShapeWidth(state);
+ t._shapeHeight = getStateShapeHeight(state);
+ t._image = getStateImage(state);
+ t._tilt = getStateTilt(state);
+ t._penWidth = getStatePenWidth(state);
+ t._penColor = getStatePenColor(state);
+ t._outlineWidth = getStateOutlineWidth(state);
+ t._outlineColor = getStateOutlineColor(state);
+ t._fillColor = getStateFillColor(state);
+ t._speed = getStateSpeed(state);
+ t._isPenDown = getStateIsPenDown(state);
+ t._isFilling = getStateIsFilling(state);
+ t._isVisible = getStateIsVisible(state);
+ t._isStamp = getStateIsStamp(state);
+ t._dotSize = getStateDotSize(state);
+ t._dotColor = getStateDotColor(state);
+ t._font = getStateFont(state);
+ t._text = getStateText(state);
+ t._justification = getStateJustification(state);
+ t._textOffset = getStateTextOffset(state);
+ }
+ }
+
+ private static long getStateTime(ArrayList state) {
+ return (Long) state.get(0);
+ }
+
+ private static Turtle getStateTurtle(ArrayList state) {
+ return (Turtle) state.get(1);
+ }
+
+ private static Point2D.Double getStateLocation(ArrayList state) {
+ return (Point2D.Double) ((Point2D.Double) state.get(2)).clone();
+ }
+
+ private static double getStateDirection(ArrayList state) {
+ return (Double) state.get(3);
+ }
+
+ private static String getStateShape(ArrayList state) {
+ return (String) state.get(4);
+ }
+
+ private static BufferedImage getStateImage(ArrayList state) {
+ return (BufferedImage) state.get(5);
+ }
+
+ private static double getStateShapeWidth(ArrayList state) {
+ return (Double) state.get(6);
+ }
+
+ private static double getStateShapeHeight(ArrayList state) {
+ return (Double) state.get(7);
+ }
+
+ private static double getStateTilt(ArrayList state) {
+ return (Double) state.get(8);
+ }
+
+ private static double getStatePenWidth(ArrayList state) {
+ return (Double) state.get(9);
+ }
+
+ private static Color getStatePenColor(ArrayList state) {
+ return (Color) state.get(10);
+ }
+
+ private static double getStateOutlineWidth(ArrayList state) {
+ return (Double) state.get(11);
+ }
+
+ private static Color getStateOutlineColor(ArrayList state) {
+ return (Color) state.get(12);
+ }
+
+ private static Color getStateFillColor(ArrayList state) {
+ return (Color) state.get(13);
+ }
+
+ private static double getStateSpeed(ArrayList state) {
+ return (Double) state.get(14);
+ }
+
+ private static boolean getStateIsPenDown(ArrayList state) {
+ return (Boolean) state.get(15);
+ }
+
+ private static boolean getStateIsFilling(ArrayList state) {
+ return (Boolean) state.get(16);
+ }
+
+ private static boolean getStateIsVisible(ArrayList state) {
+ return (Boolean) state.get(17);
+ }
+
+ private static boolean getStateIsStamp(ArrayList state) {
+ return (Boolean) state.get(18);
+ }
+
+ private static double getStateDotSize(ArrayList state) {
+ return (Double) state.get(19);
+ }
+
+ private static Color getStateDotColor(ArrayList state) {
+ return (Color) state.get(20);
+ }
+
+ private static Font getStateFont(ArrayList state) {
+ return (Font) state.get(21);
+ }
+
+ private static String getStateText(ArrayList state) {
+ return (String) state.get(22);
+ }
+
+ private static int getStateJustification(ArrayList state) {
+ return (Integer) state.get(23);
+ }
+
+ private static Point2D.Double getStateTextOffset(ArrayList state) {
+ return (Point2D.Double) state.get(24);
+ }
+
+ private static void restoreState(long time) {
+ ArrayList state = turtleStates.get(time);
+ Turtle t = getStateTurtle(turtleStates.get(time));
+ t.location = getStateLocation(state);
+ t.direction = getStateDirection(state);
+ t.shape = getStateShape(state);
+ t.shapeWidth = getStateShapeWidth(state);
+ t.shapeHeight = getStateShapeHeight(state);
+ t.image = getStateImage(state);
+ t.tilt = getStateTilt(state);
+ t.penWidth = getStatePenWidth(state);
+ t.penColor = getStatePenColor(state);
+ t.outlineWidth = getStateOutlineWidth(state);
+ t.outlineColor = getStateOutlineColor(state);
+ t.fillColor = getStateFillColor(state);
+ t.speed = getStateSpeed(state);
+ t.isPenDown = getStateIsPenDown(state);
+ t.isFilling = getStateIsFilling(state);
+ t.isVisible = getStateIsVisible(state);
+ if (refreshMode == REFRESH_MODE_STATE_CHANGE) draw();
+ }
+
+ private void select() {
+ selectedTurtle = this;
+ }
+
+ private void unselect() {
+ if (selectedTurtle == this) selectedTurtle = null;
+ }
+
+ private void output(String message) {
+ out.println("Instruction: " + message);
+ out.printf("Current Pos: (%.3f, %.3f)\n", location.getX(), location.getY());
+ }
+
+ /**
+ * Determines if a turtle is covering a screen position
+ *
+ * @param x x screen coordinate
+ * @param y y screen coordinate
+ * @return true if this turtle is at the indicated screen position.
+ */
+ public boolean contains(int x, int y) {
+ Point2D.Double point = new Point2D.Double(x, y);
+ if (_location == null) return false;
+ AffineTransform m = offscreen.getTransform();
+ double x1, y1, dir1;
+ x1 = _location.x;
+ y1 = _location.y;
+ dir1 = _direction;
+ m.translate(
+ ((x1 - centerX) * scale + width / 2),
+ ((y1 - centerY) * (-scale) + height / 2)
+ );
+ m.scale(scale, scale);
+ if (image == null) {
+ m.rotate(-Math.toRadians(dir1));
+ m.scale(shapeWidth / 100.0, shapeHeight / 100.0);
+ m.translate(-50, -50);
+ Polygon p = shapes.get(shape);
+ GeneralPath gp = new GeneralPath();
+ gp.append(p.getPathIterator(m), false);
+ return gp.contains(x, y);
+ } else {
+ int w = image.getWidth();
+ int h = image.getHeight();
+ m.rotate(-Math.toRadians(dir1));
+ m.scale(shapeWidth / 1.0 / w, shapeHeight / 1.0 / h);
+ m.translate(-w / 2, -h / 2);
+ try {
+ m.inverseTransform(point, point);
+ } catch (Exception e) {
+ return false;
+ }
+ x = (int) point.x;
+ y = (int) point.y;
+ try {
+ //System.out.println((new Color(image.getRGB(x, y),true)).getAlpha());
+ return (new Color(image.getRGB(x, y), true)).getAlpha() > 50;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ }
+
+ /* .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U U U U U
+ * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ TURTLE METHODS _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U
+ * .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*) .-./*)
+ * _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/ _/___\/
+ * U U U U U U U U U U U U U U U U
+ */
+
+ /**
+ * Gets the speed of the animation.
+ * @return milliseconds it takes to do one action
+ */
+ public double getSpeed() {
+ return speed;
+ }
+
+ /**
+ * Sets the speed of the animation.
+ *
+ *
+ * Turtle t = new Turtle();
+ * t.speed(1000);
+ * t.forward(100); // takes 1000 ms (1 second) to move forward 100 units
+ * t.forward(5); // takes 1000 ms (1 second) to move forward 5 units
+ * t.speed(100);
+ * t.left(90); // takes 100 ms (0.1 second) to turn left 90 degrees
+ *
+ *
+ * @param delay milliseconds it takes to do one action
+ * @return state change timestamp
+ */
+ public long speed(double delay) {
+ this.speed = delay;
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Moves the turtle forward by the given distance. Each unit of distance
+ * is one pixel at the default zoom level.
+ *
+ * The example below constructs a turtle and moves it forward.
+ * If the canvas is zoomed to the default zoom level, then the
+ * distance moved is 50 pixels.
+ *
+ *
+ * Turtle t = new Turtle();
+ * t.forward(50);
+ *
+ *
+ * @param distance number of units to move forward
+ * @return state change timestamp
+ */
+ public long forward(double distance) {
+ double angle = Math.toRadians(direction);
+ Point2D.Double pastLocation = (Point2D.Double) location.clone();
+ location.x += distance * Math.cos(angle);
+ location.y += distance * Math.sin(angle);
+ long timeStamp = storeAnimatedState();
+
+ output("MOVE FORWARD " + distance);
+ return timeStamp;
+ }
+
+ /**
+ * Moves the turtle backward by the given distance. Each unit of distance is one
+ * pixel at the default zoom level.
+ *
+ * @param distance number of units to move forward
+ * @return state change timestamp
+ */
+ public long backward(double distance) {
+ double angle = Math.toRadians(direction);
+ Point2D.Double pastLocation = (Point2D.Double) location.clone();
+ location.x -= distance * Math.cos(angle);
+ location.y -= distance * Math.sin(angle);
+ long timeStamp = storeAnimatedState();
+
+ output("MOVE BACKWARD " + distance);
+ return timeStamp;
+ }
+
+ /**
+ * Turns the turtle left by the number of indicated degrees.
+ *
+ * @param angle angle in degrees
+ * @return state change timestamp
+ */
+ public long left(double angle) {
+ direction += angle;
+ long timeStamp = storeAnimatedState();
+
+ output("TURN LEFT " + angle);
+ return timeStamp;
+ }
+
+ /**
+ * Turns the turtle right by the number of indicated degrees.
+ *
+ * @param angle angle in degrees
+ * @return state change timestamp
+ */
+ public long right(double angle) {
+ direction -= angle;
+ long timeStamp = storeAnimatedState();
+
+ output("TURN RIGHT " + angle);
+ return timeStamp;
+ }
+
+ /**
+ * Gets the direction the turtle is facing neglecting tilt.
+ *
+ * @return state change timestamp
+ */
+ public double getDirection() {
+ double a = direction;
+ while (a >= 360) a -= 360;
+ while (a < 0) a += 360;
+ return a;
+ }
+
+ /**
+ * Sets the direction the turtle is facing neglecting tilt.
+ *
+ * @param direction angle counter-clockwise from east
+ * @return state change timestamp
+ */
+ public long setDirection(double direction) {
+ double a = direction;
+ while (this.direction - a > 180) a += 360;
+ while (this.direction - a < -180) a -= 360;
+ this.direction = a;
+ //this.direction=direction;
+ long timeStamp = storeAnimatedState();
+
+ output("SET DIRECTION " + a);
+ return timeStamp;
+ }
+
+ /**
+ * Moves the turtle to (0,0) and facing east.
+ *
+ * @return state change timestamp
+ */
+ public long home() {
+ output("MOVE HOME");
+ return setPosition(0, 0, 0);
+ }
+
+ /**
+ * Hides the turtle but it can still draw.
+ *
+ * @return state change timestamp
+ */
+ public long hide() {
+ isVisible = false;
+ output("HIDING TURTLE");
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Makes the turtle visible.
+ *
+ * @return state change timestamp
+ */
+ public long show() {
+ isVisible = true;
+ output("SHOWING TURTLE");
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the direction in such a way that it faces (x,y)
+ *
+ * @param x x coordinate of target location
+ * @param y y coordinate of target location
+ * @return state change timestamp
+ */
+ public long face(double x, double y) {
+ return setDirection(towards(x, y));
+ }
+
+ /**
+ * Gets direction towards (x,y)
+ *
+ * @param x x coordinate of target location
+ * @param y y coordinate of target location
+ * @return angle in degrees where 0 <= angle <
+ */
+ public double towards(double x, double y) {
+ return Math.toDegrees(Math.atan2(y - location.y, x - location.x));
+ }
+
+ /**
+ * Gets the distance to another position.
+ *
+ * @param x x coordinate of target location
+ * @param y y coordinate of target location
+ * @return distance between turtle's current location and another position
+ */
+ public double distance(double x, double y) {
+ return Math.sqrt(
+ (y - location.y) * (y - location.y) + (x - location.x) * (x - location.x)
+ );
+ }
+
+ /**
+ * Gets the x coordinate of the turtle.
+ *
+ * @return x coordinate
+ */
+ public double getX() {
+ return location.x;
+ }
+
+ /**
+ * Gets the y coordinate of the turtle.
+ *
+ * @return y coordinate
+ */
+ public double getY() {
+ return location.y;
+ }
+
+ /**
+ * Sets the position and direction of a turtle.
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ * @param direction angle counter-clockwise from east in degrees
+ * @return state change timestamp
+ */
+ public long setPosition(double x, double y, double direction) {
+ location.x = x;
+ location.y = y;
+ double a = direction;
+ while (this.direction - a > 180) a += 360;
+ while (this.direction - a < -180) a -= 360;
+ this.direction = a;
+ this.direction = direction;
+
+ output(
+ String.format("SET POSITION (%f, %f) DIRECTION %f", x, y, direction)
+ );
+ long timeStamp = storeAnimatedState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the position of a turtle.
+ *
+ * @param x x coordinate
+ * @param y y coordinate
+ * @return state change timestamp
+ */
+ public long setPosition(double x, double y) {
+ return setPosition(x, y, direction);
+ }
+
+ /**
+ * Adds an additional angle to rotation of the turtle's shape when rendering.
+ * This is useful when you need to face a different direction than the
+ * direction you are moving in.
+ *
+ * @param angle angle in degrees
+ * @return state change timestamp
+ */
+ public long tilt(double angle) {
+ tilt += angle;
+
+ output("ADD TILT " + angle);
+
+ long timeStamp = storeAnimatedState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the angle to rotate the turtle's shape when rendering.
+ * This is useful when you need to face a different direction than the
+ * direction you are moving in.
+ *
+ * @param angle angle in degrees
+ * @return state change timestamp
+ */
+ public long setTilt(double angle) {
+ //double a=angle;
+ //while(tilt-a>180)a+=360;
+ //while(tilt-a<-180)a-=360;
+ //tilt=a;
+ tilt = angle;
+
+ output("SET TILT " + angle);
+
+ long timeStamp = storeAnimatedState();
+ return timeStamp;
+ }
+
+ /**
+ * Gets the rotation of the turtle's shape away from the turtle's direction.
+ *
+ * @return tilt in degrees (positive in counter-clockwise)
+ */
+ public double getTilt() {
+ return tilt;
+ }
+
+ /**
+ * Sets the width of the turtle's pen. Each unit of width corresponds to
+ * 1 pixel at the default zoom level.
+ *
+ *
+ * @param penWidth number of units wide
+ * @return state change timestamp
+ */
+ public long width(double penWidth) {
+ this.penWidth = penWidth;
+
+ output("SET PEN WIDTH " + penWidth);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the width of the turtle's outline.
+ *
+ * @param width width of the turtle's outline
+ * @return state change timestamp
+ */
+ public long outlineWidth(double width) {
+ this.outlineWidth = width;
+
+ output("SET OUTLINE WIDTH " + width);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Picks the turtle's pen up so it won't draw on the screen as it moves.
+ *
+ * @return state change timestamp
+ */
+ public long up() {
+ this.isPenDown = false;
+ output("LIFT PEN");
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Puts the turtle's pen down so it will draw on the screen as it moves.
+ *
+ * @return state change timestamp
+ */
+ public long down() {
+ this.isPenDown = true;
+ output("LOWER PEN");
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ public long stab() {
+ Color c = Turtle.getColor("red");
+ if (c != null) this.penColor = c;
+ this.isPenDown = true;
+
+ output("STAB");
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the turtle's path color.
+ *
+ * @param penColor Color of the turtle's path.
+ * @return state change timestamp
+ */
+ public long penColor(String penColor) {
+ Color c = Turtle.getColor(penColor);
+ if (c != null) this.penColor = c;
+ output("SET PEN COLOR " + c);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the turtle's path color.
+ *
+ * @param penColor Color of the turtle's path.
+ * @return state change timestamp
+ */
+ public long penColor(Color penColor) {
+ this.penColor = penColor;
+
+ output("SET PEN COLOR " + penColor);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the turtle's outlineColor color.
+ *
+ * @param outlineColor Color of the turtle's outlineColor.
+ * @return state change timestamp
+ */
+ public long outlineColor(String outlineColor) {
+ Color c = Turtle.getColor(outlineColor);
+ if (c != null) this.outlineColor = c;
+
+ output("SET OUTLINE COLOR " + c);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the turtle's outlineColor color.
+ *
+ * @param outlineColor Color of the turtle's outlineColor.
+ * @return state change timestamp
+ */
+ public long outlineColor(Color outlineColor) {
+ this.outlineColor = outlineColor;
+ output("SET OUTLINE COLOR " + outlineColor);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the turtle's fill color.
+ *
+ * @param fillColor Color of the turtle's fill.
+ * @return state change timestamp
+ */
+ public long fillColor(String fillColor) {
+ Color c = Turtle.getColor(fillColor);
+ if (c != null) this.fillColor = c;
+
+ output("SET FILL COLOR " + c);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the turtle's fill color.
+ *
+ * @param fillColor Color of the turtle's fill.
+ * @return state change timestamp
+ */
+ public long fillColor(Color fillColor) {
+ this.fillColor = fillColor;
+
+ output("SET FILL COLOR " + fillColor);
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Sets the shape of the turtle using the built in shapes (turtle,square,
+ * rectangle,triangle,arrow,circle) or to a image.
+ *
+ * @param shape shapename or filename of image
+ * @return state change timestamp
+ */
+ public long shape(String shape) {
+ try {
+ image = ImageIO.read(new File(shape));
+ output("SET SHAPE " + shape);
+ this.shapeHeight = image.getHeight();
+ this.shapeWidth = image.getWidth();
+ } catch (Exception e) {
+ if (shapes.containsKey(shape)) {
+ output("SET SHAPE " + shape);
+ this.shape = shape;
+ this.shapeHeight = 33;
+ this.shapeWidth = 33;
+ image = null;
+ } else {
+ System.out.println("Unrecognized filename or shape name.");
+ }
+ }
+ //if(refreshMode!=REFRESH_MODE_ON_DEMAND)updateAll();
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ public long shapeSize(int width, int height) {
+ this.shapeHeight = height;
+ this.shapeWidth = width;
+ output(
+ String.format("SET SHAPE SIZE (width=%d, height=%d)", width, height)
+ );
+ long timeStamp = storeCurrentState();
+ return timeStamp;
+ }
+
+ /**
+ * Put a copy of the current turtle shape on the canvas.
+ *
+ * @return state change timestamp
+ */
+ public long stamp() {
+ long timeStamp = storeCurrentState(
+ true,
+ true,
+ 0,
+ null,
+ null,
+ null,
+ 0,
+ null
+ );
+ output("LEAVING STAMP");
+ return timeStamp;
+ }
+
+ /**
+ * Put a dot 3 times the size of the penWidth on the canvas.
+ *
+ * @return state change timestamp
+ */
+ public long dot() {
+ long timeStamp = storeCurrentState(
+ true,
+ false,
+ penWidth * 3,
+ penColor,
+ null,
+ null,
+ 0,
+ null
+ );
+ output("LEAVING DOT");
+ return timeStamp;
+ }
+
+ /**
+ * Put a dot 3 times the size of the penWidth on the canvas.
+ *
+ * @param color color of dot
+ * @return state change timestamp
+ */
+ public long dot(String color) {
+ Color c = Turtle.getColor(color);
+ if (c == null) c = penColor;
+ output("LEAVING DOT WITH COLOR " + c);
+ long timeStamp = storeCurrentState(
+ true,
+ false,
+ penWidth * 3,
+ c,
+ null,
+ null,
+ 0,
+ null
+ );
+ return timeStamp;
+ }
+
+ /**
+ * Put a dot 3 times the size of the penWidth on the canvas.
+ *
+ * @param color color of dot
+ * @return state change timestamp
+ */
+ public long dot(Color color) {
+ output("LEAVING DOT WITH COLOR " + color);
+ long timeStamp = storeCurrentState(
+ true,
+ false,
+ penWidth * 3,
+ color,
+ null,
+ null,
+ 0,
+ null
+ );
+ return timeStamp;
+ }
+
+ /**
+ * Put a dot on the canvas.
+ *
+ * @param color color of dot
+ * @param dotSize diameter of the dot
+ * @return state change timestamp
+ */
+ public long dot(String color, double dotSize) {
+ Color c = Turtle.getColor(color);
+ if (c == null) c = penColor;
+
+ output("LEAVING DOT WITH COLOR " + c + " DOT SIZE " + dotSize);
+ long timeStamp = storeCurrentState(
+ true,
+ false,
+ dotSize,
+ c,
+ null,
+ null,
+ 0,
+ null
+ );
+ return timeStamp;
+ }
+
+ /**
+ * Put a dot on the canvas.
+ *
+ * @param color color of dot
+ * @param dotSize diameter of the dot
+ * @return state change timestamp
+ */
+ public long dot(Color color, double dotSize) {
+ output("LEAVING DOT WITH COLOR " + color + " DOT SIZE " + dotSize);
+ long timeStamp = storeCurrentState(
+ true,
+ false,
+ dotSize,
+ color,
+ null,
+ null,
+ 0,
+ null
+ );
+ return timeStamp;
+ }
+
+ public long write(
+ String text,
+ String fontName,
+ int fontSize,
+ int justification,
+ double xOffset,
+ double yOffset
+ ) {
+ return 0;
+ }
+
+ /**
+ * Undo turtle state changes.
+ *
+ * @param steps the number of state changes to remove
+ */
+ public void undo(int steps) {
+ for (int i = 0; i < steps; i++) rollback();
+ lastUpdate = 0;
+
+ output("UNDOING LAST " + steps + " STEPS");
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ /**
+ * Undo the last turtle state change.
+ */
+ public void undo() {
+ output("UNDO LAST STEP");
+ rollback();
+ lastUpdate = 0;
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ /**
+ * Redo turtle state changes.
+ *
+ * @param steps the number of state changes to restore
+ */
+ public void redo(int steps) {
+ output("REDO " + steps + " STEPS");
+ for (int i = 0; i < steps; i++) rollforward();
+ lastUpdate = 0;
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ /**
+ * Redo turtle state changes.
+ */
+ public void redo() {
+ output("REDO STEP");
+ rollforward();
+ lastUpdate = 0;
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ /**
+ * Clears all the drawing that a turtle has done but all the turtle
+ * settings remain the same. (color, location, direction, shape)
+ */
+ public void clear() {
+ output("CLEAR DRAWING");
+ synchronized (turtleLock) {
+ long removeKey = 0;
+ TreeMap copy_turtleStates = (TreeMap<
+ Long,
+ ArrayList
+ >) turtleStates.clone();
+ for (Map.Entry entry : copy_turtleStates.entrySet()) {
+ ArrayList state = entry.getValue();
+ long time = entry.getKey();
+ if (getStateTurtle(state) == this) {
+ if (removeKey != 0) {
+ turtleStates.remove(removeKey);
+ }
+ removeKey = time;
}
- }
-
- private void rollforward() {
- synchronized (turtleLock) {
- for (Map.Entry entry : redoStates.entrySet()) {
- ArrayList state = entry.getValue();
- long time = entry.getKey();
- if (getStateTurtle(state) == this) {
- turtleStates.put(entry.getKey(), redoStates.remove(entry.getKey()));
- restoreState(time);
- return;
- }
- }
+ }
+ redoStates.clear();
+ restoreState(removeKey);
+ }
+ lastUpdate = 0;
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ private void rollback() {
+ int steps = 0;
+
+ synchronized (turtleLock) {
+ long removeKey = 0;
+ long restoreTime = 0;
+ for (Map.Entry entry : turtleStates
+ .descendingMap()
+ .entrySet()) {
+ ArrayList state = entry.getValue();
+ long time = entry.getKey();
+ if (getStateTurtle(state) == this) {
+ if (steps == 0) {
+ removeKey = time;
+ steps += 1;
+ } else {
+ restoreTime = time;
+ break;
+ }
}
- }
-
- /**
- * This specifies when the screen gets refreshed.
- * 0(default)=Animated (The turtle will slide from one state to another without being jerky.)
- * 1=State Change (The turtle will refresh immediately to the last state. Jerky motion.)
- * 2=On Demand (The turtle will refresh only when you call update())
- *
- * @param mode refresh mode
- */
- public static void refreshMode(int mode) {
- refreshMode = mode;
- updateAll();
- }
-
- /**
- * This specifies how the background is drawn.
- * 0=The image if present is stretched to fill the screen.
- * 1=The image is centered on the middle of the screen and will not scale/pan
- * 2=The image is tiled and will not scale/pan
- * 3=The image is centered on (0,0) and will scale/pan
- * 4(default)=The image is tiled and will scale/pan
- *
- * @param mode background mode
- */
- public static void backgroundMode(int mode) {
- backgroundMode = mode;
- updateAll();
- }
-
- /**
- * Sets the background color.
- *
- * @param color Color of the background.
- */
- public static void bgcolor(String color) {
- Color c = Turtle.getColor(color);
- if (c != null) backgroundColor = c;
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- /**
- * Sets the background color.
- *
- * @param color Color of the background.
- */
- public static void bgcolor(Color color) {
- backgroundColor = color;
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- /**
- * Set the background image.
- *
- * @param filename filename for a background image
- */
- public static void bgpic(String filename) {
- try {
- backgroundImage = ImageIO.read(new File(filename));
- } catch (Exception e) {
- e.printStackTrace();
+ }
+ if (removeKey != 0 && restoreTime != 0) {
+ restoreState(restoreTime);
+ redoStates.put(removeKey, turtleStates.remove(removeKey));
+ }
+ }
+ }
+
+ private void rollforward() {
+ synchronized (turtleLock) {
+ for (Map.Entry entry : redoStates.entrySet()) {
+ ArrayList state = entry.getValue();
+ long time = entry.getKey();
+ if (getStateTurtle(state) == this) {
+ turtleStates.put(entry.getKey(), redoStates.remove(entry.getKey()));
+ restoreState(time);
+ return;
}
- if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
- }
-
- private static boolean addMouseBinding(String methodName, Turtle t, boolean append, boolean click, boolean repeat) {
- String className = "";
- try {
- throw new Exception("Who called me?");
- } catch (Exception e) {
- className = e.getStackTrace()[2].getClassName();
- }
- try {
- boolean works = false;
- for (Method m : Class.forName(className).getDeclaredMethods()) {
- if (m.getName().equals(methodName)) {
- //System.out.println(m);
- works = true;
- for (Class paramType : m.getParameterTypes()) {
- //System.out.println(paramType.getName());
- if (!paramType.getName().equals("double") && !paramType.getName().equals("java.lang.Double") && !paramType.getName().equals("Turtle")) {
- works = false;
- break;
- }
- }
- if (works) break;
- }
- }
- if (works) {
- //System.out.println("Method found!");
- } else {
- System.out.println("ERROR");
- return false;
- }
- } catch (Exception e) {
- System.out.println("Calling Class not found.");
- return false;
- }
- if (!append || !mouseBindings.containsKey(t)) mouseBindings.put(t, new ArrayList());
- ArrayList binding = new ArrayList();
- binding.add(t);
- binding.add(className);
- binding.add(methodName);
- binding.add(click);
- binding.add(repeat);
- mouseBindings.get(t).add(binding);
- return true;
- }
-
- private boolean addKeyBinding(String methodName, String keyText, boolean append, boolean repeat) {
- keyText = keyText.toLowerCase();
- String className = "";
- try {
- throw new Exception("Who called me?");
- } catch (Exception e) {
- className = e.getStackTrace()[2].getClassName();
- }
- try {
- boolean works = false;
- for (Method m : Class.forName(className).getDeclaredMethods()) {
- if (m.getName().equals(methodName)) {
- //System.out.println(m);
- works = true;
- for (Class paramType : m.getParameterTypes()) {
- //System.out.println(paramType.getName());
- if (!paramType.getName().equals("java.lang.String") && !paramType.getName().equals("Turtle")) {
- works = false;
- break;
- }
- }
- if (works) break;
- }
- }
- if (works) {
- //System.out.println("Method found!");
- } else {
- System.out.println("ERROR");
- return false;
- }
- } catch (Exception e) {
- System.out.println("Calling Class not found.");
- return false;
- }
- if (!append || !keyBindings.containsKey(keyText)) keyBindings.put(keyText, new ArrayList());
- ArrayList binding = new ArrayList();
- binding.add(this);
- binding.add(className);
- binding.add(methodName);
- binding.add(repeat);
- keyBindings.get(keyText).add(binding);
- return true;
- }
-
- /**
- * Links a method to a key.
- *
- * @param methodName method to be executed when the key is pressed
- * @param keyText key that triggers the method
- * @return boolean
- */
- public boolean onKey(String methodName, String keyText) {
- return addKeyBinding(methodName, keyText, false, false);
- }
-
- /**
- * Links a method to a key.
- *
- * @param methodName method to be executed when the key is pressed
- * @param keyText key that triggers the method
- * @param append true if you want to have multiple methods per key
- * @return boolean
- */
- public boolean onKey(String methodName, String keyText, boolean append) {
- return addKeyBinding(methodName, keyText, append, false);
- }
-
- /**
- * Links a method to a key.
- *
- * @param methodName method to be executed when the key is pressed
- * @param keyText key that triggers the method
- * @param append true if you want to have multiple methods per key
- * @param repeat true if you want call the method every screen refresh
- * @return boolean
- */
- public boolean onKey(String methodName, String keyText, boolean append, boolean repeat) {
- return addKeyBinding(methodName, keyText, append, repeat);
- }
-
- /**
- *
- * Fits the indicated box in the center of the screen as large as possible.
- *
- * @param minx left x coordinate of box
- * @param miny bottom y coordinate of box
- * @param maxx right x coordinate of box
- * @param maxy top y coordinate of box
- */
- public static void zoom(double minx, double miny, double maxx, double maxy) {
- synchronized (turtleLock) {
- centerX = (minx + maxx) / 2;
- centerY = (miny + maxy) / 2;
- if (width / (maxx - minx) > height / (maxy - miny)) scale = height / (maxy - miny);
- else scale = width / (maxx - minx);
- updateAll();
- }
- }
-
- /**
- * Fits everything on the screen.
- */
- public static void zoomFit() {
- synchronized (turtleLock) {
- Point2D.Double loc;
- if (turtleStates.isEmpty()) return;
- else loc = getStateLocation(turtleStates.firstEntry().getValue());
- double minx = loc.x, miny = loc.y;
- double maxx = minx, maxy = miny;
- double shapeWidth = 0;
- double shapeHeight = 0;
- long time = System.nanoTime();
- if (refreshMode != REFRESH_MODE_ANIMATED) time = turtleStates.lastKey() + 1;
- for (Map.Entry entry : turtleStates.headMap(time).entrySet()) {
- ArrayList state = entry.getValue();
- if (!getStateIsPenDown(state)) continue;
- Point2D.Double location = getStateLocation(state);
- if (location.x < minx) minx = location.x;
- if (location.x > maxx) maxx = location.x;
- if (location.y < miny) miny = location.y;
- if (location.y > maxy) maxy = location.y;
- shapeWidth = getStateShapeWidth(state);
- shapeHeight = getStateShapeHeight(state);
+ }
+ }
+ }
+
+ /**
+ * This specifies when the screen gets refreshed.
+ * 0(default)=Animated (The turtle will slide from one state to another without being jerky.)
+ * 1=State Change (The turtle will refresh immediately to the last state. Jerky motion.)
+ * 2=On Demand (The turtle will refresh only when you call update())
+ *
+ * @param mode refresh mode
+ */
+ public static void refreshMode(int mode) {
+ refreshMode = mode;
+ updateAll();
+ }
+
+ /**
+ * This specifies how the background is drawn.
+ * 0=The image if present is stretched to fill the screen.
+ * 1=The image is centered on the middle of the screen and will not scale/pan
+ * 2=The image is tiled and will not scale/pan
+ * 3=The image is centered on (0,0) and will scale/pan
+ * 4(default)=The image is tiled and will scale/pan
+ *
+ * @param mode background mode
+ */
+ public static void backgroundMode(int mode) {
+ backgroundMode = mode;
+ updateAll();
+ }
+
+ /**
+ * Sets the background color.
+ *
+ * @param color Color of the background.
+ */
+ public static void bgcolor(String color) {
+ Color c = Turtle.getColor(color);
+ if (c != null) backgroundColor = c;
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ /**
+ * Sets the background color.
+ *
+ * @param color Color of the background.
+ */
+ public static void bgcolor(Color color) {
+ backgroundColor = color;
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ /**
+ * Set the background image.
+ *
+ * @param filename filename for a background image
+ */
+ public static void bgpic(String filename) {
+ try {
+ backgroundImage = ImageIO.read(new File(filename));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (refreshMode != REFRESH_MODE_ON_DEMAND) updateAll();
+ }
+
+ private static boolean addMouseBinding(
+ String methodName,
+ Turtle t,
+ boolean append,
+ boolean click,
+ boolean repeat
+ ) {
+ String className = "";
+ try {
+ throw new Exception("Who called me?");
+ } catch (Exception e) {
+ className = e.getStackTrace()[2].getClassName();
+ }
+ try {
+ boolean works = false;
+ for (Method m : Class.forName(className).getDeclaredMethods()) {
+ if (m.getName().equals(methodName)) {
+ //System.out.println(m);
+ works = true;
+ for (Class paramType : m.getParameterTypes()) {
+ //System.out.println(paramType.getName());
+ if (
+ !paramType.getName().equals("double") &&
+ !paramType.getName().equals("java.lang.Double") &&
+ !paramType.getName().equals("Turtle")
+ ) {
+ works = false;
+ break;
}
-
- if (turtleStates.lastKey() > time && getStateSpeed(turtleStates.lastEntry().getValue()) > 0) {
- double percent = 1 - (turtleStates.lastKey() - time) / getStateSpeed(turtleStates.lastEntry().getValue()) / 1000000.0;
- //System.out.println("trying");
- Turtle t = getStateTurtle(turtleStates.lastEntry().getValue());
- double x1 = t._location.x, y1 = t._location.y, x2 = t.__location.x, y2 = t.__location.y;
- x1 = (x2 - x1) * percent + x1;
- y1 = (y2 - y1) * percent + y1;
- if (x1 < minx) minx = x1;
- if (x1 > maxx) maxx = x1;
- if (y1 < miny) miny = y1;
- if (y1 > maxy) maxy = y1;
- }
- double shapeMax = Math.max(shapeWidth, shapeHeight);
- zoom(minx - shapeMax / 2, miny - shapeMax / 2, maxx + shapeMax / 2, maxy + shapeMax / 2);
- }
- }
-
- private static void updateAll() {
- lastUpdate = 0;
- draw();
- }
-
- /**
- * Force redraw when the refreshMode is set to on demand.
- */
- public static void update() {
- if (refreshMode == REFRESH_MODE_ON_DEMAND) draw();
- }
-
- // Hunter: Made public for testing
- public static void draw() {
- synchronized (turtleLock) {
-
- long renderTime = System.nanoTime();
- if (turtleStates.isEmpty() || lastUpdate == 0) {
- clearStorage();
- drawBackground(offscreen);
- }
- if (turtleStates.isEmpty()) {
- onscreen.drawImage(offscreenImage, 0, 0, null);
- window.repaint();
- if (applet != null) applet.repaint();
- return;
- }
- if (refreshMode != REFRESH_MODE_ANIMATED) renderTime = turtleStates.lastKey() + 1;
- if (lastUpdate > turtleStates.lastKey()) {
- midscreen.drawImage(offscreenImage, 0, 0, null);
- for (Turtle t : turtles) {
- if (t.isVisible) t.drawStamp(1, midscreen);
- //if(t==selectedTurtle)t.drawCrossHairs(1,midscreen);
- }
- onscreen.drawImage(midscreenImage, 0, 0, null);
- window.repaint();
- if (applet != null) applet.repaint();
- return;
- }
- for (Map.Entry entry : turtleStates.tailMap(lastUpdate).headMap(renderTime).entrySet()) {
- retrieveState(entry.getKey());
- Turtle t = getStateTurtle(entry.getValue());
- t.drawLine(1, offscreen);
- if (t._isStamp) t.drawStamp(1, offscreen);
- t.drawDot(1, offscreen);
- }
-
- midscreen.drawImage(offscreenImage, 0, 0, null);
- Turtle animatedTurtle = null;
- double percent = 1;
- Long t2;
- t2 = Long.valueOf(0);
- if (renderTime < turtleStates.lastKey()) {
- animatedTurtle = getStateTurtle(turtleStates.ceilingEntry(renderTime).getValue());
- t2 = animatedTurtle._time;
- retrieveState(turtleStates.ceilingKey(renderTime));
- if (animatedTurtle._speed > 0) {
- percent = 1 - (turtleStates.ceilingKey(renderTime) - renderTime) / animatedTurtle._speed / 1000000.0;
- } else percent = 1;
- if (percent < 0) percent = 0;
- }
-
- for (Turtle t : turtles) {
- if (t == animatedTurtle) {
- //System.out.println(percent);
- t.drawLine(percent, midscreen);
- if (t._dotSize > 0) t.drawDot(percent, midscreen);
- if (t.isVisible) t.drawStamp(percent, midscreen, false);
- if (t._isStamp) t.drawStamp(percent, midscreen, true);
- //if(t==selectedTurtle)t.drawCrossHairs(percent,midscreen);
- try {
- retrieveState(t2);
- } catch (Exception e) {
- }
- } else {
- if (t.isVisible) t.drawStamp(1, midscreen);
- //if(t==selectedTurtle)t.drawCrossHairs(1,midscreen);
- }
-
- }
- lastUpdate = renderTime;
- //zoomFit();
- onscreen.drawImage(midscreenImage, 0, 0, null);
- window.repaint();
- if (applet != null) applet.repaint();
- }
-
-
- }
-
- private void drawLine(double percent, Graphics2D g) {
- if (!_isPenDown) return;
- g.setColor(_penColor);
- g.setStroke(new BasicStroke((float) (scale * _penWidth), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- if (__location != null && !__location.equals(_location)) {
- double x1 = _location.x, y1 = _location.y, x2 = __location.x, y2 = __location.y;
- if (percent < 1 && percent >= 0) {
- x1 = (x1 - x2) * percent + x2;
- y1 = (y1 - y2) * percent + y2;
- }
- //g.draw(new Line2D.Double((x1-centerX)*scale+width/2, (y1-centerY)*(-scale)+height/2, (x2-centerX)*scale+width/2, (y2-centerY)*(-scale)+height/2));
- g.drawLine((int) ((x1 - centerX) * scale + width / 2), (int) ((y1 - centerY) * (-scale) + height / 2), (int) ((x2 - centerX) * scale + width / 2), (int) ((y2 - centerY) * (-scale) + height / 2));
- }
- }
-
- private void drawStamp(double percent, Graphics2D g) {
- drawStamp(percent, g, false);
- }
-
- private void drawStamp(double percent, Graphics2D g, boolean isStamp) {
- if (_location == null) return;
- AffineTransform originalTransform = (AffineTransform) g.getTransform().clone();
- AffineTransform m = g.getTransform();
- double x1, x2, y1, y2, dir1, dir2, tilt1, tilt2;
- x1 = _location.x;
- y1 = _location.y;
- dir1 = _direction;
- tilt1 = _tilt;
- if (__location == null) {
- x2 = x1;
- y2 = y1;
- dir2 = dir1;
- tilt2 = tilt1;
- } else {
- x2 = __location.x;
- y2 = __location.y;
- dir2 = __direction;
- tilt2 = __tilt;
- }
- if (percent < 1 && percent >= 0) {
- x1 = (x1 - x2) * percent + x2;
- y1 = (y1 - y2) * percent + y2;
- dir1 = (dir1 - dir2) * percent + dir2;
- tilt1 = (tilt1 - tilt2) * percent + tilt2;
+ }
+ if (works) break;
}
- m.translate(((x1 - centerX) * scale + width / 2), ((y1 - centerY) * (-scale) + height / 2));
- if (isStamp) m.scale(scale * percent, scale * percent);
- else m.scale(scale, scale);
- if (_image == null) {
- //_outlineWidth=0.0;
- m.rotate(-Math.toRadians(dir1 + tilt1));
- m.scale(_shapeWidth / 100.0, _shapeHeight / 100.0);
- m.translate(-50, -50);
- g.setTransform(m);
- Polygon p = shapes.get(_shape);
- g.setColor(_fillColor);
- g.fillPolygon(p);
- g.setColor(_outlineColor);
- if (_outlineWidth > 0) {
- g.setStroke(new BasicStroke((float) (_outlineWidth * scale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- g.setTransform(originalTransform);
- GeneralPath gp = new GeneralPath();
- gp.append(p.getPathIterator(m), false);
- g.draw(gp);
+ }
+ if (works) {
+ //System.out.println("Method found!");
+ } else {
+ System.out.println("ERROR");
+ return false;
+ }
+ } catch (Exception e) {
+ System.out.println("Calling Class not found.");
+ return false;
+ }
+ if (!append || !mouseBindings.containsKey(t)) mouseBindings.put(
+ t,
+ new ArrayList()
+ );
+ ArrayList binding = new ArrayList();
+ binding.add(t);
+ binding.add(className);
+ binding.add(methodName);
+ binding.add(click);
+ binding.add(repeat);
+ mouseBindings.get(t).add(binding);
+ return true;
+ }
+
+ private boolean addKeyBinding(
+ String methodName,
+ String keyText,
+ boolean append,
+ boolean repeat
+ ) {
+ keyText = keyText.toLowerCase();
+ String className = "";
+ try {
+ throw new Exception("Who called me?");
+ } catch (Exception e) {
+ className = e.getStackTrace()[2].getClassName();
+ }
+ try {
+ boolean works = false;
+ for (Method m : Class.forName(className).getDeclaredMethods()) {
+ if (m.getName().equals(methodName)) {
+ //System.out.println(m);
+ works = true;
+ for (Class paramType : m.getParameterTypes()) {
+ //System.out.println(paramType.getName());
+ if (
+ !paramType.getName().equals("java.lang.String") &&
+ !paramType.getName().equals("Turtle")
+ ) {
+ works = false;
+ break;
}
- } else {
- int w = _image.getWidth();
- int h = _image.getHeight();
- m.rotate(-Math.toRadians(dir1 + tilt1));
- m.scale(_shapeWidth / 1.0 / w, _shapeHeight / 1.0 / h);
- m.translate(-w / 2, -h / 2);
- g.setTransform(m);
- g.drawImage(_image, 0, 0, null);
+ }
+ if (works) break;
}
- g.setTransform(originalTransform);
- }
-
- private void drawDot(double percent, Graphics2D g) {
- AffineTransform originalTransform = (AffineTransform) g.getTransform().clone();
- AffineTransform m = g.getTransform();
- m.translate(((_location.x - centerX) * scale + width / 2), ((_location.y - centerY) * (-scale) + height / 2));
- m.scale(scale * percent / 2, scale * percent / 2);
- g.setTransform(m);
- g.setColor(_dotColor);
- int r = (int) (_dotSize * 1.0);
- g.fillOval(-r, -r, 2 * r, 2 * r);
- g.setTransform(originalTransform);
- }
-
- private static void drawBackground(Graphics2D g) {
- g.setColor(backgroundColor);
- g.fillRect(0, 0, width, height);
- if (backgroundImage == null) return;
- int w = backgroundImage.getWidth();
- int h = backgroundImage.getHeight();
- if (backgroundMode == BACKGROUND_MODE_CENTER) {
- offscreen.drawImage(backgroundImage, (width - w) / 2, (height - h) / 2, w, h, null);
- } else if (backgroundMode == BACKGROUND_MODE_STRETCH) {
- offscreen.drawImage(backgroundImage, 0, 0, width, height, null);
- } else if (backgroundMode == BACKGROUND_MODE_CENTER_RELATIVE) {
- offscreen.drawImage(backgroundImage, (int) ((-w / 2 - centerX) * scale + width / 2), (int) ((h / 2 - centerY) * (-scale) + height / 2), (int) (w * scale), (int) (h * scale), null);
- } else if (backgroundMode == BACKGROUND_MODE_TILE) {
- for (int i = 0; i < width; i += w)
- for (int j = 0; j < height; j += h) offscreen.drawImage(backgroundImage, i, j, w, h, null);
- } else if (backgroundMode == BACKGROUND_MODE_TILE_RELATIVE) {
- double left = centerX - width / 2 / scale;
- double top = centerY + height / 2 / scale;
- double right = centerX + width / 2 / scale;
- double bottom = centerY - height / 2 / scale;
- for (double x = ((int) (left / w) - 1) * w; x <= right; x += w)
- for (double y = ((int) (bottom / h)) * h; y <= top + h; y += h)
- offscreen.drawImage(backgroundImage, (int) ((x - centerX) * scale + width / 2), (int) ((y - centerY) * (-scale) + height / 2), (int) Math.ceil(w * scale), (int) Math.ceil(h * scale), null);
+ }
+ if (works) {
+ //System.out.println("Method found!");
+ } else {
+ System.out.println("ERROR");
+ return false;
+ }
+ } catch (Exception e) {
+ System.out.println("Calling Class not found.");
+ return false;
+ }
+ if (!append || !keyBindings.containsKey(keyText)) keyBindings.put(
+ keyText,
+ new ArrayList()
+ );
+ ArrayList binding = new ArrayList();
+ binding.add(this);
+ binding.add(className);
+ binding.add(methodName);
+ binding.add(repeat);
+ keyBindings.get(keyText).add(binding);
+ return true;
+ }
+
+ /**
+ * Links a method to a key.
+ *
+ * @param methodName method to be executed when the key is pressed
+ * @param keyText key that triggers the method
+ * @return boolean
+ */
+ public boolean onKey(String methodName, String keyText) {
+ return addKeyBinding(methodName, keyText, false, false);
+ }
+
+ /**
+ * Links a method to a key.
+ *
+ * @param methodName method to be executed when the key is pressed
+ * @param keyText key that triggers the method
+ * @param append true if you want to have multiple methods per key
+ * @return boolean
+ */
+ public boolean onKey(String methodName, String keyText, boolean append) {
+ return addKeyBinding(methodName, keyText, append, false);
+ }
+
+ /**
+ * Links a method to a key.
+ *
+ * @param methodName method to be executed when the key is pressed
+ * @param keyText key that triggers the method
+ * @param append true if you want to have multiple methods per key
+ * @param repeat true if you want call the method every screen refresh
+ * @return boolean
+ */
+ public boolean onKey(
+ String methodName,
+ String keyText,
+ boolean append,
+ boolean repeat
+ ) {
+ return addKeyBinding(methodName, keyText, append, repeat);
+ }
+
+ /**
+ *
+ * Fits the indicated box in the center of the screen as large as possible.
+ *
+ * @param minx left x coordinate of box
+ * @param miny bottom y coordinate of box
+ * @param maxx right x coordinate of box
+ * @param maxy top y coordinate of box
+ */
+ public static void zoom(double minx, double miny, double maxx, double maxy) {
+ synchronized (turtleLock) {
+ centerX = (minx + maxx) / 2;
+ centerY = (miny + maxy) / 2;
+ if (width / (maxx - minx) > height / (maxy - miny)) scale = height /
+ (maxy - miny);
+ else scale = width / (maxx - minx);
+ updateAll();
+ }
+ }
+
+ /**
+ * Fits everything on the screen.
+ */
+ public static void zoomFit() {
+ synchronized (turtleLock) {
+ Point2D.Double loc;
+ if (turtleStates.isEmpty()) return;
+ else loc = getStateLocation(turtleStates.firstEntry().getValue());
+ double minx = loc.x, miny = loc.y;
+ double maxx = minx, maxy = miny;
+ double shapeWidth = 0;
+ double shapeHeight = 0;
+ long time = System.nanoTime();
+ if (refreshMode != REFRESH_MODE_ANIMATED) time = turtleStates.lastKey() +
+ 1;
+ for (Map.Entry entry : turtleStates
+ .headMap(time)
+ .entrySet()) {
+ ArrayList state = entry.getValue();
+ if (!getStateIsPenDown(state)) continue;
+ Point2D.Double location = getStateLocation(state);
+ if (location.x < minx) minx = location.x;
+ if (location.x > maxx) maxx = location.x;
+ if (location.y < miny) miny = location.y;
+ if (location.y > maxy) maxy = location.y;
+ shapeWidth = getStateShapeWidth(state);
+ shapeHeight = getStateShapeHeight(state);
+ }
+
+ if (
+ turtleStates.lastKey() > time &&
+ getStateSpeed(turtleStates.lastEntry().getValue()) > 0
+ ) {
+ double percent =
+ 1 -
+ (turtleStates.lastKey() - time) /
+ getStateSpeed(turtleStates.lastEntry().getValue()) /
+ 1000000.0;
+ //System.out.println("trying");
+ Turtle t = getStateTurtle(turtleStates.lastEntry().getValue());
+ double x1 = t._location.x, y1 = t._location.y, x2 = t.__location.x, y2 =
+ t.__location.y;
+ x1 = (x2 - x1) * percent + x1;
+ y1 = (y2 - y1) * percent + y1;
+ if (x1 < minx) minx = x1;
+ if (x1 > maxx) maxx = x1;
+ if (y1 < miny) miny = y1;
+ if (y1 > maxy) maxy = y1;
+ }
+ double shapeMax = Math.max(shapeWidth, shapeHeight);
+ zoom(
+ minx - shapeMax / 2,
+ miny - shapeMax / 2,
+ maxx + shapeMax / 2,
+ maxy + shapeMax / 2
+ );
+ }
+ }
+
+ private static void updateAll() {
+ lastUpdate = 0;
+ draw();
+ }
+
+ /**
+ * Force redraw when the refreshMode is set to on demand.
+ */
+ public static void update() {
+ if (refreshMode == REFRESH_MODE_ON_DEMAND) draw();
+ }
+
+ // Hunter: Made public for testing
+ public static void draw() {
+ synchronized (turtleLock) {
+ long renderTime = System.nanoTime();
+ if (turtleStates.isEmpty() || lastUpdate == 0) {
+ clearStorage();
+ drawBackground(offscreen);
+ }
+ if (turtleStates.isEmpty()) {
+ onscreen.drawImage(offscreenImage, 0, 0, null);
+ window.repaint();
+ if (applet != null) applet.repaint();
+ return;
+ }
+ if (refreshMode != REFRESH_MODE_ANIMATED) renderTime =
+ turtleStates.lastKey() + 1;
+ if (lastUpdate > turtleStates.lastKey()) {
+ midscreen.drawImage(offscreenImage, 0, 0, null);
+ for (Turtle t : turtles) {
+ if (t.isVisible) t.drawStamp(1, midscreen);
+ //if(t==selectedTurtle)t.drawCrossHairs(1,midscreen);
}
- }
-
- private void drawCrossHairs(double percent, Graphics2D g) {
- if (_location == null) return;
- double time = (System.nanoTime() / 100000000) / 10.0;
-
- AffineTransform originalTransform = (AffineTransform) g.getTransform().clone();
- AffineTransform m = g.getTransform();
- double x1, x2, y1, y2, dir1, dir2;
- x1 = _location.x;
- y1 = _location.y;
- if (__location == null) {
- x2 = x1;
- y2 = y1;
+ onscreen.drawImage(midscreenImage, 0, 0, null);
+ window.repaint();
+ if (applet != null) applet.repaint();
+ return;
+ }
+ for (Map.Entry entry : turtleStates
+ .tailMap(lastUpdate)
+ .headMap(renderTime)
+ .entrySet()) {
+ retrieveState(entry.getKey());
+ Turtle t = getStateTurtle(entry.getValue());
+ t.drawLine(1, offscreen);
+ if (t._isStamp) t.drawStamp(1, offscreen);
+ t.drawDot(1, offscreen);
+ }
+
+ midscreen.drawImage(offscreenImage, 0, 0, null);
+ Turtle animatedTurtle = null;
+ double percent = 1;
+ Long t2;
+ t2 = Long.valueOf(0);
+ if (renderTime < turtleStates.lastKey()) {
+ animatedTurtle = getStateTurtle(
+ turtleStates.ceilingEntry(renderTime).getValue()
+ );
+ t2 = animatedTurtle._time;
+ retrieveState(turtleStates.ceilingKey(renderTime));
+ if (animatedTurtle._speed > 0) {
+ percent = 1 -
+ (turtleStates.ceilingKey(renderTime) - renderTime) /
+ animatedTurtle._speed /
+ 1000000.0;
+ } else percent = 1;
+ if (percent < 0) percent = 0;
+ }
+
+ for (Turtle t : turtles) {
+ if (t == animatedTurtle) {
+ //System.out.println(percent);
+ t.drawLine(percent, midscreen);
+ if (t._dotSize > 0) t.drawDot(percent, midscreen);
+ if (t.isVisible) t.drawStamp(percent, midscreen, false);
+ if (t._isStamp) t.drawStamp(percent, midscreen, true);
+ //if(t==selectedTurtle)t.drawCrossHairs(percent,midscreen);
+ try {
+ retrieveState(t2);
+ } catch (Exception e) {}
} else {
- x2 = __location.x;
- y2 = __location.y;
+ if (t.isVisible) t.drawStamp(1, midscreen);
+ //if(t==selectedTurtle)t.drawCrossHairs(1,midscreen);
}
- if (percent < 1 && percent >= 0) {
- x1 = (x1 - x2) * percent + x2;
- y1 = (y1 - y2) * percent + y2;
- }
- m.translate(((x1 - centerX) * scale + width / 2), ((y1 - centerY) * (-scale) + height / 2));
- int f = 10;
- m.scale(scale / f, scale / f);
- g.setTransform(m);
-
- int period = 50;
- int r = (int) (Math.sqrt(shapeWidth * shapeWidth + shapeHeight * shapeHeight) * f / 2);
- g.setColor(new Color(255, 255, 255));
- g.setStroke(new BasicStroke((float) (6 * f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- g.drawOval(-r, -r, 2 * r, 2 * r);
- r += f;
- for (int i = 0; i < 4; i++)
- g.drawLine((int) (r * Math.cos(Math.PI / 2 * i + 2 * Math.PI * time / period)), (int) (r * Math.sin(Math.PI / 2 * i + 2 * Math.PI * time / period)),
- (int) ((r + r / 5) * Math.cos(Math.PI / 2 * i + 2 * Math.PI * time / period)), (int) ((r + r / 5) * Math.sin(Math.PI / 2 * i + 2 * Math.PI * time / period)));
- r -= f;
- g.setColor(new Color(0, 0, 0));
- g.setStroke(new BasicStroke((float) (3 * f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- g.drawOval(-r, -r, 2 * r, 2 * r);
- r += f;
- for (int i = 0; i < 4; i++)
- g.drawLine((int) (r * Math.cos(Math.PI / 2 * i + 2 * Math.PI * time / period)), (int) (r * Math.sin(Math.PI / 2 * i + 2 * Math.PI * time / period)),
- (int) ((r + r / 5) * Math.cos(Math.PI / 2 * i + 2 * Math.PI * time / period)), (int) ((r + r / 5) * Math.sin(Math.PI / 2 * i + 2 * Math.PI * time / period)));
+ }
+ lastUpdate = renderTime;
+ //zoomFit();
+ onscreen.drawImage(midscreenImage, 0, 0, null);
+ window.repaint();
+ if (applet != null) applet.repaint();
+ }
+ }
+
+ private void drawLine(double percent, Graphics2D g) {
+ if (!_isPenDown) return;
+ g.setColor(_penColor);
+ g.setStroke(
+ new BasicStroke(
+ (float) (scale * _penWidth),
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND
+ )
+ );
+ if (__location != null && !__location.equals(_location)) {
+ double x1 = _location.x, y1 = _location.y, x2 = __location.x, y2 =
+ __location.y;
+ if (percent < 1 && percent >= 0) {
+ x1 = (x1 - x2) * percent + x2;
+ y1 = (y1 - y2) * percent + y2;
+ }
+ //g.draw(new Line2D.Double((x1-centerX)*scale+width/2, (y1-centerY)*(-scale)+height/2, (x2-centerX)*scale+width/2, (y2-centerY)*(-scale)+height/2));
+ g.drawLine(
+ (int) ((x1 - centerX) * scale + width / 2),
+ (int) ((y1 - centerY) * (-scale) + height / 2),
+ (int) ((x2 - centerX) * scale + width / 2),
+ (int) ((y2 - centerY) * (-scale) + height / 2)
+ );
+ }
+ }
+
+ private void drawStamp(double percent, Graphics2D g) {
+ drawStamp(percent, g, false);
+ }
+
+ private void drawStamp(double percent, Graphics2D g, boolean isStamp) {
+ if (_location == null) return;
+ AffineTransform originalTransform = (AffineTransform) g
+ .getTransform()
+ .clone();
+ AffineTransform m = g.getTransform();
+ double x1, x2, y1, y2, dir1, dir2, tilt1, tilt2;
+ x1 = _location.x;
+ y1 = _location.y;
+ dir1 = _direction;
+ tilt1 = _tilt;
+ if (__location == null) {
+ x2 = x1;
+ y2 = y1;
+ dir2 = dir1;
+ tilt2 = tilt1;
+ } else {
+ x2 = __location.x;
+ y2 = __location.y;
+ dir2 = __direction;
+ tilt2 = __tilt;
+ }
+ if (percent < 1 && percent >= 0) {
+ x1 = (x1 - x2) * percent + x2;
+ y1 = (y1 - y2) * percent + y2;
+ dir1 = (dir1 - dir2) * percent + dir2;
+ tilt1 = (tilt1 - tilt2) * percent + tilt2;
+ }
+ m.translate(
+ ((x1 - centerX) * scale + width / 2),
+ ((y1 - centerY) * (-scale) + height / 2)
+ );
+ if (isStamp) m.scale(scale * percent, scale * percent);
+ else m.scale(scale, scale);
+ if (_image == null) {
+ //_outlineWidth=0.0;
+ m.rotate(-Math.toRadians(dir1 + tilt1));
+ m.scale(_shapeWidth / 100.0, _shapeHeight / 100.0);
+ m.translate(-50, -50);
+ g.setTransform(m);
+ Polygon p = shapes.get(_shape);
+ g.setColor(_fillColor);
+ g.fillPolygon(p);
+ g.setColor(_outlineColor);
+ if (_outlineWidth > 0) {
+ g.setStroke(
+ new BasicStroke(
+ (float) (_outlineWidth * scale),
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND
+ )
+ );
g.setTransform(originalTransform);
- }
-
- /**
- * Changes the size of the canvas effectively changing the size of the window.
- *
- * @param width width of the canvas
- * @param height height of the canvas
- */
- public static void setCanvasSize(int width, int height) {
- Turtle.width = width;
- Turtle.height = height;
- Turtle.setupBuffering();
- window.pack();
- updateAll();
- }
-
- /**
- * Saves the visible canvas to an image.
- *
- * @param filename image filename
- */
- public static void save(String filename) {
- save(new File(filename));
- }
-
- private static void save(File file) {
- 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 {
- String suffix = file.getName().substring(file.getName().lastIndexOf('.') + 1);
- if (!ImageIO.write(rgbBuffer, suffix, file)) throw new Exception("Didn't save file.");
- } catch (Exception e) {
- file.delete();
- JOptionPane.showMessageDialog(window,
- "Sorry! We can not process your request at this time.",
- "Image Save Failed",
- JOptionPane.ERROR_MESSAGE);
- }
- }
-
- /**
- * Demo program
- *
- * @param a commandline args
- */
- public static void main(String[] a) {
- //Turtle bob = new Turtle();
- /*for(int i=0;i<360;i++)
+ GeneralPath gp = new GeneralPath();
+ gp.append(p.getPathIterator(m), false);
+ g.draw(gp);
+ }
+ } else {
+ int w = _image.getWidth();
+ int h = _image.getHeight();
+ m.rotate(-Math.toRadians(dir1 + tilt1));
+ m.scale(_shapeWidth / 1.0 / w, _shapeHeight / 1.0 / h);
+ m.translate(-w / 2, -h / 2);
+ g.setTransform(m);
+ g.drawImage(_image, 0, 0, null);
+ }
+ g.setTransform(originalTransform);
+ }
+
+ private void drawDot(double percent, Graphics2D g) {
+ AffineTransform originalTransform = (AffineTransform) g
+ .getTransform()
+ .clone();
+ AffineTransform m = g.getTransform();
+ m.translate(
+ ((_location.x - centerX) * scale + width / 2),
+ ((_location.y - centerY) * (-scale) + height / 2)
+ );
+ m.scale((scale * percent) / 2, (scale * percent) / 2);
+ g.setTransform(m);
+ g.setColor(_dotColor);
+ int r = (int) (_dotSize * 1.0);
+ g.fillOval(-r, -r, 2 * r, 2 * r);
+ g.setTransform(originalTransform);
+ }
+
+ private static void drawBackground(Graphics2D g) {
+ g.setColor(backgroundColor);
+ g.fillRect(0, 0, width, height);
+ if (backgroundImage == null) return;
+ int w = backgroundImage.getWidth();
+ int h = backgroundImage.getHeight();
+ if (backgroundMode == BACKGROUND_MODE_CENTER) {
+ offscreen.drawImage(
+ backgroundImage,
+ (width - w) / 2,
+ (height - h) / 2,
+ w,
+ h,
+ null
+ );
+ } else if (backgroundMode == BACKGROUND_MODE_STRETCH) {
+ offscreen.drawImage(backgroundImage, 0, 0, width, height, null);
+ } else if (backgroundMode == BACKGROUND_MODE_CENTER_RELATIVE) {
+ offscreen.drawImage(
+ backgroundImage,
+ (int) ((-w / 2 - centerX) * scale + width / 2),
+ (int) ((h / 2 - centerY) * (-scale) + height / 2),
+ (int) (w * scale),
+ (int) (h * scale),
+ null
+ );
+ } else if (backgroundMode == BACKGROUND_MODE_TILE) {
+ for (int i = 0; i < width; i += w) for (
+ int j = 0;
+ j < height;
+ j += h
+ ) offscreen.drawImage(backgroundImage, i, j, w, h, null);
+ } else if (backgroundMode == BACKGROUND_MODE_TILE_RELATIVE) {
+ double left = centerX - width / 2 / scale;
+ double top = centerY + height / 2 / scale;
+ double right = centerX + width / 2 / scale;
+ double bottom = centerY - height / 2 / scale;
+ for (double x = ((int) (left / w) - 1) * w; x <= right; x += w) for (
+ double y = ((int) (bottom / h)) * h;
+ y <= top + h;
+ y += h
+ ) offscreen.drawImage(
+ backgroundImage,
+ (int) ((x - centerX) * scale + width / 2),
+ (int) ((y - centerY) * (-scale) + height / 2),
+ (int) Math.ceil(w * scale),
+ (int) Math.ceil(h * scale),
+ null
+ );
+ }
+ }
+
+ private void drawCrossHairs(double percent, Graphics2D g) {
+ if (_location == null) return;
+ double time = (System.nanoTime() / 100000000) / 10.0;
+
+ AffineTransform originalTransform = (AffineTransform) g
+ .getTransform()
+ .clone();
+ AffineTransform m = g.getTransform();
+ double x1, x2, y1, y2, dir1, dir2;
+ x1 = _location.x;
+ y1 = _location.y;
+ if (__location == null) {
+ x2 = x1;
+ y2 = y1;
+ } else {
+ x2 = __location.x;
+ y2 = __location.y;
+ }
+ if (percent < 1 && percent >= 0) {
+ x1 = (x1 - x2) * percent + x2;
+ y1 = (y1 - y2) * percent + y2;
+ }
+ m.translate(
+ ((x1 - centerX) * scale + width / 2),
+ ((y1 - centerY) * (-scale) + height / 2)
+ );
+ int f = 10;
+ m.scale(scale / f, scale / f);
+ g.setTransform(m);
+
+ int period = 50;
+ int r = (int) ((Math.sqrt(
+ shapeWidth * shapeWidth + shapeHeight * shapeHeight
+ ) *
+ f) /
+ 2);
+ g.setColor(new Color(255, 255, 255));
+ g.setStroke(
+ new BasicStroke(
+ (float) (6 * f),
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND
+ )
+ );
+ g.drawOval(-r, -r, 2 * r, 2 * r);
+ r += f;
+ for (int i = 0; i < 4; i++) g.drawLine(
+ (int) (r * Math.cos((Math.PI / 2) * i + (2 * Math.PI * time) / period)),
+ (int) (r * Math.sin((Math.PI / 2) * i + (2 * Math.PI * time) / period)),
+ (int) ((r + r / 5) *
+ Math.cos((Math.PI / 2) * i + (2 * Math.PI * time) / period)),
+ (int) ((r + r / 5) *
+ Math.sin((Math.PI / 2) * i + (2 * Math.PI * time) / period))
+ );
+ r -= f;
+ g.setColor(new Color(0, 0, 0));
+ g.setStroke(
+ new BasicStroke(
+ (float) (3 * f),
+ BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND
+ )
+ );
+ g.drawOval(-r, -r, 2 * r, 2 * r);
+ r += f;
+ for (int i = 0; i < 4; i++) g.drawLine(
+ (int) (r * Math.cos((Math.PI / 2) * i + (2 * Math.PI * time) / period)),
+ (int) (r * Math.sin((Math.PI / 2) * i + (2 * Math.PI * time) / period)),
+ (int) ((r + r / 5) *
+ Math.cos((Math.PI / 2) * i + (2 * Math.PI * time) / period)),
+ (int) ((r + r / 5) *
+ Math.sin((Math.PI / 2) * i + (2 * Math.PI * time) / period))
+ );
+ g.setTransform(originalTransform);
+ }
+
+ /**
+ * Changes the size of the canvas effectively changing the size of the window.
+ *
+ * @param width width of the canvas
+ * @param height height of the canvas
+ */
+ public static void setCanvasSize(int width, int height) {
+ Turtle.width = width;
+ Turtle.height = height;
+ Turtle.setupBuffering();
+ window.pack();
+ updateAll();
+ }
+
+ /**
+ * Saves the visible canvas to an image.
+ *
+ * @param filename image filename
+ */
+ public static void save(String filename) {
+ save(new File(filename));
+ }
+
+ private static void save(File file) {
+ 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 {
+ String suffix = file
+ .getName()
+ .substring(file.getName().lastIndexOf('.') + 1);
+ if (!ImageIO.write(rgbBuffer, suffix, file)) throw new Exception(
+ "Didn't save file."
+ );
+ } catch (Exception e) {
+ file.delete();
+ JOptionPane.showMessageDialog(
+ window,
+ "Sorry! We can not process your request at this time.",
+ "Image Save Failed",
+ JOptionPane.ERROR_MESSAGE
+ );
+ }
+ }
+
+ /**
+ * Demo program
+ *
+ * @param a commandline args
+ */
+ public static void main(String[] a) {
+ //Turtle bob = new Turtle();
+ /*for(int i=0;i<360;i++)
{
bob.forward(i*1.25);
bob.left(90.25);
}
*/
- /*If you don't know what a for loop is yet this is equivalent to repeating the middle 4 lines 5 times in a row.*/
- Turtle bob = new Turtle();
- bgcolor("lightblue");
- bob.penColor("red");
- bob.width(10);
- for (int i = 0; i < 200; i++) {
- bob.forward(i / 10.);
- bob.left(5);
- if (i % 10 == 0) bob.dot("orange");//Draws dots when i is a multiple of 10.
- }
- bob.saveGCODE("test.gcode");
-
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void actionPerformed(ActionEvent e) {
- if (((JMenuItem) e.getSource()).getText().equals("Save...")) {
- JFileChooser chooser = new JFileChooser(System.getProperty("user.dir"));
- chooser.setFileFilter(new FileNameExtensionFilter("Image (*.jpg, *.jpeg, *.gif, *.bmp, *.png)", "jpg", "png", "jpeg", "bmp", "gif"));
- int option = chooser.showSaveDialog(window);
- if (option == JFileChooser.APPROVE_OPTION) {
- if (chooser.getSelectedFile() != null) {
- File file = chooser.getSelectedFile();
- save(file);
- }
- }
- }
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseClicked(MouseEvent e) {
- if (e.getModifiers() == 8 && e.getClickCount() == 2) {
- centerX = 0;
- centerY = 0;
- scale = 1;
- updateAll();
- }
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseEntered(MouseEvent e) {
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseExited(MouseEvent e) {
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mousePressed(MouseEvent e) {
- dragx = e.getX();
- dragy = e.getY();
- modifiers += e.getModifiers();
- synchronized (turtleLock) {
- for (Turtle t : turtles) {
- if (t.contains(dragx, dragy)) t.select();
- else t.unselect();
- }
+ /*If you don't know what a for loop is yet this is equivalent to repeating the middle 4 lines 5 times in a row.*/
+ Turtle bob = new Turtle();
+ bgcolor("lightblue");
+ bob.penColor("red");
+ bob.width(10);
+ for (int i = 0; i < 200; i++) {
+ bob.forward(i / 10.);
+ bob.left(5);
+ if (i % 10 == 0) bob.dot("orange"); //Draws dots when i is a multiple of 10.
+ }
+ bob.saveGCODE("test.gcode");
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void actionPerformed(ActionEvent e) {
+ if (((JMenuItem) e.getSource()).getText().equals("Save...")) {
+ JFileChooser chooser = new JFileChooser(System.getProperty("user.dir"));
+ chooser.setFileFilter(
+ new FileNameExtensionFilter(
+ "Image (*.jpg, *.jpeg, *.gif, *.bmp, *.png)",
+ "jpg",
+ "png",
+ "jpeg",
+ "bmp",
+ "gif"
+ )
+ );
+ int option = chooser.showSaveDialog(window);
+ if (option == JFileChooser.APPROVE_OPTION) {
+ if (chooser.getSelectedFile() != null) {
+ File file = chooser.getSelectedFile();
+ save(file);
}
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseReleased(MouseEvent e) {
- modifiers -= e.getModifiers();
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseDragged(MouseEvent e) {
- modifiers = e.getModifiers();
- int dx, dy;
- if (e.getModifiers() == 8) {
- x = e.getX();
- dx = x - dragx;
- y = e.getY();
- dy = y - dragy;
- dragx = x;
- dragy = y;
- synchronized (turtleLock) {
- centerX -= dx * 1.0 / scale;
- centerY += dy * 1.0 / scale;
- }
- updateAll();
- }
- this.x = e.getX();
- this.y = e.getY();
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseMoved(MouseEvent e) {
- modifiers = e.getModifiers();
- x = e.getX();
- y = e.getY();
-
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void keyTyped(KeyEvent e) {
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void keyPressed(KeyEvent e) {
- String keyText = KeyEvent.getKeyText(e.getKeyCode()).toLowerCase();
- synchronized (keyLock) {
- keysDown.add(keyText);
- if (keyBindings.containsKey(keyText)) {
- unprocessedKeys.add(keyText);
- }
- }
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void keyReleased(KeyEvent e) {
- String keyText = KeyEvent.getKeyText(e.getKeyCode()).toLowerCase();
- synchronized (keyLock) {
- keysDown.remove(keyText);
- processedKeys.remove(keyText);
- }
- }
-
- private void processKeys() {
- //System.out.println(keysDown);
- TreeSet keysDownCopy = new TreeSet();
- synchronized (keyLock) {
- keysDownCopy = (TreeSet) keysDown.clone();
- }
- keysDownCopy.addAll(unprocessedKeys);
- for (String keyText : keysDownCopy) {
- if (keyBindings.containsKey(keyText)) {
- for (ArrayList binding : keyBindings.get(keyText)) {
- Turtle t = (Turtle) binding.get(0);
- String className = (String) binding.get(1);
- String methodName = (String) binding.get(2);
- Boolean repeat = (Boolean) binding.get(3);
- if (!repeat && processedKeys.contains(keyText)) break;
- unprocessedKeys.remove(keyText);
- processedKeys.add(keyText);
- try {
- Class cls = Class.forName(className);
- Object clsInstance = (Object) cls.newInstance();
- Method m = clsInstance.getClass().getMethod(methodName, t.getClass());
- m.invoke(clsInstance, t);
- } catch (Exception e1) {
- try {
- Class cls = Class.forName(className);
- Object clsInstance = (Object) cls.newInstance();
- Method m = clsInstance.getClass().getMethod(methodName, t.getClass(), keyText.getClass());
- m.invoke(clsInstance, t, keyText);
- } catch (Exception e2) {
- try {
- Class cls = Class.forName(className);
- Object clsInstance = (Object) cls.newInstance();
- Method m = clsInstance.getClass().getMethod(methodName);
- m.invoke(clsInstance);
- } catch (Exception e3) {
- System.out.println("KeyBinding for " + keyText + " has failed.");
- e1.printStackTrace();
- e2.printStackTrace();
- e3.printStackTrace();
- }
- }
- }
- }
+ }
+ }
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseClicked(MouseEvent e) {
+ if (e.getModifiers() == 8 && e.getClickCount() == 2) {
+ centerX = 0;
+ centerY = 0;
+ scale = 1;
+ updateAll();
+ }
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseEntered(MouseEvent e) {}
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseExited(MouseEvent e) {}
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mousePressed(MouseEvent e) {
+ dragx = e.getX();
+ dragy = e.getY();
+ modifiers += e.getModifiers();
+ synchronized (turtleLock) {
+ for (Turtle t : turtles) {
+ if (t.contains(dragx, dragy)) t.select();
+ else t.unselect();
+ }
+ }
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseReleased(MouseEvent e) {
+ modifiers -= e.getModifiers();
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseDragged(MouseEvent e) {
+ modifiers = e.getModifiers();
+ int dx, dy;
+ if (e.getModifiers() == 8) {
+ x = e.getX();
+ dx = x - dragx;
+ y = e.getY();
+ dy = y - dragy;
+ dragx = x;
+ dragy = y;
+ synchronized (turtleLock) {
+ centerX -= (dx * 1.0) / scale;
+ centerY += (dy * 1.0) / scale;
+ }
+ updateAll();
+ }
+ this.x = e.getX();
+ this.y = e.getY();
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseMoved(MouseEvent e) {
+ modifiers = e.getModifiers();
+ x = e.getX();
+ y = e.getY();
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void keyTyped(KeyEvent e) {}
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void keyPressed(KeyEvent e) {
+ String keyText = KeyEvent.getKeyText(e.getKeyCode()).toLowerCase();
+ synchronized (keyLock) {
+ keysDown.add(keyText);
+ if (keyBindings.containsKey(keyText)) {
+ unprocessedKeys.add(keyText);
+ }
+ }
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void keyReleased(KeyEvent e) {
+ String keyText = KeyEvent.getKeyText(e.getKeyCode()).toLowerCase();
+ synchronized (keyLock) {
+ keysDown.remove(keyText);
+ processedKeys.remove(keyText);
+ }
+ }
+
+ private void processKeys() {
+ //System.out.println(keysDown);
+ TreeSet keysDownCopy = new TreeSet();
+ synchronized (keyLock) {
+ keysDownCopy = (TreeSet) keysDown.clone();
+ }
+ keysDownCopy.addAll(unprocessedKeys);
+ for (String keyText : keysDownCopy) {
+ if (keyBindings.containsKey(keyText)) {
+ for (ArrayList binding : keyBindings.get(keyText)) {
+ Turtle t = (Turtle) binding.get(0);
+ String className = (String) binding.get(1);
+ String methodName = (String) binding.get(2);
+ Boolean repeat = (Boolean) binding.get(3);
+ if (!repeat && processedKeys.contains(keyText)) break;
+ unprocessedKeys.remove(keyText);
+ processedKeys.add(keyText);
+ try {
+ Class cls = Class.forName(className);
+ Object clsInstance = (Object) cls.newInstance();
+ Method m = clsInstance
+ .getClass()
+ .getMethod(methodName, t.getClass());
+ m.invoke(clsInstance, t);
+ } catch (Exception e1) {
+ try {
+ Class cls = Class.forName(className);
+ Object clsInstance = (Object) cls.newInstance();
+ Method m = clsInstance
+ .getClass()
+ .getMethod(methodName, t.getClass(), keyText.getClass());
+ m.invoke(clsInstance, t, keyText);
+ } catch (Exception e2) {
+ try {
+ Class cls = Class.forName(className);
+ Object clsInstance = (Object) cls.newInstance();
+ Method m = clsInstance.getClass().getMethod(methodName);
+ m.invoke(clsInstance);
+ } catch (Exception e3) {
+ System.out.println(
+ "KeyBinding for " + keyText + " has failed."
+ );
+ e1.printStackTrace();
+ e2.printStackTrace();
+ e3.printStackTrace();
+ }
}
+ }
}
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void componentHidden(ComponentEvent e) {
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void componentMoved(ComponentEvent e) {
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void componentResized(ComponentEvent e) {
- width = (int) draw.getBounds().getWidth();
- height = (int) draw.getBounds().getHeight();
- setupBuffering();
- updateAll();
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void componentShown(ComponentEvent e) {
- }
-
- /**
- * Internal mehod for handling events.
- * @param e event
- */
- public void mouseWheelMoved(MouseWheelEvent e) {
- int notches = e.getWheelRotation();
- double ds = Math.pow(1.1, notches);
- x = e.getX();
- y = e.getY();
- double dx = width / 2 - x;
- double dy = height / 2 - y;
- synchronized (turtleLock) {
- centerX -= (dx * ds - dx) / scale / ds;
- centerY += (dy * ds - dy) / scale / ds;
- scale *= ds;
+ }
+ }
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void componentHidden(ComponentEvent e) {}
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void componentMoved(ComponentEvent e) {}
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void componentResized(ComponentEvent e) {
+ width = (int) draw.getBounds().getWidth();
+ height = (int) draw.getBounds().getHeight();
+ setupBuffering();
+ updateAll();
+ }
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void componentShown(ComponentEvent e) {}
+
+ /**
+ * Internal mehod for handling events.
+ * @param e event
+ */
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ int notches = e.getWheelRotation();
+ double ds = Math.pow(1.1, notches);
+ x = e.getX();
+ y = e.getY();
+ double dx = width / 2 - x;
+ double dy = height / 2 - y;
+ synchronized (turtleLock) {
+ centerX -= (dx * ds - dx) / scale / ds;
+ centerY += (dy * ds - dy) / scale / ds;
+ scale *= ds;
+ }
+ updateAll();
+ }
+
+ /**
+ * Get the pressed keys.
+ *
+ * @return a list of pressed keys
+ */
+ public static String[] keysDown() {
+ return keysDown.toArray(new String[] {});
+ }
+
+ /**
+ * Test if a key is pressed or not.
+ *
+ * @param key key you are testing
+ * @return true if the key is pressed
+ */
+ public static boolean isKeyDown(String key) {
+ return keysDown.contains(key);
+ }
+
+ /**
+ * Get the mouse x coordinate using the screens coordinate system.
+ *
+ * @return x coordinate
+ */
+ public static int mouseX() {
+ return turtle.x;
+ }
+
+ /**
+ * Get the mouse y coordinate using the screens coordinate system.
+ *
+ * @return y coordinate
+ */
+ public static int mouseY() {
+ return turtle.y;
+ }
+
+ /**
+ * Check to see if a mouse button is down.
+ *
+ * @return true if a button is down
+ */
+ public static boolean mouseButton() {
+ return mouseButton1() || mouseButton2() || mouseButton3();
+ }
+
+ /**
+ * Check to see if the first mouse button is down.
+ *
+ * @return true if button 1 is down
+ */
+ public static boolean mouseButton1() {
+ return (turtle.modifiers & 16) == 16;
+ }
+
+ /**
+ * Check to see if the second mouse button is down.
+ *
+ * @return true if button 2 is down
+ */
+ public static boolean mouseButton2() {
+ return (turtle.modifiers & 8) == 8;
+ }
+
+ /**
+ * Check to see if the third mouse button is down.
+ *
+ * @return true if button 3 is down
+ */
+ public static boolean mouseButton3() {
+ return (turtle.modifiers & 4) == 4;
+ }
+
+ /**
+ * Converts screen coordinates to canvas coordinates.
+ *
+ * @param screenX screen x coordinate
+ * @return canvas x coordinate
+ */
+ public static double canvasX(double screenX) {
+ return (screenX - width / 2.0) / scale + centerX;
+ }
+
+ /**
+ * Converts screen coordinates to canvas coordinates.
+ *
+ * @param screenY screen y coordinate
+ * @return canvas y coordinate
+ */
+ public static double canvasY(double screenY) {
+ return (-screenY + height / 2.0) / scale + centerY;
+ }
+
+ public static double screenX(double canvasX) {
+ return (canvasX - centerX) * scale + width / 2.0;
+ }
+
+ public static double screenY(double canvasY) {
+ return (canvasY - centerY) * scale + height / 2.0;
+ }
+
+ private static void saveGCODE(String filename) {
+ PrintWriter out = new PrintWriter(System.out);
+ try {
+ out = new PrintWriter(filename);
+ } catch (Exception e) {}
+ out.println("M104 S200");
+ out.println("M109 S200");
+ out.println("G21");
+ out.println("G90");
+ out.println("M82");
+ out.println("M106");
+ out.println("G28 X0 Y0");
+ out.println("G28 Z0");
+ out.println("G29");
+ out.println("G1 Z15.0 F9000");
+ out.println("G92 E0");
+ out.println("G1 F200 E5");
+ out.println("G92 E0");
+ out.println("G1 X50 Y50 F1800");
+
+ double e = 0;
+ synchronized (turtleLock) {
+ int i = 0;
+ for (Map.Entry entry : turtleStates.entrySet()) {
+ retrieveState(entry.getKey());
+ Turtle t = getStateTurtle(entry.getValue());
+ i++;
+ if (i == 1) continue;
+ if (t.__location != null && !t.__location.equals(t._location)) {
+ double x1 = t._location.x, y1 = t._location.y, x2 =
+ t.__location.x, y2 = t.__location.y;
+ double d = Math.hypot(x1 - x2, y1 - y2);
+ e += d * 0.05;
+ //System.out.printf("%f %f %f %f",x1,y1,x2,y2);
+ if (t._isPenDown) {
+ out.printf(
+ "G1 X%.4f Y%.4f E%.4f\n",
+ ((screenX(x1) * 1.0) / width) * 100,
+ ((screenY(y1) * 1.0) / height) * 100,
+ e
+ );
+ } else {}
}
- updateAll();
- }
-
- /**
- * Get the pressed keys.
- *
- * @return a list of pressed keys
- */
- public static String[] keysDown() {
- return keysDown.toArray(new String[]{});
- }
-
- /**
- * Test if a key is pressed or not.
- *
- * @param key key you are testing
- * @return true if the key is pressed
- */
- public static boolean isKeyDown(String key) {
- return keysDown.contains(key);
- }
-
- /**
- * Get the mouse x coordinate using the screens coordinate system.
- *
- * @return x coordinate
- */
- public static int mouseX() {
- return turtle.x;
- }
-
- /**
- * Get the mouse y coordinate using the screens coordinate system.
- *
- * @return y coordinate
- */
- public static int mouseY() {
- return turtle.y;
- }
-
- /**
- * Check to see if a mouse button is down.
- *
- * @return true if a button is down
- */
- public static boolean mouseButton() {
- return mouseButton1() || mouseButton2() || mouseButton3();
- }
-
- /**
- * Check to see if the first mouse button is down.
- *
- * @return true if button 1 is down
- */
- public static boolean mouseButton1() {
- return (turtle.modifiers & 16) == 16;
- }
-
- /**
- * Check to see if the second mouse button is down.
- *
- * @return true if button 2 is down
- */
- public static boolean mouseButton2() {
- return (turtle.modifiers & 8) == 8;
- }
-
- /**
- * Check to see if the third mouse button is down.
- *
- * @return true if button 3 is down
- */
- public static boolean mouseButton3() {
- return (turtle.modifiers & 4) == 4;
- }
-
- /**
- * Converts screen coordinates to canvas coordinates.
- *
- * @param screenX screen x coordinate
- * @return canvas x coordinate
- */
- public static double canvasX(double screenX) {
- return (screenX - width / 2.0) / scale + centerX;
- }
-
- /**
- * Converts screen coordinates to canvas coordinates.
- *
- * @param screenY screen y coordinate
- * @return canvas y coordinate
- */
- public static double canvasY(double screenY) {
- return (-screenY + height / 2.0) / scale + centerY;
- }
-
- public static double screenX(double canvasX) {
- return (canvasX - centerX) * scale + width / 2.0;
- }
-
- public static double screenY(double canvasY) {
- return (canvasY - centerY) * scale + height / 2.0;
- }
-
-
- private static void saveGCODE(String filename) {
- PrintWriter out = new PrintWriter(System.out);
- try {
- out = new PrintWriter(filename);
- } catch (Exception e) {
-
- }
- out.println("M104 S200");
- out.println("M109 S200");
- out.println("G21");
- out.println("G90");
- out.println("M82");
- out.println("M106");
- out.println("G28 X0 Y0");
- out.println("G28 Z0");
- out.println("G29");
- out.println("G1 Z15.0 F9000");
- out.println("G92 E0");
- out.println("G1 F200 E5");
- out.println("G92 E0");
- out.println("G1 X50 Y50 F1800");
-
- double e = 0;
- synchronized (turtleLock) {
- int i = 0;
- for (Map.Entry entry : turtleStates.entrySet()) {
- retrieveState(entry.getKey());
- Turtle t = getStateTurtle(entry.getValue());
- i++;
- if (i == 1) continue;
- if (t.__location != null && !t.__location.equals(t._location)) {
- double x1 = t._location.x, y1 = t._location.y, x2 = t.__location.x, y2 = t.__location.y;
- double d = Math.hypot(x1 - x2, y1 - y2);
- e += d * 0.05;
- //System.out.printf("%f %f %f %f",x1,y1,x2,y2);
- if (t._isPenDown) {
- out.printf("G1 X%.4f Y%.4f E%.4f\n", screenX(x1) * 1.0 / width * 100, screenY(y1) * 1.0 / height * 100, e);
- } else {
-
- }
-
- }
- }
- out.println("G1 Z15");
- out.println("M104 S0");
- out.println("M140 S0");
- out.close();
- }
- }
-}
\ No newline at end of file
+ }
+ out.println("G1 Z15");
+ out.println("M104 S0");
+ out.println("M140 S0");
+ out.close();
+ }
+ }
+}