Package org.vfny.geoserver.wms.responses.map.kml

Source Code of org.vfny.geoserver.wms.responses.map.kml.KMLNetworkLinkTransformer

package org.vfny.geoserver.wms.responses.map.kml;

import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;

import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.util.WMSRequests;
import org.geotools.styling.Style;
import org.geotools.xml.transform.TransformerBase;
import org.geotools.xml.transform.Translator;
import org.vfny.geoserver.wms.requests.GetMapRequest;
import org.xml.sax.ContentHandler;

import com.vividsolutions.jts.geom.Envelope;

/**
* Encodes a KML document contianing a network link.
* <p>
* This transformer transforms a {@link GetMapRequest} object.
* </p>
*
* @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
*
*/
public class KMLNetworkLinkTransformer extends TransformerBase {

    /**
     * logger
     */
    static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.kml");
   
    /**
     * flag controlling wether the network link should be a super overlay.
     */
    boolean encodeAsRegion = false;
    public Translator createTranslator(ContentHandler handler) {
        return new KMLNetworkLinkTranslator( handler );
    }
   
    public void setEncodeAsRegion(boolean encodeAsRegion) {
        this.encodeAsRegion = encodeAsRegion;
    }
   
    class KMLNetworkLinkTranslator extends TranslatorSupport {

        public KMLNetworkLinkTranslator(ContentHandler contentHandler) {
            super(contentHandler, null,null);
        }
       
        public void encode(Object o) throws IllegalArgumentException {
            GetMapRequest request = (GetMapRequest) o;
           
            start( "kml" );
            start( "Folder" );
       
            if ( encodeAsRegion ) {
                encodeAsSuperOverlay( request );
            }
            else {
                encodeAsOverlay( request );
            }
           
            //look at
            encodeLookAt( request );
           
            end( "Folder" );
            end( "kml" );
        }
       
        protected void encodeAsSuperOverlay( GetMapRequest request ) {
            MapLayerInfo[] layers = request.getLayers();
            List<Style> styles = request.getStyles();
            for ( int i = 0; i < layers.length; i++ ) {
                start("NetworkLink");
                element( "name", layers[i].getName() );
                element( "open", "1" );
                element( "visibility", "1" );
            
                //region
                start( "Region" );
               
                Envelope bbox = request.getBbox();
                start( "LatLonAltBox" );
                element( "north", ""+bbox.getMaxY() );
                element( "south", ""+bbox.getMinY() );
                element( "east", ""+bbox.getMaxX() );
                element( "west", ""+bbox.getMinX() );
                end( "LatLonAltBox");
               
                start( "Lod" );
                element( "minLodPixels", "128" );
                element( "maxLodPixels", "-1" );
                end( "Lod" );
               
                end( "Region" );
               
                //link
                start("Link" );
 
                String style = i < styles.size()? styles.get(i).getName() : null;
                String href = WMSRequests.getGetMapUrl(request, layers[i].getName(), i, style, null, null);
                start( "href" );
                cdata( href );
                end( "href" );
               
//                element( "viewRefreshMode", "onRegion" );
                end( "Link" );
               
                end( "NetworkLink");
            }
        }
       
        protected void encodeAsOverlay( GetMapRequest request ) {
            MapLayerInfo[] layers = request.getLayers();
            List<Style> styles = request.getStyles();
            for ( int i = 0; i < layers.length; i++ ) {
                start("NetworkLink");
                element( "name", layers[i].getName() );
                element( "open", "1" );
                element( "visibility", "1" );
               
                start( "Url" );
               
                //set bbox to null so its not included in the request, google
                // earth will append it for us
                request.setBbox(null);
               
                String style = i < styles.size()? styles.get(i).getName() : null;
                String href = WMSRequests.getGetMapUrl(request, layers[i].getName(), i, style, null, null);
                start( "href" );
                cdata( href );
                end( "href" );
               
                element( "viewRefreshMode", "onStop" );
                element( "viewRefreshTime", "1" );
                end( "Url" );
               
                end( "NetworkLink" );
            }
        }
       
        private void encodeLookAt(GetMapRequest request){
           
            Envelope e = new Envelope();
            e.setToNull();
           
            for ( int i = 0; i < request.getLayers().length; i++ ) {
                MapLayerInfo layer = request.getLayers()[i];
               
                Envelope b = null;
                try {
                    b = request.getLayers()[i].getLatLongBoundingBox();
                } catch (IOException e1) {
                    LOGGER.warning( "Unable to calculate bounds for " + layer.getName() );
                    continue;
                }
                if ( e.isNull() ) {
                    e.init( b );
                }
                else {
                    e.expandToInclude( b );
                }
            }
           
            if ( e.isNull() ) {
                return;
            }
           
            double lon1 = e.getMinX();
            double lat1 = e.getMinY();
            double lon2 = e.getMaxX();
            double lat2 = e.getMaxY();
           
            double R_EARTH = 6.371 * 1000000; // meters
            double VIEWER_WIDTH = 22 * Math.PI / 180; // The field of view of the google maps camera, in radians
            double[] p1 = getRect(lon1, lat1, R_EARTH);
            double[] p2 = getRect(lon2, lat2, R_EARTH);
            double[] midpoint = new double[]{
              (p1[0] + p2[0])/2,
                (p1[1] + p2[1])/2,
                (p1[2] + p2[2])/2
            };
           
            midpoint = getGeographic(midpoint[0], midpoint[1], midpoint[2]);
           
            double distance = distance(p1, p2);
           
            double height = distance/ (2 * Math.tan(VIEWER_WIDTH));
           
            LOGGER.fine("lat1: " + lat1 + "; lon1: " + lon1);
            LOGGER.fine("lat2: " + lat2 + "; lon2: " + lon2);
            LOGGER.fine("latmid: " + midpoint[1] + "; lonmid: " + midpoint[0]);
           
           
            start( "LookAt" );
            element( "longitude", ""+midpoint[0] );
            element( "latitude", "" +midpoint[1] );
            element( "altitude", "0" );
            element( "range", ""+ distance );
            element( "tilt", "0" );
            element( "heading", "0" );
            element( "altitudeMode", "clampToGround" );
            end( "LookAt" );
          }
         
          private double[] getRect(double lat, double lon, double radius){
            double theta = (90 - lat) * Math.PI/180;
            double phi   = (90 - lon) * Math.PI/180;
           
            double x = radius * Math.sin(phi) * Math.cos(theta);
            double y = radius * Math.sin(phi) * Math.sin(theta);
            double z = radius * Math.cos(phi);
            return new double[]{x, y, z};
          }
         
          private double[] getGeographic(double x, double y, double z){
            double theta, phi, radius;
            radius = distance(new double[]{x, y, z}, new double[]{0,0,0});
            theta = Math.atan2(Math.sqrt(x * x + y * y) , z);
            phi = Math.atan2(y , x);
           
            double lat = 90 - (theta * 180 / Math.PI);
            double lon = 90 - (phi * 180 / Math.PI);
           
            return new double[]{(lon > 180 ? lon - 360 : lon), lat, radius};
          }
         
          private double distance(double[] p1, double[] p2){
            double dx = p1[0] - p2[0];
            double dy = p1[1] - p2[1];
            double dz = p1[2] - p2[2];
            return Math.sqrt(dx * dx + dy * dy + dz * dz);
          }
    }
}
TOP

Related Classes of org.vfny.geoserver.wms.responses.map.kml.KMLNetworkLinkTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.