📄 encodekml.java
字号:
/* 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.Envelope;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.AttributeType;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureType;
import org.geotools.feature.GeometryAttributeType;
import org.geotools.filter.IllegalFilterException;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.image.ImageWorker;
import org.geotools.map.MapContext;
import org.geotools.map.MapLayer;
import org.geotools.referencing.CRS;
import org.geotools.renderer.lite.RendererUtilities;
import org.geotools.renderer.lite.StreamingRenderer;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.vfny.geoserver.wms.WMSMapContext;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.media.jai.GraphicsJAI;
/**
* @deprecated use {@link KMLTransformer}.
*/
public class EncodeKML {
/** Standard Logger */
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(
"org.vfny.geoserver.responses.wms.map.kml");
/** Filter factory for creating bounding box filters */
//private FilterFactory filterFactory = FilterFactoryFinder.createFilterFactory();
/** the XML and KML header */
private static final String KML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t"
+ "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n";
/** the KML closing element */
private static final String KML_FOOTER = "</kml>\n";
/**
* Map context document - layers, styles aoi etc.
*
* @uml.property name="mapContext"
* @uml.associationEnd multiplicity="(1 1)"
*/
private WMSMapContext mapContext;
/**
* Actualy writes the KML out
*
* @uml.property name="writer"
* @uml.associationEnd multiplicity="(0 1)"
*/
private KMLWriter writer;
/** Filter factory for creating bounding box filters */
private FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
/** Flag to be monotored by writer loops */
private boolean abortProcess;
/**
* Creates a new EncodeKML object.
*
* @param mapContext A full description of the map to be encoded.
*/
public EncodeKML(WMSMapContext mapContext) {
this.mapContext = mapContext;
}
/**
* Sets the abort flag. Active encoding may be halted, but this is not garanteed.
*/
public void abort() {
abortProcess = true;
}
/**
* Perform the actual encoding. May return early if abort it called.
*
* @param out Ouput stream to send the data to.
*
* @throws IOException Thrown if anything goes wrong whilst writing
*/
public void encodeKML(final OutputStream out) throws IOException {
this.writer = new KMLWriter(out, mapContext);
//once KML supports bbox queries against WMS this can be used to
//decimate the geometries based on zoom level.
//writer.setMinCoordDistance(env.getWidth() / 1000);
abortProcess = false;
long t = System.currentTimeMillis();
try {
writeHeader();
ArrayList layerRenderList = new ArrayList(); // not used in straight KML generation
writeLayers(false, layerRenderList);
writeFooter();
this.writer.flush();
t = System.currentTimeMillis() - t;
LOGGER.fine(new StringBuffer("KML generated, it took").append(t).append(" ms").toString());
} catch (IOException ioe) {
if (abortProcess) {
LOGGER.fine("KML encoding aborted");
return;
} else {
throw ioe;
}
} catch (AbortedException ex) {
return;
}
}
/**
* This method is used to encode kml + images and put all the stuff into a KMZ
* file.
*
* @param out the response is a Zipped output stream
* @throws IOException
*/
public void encodeKMZ(final ZipOutputStream out) throws IOException {
this.writer = new KMLWriter(out, mapContext);
abortProcess = false;
long t = System.currentTimeMillis();
try {
// first we produce the KML file containing the code and the PlaceMarks
final ZipEntry e = new ZipEntry("wms.kml");
out.putNextEntry(e);
writeHeader();
ArrayList layerRenderList = new ArrayList();
writeLayers(true, layerRenderList);
writeFooter();
this.writer.flush();
out.closeEntry();
// then we produce and store all the layer images
writeImages(out, layerRenderList);
t = System.currentTimeMillis() - t;
LOGGER.fine(new StringBuffer("KMZ generated, it took").append(t).append(" ms").toString());
} catch (IOException ioe) {
if (abortProcess) {
LOGGER.fine("KMZ encoding aborted");
return;
} else {
throw ioe;
}
} catch (AbortedException ex) {
return;
}
}
/**
* Determines whether to return a vector (KML) result of the data or to
* return an image instead.
* If the kmscore is 100, then the output should always be vector. If
* the kmscore is 0, it should always be raster. In between, the number of
* features is weighed against the kmscore value.
* kmscore determines whether to return the features as vectors, or as one
* raster image. It is the point, determined by the user, where X number of
* features is "too many" and the result should be returned as an image instead.
*
* kmscore is logarithmic. The higher the value, the more features it takes
* to make the algorithm return an image. The lower the kmscore, the fewer
* features it takes to force an image to be returned.
* (in use, the formula is exponential: as you increase the KMScore value,
* the number of features required increases exponentially).
*
* @param kmscore the score, between 0 and 100, use to determine what output to use
* @param numFeatures how many features are being rendered
* @return true: use just kml vectors, false: use raster result
*/
private boolean useVectorOutput(int kmscore, int numFeatures) {
if (kmscore == 100) {
return true; // vector KML
}
if (kmscore == 0) {
return false; // raster KMZ
}
// For numbers in between, determine exponentionally based on kmscore value:
// 10^(kmscore/15)
// This results in exponential growth.
// The lowest bound is 1 feature and the highest bound is 3.98 million features
// The most useful kmscore values are between 20 and 70 (21 and 46000 features respectively)
// A good default kmscore value is around 40 (464 features)
double magic = Math.pow(10, kmscore / 15);
if (numFeatures > magic) {
return false; // return raster
} else {
return true; // return vector
}
}
/**
* writes out standard KML header
*
* @throws IOException
*/
private void writeHeader() throws IOException {
writer.write(KML_HEADER);
}
/**
* writes out standard KML footer
*
* @throws IOException DOCUMENT ME!
*/
private void writeFooter() throws IOException {
writer.write(KML_FOOTER);
}
/**
* Processes each of the layers within the current mapContext in turn.
*
* writeLayers must be called before writeImages in order for the kmScore
* algorithm to work.
*
* @throws IOException
* @throws AbortedException
*
*/
private void writeLayers(final boolean kmz, ArrayList layerRenderList)
throws IOException, AbortedException {
MapLayer[] layers = mapContext.getLayers();
int nLayers = layers.length;
final int imageWidth = this.mapContext.getMapWidth();
final int imageHeight = this.mapContext.getMapHeight();
//final CoordinateReferenceSystem requestedCrs = mapContext.getCoordinateReferenceSystem();
//writer.setRequestedCRS(requestedCrs);
//writer.setScreenSize(new Rectangle(imageWidth, imageHeight));
if (nLayers > 1) { // if we have more than one layer, use the name "GeoServer" to group them
writer.startDocument("GeoServer", null);
}
for (int i = 0; i < nLayers; i++) { // for every layer specified in the request
MapLayer layer = layers[i];
writer.startDocument(layer.getTitle(), null);
//FeatureReader featureReader = null;
FeatureSource fSource = layer.getFeatureSource();
FeatureType schema = fSource.getSchema();
//GeometryAttributeType geometryAttribute = schema.getDefaultGeometry();
//CoordinateReferenceSystem sourceCrs = geometryAttribute.getCoordinateSystem();
Rectangle paintArea = new Rectangle(imageWidth, imageHeight);
AffineTransform worldToScreen = RendererUtilities.worldToScreenTransform(mapContext
.getAreaOfInterest(), paintArea);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -