#region Disclaimer / License // Copyright (C) 2014, Jackie Ng // http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion Disclaimer / License using OSGeo.MapGuide.ObjectModels.Common; using OSGeo.MapGuide.ObjectModels.TileSetDefinition; using OSGeo.MapGuide.ObjectModels.WatermarkDefinition; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; namespace OSGeo.MapGuide.ObjectModels.MapDefinition { public class LayerExtent { public IEnvelope Extent { get; set; } public string LayerCoordinateSystem { get; set; } } public interface ILayerExtentCalculator { LayerExtent GetLayerExtent(string resourceID, string mapCoordSys); } /// /// Represents the base interface of map definitions and their runtime forms /// public interface IMapDefinitionBase { /// /// Gets the name. /// /// The name. string Name { get; } /// /// Gets the coordinate system. Layers whose coordinate system does /// not match will be re-projecte to this coordinate system when rendering /// /// The coordinate system. string CoordinateSystem { get; } /// /// Gets or sets the color of the background. /// /// The color of the background. Color BackgroundColor { get; set; } } /// /// Represents a Map Definition /// public interface IMapDefinition : IResource, IMapDefinitionBase, INotifyPropertyChanged { /// /// Gets or sets the name. /// /// The name. string Name { get; set; } /// /// Gets or sets the coordinate system. Layers whose coordinate system does /// not match will be re-projected to this coordinate system when rendering /// /// The coordinate system. string CoordinateSystem { get; set; } /// /// Gets or sets the extents. /// /// The extents. IEnvelope Extents { get; set; } /// /// Sets the extents. /// /// The minx. /// The miny. /// The maxx. /// The maxy. void SetExtents(double minx, double miny, double maxx, double maxy); /// /// Gets or sets the metadata. /// /// The metadata. string Metadata { get; set; } /// /// Returns the base map section of this map definition. Ensure /// is called first before accessing this property /// IBaseMapDefinition BaseMap { get; } /// /// Attaches the given base map section to this map definition. If an existing base map section /// exists, it is replaced /// /// void AttachBaseMap(IBaseMapDefinition baseMap); /// /// Initializes the base map section of this map definition. Subsequent calls /// do nothing, unless you have cleared the section via /// void InitBaseMap(); /// /// Clears the base map section of this map definition. If you want to rebuild /// this section, ensure is called /// void RemoveBaseMap(); /// /// Gets the map layers. /// /// The map layers. IEnumerable MapLayer { get; } ILayerExtentCalculator ExtentCalculator { get; set; } /// /// Inserts a layer into this map at the specified index in the map's layer collection /// /// /// /// /// /// IMapLayer InsertLayer(int index, string groupName, string layerName, string layerDefinitionId); /// /// Adds a layer to this map. If this is the first layer to be added, the coordinate system /// of this map and its extents will be set to the coordinate system and extents of this layer /// if this has not been set already. /// /// /// The layer is added to the beginning of the list. That is, if you called /// on your newly added layer, it will return 0. From a display perspective, your newly added layer will be at the top of the map's draw order when you create a runtime map from this map definition /// /// /// /// /// IMapLayer AddLayer(string groupName, string layerName, string resourceId); /// /// Adds a layer to this map. If this is the first layer to be added, the coordinate system /// of this map and its extents will be set to the coordinate system and extents of this layer /// if this has not been set already. /// /// The layer to insert above in the draw order /// The name of the group this layer belongs to. If null or empty, this layer will not belong to any group /// The name of this layer. This must be unique /// The layer definition id /// The added layer IMapLayer AddLayer(IMapLayer layerToInsertAbove, string groupName, string layerName, string resourceId); /// /// Removes the layer. /// /// The layer. void RemoveLayer(IMapLayer layer); /// /// Gets the index of the specified layer /// /// The layer. /// int GetIndex(IMapLayer layer); /// /// Moves the layer up the draw order /// /// The layer. /// The new index of the moved layer. -1 is returned if the layer does not belong to the map int MoveUp(IMapLayer layer); /// /// Moves the layer down the draw order. /// /// The layer. /// The new index of the moved layer. -1 is returned if the layer does not belong to the map int MoveDown(IMapLayer layer); /// /// Gets the map layer groups. /// /// The map layer groups. IEnumerable MapLayerGroup { get; } /// /// Adds the group. The group will be added to the end of the list /// /// Name of the group. /// IMapLayerGroup AddGroup(string groupName); /// /// Removes the group /// /// void RemoveGroup(IMapLayerGroup group); /// /// Gets the index of the specified group /// /// /// int GetIndex(IMapLayerGroup group); /// /// Moves the specified layer to the top of the draw order /// /// void SetTopDrawOrder(IMapLayer layer); /// /// Moves the specified layer to the bottom of the draw order /// /// void SetBottomDrawOrder(IMapLayer layer); /// /// Inserts the layer at the specified index /// /// /// void InsertLayer(int idx, IMapLayer layer); /// /// Moves a Map Group down the presentation order /// /// /// The new index of the moved group. -1 is returned if the group does not belong to the map int MoveDownGroup(IMapLayerGroup group); /// /// Moves a Map Group up the presentation order /// /// /// The new index of the moved group. -1 is returned if the group does not belong to the map int MoveUpGroup(IMapLayerGroup group); /// /// Removes all dynamic groups from this Map Definition /// void RemoveAllGroups(); /// /// Removes all dynamic layers from this Map Definition /// void RemoveAllLayers(); } /// /// Represents a Map Definition with support for watermarks. Corresponds to schema version 2.3.0 /// public interface IMapDefinition2 : IMapDefinition, IWatermarkCollection { } /// /// Represents a Map Definition with support for linking to tile sets. Corresponds to schema version 3.0.0 /// public interface IMapDefinition3 : IMapDefinition2 { /// /// Gets or sets the Tile Set Definition. When setting a tile set, any existing base map settings are removed /// string TileSetDefinitionID { get; set; } /// /// Gets or sets the type of tile source /// TileSourceType TileSourceType { get; set; } } /// /// Defines the type of tile source /// public enum TileSourceType { /// /// The Map Definition links to an external tile set /// External, /// /// The tile layer/group settings are defined within the Map Definition /// Inline, /// /// No tile layer/group settings are defined /// None } /// /// Extension method class /// public static class MapDefinitionExtensions { /// /// Sets the extents of the map definition from the id of the the given layer definition /// Does nothing if the extent is already set /// /// /// public static void AutoSetExtentsFromLayer(this IMapDefinition mdf, string layerDefinitionId) { //Do nothing if this is false if (!mdf.Extents.IsEmpty()) return; var calc = mdf.ExtentCalculator; if (calc != null) { var res = calc.GetLayerExtent(layerDefinitionId, mdf.CoordinateSystem); if (res != null) { //Set the coordinate system if empty if (string.IsNullOrEmpty(mdf.CoordinateSystem)) { mdf.CoordinateSystem = res.LayerCoordinateSystem; } //Set the bounds if empty if (mdf.Extents.IsEmpty()) { var env = res.Extent; mdf.SetExtents(env.MinX, env.MinY, env.MaxX, env.MaxY); } } } } /// /// Adds the specified finite display scale to the Map Definition /// /// /// public static void AddFiniteDisplayScale(this IMapDefinition map, double scale) { Check.ArgumentNotNull(map, nameof(map)); if (map.BaseMap != null) map.InitBaseMap(); map.BaseMap.AddFiniteDisplayScale(scale); } /// /// Removes the specified finite display scale from the Map Definition /// /// /// /// public static void RemoveFiniteDisplayScale(this IMapDefinition map, double scale, bool bDetachIfEmpty) { Check.ArgumentNotNull(map, nameof(map)); if (map.BaseMap == null) return; map.BaseMap.RemoveFiniteDisplayScale(scale); if (map.BaseMap.GroupCount == 0 && map.BaseMap.ScaleCount == 0 && bDetachIfEmpty) map.RemoveBaseMap(); } /// /// Removes all finite display scales from the Map Definition /// /// /// public static void RemoveAllFiniteDisplayScales(this IMapDefinition map, bool bDetachIfEmpty) { Check.ArgumentNotNull(map, nameof(map)); if (map.BaseMap == null) return; map.BaseMap.RemoveAllScales(); if (map.BaseMap.GroupCount == 0 && map.BaseMap.ScaleCount == 0 && bDetachIfEmpty) map.RemoveBaseMap(); } /// /// Adds the specified base layer group to the map definition /// /// /// /// public static IBaseMapGroup AddBaseLayerGroup(this IMapDefinition map, string name) { Check.ArgumentNotNull(map, nameof(map)); Check.ArgumentNotEmpty(name, nameof(name)); if (map.BaseMap == null) map.InitBaseMap(); return map.BaseMap.AddBaseLayerGroup(name); } /// /// Removes the given base layer group from the Map Definition /// /// /// /// public static void RemoveBaseLayerGroup(this IMapDefinition map, IBaseMapGroup group, bool bDetachIfEmpty) { Check.ArgumentNotNull(map, nameof(map)); if (null == group) return; if (map.BaseMap == null) return; map.BaseMap.RemoveBaseLayerGroup(group); if (map.BaseMap.GroupCount == 0 && map.BaseMap.GroupCount == 0 && bDetachIfEmpty) map.RemoveBaseMap(); } /// /// Updates the group name references of all layers belonging to a particular group /// /// The map. /// Old name of the group. /// New name of the group. public static void UpdateDynamicGroupName(this IMapDefinition map, string oldGroupName, string newGroupName) { Check.ArgumentNotNull(map, nameof(map)); Check.ArgumentNotEmpty(oldGroupName, nameof(oldGroupName)); Check.ArgumentNotEmpty(newGroupName, nameof(newGroupName)); var layers = map.GetLayersForGroup(oldGroupName); var groups = map.GetGroupsForGroup(oldGroupName); foreach (var l in layers) { l.Group = newGroupName; } foreach (var g in groups) { g.Group = newGroupName; } } /// /// Removes a layer group and all layers associated with this group /// /// /// /// The number of layers removed. Returns 0 if the group is empty or does not exist public static int RemoveLayerGroupAndChildLayers(this IMapDefinition map, string groupName) { Check.ArgumentNotNull(map, nameof(map)); Check.ArgumentNotEmpty(groupName, nameof(groupName)); var affectedParentGroups = new Dictionary>(); IMapLayerGroup group = null; foreach (var grp in map.MapLayerGroup) { if (grp.Name == groupName) group = grp; string parentGroupName = grp.Group; if (!string.IsNullOrEmpty(parentGroupName)) { if (!affectedParentGroups.ContainsKey(parentGroupName)) affectedParentGroups[parentGroupName] = new List(); affectedParentGroups[parentGroupName].Add(grp); } } if (group != null) { List layers = new List(map.GetLayersForGroup(groupName)); int removed = 0; //Remove layers first foreach (var l in layers) { map.RemoveLayer(l); removed++; } //Then the group map.RemoveGroup(group); //Then see if any child groups are under this group and remove them too if (affectedParentGroups.ContainsKey(group.Name)) { for (int i = 0; i < affectedParentGroups[group.Name].Count; i++) { var removeMe = affectedParentGroups[group.Name][i]; removed += map.RemoveLayerGroupAndChildLayers(removeMe.Name); } } return removed; } return 0; } /// /// Get a layer by its name /// /// /// /// public static IMapLayer GetLayerByName(this IMapDefinition map, string name) { Check.ArgumentNotNull(map, nameof(map)); Check.ArgumentNotEmpty(name, nameof(name)); foreach (var layer in map.MapLayer) { if (name.Equals(layer.Name)) return layer; } return null; } /// /// Gets a group by its name /// /// /// /// public static IMapLayerGroup GetGroupByName(this IMapDefinition map, string name) { Check.ArgumentNotNull(map, nameof(map)); foreach (var group in map.MapLayerGroup) { if (name.Equals(group.Name)) return group; } return null; } /// /// Gets the number of layers (non-tiled) on this map /// /// /// public static int GetDynamicLayerCount(this IMapDefinition map) { Check.ArgumentNotNull(map, nameof(map)); return new List(map.MapLayer).Count; } /// /// Gets the number of groups (non-tiled) on this map /// /// /// public static int GetGroupCount(this IMapDefinition map) { Check.ArgumentNotNull(map, nameof(map)); return new List(map.MapLayerGroup).Count; } /// /// Gets all the layers that belong to the specified group /// /// /// /// public static IEnumerable GetLayersForGroup(this IMapDefinition map, string name) { Check.ArgumentNotNull(map, nameof(map)); foreach (var layer in map.MapLayer) { if (name.Equals(layer.Group)) yield return layer; } } /// /// Gets all the groups that belong to the specified group /// /// /// /// public static IEnumerable GetGroupsForGroup(this IMapDefinition map, string name) { Check.ArgumentNotNull(map, nameof(map)); foreach (var group in map.MapLayerGroup) { if (name.Equals(group.Group)) yield return group; } } /// /// Gets all that layers that do not belong to a group /// /// /// public static IEnumerable GetLayersWithoutGroups(this IMapDefinition map) { Check.ArgumentNotNull(map, nameof(map)); foreach (var layer in map.MapLayer) { if (string.IsNullOrEmpty(layer.Group)) yield return layer; } } /// /// /// /// /// public static ITileSetDefinition ConvertToTileSet(this IMapDefinition map, Version schemaVersion) { Check.ArgumentNotNull(map, nameof(map)); var tsd = ObjectFactory.CreateTileSetDefinition(schemaVersion, map.Extents.Clone()); var baseMap = map.BaseMap; if (baseMap == null) throw new InvalidOperationException(Strings.MapDefinitionHasNoBaseMapSection); //Clear any existing default groups created foreach(var grp in tsd.BaseMapLayerGroups.ToArray()) { tsd.RemoveBaseLayerGroup(grp); } tsd.SetDefaultProviderParameters(300, 300, map.CoordinateSystem, baseMap.FiniteDisplayScale.ToArray()); foreach (var grp in baseMap.BaseMapLayerGroups) { var tsdGroup = tsd.AddBaseLayerGroup(grp.Name); tsdGroup.ExpandInLegend = grp.ExpandInLegend; tsdGroup.LegendLabel = grp.LegendLabel; tsdGroup.ShowInLegend = grp.ShowInLegend; tsdGroup.Visible = grp.Visible; foreach (var layer in grp.BaseMapLayer) { var tsdLayer = tsdGroup.AddLayer(layer.Name, layer.ResourceId); tsdLayer.ExpandInLegend = layer.ExpandInLegend; tsdLayer.LegendLabel = layer.LegendLabel; tsdLayer.Selectable = layer.Selectable; tsdLayer.ShowInLegend = layer.ShowInLegend; } } return tsd; } } /// /// Represents the tiled map portion of the Map Definition /// public interface IBaseMapDefinition : ITileSetAbstract { } /// /// Base legend element /// public interface IMapLegendElementBase : INotifyPropertyChanged { /// /// Gets or sets the name. /// /// The name. string Name { get; set; } /// /// Gets or sets a value indicating whether [show in legend]. /// /// true if [show in legend]; otherwise, false. bool ShowInLegend { get; set; } /// /// Gets or sets the legend label. /// /// The legend label. string LegendLabel { get; set; } /// /// Gets or sets a value indicating whether [expand in legend]. /// /// true if [expand in legend]; otherwise, false. bool ExpandInLegend { get; set; } } /// /// Base layer interface /// public interface IBaseMapLayer : IMapLegendElementBase { /// /// Gets or sets the resource id. /// /// The resource id. string ResourceId { get; set; } /// /// Gets or sets a value indicating whether this is selectable. /// /// true if selectable; otherwise, false. bool Selectable { get; set; } } /// /// Tiled map group /// public interface IBaseMapGroup : IMapLegendElementBase { /// /// Gets or sets a value indicating whether this is visible. /// /// true if visible; otherwise, false. bool Visible { get; set; } /// /// Gets the base map layers. /// /// The base map layers. IEnumerable BaseMapLayer { get; } /// /// Adds the layer. /// /// Name of the layer. /// The resource id. /// IBaseMapLayer AddLayer(string layerName, string resourceId); /// /// Removes the base map layer. /// /// The layer. void RemoveBaseMapLayer(IBaseMapLayer layer); /// /// Insert the base map layer at the specified index /// /// /// void InsertLayer(int index, IBaseMapLayer layer); /// /// Gets the index of the specified layer /// /// /// int GetIndex(IBaseMapLayer layer); /// /// Moves the specified layer up. /// /// The layer. /// int MoveUp(IBaseMapLayer layer); /// /// Moves the specified layer down. /// /// The layer. /// int MoveDown(IBaseMapLayer layer); } /// /// A dynamic map layer /// public interface IMapLayer : IBaseMapLayer { /// /// Gets or sets a value indicating whether this is visible. /// /// true if visible; otherwise, false. bool Visible { get; set; } /// /// Gets or sets the group. /// /// The group. string Group { get; set; } } /// /// A dynamic map layer group /// public interface IMapLayerGroup : IMapLegendElementBase { /// /// Gets or sets a value indicating whether this is visible. /// /// true if visible; otherwise, false. bool Visible { get; set; } /// /// Gets or sets the group name. If null, it means this layer doesn't belong to any group /// /// The group. string Group { get; set; } /// /// Gets the parent map definition /// /// The parent map definition. IMapDefinition Parent { get; } } }