All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aima.core.util.math.geom.SVGGroupParser Maven / Gradle / Ivy

Go to download

AIMA-Java Core Algorithms from the book Artificial Intelligence a Modern Approach 3rd Ed.

The newest version!
package aima.core.util.math.geom;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import aima.core.util.math.geom.shapes.Circle2D;
import aima.core.util.math.geom.shapes.Ellipse2D;
import aima.core.util.math.geom.shapes.IGeometric2D;
import aima.core.util.math.geom.shapes.Line2D;
import aima.core.util.math.geom.shapes.Point2D;
import aima.core.util.math.geom.shapes.Polyline2D;
import aima.core.util.math.geom.shapes.Rect2D;
import aima.core.util.math.geom.shapes.TransformMatrix2D;

/**
 * This class implements {@link IGroupParser} for a SVG map.
 * the "g" element is used to define the group(s) that should be parsed.
* * The parser only recognizes the following basic shapes: *
    *
  • rect
  • *
  • line
  • *
  • circle
  • *
  • ellipse
  • *
  • polyline
  • *
  • polygon
  • *
* In addition any number of grouping elements are allowed.
* For all elements only the coordinates and the transform attribute are used. This means that rounded corners etc. are ignored. * Every element/shape can use the transform attribute. The following transformations may be used:

*
    *
  • translate
  • *
  • scale
  • *
  • rotate
  • *
* To use the svg map with {@code CartesianPlot2D} it has to contain a "g" element with an id.
* See w3c® SVG standard definition for more information.
*
* During the process of parsing most of the time is spent in the {@link XMLStreamReader}. * A known issue is a element in the file. Removing this element can speed up the parsing significantly. * * @author Arno von Borries * @author Jan Phillip Kretzschmar * @author Andreas Walscheid * */ public class SVGGroupParser implements IGroupParser { private static final String GROUP_ELEMENT = "g"; private static final String CIRCLE_ELEMENT = "circle"; private static final String ELLIPSE_ELEMENT = "ellipse"; private static final String LINE_ELEMENT = "line"; private static final String POLYLINE_ELEMENT = "polyline"; private static final String POLYGON_ELEMENT = "polygon"; private static final String RECT_ELEMENT = "rect"; private static final String ID_ATTRIBUTE = "id"; private static final String TRANSFORM_ATTRIBUTE = "transform"; private static final String X_ATTRIBUTE = "x"; private static final String Y_ATTRIBUTE = "y"; private static final String CX_ATTRIBUTE = "cx"; private static final String CY_ATTRIBUTE = "cy"; private static final String X1_ATTRIBUTE = "x1"; private static final String Y1_ATTRIBUTE = "y1"; private static final String X2_ATTRIBUTE = "x2"; private static final String Y2_ATTRIBUTE = "y2"; private static final String R_ATTRIBUTE = "r"; private static final String RX_ATTRIBUTE = "rx"; private static final String RY_ATTRIBUTE = "ry"; private static final String WIDTH_ATTRIBUTE = "width"; private static final String HEIGHT_ATTRIBUTE = "height"; private static final String POINTS_ATTRIBUTE = "points"; private static final String TRANSLATE_TRANSFORM = "translate"; private static final String SCALE_TRANSFORM = "scale"; private static final String ROTATE_TRANSFORM = "rotate"; private static final String POINTS_REGEX = "[,\\s]+"; private static final String TRANSFORM_REGEX1 = "[a-zA-Z]*\\([0-9.,Ee\\+\\-\\s]*\\)"; private static final String TRANSFORM_REGEX2 = "([a-zA-Z]+)|([0-9\\.Ee\\+\\-]*[eEmMxXpPiInNcCtT%]*[^\\,\\(\\)\\s]+)"; private static final String NUMBER_REGEX = "([\\+\\-]?[0-9]+\\.?[0-9]*[Ee]?[\\+\\-]?[0-9]*\\.?[0-9]*)|em|ex|px|in|cm|mm|pt|pc|\\%"; private static final Pattern NUMBER_PATTERN = Pattern.compile(NUMBER_REGEX); private static final Pattern TRANSFORM_PATTERN1 = Pattern.compile(TRANSFORM_REGEX1); private static final Pattern TRANSFORM_PATTERN2 = Pattern.compile(TRANSFORM_REGEX2); private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance(); private XMLStreamReader reader; private ArrayList shapes; private Stack transformations = new Stack(); private TransformMatrix2D currentMatrix; /** * Parses the given {@link InputStream} into a group of geometric shapes. * @param input the given input stream. * @param groupID the identifier for the group. * @throws XMLStreamException if a syntax error is found in the input. * @return the constructed list of geometric shapes. */ @Override public ArrayList parse(InputStream input, String groupID) throws XMLStreamException { if(input == null || groupID == null) throw new NullPointerException(); reader = FACTORY.createXMLStreamReader(input); shapes = new ArrayList(); transformations.clear(); currentMatrix = TransformMatrix2D.UNITY_MATRIX; while(reader.hasNext()) { final int event = reader.next(); if (event == XMLStreamConstants.START_ELEMENT) { applyTransform(); if(reader.getLocalName().equalsIgnoreCase(GROUP_ELEMENT)) { final String element = reader.getAttributeValue(null, ID_ATTRIBUTE); if(element != null) { if(element.equalsIgnoreCase(groupID)) { parseGroup(); break; } } } } else if(event == XMLStreamConstants.END_ELEMENT) { applyTransformEnd(); } } return shapes; } /** * Parses the specified group. * @throws XMLStreamException if an syntax error was encountered in the file. */ private void parseGroup() throws XMLStreamException { int groupCounter = 1; while (reader.hasNext()) { int event = reader.next(); if (event == XMLStreamConstants.START_ELEMENT) { applyTransform(); final String elementName = reader.getLocalName(); if(elementName.equalsIgnoreCase(CIRCLE_ELEMENT)) parseCircle(); else if(elementName.equalsIgnoreCase(ELLIPSE_ELEMENT)) parseEllipse(); else if(elementName.equalsIgnoreCase(LINE_ELEMENT)) parseLine(); else if(elementName.equalsIgnoreCase(POLYLINE_ELEMENT)) parsePolyline(); else if(elementName.equalsIgnoreCase(POLYGON_ELEMENT)) parsePolygon(); else if(elementName.equalsIgnoreCase(RECT_ELEMENT)) parseRect(); } else if(event == XMLStreamConstants.END_ELEMENT) { applyTransformEnd(); if (reader.getLocalName().equalsIgnoreCase(GROUP_ELEMENT)) { groupCounter--; if(groupCounter == 0) break; } } } } /** * Checks the current element for a transform attribute and adds that attribute to the current transform matrix. * Manages the transformation stack. */ private void applyTransform() { String value = reader.getAttributeValue(null, TRANSFORM_ATTRIBUTE); transformations.push(currentMatrix); currentMatrix = currentMatrix.multiply(parseTransform(value)); } /** * Sets the current transform matrix to the matrix of the underlying element when leaving an element. * Manages the transformation stack. */ private void applyTransformEnd() { currentMatrix = transformations.pop(); } /** * This method parses a transform attribute into a {@link TransformMatrix2D}.
* @param string the string of the transform attribute. * @return the parsed transform matrix. */ private TransformMatrix2D parseTransform(String string) { TransformMatrix2D result = TransformMatrix2D.UNITY_MATRIX; if(string != null) { Matcher matcher1 = TRANSFORM_PATTERN1.matcher(string); int transformCount1 = 0; while(matcher1.lookingAt()) transformCount1++; for(int j=1;j<=transformCount1;j++) { Matcher matcher2 = TRANSFORM_PATTERN2.matcher(matcher1.group(j)); int transformCount2 = 0; while(matcher1.lookingAt()) transformCount2++; for(int i=1;i= 2 && coords.length % 2 == 0) { //otherwise something is wrong with the points list! Point2D[] vertexes = new Point2D[coords.length / 2]; for(int i=0; i= 2 && coords.length % 2 == 0) { //otherwise something is wrong with the points list! Point2D[] vertexes = new Point2D[coords.length / 2]; for(int i=1; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy