From cb2daed48a14ce4e1b80d83e3db37013d248d886 Mon Sep 17 00:00:00 2001 From: Anya Helene Bagge Date: Wed, 7 Mar 2018 13:26:00 +0100 Subject: [PATCH] small improvements in gfx library --- src/inf101/v18/gfx/IPaintLayer.java | 10 +++ src/inf101/v18/gfx/gfxmode/IPainter.java | 32 +++++++++ src/inf101/v18/gfx/gfxmode/ITurtle.java | 34 +++++++++- src/inf101/v18/gfx/gfxmode/Point.java | 21 ++++++ src/inf101/v18/gfx/gfxmode/TurtlePainter.java | 66 +++++++++++++++++++ .../v18/gfx/textmode/ControlSequences.java | 7 +- src/inf101/v18/gfx/textmode/Printer.java | 10 +++ 7 files changed, 176 insertions(+), 4 deletions(-) diff --git a/src/inf101/v18/gfx/IPaintLayer.java b/src/inf101/v18/gfx/IPaintLayer.java index 06f16cf..18a964a 100644 --- a/src/inf101/v18/gfx/IPaintLayer.java +++ b/src/inf101/v18/gfx/IPaintLayer.java @@ -25,4 +25,14 @@ public interface IPaintLayer { */ void layerToFront(); + /** + * @return Width (in pixels) of graphics layer + */ + double getWidth(); + + /** + * @return Height (in pixels) of graphics layer + */ + double getHeight(); + } diff --git a/src/inf101/v18/gfx/gfxmode/IPainter.java b/src/inf101/v18/gfx/gfxmode/IPainter.java index 5b6e322..f0b6630 100644 --- a/src/inf101/v18/gfx/gfxmode/IPainter.java +++ b/src/inf101/v18/gfx/gfxmode/IPainter.java @@ -5,13 +5,45 @@ import javafx.scene.paint.Paint; public interface IPainter extends IPaintLayer { + /** + * Restore graphics settings previously stored by {@link #save()}. + * + * @return {@code this}, for sending more draw commands + */ IPainter restore(); + /** + * Store graphics settings. + * + * @return {@code this}, for sending more draw commands + */ IPainter save(); + /** + * Set colour used to drawing and filling. + * + * @param ink A colour or paint + * @return {@code this}, for sending more draw commands + */ IPainter setInk(Paint ink); + /** + * Start drawing a shape. + * + * @return An IShape for sending shape drawing commands + */ IShape shape(); + /** + * Start drawing with a turtle. + * + * @return An ITurtle for sending turtle drawing commands + */ ITurtle turtle(); + + /** + * @return Current ink, as set by {@link #setInk(Paint)} + */ + Paint getInk(); + } \ No newline at end of file diff --git a/src/inf101/v18/gfx/gfxmode/ITurtle.java b/src/inf101/v18/gfx/gfxmode/ITurtle.java index af34c1a..4897441 100644 --- a/src/inf101/v18/gfx/gfxmode/ITurtle.java +++ b/src/inf101/v18/gfx/gfxmode/ITurtle.java @@ -2,7 +2,18 @@ package inf101.v18.gfx.gfxmode; public interface ITurtle extends IPainter { - T as(Class class1); + /** + * This method is used to convert the turtle to an other type, determined by the + * class object given as an argument. + *

+ * This can be used to access extra functionality not provided by this + * interface, such as direct access to the underlying graphics context. + * + * @param clazz + * @return This object or an appropriate closely related object of the given + * time; or null if no appropriate object can be found + */ + T as(Class clazz); /** * Move to the given position while drawing a curve @@ -236,7 +247,24 @@ public interface ITurtle extends IPainter { */ ITurtle turnTowards(double degrees, double percent); - double getWidth(); + /** + * Jump (without drawing) to the given relative position. + *

+ * The new position will be equal to getPos().move(relPos). + * + * @param relPos + * A position, interpreted relative to current position + * @return {@code this}, for sending more draw commands + */ + ITurtle jump(Point relPos); + + /** + * Move to the given relative position while drawing a line + *

+ * The new position will be equal to getPos().move(relPos). + * + * @return {@code this}, for sending more draw commands + */ + ITurtle draw(Point relPos); - double getHeight(); } \ No newline at end of file diff --git a/src/inf101/v18/gfx/gfxmode/Point.java b/src/inf101/v18/gfx/gfxmode/Point.java index 2b222af..997a2a5 100644 --- a/src/inf101/v18/gfx/gfxmode/Point.java +++ b/src/inf101/v18/gfx/gfxmode/Point.java @@ -92,4 +92,25 @@ public class Point { public String toString() { return String.format("(%.2f,%.2f)", x, y); } + + /** + * Multiply this point by a scale factor. + * + * @param factor A scale factor + * @return A new Point, (getX()*factor, getY()*factor) + */ + public Point scale(double factor) { + return new Point(x*factor, y*factor); + } + + /** + * Find difference between points. + *

+ * The returned value will be such that this.move(deltaTo(point)).equals(point). + * @param point Another point + * @return A new Point, (point.getX()-getX(), point.getY()-getY()) + */ + public Point deltaTo(Point point) { + return new Point(point.x-x, point.y-y); + } } diff --git a/src/inf101/v18/gfx/gfxmode/TurtlePainter.java b/src/inf101/v18/gfx/gfxmode/TurtlePainter.java index 2aa8a0d..3de989d 100644 --- a/src/inf101/v18/gfx/gfxmode/TurtlePainter.java +++ b/src/inf101/v18/gfx/gfxmode/TurtlePainter.java @@ -9,6 +9,8 @@ import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; +import javafx.scene.shape.StrokeLineCap; +import javafx.scene.shape.StrokeLineJoin; public class TurtlePainter implements IPaintLayer, ITurtle { @@ -63,6 +65,8 @@ public class TurtlePainter implements IPaintLayer, ITurtle { stateStack.add(new TurtleState()); state.dir = new Direction(1.0, 0.0); state.pos = new Point(screen.getWidth() / 2, screen.getHeight() / 2); + context.setLineJoin(StrokeLineJoin.BEVEL); + context.setLineCap(StrokeLineCap.SQUARE); } @Override @@ -70,6 +74,8 @@ public class TurtlePainter implements IPaintLayer, ITurtle { public T as(Class clazz) { if (clazz == GraphicsContext.class) return (T) context; + if (clazz == getClass()) + return (T) this; else return null; } @@ -113,6 +119,12 @@ public class TurtlePainter implements IPaintLayer, ITurtle { return drawTo(to); } + @Override + public ITurtle draw(Point relPos) { + Point to = state.pos.move(relPos); + return drawTo(to); + } + @Override public ITurtle drawTo(double x, double y) { Point to = new Point(x, y); @@ -122,6 +134,8 @@ public class TurtlePainter implements IPaintLayer, ITurtle { @Override public ITurtle drawTo(Point to) { if (path) { + context.setStroke(state.ink); + context.setLineWidth(state.penSize); context.lineTo(to.getX(), to.getY()); } else { line(to); @@ -164,6 +178,18 @@ public class TurtlePainter implements IPaintLayer, ITurtle { public ITurtle jump(double dist) { state.inDir = state.dir; state.pos = state.pos.move(state.dir, dist); + if (path) + context.moveTo(state.pos.getX(), state.pos.getY()); + return this; + } + + @Override + public ITurtle jump(Point relPos) { + // TODO: state.inDir = state.dir; + state.pos = state.pos.move(relPos); + if (path) + context.moveTo(state.pos.getX(), state.pos.getY()); + return this; } @@ -294,4 +320,44 @@ public class TurtlePainter implements IPaintLayer, ITurtle { return painter; } + public ITurtle beginPath() { + if (path) + throw new IllegalStateException("beginPath() after beginPath()"); + path = true; + context.setStroke(state.ink); + context.beginPath(); + context.moveTo(state.pos.getX(), state.pos.getY()); + return this; + } + + public ITurtle closePath() { + if (!path) + throw new IllegalStateException("closePath() without beginPath()"); + context.closePath(); + return this; + } + + public ITurtle endPath() { + if (!path) + throw new IllegalStateException("endPath() without beginPath()"); + path = false; + context.stroke(); + return this; + } + + public ITurtle fillPath() { + if (!path) + throw new IllegalStateException("fillPath() without beginPath()"); + path = false; + context.save(); + context.setFill(state.ink); + context.fill(); + context.restore(); + return this; + } + + @Override + public Paint getInk() { + return state.ink; + } } diff --git a/src/inf101/v18/gfx/textmode/ControlSequences.java b/src/inf101/v18/gfx/textmode/ControlSequences.java index f054fc5..6f76793 100644 --- a/src/inf101/v18/gfx/textmode/ControlSequences.java +++ b/src/inf101/v18/gfx/textmode/ControlSequences.java @@ -14,6 +14,8 @@ import java.util.regex.Pattern; import javafx.scene.paint.Color; public class ControlSequences { + private static final boolean DEBUG = false; + public static class CsiPattern { public static CsiPattern compile0(String pat, String desc, Consumer handler) { CsiPattern csiPattern = new CsiPattern(pat, 0, 0, desc, handler, null, null); @@ -73,10 +75,12 @@ public class ControlSequences { String argStr = matcher.groupCount() > 0 ? matcher.group(1) : ""; String[] args = argStr.split(";"); if (handler0 != null) { + if(DEBUG) System.out.println("Handling " + getDescription() + "."); handler0.accept(printer); } else if (handler1 != null) { int arg = args.length > 0 && !args[0].equals("") ? Integer.valueOf(args[0]) : defaultArg; + if(DEBUG) System.out.println("Handling " + getDescription() + ": " + arg); handler1.accept(printer, arg); } else if (handlerN != null) { @@ -90,7 +94,8 @@ public class ControlSequences { while (argList.size() < numArgs) { argList.add(defaultArg); } - System.out.println("Handling " + getDescription() + ": " + argList); + if(DEBUG) +System.out.println("Handling " + getDescription() + ": " + argList); handlerN.accept(printer, argList); } return true; diff --git a/src/inf101/v18/gfx/textmode/Printer.java b/src/inf101/v18/gfx/textmode/Printer.java index c8a71a5..1c02ce8 100644 --- a/src/inf101/v18/gfx/textmode/Printer.java +++ b/src/inf101/v18/gfx/textmode/Printer.java @@ -718,4 +718,14 @@ public class Printer implements IPaintLayer { plot(x, y, (a, b) -> a & ~b); } + @Override + public double getWidth() { + return textPage.getWidth(); + } + + @Override + public double getHeight() { + return textPage.getHeight(); + } + }