diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/AbstractPrintableData.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/AbstractPrintableData.java new file mode 100644 index 0000000000000000000000000000000000000000..1c068702de5f4688189d14e762d495d33ac5fbd0 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/AbstractPrintableData.java @@ -0,0 +1,33 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Format; + +/** + * Abstract parent class for all {@link PrintableData} implementations. + * @author Georg Graßnick + * @version 2019.06.26 + */ +abstract class AbstractPrintableData implements PrintableData { + + private final Printer mPrinter; + private final Format mFormat; + + AbstractPrintableData(final Printer printer, final Format format) { + if (printer == null || format == null) { + throw new NullPointerException(); + } + mPrinter = printer; + mFormat = format; + } + + @Override + public Printer getPrinterConfig() { + return mPrinter; + } + + @Override + public Format getFormatConfig() { + return mFormat; + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/BrailleCell6.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/BrailleCell6.java new file mode 100644 index 0000000000000000000000000000000000000000..37e75db44ade2a67cfc735c5c5ffe67dcdb67fd1 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/BrailleCell6.java @@ -0,0 +1,104 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +/** + * Simple container class encapsulating 6 dots to form a representation of a Braille cell. + * The ordering of the positions follows the following convention: + * Top to bottom, then left to right; indices start at 0: + * + * 0 3 + * 1 4 + * 2 5 + * + * @param <T> The type used for representing the intensity. Could be set to {@link Boolean} for basic Braille support, + * but could also by set to {@link Short} if different embossing strengths are required. + * @author Georg Graßnick + * @version 2019.06.28 + */ +public final class BrailleCell6<T> { + + static final int DOT_COUNT = 6; + static final int ROW_COUNT = 3; + static final int COLUMN_COUNT = 2; + + private T[] mDots; + + /** + * Constructor. + * The values are not checked for null! + * @param first Value of the first dot. + * @param second Value of the second dot. + * @param third Value of the third dot. + * @param fourth Value of the fourth dot. + * @param fifth Value of the fifth dot. + * @param sixth Value of the sixth dot. + */ + @SuppressWarnings({"unchecked", "checkstyle:MagicNumber"}) + public BrailleCell6(final T first, final T second, final T third, final T fourth, final T fifth, final T sixth) { + mDots = (T[]) new Object[DOT_COUNT]; + mDots[0] = first; + mDots[1] = second; + mDots[2] = third; + mDots[3] = fourth; + mDots[4] = fifth; + mDots[5] = sixth; + } + + /** + * Constructor. + * The values are not checked for null! + * @param vals An array of values to obtain the values from. + * @throws IllegalArgumentException If the length is not equal to 6. + */ + BrailleCell6(final T[] vals) { + if (vals.length != DOT_COUNT) { + throw new IllegalArgumentException("Input Array must be of length " + DOT_COUNT); + } + mDots = vals.clone(); + } + + /** + * Get the value at the specified position. + * @param index The index of the position, + * @return The according value. + * @throws ArrayIndexOutOfBoundsException If the index is out of bounds (not in 0-5). + */ + public T get(final int index) { + if (index < 0 || index >= DOT_COUNT) { + throw new ArrayIndexOutOfBoundsException("Index not valid"); + } + return mDots[index]; + } + + /** + * Set the value at the specified position. + * @param index The index of the position. + * @param value The value to set. + * @throws ArrayIndexOutOfBoundsException If the index is out of bounds (not in 0-5). + */ + public void set(final int index, final T value) { + if (index < 0 || index >= DOT_COUNT) { + throw new ArrayIndexOutOfBoundsException("Index not valid"); + } + mDots[index] = value; + } + + /** + * Get the internal data array. + * @return The internal data array of length 6. + */ + public T[] data() { + return mDots; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ROW_COUNT; i++) { + for (int j = 0; j < COLUMN_COUNT; j++) { + sb.append(mDots[i * COLUMN_COUNT + j]); + sb.append(" "); + } + sb.append("\n"); + } + return sb.toString(); + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/FloatingPointData.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/FloatingPointData.java new file mode 100644 index 0000000000000000000000000000000000000000..67a34488e35a42ed95c58ce66038c044b52841a7 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/FloatingPointData.java @@ -0,0 +1,27 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import java.util.Iterator; + +/** + * This data is used to describe the data for the "Floating Dot Area" print mode. + * For each dot to emboss, there is one {@link Point2D} object which encapsulates both the position in width and height, + * as well as the intensity of the point. + * @param <T> The type used for representing the intensity. Could be set to {@link Boolean} for basic Braille support, + * but could also by set to {@link Short} if different embossing strengths are required. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public interface FloatingPointData<T> extends PrintableData { + + /** + * Returns an iterator over all {@link Point2DValued}. + * @return An iterator over all points. + */ + Iterator<Point2DValued<T>> getIterator(); + + /** + * Add a point to the data structure. + * @param point The point to be inserted. + */ + void addPoint(Point2DValued<T> point); +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/MatrixData.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/MatrixData.java new file mode 100644 index 0000000000000000000000000000000000000000..b01567c7860b90f8f365dce5f45fb8d4a9825ec0 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/MatrixData.java @@ -0,0 +1,81 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import java.util.Iterator; + +/** + * This data is used to describe the data for the "Braille" and "Graphics" print modes. + * The data is organized in a matrix structure, which can be queried for its values on integer x (row) and y (column) indices. + * @param <T> The type used for representing the intensity. Could be set to {@link Boolean} for basic Braille support, + * but could also by set to {@link Short} if different embossing strengths are required. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public interface MatrixData<T> extends PrintableData { + + /** + * Get the value for a specific position in the matrix. + * Indices start at 0. + * @param row The row index of the position. + * @param column The column index of the position. + * @return The value at the requested position. + */ + T getValue(int row, int column); + + /** + * Get an iterator which iterates all dots of the matrix. + * Depending on the width and height parameters, the iterator will iterate the dots of Braille cells of the + * specified size from top to bottom and then from left to right + * Example: width = 2, height = 3; matrix size is 4x6: + * + * 01 04 07 10 + * 02 05 08 11 + * 03 06 09 12 + * 13 16 19 22 + * 14 17 20 23 + * 15 18 21 24 + * + * @param width The width of a Braille cell + * @param height The height of a Braille cell + * @return The according iterator. + */ + Iterator<T> getDotIterator(int width, int height); + + + /** + * Get an iterator which iterates over Braille cells of the matrix. + * The cells have a width of 2 columns and a height of 3 rows to mach a standard 6 dot Braille cell. + * The matrix is traversed from left to right and then top to bottom. + * Example: matrix size is 4x6 - The ids specify the associated Braille cell. + * + * 01 01 02 02 + * 01 01 02 02 + * 01 01 02 02 + * 03 03 04 04 + * 03 03 04 04 + * 03 03 04 04 + * + * @return The according iterator. + */ + Iterator<BrailleCell6<T>> getBrailleCell6Iterator(); + + /** + * Set the value at a specific position. + * Indices start at 0. + * @param row The row index of the position. + * @param column The column index of the position. + * @param value The value to set. + */ + void setValue(int row, int column, T value); + + /** + * Getter. + * @return The number of rows. + */ + int getRowCount(); + + /** + * Getter. + * @return The number of columns. + */ + int getColumnCount(); +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/Point2D.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/Point2D.java new file mode 100644 index 0000000000000000000000000000000000000000..6bcf6401ae76d18b5cf355702617700c92d2a016 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/Point2D.java @@ -0,0 +1,77 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import javax.measure.Quantity; +import javax.measure.quantity.Length; +import java.util.Objects; + +/** + * Representation of a 2 dimensional point. + * Encapsulates a position on x and y axis. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public class Point2D { + + private final Quantity<Length> mX; + private final Quantity<Length> mY; + + /** + * Constructor. + * @param x Position on the x axis. + * @param y Position on the y axis. + */ + public Point2D(final Quantity<Length> x, final Quantity<Length> y) { + if (x == null || y == null) { + throw new NullPointerException(); + } + mX = x; + mY = y; + } + + /** + * Getter. + * @return The position on the x axis. + */ + public final Quantity<Length> getX() { + return mX; + } + + /** + * Getter. + * @return The position on the y axis. + */ + public final Quantity<Length> getY() { + return mY; + } + + /** + * Check for Object equality. + * @param other The other to compare to. + * @return true, if X and Y positions of both points are equal; else false + */ + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Point2D)) { + return false; + } + Point2D point = (Point2D) other; + return mX.equals(point.mX) && mY.equals(point.mY); + } + + @Override + public int hashCode() { + return Objects.hash(mX, mY); + } + + /** + * Create a human readable String to represent the point. + * @return A human readable String. + */ + @Override + public String toString() { + return "(" + mX + ", " + mY + ")"; + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/Point2DValued.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/Point2DValued.java new file mode 100644 index 0000000000000000000000000000000000000000..8b674c972cb3785bf681d03d02620089427ce2fc --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/Point2DValued.java @@ -0,0 +1,71 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import javax.measure.Quantity; +import javax.measure.quantity.Length; +import java.util.Objects; + +/** + * Representation of a 2 dimensional point with an associated value. + * Encapsulates both the position on x and y axis, as well as a value (think of embossing intensity). + * @param <T> The type used for representing the intensity. Could be set to {@link Boolean} for basic Braille support, + * but could also by set to {@link Short} if different embossing strengths are required. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public class Point2DValued<T> extends Point2D { + + private final T mVal; + + /** + * Constructor. + * @param x Position on the x axis. + * @param y Position on the y axis. + * @param val The value of the dot + */ + public Point2DValued(final Quantity<Length> x, final Quantity<Length> y, final T val) { + super(x, y); + if (val == null) { + throw new NullPointerException(); + } + mVal = val; + } + + /** + * Getter. + * @return The value that is associated with this point. + */ + public final T getVal() { + return mVal; + } + + /** + * Check for Object equality. + * @param other The other to compare to. + * @return true, if X and Y positions and the values of both points are equal; else false + */ + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Point2DValued)) { + return false; + } + Point2D point = (Point2DValued) other; + return super.equals(other) && mVal.equals(((Point2DValued) other).mVal); + } + + @Override + public int hashCode() { + return Objects.hash(mVal, super.hashCode()); + } + + /** + * Create a human readable String to represent the point. + * @return A human readable String. + */ + @Override + public String toString() { + return "(" + super.getX() + ", " + super.getY() + ": " + mVal + ")"; + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/PrintableData.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/PrintableData.java new file mode 100644 index 0000000000000000000000000000000000000000..0ba23f88dfe5d83e055887801a3c75879c81d917 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/PrintableData.java @@ -0,0 +1,26 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Format; + +/** + * Top interface for all data types that describe data ready for printing. + * These data containers are generated by the rasterizer and later on processed by the printer backend. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public interface PrintableData { + + /** + * Getter for the Printer Configuration, that was used to generate this data representation in the rasterizer. + * @return The associated Printer Configuration + */ + Printer getPrinterConfig(); + + /** + * Getter for the Format Configuration, that was used to generate this data representation in the rasterizer. + * @return The associated Format Configuration + */ + Format getFormatConfig(); + +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/SimpleFloatingPointDataImpl.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/SimpleFloatingPointDataImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a8a61648047214203c61be32c81d7a033b4514b2 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/SimpleFloatingPointDataImpl.java @@ -0,0 +1,38 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import java.util.Iterator; +import java.util.LinkedList; + +import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Format; + +/** + * A low effort implementation of the {@link FloatingPointData} interface. + * The underlying data is organized in a {@link LinkedList}, which makes insertions fast, but slows down random access. + * @param <T> The type used for representing the intensity. Could be set to {@link Boolean} for basic Braille support, + * but could also by set to {@link Short} if different embossing strengths are required. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public class SimpleFloatingPointDataImpl<T> extends AbstractPrintableData implements FloatingPointData<T> { + + private LinkedList<Point2DValued<T>> mPoints; + + public SimpleFloatingPointDataImpl(final Printer printer, final Format format) { + super(printer, format); + mPoints = new LinkedList<>(); + } + + @Override + public Iterator<Point2DValued<T>> getIterator() { + return mPoints.iterator(); + } + + @Override + public void addPoint(final Point2DValued<T> point) { + if (point == null) { + throw new NullPointerException(); + } + mPoints.addLast(point); + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/SimpleMatrixDataImpl.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/SimpleMatrixDataImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..64f2c39f47547cd6e06d6d22c1ada5ab1cb47868 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/SimpleMatrixDataImpl.java @@ -0,0 +1,192 @@ +package de.tudresden.inf.mci.brailleplot.printabledata; + +import java.util.Iterator; +import java.util.Vector; + +import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Format; + +/** + * A low effort implementation of the {@link MatrixData} interface. + * The underlying data is represented by a {@link Vector} which makes the lookup and insertion fast, but uses lots of memory. + * @param <T> The type used for representing the intensity. Could be set to {@link Boolean} for basic Braille support, + * * but could also by set to {@link Short} if different embossing strengths are required. + * @author Georg Graßnick + * @version 2019.06.26 + */ +public class SimpleMatrixDataImpl<T> extends AbstractPrintableData implements MatrixData<T> { + + private final int mRows; + private final int mColumns; + private final Vector<T> mData; + + /** + * Constructor. + * @param printer The according {@link Printer} object. + * @param format The according {@link Format} object. + * @param rowCount The height of the matrix. + * @param columnCount The width of the matrix. + * @param defaultValue The default value each element will be assigned. + * @throws IllegalArgumentException if rowCount {@literal <} 0 or columnCount {@literal <} 0 + */ + public SimpleMatrixDataImpl(final Printer printer, final Format format, final int rowCount, final int columnCount, final T defaultValue) { + super(printer, format); + if (rowCount <= 0 || columnCount <= 0) { + throw new IllegalArgumentException("rowCount and columnCount must be a non zero positive integer"); + } + mRows = rowCount; + mColumns = columnCount; + mData = new Vector<>(rowCount * columnCount); + mData.setSize(rowCount * columnCount); + for (int i = 0; i < mData.size(); i++) { + mData.setElementAt(defaultValue, i); + } + } + + /** + * Calculate the index for the underlying {@link java.util.ArrayList}. + * @param row The row index of the requested index. + * @param column The column index of the requested index. + * @return The according index in the underlying {@link java.util.ArrayList} + * @throws IndexOutOfBoundsException If row or column are negative or larger than the size of the matrix. + */ + private int calcIndex(final int row, final int column) { + if (row >= mRows || column > mColumns || row < 0 || column < 0) { + throw new IndexOutOfBoundsException("Index (" + row + "," + column + ") out of bounds"); + } + return row * mColumns + column; + } + + @Override + public T getValue(final int row, final int column) { + return mData.get(calcIndex(row, column)); + } + + @Override + public void setValue(final int row, final int column, final T value) { + if (value == null) { + throw new NullPointerException(); + } + mData.set(calcIndex(row, column), value); + } + + @Override + public Iterator<T> getDotIterator(final int width, final int height) { + return new ElementIter(width, height, this); + } + + @Override + public Iterator<BrailleCell6<T>> getBrailleCell6Iterator() { + return new BrailleCell6Iterator(this); + } + + @Override + public int getColumnCount() { + return mColumns; + } + + @Override + public int getRowCount() { + return mRows; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < getRowCount(); i++) { + for (int j = 0; j < getColumnCount(); j++) { + sb.append(getValue(i, j)); + sb.append(" "); + } + sb.append("\n"); + } + return sb.toString(); + } + + /** + * Iterator that iterates all elements of the matrix in a pattern that iterates Braille cells of specified height + * and width from left to right and top to bottom. + * See {@link MatrixData#getDotIterator(int, int)} for details. + */ + class ElementIter implements Iterator<T> { + + private final SimpleMatrixDataImpl<T> mMatrix; + + private final int mCellWidth; + private final int mCellHeight; + + // We use indices starting at 1, so that we do not have to check for the x-index to be 0 in the next() method call + private int mCurrentX = 1; + private int mCurrentY = 1; + + private boolean mIsFirstElem = true; + + ElementIter(final int cellWidth, final int cellHeight, final SimpleMatrixDataImpl<T> matrix) { + if (matrix.getColumnCount() % cellWidth != 0) { + throw new IllegalArgumentException("Cannot create requested iterator: matrix column count (" + matrix.getColumnCount() + ") is not a multiple of cell height (" + cellHeight + ")"); + } + if (matrix.getRowCount() % cellHeight != 0) { + throw new IllegalArgumentException("Cannot create requested iterator: matrix row count (" + matrix.getRowCount() + ") is not a multiple of cell width (" + cellWidth + ")"); + } + mMatrix = matrix; + mCellWidth = cellWidth; + mCellHeight = cellHeight; + } + + @Override + public boolean hasNext() { + return !(mCurrentY == mMatrix.getRowCount() && mCurrentX == mMatrix.getColumnCount()); + } + + @Override + public T next() { + if (mIsFirstElem) { + mIsFirstElem = false; + } else if (mCurrentY % mCellHeight != 0) { + // Staying in the current cell, move down + mCurrentY++; + } else if (mCurrentX % mCellWidth != 0) { + // Staying in current cell, move right, set y to the top most index of the current cell + mCurrentX++; + mCurrentY = (((mCurrentY / mCellHeight) - 1) * mCellHeight) + 1; + } else if (mCurrentX < mMatrix.getColumnCount()) { // Moving on to the next cell + // Right is possible + mCurrentX += 1; + mCurrentY = (((mCurrentY / mCellHeight) - 1) * mCellHeight) + 1; + } else { + // We need to go downwards + mCurrentY += 1; + mCurrentX = 1; + } + // Correct index to match the specifications of the MatrixData interface + return mMatrix.getValue(mCurrentY - 1, mCurrentX - 1); + } + } + + /** + * Iterator that returns {@link BrailleCell6} objects rather than the dots themselves. + * See {@link MatrixData#getBrailleCell6Iterator()} for details. + */ + class BrailleCell6Iterator implements Iterator<BrailleCell6<T>> { + + private final Iterator<T> mElemIter; + + BrailleCell6Iterator(final SimpleMatrixDataImpl<T> matrix) { + mElemIter = matrix.getDotIterator(BrailleCell6.COLUMN_COUNT, BrailleCell6.ROW_COUNT); + } + + @Override + public boolean hasNext() { + return mElemIter.hasNext(); + } + + @Override + @SuppressWarnings("unchecked") + public BrailleCell6<T> next() { + T[] vals = (T[]) new Object[BrailleCell6.DOT_COUNT]; + for (int i = 0; i < BrailleCell6.DOT_COUNT; i++) { + vals[i] = mElemIter.next(); + } + return new BrailleCell6<>(vals); + } + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/package-info.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..807aba761ac1322d538c04c6479d5483e55fb3a5 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printabledata/package-info.java @@ -0,0 +1,7 @@ +/** + * This package contains all the requiered classes and interfaces for data exchange between the rasterizer and + * the printer backend. + * @author Georg Graßnick + * @version 2019.06.26 + */ +package de.tudresden.inf.mci.brailleplot.printabledata;