Refactor the PDFRenderer
This commit is contained in:
parent
66ddb27291
commit
0bdbd7d0ef
1 changed files with 194 additions and 198 deletions
|
@ -1,6 +1,7 @@
|
||||||
package ch.fritteli.labyrinth;
|
package ch.fritteli.labyrinth;
|
||||||
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Value;
|
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;
|
||||||
|
@ -26,19 +27,30 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
return new PDFRenderer();
|
return new PDFRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public byte[] render(@NonNull final Labyrinth labyrinth) {
|
||||||
|
final Generator generator = new Generator(labyrinth);
|
||||||
|
return generator.generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class Generator {
|
||||||
|
@NonNull
|
||||||
|
private final Labyrinth labyrinth;
|
||||||
|
|
||||||
private static boolean isValid(@NonNull final Position position) {
|
private static boolean isValid(@NonNull final Position position) {
|
||||||
return position.getX() >= 0 && position.getY() >= 0;
|
return position.getX() >= 0 && position.getY() >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public byte[] generate() {
|
||||||
@NonNull
|
final float pageWidth = this.labyrinth.getWidth() * SCALE + 2 * MARGIN;
|
||||||
public byte[] render(@NonNull final Labyrinth labyrinth) {
|
final float pageHeight = this.labyrinth.getHeight() * SCALE + 2 * MARGIN;
|
||||||
final float pageWidth = labyrinth.getWidth() * SCALE + 2 * MARGIN;
|
|
||||||
final float pageHeight = labyrinth.getHeight() * SCALE + 2 * MARGIN;
|
|
||||||
|
|
||||||
final PDDocument pdDocument = new PDDocument();
|
final PDDocument pdDocument = new PDDocument();
|
||||||
final PDDocumentInformation info = new PDDocumentInformation();
|
final PDDocumentInformation info = new PDDocumentInformation();
|
||||||
info.setTitle("Labyrinth " + labyrinth.getWidth() + "x" + labyrinth.getHeight() + ", ID " + labyrinth.getRandomSeed());
|
info.setTitle("Labyrinth " + this.labyrinth.getWidth() + "x" + this.labyrinth.getHeight() + ", ID " + this.labyrinth.getRandomSeed());
|
||||||
pdDocument.setDocumentInformation(info);
|
pdDocument.setDocumentInformation(info);
|
||||||
final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
||||||
final PDPage solution = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
final PDPage solution = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
||||||
|
@ -48,9 +60,9 @@ 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, solutionPageContentStream);
|
this.drawHorizonzalLines(labyrinthPageContentStream, solutionPageContentStream);
|
||||||
this.drawVerticalLines(labyrinth, labyrinthPageContentStream, solutionPageContentStream);
|
this.drawVerticalLines(labyrinthPageContentStream, solutionPageContentStream);
|
||||||
this.drawSolution(labyrinth, solutionPageContentStream);
|
this.drawSolution(solutionPageContentStream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -72,15 +84,14 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
pageContentStream.setNonStrokingColor(Color.BLACK);
|
pageContentStream.setNonStrokingColor(Color.BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth,
|
private void drawHorizonzalLines(@NonNull final PDPageContentStream... contentStreams) 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);
|
Coordinate coordinate = new Coordinate(0f, 0f);
|
||||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
for (int y = 0; y < this.labyrinth.getHeight(); y++) {
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
coordinate = coordinate.withY(y, labyrinth);
|
coordinate = coordinate.withY(y);
|
||||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
for (int x = 0; x < this.labyrinth.getWidth(); x++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x, y);
|
final Tile currentTile = this.labyrinth.getTileAt(x, y);
|
||||||
coordinate = coordinate.withX(x);
|
coordinate = coordinate.withX(x);
|
||||||
if (currentTile.hasWallAt(Direction.TOP)) {
|
if (currentTile.hasWallAt(Direction.TOP)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
|
@ -100,7 +111,7 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
coordinate = coordinate.withX(labyrinth.getWidth());
|
coordinate = coordinate.withX(this.labyrinth.getWidth());
|
||||||
for (final PDPageContentStream contentStream : contentStreams) {
|
for (final PDPageContentStream contentStream : contentStreams) {
|
||||||
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
||||||
contentStream.stroke();
|
contentStream.stroke();
|
||||||
|
@ -108,10 +119,10 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
int y = labyrinth.getHeight();
|
int y = this.labyrinth.getHeight();
|
||||||
coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth);
|
coordinate = coordinate.withY(this.labyrinth.getHeight());
|
||||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
for (int x = 0; x < this.labyrinth.getWidth(); x++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x, y - 1);
|
final Tile currentTile = this.labyrinth.getTileAt(x, y - 1);
|
||||||
coordinate = coordinate.withX(x);
|
coordinate = coordinate.withX(x);
|
||||||
if (currentTile.hasWallAt(Direction.BOTTOM)) {
|
if (currentTile.hasWallAt(Direction.BOTTOM)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
|
@ -131,7 +142,7 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
coordinate = coordinate.withX(labyrinth.getWidth());
|
coordinate = coordinate.withX(this.labyrinth.getWidth());
|
||||||
for (final PDPageContentStream contentStream : contentStreams) {
|
for (final PDPageContentStream contentStream : contentStreams) {
|
||||||
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
||||||
contentStream.stroke();
|
contentStream.stroke();
|
||||||
|
@ -139,17 +150,15 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawVerticalLines(@NonNull final Labyrinth labyrinth,
|
private void drawVerticalLines(@NonNull final PDPageContentStream... contentStreams) 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);
|
Coordinate coordinate = new Coordinate(0f, 0f);
|
||||||
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
for (int x = 0; x < this.labyrinth.getWidth(); x++) {
|
||||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
coordinate = coordinate.withX(x);
|
coordinate = coordinate.withX(x);
|
||||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
for (int y = 0; y < this.labyrinth.getHeight(); y++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x, y);
|
final Tile currentTile = this.labyrinth.getTileAt(x, y);
|
||||||
coordinate = coordinate.withY(y, labyrinth);
|
coordinate = coordinate.withY(y);
|
||||||
if (currentTile.hasWallAt(Direction.LEFT)) {
|
if (currentTile.hasWallAt(Direction.LEFT)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
for (final PDPageContentStream contentStream : contentStreams) {
|
for (final PDPageContentStream contentStream : contentStreams) {
|
||||||
|
@ -168,7 +177,7 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth);
|
coordinate = coordinate.withY(this.labyrinth.getHeight());
|
||||||
for (final PDPageContentStream contentStream : contentStreams) {
|
for (final PDPageContentStream contentStream : contentStreams) {
|
||||||
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
||||||
contentStream.stroke();
|
contentStream.stroke();
|
||||||
|
@ -176,11 +185,11 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
int x = labyrinth.getWidth();
|
int x = this.labyrinth.getWidth();
|
||||||
coordinate = coordinate.withX(labyrinth.getWidth());
|
coordinate = coordinate.withX(this.labyrinth.getWidth());
|
||||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
for (int y = 0; y < this.labyrinth.getHeight(); y++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x - 1, y);
|
final Tile currentTile = this.labyrinth.getTileAt(x - 1, y);
|
||||||
coordinate = coordinate.withY(y, labyrinth);
|
coordinate = coordinate.withY(y);
|
||||||
if (currentTile.hasWallAt(Direction.RIGHT)) {
|
if (currentTile.hasWallAt(Direction.RIGHT)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
for (final PDPageContentStream contentStream : contentStreams) {
|
for (final PDPageContentStream contentStream : contentStreams) {
|
||||||
|
@ -199,7 +208,7 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
coordinate = coordinate.withY(labyrinth.getHeight(), labyrinth);
|
coordinate = coordinate.withY(this.labyrinth.getHeight());
|
||||||
for (final PDPageContentStream contentStream : contentStreams) {
|
for (final PDPageContentStream contentStream : contentStreams) {
|
||||||
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
contentStream.lineTo(coordinate.getX(), coordinate.getY());
|
||||||
contentStream.stroke();
|
contentStream.stroke();
|
||||||
|
@ -207,36 +216,35 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawSolution(@NonNull final Labyrinth labyrinth,
|
private void drawSolution(@NonNull final PDPageContentStream pageContentStream) throws IOException {
|
||||||
@NonNull final PDPageContentStream pageContentStream) throws IOException {
|
|
||||||
// Draw the solution in red
|
// Draw the solution in red
|
||||||
pageContentStream.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 Position end = labyrinth.getEnd();
|
final Position end = this.labyrinth.getEnd();
|
||||||
Position currentPosition = labyrinth.getStart();
|
Position currentPosition = this.labyrinth.getStart();
|
||||||
Position previousPosition = null;
|
Position previousPosition = null;
|
||||||
SolutionCoordinate coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY(), labyrinth);
|
SolutionCoordinate coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY());
|
||||||
pageContentStream.moveTo(coordinate.getX(), coordinate.getY());
|
pageContentStream.moveTo(coordinate.getX(), coordinate.getY());
|
||||||
do {
|
do {
|
||||||
Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition);
|
Position newCurrent = this.findNextSolutionPosition(previousPosition, currentPosition);
|
||||||
previousPosition = currentPosition;
|
previousPosition = currentPosition;
|
||||||
currentPosition = newCurrent;
|
currentPosition = newCurrent;
|
||||||
coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY(), labyrinth);
|
coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY());
|
||||||
pageContentStream.lineTo(coordinate.getX(), coordinate.getY());
|
pageContentStream.lineTo(coordinate.getX(), coordinate.getY());
|
||||||
} while (!currentPosition.equals(end));
|
} while (!currentPosition.equals(end));
|
||||||
pageContentStream.stroke();
|
pageContentStream.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Position findNextSolutionPosition(@NonNull final Labyrinth labyrinth, @Nullable final Position previousPosition, @NonNull final Position currentPosition) {
|
private Position findNextSolutionPosition(@Nullable final Position previousPosition, @NonNull final Position currentPosition) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(currentPosition);
|
final Tile currentTile = this.labyrinth.getTileAt(currentPosition);
|
||||||
for (final Direction direction : Direction.values()) {
|
for (final Direction direction : Direction.values()) {
|
||||||
if (!currentTile.hasWallAt(direction)) {
|
if (!currentTile.hasWallAt(direction)) {
|
||||||
final Position position = direction.translate(currentPosition);
|
final Position position = direction.translate(currentPosition);
|
||||||
if (position.equals(previousPosition) || !isValid(position)) {
|
if (position.equals(previousPosition) || !isValid(position)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (labyrinth.getTileAt(position).isSolution()) {
|
if (this.labyrinth.getTileAt(position).isSolution()) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +253,7 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
private static class Coordinate {
|
private class Coordinate {
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
|
|
||||||
|
@ -254,52 +262,40 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float calcX(final int x) {
|
private float calcX(final int x) {
|
||||||
return x * SCALE + MARGIN;
|
return x * SCALE + MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float calcY(final int y, @NonNull final Labyrinth labyrinth) {
|
private float calcY(final int y) {
|
||||||
return (labyrinth.getHeight() - y) * SCALE + MARGIN;
|
return (Generator.this.labyrinth.getHeight() - y) * SCALE + MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Coordinate withX(final int x) {
|
public Coordinate withX(final int x) {
|
||||||
return new Coordinate(calcX(x), this.y);
|
return new Coordinate(calcX(x), this.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Coordinate withY(final int y, @NonNull final Labyrinth labyrinth) {
|
public Coordinate withY(final int y) {
|
||||||
return new Coordinate(this.x, calcY(y, labyrinth));
|
return new Coordinate(this.x, calcY(y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
private static class SolutionCoordinate {
|
private class SolutionCoordinate {
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
|
|
||||||
public SolutionCoordinate(final float x, final float y) {
|
public SolutionCoordinate(final int x, final int y) {
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SolutionCoordinate(final int x, final int y, @NonNull final Labyrinth labyrinth) {
|
|
||||||
this.x = calcX(x);
|
this.x = calcX(x);
|
||||||
this.y = calcY(y, labyrinth);
|
this.y = calcY(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float calcX(final int x) {
|
private float calcX(final int x) {
|
||||||
return x * SCALE + SCALE / 2 + MARGIN;
|
return x * SCALE + SCALE / 2 + MARGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float calcY(final int y, @NonNull final Labyrinth labyrinth) {
|
private float calcY(final int y) {
|
||||||
return (labyrinth.getHeight() - y) * SCALE - SCALE / 2 + MARGIN;
|
return (Generator.this.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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue