Statistics
| Revision:

gvsig-raster / org.gvsig.raster.tools / trunk / org.gvsig.raster.tools / org.gvsig.raster.tools.app / org.gvsig.raster.tools.app.basic / src / main / java / org / gvsig / raster / tools / app / basic / tool / geolocation / behavior / RotationBehavior.java @ 1174

History | View | Annotate | Download (12.7 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
*
3
* Copyright (C) 2007-2008 Infrastructures and Transports Department
4
* of the Valencian Government (CIT)
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 2
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
*/
22
package org.gvsig.raster.tools.app.basic.tool.geolocation.behavior;
23

    
24
import java.awt.AlphaComposite;
25
import java.awt.Color;
26
import java.awt.Image;
27
import java.awt.event.MouseEvent;
28
import java.awt.geom.AffineTransform;
29
import java.awt.geom.NoninvertibleTransformException;
30
import java.awt.geom.Point2D;
31

    
32
import org.gvsig.andami.IconThemeHelper;
33
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
34
import org.gvsig.fmap.mapcontext.ViewPort;
35
import org.gvsig.fmap.mapcontrol.MapControlDrawer;
36
import org.gvsig.fmap.mapcontrol.tools.BehaviorException;
37
import org.gvsig.fmap.mapcontrol.tools.Listeners.RectangleListener;
38
import org.gvsig.fmap.mapcontrol.tools.Listeners.ToolListener;
39
import org.gvsig.raster.tools.app.basic.RasterToolsUtil;
40

    
41

    
42
/**
43
 * Comportamiento que se aplica a la herramienta de rotation. El cursor del rat?n cambiar? cuando
44
 * se encuentre en las esquinas y en la zona exterior al raster, permitiendo el rotar la imagen al pinchar y
45
 * arrastrar.
46
 *
47
 * Nacho Brodin (nachobrodin@gmail.com)
48
 *
49
 */
50
@SuppressWarnings("deprecation")
51
public class RotationBehavior extends TransformationBehavior {
52
        //N?mero de pixeles de ancho del borde donde el cursor se activar?. Son pixeles del canvas de la vista.
53
        //De esta forma da igual la escala a la que est? la imagen siempre tiene la misma precisi?n
54
        private int                                                         PX_SELEC_BASE = 12;
55
        private int                                                         LONG_CORNER_BASE = 18;
56
        private int                                                         PX_SELEC = PX_SELEC_BASE;
57
        private int                                                         LONG_CORNER = LONG_CORNER_BASE;
58

    
59
        private Color                                                        rectangleColor = Color.RED;
60

    
61
        private RectangleListener               listener;
62

    
63
        private final Image                     rotImg = IconThemeHelper.getImage("rotate-cursor");
64

    
65
        /**
66
         * Puntos de inicio y final para el arrastre de la imagen.
67
         */
68
        private Point2D                                                 beforePoint = null;
69
        private Point2D                                                 nextPoint = null;
70

    
71
        /**
72
         * Variable que si est? a true permite que se pinte el marco de la imagen. Se activa al
73
         * comenzar el redimensionado y se desactiva al terminar
74
         */
75
        private boolean                                                 isRotable = false;
76
        private AffineTransform                 boxRot = null;
77
        /**
78
         * Valor de la rotaci?n.
79
         */
80
        private double                          rotation = 0;
81

    
82
        /**
83
         * Lista de flags de redimensionado para cada lado del raster
84
         * [0]-esquina superior derecha
85
         * [1]-esquina superior izquierda
86
         * [2]-esquina inferior derecha
87
         * [3]-esquina inferior izquierda
88
         */
89
        private boolean[]                                                cornerActive = {false, false, false, false};
90
        private boolean                                                 init = false;
91
        /**
92
         * Indica cual ser? la velocidad de rotaci?n
93
         */
94
        private double                                                        incrRot = 0.005;
95

    
96
        /**
97
         * Crea un nuevo RectangleBehavior.
98
         *
99
         * @param zili listener.
100
         */
101
        public RotationBehavior(GeoRasterBehavior grb, Image curImage, ITransformIO windowIO) {
102
                grBehavior = grb;
103
                defaultImage = curImage;
104
                this.trIO = windowIO;
105
        }
106

    
107
        /**
108
         * Inicializaci?n. Calcula la longitud de la esquina y el ancho en p?xeles
109
         * de la zona de detecci?n del puntero de rat?n. Inicialmente esto est? calculado en
110
         * unidades pixel de la vista pero la detecci?n de puntero, debido a la rotaci?n posible
111
         * del raster ha de hacerse en unidades del raster en disco por ello ha de calcularse
112
         * una escala entre ambas unidades cuando se carga la aplicaci?n.
113
         *
114
         */
115
        private void init() {
116
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
117
                lyr = grBehavior.getLayer();
118
                if(lyr == null)
119
                        return ;
120

    
121
                Extent ext = lyr.getDataStore().getExtent();
122
                AffineTransform atImg = lyr.getDataStore().getAffineTransform();
123

    
124
                //Establecer una escala entre las coordenadas de la vista y las coordenadas pixel
125
                Point2D ul = new Point2D.Double(ext.getULX(), ext.getULY());
126
                Point2D lr = new Point2D.Double(ext.getLRX(), ext.getLRY());
127
                Point2D ulPx = new Point2D.Double();
128
                Point2D lrPx = new Point2D.Double();
129
                Point2D ulVp = new Point2D.Double();
130
                Point2D lrVp = new Point2D.Double();
131
                double esc = 1;
132
                try {
133
                        atImg.inverseTransform(ul, ulPx);
134
                        atImg.inverseTransform(lr, lrPx);
135
                        ulVp = vp.fromMapPoint(ul);
136
                        lrVp = vp.fromMapPoint(lr);
137
                        esc = Math.abs(lrPx.getX() - ulPx.getX()) / Math.abs(lrVp.getX() - ulVp.getX());
138
                } catch (NoninvertibleTransformException e1) {
139
                        return;
140
                }
141

    
142
                //Escalar PX_SELEC y LONG_CORNER para tenerlo en coordenadas pixel
143

    
144
                PX_SELEC = (int)(PX_SELEC_BASE * esc);
145
                LONG_CORNER = (int)(LONG_CORNER_BASE * esc);
146
                init = true;
147
        }
148

    
149
        /**
150
         * Cuando se produce un evento de pintado dibujamos el marco de la imagen para
151
         * que el usuario pueda seleccionar y redimensionar.
152
         */
153
        public void paintComponent(MapControlDrawer mapcontrolDrawer) {
154
                if(lyr == null)
155
                        lyr = grBehavior.getLayer();
156

    
157
                if(isRotable && lyr != null) {
158
                        try {
159
                                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
160
                                AffineTransform at = new AffineTransform(lyr.getAffineTransform());
161
                                Extent ext = lyr.getFullRasterExtent();
162
                                Point2D center = new Point2D.Double(lyr.getPxWidth() / 2, lyr.getPxHeight()/ 2);
163
                                at.transform(center, center);
164

    
165
                                Point2D ul = new Point2D.Double(ext.getULX(), ext.getULY());
166
                                Point2D lr = new Point2D.Double(ext.getLRX(), ext.getLRY());
167

    
168
                                AffineTransform T1 = new AffineTransform(1, 0, 0, 1, -center.getX(), -center.getY());
169
                                AffineTransform R1 = new AffineTransform();
170
                                R1.setToRotation(rotation);
171
                                AffineTransform T2 = new AffineTransform(1, 0, 0, 1, center.getX(), center.getY());
172
                                T2.concatenate(R1);
173
                                T2.concatenate(T1);
174

    
175
                                T2.transform(ul, ul);
176
                                T2.transform(lr, lr);
177

    
178
                                at.preConcatenate(T2);
179
                                boxRot = new AffineTransform(at);
180
                                at.preConcatenate(vp.getAffineTransform());
181

    
182
                                vp.getAffineTransform().transform(ul, ul);
183
                                at.inverseTransform(ul, ul);
184

    
185
                                vp.getAffineTransform().transform(lr, lr);
186
                                at.inverseTransform(lr, lr);
187

    
188
                                mapcontrolDrawer.transform(at);
189
                                mapcontrolDrawer.setColor(rectangleColor);
190
                                mapcontrolDrawer.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f));
191
                                mapcontrolDrawer.fillRect((int)ul.getX(), (int)ul.getY(), (int)lr.getX(), (int)lr.getY());
192
                                mapcontrolDrawer.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
193
                                mapcontrolDrawer.drawRect((int)ul.getX(), (int)ul.getY(), (int)lr.getX(), (int)lr.getY());
194
                                mapcontrolDrawer.transform(at.createInverse());
195
                        } catch (NoninvertibleTransformException e1) {
196
                                RasterToolsUtil.messageBoxError("error_transformacion1", this, e1);
197
                        }
198
                }
199
        }
200

    
201
        /**
202
         * Reimplementaci?n del m?todo mousePressed de Behavior. Si no est?
203
         * activo el cursor por defecto capturamos el punto seleccionado en
204
         * coordenadas del mundo real.
205
         *
206
         * @param e MouseEvent
207
         */
208
        public void mousePressed(MouseEvent e) {
209
                if (e.getButton() == MouseEvent.BUTTON1) {
210
                        ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
211
                        beforePoint = vp.toMapPoint(e.getPoint());
212
                        if(lyr == null)
213
                                lyr = grBehavior.getLayer();
214
                        isRotable = true;
215
                }
216
        }
217

    
218
        /**
219
         * Reimplementaci?n del m?todo mouseReleased de Behavior. Desactivamos
220
         * los flags de redimensionado y a partir de la selecci?n del usuario
221
         * creamos un nuevo extent para la imagen. Con este extent creamos una nueva
222
         * capa que sustituir? a la anterior.
223
         *
224
         * @param e MouseEvent
225
         *
226
         * @throws BehaviorException Excepci?n lanzada cuando el Behavior.
227
         */
228
        public void mouseReleased(MouseEvent e) throws BehaviorException {
229
                if(e.getButton() == MouseEvent.BUTTON1) {
230
                        if(boxRot != null)
231
                                lyr.setAffineTransform(boxRot);
232
                        rotation = 0;
233
                        grBehavior.getMapControl().getMapContext().invalidate();
234
                        isRotable = false;
235
                        super.mouseReleased(e);
236
                }
237
        }
238

    
239
        /**
240
         * Cuando arrastramos con el rat?n pulsado significa que estamos rotando la imagen. Para realizar la rotaci?n
241
         * medimos la distancia al punto inicial (desde el pto que estamos al pto donde se picho la primera vez). Esta distancia
242
         * nos da la velocidad de giro ya que si es grande es que lo habremos movido deprisa y si es peque?a habremos arrastrado
243
         * el rat?n despacio. Creamos una matriz de transformaci?n con la identidad y la rotaci?n que hemos medido aplicada. Al
244
         * final repintamos para que se pueda usar esta rotaci?n calculada en el repintado.
245
         */
246
        public void mouseDragged(MouseEvent e) {
247
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
248
                nextPoint = vp.toMapPoint(e.getPoint());
249

    
250
                //Para la esquinas derechas cuando subimos el puntero giramos a izquierdas
251
                //Para la esquinas izquierdas cuando subimos el puntero giramos a derechas
252
                if( ((cornerActive[0] || cornerActive[2]) && (beforePoint.getY() < nextPoint.getY())) ||
253
                        ((cornerActive[1] || cornerActive[3]) && (beforePoint.getY() >= nextPoint.getY())))
254
                        rotation += incrRot;
255
                else
256
                        rotation -= incrRot;
257

    
258
                beforePoint = vp.toMapPoint(e.getPoint());
259
                if(boxRot != null)
260
                        trIO.loadTransform(boxRot);
261
                grBehavior.getMapControl().repaint();
262
        }
263

    
264
        /**
265
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#setListener(org.gvsig.georeferencing.fmap.tools.ToolListener)
266
         */
267
        public void setListener(ToolListener listener) {
268
                this.listener = (RectangleListener) listener;
269
        }
270

    
271
        /**
272
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#getListener()
273
         */
274
        public ToolListener getListener() {
275
                return listener;
276
        }
277

    
278
        /**
279
         * Cuando movemos el rat?n detecta si estamos en el marco de la
280
         * imagen y pone el icono del cursor del rat?n adecuado.
281
         */
282
        public boolean mouseMoved(MouseEvent ev) throws BehaviorException {
283
                if(!init)
284
                        init();
285

    
286
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
287
                resetBorderSelected();
288

    
289
                lyr = grBehavior.getLayer();
290
                if(lyr == null) {
291
                        setActiveTool(false);
292
                        return false;
293
                }
294

    
295
                AffineTransform atImg = lyr.getAffineTransform();
296

    
297
                //Pasar coordenadas del punto a coordenadas reales y luego a coordenadas pixel
298
                Point2D e = vp.toMapPoint(ev.getX(), ev.getY());
299
                try {
300
                        atImg.inverseTransform(e, e);
301
                } catch (NoninvertibleTransformException e1) {
302
                        return false;
303
                }
304

    
305
                //Comprobar si est? dentro del raster
306
                Point2D p1 = new Point2D.Double(0, 0);
307
                Point2D p2 = new Point2D.Double(lyr.getDataStore().getWidth(), lyr.getDataStore().getHeight());
308

    
309
                //esquina superior izquierda
310
                if ((e.getX() > (p1.getX() - PX_SELEC) && e.getX() <= (p1.getX() + LONG_CORNER) && e.getY() <= p1.getY() && e.getY() > (p1.getY() - PX_SELEC)) ||
311
                        (e.getX() <= p1.getX() && e.getX() > (p1.getX() - PX_SELEC) && e.getY() > p1.getY() && e.getY() <= (p1.getY() + LONG_CORNER))) {
312
                        setCursor(rotImg);
313
                        setActiveTool(true);
314
                        cornerActive[1] = true;
315
                        return true;
316
                }
317

    
318
                //esquina superior derecha
319
                if ((e.getX() >= (p2.getX() - LONG_CORNER) && e.getX() < (p2.getX() + PX_SELEC) && e.getY() <= p1.getY() && e.getY() > (p1.getY() - PX_SELEC)) ||
320
                        (e.getX() >= p2.getX() && e.getX() < (p2.getX() + PX_SELEC) && e.getY() > p1.getY() && e.getY() <= (p1.getY() + LONG_CORNER))) {
321
                        setCursor(rotImg);
322
                        setActiveTool(true);
323
                        cornerActive[0] = true;
324
                        return true;
325
                }
326

    
327
                //esquina inferior izquierda
328
                if ((e.getX() > (p1.getX() - PX_SELEC) && e.getX() <= (p1.getX() + LONG_CORNER) && e.getY() >= p2.getY() && e.getY() < (p2.getY() + PX_SELEC)) ||
329
                        (e.getX() <= p1.getX() && e.getX() > (p1.getX() - PX_SELEC) && e.getY() < p2.getY() && e.getY() >= (p2.getY() - LONG_CORNER))) {
330
                        setCursor(rotImg);
331
                        setActiveTool(true);
332
                        cornerActive[3] = true;
333
                        return true;
334
                }
335

    
336
                //esquina inferior derecha
337
                if ((e.getX() < (p2.getX() + PX_SELEC) && e.getX() >= (p2.getX() - LONG_CORNER) && e.getY() >= p2.getY() && e.getY() < (p2.getY() + PX_SELEC)) ||
338
                        (e.getX() >= p2.getX() && e.getX() <= (p2.getX() + PX_SELEC) && e.getY() < p2.getY() && e.getY() >= (p2.getY() - LONG_CORNER))){
339
                        setCursor(rotImg);
340
                        setActiveTool(true);
341
                        cornerActive[2] = true;
342
                        return true;
343
                }
344

    
345
                grBehavior.getMapControl().repaint();
346
//                grBehavior.getMapControl().setCursor(defaultCursor);
347
                return false;
348
        }
349

    
350
        /**
351
         * Pone a false todos los elementos del array sideActive. Esto es equivalente
352
         * a eliminar cualquier selecci?n de borde.
353
         */
354
        private void resetBorderSelected() {
355
                for (int i = 0; i < cornerActive.length; i++)
356
                        cornerActive[i] = false;
357
        }
358

    
359
}