Package org.geoserver.kml.decorator

Source Code of org.geoserver.kml.decorator.LookAtDecoratorFactory

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.kml.decorator;

import org.geoserver.kml.KmlEncodingContext;
import org.geoserver.kml.utils.LookAtOptions;
import org.geoserver.wms.WMSInfo;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;

import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.LookAt;
import de.micromata.opengis.kml.v_2_2_0.NetworkLink;
import de.micromata.opengis.kml.v_2_2_0.Placemark;

/**
* Adds LookAt elements on Document, Folder and Placemark
*
* @author Andrea Aime - GeoSolutions
*/
public class LookAtDecoratorFactory implements KmlDecoratorFactory {

    @Override
    public KmlDecorator getDecorator(Class<? extends Feature> featureClass,
            KmlEncodingContext context) {
        // this decorator makes sense only for WMS
        if(!(context.getService() instanceof WMSInfo)) {
            return null;
        }
       
        if (Placemark.class.isAssignableFrom(featureClass)) {
            return new PlacemarkLookAtDecorator();
        } else if (Folder.class.isAssignableFrom(featureClass) || NetworkLink.class.isAssignableFrom(featureClass)) {
            return new LayerLookAtDecorator();
        } else if (Document.class.isAssignableFrom(featureClass)) {
            return new DocumentLookAtDecorator();
        } else {
            return null;
        }
    }

    class DocumentLookAtDecorator implements KmlDecorator {

        @Override
        public Feature decorate(Feature feature, KmlEncodingContext context) {
            Document document = (Document) feature;
            Envelope bounds = context.getMapContent().getRenderingArea();
            LookAt lookAt = buildLookAt(bounds, context.getLookAtOptions(), false);
            document.setAbstractView(lookAt);

            return document;

        }

    }

    class LayerLookAtDecorator implements KmlDecorator {

        @Override
        public Feature decorate(Feature feature, KmlEncodingContext context) {
            Envelope bounds = context.getCurrentLayer().getBounds();
            LookAt lookAt = buildLookAt(bounds, context.getLookAtOptions(), false);
            feature.setAbstractView(lookAt);

            return feature;
        }

    }

    class PlacemarkLookAtDecorator implements KmlDecorator {

        @Override
        public Feature decorate(Feature feature, KmlEncodingContext context) {
            Placemark pm = (Placemark) feature;
            Geometry geometry = (Geometry) context.getCurrentFeature().getDefaultGeometry();
            Envelope bounds = null;
            if (geometry != null) {
                bounds = geometry.getEnvelopeInternal();
            }
            LookAt lookAt = buildLookAt(bounds, context.getLookAtOptions(), true);
            pm.setAbstractView(lookAt);

            return pm;
        }

    }

    public LookAt buildLookAt(Envelope bounds, LookAtOptions options, boolean forceBounds) {
        // get/build the target envelope
        Envelope lookAtEnvelope = bounds;
        Geometry lookAtGeometry = options.getLookAt();
        if (!forceBounds && lookAtGeometry != null) {
            lookAtEnvelope = lookAtGeometry.getEnvelopeInternal();
        }

        if (lookAtEnvelope == null || lookAtEnvelope.isNull()) {
            return null;
        }

        // compute the lookAt details
        double lon1 = lookAtEnvelope.getMinX();
        double lat1 = lookAtEnvelope.getMinY();
        double lon2 = lookAtEnvelope.getMaxX();
        double lat2 = lookAtEnvelope.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 = options.getRange();
        if (null == distance) {
            distance = distance(p1, p2);
        }
        double height = distance / (2 * Math.tan(VIEWER_WIDTH));

        final Double tilt = options.getTilt() == null ? Double.valueOf(0) : options.getTilt();
        final Double heading = options.getHeading() == null ? Double.valueOf(0) : options
                .getHeading();
        final Double altitude = options.getAltitude() == null ? Double.valueOf(height) : options
                .getAltitude();

        // build the lookat
        LookAt lookAt = new LookAt();
        lookAt.setLongitude(midpoint[0]);
        lookAt.setLatitude(midpoint[1]);
        lookAt.setAltitude(altitude);
        lookAt.setRange(distance);
        lookAt.setTilt(tilt);
        lookAt.setHeading(heading);
        lookAt.setAltitudeMode(options.getAltitudeMode());

        return 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.geoserver.kml.decorator.LookAtDecoratorFactory

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.