001    //$$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/portal/standard/wms/control/ScaleSwitcherListener.java $$
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.portal.standard.wms.control;
038    
039    import java.util.ResourceBundle;
040    
041    import javax.servlet.ServletRequest;
042    
043    import org.deegree.enterprise.control.FormEvent;
044    import org.deegree.enterprise.control.RPCMethodCall;
045    import org.deegree.enterprise.control.RPCParameter;
046    import org.deegree.enterprise.control.RPCStruct;
047    import org.deegree.enterprise.control.RPCWebEvent;
048    import org.deegree.framework.util.MapUtils;
049    import org.deegree.model.crs.CRSFactory;
050    import org.deegree.model.crs.CoordinateSystem;
051    import org.deegree.model.crs.UnknownCRSException;
052    import org.deegree.model.spatialschema.Envelope;
053    import org.deegree.model.spatialschema.GeometryFactory;
054    import org.deegree.portal.Constants;
055    import org.deegree.portal.PortalException;
056    
057    /**
058     * The ScaleSwitcherListner handles switching the values of the scales from igeoportal
059     *
060     * @author <a href="mailto:ncho@lat-lon.de">Serge N'Cho</a>
061     * @author last edited by: $Author: mschneider $
062     *
063     * @version $Revision: 18195 $, $Date: 2007-12-27 17:59:14 +0100 (Do, 27 Dez 2007)$
064     */
065    public class ScaleSwitcherListener extends AbstractMapListener {
066    
067        private static double PIXEL_SIZE = 0.00028;
068    
069        static {
070            final ResourceBundle bundle = ResourceBundle.getBundle( "org.deegree.portal.standard.wms.control.map_listener" ); //$NON-NLS-1$
071            String ps = bundle.getString( "ScaleSwitcher.pixelSize" );
072            if ( ps != null ) {
073                PIXEL_SIZE = Double.valueOf( ps );
074            }
075        }
076    
077        /**
078         * Constant for "taskFromListener"
079         */
080        public static final String TASK_FROM_LISTENER = "taskFromListener";
081    
082        /**
083         * Constant for "BBOX"
084         */
085        public static final String BBOX = "BBOX";
086    
087        /**
088         * Constant for "zoomToFullExtent"
089         */
090        public static final String FULL_EXTENT = "zoomToFullExtent";
091    
092        /**
093         * Constant for "scaleValue"
094         */
095        public static final String SCALE_VALUE = "scaleValue";
096    
097        /**
098         * Constant for "newScaleValue"
099         */
100        public static final String NEW_SCALE_VALUE = "newScaleValue";
101    
102        /**
103         * Constant for "newBBox"
104         */
105        public static final String NEW_BBOX = "newBBox";
106    
107        /**
108         * Constant for "crs"
109         */
110        private static final String CRS = "crs";
111    
112        /**
113         * Constant for "mapWidth"
114         */
115        private static final String MAP_WIDTH = "mapWidth";
116    
117        /**
118         * Constant for "mapHeight"
119         */
120        private static final String MAP_HEIGHT = "mapHeight";
121    
122        /**
123         * Constant for "taskFromJSObject"
124         */
125        private static final String JS_TAK = "taskFromJSObject";
126    
127        /**
128         * Constant for "requestedScale"
129         */
130        private static final String REQUESTED_SCALE = "requestedScale";
131    
132        /**
133         * Constant for "getNewBBOX"
134         */
135        private static final String GET_NEW_BBOX = "getNewBBOX";
136    
137        /**
138         * Constant for "savedScaleValue"
139         */
140        private static final String SAVED_SCALE = "savedScaleValue";
141    
142        /**
143         * Constant for "getActualScaleValue"
144         */
145        private static final String GET_CURRENT_SCALE = "getActualScaleValue";
146    
147        /**
148         * @see org.deegree.enterprise.control .WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
149         */
150        @Override
151        public void actionPerformed( FormEvent event ) {
152    
153            RPCWebEvent rpc = (RPCWebEvent) event;
154            RPCMethodCall mc = rpc.getRPCMethodCall();
155            RPCParameter param = mc.getParameters()[0];
156            RPCStruct struct = (RPCStruct) param.getValue();
157            double minx = (Double) struct.getMember( Constants.RPC_BBOXMINX ).getValue();
158            double miny = (Double) struct.getMember( Constants.RPC_BBOXMINY ).getValue();
159            double maxx = (Double) struct.getMember( Constants.RPC_BBOXMAXX ).getValue();
160            double maxy = (Double) struct.getMember( Constants.RPC_BBOXMAXY ).getValue();
161            String crs = struct.getMember( CRS ).getValue().toString();
162            CoordinateSystem cs;
163            try {
164                cs = CRSFactory.create( crs );
165            } catch ( UnknownCRSException e1 ) {
166                gotoErrorPage( e1.getMessage() );
167                return;
168            }
169            Envelope actualBBox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, cs );
170            double mapWidth = (Double) struct.getMember( MAP_WIDTH ).getValue();
171            double mapHeight = (Double) struct.getMember( MAP_HEIGHT ).getValue();
172            String taskFromJSObject = struct.getMember( JS_TAK ).getValue().toString();
173            ServletRequest request = this.getRequest();
174    
175            try {
176    
177                double currentScaleValue = MapUtils.calcScale( (int) mapWidth, (int) mapHeight, actualBBox,
178                                                               actualBBox.getCoordinateSystem(), PIXEL_SIZE );
179    
180                if ( GET_NEW_BBOX.equals( taskFromJSObject ) ) {
181    
182                    String scaleRequestString = struct.getMember( REQUESTED_SCALE ).getValue().toString();
183    
184                    double requestedScale = Double.parseDouble( scaleRequestString.substring( 2,
185                                                                                              scaleRequestString.length() ) );
186    
187                    double savedScaleValue = (Double) struct.getMember( SAVED_SCALE ).getValue();
188                    Envelope newBbox = calcNewBBox( actualBBox, requestedScale, currentScaleValue, savedScaleValue );
189    
190                    double[] bbox = { newBbox.getMin().getX(), newBbox.getMin().getY(), newBbox.getMax().getX(),
191                                     newBbox.getMax().getY() };
192    
193                    Integer scaleValue = new Integer( (int) ( requestedScale ) );
194                    request.setAttribute( SCALE_VALUE, scaleValue );
195                    request.setAttribute( BBOX, bbox );
196                    request.setAttribute( TASK_FROM_LISTENER, NEW_BBOX );
197    
198                } else if ( GET_CURRENT_SCALE.equals( taskFromJSObject ) ) {
199    
200                    Integer scaleValue = new Integer( (int) currentScaleValue );
201                    request.setAttribute( SCALE_VALUE, scaleValue );
202                    request.setAttribute( TASK_FROM_LISTENER, NEW_SCALE_VALUE );
203    
204                } else {
205                    String message = "Unknown task from ScaleSwitcher module" + taskFromJSObject;
206                    throw new PortalException( message );
207                }
208            } catch ( PortalException e ) {
209                request.setAttribute( TASK_FROM_LISTENER, FULL_EXTENT );
210    
211            } catch ( Exception e ) {
212                e.printStackTrace();
213            }
214    
215        }
216    
217        /**
218         * The methode <code>calcNewBBox</code> calculates a new boundingbox for a requested scale. It will either zoom in
219         * or zoom out of the <code>actualBBOX<code> depending
220         * on the ratio of the <code>requestedScale</code> to the <code>actualScale</code>
221         *
222         * @param currentBBOX
223         * @param requestedScale
224         * @param currentScale
225         * @param savedScaleValue
226         * @return Envelope of the new BBox
227         * @throws Exception
228         */
229        private Envelope calcNewBBox( Envelope currentBBOX, double requestedScale, double currentScale,
230                                      double savedScaleValue )
231                                throws Exception {
232    
233            Envelope newBBox = null;
234            double ratio = requestedScale / currentScale;
235            // NaN ration will return a null Envelope
236            if ( Double.isNaN( ratio ) ) {
237                // FIXME when does this occurs? and how should this be handle?
238                throw new PortalException( "ratio is not a number" );
239            }
240    
241            if ( Double.isInfinite( ratio ) ) {// infinite ratio will return infinite Envelope
242                // the actualScale calculated was probably 0: use the saveScaleValue
243                if ( savedScaleValue > 1 ) {
244                    ratio = requestedScale / savedScaleValue;
245                }
246                if ( Double.isInfinite( ratio ) ) {
247                    throw new PortalException( "ratio is infinite" );
248                }
249            }
250            double newWidth = currentBBOX.getWidth() * ratio;
251            double newHeight = currentBBOX.getHeight() * ratio;
252            double midX = currentBBOX.getMin().getX() + ( currentBBOX.getWidth() / 2d );
253            double midY = currentBBOX.getMin().getY() + ( currentBBOX.getHeight() / 2d );
254            double minx = midX - newWidth / 2d;
255            double maxx = midX + newWidth / 2d;
256            double miny = midY - newHeight / 2d;
257            double maxy = midY + newHeight / 2d;
258            newBBox = GeometryFactory.createEnvelope( minx, miny, maxx, maxy, currentBBOX.getCoordinateSystem() );
259    
260            return newBBox;
261        }
262    
263    }