Add a second page with the solution to the PDF.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
74441c91cc
commit
911aa35577
2 changed files with 82 additions and 22 deletions
|
@ -13,7 +13,9 @@ public class Labyrinth {
|
|||
private final int width;
|
||||
@Getter
|
||||
private final int height;
|
||||
@Getter
|
||||
private final Position start;
|
||||
@Getter
|
||||
private final Position end;
|
||||
|
||||
public Labyrinth(final int width, final int height) {
|
||||
|
|
|
@ -5,12 +5,16 @@ import org.apache.pdfbox.pdmodel.PDDocument;
|
|||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class PDFRenderer implements Renderer<byte[]> {
|
||||
private static final float MARGIN = 10;
|
||||
private static final float SCALE = 10;
|
||||
|
||||
private PDFRenderer() {
|
||||
|
||||
}
|
||||
|
@ -20,13 +24,15 @@ public class PDFRenderer implements Renderer<byte[]> {
|
|||
return new PDFRenderer();
|
||||
}
|
||||
|
||||
private static boolean isValid(@NonNull final Position position) {
|
||||
return position.getX() >= 0 && position.getY() >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public byte[] render(@NonNull final Labyrinth labyrinth) {
|
||||
final float scale = 10;
|
||||
final float margin = 5;
|
||||
final float pageWidth = labyrinth.getWidth() * scale + 2 * margin;
|
||||
final float pageHeight = 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 PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
||||
|
@ -37,8 +43,22 @@ public class PDFRenderer implements Renderer<byte[]> {
|
|||
pdPageContentStream.setLineWidth(1.0f);
|
||||
pdPageContentStream.setStrokingColor(Color.BLACK);
|
||||
pdPageContentStream.setNonStrokingColor(Color.BLACK);
|
||||
this.drawHorizonzalLines(labyrinth, pdPageContentStream, margin, scale);
|
||||
this.drawVerticalLines(labyrinth, pdPageContentStream, margin, scale);
|
||||
this.drawHorizonzalLines(labyrinth, pdPageContentStream);
|
||||
this.drawVerticalLines(labyrinth, pdPageContentStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
final PDPage solution = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
||||
pdDocument.addPage(solution);
|
||||
try (PDPageContentStream pdPageContentStream = new PDPageContentStream(pdDocument, solution)) {
|
||||
pdPageContentStream.setLineCapStyle(BasicStroke.CAP_ROUND);
|
||||
pdPageContentStream.setLineJoinStyle(BasicStroke.JOIN_MITER);
|
||||
pdPageContentStream.setLineWidth(1.0f);
|
||||
pdPageContentStream.setStrokingColor(Color.BLACK);
|
||||
pdPageContentStream.setNonStrokingColor(Color.BLACK);
|
||||
this.drawHorizonzalLines(labyrinth, pdPageContentStream);
|
||||
this.drawVerticalLines(labyrinth, pdPageContentStream);
|
||||
this.drawSolution(labyrinth, pdPageContentStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -52,28 +72,29 @@ public class PDFRenderer implements Renderer<byte[]> {
|
|||
return output.toByteArray();
|
||||
}
|
||||
|
||||
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth, @NonNull final PDPageContentStream pdPageContentStream, final float margin, final float scale) throws IOException {
|
||||
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth,
|
||||
@NonNull final PDPageContentStream pdPageContentStream) 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;
|
||||
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
||||
boolean isPainting = false;
|
||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
||||
final Tile currentTile = labyrinth.getTileAt(x, y);
|
||||
if (currentTile.hasWallAt(Direction.TOP)) {
|
||||
if (!isPainting) {
|
||||
pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
isPainting = true;
|
||||
}
|
||||
} else {
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
isPainting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
}
|
||||
}
|
||||
|
@ -83,45 +104,46 @@ public class PDFRenderer implements Renderer<byte[]> {
|
|||
final Tile currentTile = labyrinth.getTileAt(x, y - 1);
|
||||
if (currentTile.hasWallAt(Direction.BOTTOM)) {
|
||||
if (!isPainting) {
|
||||
pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
isPainting = true;
|
||||
}
|
||||
} else {
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
isPainting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin);
|
||||
pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
private void drawVerticalLines(@NonNull final Labyrinth labyrinth, @NonNull final PDPageContentStream pdPageContentStream, final float margin, final float scale) throws IOException {
|
||||
private void drawVerticalLines(@NonNull final Labyrinth labyrinth,
|
||||
@NonNull final PDPageContentStream pdPageContentStream) 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;
|
||||
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
||||
boolean isPainting = false;
|
||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
||||
final Tile currentTile = labyrinth.getTileAt(x, y);
|
||||
if (currentTile.hasWallAt(Direction.LEFT)) {
|
||||
if (!isPainting) {
|
||||
pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
isPainting = true;
|
||||
}
|
||||
} else {
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
isPainting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin);
|
||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
}
|
||||
}
|
||||
|
@ -131,20 +153,56 @@ public class PDFRenderer implements Renderer<byte[]> {
|
|||
final Tile currentTile = labyrinth.getTileAt(x - 1, y);
|
||||
if (currentTile.hasWallAt(Direction.RIGHT)) {
|
||||
if (!isPainting) {
|
||||
pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
isPainting = true;
|
||||
}
|
||||
} else {
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin);
|
||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
isPainting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPainting) {
|
||||
pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin);
|
||||
pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN);
|
||||
pdPageContentStream.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
private void drawSolution(@NonNull final Labyrinth labyrinth,
|
||||
@NonNull final PDPageContentStream pdPageContentStream) throws IOException {
|
||||
// Draw the solution in red
|
||||
pdPageContentStream.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));
|
||||
do {
|
||||
Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition);
|
||||
previousPosition = currentPosition;
|
||||
currentPosition = newCurrent;
|
||||
pdPageContentStream.lineTo(MARGIN + currentPosition.getX() * SCALE + SCALE / 2, MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2));
|
||||
} while (!currentPosition.equals(end));
|
||||
pdPageContentStream.stroke();
|
||||
}
|
||||
|
||||
private Position findNextSolutionPosition(@NonNull final Labyrinth labyrinth, @Nullable final Position previousPosition, @NonNull final Position currentPosition) {
|
||||
final Tile currentTile = labyrinth.getTileAt(currentPosition);
|
||||
for (final Direction direction : Direction.values()) {
|
||||
if (!currentTile.hasWallAt(direction)) {
|
||||
final Position position = direction.translate(currentPosition);
|
||||
if (position.equals(previousPosition) || !isValid(position)) {
|
||||
continue;
|
||||
}
|
||||
if (labyrinth.getTileAt(position).isSolution()) {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We *SHOULD* never get here. ... famous last words ...
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue