Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / 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 @ 40560

History | View | Annotate | Download (9.15 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style;
25

    
26
import java.awt.Graphics2D;
27
import java.awt.Rectangle;
28
import java.awt.RenderingHints;
29
import java.awt.geom.AffineTransform;
30
import java.awt.geom.Rectangle2D;
31
import java.io.IOException;
32
import java.net.URISyntaxException;
33
import java.net.URL;
34

    
35
import org.apache.batik.bridge.BridgeContext;
36
import org.apache.batik.bridge.DocumentLoader;
37
import org.apache.batik.bridge.GVTBuilder;
38
import org.apache.batik.bridge.UserAgentAdapter;
39
import org.apache.batik.bridge.ViewBox;
40
import org.apache.batik.dom.svg.SVGOMDocument;
41
import org.apache.batik.gvt.GraphicsNode;
42
import org.apache.batik.gvt.renderer.StaticRenderer;
43
import org.w3c.dom.Document;
44
import org.w3c.dom.Element;
45

    
46
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
47
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
48
import org.gvsig.tools.ToolsLocator;
49
import org.gvsig.tools.dynobject.DynStruct;
50
import org.gvsig.tools.persistence.PersistenceManager;
51
import org.gvsig.tools.persistence.PersistentState;
52
import org.gvsig.tools.persistence.exception.PersistenceException;
53
import org.gvsig.tools.util.Callable;
54

    
55
/**
56
 * Style for a SVG files.This is a XML specification and file format for
57
 * describing two-dimensional vector graphics, both static and animated.
58
 * SVG can be purely declarative or may include scripting. Images can contain
59
 * hyperlinks using outbound simple XLinks.It is an open standard created
60
 * by the World Wide Web Consortium..
61
 * 
62
 * @author jaume dominguez faus - jaume.dominguez@iver.es
63
 * 
64
 */
65
public class SVGStyle extends BackgroundFileStyle {
66

    
67
    public static final String SVG_STYLE_PERSISTENCE_DEFINITION_NAME =
68
        "SVGStyle";
69
    private static final String SOURCE = "source";
70
    private GVTBuilder gvtBuilder = new GVTBuilder();
71
    private UserAgentAdapter userAgent;
72
    private DocumentLoader loader;
73
    private StaticRenderer renderer = new StaticRenderer();
74
    private GraphicsNode gvtRoot;
75
    private BridgeContext ctx;
76
    private Element elt;
77

    
78
    protected static RenderingHints defaultRenderingHints;
79
    static {
80
        defaultRenderingHints = new RenderingHints(null);
81
        defaultRenderingHints.put(RenderingHints.KEY_ANTIALIASING,
82
            RenderingHints.VALUE_ANTIALIAS_ON);
83

    
84
        defaultRenderingHints.put(RenderingHints.KEY_INTERPOLATION,
85
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
86
    }
87

    
88
    /**
89
     * Constructor method
90
     * 
91
     */
92
    public SVGStyle() {
93
        userAgent = new UserAgentAdapter();
94
        loader = new DocumentLoader(userAgent);
95
        ctx = new BridgeContext(userAgent, loader);
96
        renderer.setDoubleBuffered(true);
97
    }
98

    
99
    public void drawInsideRectangle(Graphics2D g,
100
        Rectangle rect,
101
        boolean keepAspectRatio) throws SymbolDrawingException {
102
        if (keepAspectRatio) {
103
            AffineTransform ataux;
104
            if (elt.hasAttribute("viewBox")) {
105

    
106
                try {
107
                    ataux =
108
                        ViewBox.getViewTransform(null,
109
                            elt,
110
                            (float) rect.getWidth(),
111
                            (float) rect.getHeight(),
112
                            ctx);
113
                } catch (NullPointerException e) {
114
                    throw new SymbolDrawingException(SymbolDrawingException.UNSUPPORTED_SET_OF_SETTINGS);
115
                }
116
            } else {
117
                Rectangle2D bounds = gvtRoot.getBounds();
118
                
119
                ataux = getNoRotationTransform(
120
                    bounds,
121
                    new Rectangle2D.Double(
122
                        rect.x,
123
                        rect.y,
124
                        rect.width,
125
                        rect.height),
126
                    true);
127
            }
128
            RenderingHints renderingHints = new RenderingHints(null);
129
            renderingHints.putAll(defaultRenderingHints);
130
            g.setRenderingHints(renderingHints);
131
            gvtRoot.setTransform(ataux);
132
            gvtRoot.paint(g);
133

    
134
        } else {
135

    
136
            Rectangle2D bounds = gvtRoot.getBounds();
137
            AffineTransform ataux = getNoRotationTransform(
138
                bounds,
139
                new Rectangle2D.Double(rect.x, rect.y, rect.width, rect.height),
140
                false);
141
            
142
            RenderingHints renderingHints = new RenderingHints(null);
143
            renderingHints.putAll(defaultRenderingHints);
144
            g.setRenderingHints(renderingHints);
145
            gvtRoot.setTransform(ataux);
146
            gvtRoot.paint(g);
147
        }
148
    }
149

    
150
    public boolean isSuitableFor(ISymbol symbol) {
151
        return true;
152
    }
153

    
154
    public void setSource(URL url) throws IOException {
155

    
156
            source = url;
157
            Document svgDoc;
158
            try {
159
                    svgDoc = loader.loadDocument(url.toURI().toString());
160
            } catch (URISyntaxException e) {
161
            IOException ioex = new IOException();
162
            ioex.initCause(e);
163
            throw ioex;
164
            }
165
            gvtRoot = gvtBuilder.build(ctx, svgDoc);
166
            renderer.setTree(gvtRoot);
167
            elt = ((SVGOMDocument) svgDoc).getRootElement();
168
    }
169

    
170
    public Rectangle getBounds() {
171
        try {
172
            Rectangle2D r = gvtRoot.getBounds();
173
            return new Rectangle((int) r.getX(),
174
                (int) r.getY(),
175
                (int) r.getWidth(),
176
                (int) r.getHeight());
177
        } catch (Exception e) {
178
            return new Rectangle();
179
        }
180
    }
181

    
182
    public void drawOutline(Graphics2D g, Rectangle r) throws SymbolDrawingException {
183
        drawInsideRectangle(g, r);
184
    }
185

    
186
    
187
    public void loadFromState(PersistentState state) throws PersistenceException {
188
            try {
189
                    String sourceSymbolInLibrary = state.getString(SOURCE_SYMBOL_IN_LIBRARY);
190
                    if (sourceSymbolInLibrary != null){
191
                            setSource(new URL(getSymbolLibraryURL().toString()+sourceSymbolInLibrary));
192
                    } else {
193
                            setSource(state.getURL(SOURCE));
194
                    }
195
            } catch (Exception e) {
196
                    throw new PersistenceCantSetSourceException(e);
197
            }
198
    }
199

    
200
    public void saveToState(PersistentState state) throws PersistenceException {
201
            if (isLibrarySymbol()){
202
                    state.set(SOURCE_SYMBOL_IN_LIBRARY, getSourceSymbolInLibrary());
203
            } else {
204
                    state.setNull(SOURCE_SYMBOL_IN_LIBRARY);
205
            }
206
        state.set(SOURCE, source);
207
    }
208

    
209
    public static class RegisterPersistence implements Callable {
210

    
211
        public Object call() throws Exception {
212
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
213
            if (manager.getDefinition(SVG_STYLE_PERSISTENCE_DEFINITION_NAME) == null) {
214
                DynStruct definition =
215
                    manager.addDefinition(SVGStyle.class,
216
                        SVG_STYLE_PERSISTENCE_DEFINITION_NAME,
217
                        SVG_STYLE_PERSISTENCE_DEFINITION_NAME
218
                            + " Persistence definition",
219
                        null,
220
                        null);
221

    
222
                // Extend the Style base definition
223
                definition.extend(manager.getDefinition(BACKGROUND_FILE_STYLE_PERSISTENCE_DEFINITION_NAME));
224

    
225
                definition.addDynFieldURL(SOURCE).setMandatory(true);
226
                definition.addDynFieldString(SOURCE_SYMBOL_IN_LIBRARY).setMandatory(false);
227
            }
228
            return Boolean.TRUE;
229
        }
230

    
231
    }
232
    
233
    
234
    private AffineTransform getNoRotationTransform(
235
        Rectangle2D from_rect,
236
        Rectangle2D to_rect,
237
        boolean keep_aspect) {
238
        
239
        double scalex = to_rect.getWidth() / from_rect.getWidth();
240
        double scaley = to_rect.getHeight() / from_rect.getHeight();
241
        
242
        if (keep_aspect) {
243
            // force min value for both
244
            scalex = Math.min(scalex,  scaley);
245
            scaley = scalex;
246
        }
247
        
248
        double from_new_center_x = scalex * from_rect.getCenterX(); 
249
        double from_new_center_y = scaley * from_rect.getCenterY(); 
250
        
251
        double offx = to_rect.getCenterX() - from_new_center_x;
252
        double offy = to_rect.getCenterY() - from_new_center_y;
253
        
254
        AffineTransform resp =
255
            AffineTransform.getTranslateInstance(offx, offy);
256
        
257
        // this composition is equivalent to:
258
        // first scale, then move
259
        resp.concatenate(
260
            AffineTransform.getScaleInstance(scalex, scaley));
261
        return resp;
262
    }
263
}