/* * ShapeElement.java * * * The Salamander Project - 2D and 3D graphics libraries in Java * Copyright (C) 2004 Mark McKay * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Mark McKay can be contacted at mark@kitfox.com. Salamander and other * projects can be found at http://www.kitfox.com * * Created on January 26, 2004, 5:21 PM */ package com.kitfox.svg; import com.kitfox.svg.xml.StyleAttribute; import java.net.*; import java.awt.*; import java.awt.geom.*; import com.kitfox.svg.xml.*; import java.util.Vector; /** * Parent of shape objects * * @author Mark McKay * @author Mark McKay */ abstract public class ShapeElement extends RenderableElement { /** * This is necessary to get text elements to render the stroke the correct * width. It is an alternative to producing new font glyph sets at different * sizes. */ protected float strokeWidthScalar = 1f; /** Creates a new instance of ShapeElement */ public ShapeElement() { } abstract public void render(java.awt.Graphics2D g) throws SVGException; /* protected void setStrokeWidthScalar(float strokeWidthScalar) { this.strokeWidthScalar = strokeWidthScalar; } */ void pick(Point2D point, Vector retVec) throws SVGException { StyleAttribute styleAttrib = new StyleAttribute(); // if (getStyle(styleAttrib.setName("fill")) && getShape().contains(point)) if (getShape().contains(point)) { retVec.add(getPath(null)); } } void pick(Rectangle2D pickArea, AffineTransform ltw, Vector retVec) throws SVGException { StyleAttribute styleAttrib = new StyleAttribute(); // if (getStyle(styleAttrib.setName("fill")) && getShape().contains(point)) if (ltw.createTransformedShape(getShape()).intersects(pickArea)) { retVec.add(getPath(null)); } } protected void renderShape(Graphics2D g, Shape shape) throws SVGException { //g.setColor(Color.green); StyleAttribute styleAttrib = new StyleAttribute(); //Don't process if not visible if (getStyle(styleAttrib.setName("visibility"))) { if (!styleAttrib.getStringValue().equals("visible")) return; } if (getStyle(styleAttrib.setName("display"))) { if (styleAttrib.getStringValue().equals("none")) return; } //None, solid color, gradient, pattern Paint fillPaint = Color.black; //Default to black. Must be explicitly set to none for no fill. if (getStyle(styleAttrib.setName("fill"))) { if (styleAttrib.getStringValue().equals("none")) fillPaint = null; else { fillPaint = styleAttrib.getColorValue(); if (fillPaint == null) { URI uri = styleAttrib.getURIValue(getXMLBase()); if (uri != null) { Rectangle2D bounds = shape.getBounds2D(); AffineTransform xform = g.getTransform(); SVGElement ele = diagram.getUniverse().getElement(uri); fillPaint = ((FillElement)ele).getPaint(bounds, xform); } } } } //Default opacity float opacity = 1f; if (getStyle(styleAttrib.setName("opacity"))) { opacity = styleAttrib.getRatioValue(); } float fillOpacity = opacity; if (getStyle(styleAttrib.setName("fill-opacity"))) { fillOpacity *= styleAttrib.getRatioValue(); } Paint strokePaint = null; //Default is to stroke with none if (getStyle(styleAttrib.setName("stroke"))) { if (styleAttrib.getStringValue().equals("none")) strokePaint = null; else { strokePaint = styleAttrib.getColorValue(); if (strokePaint == null) { URI uri = styleAttrib.getURIValue(getXMLBase()); if (uri != null) { Rectangle2D bounds = shape.getBounds2D(); AffineTransform xform = g.getTransform(); SVGElement ele = diagram.getUniverse().getElement(uri); strokePaint = ((FillElement)ele).getPaint(bounds, xform); } } } } float[] strokeDashArray = null; if (getStyle(styleAttrib.setName("stroke-dasharray"))) { strokeDashArray = styleAttrib.getFloatList(); if (strokeDashArray.length == 0) strokeDashArray = null; } float strokeDashOffset = 0f; if (getStyle(styleAttrib.setName("stroke-dashoffset"))) { strokeDashOffset = styleAttrib.getFloatValueWithUnits(); } int strokeLinecap = BasicStroke.CAP_BUTT; if (getStyle(styleAttrib.setName("stroke-linecap"))) { String val = styleAttrib.getStringValue(); if (val.equals("round")) { strokeLinecap = BasicStroke.CAP_ROUND; } else if (val.equals("square")) { strokeLinecap = BasicStroke.CAP_SQUARE; } } int strokeLinejoin = BasicStroke.JOIN_MITER; if (getStyle(styleAttrib.setName("stroke-linejoin"))) { String val = styleAttrib.getStringValue(); if (val.equals("round")) { strokeLinejoin = BasicStroke.JOIN_ROUND; } else if (val.equals("bevel")) { strokeLinejoin = BasicStroke.JOIN_BEVEL; } } float strokeMiterLimit = 4f; if (getStyle(styleAttrib.setName("stroke-miterlimit"))) { strokeMiterLimit = Math.max(styleAttrib.getFloatValueWithUnits(), 1); } float strokeOpacity = opacity; if (getStyle(styleAttrib.setName("stroke-opacity"))) { strokeOpacity *= styleAttrib.getRatioValue(); } float strokeWidth = 1f; if (getStyle(styleAttrib.setName("stroke-width"))) { strokeWidth = styleAttrib.getFloatValueWithUnits(); } // if (strokeWidthScalar != 1f) // { strokeWidth *= strokeWidthScalar; // } //Draw the shape if (fillPaint != null && fillOpacity != 0f) { if (fillOpacity <= 0) { //Do nothing } else if (fillOpacity < 1f) { Composite cachedComposite = g.getComposite(); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, fillOpacity)); g.setPaint(fillPaint); g.fill(shape); g.setComposite(cachedComposite); } else { g.setPaint(fillPaint); g.fill(shape); } } if (strokePaint != null && strokeOpacity != 0f) { BasicStroke stroke; if (strokeDashArray == null) { stroke = new BasicStroke(strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterLimit); } else { stroke = new BasicStroke(strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterLimit, strokeDashArray, strokeDashOffset); } Shape strokeShape = stroke.createStrokedShape(shape); if (strokeOpacity <= 0) { //Do nothing } else if (strokeOpacity < 1f) { Composite cachedComposite = g.getComposite(); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, strokeOpacity)); g.setPaint(strokePaint); g.fill(strokeShape); g.setComposite(cachedComposite); } else { g.setPaint(strokePaint); g.fill(strokeShape); } } } abstract public Shape getShape(); protected Rectangle2D includeStrokeInBounds(Rectangle2D rect) throws SVGException { StyleAttribute styleAttrib = new StyleAttribute(); if (!getStyle(styleAttrib.setName("stroke"))) return rect; double strokeWidth = 1; if (getStyle(styleAttrib.setName("stroke-width"))) strokeWidth = styleAttrib.getDoubleValue(); rect.setRect( rect.getX() - strokeWidth / 2, rect.getY() - strokeWidth / 2, rect.getWidth() + strokeWidth, rect.getHeight() + strokeWidth); return rect; } }