Statistics
| Revision:

root / trunk / extensions / extRasterTools-SE / src / org / gvsig / rastertools / geolocation / behavior / ShearBehavior.java @ 13328

History | View | Annotate | Download (11.7 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 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
package org.gvsig.rastertools.geolocation.behavior;
20

    
21
import java.awt.Color;
22
import java.awt.Cursor;
23
import java.awt.Graphics;
24
import java.awt.Image;
25
import java.awt.event.MouseEvent;
26
import java.awt.geom.AffineTransform;
27
import java.awt.geom.NoninvertibleTransformException;
28
import java.awt.geom.Point2D;
29

    
30
import javax.swing.ImageIcon;
31

    
32
import org.gvsig.raster.datastruct.Extent;
33

    
34
import com.iver.cit.gvsig.fmap.ViewPort;
35
import com.iver.cit.gvsig.fmap.tools.BehaviorException;
36
import com.iver.cit.gvsig.fmap.tools.Listeners.RectangleListener;
37
import com.iver.cit.gvsig.fmap.tools.Listeners.ToolListener;
38

    
39

    
40
/**
41
 * Comportamiento que se aplica a la herramienta de shear. El cursor del rat?n cambiar? cuando
42
 * se encuentre en la zona exterior al raster, permitiendo el deformar la imagen al pinchar y 
43
 * arrastrar en los ejes X e Y.
44
 * 
45
 * Nacho Brodin (nachobrodin@gmail.com)
46
 *
47
 */
48
public class ShearBehavior extends TransformationBehavior {
49
        //N?mero de pixeles de ancho del borde donde el cursor se activar?. Son pixeles del canvas de la vista.
50
        //De esta forma da igual la escala a la que est? la imagen siempre tiene la misma precisi?n
51
        private int                                                         PX_SELEC_BASE = 12;
52
        private int                                                         PX_SELEC = PX_SELEC_BASE;
53

    
54
        private Color                                                        rectangleColor = Color.RED;
55
        
56
        private RectangleListener listener;
57
        
58
        private final Image shearYImg = new ImageIcon(getClass().getClassLoader().getResource(
59
                "images/y.gif")).getImage(); 
60
        private final Image shearXImg = new ImageIcon(getClass().getClassLoader().getResource(
61
                "images/x.gif")).getImage(); 
62

    
63
        /**
64
         * Puntos de inicio y final para el arrastre de la imagen.
65
         */
66
        private Point2D                                                 beforePoint = null;
67
        private Point2D                                                 nextPoint = null;
68
        
69
        /**
70
         * Variable que si est? a true permite que se pinte el marco de la imagen. Se activa al
71
         * comenzar el redimensionado y se desactiva al terminar
72
         */
73
        private boolean                                                 isRotable = false;
74
        private AffineTransform                 boxRot = null;
75
        /**
76
         * Valor de la rotaci?n.
77
         */
78
        private double                          rotation = 0;
79
        
80
        /**
81
         * Lista de flags de redimensionado para cada lado del raster
82
         * [0]-esquina superior derecha
83
         * [1]-esquina superior izquierda
84
         * [2]-esquina inferior derecha
85
         * [3]-esquina inferior izquierda
86
         */
87
        private boolean[]                                                cornerActive = {false, false, false, false};
88
        private boolean                                                 init = false;
89
        private double                                                        incrRot = 0.01;        
90
        
91
        /**
92
         * Crea un nuevo RectangleBehavior.
93
         *
94
         * @param zili listener.
95
         */
96
        public ShearBehavior(GeoRasterBehavior grb, Cursor cur, ITransformIO windowIO) {
97
                grBehavior = grb;
98
                defaultCursor = cur;
99
                this.trIO = windowIO;
100
        }
101

    
102
        /**
103
         * Inicializaci?n. Calcula la longitud de la esquina y el ancho en p?xeles
104
         * de la zona de detecci?n del puntero de rat?n. Inicialmente esto est? calculado en 
105
         * unidades pixel de la vista pero la detecci?n de puntero, debido a la rotaci?n posible
106
         * del raster ha de hacerse en unidades del raster en disco por ello ha de calcularse
107
         * una escala entre ambas unidades cuando se carga la aplicaci?n.
108
         *
109
         */
110
        private void init() {
111
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();                
112
                lyr = grBehavior.getLayer();
113
                if(lyr == null) 
114
                        return ;
115
                
116
                Extent ext = lyr.getDataSource().getExtent();
117
                AffineTransform atImg = lyr.getAffineTransform();
118
                                
119
                //Establecer una escala entre las coordenadas de la vista y las coordenadas pixel
120
                Point2D ul = new Point2D.Double(ext.getULX(), ext.getULY());
121
                Point2D lr = new Point2D.Double(ext.getLRX(), ext.getLRY());
122
                Point2D ulPx = new Point2D.Double();
123
                Point2D lrPx = new Point2D.Double();
124
                Point2D ulVp = new Point2D.Double();
125
                Point2D lrVp = new Point2D.Double();
126
                double esc = 1;
127
                try {
128
                        atImg.inverseTransform(ul, ulPx);
129
                        atImg.inverseTransform(lr, lrPx);
130
                        ulVp = vp.fromMapPoint(ul);
131
                        lrVp = vp.fromMapPoint(lr);
132
                        esc = Math.abs(lrPx.getX() - ulPx.getX()) / Math.abs(lrVp.getX() - ulVp.getX());
133
                } catch (NoninvertibleTransformException e1) {
134
                        return;
135
                }
136
                
137
                //Escalar PX_SELEC y LONG_CORNER para tenerlo en coordenadas pixel
138
                
139
                PX_SELEC = (int)(PX_SELEC_BASE * esc);
140
                init = true;
141
        }
142
        
143
        /**
144
         * Cuando se produce un evento de pintado dibujamos el marco de la imagen para
145
         * que el usuario pueda seleccionar y redimensionar.
146
         */
147
        public void paintComponent(Graphics g) {
148
                /*if(lyr == null)
149
                        lyr = grBehavior.getLayer();
150
                
151
                if(isRotable && lyr != null) {                        
152
                        try {
153
                                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
154
                                AffineTransform at = new AffineTransform(lyr.getAffineTransform());
155
                                Extent ext = lyr.getFullRasterExtent();
156
                                Point2D center = new Point2D.Double(lyr.getPxWidth() / 2, lyr.getPxHeight()/ 2);
157
                                at.transform(center, center);
158
                                                
159
                                Point2D ul = new Point2D.Double(ext.getULX(), ext.getULY());
160
                                Point2D lr = new Point2D.Double(ext.getLRX(), ext.getLRY());
161
                                                                
162
                                AffineTransform T1 = new AffineTransform(1, 0, 0, 1, -center.getX(), -center.getY());
163
                                AffineTransform R1 = new AffineTransform();
164
                                R1.setToRotation(rotation);
165
                                AffineTransform T2 = new AffineTransform(1, 0, 0, 1, center.getX(), center.getY());
166
                                T2.concatenate(R1);
167
                                T2.concatenate(T1);
168
                                                                
169
                                T2.transform(ul, ul);
170
                                T2.transform(lr, lr);
171
                                
172
                                at.preConcatenate(T2);
173
                                boxRot = new AffineTransform(at);
174
                                at.preConcatenate(vp.getAffineTransform());
175
                                                                                                
176
                                vp.getAffineTransform().transform(ul, ul);
177
                                at.inverseTransform(ul, ul);
178
                                
179
                                vp.getAffineTransform().transform(lr, lr);
180
                                at.inverseTransform(lr, lr);
181
                                
182
                                ((Graphics2D)g).transform(at);
183
                                g.setColor(rectangleColor);
184
                                ((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f));
185
                                g.fillRect((int)ul.getX(), (int)ul.getY(), (int)lr.getX(), (int)lr.getY());
186
                                ((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
187
                                g.drawRect((int)ul.getX(), (int)ul.getY(), (int)lr.getX(), (int)lr.getY());
188
                                ((Graphics2D)g).transform(at.createInverse());
189
                        } catch (NoninvertibleTransformException e1) {
190
                                NotificationManager.addError("No se puede calcular la transformaci?n inversa de alguna esquina del raster", e1);
191
                        }
192
                }*/                
193
        }
194

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

    
212
        /**
213
         * Reimplementaci?n del m?todo mouseReleased de Behavior. Desactivamos
214
         * los flags de redimensionado y a partir de la selecci?n del usuario 
215
         * creamos un nuevo extent para la imagen. Con este extent creamos una nueva
216
         * capa que sustituir? a la anterior.
217
         *
218
         * @param e MouseEvent
219
         *
220
         * @throws BehaviorException Excepci?n lanzada cuando el Behavior.
221
         */
222
        public void mouseReleased(MouseEvent e) throws BehaviorException {
223
                /*if(e.getButton() == MouseEvent.BUTTON1) {
224
                        lyr.setAffineTransform(boxRot);
225
                        rotation = 0;
226
                        grBehavior.getMapControl().getMapContext().invalidate();
227
                        isRotable = false;
228
                        super.mouseReleased(e);
229
                }*/
230
        }
231
        
232
        /**
233
         * Cuando arrastramos con el rat?n pulsado significa que estamos rotando la imagen. Para realizar la rotaci?n
234
         * medimos la distancia al punto inicial (desde el pto que estamos al pto donde se picho la primera vez). Esta distancia
235
         * nos da la velocidad de giro ya que si es grande es que lo habremos movido deprisa y si es peque?a habremos arrastrado
236
         * el rat?n despacio. Creamos una matriz de transformaci?n con la identidad y la rotaci?n que hemos medido aplicada. Al
237
         * final repintamos para que se pueda usar esta rotaci?n calculada en el repintado. 
238
         */
239
        public void mouseDragged(MouseEvent e) {
240
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
241
                nextPoint = vp.toMapPoint(e.getPoint());                                                        
242
                //El valor por el que se divide controla la velocidad del giro
243
                if((beforePoint.getY() < nextPoint.getY())) 
244
                        rotation += incrRot;
245
                else
246
                        rotation -= incrRot;
247
                                                
248
                beforePoint = vp.toMapPoint(e.getPoint());
249
                if(boxRot != null)
250
                        trIO.loadTransform(boxRot);
251
                grBehavior.getMapControl().repaint();
252
        }
253
        
254
        /**
255
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#setListener(org.gvsig.georeferencing.fmap.tools.ToolListener)
256
         */
257
        public void setListener(ToolListener listener) {
258
                this.listener = (RectangleListener) listener;
259
        }
260

    
261
        /**
262
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#getListener()
263
         */
264
        public ToolListener getListener() {
265
                return listener;
266
        }
267
        
268
        /**
269
         * Cuando movemos el rat?n detecta si estamos en el marco de la 
270
         * imagen y pone el icono del cursor del rat?n adecuado.
271
         */
272
        public boolean mouseMoved(MouseEvent ev) throws BehaviorException {
273
                if(!init)
274
                        init();
275
                
276
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
277
                resetBorderSelected();
278
                
279
                lyr = grBehavior.getLayer();
280
                if(lyr == null) {
281
                        setActiveTool(false);
282
                        return false;
283
                }
284
                
285
                AffineTransform atImg = lyr.getAffineTransform();
286
                                
287
                //Pasar coordenadas del punto a coordenadas reales y luego a coordenadas pixel
288
                Point2D e = vp.toMapPoint(ev.getX(), ev.getY());
289
                try {
290
                        atImg.inverseTransform(e, e);
291
                } catch (NoninvertibleTransformException e1) {
292
                        return false;
293
                }
294
                                
295
                //Comprobar si est? dentro del raster
296
                Point2D p1 = new Point2D.Double(0, 0);
297
                Point2D p2 = new Point2D.Double(lyr.getDataSource().getWidth()[0], lyr.getDataSource().getHeight()[0]);
298
                
299
                //System.out.println("--->" + e.getX() + " , " + e.getY());
300
                
301
                //lateral derecho
302
                if (e.getY() > p1.getY() && e.getY() < p2.getY() && e.getX() > p2.getX() && e.getX() < (p2.getX() + PX_SELEC)) {
303
                        setCursor(shearYImg);
304
                        setActiveTool(true);
305
                        cornerActive[1] = true;
306
                        return true;
307
                }
308
                
309
                //lateral izquierdo
310
                if (e.getY() > p1.getY() && e.getY() < p2.getY() && e.getX() < p1.getX() && e.getX() > (p1.getX() - PX_SELEC)) {
311
                        setCursor(shearYImg);
312
                        setActiveTool(true);
313
                        cornerActive[0] = true;
314
                        return true;
315
                }
316
                
317
                //lateral superior
318
                if (e.getX() > p1.getX() && e.getX() < p2.getX() && e.getY() < p1.getY() && e.getY() > (p1.getX() - PX_SELEC)) {
319
                        setCursor(shearXImg);
320
                        setActiveTool(true);
321
                        cornerActive[3] = true;
322
                        return true;
323
                }
324
                
325
                //lateral inferior
326
                if (e.getX() > p1.getX() && e.getX() < p2.getX() && e.getY() > p2.getY() && e.getY() < (p2.getY() + PX_SELEC)) {
327
                        setCursor(shearXImg);
328
                        setActiveTool(true);
329
                        cornerActive[2] = true;
330
                        return true;
331
                }
332
                
333
                grBehavior.getMapControl().repaint();
334
                grBehavior.getMapControl().setCursor(defaultCursor);
335
                return false;
336
        }
337
        
338
        /**
339
         * Pone a false todos los elementos del array sideActive. Esto es equivalente 
340
         * a eliminar cualquier selecci?n de borde.
341
         */
342
        private void resetBorderSelected() {
343
                for (int i = 0; i < cornerActive.length; i++)
344
                        cornerActive[i] = false;
345
        }
346

    
347
}