/** * This file is part of VisiCut. * Copyright (C) 2011 - 2013 Thomas Oster <thomas.oster@rwth-aachen.de> * RWTH Aachen University - 52062 Aachen, Germany * * VisiCut is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VisiCut is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with VisiCut. If not, see <http://www.gnu.org/licenses/>. **/ package com.t_oster.visicut.model.graphicelements.svgsupport; import com.kitfox.svg.Circle; import com.kitfox.svg.Line; import com.kitfox.svg.Path; import com.kitfox.svg.Rect; import com.kitfox.svg.SVGException; import com.kitfox.svg.ShapeElement; import com.kitfox.svg.Text; import com.kitfox.svg.Tspan; import com.kitfox.svg.xml.StyleAttribute; import com.t_oster.visicut.misc.Helper; import com.t_oster.visicut.model.graphicelements.ShapeObject; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Thomas Oster <thomas.oster@rwth-aachen.de> */ public class SVGShape extends SVGObject implements ShapeObject { private double svgResolution = 90; private ShapeElement decoratee; public SVGShape(ShapeElement s, double svgResolution) { this.svgResolution = svgResolution; this.decoratee = s; } /** * Returns the first StyleAttribute with the given name in the * Path from the current Node to the Root node * @param name * @return */ private StyleAttribute getStyleAttributeRecursive(String name) { StyleAttribute sa = new StyleAttribute(name); try { if (this.getDecoratee().getStyle(sa, true)) { return sa; } } catch (Exception ex) { Logger.getLogger(SVGShape.class.getName()).log(Level.SEVERE, null, ex); } return null; } private Map<String, List<Object>> attributeValues = new LinkedHashMap<String, List<Object>>(); @Override public List<Object> getAttributeValues(String a) { if (attributeValues.containsKey(a)) { return attributeValues.get(a); } List<Object> result = super.getAttributeValues(a); switch (Attribute.valueOf(a.replace(" ", "_"))) { case Stroke_Width: { StyleAttribute sa = getStyleAttributeRecursive("stroke-width"); double width = 1; if (sa != null) { width = SVGImporter.numberWithUnitsToMm(sa.getNumberWithUnits(), this.svgResolution); } try { AffineTransform t = this.getAbsoluteTransformation(); width *= (t.getScaleX()+t.getScaleY()) / 2; } catch (SVGException ex) { Logger.getLogger(SVGShape.class.getName()).log(Level.SEVERE, null, ex); } result.add((Double) width); break; } case Type: { if (this.getDecoratee() instanceof Tspan) { result.add("Tspan"); } if (this.getDecoratee() instanceof Circle) { result.add("Circle"); } if (this.getDecoratee() instanceof Rect) { result.add("Rect"); } if (this.getDecoratee() instanceof Text) { result.add("Text"); } if (this.getDecoratee() instanceof com.kitfox.svg.Ellipse) { result.add("Ellipse"); } if (this.getDecoratee() instanceof Line) { result.add("Line"); } if (this.getDecoratee() instanceof Path) { result.add("Path"); } result.add("Shape"); break; } case Color: { StyleAttribute sa = getStyleAttributeRecursive("stroke"); if (sa != null && sa.getColorValue() != null) { result.add(sa.getColorValue()); } else { result.add("none"); } sa = getStyleAttributeRecursive("fill"); if (sa != null && sa.getColorValue() != null) { result.add(sa.getColorValue()); } else { result.add(Color.BLACK); } break; } case Stroke_Color: { StyleAttribute sa = getStyleAttributeRecursive("stroke"); if (sa != null) { Color c = sa.getColorValue(); result.add(c == null ? "none" : c); } else { result.add("none"); } break; } case Fill_Color: { StyleAttribute sa = getStyleAttributeRecursive("fill"); if (sa != null) { Color c = sa.getColorValue(); result.add(c == null ? "none" : c); } else { result.add(Color.BLACK); } break; } } attributeValues.put(a, result); return result; } public ShapeElement getDecoratee() { return this.decoratee; } public Rectangle2D getShapeBoundingBox() { Rectangle2D bb = this.getShape().getBounds2D(); return bb; } @Override public Rectangle2D getBoundingBox() { AffineTransform at; try { at = this.getAbsoluteTransformation(); } catch (SVGException ex) { Logger.getLogger(SVGShape.class.getName()).log(Level.SEVERE, null, ex); at = new AffineTransform(); } Rectangle2D bb = Helper.smallestBoundingBox(this.getDecoratee().getShape(), at); StyleAttribute sa = getStyleAttributeRecursive("stroke-width"); if (sa != null) { double w = SVGImporter.numberWithUnitsToMm(sa.getNumberWithUnits(),svgResolution); //TODO: get Stroke width with unit and add it to width/height of BB bb.setRect(bb.getX()-w/2, bb.getY()-w/2, bb.getWidth()+w, bb.getHeight()+w); } return bb; } public Shape getShape() { try { AffineTransform at = this.getAbsoluteTransformation(); StyleAttribute styleAttrib = new StyleAttribute(); float[] strokeDashArray = null; if (getDecoratee().getStyle(styleAttrib.setName("stroke-dasharray"))) { strokeDashArray = styleAttrib.getFloatList(); if (strokeDashArray.length == 0) { strokeDashArray = null; } } float strokeDashOffset = 0f; if (getDecoratee().getStyle(styleAttrib.setName("stroke-dashoffset"))) { strokeDashOffset = styleAttrib.getFloatValueWithUnits(); } if (strokeDashArray == null) { return at.createTransformedShape(this.getDecoratee().getShape()); } else { return at.createTransformedShape(new DashedShape(getDecoratee().getShape(), strokeDashArray, strokeDashOffset)); } } catch (SVGException ex) { Logger.getLogger(SVGShape.class.getName()).log(Level.SEVERE, null, ex); } return null; } }