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 @ 42558

History | View | Annotate | Download (9.24 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 final GVTBuilder gvtBuilder = new GVTBuilder();
71
    private final UserAgentAdapter userAgent;
72
    private final DocumentLoader loader;
73
    private final StaticRenderer renderer = new StaticRenderer();
74
    private GraphicsNode gvtRoot;
75
    private final BridgeContext ctx;
76
    private Element elt;
77

    
78
    protected static final 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
    @Override
100
    public void drawInsideRectangle(Graphics2D g,
101
        Rectangle rect,
102
        boolean keepAspectRatio) throws SymbolDrawingException {
103
        if (keepAspectRatio) {
104
            AffineTransform ataux;
105
            if (elt.hasAttribute("viewBox")) {
106

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

    
135
        } else {
136

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

    
151
    @Override
152
    public boolean isSuitableFor(ISymbol symbol) {
153
        return true;
154
    }
155

    
156
    @Override
157
    public void setSource(URL url) throws IOException {
158

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

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

    
184
    @Override
185
    public void drawOutline(Graphics2D g, Rectangle r) throws SymbolDrawingException {
186
        drawInsideRectangle(g, r);
187
    }
188

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

    
204
    @Override
205
    public void saveToState(PersistentState state) throws PersistenceException {
206
            if (isLibrarySymbol()){
207
                    state.set(SOURCE_SYMBOL_IN_LIBRARY, getSourceSymbolInLibrary());
208
            } else {
209
                    state.setNull(SOURCE_SYMBOL_IN_LIBRARY);
210
            }
211
        state.set(SOURCE, source);
212
    }
213

    
214
    public static class RegisterPersistence implements Callable {
215

    
216
        @Override
217
        public Object call() throws Exception {
218
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
219
            if (manager.getDefinition(SVG_STYLE_PERSISTENCE_DEFINITION_NAME) == null) {
220
                DynStruct definition =
221
                    manager.addDefinition(SVGStyle.class,
222
                        SVG_STYLE_PERSISTENCE_DEFINITION_NAME,
223
                        SVG_STYLE_PERSISTENCE_DEFINITION_NAME
224
                            + " Persistence definition",
225
                        null,
226
                        null);
227

    
228
                // Extend the Style base definition
229
                definition.extend(manager.getDefinition(BACKGROUND_FILE_STYLE_PERSISTENCE_DEFINITION_NAME));
230

    
231
                definition.addDynFieldURL(SOURCE).setMandatory(true);
232
                definition.addDynFieldString(SOURCE_SYMBOL_IN_LIBRARY).setMandatory(false);
233
            }
234
            return Boolean.TRUE;
235
        }
236

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