Encapsulate the coordinate calculation logic in separate classes.

This commit is contained in:
Manuel Friedli 2020-10-04 22:36:04 +02:00
parent 6060a08573
commit 66ddb27291

View file

@ -1,6 +1,7 @@
package ch.fritteli.labyrinth; package ch.fritteli.labyrinth;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
@ -47,10 +48,8 @@ public class PDFRenderer implements Renderer<byte[]> {
final PDPageContentStream solutionPageContentStream = new PDPageContentStream(pdDocument, solution)) { final PDPageContentStream solutionPageContentStream = new PDPageContentStream(pdDocument, solution)) {
setUpPageContentStream(labyrinthPageContentStream); setUpPageContentStream(labyrinthPageContentStream);
setUpPageContentStream(solutionPageContentStream); setUpPageContentStream(solutionPageContentStream);
this.drawHorizonzalLines(labyrinth, labyrinthPageContentStream); this.drawHorizonzalLines(labyrinth, labyrinthPageContentStream, solutionPageContentStream);
this.drawVerticalLines(labyrinth, labyrinthPageContentStream); this.drawVerticalLines(labyrinth, labyrinthPageContentStream, solutionPageContentStream);
this.drawHorizonzalLines(labyrinth, solutionPageContentStream);
this.drawVerticalLines(labyrinth, solutionPageContentStream);
this.drawSolution(labyrinth, solutionPageContentStream); this.drawSolution(labyrinth, solutionPageContentStream);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -74,132 +73,158 @@ public class PDFRenderer implements Renderer<byte[]> {
} }
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth, 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. // 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++) { for (int y = 0; y < labyrinth.getHeight(); y++) {
boolean isPainting = false; boolean isPainting = false;
final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN; coordinate = coordinate.withY(y, labyrinth);
for (int x = 0; x < labyrinth.getWidth(); x++) { for (int x = 0; x < labyrinth.getWidth(); x++) {
final Tile currentTile = labyrinth.getTileAt(x, y); final Tile currentTile = labyrinth.getTileAt(x, y);
final float xCoordinate = x * SCALE + MARGIN; coordinate = coordinate.withX(x);
if (currentTile.hasWallAt(Direction.TOP)) { if (currentTile.hasWallAt(Direction.TOP)) {
if (!isPainting) { if (!isPainting) {
pdPageContentStream.moveTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.moveTo(coordinate.getX(), coordinate.getY());
}
isPainting = true; isPainting = true;
} }
} else { } else {
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
pdPageContentStream.stroke(); contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
isPainting = false; isPainting = false;
} }
} }
} }
if (isPainting) { if (isPainting) {
final float xCoordinate = labyrinth.getWidth() * SCALE + MARGIN; coordinate = coordinate.withX(labyrinth.getWidth());
pdPageContentStream.lineTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
pdPageContentStream.stroke(); contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
} }
} }
boolean isPainting = false; boolean isPainting = false;
int y = labyrinth.getHeight(); 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++) { for (int x = 0; x < labyrinth.getWidth(); x++) {
final Tile currentTile = labyrinth.getTileAt(x, y - 1); final Tile currentTile = labyrinth.getTileAt(x, y - 1);
final float xCoordinate = x * SCALE + MARGIN; coordinate = coordinate.withX(x);
if (currentTile.hasWallAt(Direction.BOTTOM)) { if (currentTile.hasWallAt(Direction.BOTTOM)) {
if (!isPainting) { if (!isPainting) {
pdPageContentStream.moveTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.moveTo(coordinate.getX(), coordinate.getY());
}
isPainting = true; isPainting = true;
} }
} else { } else {
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
pdPageContentStream.stroke(); contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
isPainting = false; isPainting = false;
} }
} }
} }
final float xCoordinate = labyrinth.getWidth() * SCALE + MARGIN;
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, yCoordinate); coordinate = coordinate.withX(labyrinth.getWidth());
pdPageContentStream.stroke(); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
} }
} }
private void drawVerticalLines(@NonNull final Labyrinth labyrinth, 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. // 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; final float labyrinthHeight = labyrinth.getHeight() * SCALE;
for (int x = 0; x < labyrinth.getWidth(); x++) { for (int x = 0; x < labyrinth.getWidth(); x++) {
boolean isPainting = false; boolean isPainting = false;
final float xCoordinate = x * SCALE + MARGIN; coordinate = coordinate.withX(x);
for (int y = 0; y < labyrinth.getHeight(); y++) { for (int y = 0; y < labyrinth.getHeight(); y++) {
final Tile currentTile = labyrinth.getTileAt(x, 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 (currentTile.hasWallAt(Direction.LEFT)) {
if (!isPainting) { if (!isPainting) {
pdPageContentStream.moveTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.moveTo(coordinate.getX(), coordinate.getY());
}
isPainting = true; isPainting = true;
} }
} else { } else {
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
pdPageContentStream.stroke(); contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
isPainting = false; isPainting = false;
} }
} }
} }
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, MARGIN); coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth);
pdPageContentStream.stroke(); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
} }
} }
boolean isPainting = false; boolean isPainting = false;
int x = labyrinth.getWidth(); int x = labyrinth.getWidth();
final float xCoordinate = x * SCALE + MARGIN; coordinate = coordinate.withX(labyrinth.getWidth());
for (int y = 0; y < labyrinth.getHeight(); y++) { for (int y = 0; y < labyrinth.getHeight(); y++) {
final Tile currentTile = labyrinth.getTileAt(x - 1, 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 (currentTile.hasWallAt(Direction.RIGHT)) {
if (!isPainting) { if (!isPainting) {
pdPageContentStream.moveTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.moveTo(coordinate.getX(), coordinate.getY());
}
isPainting = true; isPainting = true;
} }
} else { } else {
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, yCoordinate); for (final PDPageContentStream contentStream : contentStreams) {
pdPageContentStream.stroke(); contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
isPainting = false; isPainting = false;
} }
} }
} }
if (isPainting) { if (isPainting) {
pdPageContentStream.lineTo(xCoordinate, MARGIN); coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth);
pdPageContentStream.stroke(); for (final PDPageContentStream contentStream : contentStreams) {
contentStream.lineTo(coordinate.getX(), coordinate.getY());
contentStream.stroke();
}
} }
} }
private void drawSolution(@NonNull final Labyrinth labyrinth, private void drawSolution(@NonNull final Labyrinth labyrinth,
@NonNull final PDPageContentStream pdPageContentStream) throws IOException { @NonNull final PDPageContentStream pageContentStream) throws IOException {
// Draw the solution in red // 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. // 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(); final Position end = labyrinth.getEnd();
Position currentPosition = labyrinth.getStart(); Position currentPosition = labyrinth.getStart();
Position previousPosition = null; 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 { do {
Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition); Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition);
previousPosition = currentPosition; previousPosition = currentPosition;
currentPosition = newCurrent; currentPosition = newCurrent;
final float xCoordinate = MARGIN + currentPosition.getX() * SCALE + SCALE / 2; coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY(), labyrinth);
final float yCoordinate = MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2); pageContentStream.lineTo(coordinate.getX(), coordinate.getY());
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
} while (!currentPosition.equals(end)); } while (!currentPosition.equals(end));
pdPageContentStream.stroke(); pageContentStream.stroke();
} }
@NonNull @NonNull
@ -218,4 +243,63 @@ public class PDFRenderer implements Renderer<byte[]> {
} }
throw new IllegalStateException("We *SHOULD* never have gotten here. ... famous last words ..."); 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));
}
}
} }