diff --git a/src/main/java/ch/fritteli/labyrinth/PDFRenderer.java b/src/main/java/ch/fritteli/labyrinth/PDFRenderer.java index dd403ff..1680ef5 100644 --- a/src/main/java/ch/fritteli/labyrinth/PDFRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/PDFRenderer.java @@ -1,6 +1,7 @@ package ch.fritteli.labyrinth; import lombok.NonNull; +import lombok.Value; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDPage; @@ -47,10 +48,8 @@ public class PDFRenderer implements Renderer { final PDPageContentStream solutionPageContentStream = new PDPageContentStream(pdDocument, solution)) { setUpPageContentStream(labyrinthPageContentStream); setUpPageContentStream(solutionPageContentStream); - this.drawHorizonzalLines(labyrinth, labyrinthPageContentStream); - this.drawVerticalLines(labyrinth, labyrinthPageContentStream); - this.drawHorizonzalLines(labyrinth, solutionPageContentStream); - this.drawVerticalLines(labyrinth, solutionPageContentStream); + this.drawHorizonzalLines(labyrinth, labyrinthPageContentStream, solutionPageContentStream); + this.drawVerticalLines(labyrinth, labyrinthPageContentStream, solutionPageContentStream); this.drawSolution(labyrinth, solutionPageContentStream); } catch (IOException e) { e.printStackTrace(); @@ -74,132 +73,158 @@ public class PDFRenderer implements Renderer { } private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth, - @NonNull final PDPageContentStream pdPageContentStream) throws IOException { + @NonNull final PDPageContentStream... contentStreams) throws IOException { // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. - final float labyrinthHeight = labyrinth.getHeight() * SCALE; + Coordinate coordinate = new Coordinate(0f, 0f); for (int y = 0; y < labyrinth.getHeight(); y++) { boolean isPainting = false; - final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN; + coordinate = coordinate.withY(y, labyrinth); for (int x = 0; x < labyrinth.getWidth(); x++) { final Tile currentTile = labyrinth.getTileAt(x, y); - final float xCoordinate = x * SCALE + MARGIN; + coordinate = coordinate.withX(x); if (currentTile.hasWallAt(Direction.TOP)) { if (!isPainting) { - pdPageContentStream.moveTo(xCoordinate, yCoordinate); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.moveTo(coordinate.getX(), coordinate.getY()); + } isPainting = true; } } else { if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, yCoordinate); - pdPageContentStream.stroke(); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } isPainting = false; } } } if (isPainting) { - final float xCoordinate = labyrinth.getWidth() * SCALE + MARGIN; - pdPageContentStream.lineTo(xCoordinate, yCoordinate); - pdPageContentStream.stroke(); + coordinate = coordinate.withX(labyrinth.getWidth()); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } } } boolean isPainting = false; int y = labyrinth.getHeight(); - final float yCoordinate = /*labyrinthHeight - y * SCALE +*/ MARGIN; + coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth); for (int x = 0; x < labyrinth.getWidth(); x++) { final Tile currentTile = labyrinth.getTileAt(x, y - 1); - final float xCoordinate = x * SCALE + MARGIN; + coordinate = coordinate.withX(x); if (currentTile.hasWallAt(Direction.BOTTOM)) { if (!isPainting) { - pdPageContentStream.moveTo(xCoordinate, yCoordinate); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.moveTo(coordinate.getX(), coordinate.getY()); + } isPainting = true; } } else { if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, yCoordinate); - pdPageContentStream.stroke(); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } isPainting = false; } } } - final float xCoordinate = labyrinth.getWidth() * SCALE + MARGIN; if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, yCoordinate); - pdPageContentStream.stroke(); + coordinate = coordinate.withX(labyrinth.getWidth()); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } } } private void drawVerticalLines(@NonNull final Labyrinth labyrinth, - @NonNull final PDPageContentStream pdPageContentStream) throws IOException { + @NonNull final PDPageContentStream... contentStreams) throws IOException { // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. + Coordinate coordinate = new Coordinate(0f, 0f); final float labyrinthHeight = labyrinth.getHeight() * SCALE; for (int x = 0; x < labyrinth.getWidth(); x++) { boolean isPainting = false; - final float xCoordinate = x * SCALE + MARGIN; + coordinate = coordinate.withX(x); for (int y = 0; y < labyrinth.getHeight(); y++) { final Tile currentTile = labyrinth.getTileAt(x, y); - final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN; + coordinate = coordinate.withY(y, labyrinth); if (currentTile.hasWallAt(Direction.LEFT)) { if (!isPainting) { - pdPageContentStream.moveTo(xCoordinate, yCoordinate); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.moveTo(coordinate.getX(), coordinate.getY()); + } isPainting = true; } } else { if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, yCoordinate); - pdPageContentStream.stroke(); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } isPainting = false; } } } if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, MARGIN); - pdPageContentStream.stroke(); + coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } } } boolean isPainting = false; int x = labyrinth.getWidth(); - final float xCoordinate = x * SCALE + MARGIN; + coordinate = coordinate.withX(labyrinth.getWidth()); for (int y = 0; y < labyrinth.getHeight(); y++) { final Tile currentTile = labyrinth.getTileAt(x - 1, y); - final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN; + coordinate = coordinate.withY(y, labyrinth); if (currentTile.hasWallAt(Direction.RIGHT)) { if (!isPainting) { - pdPageContentStream.moveTo(xCoordinate, yCoordinate); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.moveTo(coordinate.getX(), coordinate.getY()); + } isPainting = true; } } else { if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, yCoordinate); - pdPageContentStream.stroke(); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } isPainting = false; } } } if (isPainting) { - pdPageContentStream.lineTo(xCoordinate, MARGIN); - pdPageContentStream.stroke(); + coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth); + for (final PDPageContentStream contentStream : contentStreams) { + contentStream.lineTo(coordinate.getX(), coordinate.getY()); + contentStream.stroke(); + } } } private void drawSolution(@NonNull final Labyrinth labyrinth, - @NonNull final PDPageContentStream pdPageContentStream) throws IOException { + @NonNull final PDPageContentStream pageContentStream) throws IOException { // Draw the solution in red - pdPageContentStream.setStrokingColor(Color.RED); + pageContentStream.setStrokingColor(Color.RED); // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. - final float labyrinthHeight = labyrinth.getHeight() * SCALE; final Position end = labyrinth.getEnd(); Position currentPosition = labyrinth.getStart(); Position previousPosition = null; - pdPageContentStream.moveTo(MARGIN + currentPosition.getX() * SCALE + SCALE / 2, MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2)); + SolutionCoordinate coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY(), labyrinth); + pageContentStream.moveTo(coordinate.getX(), coordinate.getY()); do { Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition); previousPosition = currentPosition; currentPosition = newCurrent; - final float xCoordinate = MARGIN + currentPosition.getX() * SCALE + SCALE / 2; - final float yCoordinate = MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2); - pdPageContentStream.lineTo(xCoordinate, yCoordinate); + coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY(), labyrinth); + pageContentStream.lineTo(coordinate.getX(), coordinate.getY()); } while (!currentPosition.equals(end)); - pdPageContentStream.stroke(); + pageContentStream.stroke(); } @NonNull @@ -218,4 +243,63 @@ public class PDFRenderer implements Renderer { } throw new IllegalStateException("We *SHOULD* never have gotten here. ... famous last words ..."); } + + @Value + private static class Coordinate { + float x; + float y; + + public Coordinate(final float x, final float y) { + this.x = x; + this.y = y; + } + + private static float calcX(final int x) { + return x * SCALE + MARGIN; + } + + private static float calcY(final int y, @NonNull final Labyrinth labyrinth) { + return (labyrinth.getHeight() - y) * SCALE + MARGIN; + } + + public Coordinate withX(final int x) { + return new Coordinate(calcX(x), this.y); + } + + public Coordinate withY(final int y, @NonNull final Labyrinth labyrinth) { + return new Coordinate(this.x, calcY(y, labyrinth)); + } + } + + @Value + private static class SolutionCoordinate { + float x; + float y; + + public SolutionCoordinate(final float x, final float y) { + this.x = x; + this.y = y; + } + + public SolutionCoordinate(final int x, final int y, @NonNull final Labyrinth labyrinth) { + this.x = calcX(x); + this.y = calcY(y, labyrinth); + } + + private static float calcX(final int x) { + return x * SCALE + SCALE / 2 + MARGIN; + } + + private static float calcY(final int y, @NonNull final Labyrinth labyrinth) { + return (labyrinth.getHeight() - y) * SCALE - SCALE / 2 + MARGIN; + } + + public SolutionCoordinate withX(final int x) { + return new SolutionCoordinate(calcX(x), this.y); + } + + public SolutionCoordinate withY(final int y, @NonNull final Labyrinth labyrinth) { + return new SolutionCoordinate(this.x, calcY(y, labyrinth)); + } + } }