/* * Adds a feature layer to the geopackage. */ void addFeatureLayer( GeoPackage geopkg, FeatureLayer layer, MapLayerInfo mapLayer, WMSMapContent map) throws IOException { FeatureEntry e = new FeatureEntry(); initEntry(e, layer, mapLayer, map); Filter filter = layer.getQuery().getFilter(); GeometryDescriptor gd = mapLayer.getFeature().getFeatureType().getGeometryDescriptor(); if (gd != null) { Envelope bnds = bounds(map); BBOX bboxFilter = filterFactory.bbox( gd.getLocalName(), bnds.getMinX(), bnds.getMinY(), bnds.getMaxX(), bnds.getMaxY(), map.getRequest().getSRS()); filter = filterFactory.and(filter, bboxFilter); } LOGGER.fine("Creating feature entry" + e.getTableName()); geopkg.add(e, layer.getSimpleFeatureSource(), filter); }
/** * Encodes the url of a GetMap request from a map context + map layer. * * <p>If the <tt>Layer</tt> argument is <code>null</code>, the request is made including all * layers in the <tt>mapContexT</tt>. * * <p>If the <tt>bbox</tt> argument is <code>null</code>. {@link * WMSMapContent#getAreaOfInterest()} is used for the bbox parameter. * * @param mapContent The map context. * @param layer The Map layer, may be <code>null</code>. * @param layerIndex The index of the layer in the request. * @param bbox The bounding box of the request, may be <code>null</code>. * @param kvp Additional or overiding kvp parameters, may be <code>null</code> * @param tile Flag controlling whether the request should be made against tile cache * @param geoserver * @return The full url for a getMap request. * @deprecated use {@link WMSRequests#getGetMapUrl(WMSMapContent, Layer, Envelope, String[])} */ public static String getMapUrl( WMSMapContent mapContent, Layer layer, int layerIndex, Envelope bbox, String[] kvp, boolean tile, GeoServer geoserver) { if (tile) { org.geoserver.wms.GetMapRequest request = mapContent.getRequest(); return WMSRequests.getTiledGetMapUrl(geoserver, request, layer, layerIndex, bbox, kvp); } return WMSRequests.getGetMapUrl(mapContent.getRequest(), layer, layerIndex, bbox, kvp); }
String findBestFormat(WMSMapContent map) { // if request is a single coverage layer return jpeg, otherwise use just png List<MapLayerInfo> layers = map.getRequest().getLayers(); if (layers.size() == 1 && layers.get(0).getType() == MapLayerInfo.TYPE_RASTER) { return JPEG_MIME_TYPE; } return PNG_MIME_TYPE; }
/** * Creates the {@link RenderedImage} corresponding to the tile at index {@code tileIdx} and uses a * {@link RenderedImageMapResponse} to encode it into the {@link #getResponseFormat() response * format}. * * @see org.geowebcache.layer.MetaTile#writeTileToStream(int, org.geowebcache.io.Resource) * @see RenderedImageMapResponse#write */ @Override public boolean writeTileToStream(final int tileIdx, Resource target) throws IOException { checkNotNull(metaTileMap, "webMap is not set"); if (!(metaTileMap instanceof RenderedImageMap)) { throw new IllegalArgumentException( "Only RenderedImageMaps are supported so far: " + metaTileMap.getClass().getName()); } final RenderedImageMapResponse mapEncoder; { final GWC mediator = GWC.get(); final Response responseEncoder = mediator.getResponseEncoder(responseFormat, metaTileMap); mapEncoder = (RenderedImageMapResponse) responseEncoder; } RenderedImage tile = metaTileMap.getImage(); WMSMapContent tileContext = metaTileMap.getMapContext(); if (this.tiles.length > 1 || (this.tiles.length == 1 && metaHasGutter())) { final Rectangle tileDim = this.tiles[tileIdx]; tile = createTile(tileDim.x, tileDim.y, tileDim.width, tileDim.height); disposeLater(tile); { final WMSMapContent metaTileContext = metaTileMap.getMapContext(); // do not create tileContext with metaTileContext.getLayers() as the layer list. // It is not needed at this stage and the constructor would force a // MapLayer.getBounds() that might fail tileContext = new WMSMapContent(); tileContext.setRequest(metaTileContext.getRequest()); tileContext.setBgColor(metaTileContext.getBgColor()); tileContext.setMapWidth(tileDim.width); tileContext.setMapHeight(tileDim.height); tileContext.setPalette(metaTileContext.getPalette()); tileContext.setTransparent(tileContext.isTransparent()); long[][] tileIndexes = getTilesGridPositions(); BoundingBox tileBounds = gridSubset.boundsFromIndex(tileIndexes[tileIdx]); ReferencedEnvelope tilebbox = new ReferencedEnvelope(metaTileContext.getCoordinateReferenceSystem()); tilebbox.init( tileBounds.getMinX(), tileBounds.getMaxX(), tileBounds.getMinY(), tileBounds.getMaxY()); tileContext.getViewport().setBounds(tilebbox); } } OutputStream outStream = target.getOutputStream(); try { // call formatImageOuputStream instead of write to avoid disposition of rendered images // when processing a tile from a metatile and instead defer it to this class' dispose() // method mapEncoder.formatImageOutputStream(tile, outStream, tileContext); return true; } finally { outStream.close(); } }
/** * Returns true if the request is GWC compatible * * @param mapContent * @return */ public static boolean isRequestGWCCompatible(WMSMapContent mapContent, Layer layer, WMS wms) { List<Layer> layers = mapContent.layers(); for (int i = 0; i < layers.size(); i++) { if (layers.get(i) == layer) { return isRequestGWCCompatible(mapContent.getRequest(), i, wms); } } LOGGER.warning("Could not find map layer " + layer.getTitle() + " in the map context"); return false; }
public KMLGeometryTranslator( ContentHandler handler, int numDecimals, boolean useDummyZ, WMSMapContent context) { // super(handler, "kml", "http://earth.google.com/kml/2.0" ); super(handler, null, null, numDecimals, useDummyZ, 3); coordWriter = new KMLCoordinateWriter(numDecimals, useDummyZ); String extrudeValue = (String) context.getRequest().getFormatOptions().get("extrude"); if (extrudeValue != null) { extrude = Boolean.valueOf(extrudeValue).booleanValue(); } String requestedAltitudeMode = (String) context.getRequest().getFormatOptions().get("altitudeMode"); if (requestedAltitudeMode != null) { for (String mode : validAltitudeModes) { if (mode.equalsIgnoreCase(requestedAltitudeMode.trim())) { altitudeMode = mode; } } } }
Integer srid(WMSMapContent map) { Integer srid = null; try { srid = CRS.lookupEpsgCode(map.getCoordinateReferenceSystem(), false); if (srid == null) { srid = Integer.parseInt(map.getRequest().getSRS().split(":")[1]); } } catch (Exception ex) { LOGGER.log(Level.WARNING, "Error determining srid", ex); } return srid; }
int[] findMinMaxZoom(GridSubset gridSubset, WMSMapContent map) { GridSet gridSet = gridSubset.getGridSet(); Map formatOpts = map.getRequest().getFormatOptions(); Integer minZoom = null; if (formatOpts.containsKey("min_zoom")) { minZoom = Integer.parseInt(formatOpts.get("min_zoom").toString()); } if (minZoom == null) { minZoom = findClosestZoom(gridSet, map); } Integer maxZoom = null; if (formatOpts.containsKey("max_zoom")) { maxZoom = Integer.parseInt(formatOpts.get("max_zoom").toString()); } else if (formatOpts.containsKey("num_zooms")) { maxZoom = minZoom + Integer.parseInt(formatOpts.get("num_zooms").toString()); } if (maxZoom == null) { // walk down until we hit too many tiles maxZoom = findMaxZoomAuto(gridSubset, minZoom, map); } if (maxZoom < minZoom) { throw new ServiceException( format("maxZoom (%d) can not be less than minZoom (%d)", maxZoom, minZoom)); } // end index if (maxZoom > gridSet.getNumLevels()) { LOGGER.warning( format( "Max zoom (%d) can't be greater than number of zoom levels (%d)", maxZoom, gridSet.getNumLevels())); maxZoom = gridSet.getNumLevels(); } return new int[] {minZoom, maxZoom}; }
/** * Loads the feature collection based on the current styling and the scale denominator. If no * feature is going to be returned a null feature collection will be returned instead * * @param featureSource * @param layer * @param mapContent * @param wms * @param scaleDenominator * @return * @throws Exception */ public static SimpleFeatureCollection loadFeatureCollection( SimpleFeatureSource featureSource, Layer layer, WMSMapContent mapContent, WMS wms, double scaleDenominator) throws Exception { SimpleFeatureType schema = featureSource.getSchema(); Envelope envelope = mapContent.getRenderingArea(); ReferencedEnvelope aoi = new ReferencedEnvelope(envelope, mapContent.getCoordinateReferenceSystem()); CoordinateReferenceSystem sourceCrs = schema.getCoordinateReferenceSystem(); boolean reprojectBBox = (sourceCrs != null) && !CRS.equalsIgnoreMetadata(aoi.getCoordinateReferenceSystem(), sourceCrs); if (reprojectBBox) { aoi = aoi.transform(sourceCrs, true); } Filter filter = createBBoxFilter(schema, aoi); // now build the query using only the attributes and the bounding // box needed Query q = new Query(schema.getTypeName()); q.setFilter(filter); // now, if a definition query has been established for this layer, // be sure to respect it by combining it with the bounding box one. Query definitionQuery = layer.getQuery(); if (definitionQuery != Query.ALL) { if (q == Query.ALL) { q = (Query) definitionQuery; } else { q = (Query) DataUtilities.mixQueries(definitionQuery, q, "KMLEncoder"); } } // handle startIndex requested by client query q.setStartIndex(definitionQuery.getStartIndex()); // check the regionating strategy RegionatingStrategy regionatingStrategy = null; String stratname = (String) mapContent.getRequest().getFormatOptions().get("regionateBy"); if (("auto").equals(stratname)) { Catalog catalog = wms.getGeoServer().getCatalog(); Name name = layer.getFeatureSource().getName(); stratname = catalog .getFeatureTypeByName(name) .getMetadata() .get("kml.regionateStrategy", String.class); if (stratname == null || "".equals(stratname)) { stratname = "best_guess"; LOGGER.log( Level.FINE, "No default regionating strategy has been configured in " + name + "; using automatic best-guess strategy."); } } if (stratname != null) { regionatingStrategy = findStrategyByName(stratname); // if a strategy was specified but we did not find it, let the user // know if (regionatingStrategy == null) throw new ServiceException("Unknown regionating strategy " + stratname); } // try to load less features by leveraging regionating strategy and the // SLD Filter regionatingFilter = Filter.INCLUDE; if (regionatingStrategy != null) regionatingFilter = regionatingStrategy.getFilter(mapContent, layer); Filter ruleFilter = summarizeRuleFilters( getLayerRules(featureSource.getSchema(), layer.getStyle()), scaleDenominator); Filter finalFilter = joinFilters(q.getFilter(), ruleFilter, regionatingFilter); if (finalFilter == Filter.EXCLUDE) { // if we don't have any feature to return return null; } q.setFilter(finalFilter); // make sure we output in 4326 since that's what KML mandates CoordinateReferenceSystem wgs84; try { wgs84 = CRS.decode("EPSG:4326"); } catch (Exception e) { throw new RuntimeException( "Cannot decode EPSG:4326, the CRS subsystem must be badly broken..."); } if (sourceCrs != null && !CRS.equalsIgnoreMetadata(wgs84, sourceCrs)) { return new ReprojectFeatureResults(featureSource.getFeatures(q), wgs84); } return featureSource.getFeatures(q); }
/** * Encodes the url for a GetLegendGraphic request from a map context + map layer. * * @param mapContent The map context. * @param layer The map layer. * @param kvp Additional or overidding kvp parameters, may be <code>null</code> * * @return A map containing all the key value pairs for a GetLegendGraphic request. * @deprecated use {@link WMSRequests#getGetLegendGraphicUrl(WMSMapContent, Layer, String[]) */ public static String getLegendGraphicUrl(WMSMapContent mapContent, Layer layer, String[] kvp) { return WMSRequests.getGetLegendGraphicUrl(mapContent.getRequest(), layer, kvp); }
GridSubset findBestGridSubset(WMSMapContent map) { GetMapRequest req = map.getRequest(); Map formatOpts = req.getFormatOptions(); GridSetBroker gridSetBroker = gwc.getGridSetBroker(); GridSet gridSet = null; // first check format options to see if explicitly specified if (formatOpts.containsKey("gridset")) { gridSet = gridSetBroker.get(formatOpts.get("gridset").toString()); } // next check srs if (gridSet == null) { gridSet = gridSetBroker.get(req.getSRS().toUpperCase()); } if (gridSet != null) { return GridSubsetFactory.createGridSubSet(gridSet); } CoordinateReferenceSystem crs = map.getCoordinateReferenceSystem(); // look up epsg code Integer epsgCode = null; try { epsgCode = CRS.lookupEpsgCode(crs, false); } catch (Exception e) { throw new ServiceException("Unable to determine epsg code for " + crs, e); } if (epsgCode == null) { throw new ServiceException("Unable to determine epsg code for " + crs); } SRS srs = SRS.getSRS(epsgCode); // figure out the appropriate grid sub set Set<GridSubset> gridSubsets = new LinkedHashSet<GridSubset>(); for (MapLayerInfo l : req.getLayers()) { TileLayer tl = gwc.getTileLayerByName(l.getName()); if (tl == null) { throw new ServiceException("No tile layer for " + l.getName()); } List<GridSubset> theseGridSubsets = tl.getGridSubsetsForSRS(srs); if (gridSubsets.isEmpty()) { gridSubsets.addAll(theseGridSubsets); } else { gridSubsets.retainAll(theseGridSubsets); } if (gridSubsets.isEmpty()) { throw new ServiceException( "No suitable " + epsgCode + " grid subset for " + req.getLayers()); } } if (gridSubsets.size() > 1) { if (LOGGER.isLoggable(Level.WARNING)) { StringBuilder msg = new StringBuilder("Found multiple grid subsets: "); for (GridSubset gs : gridSubsets) { msg.append(gs.getName()).append(", "); } msg.setLength(msg.length() - 2); msg.append(". Choosing first."); LOGGER.warning(msg.toString()); } } return gridSubsets.iterator().next(); }
ReferencedEnvelope bounds(WMSMapContent map) { return new ReferencedEnvelope(map.getRequest().getBbox(), map.getCoordinateReferenceSystem()); }
void addTileLayers(GeoPackage geopkg, List<MapLayerInfo> mapLayers, WMSMapContent map) throws IOException { if (mapLayers.isEmpty()) { return; } // figure out a name for the file entry String tileEntryName = null; Map formatOpts = map.getRequest().getFormatOptions(); if (formatOpts.containsKey("tileset_name")) { tileEntryName = (String) formatOpts.get("tileset_name"); } if (tileEntryName == null) { tileEntryName = map.getTitle(); } if (tileEntryName == null && mapLayers.size() == 1) { Iterator<MapLayerInfo> it = mapLayers.iterator(); tileEntryName = it.next().getLayerInfo().getName(); } GridSubset gridSubset = findBestGridSubset(map); int[] minmax = findMinMaxZoom(gridSubset, map); BoundingBox bbox = bbox(map); TileEntry e = new TileEntry(); e.setTableName(tileEntryName); if (mapLayers.size() == 1) { ResourceInfo r = mapLayers.get(0).getResource(); e.setIdentifier(r.getTitle()); e.setDescription(r.getAbstract()); } e.setBounds( new ReferencedEnvelope( findTileBounds(gridSubset, bbox, minmax[0]), map.getCoordinateReferenceSystem())); e.setSrid(srid(map)); GridSet gridSet = gridSubset.getGridSet(); for (int z = minmax[0]; z < minmax[1]; z++) { Grid g = gridSet.getGrid(z); TileMatrix m = new TileMatrix(); m.setZoomLevel(z); m.setMatrixWidth((int) g.getNumTilesWide()); m.setMatrixHeight((int) g.getNumTilesHigh()); m.setTileWidth(gridSubset.getTileWidth()); m.setTileHeight(gridSubset.getTileHeight()); // TODO: not sure about this m.setXPixelSize(g.getResolution()); m.setYPixelSize(g.getResolution()); // m.setXPixelSize(gridSet.getPixelSize()); // m.setYPixelSize(gridSet.getPixelSize()); e.getTileMatricies().add(m); } // figure out the actual bounds of the tiles to be renderered LOGGER.fine("Creating tile entry" + e.getTableName()); geopkg.create(e); // create a prototype getmap request GetMapRequest req = new GetMapRequest(); OwsUtils.copy(map.getRequest(), req, GetMapRequest.class); req.setLayers(mapLayers); String imageFormat = formatOpts.containsKey("format") ? parseFormatFromOpts(formatOpts) : findBestFormat(map); req.setFormat(imageFormat); req.setWidth(gridSubset.getTileWidth()); req.setHeight(gridSubset.getTileHeight()); // count tiles as we generate them int ntiles = 0; // flag determining if tile row indexes we store in database should be inverted boolean flipy = Boolean.valueOf((String) formatOpts.get("flipy")); for (int z = minmax[0]; z < minmax[1]; z++) { long[] intersect = gridSubset.getCoverageIntersection(z, bbox); for (long x = intersect[0]; x <= intersect[2]; x++) { for (long y = intersect[1]; y <= intersect[3]; y++) { BoundingBox box = gridSubset.boundsFromIndex(new long[] {x, y, z}); req.setBbox(new Envelope(box.getMinX(), box.getMaxX(), box.getMinY(), box.getMaxY())); Tile t = new Tile(); t.setZoom(z); t.setColumn((int) x); t.setRow((int) (flipy ? gridSubset.getNumTilesHigh(z) - (y + 1) : y)); WebMap result = webMapService.getMap(req); t.setData(toBytes(result)); geopkg.add(e, t); // images we encode are actually kept around, we need to clean them up if (ntiles++ == TILE_CLEANUP_INTERVAL) { cleanUpImages(); ntiles = 0; } } } } }
@Override public WebMap produceMap(WMSMapContent map) throws ServiceException, IOException { GeoPackage geopkg = new GeoPackage(); geopkg.init(); GetMapRequest req = map.getRequest(); List<Layer> layers = map.layers(); List<MapLayerInfo> mapLayers = req.getLayers(); Preconditions.checkState( layers.size() == mapLayers.size(), "Number of map layers not same as number of rendered layers"); // list of layers to render directly and include as tiles List<MapLayerInfo> tileLayers = new ArrayList(); // check mode, one of: // vector - render vector layers as feature entries and all else as tiles (default) // hybrid - render vector layers as feature entries, raster layers as raster entries, all // others as tile entries // tiled - all layers as a single tile set Map formatOpts = req.getFormatOptions(); Mode mode = formatOpts.containsKey("mode") ? Mode.valueOf(((String) formatOpts.get("mode")).toUpperCase()) : Mode.VECTOR; if (mode == Mode.TILED) { // tiled mode means render all as map tile layer tileLayers.addAll(mapLayers); } else { // hybrid mode, dump as raw vector or raster unless the request specifically asks for a // layer to be rendered as tiles for (int i = 0; i < layers.size(); i++) { Layer layer = layers.get(i); MapLayerInfo mapLayer = mapLayers.get(i); if (layer instanceof FeatureLayer) { addFeatureLayer(geopkg, (FeatureLayer) layer, mapLayer, map); } else if (layer instanceof GridCoverageLayer) { if (mode == Mode.HYBRID) { addCoverageLayer(geopkg, (GridCoverageLayer) layer, mapLayer, map); } else { tileLayers.add(mapLayer); } } else { tileLayers.add(mapLayer); } } } addTileLayers(geopkg, tileLayers, map); geopkg.close(); final File dbFile = geopkg.getFile(); final BufferedInputStream bin = new BufferedInputStream(new FileInputStream(dbFile)); RawMap result = new RawMap(map, bin, MIME_TYPE) { @Override public void writeTo(OutputStream out) throws IOException { String dbFilename = getAttachmentFileName(); if (dbFilename != null) { dbFilename = dbFilename.substring(0, dbFilename.length() - 4) + ".gpkg"; } else { // this shouldn't really ever happen, but fallback anyways dbFilename = "geoserver.gpkg"; } IOUtils.copy(bin, out); out.flush(); // JD: disabling zip compression for now // ZipOutputStream zout = new ZipOutputStream(out); // zout.putNextEntry(new ZipEntry(dbFilename)); // // super.writeTo(zout); // zout.closeEntry(); // zout.close(); bin.close(); try { dbFile.delete(); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error deleting file: " + dbFile.getAbsolutePath(), e); } } }; result.setContentDispositionHeader(map, ".gpkg", true); return result; }