Skip to content
Snippets Groups Projects
Commit 74e00084 authored by Leonard Kupper's avatar Leonard Kupper
Browse files

Update printing area calculation according to latest config revision and configparser update.

parent de10294c
No related branches found
No related tags found
1 merge request!8Feat/rasterizer 10
Showing
with 236 additions and 148 deletions
......@@ -165,8 +165,9 @@ public final class App {
String usedPrinter = "index_everest_d_v4.properties";
//String usedPrinter = "index_basic_d.properties";
String defaultConfigFilePath = getClass().getClassLoader().getResource("default.properties").getFile();
String configFilePath = getClass().getClassLoader().getResource(usedPrinter).getFile();
ConfigurationParser configParser = new JavaPropertiesConfigurationParser(configFilePath);
ConfigurationParser configParser = new JavaPropertiesConfigurationParser(configFilePath, defaultConfigFilePath);
Printer printerConfig = configParser.getPrinter();
Format formatConfig = configParser.getFormat("wide");
......@@ -174,7 +175,7 @@ public final class App {
// Rasterizing
MasterRenderer renderer = new MasterRenderer(printerConfig, formatConfig);
//AbstractRasterCanvas canvas = renderer.rasterize(exampleBarChart);
File imageFile = new File(getClass().getClassLoader().getResource("chart.png").getFile());
File imageFile = new File(getClass().getClassLoader().getResource("2_image_chart.png").getFile());
Image image = new Image(imageFile);
AbstractRasterCanvas canvas = renderer.rasterize(image);
System.out.println(canvas.getCurrentPage());
......
......@@ -14,7 +14,7 @@ import java.util.Set;
* Abstract parser for configuration files. Interface for {@link Printer} and multiple {@link Format} configurations.
* Must be extended to implement a concrete parsing algorithm for a specific file format.
* @author Leonard Kupper
* @version 2019.06.26
* @version 2019.07.18
*/
public abstract class ConfigurationParser {
......@@ -24,7 +24,7 @@ public abstract class ConfigurationParser {
private Printer mPrinter;
private Map<String, Format> mFormats = new HashMap<>();
private String mConfigFilePath;
private List<PrinterProperty> mPrinterProperties = new ArrayList<>();;
private List<PrinterProperty> mPrinterProperties = new ArrayList<>();
private Map<String, List<FormatProperty>> mFormatProperties = new HashMap<>();
private Printer mDefaultPrinter;
private Format mDefaultFormat;
......@@ -38,7 +38,7 @@ public abstract class ConfigurationParser {
* Implement this method by parsing information from the configuration file (see {@link #getInput()}), optionally validating it (see {@link ConfigurationValidator}),
* constructing {@link PrinterProperty} and {@link FormatProperty} objects from this information and adding them with the methods
* {@link #addProperty(PrinterProperty)} and {@link #addProperty(FormatProperty)}.
* This method is called by ({@link #parseConfigFile(String)}).
* This method is called by ({@link #parseConfigFile(String, boolean)}).
* @throws ConfigurationParsingException On any error while accessing the configuration file or syntax.
* @throws ConfigurationValidationException On any error while checking the parsed properties validity.
*/
......@@ -144,27 +144,35 @@ public abstract class ConfigurationParser {
* 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.
* @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
* @throws ConfigurationValidationException On any error while checking the parsed properties validity.
*/
protected final void parseConfigFile(final String filePath)
protected final void parseConfigFile(final String filePath, final boolean assertCompleteness)
throws ConfigurationParsingException, ConfigurationValidationException {
// reset internal property buffer
mPrinterProperties.clear();
mFormatProperties.clear();
// load and parse file
setConfigFile(filePath);
parse();
// Check validation completeness. (Required properties)
mValidator.assertComplete();
// build printer object from added properties
mPrinter = new Printer(mPrinterProperties);
if (mDefaultPrinter != null) {
mPrinter.setFallback(mDefaultPrinter);
}
if (assertCompleteness) {
mValidator.checkPrinterConfigComplete(mPrinter);
}
// build format objects from added properties
for (String formatName : mFormatProperties.keySet()) {
Format newFormat = new Format(mFormatProperties.get(formatName));
Format newFormat = new Format(mFormatProperties.get(formatName), formatName);
if (mDefaultFormat != null) {
newFormat.setFallback(mDefaultFormat);
}
if (assertCompleteness) {
mValidator.checkFormatConfigComplete(newFormat);
}
mFormats.put(formatName, newFormat);
}
}
......
......@@ -3,7 +3,7 @@ package de.tudresden.inf.mci.brailleplot.configparser;
/**
* An interface for a validator that checks properties as (key, value) pairs.
* @author Leonard Kupper
* @version 2019.06.04
* @version 2019.07.18
*/
interface ConfigurationValidator {
/**
......@@ -15,5 +15,18 @@ interface ConfigurationValidator {
* @throws ConfigurationValidationException On any error while checking the parsed properties validity.
*/
ValidProperty validate(String key, String value) throws ConfigurationValidationException;
void assertComplete();
/**
* Check whether the given {@link Printer} configuration is complete, meaning that it contains all
* properties that were declared as 'required' for the printer namespace.
* @param printerConfig The {@link Printer} configuration instance to be checked.
*/
void checkPrinterConfigComplete(Printer printerConfig);
/**
* Check whether the given {@link Format} configuration is complete, meaning that it contains all
* properties that were declared as 'required' for the format namespace.
* @param formatConfig The {@link Format} configuration instance to be checked.
*/
void checkFormatConfigComplete(Format formatConfig);
}
......@@ -2,14 +2,17 @@ package de.tudresden.inf.mci.brailleplot.configparser;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Representation of a printing formats properties.
* @author Leonard Kupper
* @version 2019.06.04
* @version 2019.07.18
*/
public final class Format extends Configurable {
private String mFormatName = "";
/**
* Constructor.
* @param properties A {@link List} of {@link FormatProperty} objects.
......@@ -18,4 +21,20 @@ public final class Format extends Configurable {
mProperties = new ArrayList<>();
mProperties.addAll(properties);
}
/**
* Constructor.
* @param properties A {@link List} of {@link FormatProperty} objects.
* @param formatName The name of the format. (e.g. 'A4')
*/
public Format(final List<FormatProperty> properties, final String formatName) {
mFormatName = Objects.requireNonNull(formatName);
mProperties = new ArrayList<>();
mProperties.addAll(properties);
}
@Override
public String toString() {
return "format configuration (" + mFormatName + ")";
}
}
......@@ -6,56 +6,42 @@ import java.util.Properties;
/**
* Concrete parser for configuration files in Java Property File format.
* @author Leonard Kupper
* @version 2019.06.26
* @version 2019.07.18
*/
public final class JavaPropertiesConfigurationParser extends ConfigurationParser {
private Properties mProperties = new Properties();
/**
* Constructor.
*
* Parse the configuration from a JAVA Property File (.properties) without a default configuration.
* @param filePath The path of the JAVA Property File.
* @throws ConfigurationParsingException On any error while accessing the configuration file or syntax.
* @throws ConfigurationValidationException On any error while checking the parsed properties validity.
*/
public JavaPropertiesConfigurationParser(
final String filePath
) throws ConfigurationParsingException, ConfigurationValidationException {
setValidator(new JavaPropertiesConfigurationValidator());
parseConfigFile(filePath);
}
/**
* Constructor.
*
* Parse the configuration from a Java Property File (.properties) with a given default configuration.
* @param filePath The path of the Java Property File.
* @param defaultPrinter A {@link Printer} 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.
* @param defaultPath The path to the Java Property File containing the default properties.
* @throws ConfigurationParsingException On any error while accessing the configuration file or syntax.
* @throws ConfigurationValidationException On any error while checking the parsed properties validity.
*/
public JavaPropertiesConfigurationParser(
final String filePath,
final Printer defaultPrinter,
final Format defaultFormat
final String defaultPath
) throws ConfigurationParsingException, ConfigurationValidationException {
setValidator(new JavaPropertiesConfigurationValidator());
setDefaults(defaultPrinter, defaultFormat);
parseConfigFile(filePath);
parseConfigFile(defaultPath, false);
setDefaults(getPrinter(), getFormat("default"));
parseConfigFile(filePath, true);
}
/**
* Concrete internal algorithm used for parsing the Java Property File.
* This method is called by ({@link #parseConfigFile(String)}).
* This method is called by ({@link #parseConfigFile(String, boolean)}).
* @throws ConfigurationParsingException On any error while accessing the configuration file or syntax.
* @throws ConfigurationValidationException On any error while checking the parsed properties validity.
*/
protected void parse() throws ConfigurationParsingException, ConfigurationValidationException {
// Load properties from the .properties file
try {
// Reset java property instance
mProperties.clear();
mProperties.load(getInput());
} catch (IOException e) {
throw new ConfigurationParsingException("Unable to load properties from file.", e);
......
......@@ -2,19 +2,22 @@ package de.tudresden.inf.mci.brailleplot.configparser;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.*;
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;
/**
* Concrete validator for properties parsed from configuration files in Java Property File format.
* @author Leonard Kupper
* @version 2019.06.26
* @version 2019.07.18
*/
class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
private final String PRINTER_PREFIX = "printer";
private final String FORMAT_PREFIX = "format";
private final String mPrinterPrefix = "printer";
private final String mFormatPrefix = "format";
private final HashMap<String, Predicate<String>> mValidPrinterProperties = new HashMap<>();
private final HashMap<String, Predicate<String>> mValidFormatProperties = new HashMap<>();
......@@ -24,9 +27,6 @@ class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
JavaPropertiesConfigurationValidator() {
// Reset state for check of required properties.
resetCompletenessCheck();
// Definition of type checker predicates
Predicate<String> requireEmpty = String::isEmpty;
Predicate<String> requireNotEmpty = requireEmpty.negate();
......@@ -40,25 +40,23 @@ class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
Map<String, Predicate<String>> p = new HashMap<>();
definePrinterProperty("name", requireNotEmpty);
definePrinterProperty("mode", requireNotEmpty);
definePrinterProperty("indent.top", requireDouble.and(requirePositive));
definePrinterProperty("indent.left", requireDouble.and(requirePositive));
definePrinterProperty("indent.bottom", requireDouble.and(requirePositive));
definePrinterProperty("indent.right", requireDouble.and(requirePositive));
definePrinterProperty("raster.indent.top", requireInteger.and(requirePositive));
definePrinterProperty("raster.indent.left", requireInteger.and(requirePositive));
definePrinterProperty("raster.indent.bottom", requireInteger.and(requirePositive));
definePrinterProperty("raster.indent.right", requireInteger.and(requirePositive));
definePrinterProperty("brailletable", requireFileExists);
definePrinterProperty("floatingDot.support", requireBoolean);
definePrinterProperty("floatingDot.resolution", requireDouble.and(requirePositive), false);
definePrinterProperty("constraint.top", requireDouble.and(requirePositive));
definePrinterProperty("constraint.left", requireDouble.and(requirePositive));
definePrinterProperty("constraint.width", requireDouble.and(requirePositive), false);
definePrinterProperty("constraint.height", requireDouble.and(requirePositive), false);
definePrinterProperty("raster.constraint.top", requireInteger.and(requirePositive));
definePrinterProperty("raster.constraint.left", requireInteger.and(requirePositive));
definePrinterProperty("raster.constraint.width", requireInteger.and(requirePositive), false);
definePrinterProperty("raster.constraint.height", requireInteger.and(requirePositive), false);
definePrinterProperty("raster.type", requireNotEmpty);
definePrinterProperty("raster.dotDistance.horizontal", requireDouble.and(requirePositive));
definePrinterProperty("raster.dotDistance.vertical", requireDouble.and(requirePositive));
definePrinterProperty("raster.cellDistance.horizontal", requireDouble.and(requirePositive));
definePrinterProperty("raster.cellDistance.vertical", requireDouble.and(requirePositive));
definePrinterProperty("raster.dotDiameter", requireDouble.and(requirePositive));
definePrinterProperty("floatingDotSupport", requireBoolean);
definePrinterProperty("min.characterDistance", requireDouble.and(requirePositive), false);
definePrinterProperty("max.characterDistance", requireDouble.and(requirePositive), false);
definePrinterProperty("min.lineDistance", requireDouble.and(requirePositive), false);
definePrinterProperty("max.lineDistance", requireDouble.and(requirePositive), false);
definePrinterProperty("brailletable", requireFileExists);
// Definition of valid format properties
Map<String, Predicate<String>> f = new HashMap<>();
......@@ -68,27 +66,50 @@ class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
defineFormatProperty("margin.right", requireInteger.and(requirePositive));
defineFormatProperty("margin.bottom", requireInteger.and(requirePositive));
defineFormatProperty("margin.left", requireInteger.and(requirePositive));
defineFormatProperty("isPortrait", requireBoolean, false);
}
private void definePrinterProperty(String propertyName, Predicate<String> validation) {
/**
* Use this function in the validators constructor to add a printer property definition to the internal validation table.
* The property will be treated as 'required'.
* @param propertyName The name of the property. (The prefix 'printer.' must be omitted.)
* @param validation The validation predicate. {@link Predicate}&lt;{@link String}&gt;
*/
private void definePrinterProperty(final String propertyName, final Predicate<String> validation) {
definePrinterProperty(propertyName, validation, true);
}
private void definePrinterProperty(String propertyName, Predicate<String> validation, boolean required) {
/**
* Use this function in the validators constructor to add a printer property definition to the internal validation table.
* @param propertyName The name of the property. (The prefix 'printer.' must be omitted.)
* @param validation The validation predicate. {@link Predicate}&lt;{@link String}&gt;
* @param required Signals whether this is a required property or not.
*/
private void definePrinterProperty(final String propertyName, final Predicate<String> validation, final boolean required) {
defineProperty(mValidPrinterProperties, propertyName, validation, required, mRequiredPrinterProperties);
}
private void defineFormatProperty(String propertyName, Predicate<String> validation) {
/**
* 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'.
* @param propertyName The name of the property. (The prefix 'format.[name].' must be omitted.)
* @param validation The validation predicate. {@link Predicate}&lt;{@link String}&gt;
*/
private void defineFormatProperty(final String propertyName, final Predicate<String> validation) {
defineFormatProperty(propertyName, validation, true);
}
private void defineFormatProperty(String propertyName, Predicate<String> validation, boolean required) {
/**
* Use this function in the validators constructor to add a format property definition to the internal validation table.
* @param propertyName The name of the property. (The prefix 'format.[name].' must be omitted.)
* @param validation The validation predicate. {@link Predicate}&lt;{@link String}&gt;
* @param required Signals whether this is a required property or not.
*/
private void defineFormatProperty(final String propertyName, final Predicate<String> validation, final boolean required) {
defineProperty(mValidFormatProperties, propertyName, validation, required, mRequiredFormatProperties);
}
private void defineProperty(HashMap<String, Predicate<String>> defTable, String propertyName,
Predicate<String> validation, boolean required, ArrayList<String> checkList) {
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);
if (Objects.nonNull(checkList) && required) {
checkList.add(propertyName);
if (required) {
Objects.requireNonNull(checkList).add(propertyName);
}
}
......@@ -110,7 +131,7 @@ class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
String prefix = keyParts[0];
// Decide whether printer or format property and do lookup in respective validation table.
if (prefix.equals(PRINTER_PREFIX)) {
if (prefix.equals(mPrinterPrefix)) {
if (keyParts.length <= 1) {
throw new ConfigurationValidationException("Invalid printer property key: " + key);
}
......@@ -119,50 +140,40 @@ class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
propertyName = propertyName + "." + keyParts[2];
}
validationLookup(mValidPrinterProperties, propertyName, value);
updateCompletenessCheck(PRINTER_PREFIX, propertyName, mRequiredPrinterProperties);
return new PrinterProperty(propertyName, value);
} else if (prefix.equals(FORMAT_PREFIX)) {
} else if (prefix.equals(mFormatPrefix)) {
if (keyParts.length <= 2) {
throw new ConfigurationValidationException("Invalid format property key: " + key);
}
String formatName = keyParts[1];
String namespace = FORMAT_PREFIX + "." + formatName;
String namespace = mFormatPrefix + "." + formatName;
String propertyName = keyParts[2];
validationLookup(mValidFormatProperties, propertyName, value);
updateCompletenessCheck(namespace, propertyName, mRequiredFormatProperties);
return new FormatProperty(formatName, propertyName, value);
} else {
throw new ConfigurationValidationException("Invalid property prefix: " + prefix);
}
}
@SuppressWarnings("unchecked")
// mRequiredPrinterProperties is ArrayList<String>.
void resetCompletenessCheck() {
mCompletenessCheck.clear();
// This namespace is always required:
mCompletenessCheck.put(PRINTER_PREFIX, (ArrayList<String>) mRequiredPrinterProperties.clone());
@Override
public void checkPrinterConfigComplete(final Printer printerConfig) {
checkCompleteness(printerConfig, mRequiredPrinterProperties);
}
@Override
public void checkFormatConfigComplete(final Format formatConfig) {
checkCompleteness(formatConfig, mRequiredFormatProperties);
}
@SuppressWarnings("unchecked")
// checklist must be an ArrayList<String> in first place.
private void updateCompletenessCheck(String namespace, String propertyName, ArrayList<String> checklist) {
// If this is a new namespace, first add the checklist for the namespace.
if (!mCompletenessCheck.containsKey(namespace)) {
mCompletenessCheck.put(namespace, (ArrayList<String>) checklist.clone());
// checklist is always of type ArrayList<String>
public void checkCompleteness(final Configurable config, final ArrayList<String> checklist) {
ArrayList<String> missingProperties = (ArrayList<String>) checklist.clone();
for (String propertyName : config.getPropertyNames()) {
// 'tick off' the existing properties.
missingProperties.remove(propertyName);
}
// 'tick off' the given property from the checklist associated with the regarding namespace.
mCompletenessCheck.get(namespace).remove(propertyName);
}
@Override
public void assertComplete() {
for (String namespace : mCompletenessCheck.keySet()) {
List checklist = mCompletenessCheck.get(namespace);
if (!checklist.isEmpty()) {
throw new IllegalStateException("Incomplete validation. Missing required properties: '" + checklist +
"' in namespace '" + namespace + "'");
}
if (!missingProperties.isEmpty()) {
throw new IllegalStateException("Incomplete validation. Missing required properties: '" + missingProperties
+ "' in '" + config + "'");
}
}
......@@ -221,7 +232,7 @@ class JavaPropertiesConfigurationValidator implements ConfigurationValidator {
}
}
private static boolean checkIfFileExists(final String filePath){
private static boolean checkIfFileExists(final String filePath) {
try {
FileInputStream stream = new FileInputStream(filePath);
} catch (FileNotFoundException e) {
......
......@@ -6,7 +6,7 @@ import java.util.List;
/**
* Representation of a printers configuration properties.
* @author Leonard Kupper
* @version 2019.06.04
* @version 2019.07.18
*/
public final class Printer extends Configurable {
......@@ -19,4 +19,9 @@ public final class Printer extends Configurable {
mProperties = new ArrayList<>();
mProperties.addAll(properties);
}
@Override
public String toString() {
return "printer configuration";
}
}
......@@ -100,7 +100,7 @@ public class SimpleMatrixDataImpl<T> extends AbstractPrintableData implements Ma
if (getValue(i, j).equals(true)) {
sb.append("o");
} else {
sb.append("´");
sb.append(" ");
}
if (((j+1) % 2) == 0) {
sb.append(" ");
......
......@@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.List;
import static java.lang.Math.max;
import static java.lang.Math.min;
/**
* Representation of a target onto which can be drawn. It wraps a {@link PrintableData} instance and specifies the size of the drawing area (in mm).
......@@ -38,23 +39,34 @@ public abstract class AbstractCanvas {
private void readConfig() {
double indentTop = mPrinter.getProperty("indent.top").toDouble();
double indentLeft = mPrinter.getProperty("indent.left").toDouble();
double indentBottom = mPrinter.getProperty("indent.bottom").toDouble();
double indentRight = mPrinter.getProperty("indent.right").toDouble();
// Page margins in mm. The indentation is subtracted, we have no control over it, so the canvas just has to
// create the remaining 'virtual' margins by omitting some cells from the printing area rectangle.
double constraintTop = mPrinter.getProperty("constraint.top").toDouble();
double constraintLeft = mPrinter.getProperty("constraint.left").toDouble();
double constraintHeight, constraintWidth;
if (mPrinter.getPropertyNames().contains("constraint.height")) {
constraintHeight = mPrinter.getProperty("constraint.height").toDouble();
} else {
constraintHeight = Integer.MAX_VALUE;
}
if (mPrinter.getPropertyNames().contains("constraint.width")) {
constraintWidth = mPrinter.getProperty("constraint.width").toDouble();
} else {
constraintWidth = Integer.MAX_VALUE;
}
int pageWidth = mFormat.getProperty("page.width").toInt();
int pageHeight = mFormat.getProperty("page.height").toInt();
// Page margins in mm. The printing area constraint is subtracted, we have no control over it, so the canvas just
// has to create the remaining 'virtual' margins by omitting some cells from the printing area rectangle.
// However, even this 'virtual' margin can never be negative! We can't add printing space where there is none.
mMarginTop = max(mFormat.getProperty("margin.top").toInt() - indentTop, 0);
mMarginLeft = max(mFormat.getProperty("margin.left").toInt() - indentLeft, 0);
mMarginBottom = max(mFormat.getProperty("margin.bottom").toInt() - indentBottom, 0);
mMarginRight = max(mFormat.getProperty("margin.right").toInt() - indentRight, 0);
mMarginTop = max(0, mFormat.getProperty("margin.top").toInt() - constraintTop);
mMarginLeft = max(0, mFormat.getProperty("margin.left").toInt() - constraintLeft);
mMarginBottom = max(0, mFormat.getProperty("margin.bottom").toInt() - max(0, pageHeight - (constraintTop + constraintHeight)));
mMarginRight = max(0, mFormat.getProperty("margin.right").toInt() - max(0, pageWidth - (constraintLeft + constraintWidth)));
// How big is the technically accessible area of the page in mm?
// These sizes can't be negative too of course.
mMillimeterWidth = max(mFormat.getProperty("page.width").toInt() - (indentLeft + indentRight), 0);
mMillimeterHeight = max(mFormat.getProperty("page.height").toInt() - (indentTop + indentBottom), 0);
mMillimeterWidth = max(0, min(pageWidth - constraintLeft, constraintWidth));
mMillimeterHeight = max(0, min(pageHeight - constraintTop, constraintHeight));
}
......
......@@ -88,63 +88,77 @@ public abstract class AbstractRasterCanvas extends AbstractCanvas {
mCellHorizontalMM = mHorizontalDotDistance * (mCellWidth - 1) + mHorizontalCellDistance; // Full width of one cell + padding in mm
mCellVerticalMM = mVerticalDotDistance * (mCellHeight - 1) + mVerticalCellDistance; // Full height of one cell + padding in mm
// Now we are reading properties that are specific to rasterizing.
// The abstract parent class (AbstractCanvas) already calculated indentations based on millimeters, but it is
// also possible to set a raster.indentation counted in amount of cells and lines. Those must be removed additionally.
double indentTop = mPrinter.getProperty("raster.indent.top").toDouble() * mCellVerticalMM;
double indentLeft = mPrinter.getProperty("raster.indent.left").toDouble() * mCellHorizontalMM;
double indentBottom = mPrinter.getProperty("raster.indent.bottom").toDouble() * mCellVerticalMM;
double indentRight = mPrinter.getProperty("raster.indent.right").toDouble() * mCellHorizontalMM;
/* TO BE DELETED
// Subtract additional raster indentation from virtual margin.
mMarginTop = max(mMarginTop - indentTop, 0);
mMarginLeft = max(mMarginLeft - indentLeft, 0);
mMarginBottom = max(mMarginBottom - indentBottom, 0);
mMarginRight = max(mMarginRight - indentRight, 0);
mMarginTop = max(mMarginTop - rasterConstraintTop, 0);
mMarginLeft = max(mMarginLeft - rasterConstraintLeft, 0);
mMarginBottom = max(mMarginBottom - rasterConstraintWidth, 0);
mMarginRight = max(mMarginRight - rasterConstraintWidth, 0);
// Subtract additional raster indentation from page size.
mMillimeterWidth = max(mMillimeterWidth - (indentLeft + indentRight), 0);
mMillimeterHeight = max(mMillimeterHeight - (indentTop + indentBottom), 0);
mMillimeterWidth = max(mMillimeterWidth - (rasterConstraintLeft + rasterConstraintWidth), 0);
mMillimeterHeight = max(mMillimeterHeight - (rasterConstraintTop + rasterConstraintWidth), 0);
*/
}
private void calculateRasterSize() throws InsufficientRenderingAreaException {
// Calculate how many rows and columns of full cells fit inside the given page area
mHorizontalCellCount = (int) floor((mMillimeterWidth + mHorizontalCellDistance) / mCellHorizontalMM); // How many full cells fit horizontally?
mVerticalCellCount = (int) floor((mMillimeterHeight + mVerticalCellDistance) / mCellVerticalMM); // How many full cells fit vertically?
// The following properties impact the printing area, but are specific to rasterizing. (That's why they weren't read before in the AbstractCanvas)
// The abstract parent class (AbstractCanvas) already calculated indentations based on millimeters, but it is
// also possible to set a raster.indentation counted in amount of cells and lines. Those must be removed additionally.
int rasterConstraintTop = mPrinter.getProperty("raster.constraint.top").toInt();
int rasterConstraintLeft = mPrinter.getProperty("raster.constraint.left").toInt();
int rasterConstraintHeight, rasterConstraintWidth;
if (mPrinter.getPropertyNames().contains("raster.constraint.height")) {
rasterConstraintHeight = mPrinter.getProperty("raster.constraint.height").toInt();
} else {
rasterConstraintHeight = Integer.MAX_VALUE;
}
if (mPrinter.getPropertyNames().contains("raster.constraint.width")) {
rasterConstraintWidth = mPrinter.getProperty("raster.constraint.width").toInt();
} else {
rasterConstraintWidth = Integer.MAX_VALUE;
}
// To how many dots does this raster size correspond?
mColumnCount = mHorizontalCellCount * mCellWidth;
mRowCount = mVerticalCellCount * mCellHeight;
// How many cells would be omitted by applying the remaining virtual margins?
int omitTop = max(0, (int) ceil(mMarginTop / mCellVerticalMM) - rasterConstraintTop);
int omitLeft = max(0, (int) ceil(mMarginLeft / mCellHorizontalMM) - rasterConstraintLeft);
int omitBottom = (int) ceil(mMarginBottom / mCellVerticalMM);
int omitRight = (int) ceil(mMarginRight / mCellHorizontalMM);
/*
// How big is the raster on the page?
double fullHorizontalMM = (mHorizontalCellCount * cellHorizontalMM) - mHorizontalCellDistance;
double fullVerticalMM = (mVerticalCellCount * cellVerticalMM) - mVerticalCellDistance;
*/
// Calculate how many rows and columns of full cells fit inside the given page area (ignoring margins and raster constraints)
mHorizontalCellCount = (int) floor((mMillimeterWidth + mHorizontalCellDistance) / mCellHorizontalMM); // How many full cells fit horizontally?
mVerticalCellCount = (int) floor((mMillimeterHeight + mVerticalCellDistance) / mCellVerticalMM); // How many full cells fit vertically?
// Calculate a 'restricted' printing area rectangle, based on the given virtual margins.
// By omitting some cells from the printing area rectangle, a real margin is imitated.
// A rasterizer working with this canvas can still force to write values outside the restricted rectangle
// so it is expected to at least take a look at the cell rectangle.
mPrintingAreaCells = new Rectangle(0, 0,mHorizontalCellCount,mVerticalCellCount); // The whole area.
int omitTop = (int) ceil(mMarginTop / mCellVerticalMM);
int omitLeft = (int) ceil(mMarginLeft / mCellHorizontalMM);
int omitBottom = (int) ceil(mMarginBottom / mCellVerticalMM);
int omitRight = (int) ceil(mMarginRight / mCellHorizontalMM);
Rectangle raster = new Rectangle(0, 0, mHorizontalCellCount, mVerticalCellCount);
try {
mPrintingAreaCells.removeFromTop(omitTop);
mPrintingAreaCells.removeFromLeft(omitLeft);
mPrintingAreaCells.removeFromBottom(omitBottom);
mPrintingAreaCells.removeFromRight(omitRight);
raster.removeFromTop(omitTop);
raster.removeFromLeft(omitLeft);
raster.removeFromBottom(omitBottom);
raster.removeFromRight(omitRight);
} catch (Rectangle.OutOfSpaceException e) {
// If an OutOfSpaceException is thrown this early, it basically means that the defined page size is smaller
// than the sum of its margins, indicating heavy layer 8 error.
throw new InsufficientRenderingAreaException("The defined page size is smaller than the sum of its margins", e);
}
// rasterConstraintTop and rasterConstraintLeft are already regarded in the virtual margins
Rectangle rasterConstraint = new Rectangle(0, 0, rasterConstraintWidth, rasterConstraintHeight);
//Rectangle rasterConstraint = new Rectangle(0, 0, rasterConstraintWidth, rasterConstraintHeight);
Rectangle intersect = raster.intersectedWith(rasterConstraint);
mPrintingAreaCells = new Rectangle(intersect); // The whole area.
//mPrintingAreaCells = new Rectangle(0, 0, intersect.getWidth(), intersect.getHeight()); // The whole area.
// To how many dots does this raster size correspond?
mColumnCount = mPrintingAreaCells.intWrapper().getWidth() * mCellWidth;
mRowCount = mPrintingAreaCells.intWrapper().getHeight() * mCellHeight;
}
......
......@@ -3,6 +3,8 @@ package de.tudresden.inf.mci.brailleplot.rendering;
import java.util.Objects;
import static java.lang.Math.round;
import static java.lang.Math.min;
import static java.lang.Math.max;
/**
* Represents a rectangle that can be continuously divided into partitions. Can be used for doing chart layout and as
......@@ -113,10 +115,10 @@ public class Rectangle {
}
public double getRight() {
return mX + mW - 1;
return mX + mW;
}
public double getBottom() {
return mY + mH - 1;
return mY + mH;
}
public void setX(double x) {
......@@ -151,6 +153,19 @@ public class Rectangle {
return new Rectangle(mX * xScale, mY * yScale, mW * xScale, mH * yScale);
}
/**
* Returns a new rectangle representing the intersection of this rectangle with another rectangle.
* @param otherRectangle The other rectangle to intersect with this.
* @return New rectangle representing the intersection.
*/
public Rectangle intersectedWith(Rectangle otherRectangle) {
double itsctX = max(getX(), otherRectangle.getX());
double itsctY = max(getY(), otherRectangle.getY());
double itsctB = min(getBottom(), otherRectangle.getBottom());
double itsctR = min(getRight(), otherRectangle.getRight());
return new Rectangle(itsctX, itsctY, max(0, itsctR - itsctX), max(0, itsctB - itsctY));
}
@Override
public String toString() {
return "x:" + getX() + ", y:" + getY() + ", w:" + getWidth() + ", h:" + getHeight();
......@@ -191,11 +206,15 @@ public class Rectangle {
return wrapInt(mRectangle.getHeight());
}
// QUESTION FOR REVIEW:
// Does the -1 always make sense for integer coordinates?
// The point is that on integer coords, if you have a rectangle at x,y of size 1x1, it 'ends' at x,y not x+1,y+1
// The rectangle does not 'touch' the neighboring positions.
public int getRight() {
return wrapInt(mRectangle.getRight());
return wrapInt(mRectangle.getRight()) - 1;
}
public int getBottom() {
return wrapInt(mRectangle.getBottom());
return wrapInt(mRectangle.getBottom()) - 1;
}
public Rectangle getRectangle() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment