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

History | View | Annotate | Download (12.7 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

    
31
import org.apache.batik.ext.awt.geom.DefaultPathLength;
32
import org.gvsig.fmap.dal.feature.Feature;
33
import org.gvsig.fmap.geom.Geometry;
34
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
35
import org.gvsig.fmap.geom.GeometryLocator;
36
import org.gvsig.fmap.geom.GeometryManager;
37
import org.gvsig.fmap.geom.exception.CreateGeometryException;
38
import org.gvsig.fmap.geom.primitive.Point;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
40
import org.gvsig.symbology.PathLength;
41
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
42
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IArrowMarkerSymbol;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
44
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.impl.ArrowMarkerSymbol;
45
import org.gvsig.tools.ToolsLocator;
46
import org.gvsig.tools.dynobject.DynStruct;
47
import org.gvsig.tools.persistence.PersistenceManager;
48
import org.gvsig.tools.persistence.PersistentState;
49
import org.gvsig.tools.persistence.exception.PersistenceException;
50
import org.gvsig.tools.util.Callable;
51

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

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

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

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

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

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

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

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

    
117
        /**
118
         * Obtains the flipFirst attribute.If it is true only the first arrow of the line
119
         * will be flipped.The rest will keep the same orientation.
120
         * @return
121
         */
122
        public boolean isFlipFirst() {
123
                return flipFirst;
124
        }
125

    
126
        /**
127
         * Sets the flipFirst attribute.If it is true only the first arrow of the line
128
         * will be flipped.The rest will keep the same orientation.
129
         * @return
130
         */
131
        public void setFlipFirst(boolean flipFirst) {
132
                this.flipFirst = flipFirst;
133
        }
134

    
135
        /**
136
         * Gets the followLineAngle attribute.This attribute allows the arrow that we are
137
         * going to draw to be more or less aligned with the line where it will be included (depending on the angle) .
138
         * @return
139
         */
140
        public boolean isFollowLineAngle() {
141
                return followLineAngle;
142
        }
143

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

    
169
                Geometry geomToDraw = geom.cloneGeometry();
170
                geomToDraw.transform(affineTransform);
171
                PathLength pl = new DefaultPathLength(geomToDraw.getShape());
172
                float size = (float) marker.getSize();
173
                marker.setRotation(0.0);
174
                float myLineLength = pl.lengthOfPath();
175
                if (size > myLineLength){
176
                        return;
177
                }
178
                float step = arrowMarkerCount>2 ? myLineLength/(arrowMarkerCount-1) : pl.lengthOfPath();
179
                float rotation1 = 0; // rotation at the arrow's vertex
180
                float rotation2 = 0; // rotation at the arrow's back;
181

    
182
                Point startP = null;
183

    
184
                // the first arrow at the end of the line
185
                float theLength = pl.lengthOfPath();
186
                {
187

    
188
                        if ((flipFirst || flipAll) && (flipFirst != flipAll) && followLineAngle) { // logical XOR
189
                                Point2D p = pl.pointAtLength(theLength-size);
190
                                if (p!=null){
191
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
192
                                        if(followLineAngle){
193
                                                rotation1 = pl.angleAtLength(theLength-size);
194
                                                rotation2 = pl.angleAtLength(theLength);
195
                                                marker.setRotation(rotation1);
196
                                        }
197
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
198
                                }
199
                        } else {
200
                                Point2D p = pl.pointAtLength(theLength);
201
                                if (p!=null){
202
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
203
                                        if(followLineAngle){
204
                                                rotation1 = pl.angleAtLength(theLength-size)+(float) Math.PI;
205
                                                rotation2 = pl.angleAtLength(theLength)+(float) Math.PI;
206
                                                marker.setRotation(rotation2);
207
                                        }
208
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
209
                                }
210
                        }
211
                }
212
                // the other arrows but the first and the last
213
                float aLength;
214
                for (int i = 1; i < arrowMarkerCount-1; i++) {
215
                        aLength = (float) (step*i);
216

    
217
                        if (flipAll && followLineAngle) {
218
                                Point2D p = pl.pointAtLength(aLength);
219
                                if (p==null){
220
                                        p = pl.pointAtLength(theLength);
221
                                }
222
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
223
                                if(followLineAngle){
224
                                        rotation1 = (float) pl.angleAtLength(aLength);
225
                                        rotation2 = (float) pl.angleAtLength((float)(aLength+size));
226
                                        marker.setRotation(rotation1);
227
                                }
228
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
229
                        } else {
230
                                Point2D p = pl.pointAtLength(aLength+size);
231
                                if (p==null){
232
                                        p = pl.pointAtLength(theLength);
233
                                }
234

    
235
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
236
                                if(followLineAngle){
237
                                        rotation1 = (float) (pl.angleAtLength(aLength) + Math.PI);
238
                                        rotation2 = (float) (pl.angleAtLength((float)(aLength+size)) + Math.PI);
239
                                        marker.setRotation(rotation2);
240
                                }
241
                                marker.draw(g, new AffineTransform(), startP, feature, null);
242
                        }
243
                }
244

    
245
                startP = null;
246
                // and the last arrow at the begining of the line
247
                if (arrowMarkerCount>1) {
248
                        if (flipAll) {
249
                                Point2D p = null;
250
                                p = pl.pointAtLength(0);
251
                                if (p!=null){
252
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
253
                                        if(followLineAngle){
254
                                                rotation1 = (float) pl.angleAtLength(size);
255
                                                rotation2 = (float) pl.angleAtLength(0);
256
                                                marker.setRotation(rotation2);
257
                                        }
258
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
259
                                }                                
260
                        } else {
261
                                Point2D p = null;
262
                                if(followLineAngle){
263
                                        p = pl.pointAtLength(size);
264
                                } else {
265
                                        p = pl.pointAtLength(0);
266
                                }
267
                                if (p!=null){
268
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
269
                                        if(followLineAngle){
270
                                                rotation1 = (float) (pl.angleAtLength(size) + Math.PI);
271
                                                rotation2 = (float) (pl.angleAtLength(0) + Math.PI);
272
                                                marker.setRotation(rotation1);
273
                                        }
274
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
275
                                }
276
                        }
277
                }
278
        }
279

    
280
        public void drawInsideRectangle(Graphics2D g, Rectangle r) {
281
                // TODO Auto-generated method stub
282
                throw new Error("Not yet implemented!");
283
        }
284

    
285
        public void drawOutline(Graphics2D g, Rectangle r) {
286
                // TODO Auto-generated method stub
287
                throw new Error("Not yet implemented!");
288
        }
289

    
290
        public boolean isSuitableFor(ISymbol symbol) {
291
                return symbol instanceof ILineSymbol;
292
        }
293

    
294
        public String getClassName() {
295
                return getClass().getName();
296
        }
297

    
298
        public IMarkerSymbol getMarker() {
299
                if(marker == null){
300
                        marker = getDefaultMarker();
301
                }
302
                return marker;
303
        }
304

    
305
        public void setMarker(IMarkerSymbol marker) {
306
                this.marker = marker;
307
        }
308
        
309
        public Object clone() throws CloneNotSupportedException {
310
                ArrowDecoratorStyle copy  = (ArrowDecoratorStyle) super.clone();
311
                if (marker != null) {
312
                        copy.marker = (IMarkerSymbol) marker.clone();
313
                }
314
                return copy;
315
        }
316

    
317
        public void loadFromState(PersistentState state)
318
                        throws PersistenceException {
319
                // Set parent style properties
320
                super.loadFromState(state);
321

    
322
                // Set own properties
323
                setArrowMarkerCount(state.getInt(FIELD_ARROW_MARKER_COUNT));
324
                setFlipAll(state.getBoolean(FIELD_FLIP_ALL));
325
                setFlipFirst(state.getBoolean(FIELD_FLIP_FIRST));
326
                setFollowLineAngle(state.getBoolean(FIELD_FOLLOW_LINE_ANGLE));
327
                setMarker((IMarkerSymbol) state.get(FIELD_MARKER));
328
        }
329

    
330
        public void saveToState(PersistentState state) throws PersistenceException {
331
                // Save parent fill symbol properties
332
                super.saveToState(state);
333

    
334
                // Save own properties
335
                state.set(FIELD_ARROW_MARKER_COUNT, getArrowMarkerCount());
336
                state.set(FIELD_FLIP_ALL, isFlipAll());
337
                state.set(FIELD_FLIP_FIRST, isFlipFirst());
338
                state.set(FIELD_FOLLOW_LINE_ANGLE, isFollowLineAngle());
339
                state.set(FIELD_MARKER, getMarker());
340
        }
341
        
342
        public static class RegisterPersistence implements Callable {
343

    
344
                public Object call() throws Exception {
345
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
346
                        if( manager.getDefinition(ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME)==null ) {
347
                                DynStruct definition = manager.addDefinition(
348
                                                ArrowDecoratorStyle.class,
349
                                                ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME,
350
                                                ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
351
                                                null, 
352
                                                null
353
                                );
354
                                
355
                                // Extend the Style base definition
356
                                definition.extend(manager.getDefinition(STYLE_PERSISTENCE_DEFINITION_NAME));
357

    
358
                                // Arrow marker count
359
                                definition.addDynFieldInt(FIELD_ARROW_MARKER_COUNT).setMandatory(true);
360
                                // Flip all
361
                                definition.addDynFieldBoolean(FIELD_FLIP_ALL).setMandatory(true);
362
                                // flip first
363
                                definition.addDynFieldBoolean(FIELD_FLIP_FIRST).setMandatory(true);
364
                                // Follow line angles
365
                                definition.addDynFieldBoolean(FIELD_FOLLOW_LINE_ANGLE).setMandatory(true);
366
                                // Marker
367
                                definition.addDynFieldObject(FIELD_MARKER)
368
                                        .setClassOfValue(IMarkerSymbol.class)
369
                                        .setMandatory(true);
370

    
371
                        }
372
                        return Boolean.TRUE;
373
                }
374
                
375
        }
376

    
377
}