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 / ShearBehavior.java @ 1174

History | View | Annotate | Download (12.3 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.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 org.gvsig.andami.IconThemeHelper;
32
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
33
import org.gvsig.fmap.mapcontext.ViewPort;
34
import org.gvsig.fmap.mapcontrol.MapControlDrawer;
35
import org.gvsig.fmap.mapcontrol.tools.BehaviorException;
36
import org.gvsig.fmap.mapcontrol.tools.Listeners.RectangleListener;
37
import org.gvsig.fmap.mapcontrol.tools.Listeners.ToolListener;
38
import org.gvsig.raster.tools.app.basic.RasterToolsUtil;
39

    
40

    
41
/**
42
 * Comportamiento que se aplica a la herramienta de shear. El cursor del rat?n cambiar? cuando
43
 * se encuentre en la zona exterior al raster, permitiendo el deformar la imagen al pinchar y
44
 * arrastrar en los ejes X e Y.
45
 *
46
 * Nacho Brodin (nachobrodin@gmail.com)
47
 *
48
 */
49
@SuppressWarnings("deprecation")
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                     shearXImg = IconThemeHelper.getImage("shear-x-cursor");
59
        private final Image                     shearYImg = IconThemeHelper.getImage("shear-y-cursor");
60
        
61
        /**
62
         * Puntos de inicio y final para el arrastre de la imagen.
63
         */
64
        private Point2D                                                 beforePoint = null;
65
        private Point2D                                                 nextPoint = null;
66

    
67
        private AffineTransform                 boxShear = null;
68

    
69
        /**
70
         * Lista de flags de redimensionado para cada lado del raster
71
         * [0]-esquina superior derecha
72
         * [1]-esquina superior izquierda
73
         * [2]-esquina inferior derecha
74
         * [3]-esquina inferior izquierda
75
         */
76
        private boolean[]                                                cornerActive = {false, false, false, false};
77
        private boolean                                                 init = false;
78
        /**
79
         * Controla si se ha activado el shear o no
80
         */
81
        private boolean                         isShearing = false;
82
        /**
83
         * Contiene el valor del incremento
84
         */
85
        private double                                                        incrShear = 0.01;
86
        /**
87
         * Control del valor del shearing en X
88
         */
89
        private double                          shearX = 0;
90
        /**
91
         * Control del valor del shearing en Y
92
         */
93
        private double                          shearY = 0;
94

    
95

    
96
        /**
97
         * Crea un nuevo RectangleBehavior.
98
         *
99
         * @param zili listener.
100
         */
101
        public ShearBehavior(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.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
                        RasterToolsUtil.messageBoxError("error_transformacion1", this, e1);
140
                        return;
141
                }
142

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

    
145
                PX_SELEC = (int)(PX_SELEC_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(isShearing && 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.setToShear(shearX, shearY);
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
                                boxShear = 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
                        isShearing = 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
                        lyr.setAffineTransform(boxShear);
231
                        shearX = shearY = 0;
232
                        grBehavior.getMapControl().getMapContext().invalidate();
233
                        isShearing = false;
234
                        super.mouseReleased(e);
235
                }
236
        }
237

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

    
249
                if( (cornerActive[0] && (beforePoint.getY() >= nextPoint.getY())) ||
250
                        (cornerActive[1] && (beforePoint.getY() < nextPoint.getY())) )
251
                        shearY += incrShear;
252
                if( (cornerActive[0] && (beforePoint.getY() < nextPoint.getY())) ||
253
                        (cornerActive[1] && (beforePoint.getY() >= nextPoint.getY())) )
254
                                shearY -= incrShear;
255
                if( (cornerActive[2] && (beforePoint.getX() >= nextPoint.getX())) ||
256
                        (cornerActive[3] && (beforePoint.getX() < nextPoint.getX())) )
257
                                shearX += incrShear;
258
                if( (cornerActive[2] && (beforePoint.getX() < nextPoint.getX())) ||
259
                        (cornerActive[3] && (beforePoint.getX() >= nextPoint.getX())) )
260
                                shearX -= incrShear;
261

    
262
                beforePoint = vp.toMapPoint(e.getPoint());
263
                if(boxShear != null)
264
                        trIO.loadTransform(boxShear);
265
                grBehavior.getMapControl().repaint();
266
        }
267

    
268
        /**
269
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#setListener(org.gvsig.georeferencing.fmap.tools.ToolListener)
270
         */
271
        public void setListener(ToolListener listener) {
272
                this.listener = (RectangleListener) listener;
273
        }
274

    
275
        /**
276
         * @see com.iver.cit.gvsig.fmap.tools.Behavior.Behavior#getListener()
277
         */
278
        public ToolListener getListener() {
279
                return listener;
280
        }
281

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

    
290
                ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
291
                resetBorderSelected();
292

    
293
                lyr = grBehavior.getLayer();
294
                if(lyr == null) {
295
                        setActiveTool(false);
296
                        return false;
297
                }
298

    
299
                AffineTransform atImg = lyr.getAffineTransform();
300

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

    
309
                //Comprobar si est? dentro del raster
310
                Point2D p1 = new Point2D.Double(0, 0);
311
                Point2D p2 = new Point2D.Double(lyr.getDataStore().getWidth(), lyr.getDataStore().getHeight());
312

    
313
                //System.out.println("--->" + e.getX() + " , " + e.getY());
314

    
315
                //lateral derecho
316
                if (e.getY() > p1.getY() && e.getY() < p2.getY() && e.getX() > p2.getX() && e.getX() < (p2.getX() + PX_SELEC)) {
317
                        setCursor(shearYImg);
318
                        setActiveTool(true);
319
                        cornerActive[1] = true;
320
                        return true;
321
                }
322

    
323
                //lateral izquierdo
324
                if (e.getY() > p1.getY() && e.getY() < p2.getY() && e.getX() < p1.getX() && e.getX() > (p1.getX() - PX_SELEC)) {
325
                        setCursor(shearYImg);
326
                        setActiveTool(true);
327
                        cornerActive[0] = true;
328
                        return true;
329
                }
330

    
331
                //lateral superior
332
                if (e.getX() > p1.getX() && e.getX() < p2.getX() && e.getY() < p1.getY() && e.getY() > (p1.getX() - PX_SELEC)) {
333
                        setCursor(shearXImg);
334
                        setActiveTool(true);
335
                        cornerActive[3] = true;
336
                        return true;
337
                }
338

    
339
                //lateral inferior
340
                if (e.getX() > p1.getX() && e.getX() < p2.getX() && e.getY() > p2.getY() && e.getY() < (p2.getY() + PX_SELEC)) {
341
                        setCursor(shearXImg);
342
                        setActiveTool(true);
343
                        cornerActive[2] = true;
344
                        return true;
345
                }
346

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

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

    
361
}