/** * OrbisGIS is a java GIS application dedicated to research in GIScience. * OrbisGIS is developed by the GIS group of the DECIDE team of the * Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>. * * The GIS group of the DECIDE team is located at : * * Laboratoire Lab-STICC – CNRS UMR 6285 * Equipe DECIDE * UNIVERSITÉ DE BRETAGNE-SUD * Institut Universitaire de Technologie de Vannes * 8, Rue Montaigne - BP 561 56017 Vannes Cedex * * OrbisGIS is distributed under GPL 3 license. * * Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488) * Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285) * * This file is part of OrbisGIS. * * OrbisGIS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * OrbisGIS is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * OrbisGIS. If not, see <http://www.gnu.org/licenses/>. * * For more information, please consult: <http://www.orbisgis.org/> * or contact directly: * info_at_ orbisgis.org */ // Changed by Uwe Dalluege, uwe.dalluege@rzcn.haw-hamburg.de // to differ between LatLonBoundingBox and BoundingBox // 2005-07-29 package com.vividsolutions.wms; import java.util.*; import com.vividsolutions.jts.geom.Envelope; /** * Represents a WMS Layer. * * @author Chris Hodgson chodgson@refractions.net * @author Uwe Dalluege, uwe.dalluege@rzcn.haw-hamburg.de * @author Michael Michaud michael.michaud@free.fr */ public class MapLayer { // immutable members private MapLayer parent; private String name; private String title; private ArrayList<String> srsList; private ArrayList<MapLayer> subLayers; // Default bounding box in geographic coordinates private BoundingBox bbox; private Map<String,BoundingBox> boundingBoxMap; // user modifiable members private boolean enabled = false; /** * * Creates a new instance of MapLayer * @param name Name of the layer * @param title Title of the layer * @param srsList List of supported SRS * @param subLayers List of children * @param latLon LatLong bounding box as defined in WMS 1.1.1 */ public MapLayer(String name, String title, Collection<String> srsList, Collection<MapLayer> subLayers, BoundingBox latLon) { this.parent = null; this.name = name; this.title = title; this.srsList = new ArrayList<String>( srsList ); this.subLayers = new ArrayList<MapLayer>( subLayers ); for(MapLayer ml : subLayers){ ml.parent = this; } } /** * Creates a new instance of MapLayer with boundingBoxMap [uwe dalluege] * @param name The name of the layer * @param title The title of the layer * @param srsList The collection of SRS/CRS that are explicitly associated to this layer * @param subLayers The children of this layer * @param bbox The geographic bounding box of the layer * @param boundingBoxMap The BoundingBox mapped to their declared SRS/CRS. * @throws NullPointerException When one of the expected collection/map that * should be given in argument of this constructor is null. */ public MapLayer ( String name, String title, Collection<String> srsList, Collection<MapLayer> subLayers, BoundingBox bbox, Map<String,BoundingBox> boundingBoxMap) { this ( name, title, srsList, subLayers, bbox ); this.boundingBoxMap = boundingBoxMap; } /** * @return All BoundingBoxes associated to this layer. * If there is no BoundingBox for this MapLayer the parent-BoundingBox * will be taken. * [uwe dalluege] */ public List<BoundingBox> getAllBoundingBoxList(){ if(boundingBoxMap != null){ Collection<BoundingBox> values = boundingBoxMap.values(); if(values != null && !values.isEmpty()){ return new ArrayList<BoundingBox>(values); } } //We didn't find anything, let's check the parents... return parent == null ? new ArrayList<BoundingBox>() : parent.getAllBoundingBoxList(); } /** * Returns the number of sub-layers that this MapLayer has. * @return the number of sub-layers that this MapLayer has */ public int numSubLayers() { return subLayers.size(); } /** * Returns the sub-layer at the specified index. * @param n the index of the sub-layer to return * @return the MapLayer sub-layer at the specified index */ public MapLayer getSubLayer( int n ) { return (MapLayer)subLayers.get( n ); } /** * Gets a copy of the list of the sublayers of this layer. * @return a copy of the Arraylist containing all the sub-layers of this layer */ public ArrayList<MapLayer> getSubLayerList() { return (ArrayList<MapLayer>)subLayers.clone(); } /** * Returns a list of all the layers in order of a root-left-right traversal of * the layer tree. * @return a list of all the layers in order of a root-left-right traversal of * the layer tree. */ public ArrayList getLayerList() { ArrayList list = new ArrayList(); list.add( this ); Iterator it = subLayers.iterator(); while( it.hasNext() ) { list.addAll( ((MapLayer)it.next()).getLayerList() ); } return list; } /** * Gets the title of this MapLayer. * The title of a layer should be used for display purposes. * @return the title of this Layer */ public String getTitle() { return title; } /** * Gets the name of this Layer. * The name of a layer is its 'back-end', ugly name, which generally * shouldn't need to be used by others but is available anyway. * Layers which do not have any data associated with them, such as container * or grouping layers, might not have a name, in which case null will be * returned. * @return the name of the layer, or null if it doesn't have a name */ public String getName() { return name; } /** * Gets the parent MapLayer of this MapLayer. * @return the parent layer of this MapLayer, or null if the layer has no parent. */ public MapLayer getParent() { return parent; } /** * Gets the LatLonBoundingBox for this layer. * If this layer doesn't have a LatLonBoundingBox specified, we recursively * ask the parent layer for its bounding box. The WMS spec says that each * layer should either have its own LatLonBoundingBox, or inherit one from * its parent, so this recursive call should be successful. If not, null is * returned. However, if a bounding box is returned, it will have the * SRS string "LatLon". * Note that the BoundingBox is not necessarily "tight". * @return the BoundingBox for this layer, or null if the BBox is unknown */ public BoundingBox getBoundingBox() { if( bbox != null ) { return bbox; } if( parent != null ) { return parent.getBoundingBox(); } return null; } /** * Return the bounding box defined for this MapLayer in this SRS. * If not found, the bounding box is searched in this Layer's children, * then in its the parents. * If not found, return the whole earth in LonLat SRS. */ public BoundingBox getBoundingBox(String srs) { Envelope envelope = getBoundingBox(srs, this, new Envelope()); MapLayer p = this; while (envelope.getMinX() > envelope.getMaxX() && p.getParent() != null) { p = p.getParent(); if(p != null){ BoundingBox bb = p.getBoundingBoxMap().get(srs); if (bb != null) { // if this layer has a bounding box for this srs, return its envelope envelope.expandToInclude(bb.getEnvelope()); return new BoundingBox(srs, envelope); } } } return new BoundingBox(srs, envelope); } /** * Return the envelope of this layer in the wished srs if a BoundingBox in * this srs exists. Else if, layer's children are scanned recursively. * @param srs The expected SRS * @param lyr The original Layer * @param env The original envelope. It will be used as a basis and will be expanded to match the bounding box * of the layer. * @return The envelope of the layer in the given srs or the expended Envelop of all the children of {@code lyr} * if no explicit bounding box was found for {@code lyr} in the provided srs. */ public static Envelope getBoundingBox(String srs, MapLayer lyr, Envelope env) { BoundingBox bb = lyr.getBoundingBoxMap().get(srs); if(bb!=null){ //this layer has a bounding box for this srs, return its envelope env.expandToInclude(bb.getEnvelope()); } else { for (MapLayer child : lyr.getSubLayerList()) { env.expandToInclude(getBoundingBox(srs, child, env)); } } return env; } /** * I think this name is better [uwe dalluege] * Gets the LatLonBoundingBox for this layer. * If this layer doesn't have a LatLonBoundingBox specified, we recursively * ask the parent layer for its bounding box. The WMS spec says that each * layer should either have its own LatLonBoundingBox, or inherit one from * its parent, so this recursive call should be successful. If not, null is * returned. However, if a bounding box is returned, it will have the * SRS string "LatLon". * Note that the BoundingBox is not necessarily "tight". * @return the BoundingBox for this layer, or null if the BBox is unknown */ public BoundingBox getLatLonBoundingBox() { if( bbox != null ) { return bbox; } if( parent != null ) { return parent.getBoundingBox(); } return null; } /** * Gets the BoundingBoxList for this Layer * @return the BoundingBoxList containing the BoundingBoxes */ public Map<String,BoundingBox> getBoundingBoxMap() {// [uwe dalluege] return new HashMap<String,BoundingBox>(boundingBoxMap); } /** * Returns a copy of the list of supported SRS's. Each SRS is a string in the * format described by the WMS specification, such as "EPSG:1234". * @return a copy of the list of supported SRS's */ public ArrayList getSRSList() { return (ArrayList)srsList.clone(); } //<<TODO>>I'd like to return generic Lists, rather than concrete ArrayLists. //Or even better, Collections, since order is not significant (I think) [Jon Aquino] /** * @return a list of the SRS list of this MapLayer and its ancestors */ public Collection getFullSRSList() { // Change TreeSet to LinkedHashSet in order to preserve the natural order // with layer SRS first ans parent SRS second Set fullSRSList = new LinkedHashSet(getSRSList()); if (parent != null) fullSRSList.addAll(parent.getFullSRSList()); return fullSRSList; } /** * Returns a somewhat nicely-formatted string representing all of the details of * this layer and its sub-layers (recursively). * @return a somewhat nicely-formatted string representing all of the details of * this layer and its sub-layers (recursively). */ @Override public String toString() { StringBuilder s = new StringBuilder( "WMSLayer {\n name: \""); s.append(name); s.append("\"\n title: \""); s.append(title); s.append("\"\n srsList: "); s.append(srsList.toString()); s.append("\n subLayers: [\n" ); for( int i = 0; i < subLayers.size(); i++ ) { s.append( subLayers.get( i ).toString()).append(", "); } s.append( " ]\n bbox: " ); if( bbox != null ) { s.append( bbox.toString() ); } else { s.append( "null" ); } s.append( "\n}\n" ); return s.toString(); } }