Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extRasterTools-SE / src / org / gvsig / rastertools / geolocation / behavior / ShearBehavior.java @ 22529

History | View | Annotate | Download (12.3 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.AlphaComposite;
22
import java.awt.Cursor;
23
import java.awt.Graphics;
24
import java.awt.Graphics2D;
25
import java.awt.Image;
26
import java.awt.event.MouseEvent;
27
import java.awt.geom.AffineTransform;
28
import java.awt.geom.NoninvertibleTransformException;
29
import java.awt.geom.Point2D;
30

    
31
import javax.swing.ImageIcon;
32

    
33
import org.gvsig.raster.datastruct.Extent;
34
import org.gvsig.raster.util.RasterToolsUtil;
35

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

    
41

    
42
/**
43
 * Comportamiento que se aplica a la herramienta de shear. El cursor del rat?n cambiar? cuando
44
 * se encuentre en la zona exterior al raster, permitiendo el deformar la imagen al pinchar y 
45
 * arrastrar en los ejes X e Y.
46
 * 
47
 * Nacho Brodin (nachobrodin@gmail.com)
48
 *
49
 */
50
public class ShearBehavior extends TransformationBehavior {
51
        //N?mero de pixeles de ancho del borde donde el cursor se activar?. Son pixeles del canvas de la vista.
52
        //De esta forma da igual la escala a la que est? la imagen siempre tiene la misma precisi?n
53
        private int                                                         PX_SELEC_BASE = 12;
54
        private int                                                         PX_SELEC = PX_SELEC_BASE;
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
        private AffineTransform                 boxShear = null;
70
        
71
        /**
72
         * Lista de flags de redimensionado para cada lado del raster
73
         * [0]-esquina superior derecha
74
         * [1]-esquina superior izquierda
75
         * [2]-esquina inferior derecha
76
         * [3]-esquina inferior izquierda
77
         */
78
        private boolean[]                                                cornerActive = {false, false, false, false};
79
        private boolean                                                 init = false;
80
        /**
81
         * Controla si se ha activado el shear o no
82
         */
83
        private boolean                         isShearing = false;
84
        /**
85
         * Contiene el valor del incremento
86
         */
87
        private double                                                        incrShear = 0.01;
88
        /**
89
         * Control del valor del shearing en X
90
         */
91
        private double                          shearX = 0;
92
        /**
93
         * Control del valor del shearing en Y
94
         */
95
        private double                          shearY = 0;
96
        
97
        
98
        /**
99
         * Crea un nuevo RectangleBehavior.
100
         *
101
         * @param zili listener.
102
         */
103
        public ShearBehavior(GeoRasterBehavior grb, Cursor cur, ITransformIO windowIO) {
104
                grBehavior = grb;
105
                defaultCursor = cur;
106
                this.trIO = windowIO;
107
        }
108

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

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

    
220
        /**
221
         * Reimplementaci?n del m?todo mouseReleased de Behavior. Desactivamos
222
         * los flags de redimensionado y a partir de la selecci?n del usuario 
223
         * creamos un nuevo extent para la imagen. Con este extent creamos una nueva
224
         * capa que sustituir? a la anterior.
225
         *
226
         * @param e MouseEvent
227
         *
228
         * @throws BehaviorException Excepci?n lanzada cuando el Behavior.
229
         */
230
        public void mouseReleased(MouseEvent e) throws BehaviorException {
231
                if(e.getButton() == MouseEvent.BUTTON1) {
232
                        lyr.setAffineTransform(boxShear);
233
                        shearX = shearY = 0;
234
                        grBehavior.getMapControl().getMapContext().invalidate();
235
                        isShearing = false;
236
                        super.mouseReleased(e);
237
                }
238
        }
239
        
240
        /**
241
         * Cuando arrastramos con el rat?n pulsado significa que estamos rotando la imagen. Para realizar la rotaci?n
242
         * medimos la distancia al punto inicial (desde el pto que estamos al pto donde se picho la primera vez). Esta distancia
243
         * nos da la velocidad de giro ya que si es grande es que lo habremos movido deprisa y si es peque?a habremos arrastrado
244
         * el rat?n despacio. Creamos una matriz de transformaci?n con la identidad y la rotaci?n que hemos medido aplicada. Al
245
         * final repintamos para que se pueda usar esta rotaci?n calculada en el repintado. 
246
         */
247
        public void mouseDragged(MouseEvent e) {
248
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
249
                nextPoint = vp.toMapPoint(e.getPoint());
250
                
251
                if( (cornerActive[0] && (beforePoint.getY() >= nextPoint.getY())) ||
252
                        (cornerActive[1] && (beforePoint.getY() < nextPoint.getY())) )
253
                        shearY += incrShear;
254
                if( (cornerActive[0] && (beforePoint.getY() < nextPoint.getY())) ||
255
                        (cornerActive[1] && (beforePoint.getY() >= nextPoint.getY())) )
256
                                shearY -= incrShear;
257
                if( (cornerActive[2] && (beforePoint.getX() >= nextPoint.getX())) ||
258
                        (cornerActive[3] && (beforePoint.getX() < nextPoint.getX())) )
259
                                shearX += incrShear;
260
                if( (cornerActive[2] && (beforePoint.getX() < nextPoint.getX())) ||
261
                        (cornerActive[3] && (beforePoint.getX() >= nextPoint.getX())) )
262
                                shearX -= incrShear;
263
                                                
264
                beforePoint = vp.toMapPoint(e.getPoint());
265
                if(boxShear != null)
266
                        trIO.loadTransform(boxShear);
267
                grBehavior.getMapControl().repaint();
268
        }
269
        
270
        /**
271
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#setListener(org.gvsig.georeferencing.fmap.tools.ToolListener)
272
         */
273
        public void setListener(ToolListener listener) {
274
                this.listener = (RectangleListener) listener;
275
        }
276

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

    
363
}