// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap 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 of the License, or
// (at your option) any later version.
//
// SharpMap 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 SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using Core.Common.Utils.Aop;
using Core.Common.Utils.Aop.Markers;
using Core.GIS.GeoAPI.CoordinateSystems.Transformations;
using Core.GIS.GeoAPI.Extensions.Feature;
using Core.GIS.GeoAPI.Geometries;
using Core.GIS.NetTopologySuite.Extensions.Features;
using Core.GIS.SharpMap.Api;
using Core.GIS.SharpMap.Api.Delegates;
using Core.GIS.SharpMap.Api.Enums;
using Core.GIS.SharpMap.Api.Layers;
using Core.GIS.SharpMap.Converters.Geometries;
using Core.GIS.SharpMap.CoordinateSystems.Transformations;
using Core.GIS.SharpMap.Rendering;
using Core.GIS.SharpMap.Styles;
namespace Core.GIS.SharpMap.Layers
{
///
/// Label layer class
/// TODO: Auto-configure LabelColumn etc to some default on DataSource change (?)
/// TODO: Change Map Rendering to check LabelLayer RenderRequired (more efficient: currently parent layer must be redrawn)
/// TODO: Remove classes that override this class only to get access to GetText: there's a delegate for that.
///
///
/// Creates a new label layer and sets the label text to the "Name" column in the FeatureDataTable of the datasource
///
/// //Set up a label layer
/// SharpMap.Layers.LabelLayer layLabel = new SharpMap.Layers.LabelLayer("Country labels");
/// layLabel.DataSource = layCountries.DataSource;
/// layLabel.Enabled = true;
/// layLabel.LabelColumn = "Name";
/// layLabel.Style = new SharpMap.Styles.LabelStyle();
/// layLabel.Style.CollisionDetection = true;
/// layLabel.Style.CollisionBuffer = new SizeF(20, 20);
/// layLabel.Style.ForeColor = Color.White;
/// layLabel.Style.Font = new Font(FontFamily.GenericSerif, 8);
/// layLabel.MaxVisible = 90;
/// layLabel.Style.HorizontalAlignment = SharpMap.Styles.LabelStyle.HorizontalAlignmentEnum.Center;
///
///
[Entity(FireOnCollectionChange = false)]
public class LabelLayer : Layer, ILabelLayer
{
private MultipartGeometryBehaviourEnum multipartGeometryBehaviour;
private LabelCollisionDetection.LabelFilterMethod labelFilter;
private ILabelStyle style;
private GetLabelMethod getLabelMethod;
public LabelLayer() : this("") {}
///
/// Creates a new instance of a LabelLayer
///
public LabelLayer(string layername)
{
style = new LabelStyle();
Name = layername;
SmoothingMode = SmoothingMode.AntiAlias;
TextRenderingHint = TextRenderingHint.AntiAlias;
multipartGeometryBehaviour = MultipartGeometryBehaviourEnum.All;
ShowInTreeView = false;
ShowInLegend = false;
Visible = false;
LabelFilter = LabelCollisionDetection.ThoroughCollisionDetection;
Style = new LabelStyle
{
Font = new Font("Arial", 12),
Halo = new Pen(Brushes.White, 1f),
CollisionDetection = true
};
}
///
/// Filtermethod delegate for performing filtering
///
///
/// Default method is
///
public virtual LabelCollisionDetection.LabelFilterMethod LabelFilter
{
get
{
return labelFilter;
}
set
{
labelFilter = value;
}
}
///
/// Gets or sets labelling behavior on multipart geometries
///
/// Default value is
public virtual MultipartGeometryBehaviourEnum MultipartGeometryBehaviour
{
get
{
return multipartGeometryBehaviour;
}
set
{
multipartGeometryBehaviour = value;
}
}
///
/// Render whether smoothing (antialiasing) is applied to lines and curves and the edges of filled areas
///
public virtual SmoothingMode SmoothingMode { get; set; }
///
/// Specifies the quality of text rendering
///
public virtual TextRenderingHint TextRenderingHint { get; set; }
///
/// Gets or sets the rendering style of the label layer.
///
public virtual ILabelStyle Style
{
get
{
return style;
}
set
{
style = value;
}
}
///
/// Gets or sets thematic settings for the layer. Set to null to ignore thematics
///
public virtual ITheme Theme { get; set; }
///
/// Data column or expression where label text is extracted from.
///
///
/// This property is overriden by the .
///
public virtual string LabelColumn { get; set; }
///
/// Gets or sets the method for creating a custom label string based on a feature.
///
///
/// If this method is not null, it will override the value.
/// The label delegate must take a and return a string.
///
/// Creating a label-text by combining attributes "ROADNAME" and "STATE" into one string, using
/// an anonymous delegate:
///
/// myLabelLayer.LabelStringDelegate = delegate(SharpMap.Data.FeatureDataRow fdr)
/// { return fdr["ROADNAME"].ToString() + ", " + fdr["STATE"].ToString(); };
///
///
///
public virtual GetLabelMethod LabelStringDelegate
{
get
{
return getLabelMethod;
}
set
{
getLabelMethod = value;
}
}
///
/// Data column from where the label rotation is derived.
/// If this is empty, rotation will be zero, or aligned to a linestring.
/// Rotation are in degrees (positive = clockwise).
///
public virtual string RotationColumn { get; set; }
///
/// A value indication the priority of the label in cases of label-collision detection
///
public virtual int Priority { get; set; }
[NoNotifyPropertyChange]
public override IFeatureProvider DataSource
{
get
{
return base.DataSource ?? ParentDataSource;
} //either custom datasource (different from parent, otherwise parent datasource)
set
{
base.DataSource = value;
}
}
[NoNotifyPropertyChange]
public override ICoordinateTransformation CoordinateTransformation
{
get
{
return base.DataSource == null ? ParentCoordinateTransformation : base.CoordinateTransformation;
}
set
{
base.CoordinateTransformation = value;
}
}
///
/// Gets the boundingbox of the entire layer
///
public override IEnvelope Envelope
{
get
{
if (DataSource == null)
{
return null;
}
if (CoordinateTransformation != null)
{
throw new NotImplementedException();
}
return DataSource.GetExtents();
}
}
[NoNotifyPropertyChange]
public virtual ILayer Parent { get; set; }
///
/// Renders the layer
///
/// Graphics object reference
/// Map which is rendered
public override void OnRender(Graphics g, IMap map)
{
if (Style.Enabled && Style.MaxVisible >= map.Zoom && Style.MinVisible < map.Zoom)
{
if (DataSource == null)
{
throw (new ApplicationException("DataSource property not set on layer '" + Name + "'"));
}
g.TextRenderingHint = TextRenderingHint;
g.SmoothingMode = SmoothingMode;
var features = Parent.GetFeatures(map.Envelope);
if (!features.Any())
{
return;
}
//Initialize label collection
var labels = new List