From 83b6ddb437fd604cd68f1a6c19d3d72097861c9a Mon Sep 17 00:00:00 2001 From: kitfox Date: Tue, 8 Feb 2011 11:39:48 +0000 Subject: Added support for the SVG Marker tag. git-svn-id: https://svn.java.net/svn/svgsalamander~svn/trunk/svg-core@88 7dc7fa77-23fb-e6ad-8e2e-c86bd48ed22b --- nbproject/build-impl.xml | 7 +- nbproject/genfiles.properties | 4 +- nbproject/project.properties | 6 + src/main/java/com/kitfox/svg/Marker.java | 263 +++++++++++++++++++++++++ src/main/java/com/kitfox/svg/SVGLoader.java | 1 + src/main/java/com/kitfox/svg/ShapeElement.java | 57 +++++- src/main/java/com/kitfox/svg/Symbol.java | 3 - 7 files changed, 333 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/kitfox/svg/Marker.java diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index fafcef2..3a71c95 100755 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -326,15 +326,18 @@ is divided into following sections: Must set javac.includes - + + + - + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index f096182..49bff32 100755 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=be360661 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=478066e1 -nbproject/build-impl.xml.script.CRC32=3700c371 -nbproject/build-impl.xml.stylesheet.CRC32=f33e10ff@1.38.2.45 +nbproject/build-impl.xml.script.CRC32=1ebb99f0 +nbproject/build-impl.xml.stylesheet.CRC32=229523de@1.38.3.45 diff --git a/nbproject/project.properties b/nbproject/project.properties index 70220d9..406fd4c 100755 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,3 +1,6 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.run.all.processors=true application.title=svg-salamander-core application.vendor=kitfox build.classes.dir=${build.dir}/classes @@ -18,6 +21,7 @@ debug.test.classpath=\ dist.dir=dist dist.jar=${dist.dir}/svg-salamander-core.jar dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= excludes= file.reference.ant.jar=..\\libraries\\ant.jar file.reference.javacc.jar=..\\libraries\\javacc.jar @@ -34,6 +38,8 @@ javac.classpath=\ # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} javac.source=1.4 javac.target=1.4 javac.test.classpath=\ diff --git a/src/main/java/com/kitfox/svg/Marker.java b/src/main/java/com/kitfox/svg/Marker.java new file mode 100644 index 0000000..e68a838 --- /dev/null +++ b/src/main/java/com/kitfox/svg/Marker.java @@ -0,0 +1,263 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package com.kitfox.svg; + +import com.kitfox.svg.xml.StyleAttribute; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; + +/** + * + * @author kitfox + */ +public class Marker extends Group +{ + AffineTransform viewXform; + AffineTransform markerXform; + Rectangle2D viewBox; + + float refX; + float refY; + float markerWidth = 3; + float markerHeight = 3; + float orient = Float.NaN; + + protected void build() throws SVGException + { + super.build(); + + StyleAttribute sty = new StyleAttribute(); + + if (getPres(sty.setName("refX"))) refX = sty.getFloatValueWithUnits(); + if (getPres(sty.setName("refY"))) refY = sty.getFloatValueWithUnits(); + if (getPres(sty.setName("markerWidth"))) markerWidth = sty.getFloatValueWithUnits(); + if (getPres(sty.setName("markerHeight"))) markerHeight = sty.getFloatValueWithUnits(); + + if (getPres(sty.setName("orient"))) + { + if ("auto".equals(sty.getStringValue())) + { + orient = Float.NaN; + } + else + { + orient = sty.getFloatValue(); + } + } + + if (getPres(sty.setName("viewBox"))) + { + float[] dim = sty.getFloatList(); + viewBox = new Rectangle2D.Float(dim[0], dim[1], dim[2], dim[3]); + } + + if (viewBox == null) + { + viewBox = new Rectangle(0, 0, 1, 1); + } + + //Transform pattern onto unit square + viewXform = new AffineTransform(); + viewXform.scale(1.0 / viewBox.getWidth(), 1.0 / viewBox.getHeight()); + viewXform.translate(-viewBox.getX(), -viewBox.getY()); + + markerXform = new AffineTransform(); + markerXform.scale(markerWidth, markerHeight); + markerXform.concatenate(viewXform); + markerXform.translate(-refX, -refY); + } + + protected boolean outsideClip(Graphics2D g) throws SVGException + { + g.getClipBounds(clipBounds); + Rectangle2D rect = super.getBoundingBox(); + if (rect.intersects(clipBounds)) + { + return false; + } + + return true; + + } + + public void render(Graphics2D g) throws SVGException + { + AffineTransform oldXform = g.getTransform(); + g.transform(markerXform); + + super.render(g); + + g.setTransform(oldXform); + } + + public void render(Graphics2D g, MarkerPos pos, float strokeWidth) throws SVGException + { + AffineTransform cacheXform = g.getTransform(); + + g.translate(pos.x, pos.y); + g.scale(strokeWidth, strokeWidth); + g.rotate(Math.atan2(pos.dy, pos.dx)); + + g.transform(markerXform); + + super.render(g); + + g.setTransform(cacheXform); + } + + public Shape getShape() + { + Shape shape = super.getShape(); + return markerXform.createTransformedShape(shape); + } + + public Rectangle2D getBoundingBox() throws SVGException + { + Rectangle2D rect = super.getBoundingBox(); + return markerXform.createTransformedShape(rect).getBounds2D(); + } + + /** + * Updates all attributes in this diagram associated with a time event. + * Ie, all attributes with track information. + * @return - true if this node has changed state as a result of the time + * update + */ + public boolean updateTime(double curTime) throws SVGException + { + boolean changeState = super.updateTime(curTime); + + //Marker properties do not change + return changeState; + } + + //-------------------------------- + public static final int MARKER_START = 0; + public static final int MARKER_MID = 1; + public static final int MARKER_END = 2; + + public static class MarkerPos + { + int type; + double x; + double y; + double dx; + double dy; + + public MarkerPos(int type, double x, double y, double dx, double dy) + { + this.type = type; + this.x = x; + this.y = y; + this.dx = dx; + this.dy = dy; + } + } + + public static class MarkerLayout + { + private ArrayList markerList = new ArrayList(); + boolean started = false; + + public void layout(Shape shape) + { + double px = 0; + double py = 0; + double[] coords = new double[6]; + for (PathIterator it = shape.getPathIterator(null); + !it.isDone(); it.next()) + { + switch (it.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + px = coords[0]; + py = coords[1]; + started = false; + break; + case PathIterator.SEG_CLOSE: + started = false; + break; + case PathIterator.SEG_LINETO: + { + double x = coords[0]; + double y = coords[1]; + markerIn(px, py, x - px, y - py); + markerOut(x, y, x - px, y - py); + px = x; + py = y; + break; + } + case PathIterator.SEG_QUADTO: + { + double k0x = coords[0]; + double k0y = coords[1]; + double x = coords[2]; + double y = coords[3]; + markerIn(px, py, k0x - px, k0y - py); + markerOut(x, y, x - k0x, y - k0y); + px = x; + py = y; + break; + } + case PathIterator.SEG_CUBICTO: + { + double k0x = coords[0]; + double k0y = coords[1]; + double k1x = coords[2]; + double k1y = coords[3]; + double x = coords[4]; + double y = coords[5]; + markerIn(px, py, k0x - px, k0y - py); + markerOut(x, y, x - k1x, y - k1y); + px = x; + py = y; + break; + } + } + } + + for (int i = 1; i < markerList.size(); ++i) + { + MarkerPos prev = (MarkerPos)markerList.get(i - 1); + MarkerPos cur = (MarkerPos)markerList.get(i); + + if (cur.type == MARKER_START) + { + prev.type = MARKER_END; + } + } + MarkerPos last = (MarkerPos)markerList.get(markerList.size() - 1); + last.type = MARKER_END; + } + + private void markerIn(double x, double y, double dx, double dy) + { + if (started == false) + { + started = true; + markerList.add(new MarkerPos(MARKER_START, x, y, dx, dy)); + } + } + + private void markerOut(double x, double y, double dx, double dy) + { + markerList.add(new MarkerPos(MARKER_MID, x, y, dx, dy)); + } + + /** + * @return the markerList + */ + public ArrayList getMarkerList() + { + return markerList; + } + } +} diff --git a/src/main/java/com/kitfox/svg/SVGLoader.java b/src/main/java/com/kitfox/svg/SVGLoader.java index 9ba8527..ecace13 100644 --- a/src/main/java/com/kitfox/svg/SVGLoader.java +++ b/src/main/java/com/kitfox/svg/SVGLoader.java @@ -95,6 +95,7 @@ public class SVGLoader extends DefaultHandler nodeClasses.put("image", ImageSVG.class); nodeClasses.put("line", Line.class); nodeClasses.put("lineargradient", LinearGradient.class); + nodeClasses.put("marker", Marker.class); nodeClasses.put("metadata", Metadata.class); nodeClasses.put("missing-glyph", MissingGlyph.class); nodeClasses.put("path", Path.class); diff --git a/src/main/java/com/kitfox/svg/ShapeElement.java b/src/main/java/com/kitfox/svg/ShapeElement.java index 6446d11..f55ff15 100644 --- a/src/main/java/com/kitfox/svg/ShapeElement.java +++ b/src/main/java/com/kitfox/svg/ShapeElement.java @@ -27,6 +27,8 @@ package com.kitfox.svg; +import com.kitfox.svg.Marker.MarkerLayout; +import com.kitfox.svg.Marker.MarkerPos; import com.kitfox.svg.xml.StyleAttribute; import java.awt.AlphaComposite; import java.awt.BasicStroke; @@ -39,6 +41,7 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.net.URI; +import java.util.ArrayList; import java.util.List; @@ -231,6 +234,26 @@ abstract public class ShapeElement extends RenderableElement strokeWidth *= strokeWidthScalar; // } + Marker markerStart = null; + if (getStyle(styleAttrib.setName("marker-start"))) + { + URI uri = styleAttrib.getURIValue(getXMLBase()); + markerStart = (Marker)diagram.getUniverse().getElement(uri); + } + + Marker markerMid = null; + if (getStyle(styleAttrib.setName("marker-mid"))) + { + URI uri = styleAttrib.getURIValue(getXMLBase()); + markerMid = (Marker)diagram.getUniverse().getElement(uri); + } + + Marker markerEnd = null; + if (getStyle(styleAttrib.setName("marker-end"))) + { + URI uri = styleAttrib.getURIValue(getXMLBase()); + markerEnd = (Marker)diagram.getUniverse().getElement(uri); + } //Draw the shape @@ -291,9 +314,41 @@ abstract public class ShapeElement extends RenderableElement g.setPaint(strokePaint); g.fill(strokeShape); } - } + if (markerStart != null || markerMid != null || markerEnd != null) + { + MarkerLayout layout = new MarkerLayout(); + layout.layout(shape); + + ArrayList list = layout.getMarkerList(); + for (int i = 0; i < list.size(); ++i) + { + MarkerPos pos = (MarkerPos)list.get(i); + + switch (pos.type) + { + case Marker.MARKER_START: + if (markerStart != null) + { + markerStart.render(g, pos, strokeWidth); + } + break; + case Marker.MARKER_MID: + if (markerMid != null) + { + markerMid.render(g, pos, strokeWidth); + } + break; + case Marker.MARKER_END: + if (markerEnd != null) + { + markerEnd.render(g, pos, strokeWidth); + } + break; + } + } + } } abstract public Shape getShape(); diff --git a/src/main/java/com/kitfox/svg/Symbol.java b/src/main/java/com/kitfox/svg/Symbol.java index 1a9f0b3..6d9e219 100644 --- a/src/main/java/com/kitfox/svg/Symbol.java +++ b/src/main/java/com/kitfox/svg/Symbol.java @@ -27,13 +27,10 @@ package com.kitfox.svg; -import com.kitfox.svg.xml.StyleAttribute; import java.awt.*; import java.awt.geom.*; -import java.util.*; import com.kitfox.svg.xml.*; -import org.xml.sax.*; /** * @author Mark McKay -- cgit v1.2.3-55-g7522