Statistics
| Revision:

root / tags / v2_0_0_Build_2051 / libraries / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / style / SVGStyle.java @ 38760

History | View | Annotate | Download (9.41 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style;
42

    
43
import java.awt.Graphics2D;
44
import java.awt.Rectangle;
45
import java.awt.RenderingHints;
46
import java.awt.geom.AffineTransform;
47
import java.awt.geom.Rectangle2D;
48
import java.io.IOException;
49
import java.net.URISyntaxException;
50
import java.net.URL;
51

    
52
import org.apache.batik.bridge.BridgeContext;
53
import org.apache.batik.bridge.DocumentLoader;
54
import org.apache.batik.bridge.GVTBuilder;
55
import org.apache.batik.bridge.UserAgentAdapter;
56
import org.apache.batik.bridge.ViewBox;
57
import org.apache.batik.dom.svg.SVGOMDocument;
58
import org.apache.batik.gvt.GraphicsNode;
59
import org.apache.batik.gvt.renderer.StaticRenderer;
60
import org.w3c.dom.Document;
61
import org.w3c.dom.Element;
62

    
63
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
64
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
65
import org.gvsig.tools.ToolsLocator;
66
import org.gvsig.tools.dynobject.DynStruct;
67
import org.gvsig.tools.persistence.PersistenceManager;
68
import org.gvsig.tools.persistence.PersistentState;
69
import org.gvsig.tools.persistence.exception.PersistenceException;
70
import org.gvsig.tools.util.Callable;
71

    
72
/**
73
 * Style for a SVG files.This is a XML specification and file format for
74
 * describing two-dimensional vector graphics, both static and animated.
75
 * SVG can be purely declarative or may include scripting. Images can contain
76
 * hyperlinks using outbound simple XLinks.It is an open standard created
77
 * by the World Wide Web Consortium..
78
 * 
79
 * @author jaume dominguez faus - jaume.dominguez@iver.es
80
 * 
81
 */
82
public class SVGStyle extends BackgroundFileStyle {
83

    
84
    public static final String SVG_STYLE_PERSISTENCE_DEFINITION_NAME =
85
        "SVGStyle";
86
    private static final String SOURCE = "source";
87
    private GVTBuilder gvtBuilder = new GVTBuilder();
88
    private UserAgentAdapter userAgent;
89
    private DocumentLoader loader;
90
    private StaticRenderer renderer = new StaticRenderer();
91
    private GraphicsNode gvtRoot;
92
    private BridgeContext ctx;
93
    private Element elt;
94

    
95
    protected static RenderingHints defaultRenderingHints;
96
    static {
97
        defaultRenderingHints = new RenderingHints(null);
98
        defaultRenderingHints.put(RenderingHints.KEY_ANTIALIASING,
99
            RenderingHints.VALUE_ANTIALIAS_ON);
100

    
101
        defaultRenderingHints.put(RenderingHints.KEY_INTERPOLATION,
102
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
103
    }
104

    
105
    /**
106
     * Constructor method
107
     * 
108
     */
109
    public SVGStyle() {
110
        userAgent = new UserAgentAdapter();
111
        loader = new DocumentLoader(userAgent);
112
        ctx = new BridgeContext(userAgent, loader);
113
        renderer.setDoubleBuffered(true);
114
    }
115

    
116
    public void drawInsideRectangle(Graphics2D g,
117
        Rectangle rect,
118
        boolean keepAspectRatio) throws SymbolDrawingException {
119
        if (keepAspectRatio) {
120
            AffineTransform ataux;
121
            if (elt.hasAttribute("viewBox")) {
122

    
123
                try {
124
                    ataux =
125
                        ViewBox.getViewTransform(null,
126
                            elt,
127
                            (float) rect.getWidth(),
128
                            (float) rect.getHeight(),
129
                            ctx);
130
                } catch (NullPointerException e) {
131
                    throw new SymbolDrawingException(SymbolDrawingException.UNSUPPORTED_SET_OF_SETTINGS);
132
                }
133
            } else {
134
                Rectangle2D bounds = gvtRoot.getBounds();
135
                
136
                ataux = getNoRotationTransform(
137
                    bounds,
138
                    new Rectangle2D.Double(
139
                        rect.x,
140
                        rect.y,
141
                        rect.width,
142
                        rect.height),
143
                    true);
144
            }
145
            RenderingHints renderingHints = new RenderingHints(null);
146
            renderingHints.putAll(defaultRenderingHints);
147
            g.setRenderingHints(renderingHints);
148
            gvtRoot.setTransform(ataux);
149
            gvtRoot.paint(g);
150

    
151
        } else {
152

    
153
            Rectangle2D bounds = gvtRoot.getBounds();
154
            AffineTransform ataux = getNoRotationTransform(
155
                bounds,
156
                new Rectangle2D.Double(rect.x, rect.y, rect.width, rect.height),
157
                false);
158
            
159
            RenderingHints renderingHints = new RenderingHints(null);
160
            renderingHints.putAll(defaultRenderingHints);
161
            g.setRenderingHints(renderingHints);
162
            gvtRoot.setTransform(ataux);
163
            gvtRoot.paint(g);
164
        }
165
    }
166

    
167
    public boolean isSuitableFor(ISymbol symbol) {
168
        return true;
169
    }
170

    
171
    public void setSource(URL url) throws IOException {
172

    
173
            source = url;
174
            Document svgDoc;
175
            try {
176
                    svgDoc = loader.loadDocument(url.toURI().toString());
177
            } catch (URISyntaxException e) {
178
            IOException ioex = new IOException();
179
            ioex.initCause(e);
180
            throw ioex;
181
            }
182
            gvtRoot = gvtBuilder.build(ctx, svgDoc);
183
            renderer.setTree(gvtRoot);
184
            elt = ((SVGOMDocument) svgDoc).getRootElement();
185
    }
186

    
187
    public Rectangle getBounds() {
188
        try {
189
            Rectangle2D r = gvtRoot.getBounds();
190
            return new Rectangle((int) r.getX(),
191
                (int) r.getY(),
192
                (int) r.getWidth(),
193
                (int) r.getHeight());
194
        } catch (Exception e) {
195
            return new Rectangle();
196
        }
197
    }
198

    
199
    public void drawOutline(Graphics2D g, Rectangle r) throws SymbolDrawingException {
200
        drawInsideRectangle(g, r);
201
    }
202

    
203
    
204
    public void loadFromState(PersistentState state) throws PersistenceException {
205
            try {
206
                    String sourceSymbolInLibrary = state.getString(SOURCE_SYMBOL_IN_LIBRARY);
207
                    if (sourceSymbolInLibrary != null){
208
                            setSource(new URL(getSymbolLibraryURL().toString()+sourceSymbolInLibrary));
209
                    } else {
210
                            setSource(state.getURL(SOURCE));
211
                    }
212
            } catch (Exception e) {
213
                    throw new PersistenceCantSetSourceException(e);
214
            }
215
    }
216

    
217
    public void saveToState(PersistentState state) throws PersistenceException {
218
            if (isLibrarySymbol()){
219
                    state.set(SOURCE_SYMBOL_IN_LIBRARY, getSourceSymbolInLibrary());
220
            } else {
221
                    state.setNull(SOURCE_SYMBOL_IN_LIBRARY);
222
            }
223
        state.set(SOURCE, source);
224
    }
225

    
226
    public static class RegisterPersistence implements Callable {
227

    
228
        public Object call() throws Exception {
229
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
230
            if (manager.getDefinition(SVG_STYLE_PERSISTENCE_DEFINITION_NAME) == null) {
231
                DynStruct definition =
232
                    manager.addDefinition(SVGStyle.class,
233
                        SVG_STYLE_PERSISTENCE_DEFINITION_NAME,
234
                        SVG_STYLE_PERSISTENCE_DEFINITION_NAME
235
                            + " Persistence definition",
236
                        null,
237
                        null);
238

    
239
                // Extend the Style base definition
240
                definition.extend(manager.getDefinition(BACKGROUND_FILE_STYLE_PERSISTENCE_DEFINITION_NAME));
241

    
242
                definition.addDynFieldURL(SOURCE).setMandatory(true);
243
                definition.addDynFieldString(SOURCE_SYMBOL_IN_LIBRARY).setMandatory(false);
244
            }
245
            return Boolean.TRUE;
246
        }
247

    
248
    }
249
    
250
    
251
    private AffineTransform getNoRotationTransform(
252
        Rectangle2D from_rect,
253
        Rectangle2D to_rect,
254
        boolean keep_aspect) {
255
        
256
        double scalex = to_rect.getWidth() / from_rect.getWidth();
257
        double scaley = to_rect.getHeight() / from_rect.getHeight();
258
        
259
        if (keep_aspect) {
260
            // force min value for both
261
            scalex = Math.min(scalex,  scaley);
262
            scaley = scalex;
263
        }
264
        
265
        double from_new_center_x = scalex * from_rect.getCenterX(); 
266
        double from_new_center_y = scaley * from_rect.getCenterY(); 
267
        
268
        double offx = to_rect.getCenterX() - from_new_center_x;
269
        double offy = to_rect.getCenterY() - from_new_center_y;
270
        
271
        AffineTransform resp =
272
            AffineTransform.getTranslateInstance(offx, offy);
273
        
274
        // this composition is equivalent to:
275
        // first scale, then move
276
        resp.concatenate(
277
            AffineTransform.getScaleInstance(scalex, scaley));
278
        return resp;
279
    }
280
}