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 / ArrowDecoratorStyle.java @ 47476

History | View | Annotate | Download (16.2 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.geom.AffineTransform;
29
import java.awt.geom.Point2D;
30
import org.apache.batik.ext.awt.geom.DefaultPathLength;
31
import org.gvsig.fmap.dal.feature.Feature;
32
import org.gvsig.fmap.geom.Geometry;
33
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
34
import org.gvsig.fmap.geom.GeometryLocator;
35
import org.gvsig.fmap.geom.GeometryManager;
36
import org.gvsig.fmap.geom.exception.CreateGeometryException;
37
import org.gvsig.fmap.geom.primitive.Point;
38
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
40
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol_v2;
41
import org.gvsig.symbology.PathLength;
42
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IArrowMarkerSymbol;
44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
45
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.impl.ArrowMarkerSymbol;
46
import org.gvsig.tools.ToolsLocator;
47
import org.gvsig.tools.dynobject.DynStruct;
48
import org.gvsig.tools.persistence.PersistenceManager;
49
import org.gvsig.tools.persistence.PersistentState;
50
import org.gvsig.tools.persistence.exception.PersistenceException;
51
import org.gvsig.tools.util.Callable;
52

    
53
/**
54
 * Class ArrowDecoratorStyle. It is used to store the information about the
55
 * different options to draw an arrow in a line (and draw it too). This
56
 * information is taken from the panel.
57
 *
58
 */
59
public class ArrowDecoratorStyle extends AbstractStyle implements IArrowDecoratorStyle  {
60
        public static final String ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME = "ArrowDecoratorStyle";
61

    
62
        private static final String FIELD_FLIP_ALL = "flipAll";
63
        private static final String FIELD_FLIP_FIRST = "flipFirst";
64
        private static final String FIELD_ARROW_MARKER_COUNT = "arrowMarkerCount";
65
        private static final String FIELD_FOLLOW_LINE_ANGLE = "followLineAngle";
66
        private static final String FIELD_MARKER = "marker";
67

    
68
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
69
        private boolean flipAll = false;
70
        private boolean flipFirst = false;
71
        private int arrowMarkerCount = 2;
72
        private boolean followLineAngle = true;
73
        private IMarkerSymbol marker = getDefaultMarker();
74

    
75
        public ArrowDecoratorStyle() {
76
                marker.setSize(10);
77
                ((IArrowMarkerSymbol) marker).setSharpness(30);
78
        }
79

    
80
        private IMarkerSymbol getDefaultMarker() {
81
                return new ArrowMarkerSymbol();
82
        }
83
        
84
        /**
85
         * Obtains the number of arrows that the user wants to draw in the same line.
86
         * @return
87
         */
88
        @Override
89
        public int getArrowMarkerCount() {
90
                return arrowMarkerCount;
91
        }
92

    
93
        /**
94
         * Defines the number of arrows that the user wants to draw in the same line.
95
         * @return
96
         */
97
        @Override
98
        public void setArrowMarkerCount(int arrowMarkerCount) {
99
                this.arrowMarkerCount = arrowMarkerCount;
100
        }
101

    
102
        /**
103
         * Defines the flipAll attribute.If the value of this attribute is true all the
104
         * arrows that we had drawn in the same line will be flipped.
105
         * @return
106
         */
107
        @Override
108
        public boolean isFlipAll() {
109
                return flipAll;
110
        }
111

    
112
        /**
113
         * Obtains the flipAll attribute.If the value of this attribute is true all the
114
         * arrows that we had drawn in the same line will be flipped.
115
         * @return
116
         */
117
        @Override
118
        public void setFlipAll(boolean flipAll) {
119
                this.flipAll = flipAll;
120
        }
121

    
122
        /**
123
         * Obtains the flipFirst attribute.If it is true only the first arrow of the line
124
         * will be flipped.The rest will keep the same orientation.
125
         * @return
126
         */
127
        @Override
128
        public boolean isFlipFirst() {
129
                return flipFirst;
130
        }
131

    
132
        /**
133
         * Sets the flipFirst attribute.If it is true only the first arrow of the line
134
         * will be flipped.The rest will keep the same orientation.
135
         * @return
136
         */
137
        @Override
138
        public void setFlipFirst(boolean flipFirst) {
139
                this.flipFirst = flipFirst;
140
        }
141

    
142
        /**
143
         * Gets the followLineAngle attribute.This attribute allows the arrow that we are
144
         * going to draw to be more or less aligned with the line where it will be included (depending on the angle) .
145
         * @return
146
         */
147
        @Override
148
        public boolean isFollowLineAngle() {
149
                return followLineAngle;
150
        }
151

    
152
        /**
153
         * Sets the followLineAngle attribute.This attribute allows the arrow that we are
154
         * going to draw to be more or less aligned with the line where it will be included.
155
         * (depending on the angle).
156
         * @param followingLineAngle
157
         * @return
158
         */
159
        @Override
160
        public void setFollowLineAngle(boolean followLineAngle) {
161
                this.followLineAngle = followLineAngle;
162
        }
163
        /**
164
         * Draws an arrow(or other symbol that substitutes an arrow selected by the user)
165
         * in a line.When the line is drawn, the symbol is added and takes care of the different
166
         * options of the user(for example if he wants to flip the first symbol or all and
167
         * the number of symbols per line to be drawn)
168
         * @param g
169
         * @param affineTransform
170
         * @param feature 
171
         * @param shp
172
         * @throws CreateGeometryException 
173
         */
174
        @Override
175
        public void draw(Graphics2D g, AffineTransform affineTransform,
176
                        Geometry geom, Feature feature) throws CreateGeometryException {
177
                if (arrowMarkerCount <= 0) {
178
                    return;
179
                }
180

    
181
                Geometry geomToDraw = geom;
182
                if(affineTransform != null){
183
                    geomToDraw = geom.cloneGeometry();
184
                    geomToDraw.transform(affineTransform);
185
                }
186
                PathLength pl = new DefaultPathLength(geomToDraw.getShape());
187
                float size = (float) marker.getSize();
188
                if(marker instanceof CartographicSupport){
189
                    ((CartographicSupport)marker).setCartographicContext(this.getCartographicContext());
190
                    size = (float) ((CartographicSupport)marker).toCartographicUnits(size);
191
                }
192
                
193
                marker.setRotation(0.0);
194
                float myLineLength = pl.lengthOfPath();
195
                if (size > myLineLength){
196
                        return;
197
                }
198
                float step = arrowMarkerCount>2 ? myLineLength/(arrowMarkerCount-1) : pl.lengthOfPath();
199
                float rotation1 = 0; // rotation at the arrow's vertex
200
                float rotation2 = 0; // rotation at the arrow's back;
201

    
202
                Point startP = null;
203

    
204
                // the first arrow at the end of the line
205
                float theLength = pl.lengthOfPath();
206

    
207
                if ((flipFirst || flipAll) && (flipFirst != flipAll) && followLineAngle) { // logical XOR
208
                    Point2D p = pl.pointAtLength(theLength-size);
209
                    if (p!=null){
210
                            startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
211
                            if(followLineAngle){
212
                                    rotation1 = pl.angleAtLength(theLength-size);
213
                                    rotation2 = pl.angleAtLength(theLength);
214
                                    marker.setRotation(rotation1);
215
                            }
216
                            if(marker instanceof ISymbol_v2){
217
                                ((ISymbol_v2)marker).draw(g, new AffineTransform(), startP, feature, null, null);
218
                            } else {
219
                                marker.draw(g, new AffineTransform(), startP, feature, null);
220
                            }
221
                    }
222
                } else {
223
                        Point2D p = pl.pointAtLength(theLength);
224
                        if (p!=null){
225
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
226
                                if(followLineAngle){
227
                                        rotation1 = pl.angleAtLength(theLength-size)+(float) Math.PI;
228
                                        rotation2 = pl.angleAtLength(theLength)+(float) Math.PI;
229
                                        marker.setRotation(rotation2);
230
                                }
231
                                if(marker instanceof ISymbol_v2){
232
                                    ((ISymbol_v2)marker).draw(g, new AffineTransform(), startP, feature, null, null);
233
                                } else {
234
                                    marker.draw(g, new AffineTransform(), startP, feature, null);
235
                                }
236
                        }
237
                }
238

    
239
                // the other arrows but the first and the last
240
                float aLength;
241
                for (int i = 1; i < arrowMarkerCount-1; i++) {
242
                        aLength = (float) (step*i);
243

    
244
                        if (flipAll && followLineAngle) {
245
                                Point2D p = pl.pointAtLength(aLength-size);
246
                                if (p==null){
247
                                        p = pl.pointAtLength(theLength);
248
                                }
249
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
250
                                if(followLineAngle){
251
                                        rotation1 = (float) pl.angleAtLength(aLength);
252
                                        rotation2 = (float) pl.angleAtLength((float)(aLength+size));
253
                                        marker.setRotation(rotation1);
254
                                }
255
                                        if(marker instanceof ISymbol_v2){
256
                                            ((ISymbol_v2)marker).draw(g, new AffineTransform(), startP, feature, null, null);
257
                                        } else {
258
                                            marker.draw(g, new AffineTransform(), startP, feature, null);
259
                                        }
260
                        } else {
261
                                Point2D p = pl.pointAtLength(aLength+size);
262
                                if (p==null){
263
                                        p = pl.pointAtLength(theLength);
264
                                }
265

    
266
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
267
                                if(followLineAngle){
268
                                        rotation1 = (float) (pl.angleAtLength(aLength) + Math.PI);
269
                                        rotation2 = (float) (pl.angleAtLength((float)(aLength+size)) + Math.PI);
270
                                        marker.setRotation(rotation2);
271
                                }
272
                                        if(marker instanceof ISymbol_v2){
273
                                            ((ISymbol_v2)marker).draw(g, new AffineTransform(), startP, feature, null, null);
274
                                        } else {
275
                                            marker.draw(g, new AffineTransform(), startP, feature, null);
276
                                        }
277
                        }
278
                }
279

    
280
                startP = null;
281
                // and the last arrow at the begining of the line
282
                if (arrowMarkerCount>1) {
283
                        if (flipAll) {
284
                                Point2D p = null;
285
                                p = pl.pointAtLength(0);
286
                                if (p!=null){
287
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
288
                                        if(followLineAngle){
289
                                                rotation1 = (float) pl.angleAtLength(size);
290
                                                rotation2 = (float) pl.angleAtLength(0);
291
                                                marker.setRotation(rotation2);
292
                                        }
293
                                        if(marker instanceof ISymbol_v2){
294
                                            ((ISymbol_v2)marker).draw(g, new AffineTransform(), startP, feature, null, null);
295
                                        } else {
296
                                            marker.draw(g, new AffineTransform(), startP, feature, null);
297
                                        }
298
                                }                                
299
                        } else {
300
                                Point2D p = null;
301
                                if(followLineAngle){
302
                                        p = pl.pointAtLength(size);
303
                                } else {
304
                                        p = pl.pointAtLength(0);
305
                                }
306
                                if (p!=null){
307
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
308
                                        if(followLineAngle){
309
                                                rotation1 = (float) (pl.angleAtLength(size) + Math.PI);
310
                                                rotation2 = (float) (pl.angleAtLength(0) + Math.PI);
311
                                                marker.setRotation(rotation1);
312
                                        }
313
                                        if(marker instanceof ISymbol_v2){
314
                                            ((ISymbol_v2)marker).draw(g, new AffineTransform(), startP, feature, null, null);
315
                                        } else {
316
                                            marker.draw(g, new AffineTransform(), startP, feature, null);
317
                                        }
318
                                }
319
                        }
320
                }
321
        }
322

    
323
        @Override
324
        public void drawInsideRectangle(Graphics2D g, Rectangle r) {
325
                // TODO Auto-generated method stub
326
                throw new Error("Not yet implemented!");
327
        }
328

    
329
        @Override
330
        public void drawOutline(Graphics2D g, Rectangle r) {
331
                // TODO Auto-generated method stub
332
                throw new Error("Not yet implemented!");
333
        }
334

    
335
        @Override
336
        public boolean isSuitableFor(ISymbol symbol) {
337
                return symbol instanceof ILineSymbol;
338
        }
339

    
340
        public String getClassName() {
341
                return getClass().getName();
342
        }
343

    
344
        @Override
345
        public IMarkerSymbol getMarker() {
346
                if(marker == null){
347
                        marker = getDefaultMarker();
348
                }
349
                return marker;
350
        }
351

    
352
        @Override
353
        public void setMarker(IMarkerSymbol marker) {
354
                this.marker = marker;
355
        }
356
        
357
        @Override
358
        public Object clone() throws CloneNotSupportedException {
359
                ArrowDecoratorStyle copy  = (ArrowDecoratorStyle) super.clone();
360
                if (marker != null) {
361
                        copy.marker = (IMarkerSymbol) marker.clone();
362
                }
363
                return copy;
364
        }
365

    
366
        @Override
367
        public void loadFromState(PersistentState state)
368
                        throws PersistenceException {
369
                // Set parent style properties
370
                super.loadFromState(state);
371

    
372
                // Set own properties
373
                setArrowMarkerCount(state.getInt(FIELD_ARROW_MARKER_COUNT));
374
                setFlipAll(state.getBoolean(FIELD_FLIP_ALL));
375
                setFlipFirst(state.getBoolean(FIELD_FLIP_FIRST));
376
                setFollowLineAngle(state.getBoolean(FIELD_FOLLOW_LINE_ANGLE));
377
                setMarker((IMarkerSymbol) state.get(FIELD_MARKER));
378
        }
379

    
380
        @Override
381
        public void saveToState(PersistentState state) throws PersistenceException {
382
                // Save parent fill symbol properties
383
                super.saveToState(state);
384

    
385
                // Save own properties
386
                state.set(FIELD_ARROW_MARKER_COUNT, getArrowMarkerCount());
387
                state.set(FIELD_FLIP_ALL, isFlipAll());
388
                state.set(FIELD_FLIP_FIRST, isFlipFirst());
389
                state.set(FIELD_FOLLOW_LINE_ANGLE, isFollowLineAngle());
390
                state.set(FIELD_MARKER, getMarker());
391
        }
392
        
393
        public static class RegisterPersistence implements Callable {
394

    
395
                @Override
396
                public Object call() throws Exception {
397
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
398
                        if( manager.getDefinition(ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME)==null ) {
399
                                DynStruct definition = manager.addDefinition(
400
                                                ArrowDecoratorStyle.class,
401
                                                ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME,
402
                                                ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
403
                                                null, 
404
                                                null
405
                                );
406
                                
407
                                // Extend the Style base definition
408
                                definition.extend(manager.getDefinition(STYLE_PERSISTENCE_DEFINITION_NAME));
409

    
410
                                // Arrow marker count
411
                                definition.addDynFieldInt(FIELD_ARROW_MARKER_COUNT).setMandatory(true);
412
                                // Flip all
413
                                definition.addDynFieldBoolean(FIELD_FLIP_ALL).setMandatory(true);
414
                                // flip first
415
                                definition.addDynFieldBoolean(FIELD_FLIP_FIRST).setMandatory(true);
416
                                // Follow line angles
417
                                definition.addDynFieldBoolean(FIELD_FOLLOW_LINE_ANGLE).setMandatory(true);
418
                                // Marker
419
                                definition.addDynFieldObject(FIELD_MARKER)
420
                                        .setClassOfValue(IMarkerSymbol.class)
421
                                        .setMandatory(true);
422

    
423
                        }
424
                        return Boolean.TRUE;
425
                }
426
                
427
        }
428

    
429
    @Override
430
    public void setCartographicContext(CartographicContext ctx) {
431
        super.setCartographicContext(ctx);
432
        if(this.marker instanceof CartographicContext){
433
            ((CartographicSupport)marker).setCartographicContext(ctx);
434
        }
435
    }
436
        
437
        
438

    
439
}