diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java index b7ee3097e4e621375eba2c7e42249a2520e1cdc1..84f2387ea47b1cc576f08def17c0fb60353bc2a8 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java @@ -4,6 +4,7 @@ import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.JavaPropertiesConfigurationParser; import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Representation; import de.tudresden.inf.mci.brailleplot.diagrams.CategoricalBarChart; import de.tudresden.inf.mci.brailleplot.layout.PlotCanvas; import de.tudresden.inf.mci.brailleplot.layout.RasterCanvas; @@ -172,6 +173,7 @@ public final class App { ); Printer indexV4Printer = configParser.getPrinter(); Format a4Format = configParser.getFormat("A4"); + Representation representationParameters = configParser.getRepresentation(); // Parse csv data ClassLoader classloader = Thread.currentThread().getContextClassLoader(); @@ -184,7 +186,7 @@ public final class App { CategoricalBarChart barChart = new CategoricalBarChart(container); // Render diagram - MasterRenderer renderer = new MasterRenderer(indexV4Printer, a4Format); + MasterRenderer renderer = new MasterRenderer(indexV4Printer, representationParameters, a4Format); RasterCanvas canvas = renderer.rasterize(barChart); // SVG exporting SvgExporter<RasterCanvas> svgExporter = new BoolMatrixDataSvgExporter(canvas); @@ -192,7 +194,7 @@ public final class App { svgExporter.dump("boolMat"); // FloatingPointData SVG exporting example - PlotCanvas floatCanvas = new PlotCanvas(indexV4Printer, a4Format); + PlotCanvas floatCanvas = new PlotCanvas(indexV4Printer, representationParameters, a4Format); FloatingPointData<Boolean> points = floatCanvas.getNewPage(); final int blockX = 230; diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationParser.java b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationParser.java index 49872d3a3ed16eb889a19a19a62088add3e8c205..01645f44310c711caa3395b0fd0c54a85161bc73 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationParser.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationParser.java @@ -21,11 +21,14 @@ public abstract class ConfigurationParser { private ConfigurationValidator mValidator; private Printer mPrinter; + private Representation mRepresentation; private Map<String, Format> mFormats = new HashMap<>(); private File mCurrentConfigFile; private List<PrinterProperty> mPrinterProperties = new ArrayList<>(); + private List<RepresentationProperty> mRepresentationProperties = new ArrayList<>(); private Map<String, List<FormatProperty>> mFormatProperties = new HashMap<>(); private Printer mDefaultPrinter; + private Representation mDefaultRepresentation; private Format mDefaultFormat; ConfigurationParser() { @@ -53,6 +56,14 @@ public abstract class ConfigurationParser { return mCurrentConfigFile; } + /** + * Get the representation configuration. + * @return A {@link Representation} object, representing the representation properties. + */ + public final Representation getRepresentation() { + return mRepresentation; + } + /** * Get the printer configuration. * @return A {@link Printer} object, representing the printers properties. @@ -101,16 +112,24 @@ public abstract class ConfigurationParser { } /** - * Add a general printer property to the internal printer configuration representation. - * @param property The represented property of the printer. + * Add a general printer property to the internal representation configuration. + * @param property The property of the printer. */ protected void addProperty(final PrinterProperty property) { mPrinterProperties.add(property); } /** - * Add a specific format property to the internal list of format configuration representation. - * @param property The represented property of a specific format. + * Add a general representation property to the internal printer configuration. + * @param property The property of the representation. + */ + protected void addProperty(final RepresentationProperty property) { + mRepresentationProperties.add(property); + } + + /** + * Add a specific format property to the internal list of format configuration. + * @param property The property of a specific format. */ protected void addProperty(final FormatProperty property) { String formatName = property.getFormat(); @@ -124,17 +143,19 @@ public abstract class ConfigurationParser { * Set the optional default configurations for {@link Printer} and {@link Format} objects created by this parser. * This method should be called inside the concrete parsers constructor. * @param defaultPrinter A {@link Printer} object containing the default properties or null for no default to be set. + * @param defaultRepresentation A {@link Representation} object containing the default properties or null for no default to be set. * @param defaultFormat A {@link Format} object containing the default properties or null for no default to be set. */ - protected final void setDefaults(final Printer defaultPrinter, final Format defaultFormat) { + protected final void setDefaults(final Printer defaultPrinter, final Representation defaultRepresentation, final Format defaultFormat) { mDefaultPrinter = defaultPrinter; + mDefaultRepresentation = defaultRepresentation; mDefaultFormat = defaultFormat; } /** * Parse the specified configuration file. * This method should be called inside the concrete parsers constructor after the optional default configurations - * ({@link #setDefaults(Printer, Format)}) and the validator ({@link #setValidator(ConfigurationValidator)}) have been set. + * ({@link #setDefaults(Printer, Representation, Format)}) and the validator ({@link #setValidator(ConfigurationValidator)}) have been set. * @param filePath The configuration file to be parsed. The type depends on the concrete implementation of the parser. * @param assertCompleteness Signals whether to check for existence of all required properties or not. * @throws ConfigurationParsingException On any error while accessing the configuration file or syntax @@ -152,11 +173,16 @@ public abstract class ConfigurationParser { closeInputStream(input); // build printer object from added properties mPrinter = new Printer(mPrinterProperties); + mRepresentation = new Representation(mRepresentationProperties); if (mDefaultPrinter != null) { mPrinter.setFallback(mDefaultPrinter); } + if (mDefaultRepresentation != null) { + mRepresentation.setFallback(mDefaultRepresentation); + } if (assertCompleteness) { mValidator.checkPrinterConfigComplete(mPrinter); + mValidator.checkRepresentationConfigComplete(mRepresentation); } // build format objects from added properties for (String formatName : mFormatProperties.keySet()) { diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationValidator.java b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationValidator.java index adb711d4848cfe6b4fcaeaf8e56bf0a795077cb8..44d325ce820644626c61ea8af4be6fc09b5a9c83 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationValidator.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/ConfigurationValidator.java @@ -23,6 +23,13 @@ public interface ConfigurationValidator { */ void checkPrinterConfigComplete(Printer printerConfig); + /** + * Check whether the given {@link Representation} configuration is complete, meaning that it contains all + * properties that were declared as 'required' for the representation namespace. + * @param representationConfig The {@link Representation} configuration instance to be checked. + */ + void checkRepresentationConfigComplete(Representation representationConfig); + /** * Check whether the given {@link Format} configuration is complete, meaning that it contains all * properties that were declared as 'required' for the format namespace. diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationParser.java b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationParser.java index d86746d066748274e318cc954cd9c2ce527d70a1..27757535442964751c78bc96f910dc0d90bf8bbb 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationParser.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationParser.java @@ -30,7 +30,7 @@ public final class JavaPropertiesConfigurationParser extends ConfigurationParser ) throws ConfigurationParsingException, ConfigurationValidationException { setValidator(new JavaPropertiesConfigurationValidator()); parseConfigFile(defaultPath, false); - setDefaults(getPrinter(), getFormat("default")); + setDefaults(getPrinter(), getRepresentation(), getFormat("default")); parseConfigFile(filePath, true); } @@ -70,6 +70,9 @@ public final class JavaPropertiesConfigurationParser extends ConfigurationParser if (property instanceof PrinterProperty) { addProperty((PrinterProperty) property); } + if (property instanceof RepresentationProperty) { + addProperty((RepresentationProperty) property); + } } private void includeFiles(final String fileList) throws ConfigurationParsingException, ConfigurationValidationException { diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationValidator.java b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationValidator.java index d4f9b6b08262eed619f3f92cde1ce8ef458f6fca..587b3e9a17c6974354f9aa0961b134821513d798 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationValidator.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/JavaPropertiesConfigurationValidator.java @@ -7,7 +7,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; import java.util.Objects; import java.util.function.Predicate; import java.util.regex.Pattern; @@ -20,12 +19,14 @@ import java.util.regex.Pattern; public final class JavaPropertiesConfigurationValidator implements ConfigurationValidator { private final String mPrinterPrefix = "printer"; + private final String mRepresentationPrefix = "representation"; private final String mFormatPrefix = "format"; private final HashMap<String, Predicate<String>> mValidPrinterProperties = new HashMap<>(); + private final HashMap<String, Predicate<String>> mValidRepresentationProperties = new HashMap<>(); private final HashMap<String, Predicate<String>> mValidFormatProperties = new HashMap<>(); - private final HashMap<String, ArrayList<String>> mCompletenessCheck = new HashMap<>(); private final ArrayList<String> mRequiredPrinterProperties = new ArrayList<>(); + private final ArrayList<String> mRequiredRepresentationProperties = new ArrayList<>(); private final ArrayList<String> mRequiredFormatProperties = new ArrayList<>(); public JavaPropertiesConfigurationValidator() { @@ -34,13 +35,13 @@ public final class JavaPropertiesConfigurationValidator implements Configuration Predicate<String> requireEmpty = String::isEmpty; Predicate<String> requireNotEmpty = requireEmpty.negate(); Predicate<String> requireInteger = JavaPropertiesConfigurationValidator::checkIfInteger; + Predicate<String> requireNonZero = JavaPropertiesConfigurationValidator::checkIfNonZero; Predicate<String> requireDouble = JavaPropertiesConfigurationValidator::checkIfDouble; Predicate<String> requireBoolean = JavaPropertiesConfigurationValidator::checkIfBoolean; Predicate<String> requirePositive = JavaPropertiesConfigurationValidator::checkIfPositive; Predicate<String> requireFileExists = JavaPropertiesConfigurationValidator::checkIfFileExists; // Definition of valid printer properties - Map<String, Predicate<String>> p = new HashMap<>(); definePrinterProperty("name", requireNotEmpty); definePrinterProperty("mode", requireNotEmpty); definePrinterProperty("brailletable", requireFileExists); @@ -63,7 +64,6 @@ public final class JavaPropertiesConfigurationValidator implements Configuration definePrinterProperty("raster.dotDiameter", requireDouble.and(requirePositive)); // Definition of valid format properties - Map<String, Predicate<String>> f = new HashMap<>(); defineFormatProperty("page.width", requireInteger.and(requirePositive)); defineFormatProperty("page.height", requireInteger.and(requirePositive)); defineFormatProperty("margin.top", requireInteger.and(requirePositive)); @@ -71,6 +71,15 @@ public final class JavaPropertiesConfigurationValidator implements Configuration defineFormatProperty("margin.bottom", requireInteger.and(requirePositive)); defineFormatProperty("margin.left", requireInteger.and(requirePositive)); + // Definition of valid representation properties + defineRepresentationProperty("general.nonexistentDataText", requireNotEmpty); + defineRepresentationProperty("general.maxTitleHeight", requireInteger.and(requirePositive).and(requireNonZero)); + defineRepresentationProperty("rasterize.barChart.maxBarThickness", requireInteger.and(requirePositive)); + defineRepresentationProperty("rasterize.barChart.minBarThickness", requireInteger.and(requirePositive)); + defineRepresentationProperty("rasterize.barChart.padding.title", requireInteger); + defineRepresentationProperty("rasterize.barChart.padding.caption", requireInteger); + defineRepresentationProperty("rasterize.barChart.padding.groups", requireInteger); + defineRepresentationProperty("rasterize.barChart.padding.bars", requireInteger); } /** @@ -91,6 +100,26 @@ public final class JavaPropertiesConfigurationValidator implements Configuration private void definePrinterProperty(final String propertyName, final Predicate<String> validation, final boolean required) { defineProperty(mValidPrinterProperties, propertyName, validation, required, mRequiredPrinterProperties); } + + /** + * Use this function in the validators constructor to add a representation property definition to the internal validation table. + * The property will be treated as 'required'. + * @param propertyName The name of the property. (The prefix 'representation.' must be omitted.) + * @param validation The validation predicate. {@link Predicate}<{@link String}> + */ + private void defineRepresentationProperty(final String propertyName, final Predicate<String> validation) { + defineRepresentationProperty(propertyName, validation, true); + } + /** + * Use this function in the validators constructor to add a representation property definition to the internal validation table. + * @param propertyName The name of the property. (The prefix 'representation.' must be omitted.) + * @param validation The validation predicate. {@link Predicate}<{@link String}> + * @param required Signals whether this is a required property or not. + */ + private void defineRepresentationProperty(final String propertyName, final Predicate<String> validation, final boolean required) { + defineProperty(mValidRepresentationProperties, propertyName, validation, required, mRequiredRepresentationProperties); + } + /** * Use this function in the validators constructor to add a format property definition to the internal validation table. * The property will be treated as 'required'. @@ -109,6 +138,8 @@ public final class JavaPropertiesConfigurationValidator implements Configuration private void defineFormatProperty(final String propertyName, final Predicate<String> validation, final boolean required) { defineProperty(mValidFormatProperties, propertyName, validation, required, mRequiredFormatProperties); } + + private void defineProperty(final HashMap<String, Predicate<String>> defTable, final String propertyName, final Predicate<String> validation, final boolean required, final ArrayList<String> checkList) { defTable.put(propertyName, validation); @@ -145,6 +176,16 @@ public final class JavaPropertiesConfigurationValidator implements Configuration } validationLookup(mValidPrinterProperties, propertyName, value); return new PrinterProperty(propertyName, value); + } else if (prefix.equals(mRepresentationPrefix)) { + if (keyParts.length <= 1) { + throw new ConfigurationValidationException("Invalid representation property key: " + key); + } + String propertyName = keyParts[1]; + if (keyParts.length > 2) { + propertyName = propertyName + "." + keyParts[2]; + } + validationLookup(mValidRepresentationProperties, propertyName, value); + return new RepresentationProperty(propertyName, value); } else if (prefix.equals(mFormatPrefix)) { if (keyParts.length <= 2) { throw new ConfigurationValidationException("Invalid format property key: " + key); @@ -164,6 +205,10 @@ public final class JavaPropertiesConfigurationValidator implements Configuration checkCompleteness(printerConfig, mRequiredPrinterProperties); } @Override + public void checkRepresentationConfigComplete(final Representation representationConfig) { + checkCompleteness(representationConfig, mRequiredRepresentationProperties); + } + @Override public void checkFormatConfigComplete(final Format formatConfig) { checkCompleteness(formatConfig, mRequiredFormatProperties); } @@ -236,6 +281,14 @@ public final class JavaPropertiesConfigurationValidator implements Configuration } } + private static boolean checkIfNonZero(final String value) { + try { + return (Double.parseDouble(value) != 0); + } catch (NumberFormatException e) { + return false; + } + } + private static boolean checkIfFileExists(final String filePath) { try { FileInputStream stream = new FileInputStream(filePath); diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/Representation.java b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/Representation.java new file mode 100644 index 0000000000000000000000000000000000000000..7fdb61d1db86fb1eccbe6377075d24095ffd934a --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/Representation.java @@ -0,0 +1,27 @@ +package de.tudresden.inf.mci.brailleplot.configparser; + +import java.util.ArrayList; +import java.util.List; + +/** + * Configuration properties that describe parameters for the representation of charts. + * @author Leonard Kupper + * @version 2019.09.25 + */ +public final class Representation extends Configurable { + + /** + * Constructor. + * + * @param properties A {@link List} of {@link RepresentationProperty} objects. + */ + public Representation(final List<RepresentationProperty> properties) { + mProperties = new ArrayList<>(); + mProperties.addAll(properties); + } + + @Override + public String toString() { + return "representation configuration"; + } +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/RepresentationProperty.java b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/RepresentationProperty.java new file mode 100644 index 0000000000000000000000000000000000000000..6ddcc3a9dbb29a9f74cc0455ce5515efbb37f5e2 --- /dev/null +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/configparser/RepresentationProperty.java @@ -0,0 +1,20 @@ +package de.tudresden.inf.mci.brailleplot.configparser; + +/** + * A property describing a representational aspect or parameter of charts. + * @author Leonard Kupper + * @version 2019.09.25 + */ +public final class RepresentationProperty extends ValidProperty { + + /** + * Constructor. + * + * @param name The name of the property. + * @param value The value of the property. + */ + RepresentationProperty(final String name, final String value) { + super(name, value); + } + +} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/AbstractCanvas.java b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/AbstractCanvas.java index d8495f640965a31eecc22e7cd16b9746c0479d3f..b83807d6e51561b609f2fc7228db17c81cbf2c5f 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/AbstractCanvas.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/AbstractCanvas.java @@ -2,6 +2,7 @@ package de.tudresden.inf.mci.brailleplot.layout; import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Representation; import de.tudresden.inf.mci.brailleplot.printabledata.PrintableData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,6 +22,7 @@ public abstract class AbstractCanvas<T extends PrintableData> { private final Logger mLogger = LoggerFactory.getLogger(this.getClass()); Printer mPrinter; + Representation mRepresentation; Format mFormat; Rectangle mPrintableArea; @@ -31,11 +33,12 @@ public abstract class AbstractCanvas<T extends PrintableData> { List<T> mPageContainer; - AbstractCanvas(final Printer printer, final Format format) throws InsufficientRenderingAreaException { + AbstractCanvas(final Printer printer, final Representation representation, final Format format) throws InsufficientRenderingAreaException { mLogger.trace("Creating new canvas"); mPrinter = printer; + mRepresentation = representation; mFormat = format; mPageContainer = new ArrayList<>(); @@ -180,6 +183,22 @@ public abstract class AbstractCanvas<T extends PrintableData> { return mPrinter; } + /** + * Get the Representation Configuration. + * @return A {@link Representation}. + */ + public Representation getRepresentation() { + return mRepresentation; + } + + /** + * Get the Format Configuration. + * @return A {@link Format}. + */ + public Format getFormat() { + return mFormat; + } + public final T getCurrentPage() { if (mPageContainer.size() < 1) { diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/PlotCanvas.java b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/PlotCanvas.java index 6a74413980f348ad78cc1a5a1de5130a758dc294..051f5d5eb2d2586032d33ffe3c56bbc5b674f2d3 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/PlotCanvas.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/PlotCanvas.java @@ -2,6 +2,7 @@ package de.tudresden.inf.mci.brailleplot.layout; import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Representation; import de.tudresden.inf.mci.brailleplot.printabledata.FloatingPointData; import de.tudresden.inf.mci.brailleplot.printabledata.SimpleFloatingPointDataImpl; @@ -13,8 +14,8 @@ import de.tudresden.inf.mci.brailleplot.printabledata.SimpleFloatingPointDataImp */ public class PlotCanvas extends AbstractCanvas<FloatingPointData<Boolean>> { - public PlotCanvas(final Printer printer, final Format format) throws InsufficientRenderingAreaException { - super(printer, format); + public PlotCanvas(final Printer printer, final Representation representation, final Format format) throws InsufficientRenderingAreaException { + super(printer, representation, format); } public final FloatingPointData<Boolean> getNewPage() { diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/RasterCanvas.java b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/RasterCanvas.java index 1d268a577595f878cf2865da11eaa6e8ac754e89..1415ac9e7b457ead7255a22a3e5089206b3ff0b3 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/RasterCanvas.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/RasterCanvas.java @@ -2,6 +2,7 @@ package de.tudresden.inf.mci.brailleplot.layout; import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Representation; import de.tudresden.inf.mci.brailleplot.printabledata.BrailleCell6; import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; import de.tudresden.inf.mci.brailleplot.printabledata.SimpleMatrixDataImpl; @@ -60,16 +61,17 @@ public class RasterCanvas extends AbstractCanvas<MatrixData<Boolean>> { * The described grid is build from uniform 'cells' consisting of a variable amount of dots. * It is used as a target on which can be drawn by a {@link de.tudresden.inf.mci.brailleplot.rendering.Rasterizer}. * @param printer The {@link Printer} configuration to be used. + * @param representation The {@link Representation} configuration to be used. * @param format The {@link Format} configuration to be used. * @param cellWidth The horizontal count of dots in a cell. * @param cellHeight The vertical count of dots in a cell. * @throws InsufficientRenderingAreaException If the given configuration leads to an printable area of negative * size or zero size, e.g. if the sum of defined margins and constraints adds up to be greater than the original page size. */ - RasterCanvas(final Printer printer, final Format format, final int cellWidth, final int cellHeight) + RasterCanvas(final Printer printer, final Representation representation, final Format format, final int cellWidth, final int cellHeight) throws InsufficientRenderingAreaException { - super(printer, format); + super(printer, representation, format); // Cell size in dots mCellWidth = cellWidth; diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/SixDotBrailleRasterCanvas.java b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/SixDotBrailleRasterCanvas.java index cb412f2071d0adbd0fcdf12458307fc9a44fb106..0fa766d659e28f2f8ffcb377d39bfab941c5fb8c 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/layout/SixDotBrailleRasterCanvas.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/layout/SixDotBrailleRasterCanvas.java @@ -2,6 +2,7 @@ package de.tudresden.inf.mci.brailleplot.layout; import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.Printer; +import de.tudresden.inf.mci.brailleplot.configparser.Representation; import de.tudresden.inf.mci.brailleplot.printabledata.BrailleCell6; /** @@ -11,7 +12,7 @@ import de.tudresden.inf.mci.brailleplot.printabledata.BrailleCell6; */ public class SixDotBrailleRasterCanvas extends RasterCanvas { - public SixDotBrailleRasterCanvas(final Printer printer, final Format format) throws InsufficientRenderingAreaException { - super(printer, format, BrailleCell6.COLUMN_COUNT, BrailleCell6.ROW_COUNT); + public SixDotBrailleRasterCanvas(final Printer printer, final Representation representation, final Format format) throws InsufficientRenderingAreaException { + super(printer, representation, format, BrailleCell6.COLUMN_COUNT, BrailleCell6.ROW_COUNT); } } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/BarChartRasterizer.java b/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/BarChartRasterizer.java index 1e62e0db980fb000013b589338d4d8dfd99e00ed..49d07c2396953314d47b74f7fae3781528a5071c 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/BarChartRasterizer.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/BarChartRasterizer.java @@ -11,6 +11,7 @@ import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -35,7 +36,7 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { // Constants private static final int X_AXIS_UNIT_SIZE_DOTS = 4; // the size of one step on the x-axis in dots. Equals the amount of dots after which the used bar textures will repeat private static final int X_AXIS_TICK_SIZE_DOTS = 2; // the size of the x-axis tickmarks in dots - private static final int HELP_LINE_MIN_LENGTH_DOTS = 5; // the min. distance in dots for which a help line from group caption to the groups first bar will appear + private static final int HELP_LINE_MIN_LENGTH_DOTS = 3; // the min. distance in dots for which a help line from group caption to the groups first bar will appear private static final int LEGEND_TEXTURE_BAR_LENGTH = 3; // tells how big (in axis units) texture example bars in the legend are. private static final int DECIMAL_BASE = 10; // the base to which the magnitude of the axis scale will be calculated. change if you love headaches. @@ -51,6 +52,7 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { private int mCaptionPaddingCells; // the padding size between the group captions on the left and the bar groups in cells private int mGroupPaddingCells; // the padding size between two neighbouring bar groups in cells private int mBarPaddingCells; // the padding size between two bars inside the same group in cells + private String nonexistentDataText; // the text which is displayed for a missing datapoint // Texture Management private List<Texture<Boolean>> mTextures = new ArrayList<>(); // A list of textures to differentiate bars inside a group @@ -71,27 +73,29 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { /** * Initialization of algorithm parameters. + * @param canvas The {@link RasterCanvas} on which the rasterizer will work. */ - private void initConfig() { + private void initConfig(final RasterCanvas canvas) { // This method will currently set the properties to some default values, // but we could change it to load them from somewhere else. Please comment in review. - final double tenth = 0.1, fifth = 0.2, quarter = 0.25, half = 0.5; - mUnitScalings = new double[]{tenth, fifth, quarter, half, 1.0}; + final double tenth = 0.1, fifth = 0.2, quarter = 0.25, half = 0.5, full = 1.0; + mUnitScalings = new double[]{tenth, fifth, quarter, half, full}; - mMaximumTitleHeightCells = 2; + mMaximumTitleHeightCells = canvas.getRepresentation().getProperty("general.maxTitleHeight").toInt(); mCaptionLengthCells = 1; mXAxisHeightCells = 2; - final int defaultMaxBarThicknessCells = 3; - mMaxBarThicknessCells = defaultMaxBarThicknessCells; - mMinBarThicknessCells = 1; + mMaxBarThicknessCells = canvas.getRepresentation().getProperty("rasterize.barChart.maxBarThickness").toInt(); + mMinBarThicknessCells = canvas.getRepresentation().getProperty("rasterize.barChart.minBarThickness").toInt(); - mTitlePaddingCells = 0; - mCaptionPaddingCells = 2; - mGroupPaddingCells = 2; - mBarPaddingCells = 1; + mTitlePaddingCells = canvas.getRepresentation().getProperty("rasterize.barChart.padding.title").toInt(); + mCaptionPaddingCells = canvas.getRepresentation().getProperty("rasterize.barChart.padding.caption").toInt(); + mGroupPaddingCells = canvas.getRepresentation().getProperty("rasterize.barChart.padding.groups").toInt(); + mBarPaddingCells = canvas.getRepresentation().getProperty("rasterize.barChart.padding.bars").toInt(); + + nonexistentDataText = canvas.getRepresentation().getProperty("general.nonexistentDataText").toString(); // Load textures double[] rotate90 = {0, 0, 0, 1, 1, 0}; @@ -123,7 +127,7 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { throw new InsufficientRenderingAreaException("This rasterizer can only work with a 6-dot braille grid."); } - initConfig(); + initConfig(canvas); drawDiagram(diagram, canvas); } @@ -213,16 +217,15 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { Rectangle borderBeforeCellArea, barCellArea, borderAfterCellArea; Map<String, String> groupNameExplanations = new LinkedHashMap<>(); Map<Texture<Boolean>, String> textureExplanations = new LinkedHashMap<>(); - // Reserve first line for first border. - borderBeforeCellArea = mFullChartCellArea.removeFromTop(1); + borderBeforeCellArea = mFullChartCellArea.removeFromTop(1); // Reserve first line for first border. char groupCaptionLetter = 'a'; int group = 0; for (PointList pointList : diagram.getDataSet()) { // For each group: String groupName = pointList.getName(); // Save group name for legend groupNameExplanations.put(Character.toString(groupCaptionLetter), groupName); - int bar = 0, amountOfBarsInGroup = pointList.getSize(); - for (Point2DDouble point : pointList) { // For each bar in group: - int barLength = (int) round(X_AXIS_UNIT_SIZE_DOTS * point.getY() / xAxisScaling); + int amountOfBarsInGroup = amountOfBars / amountOfGroups; + Iterator<Point2DDouble> points = pointList.getListIterator(); + for (int bar = 0; bar < amountOfBarsInGroup; bar++) { barCellArea = mFullChartCellArea.removeFromTop(mBarThickness); if (bar < (amountOfBarsInGroup - 1)) { borderAfterCellArea = mFullChartCellArea.removeFromTop(mBarPaddingCells); // If another bar in the same group follows, use bar padding. @@ -232,16 +235,26 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { borderAfterCellArea = mFullChartCellArea.removeFromTop(1); // If nothing follows, use single line for last border. } // the actual bar - int textureID = bar % mTextures.size(); - drawBar(barLength, originXDotCoordinate, borderBeforeCellArea, barCellArea, borderAfterCellArea, textureID, canvas); + int barLength; + if (points.hasNext()) { + Point2DDouble point = points.next(); + barLength = (int) round(X_AXIS_UNIT_SIZE_DOTS * point.getY() / xAxisScaling); + int textureID = bar % mTextures.size(); + drawBar(barLength, originXDotCoordinate, borderBeforeCellArea, barCellArea, borderAfterCellArea, textureID, canvas); + // Save used texture and corresponding name for explanation in legend + Texture<Boolean> exampleTexture = mTextures.get(textureID).setAffineTransformation(new double[]{mPositiveTextureAlignments.get(textureID), 0}); + textureExplanations.put(exampleTexture, diagram.getCategoryName(bar)); + } else { + barLength = 0; // nonexistent data point + Rectangle hintTextCellArea = new Rectangle(barCellArea); + hintTextCellArea.removeFromLeft(1 + ceil(originXDotCoordinate / (double) canvas.getCellWidth())); // move to left side of y axis + BrailleText nonexistentDataHint = new BrailleText(nonexistentDataText, canvas.toDotRectangle(hintTextCellArea)); + mTextRasterizer.rasterize(nonexistentDataHint, canvas); + } borderBeforeCellArea = borderAfterCellArea; - // Save used texture and corresponding name for explanation in legend - Texture<Boolean> exampleTexture = mTextures.get(textureID).setAffineTransformation(new double[]{mPositiveTextureAlignments.get(textureID), 0}); - textureExplanations.put(exampleTexture, diagram.getCategoryName(bar)); - // the group caption for each first bar in a group - if (bar == 0) { - Rectangle groupCaptionCellArea = canvas.toDotRectangle(mCaptionCellArea.intersectedWith(barCellArea)); - BrailleText captionName = new BrailleText(Character.toString(groupCaptionLetter), groupCaptionCellArea); + if (bar == (amountOfBarsInGroup - 1) / 2) { // the group caption for each first bar in a group + Rectangle groupCaptionDotArea = canvas.toDotRectangle(mCaptionCellArea.intersectedWith(barCellArea)); + BrailleText captionName = new BrailleText(Character.toString(groupCaptionLetter), groupCaptionDotArea.translatedBy(0, mBarThickness * canvas.getCellHeight() * (1 - (amountOfBarsInGroup % 2)))); mTextRasterizer.rasterize(captionName, canvas); groupCaptionLetter++; int dashedLineStartX = canvas.toDotRectangle(mNegativeChartCellArea).intWrapper().getX(); // dashed caption help line @@ -251,14 +264,13 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { Rasterizer.dashedLine(dashedLineStartX, dashedLineStartY, dashedLineLength, true, canvas.getCurrentPage(), 1); } } - bar++; } group++; } // PHASE 3 - DIAGRAM LEGEND: Symbols and textures are explained in the legend which will be created by the LegendRasterizer Legend diagramLegend = new Legend(title); // Create a legend container - diagramLegend.addSymbolExplanation("Achsenskalierung:", "X-Achse", "Größenordung " + xAxisScalingMagnitude); // Explain axis scaling + diagramLegend.addSymbolExplanation("Achsenskalierung:", "X-Achse", "Faktor " + xAxisScalingMagnitude); // Explain axis scaling diagramLegend.addSymbolExplanationGroup("Kategorien:", groupNameExplanations); // Explain bar group single character captions if (textureExplanations.size() > 1) { // Explain textures (if multiple of them were used) diagramLegend.addTextureExplanationGroup("Reihen:", textureExplanations); @@ -348,6 +360,20 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { private int countTotalBarAmount(final BarChart diagram) throws InsufficientRenderingAreaException { int amountOfBars = 0; + + int barsPerGroup = 0; + for (PointList group : diagram.getDataSet()) { + if (group.getSize() > barsPerGroup) { + barsPerGroup = group.getSize(); + } + + } + if (barsPerGroup > mTextures.size()) { + throw new InsufficientRenderingAreaException("The maximum amount of bars in a group is " + mTextures.size()); + } + amountOfBars = diagram.getDataSet().getSize() * barsPerGroup; + + /* for (PointList group : diagram.getDataSet()) { int barsInGroup = group.getSize(); if (barsInGroup > mTextures.size()) { @@ -355,6 +381,7 @@ public class BarChartRasterizer implements Rasterizer<CategoricalBarChart> { } amountOfBars += barsInGroup; } + */ if (amountOfBars < 1) { throw new IllegalArgumentException("The given diagram does not contain any data."); } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/FunctionalRenderingBase.java b/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/FunctionalRenderingBase.java index 1dfe60a4570b11912791c6b9174a4a647b8366c6..860704bf5d7a5e43e13def1fa419055d43a97525 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/FunctionalRenderingBase.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/FunctionalRenderingBase.java @@ -53,7 +53,7 @@ public class FunctionalRenderingBase { selectedRasterizer.rasterize(renderData, mRaster); } else { mLogger.error("No rasterizer found for given renderable type!"); - throw new IllegalArgumentException("No rasterizer registered for renderData class: '" + throw new IllegalArgumentException("No rasterizer registered for renderable class: '" + renderableClass.getCanonicalName() + "'"); } } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/MasterRenderer.java b/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/MasterRenderer.java index 7d588528d63eff2073718ca0b7561fe2630cbe66..5f29f471946e01cd2ab6d550cfa5fb64e299961c 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/MasterRenderer.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/rendering/MasterRenderer.java @@ -1,5 +1,6 @@ package de.tudresden.inf.mci.brailleplot.rendering; +import de.tudresden.inf.mci.brailleplot.configparser.Representation; import de.tudresden.inf.mci.brailleplot.diagrams.CategoricalBarChart; import de.tudresden.inf.mci.brailleplot.layout.InsufficientRenderingAreaException; import de.tudresden.inf.mci.brailleplot.layout.RasterCanvas; @@ -24,10 +25,11 @@ public final class MasterRenderer { private final Logger mLogger = LoggerFactory.getLogger(this.getClass()); Printer mPrinter; + Representation mRepresentation; Format mFormat; FunctionalRenderingBase mRenderingBase; - public MasterRenderer(final Printer printer, final Format format) { + public MasterRenderer(final Printer printer, final Representation representation, final Format format) { mLogger.info("Creating MasterRenderer with default context"); @@ -47,12 +49,12 @@ public final class MasterRenderer { //renderingBase.registerRasterizer(new FunctionalRasterizer<ScatterPlot>(ScatterPlot.class, ScatterPlotRasterizing::fooRasterizing)); //... - setRenderingContext(printer, format, renderingBase); + setRenderingContext(printer, representation, format, renderingBase); } - public MasterRenderer(final Printer printer, final Format format, final FunctionalRenderingBase renderingBase) { + public MasterRenderer(final Printer printer, final Representation representation, final Format format, final FunctionalRenderingBase renderingBase) { mLogger.info("Creating MasterRenderer with custom context"); - setRenderingContext(printer, format, renderingBase); + setRenderingContext(printer, representation, format, renderingBase); } public RasterCanvas rasterize(final Renderable data) throws InsufficientRenderingAreaException { @@ -68,7 +70,7 @@ public final class MasterRenderer { private RasterCanvas createCompatibleRasterCanvas() throws InsufficientRenderingAreaException { mLogger.info("Creating compatible RasterCanvas for current rendering context"); - return new SixDotBrailleRasterCanvas(mPrinter, mFormat); + return new SixDotBrailleRasterCanvas(mPrinter, mRepresentation, mFormat); /* TODO: support 6 and 8 dot layout# @@ -83,8 +85,9 @@ public final class MasterRenderer { // Getter & Setter - public void setRenderingContext(final Printer printer, final Format format, final FunctionalRenderingBase renderingBase) { + public void setRenderingContext(final Printer printer, final Representation representation, final Format format, final FunctionalRenderingBase renderingBase) { setPrinter(printer); + setRepresentation(representation); setFormat(format); setRenderingBase(renderingBase); } @@ -97,6 +100,14 @@ public final class MasterRenderer { return mPrinter; } + public void setRepresentation(final Representation representation) { + mRepresentation = Objects.requireNonNull(representation); + mLogger.info("Rendering context: Representation was set to {}", mRepresentation); + } + public Representation getRepresentation() { + return mRepresentation; + } + public void setFormat(final Format format) { mFormat = Objects.requireNonNull(format); mLogger.info("Rendering context: Format was set to {}", mFormat);