Statistics
| Revision:

root / tags / v2_0_0_Build_2050 / libraries / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / line / impl / PictureLineSymbol.java @ 38699

History | View | Annotate | Download (13.4 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.line.impl;
42

    
43
import java.awt.BasicStroke;
44
import java.awt.Color;
45
import java.awt.Graphics2D;
46
import java.awt.Rectangle;
47
import java.awt.Shape;
48
import java.awt.geom.AffineTransform;
49
import java.awt.geom.PathIterator;
50
import java.awt.geom.Point2D;
51
import java.io.IOException;
52
import java.net.URL;
53

    
54
import org.apache.batik.ext.awt.geom.PathLength;
55
import org.gvsig.compat.print.PrintAttributes;
56
import org.gvsig.fmap.dal.feature.Feature;
57
import org.gvsig.fmap.geom.Geometry;
58
import org.gvsig.fmap.mapcontext.MapContextLocator;
59
import org.gvsig.fmap.mapcontext.ViewPort;
60
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
61
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
62
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
63
import org.gvsig.i18n.Messages;
64
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.CartographicSupportToolkit;
65
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.IPictureLineSymbol;
66
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.BackgroundFileStyle;
67
import org.gvsig.tools.ToolsLocator;
68
import org.gvsig.tools.dynobject.DynStruct;
69
import org.gvsig.tools.persistence.PersistenceManager;
70
import org.gvsig.tools.persistence.PersistentState;
71
import org.gvsig.tools.persistence.exception.PersistenceException;
72
import org.gvsig.tools.task.Cancellable;
73
import org.gvsig.tools.util.Callable;
74
import org.slf4j.Logger;
75
import org.slf4j.LoggerFactory;
76

    
77

    
78
/**
79
 * PictureLineSymbol allows to use any symbol defined as an image (by an image file)
80
 * supported  by gvSIG.This symbol will be used as an initial object.The line will be
81
 * painted as a succession of puntual symbols through the path defined by it(the line).
82
 *
83
 * @author jaume dominguez faus - jaume.dominguez@iver.es
84
 */
85
public class PictureLineSymbol extends AbstractLineSymbol implements IPictureLineSymbol  {
86

    
87
        private static final Logger logger = LoggerFactory.getLogger(PictureLineSymbol.class);
88

    
89
    public static final String PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME =
90
        "PictureLineSymbol";
91
    private static final String SELECTED = "selected";
92
    private static final String SELECTION_SYMBOL = "selectionSym";
93
    private static final String BACKGROUND_IMAGE = "bgImage";
94
    private static final String BACKGROUND_SELECTION_IMAGE = "bgSelImage";
95

    
96
        transient private PictureLineSymbol selectionSym;
97
        private double width;
98
        private boolean selected;
99
        private double xScale = 1, csXScale = xScale;
100
        private double yScale = 1, csYScale = yScale;
101

    
102
        private BackgroundFileStyle bgImage;
103
        private BackgroundFileStyle bgSelImage;
104
        private PrintAttributes properties;
105

    
106
        /**
107
         * Constructor method
108
         *
109
         */
110
        public PictureLineSymbol() {
111
                super();
112
        }
113
        /**
114
         * Constructor method
115
         * @param imageURL, URL of the normal image
116
         * @param selImageURL, URL of the image when it is selected in the map
117
         * @throws IOException
118
         */
119

    
120
        public PictureLineSymbol(URL imageURL, URL selImageURL) throws IOException {
121
                setImage(imageURL);
122
                if (selImageURL!=null)
123
                        setSelImage(selImageURL);
124
                else setSelImage(imageURL);
125
        }
126
        /**
127
         * Sets the URL for the image to be used as a picture line symbol
128
         * @param imageFile, File
129
         * @throws IOException
130
         */
131
        public void setImage(URL imageUrl) throws IOException{
132

    
133
                bgImage= BackgroundFileStyle.createStyleByURL(imageUrl);
134
        }
135
        /**
136
         * Sets the URL for the image to be used as a picture line symbol (when it is selected in the map)
137
         * @param imageFile, File
138
         * @throws IOException
139
         */
140
        public void setSelImage(URL selImageUrl) throws IOException{
141

    
142
                bgSelImage= BackgroundFileStyle.createStyleByURL(selImageUrl);
143
        }
144

    
145

    
146
        public void setLineWidth(double width) {
147
                this.width = width;
148
                getLineStyle().setLineWidth((float) width);
149
        }
150

    
151
        public double getLineWidth() {
152
                return width;
153
        }
154

    
155
        public ISymbol getSymbolForSelection() {
156
                if (selectionSym == null) {
157
                        selectionSym = (PictureLineSymbol) cloneForSelection();
158
                        selectionSym.selected=true;
159
                        selectionSym.selectionSym = selectionSym; // avoid too much lazy creations
160

    
161
                }
162
                return selectionSym;
163

    
164
        }
165

    
166
        public void draw(Graphics2D g, AffineTransform affineTransform,        Geometry geom, Feature f, Cancellable cancel) {
167
                draw(g, affineTransform, geom, cancel);
168
        }
169

    
170
        private void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Cancellable cancel) {
171

    
172
            if (csXScale<=0 && csYScale<=0) {
173
                return;
174
            }
175

    
176
            float csWidth = getLineStyle().getLineWidth();
177
                
178
                BasicStroke bs = new BasicStroke(
179
                    (float) csWidth,
180
                    BasicStroke.CAP_ROUND,
181
                    BasicStroke.CAP_ROUND);
182
                
183
                Shape geom_transf_clip = geom.getShape(affineTransform);
184
                g.setClip(bs.createStrokedShape(geom_transf_clip));
185
                
186
                BackgroundFileStyle bg = (!selected) ? bgImage : bgSelImage ;
187

    
188
                Rectangle bounds = bg.getBounds();
189
                final double imageWidth  = bounds.getWidth()  * csXScale;
190
                final double imageHeight = bounds.getHeight() * csYScale;
191

    
192
                if (imageWidth==0 || imageHeight==0) return;
193
                int height = (int) csWidth;
194

    
195
                PathLength pl = new PathLength(geom_transf_clip);
196
                PathIterator iterator = geom_transf_clip.getPathIterator(null, 0.8);
197
                double[] theData = new double[6];
198
                Point2D firstPoint = null, startPoint = null, endPoint = null;
199
                if (!iterator.isDone()) {
200
                        if ( iterator.currentSegment(theData) != PathIterator.SEG_CLOSE) {
201
                                firstPoint = new Point2D.Double(theData[0], theData[1]);
202
                        }
203
                }
204
                float currentPathLength = 1;
205

    
206
                Rectangle rect = new Rectangle();
207

    
208
                while ((cancel==null || !cancel.isCanceled()) && !iterator.isDone()) {
209

    
210
                        int theType = iterator.currentSegment(theData);
211
                        switch (theType) {
212
                        case PathIterator.SEG_MOVETO:
213
                                startPoint = new Point2D.Double(theData[0], theData[1]);
214

    
215
                                endPoint = null;
216
                                iterator.next();
217

    
218
                                continue;
219

    
220
                        case PathIterator.SEG_LINETO:
221
                        case PathIterator.SEG_QUADTO:
222
                        case PathIterator.SEG_CUBICTO:
223
                                endPoint = new Point2D.Double(theData[0], theData[1]);
224

    
225
                                break;
226
                        case PathIterator.SEG_CLOSE:
227
                                endPoint = startPoint;
228
                                startPoint = firstPoint;
229
                                break;
230
                        }
231

    
232
                        double a = endPoint.getX() - startPoint.getX();
233
                        double b = endPoint.getY() - startPoint.getY();
234
                        double theta = pl.angleAtLength(currentPathLength);
235

    
236
                        double x = startPoint.getX();
237
                        double y = startPoint.getY();
238

    
239
                        // Theorem of Pythagoras
240
                        float segmentLength = (float) Math.sqrt(a*a + b*b);
241

    
242
                        // compute how many times the image has to be drawn
243
                        // to completely cover this segment's length
244
                        int count = (int) Math.ceil(segmentLength/imageWidth);
245

    
246
                        for (int i = 0; (cancel==null || !cancel.isCanceled()) && i < count; i++) {
247
                                g.translate(x, y);
248
                                g.rotate(theta);
249

    
250
                                double xOffsetTranslation = imageWidth*i;
251
                                g.translate(xOffsetTranslation, -csWidth);
252

    
253
                                rect.setBounds(0, (int) Math.round(height*.5), (int) Math.ceil(imageWidth), height);
254
                                try {
255
                                        bg.drawInsideRectangle(g, rect, false);
256
                                } catch (SymbolDrawingException e) {
257
                                        logger.warn(Messages.getText("label_style_could_not_be_painted"), e);
258
                                }
259
                                g.translate(-xOffsetTranslation, csWidth);
260

    
261
                                g.rotate(-theta);
262
                                g.translate(-x, -y);
263
                        }
264

    
265
                        startPoint = endPoint;
266
                        currentPathLength += segmentLength;
267
                        iterator.next();
268
                }
269
                g.setClip(null);
270
        }
271

    
272
        /**
273
         * Sets the yscale for the picture line symbol
274
         * @param yScale
275
         */
276
        public void setYScale(double yScale) {
277
                this.yScale = yScale;
278
                this.csYScale = yScale;
279
        }
280
        /**
281
         * Sets the xscale for the picture line symbol
282
         * @param xScale
283
         */
284
        public void setXScale(double xScale) {
285
                this.xScale = xScale;
286
                this.csXScale = xScale;
287
        }
288

    
289
        public String getClassName() {
290
                return getClass().getName();
291
        }
292

    
293
        public void print(Graphics2D g, AffineTransform at, Geometry geom,
294
                        PrintAttributes properties) {
295
                this.properties=properties;
296
        draw(g, at, geom, null);
297
        this.properties=null;
298

    
299
        }
300
        
301
        /**
302
         * Returns the URL of the image that is used as a picture line symbol (when it
303
         * is selected in the map)
304
         * @return selimagePath,URL
305
         */
306
        public URL getSelectedSource(){
307
                return bgSelImage.getSource();
308
        }
309
        /**
310
         * Returns the URL of the image that is used as a picture line symbol
311
         * @return imagePath,URL
312
         */
313
        public URL getSource() {
314
                return bgImage.getSource();
315
        }
316
        
317
        /**
318
         * Returns the xscale for the picture line symbol
319
         * @param xScale
320
         */
321
        public double getXScale() {
322
                return xScale;
323
        }
324
        /**
325
         * Returns the yscale for the picture line symbol
326
         * @param yScale
327
         */
328
        public double getYScale() {
329
                return yScale;
330
        }
331

    
332
        @Override
333
        public void setCartographicSize(double cartographicSize, Geometry geom) {
334
                getLineStyle().setLineWidth((float) cartographicSize);
335
                double scale = cartographicSize/width;
336
                csXScale = xScale * scale;
337
                csYScale = yScale * scale;
338
        }
339

    
340
        @Override
341
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
342
                double s = super.toCartographicSize(viewPort, dpi, geom);
343
                setCartographicSize(CartographicSupportToolkit.
344
                                getCartographicLength(this, width, viewPort, dpi), geom);
345
                return s;
346
        }
347
        
348
        
349
    public Object clone() throws CloneNotSupportedException {
350
        PictureLineSymbol copy = (PictureLineSymbol) super.clone();
351

    
352
        // clone selection
353
        if (selectionSym != null) {
354
                //to avoid an infinite loop
355
                if (this == selectionSym){
356
                        copy.selectionSym = copy;
357
                } else {
358
                        copy.selectionSym = (PictureLineSymbol) selectionSym.clone();
359
                }
360
        }
361

    
362
        // clone brackground image
363
        if (bgImage != null) {
364
            copy.bgImage = (BackgroundFileStyle) bgImage.clone();
365
        }
366

    
367
        // clone selection brackground image
368
        if (bgSelImage != null) {
369
            copy.bgSelImage = (BackgroundFileStyle) bgSelImage.clone();
370
        }
371

    
372
        // FIXME: clone properties
373
        
374
        return copy;
375
    }
376

    
377
    public void loadFromState(PersistentState state) throws PersistenceException {
378
        // Set parent style properties
379
        super.loadFromState(state);
380

    
381
        this.selected = (Boolean) state.get(SELECTED);
382
        this.selectionSym = (PictureLineSymbol) state.get(SELECTION_SYMBOL);
383
        this.bgImage = (BackgroundFileStyle) state.get(BACKGROUND_IMAGE);
384
        this.bgSelImage =
385
            (BackgroundFileStyle) state.get(BACKGROUND_SELECTION_IMAGE);
386
    }
387

    
388
    public void saveToState(PersistentState state) throws PersistenceException {
389
        // Save parent fill symbol properties
390
        super.saveToState(state);
391

    
392
        // Save own properties
393
        state.set(SELECTED, this.selected);
394
        state.set(SELECTION_SYMBOL, this.getSymbolForSelection());
395
        state.set(BACKGROUND_IMAGE, this.bgImage);
396
        state.set(BACKGROUND_SELECTION_IMAGE, this.bgSelImage);
397
    }
398

    
399
    public static class RegisterPersistence implements Callable {
400

    
401
        public Object call() throws Exception {
402
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
403
            if (manager.getDefinition(PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
404
                DynStruct definition =
405
                    manager.addDefinition(PictureLineSymbol.class,
406
                                    PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
407
                                    PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME
408
                            + " Persistence definition",
409
                        null,
410
                        null);
411

    
412
                // Extend the Style base definition
413
                definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME));
414

    
415
                definition.addDynFieldBoolean(SELECTED).setMandatory(false);
416
                definition.addDynFieldObject(SELECTION_SYMBOL)
417
                    .setClassOfValue(PictureLineSymbol.class).setMandatory(false);
418
                definition.addDynFieldObject(BACKGROUND_IMAGE)
419
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
420
                definition.addDynFieldObject(BACKGROUND_SELECTION_IMAGE)
421
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
422
            }
423
            return Boolean.TRUE;
424
        }
425
    }
426
    
427
        public static class RegisterSymbol implements Callable {
428

    
429
                public Object call() throws Exception {
430
                        SymbolManager manager = MapContextLocator.getSymbolManager();
431

    
432
                        manager.registerSymbol(PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
433
                            PictureLineSymbol.class);
434

    
435
                        return Boolean.TRUE;
436
                }
437
        }
438
}