⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kmlvectortransformer.java

📁 电子地图服务器,搭建自己的地图服务
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
 * This code is licensed under the GPL 2.0 license, availible at the root
 * application directory.
 */
package org.vfny.geoserver.wms.responses.map.kml;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineSegment;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import org.geoserver.ows.util.RequestUtils;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.FeatureType;
import org.geotools.feature.type.DateUtil;
import org.geotools.geometry.jts.JTS;
import org.geotools.map.MapLayer;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.renderer.style.LineStyle2D;
import org.geotools.renderer.style.MarkStyle2D;
import org.geotools.renderer.style.PolygonStyle2D;
import org.geotools.renderer.style.SLDStyleFactory;
import org.geotools.renderer.style.Style2D;
import org.geotools.renderer.style.TextStyle2D;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.geotools.styling.Symbolizer;
import org.geotools.styling.TextSymbolizer;
import org.geotools.util.Converters;
import org.geotools.util.NumberRange;
import org.geotools.xml.SimpleBinding;
import org.geotools.xml.transform.TransformerBase;
import org.geotools.xml.transform.Translator;
import org.geotools.xs.bindings.XSDateBinding;
import org.geotools.xs.bindings.XSDateTimeBinding;
import org.geotools.xs.bindings.XSTimeBinding;
import org.opengis.filter.Filter;
import org.opengis.filter.expression.Expression;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.vfny.geoserver.global.GeoServer;
import org.vfny.geoserver.wms.WMSMapContext;
import org.vfny.geoserver.wms.responses.featureInfo.FeatureTemplate;
import org.vfny.geoserver.wms.responses.featureInfo.FeatureTimeTemplate;
import org.vfny.geoserver.wms.responses.map.kml.KMLGeometryTransformer.KMLGeometryTranslator;
import org.xml.sax.ContentHandler;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * Transforms a feature collection to a kml document consisting of nested
 * "Style" and "Placemark" elements for each feature in the collection.
 * A new transfomer must be instantianted for each feature collection, 
 * the feature collection provided to the translator is supposed to be
 * the one coming out of the MapLayer 
 * <p>
 * Usage:
 * </p>
 * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
 *
 */
public class KMLVectorTransformer extends KMLTransformerBase {
    /**
     * logger
     */
    static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.kml");

    /**
     * Tolerance used to compare doubles for equality
     */
    static final double TOLERANCE = 1e-6;

    /**
     * The map context
     */
    protected final WMSMapContext mapContext;

    /**
     * The map layer being transformed
     */
    protected final MapLayer mapLayer;

    /**
     * The scale denominator.
     *
     * TODO: calcuate a real value based on image size to bbox ratio, as image
     * size has no meanining for KML yet this is a fudge.
     */
    double scaleDenominator = 1;
    NumberRange scaleRange = new NumberRange(scaleDenominator, scaleDenominator);

    /**
     * used to create 2d style objects for features
     */
    SLDStyleFactory styleFactory = new SLDStyleFactory();
    
    /**
     * Feature template, cached for performance reasons
     */
    FeatureTemplate template = new FeatureTemplate();
    
    /**
     * list of formats which correspond to the default formats in which 
     * freemarker outputs dates when a user calls the ?datetime(),?date(),?time()
     * fuctions. 
     */
    static List/*<SimpleDateFormat>*/ dtformats = new ArrayList();
    static List/*<SimpleDateFormat>*/ dformats = new ArrayList();
    static List/*<SimpleDateFormat>*/ tformats = new ArrayList();
    static {
        
        //add default freemarker ones first since they are likely to be used 
        // first, the order of this list matters.
        
        dtformats.add( FeatureTemplate.DATETIME_FORMAT );
        addFormats(dtformats,"dd%MM%yy hh:mm:ss" );
        addFormats(dtformats,"MM%dd%yy hh:mm:ss" );
        //addFormats(formats,"yy%MM%dd hh:mm:ss" );
        addFormats(dtformats,"dd%MMM%yy hh:mm:ss" );
        addFormats(dtformats,"MMM%dd%yy hh:mm:ss" );
        //addFormats(formats,"yy%MMM%dd hh:mm:ss" );
        
        addFormats(dtformats,"dd%MM%yy hh:mm" );
        addFormats(dtformats,"MM%dd%yy hh:mm" );
        //addFormats(formats,"yy%MM%dd hh:mm" );
        addFormats(dtformats,"dd%MMM%yy hh:mm" );
        addFormats(dtformats,"MMM%dd%yy hh:mm" );
        //addFormats(formats,"yy%MMM%dd hh:mm" );
        
        dformats.add( FeatureTemplate.DATE_FORMAT );
        addFormats(dformats,"dd%MM%yy" );
        addFormats(dformats,"MM%dd%yy" );
        //addFormats(formats,"yy%MM%dd" );
        addFormats(dformats,"dd%MMM%yy" );
        addFormats(dformats,"MMM%dd%yy" );
        //addFormats(formats,"yy%MMM%dd" );
         
        tformats.add( FeatureTemplate.TIME_FORMAT );
    }
    
    static void addFormats( List formats, String pattern ) {
        
        formats.add( new SimpleDateFormat( pattern.replaceAll("%","-" ) ) );
        formats.add( new SimpleDateFormat( pattern.replaceAll("%","/" ) ) );
        formats.add( new SimpleDateFormat( pattern.replaceAll("%","." ) ) );
        formats.add( new SimpleDateFormat( pattern.replaceAll("%"," " ) ) );
        formats.add( new SimpleDateFormat( pattern.replaceAll("%","," ) ) );
        
    }
    
    public KMLVectorTransformer(WMSMapContext mapContext, MapLayer mapLayer) {
        this.mapContext = mapContext;
        this.mapLayer = mapLayer;

        setNamespaceDeclarationEnabled(false);
    }

   /**
     * Sets the scale denominator.
     */
    public void setScaleDenominator(double scaleDenominator) {
        this.scaleDenominator = scaleDenominator;
    }

    public Translator createTranslator(ContentHandler handler) {
        return new KMLTranslator(handler);
    }

    protected class KMLTranslator extends KMLTranslatorSupport {
        /**
         * Geometry transformer
         */
        Translator geometryTranslator;

        public KMLTranslator(ContentHandler contentHandler) {
            super(contentHandler);

            KMLGeometryTransformer geometryTransformer = new KMLGeometryTransformer();
            //geometryTransformer.setUseDummyZ( true );
            geometryTransformer.setOmitXMLDeclaration(true);
            geometryTransformer.setNamespaceDeclarationEnabled(true);

            GeoServer config = mapContext.getRequest().getGeoServer();
            geometryTransformer.setNumDecimals(config.getNumDecimals());

            geometryTranslator = geometryTransformer.createTranslator(contentHandler);
        }

        public void encode(Object o) throws IllegalArgumentException {
            FeatureCollection features = (FeatureCollection) o;
            FeatureType featureType = features.getSchema();

            if (isStandAlone()) {
                start( "kml" );
            }

            //start the root document, name it the name of the layer
            start("Document");
            element("name", mapLayer.getTitle());

            //get the styles for hte layer
            FeatureTypeStyle[] featureTypeStyles = filterFeatureTypeStyles(mapLayer.getStyle(),
                    featureType);
            
            // encode the schemas (kml 2.2)
            encodeSchemas(features);

            // encode the layers
            encode(features, featureTypeStyles);
            
            //encode the legend
            //encodeLegendScreenOverlay();
            end("Document");
            
            if ( isStandAlone() ) {
                end( "kml" );
            }
        }

        /**
         * Encodes the <Schema> element in kml 2.2
         * @param featureTypeStyles
         */
        protected void encodeSchemas(FeatureCollection featureTypeStyles) {
            // the code is at the moment in KML3VectorTransformer
        }

        protected void encode(FeatureCollection features, FeatureTypeStyle[] styles) {
           //grab a feader and process
            FeatureIterator reader = features.features();

            try {
                while (reader.hasNext()) {
                    Feature feature = (Feature) reader.next();

                    try {
                        encode(feature, styles);
                    } catch (Throwable t) {
                        //TODO: perhaps rethrow hte exception
                        String msg = "Failure tranforming feature to KML:" + feature.getID();
                        LOGGER.log(Level.WARNING, msg, t);
                    }
                }
            } finally {
                //make sure we always close
                features.close(reader);
            }
        }

        protected void encode(Feature feature, FeatureTypeStyle[] styles) {
            //get the feature id
            String featureId = featureId(feature);

            //start the document
            //start("Document");

//            element("name", featureId);
//            element("title", mapLayer.getTitle());

            //encode the styles, keep track of any labels provided by the 
            // styles
            if ( encodeStyle(feature, styles) ) {
                encodePlacemark(feature,styles);    
            }
            

            //end("Document");
        }

        /**
         * Encodes the provided set of rules as KML styles.
         */
        protected boolean encodeStyle(Feature feature, FeatureTypeStyle[] styles) {
           
            //encode hte Line/Poly styles
            List symbolizerList = new ArrayList();
            for ( int j = 0; j < styles.length ; j++ ) {
               Rule[] rules = filterRules(styles[j], feature);
            	
                for (int i = 0; i < rules.length; i++) {
                    symbolizerList.addAll(Arrays.asList(rules[i].getSymbolizers()));
                }
            }
            
            if ( !symbolizerList.isEmpty() ) {
                //start the style
                start("Style",
                    KMLUtils.attributes(new String[] { "id", "GeoServerStyle" + feature.getID() }));

                //encode the icon
                encodeIconStyle(feature, styles);

                Symbolizer[] symbolizers = (Symbolizer[]) symbolizerList.toArray(new Symbolizer[symbolizerList.size()]);
                encodeStyle(feature, symbolizers);
                
                //end the style
                end("Style");
                
                //return true to specify that the feature has a style
                return true;
            }
            else {
                //dont encode
                return false;
            }

        }

        /**
         * Encodes an IconStyle for a feature.
         */
        protected void encodeIconStyle(Feature feature, FeatureTypeStyle[] styles ) {
            //encode the style for the icon
            //start IconStyle
            start("IconStyle");

            //make transparent if they didn't ask for attributes
            if (!mapContext.getRequest().getKMattr()) {
                encodeColor("00ffffff");
            }

            //figure out if line or polygon
            boolean line = feature.getDefaultGeometry() != null && 
                (feature.getDefaultGeometry() instanceof LineString
                    || feature.getDefaultGeometry() instanceof MultiLineString);
            boolean poly = feature.getDefaultGeometry() != null && 
            	(feature.getDefaultGeometry() instanceof Polygon
                    || feature.getDefaultGeometry() instanceof MultiPolygon);
            
            //if line or polygon scale the label
            if ( line ) {
            	element( "scale", "0.7");
            } else if ( poly ) {
                element( "scale", "1.4" );
            }
            //start Icon
            start("Icon");
            
            if ( line || poly ) {
            	String imageURL;
            	try {
            		URL requestURL = new URL(mapContext.getRequest().getBaseUrl());
            		imageURL = requestURL.getProtocol() + "://" + requestURL.getHost() + ":" + requestURL.getPort();
            		imageURL += "/geoserver/" + (poly ? "icon-poly.png" : "icon-line.png");
            	} catch (MalformedURLException mue){
            		imageURL = "http://maps.google.com/mapfiles/kml/pal3/icon61.png";
            	}
                element("href", imageURL); 
            }
            else {
                //do nothing, this is handled by encodePointStyle
            }
            
            end("Icon");

            //end IconStyle
            end("IconStyle");
            
        }
        /**
         * Encodes the provided set of symbolizers as KML styles.
         */
        protected void encodeStyle(Feature feature, Symbolizer[] symbolizers) {
            // look for line symbolizers, if there is any, we should tell the
            // polygon style to have an outline
            boolean forceOutline = false;
            for (int i = 0; i < symbolizers.length; i++) {
                if (symbolizers[i] instanceof LineSymbolizer) {
                    forceOutline = true;
                    break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -