001 /*
002 * SVGDiagram.java
003 *
004 *
005 * The Salamander Project - 2D and 3D graphics libraries in Java
006 * Copyright (C) 2004 Mark McKay
007 *
008 * This library is free software; you can redistribute it and/or
009 * modify it under the terms of the GNU Lesser General Public
010 * License as published by the Free Software Foundation; either
011 * version 2.1 of the License, or (at your option) any later version.
012 *
013 * This library is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016 * Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public
019 * License along with this library; if not, write to the Free Software
020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021 *
022 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
023 * projects can be found at http://www.kitfox.com
024 *
025 * Created on February 18, 2004, 5:04 PM
026 */
027
028 package com.kitfox.svg;
029
030 import java.awt.Graphics2D;
031 import java.awt.Rectangle;
032 import java.awt.geom.AffineTransform;
033 import java.awt.geom.Point2D;
034 import java.awt.geom.Rectangle2D;
035 import java.io.Serializable;
036 import java.net.URI;
037 import java.util.ArrayList;
038 import java.util.HashMap;
039 import java.util.List;
040
041
042 /**
043 * Top level structure in an SVG tree.
044 *
045 * @author Mark McKay
046 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
047 */
048 public class SVGDiagram implements Serializable
049 {
050 public static final long serialVersionUID = 0;
051
052 //Indexes elements within this SVG diagram
053 final HashMap idMap = new HashMap();
054
055 SVGRoot root;
056 final SVGUniverse universe;
057
058 /**
059 * This is used by the SVGRoot to determine the width of the
060 */
061 private Rectangle deviceViewport = new Rectangle(100, 100);
062
063 /**
064 * If true, no attempt will be made to discard geometry based on it being
065 * out of bounds. This trades potentially drawing many out of bounds
066 * shapes with having to recalculate bounding boxes every animation iteration.
067 */
068 protected boolean ignoreClipHeuristic = false;
069
070 /**
071 * URL which uniquely identifies this document
072 */
073 // final URI docRoot;
074
075 /**
076 * URI that uniquely identifies this document. Also used to resolve
077 * relative urls. Default base for document.
078 */
079 final URI xmlBase;
080
081 /** Creates a new instance of SVGDiagram */
082 public SVGDiagram(URI xmlBase, SVGUniverse universe)
083 {
084 this.universe = universe;
085 // this.docRoot = docRoot;
086 this.xmlBase = xmlBase;
087 }
088
089 /**
090 * Draws this diagram to the passed graphics context
091 */
092 public void render(Graphics2D g) throws SVGException
093 {
094 root.render(g);
095 }
096
097 /**
098 * Searches thorough the scene graph for all RenderableElements that have
099 * shapes that contain the passed point.
100 *
101 * For every shape which contains the pick point, a List containing the
102 * path to the node is added to the return list. That is, the result of
103 * SVGElement.getPath() is added for each entry.
104 *
105 * @return the passed in list
106 */
107 public List pick(Point2D point, List retVec) throws SVGException
108 {
109 return pick(point, false, retVec);
110 }
111
112 public List pick(Point2D point, boolean boundingBox, List retVec) throws SVGException
113 {
114 if (retVec == null)
115 {
116 retVec = new ArrayList();
117 }
118
119 root.pick(point, boundingBox, retVec);
120
121 return retVec;
122 }
123
124 public List pick(Rectangle2D pickArea, List retVec) throws SVGException
125 {
126 return pick(pickArea, false, retVec);
127 }
128
129 public List pick(Rectangle2D pickArea, boolean boundingBox, List retVec) throws SVGException
130 {
131 if (retVec == null)
132 {
133 retVec = new ArrayList();
134 }
135
136 root.pick(pickArea, new AffineTransform(), boundingBox, retVec);
137
138 return retVec;
139 }
140
141 public SVGUniverse getUniverse()
142 {
143 return universe;
144 }
145
146 public URI getXMLBase()
147 {
148 return xmlBase;
149 }
150
151 // public URL getDocRoot()
152 // {
153 // return docRoot;
154 // }
155
156 public float getWidth()
157 {
158 if (root == null) return 0;
159 return root.getDeviceWidth();
160 }
161
162 public float getHeight()
163 {
164 if (root == null) return 0;
165 return root.getDeviceHeight();
166 }
167
168 /**
169 * Returns the viewing rectangle of this diagram in device coordinates.
170 */
171 public Rectangle2D getViewRect(Rectangle2D rect)
172 {
173 if (root != null) return root.getDeviceRect(rect);
174 return rect;
175 }
176
177 public Rectangle2D getViewRect()
178 {
179 return getViewRect(new Rectangle2D.Double());
180 }
181
182 public SVGElement getElement(String name)
183 {
184 return (SVGElement)idMap.get(name);
185 }
186
187 public void setElement(String name, SVGElement node)
188 {
189 idMap.put(name, node);
190 }
191
192 public void removeElement(String name)
193 {
194 idMap.remove(name);
195 }
196
197 public SVGRoot getRoot()
198 {
199 return root;
200 }
201
202 public void setRoot(SVGRoot root)
203 {
204 this.root = root;
205 root.setDiagram(this);
206 }
207
208 public boolean ignoringClipHeuristic() { return ignoreClipHeuristic; }
209
210 public void setIgnoringClipHeuristic(boolean ignoreClipHeuristic) { this.ignoreClipHeuristic = ignoreClipHeuristic; }
211
212 /**
213 * Updates all attributes in this diagram associated with a time event.
214 * Ie, all attributes with track information.
215 */
216 public void updateTime(double curTime) throws SVGException
217 {
218 if (root == null) return;
219 root.updateTime(curTime);
220 }
221
222 public Rectangle getDeviceViewport()
223 {
224 return deviceViewport;
225 }
226
227 /**
228 * Sets the dimensions of the device being rendered into. This is used by
229 * SVGRoot when its x, y, width or height parameters are specified as
230 * percentages.
231 */
232 public void setDeviceViewport(Rectangle deviceViewport)
233 {
234 this.deviceViewport.setBounds(deviceViewport);
235 if (root != null)
236 {
237 try
238 {
239 root.build();
240 } catch (SVGException ex)
241 {
242 ex.printStackTrace();
243 }
244 }
245 }
246 }