/GPX.Firemap.Desktop/GPX.Firemap.Desktop.Add-ins/GraticuleCustomLayers.esriaddin/CustomLayers/GDA94GraticuleCustomLayer.cs
C# | 589 lines | 373 code | 73 blank | 143 comment | 42 complexity | 277ea77fc342127ce8821f2f553d5cc6 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using ESRI.ArcGIS.ADF;
- using ESRI.ArcGIS.ArcMapUI;
- using ESRI.ArcGIS.Carto;
- using ESRI.ArcGIS.Display;
- using ESRI.ArcGIS.esriSystem;
- using ESRI.ArcGIS.Geometry;
-
- namespace GraticuleCustomLayers.esriaddin
- {
- public class GDA94GraticuleCustomLayer : ILayer
- {
- #region Module Level Variables and Constants
-
- // Temporary constants (TODO: Will be replaced with values extracted from config)
- // These are DD intervals: private const string GraticuleIntervals = "100,90,80,70,60,50,40,30,20,10,9,8,7,6,5,4,3,2,1,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.09,0.08,0.07,0.06,0.05,0.04,0.03,0.02,0.01,0.009,0.008,0.007,0.006,0.005,0.004,0.003,0.002,0.001,0.0009,0.0008,0.0007,0.0006,0.0005,0.0004,0.0003,0.0002,0.0001,0.00009,0.00008,0.00007,0.00006,0.00005,0.00004,0.00003,0.00002,0.00001";
-
- // The following intervals are whole degree, minute and seconds values (converted to DD).
- // Whole DMS values must be used to ensure the graticule line coordinates and labels match.
- private const string GraticuleIntervals = "100,90,80,70,60,50,40,30,20,10,9,8,7,6,5,4,3,2," +
- "1,0.833333333,0.666666667,0.5,0.333333333,0.166666667,0.133333333,0.1,0.066666667,0.033333333,0.016666667," +
- "0.013888889,0.011111111,0.008333333,0.005555556,0.002777778,0.002222222,0.001666667,0.001111111,0.000555556,0.000277778";
- private const int DensifySegmentCount = 50;
-
- /// <summary>
- /// Unique COM identifier for this class, to facilitate IPersistVariant (if persistence is implemented)
- /// </summary>
- private const string ClassGuid = "7e964821-34c2-47f7-b53b-0b2e48486886";
-
- /// <summary>
- /// Name of the layer
- /// </summary>
- public static readonly string LayerName = "Graticule";
-
- /// <summary>
- /// The MxDocument holding the map the is showing this custom layer
- /// </summary>
- private IMxDocument m_mxDocument = null;
-
- /// <summary>
- /// Indicates if the layer needs its own display cache.
- /// </summary>
- private bool m_isCached = false;
-
- /// <summary>
- /// Indicates if the layer is currently visible.
- /// </summary>
- private bool m_visible = true;
-
- /// <summary>
- /// Describes the area of interest of the layer.
- /// </summary>
- private IEnvelope m_areaOfInterest = default(IEnvelope);
-
- #endregion
-
- #region Constructors
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GraticuleCustomLayer"/> class.
- /// </summary>
- /// <param name="mxDocument">The ArcMap document this layer is associated with.</param>
- public GDA94GraticuleCustomLayer(IMxDocument mxDocument)
- {
- m_mxDocument = mxDocument;
- }
-
- #endregion
-
- #region ILayer Members
-
- /// <summary>
- /// The default area of interest for the layer.
- /// </summary>
- public IEnvelope AreaOfInterest
- {
- get
- {
- return m_areaOfInterest;
- }
- }
-
- /// <summary>
- /// Indicates if the layer needs its own display cache.
- /// </summary>
- public bool Cached
- {
- get
- {
- return m_isCached;
- }
- set
- {
- m_isCached = value;
- }
- }
-
- /// <summary>
- /// Draws the layer to the specified display for the given draw phase.
- /// </summary>
- /// <param name="DrawPhase"></param>
- /// <param name="Display"></param>
- /// <param name="TrackCancel"></param>
- public void Draw(esriDrawPhase DrawPhase, IDisplay Display, ITrackCancel TrackCancel)
- {
- System.Diagnostics.Debug.WriteLine("GraticuleDrawEvent");
- using (ComReleaser comReleaser = new ComReleaser())
- {
- // Make sure we can proceed, if not exit
- if (!Valid || !Visible) { return; }
-
- // Get the display transformation and spatial references
- IDisplayTransformation displayTranformation = Display.DisplayTransformation;
- ISpatialReference displaySpatialReference = displayTranformation.SpatialReference;
- comReleaser.ManageLifetime(displaySpatialReference);
- if (SpatialReferenceStore.IsUnknownSpatialReference(displaySpatialReference)) { return; }
- ISpatialReference graticuleSpatialReference = displayTranformation.SpatialReference;
- comReleaser.ManageLifetime(graticuleSpatialReference);
- if ((displaySpatialReference as IProjectedCoordinateSystem) != null)
- {
- graticuleSpatialReference = (ISpatialReference)((IProjectedCoordinateSystem)displaySpatialReference).GeographicCoordinateSystem;
- comReleaser.ManageLifetime(graticuleSpatialReference);
- }
-
- // Get the bounds of the map.
- // This must be fitted bounds when drawing in data view, or printing in data view or layout view.
- // When drawing in layout view this must be the bounds of the matching map frame (IDisplays match)
- m_areaOfInterest = displayTranformation.FittedBounds;
- if ((m_mxDocument.ActiveView as IPageLayout) != null)
- {
- IMapFrame[] mapFrames = LayoutMethods.GetMapFrames((IPageLayout)m_mxDocument.ActiveView);
- foreach (IMapFrame mapFrame in mapFrames)
- {
- if (((IActiveView)mapFrame.Map).ScreenDisplay.Equals(Display))
- {
- m_areaOfInterest = mapFrame.MapBounds;
- }
- }
- }
-
- // Get the list of lines and label points to be displayed (calculated in graticule coords, returned in display coords)
- List<GraticuleLine> graticuleLines = CalculateGraticuleLines(m_areaOfInterest, displaySpatialReference, graticuleSpatialReference);
-
- // Draw the lines
- Display.SetSymbol((ISymbol)OsraGraphics.GraticuleLineSymbol);
- foreach (GraticuleLine graticuleLine in graticuleLines)
- {
- Display.DrawPolyline((IGeometry)graticuleLine.Line);
- }
-
- // Draw the labels
- ITextSymbol textSymbol = OsraGraphics.GraticuleTextSymbol;
- foreach (GraticuleLine graticuleLine in graticuleLines)
- {
- foreach (GraticuleLabelPoint graticuleLabelPoint in graticuleLine.LabelPoints)
- {
- // Set the properties of the text symbol based on the properties of the label point
- textSymbol.HorizontalAlignment = graticuleLabelPoint.HorizontalAlignment;
- textSymbol.VerticalAlignment = graticuleLabelPoint.VerticalAlignment;
- textSymbol.Text = graticuleLabelPoint.Text;
-
- // Work out the extent of the label to be drawn
- IEnvelope boundsEnv = new EnvelopeClass();
- comReleaser.ManageLifetime(boundsEnv);
- ((IQueryGeometry)textSymbol).QueryEnvelope(Display.hDC, (ITransformation)displayTranformation, (IGeometry)graticuleLabelPoint.AnchorPoint, boundsEnv);
-
- // Do some calcs to make sure we only draw lables that not too close to the corners of the display.
- bool draw = false;
- if (textSymbol.VerticalAlignment == esriTextVerticalAlignment.esriTVATop ||
- textSymbol.VerticalAlignment == esriTextVerticalAlignment.esriTVABottom) // Longiture labels
- {
- if (boundsEnv.XMin > m_areaOfInterest.XMin && boundsEnv.XMax < m_areaOfInterest.XMax)
- {
- draw = true;
- }
- }
- else // Latitude labels
- {
- if ((m_areaOfInterest.YMax - boundsEnv.YMax) > boundsEnv.Height &&
- (boundsEnv.YMin - m_areaOfInterest.YMin) > boundsEnv.Height)
- {
- draw = true;
- }
- }
-
- // If the label is to be drawn, the draw it
- if (draw)
- {
- Display.SetSymbol((ISymbol)textSymbol);
- Display.DrawText((IGeometry)graticuleLabelPoint.AnchorPoint, graticuleLabelPoint.Text);
- }
- ComReleaser.ReleaseCOMObject(graticuleLabelPoint.AnchorPoint);
- }
- ComReleaser.ReleaseCOMObject(graticuleLine.Line);
- }
- }
- }
-
- /// <summary>
- /// Maximum scale (representative fraction) at which the layer will display.
- /// </summary>
- public double MaximumScale
- {
- get
- {
- return default(double);
- }
- set
- {
- // Setting MaximumScale does nothing
- }
- }
-
- /// <summary>
- /// Minimum scale (representative fraction) at which the layer will display.
- /// </summary>
- public double MinimumScale
- {
- get
- {
- return default(double);
- }
- set
- {
- // Setting MinimumScale does nothing
- }
- }
-
- /// <summary>
- /// Layer name.
- /// </summary>
- public string Name
- {
- get
- {
- return LayerName;
- }
- set
- {
- // Setting Name does nothing
- }
- }
-
- /// <summary>
- /// Indicates if the layer shows map tips.
- /// </summary>
- public bool ShowTips
- {
- get
- {
- return default(bool);
- }
- set
- {
- // Setting ShowTips does nothing
- }
- }
-
- /// <summary>
- /// Spatial reference for the layer.
- /// </summary>
- public ISpatialReference SpatialReference
- {
- set
- {
- // Setting SpatialReference does nothing
- }
- }
-
- /// <summary>
- /// Supported draw phases.
- /// </summary>
- public int SupportedDrawPhases
- {
- get
- {
- return (int)esriDrawPhase.esriDPGeography;
- }
- }
-
- /// <summary>
- /// Indicates if the layer is currently valid.
- /// </summary>
- public bool Valid
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Indicates if the layer is currently visible.
- /// </summary>
- public bool Visible
- {
- get
- {
- return m_visible;
- }
- set
- {
- m_visible = value;
- }
- }
-
- /// <summary>
- /// Get_s the tip text.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <param name="Tolerance">The tolerance.</param>
- public string get_TipText(double x, double y, double Tolerance)
- {
- return default(string);
- }
-
- #endregion
-
- #region Static Helper Methods
-
- /// <summary>
- /// Calculates the graticule lines.
- /// </summary>
- /// <param name="displayBounds">The display bounds.</param>
- /// <param name="displaySpatialReference">The display spatial reference.</param>
- /// <param name="graticuleSpatialReference">The graticule spatial reference.</param>
- /// <returns>A list of GraticuleLine DTOs</returns>
- private static List<GraticuleLine> CalculateGraticuleLines(IEnvelope displayBounds, ISpatialReference displaySpatialReference, ISpatialReference graticuleSpatialReference)
- {
- using (ComReleaser comReleaser = new ComReleaser())
- {
- // Project the display bounds and slightly expanded display bounds into graticule coordinates
- IEnvelope graticuleBounds = (IEnvelope)ProjectionMethods.ProjectCopy(displayBounds, graticuleSpatialReference);
- comReleaser.ManageLifetime(graticuleBounds);
- IEnvelope graticuleBoundsExpanded = (IEnvelope)ProjectionMethods.ProjectCopy(displayBounds, graticuleSpatialReference);
- comReleaser.ManageLifetime(graticuleBoundsExpanded);
- graticuleBoundsExpanded.Expand(1.25, 1.25, true);
-
- // Get the edges of the display bounds in display coordinates
- object missing = Type.Missing;
- IPointCollection displayBoundsTopEdge = new PolylineClass();
- comReleaser.ManageLifetime(displayBoundsTopEdge);
- ((IPolyline)displayBoundsTopEdge).SpatialReference = displaySpatialReference;
- displayBoundsTopEdge.AddPoint(displayBounds.UpperLeft, ref missing, ref missing);
- displayBoundsTopEdge.AddPoint(displayBounds.UpperRight, ref missing, ref missing);
- IPointCollection displayBoundsBottomEdge = new PolylineClass();
- comReleaser.ManageLifetime(displayBoundsBottomEdge);
- ((IPolyline)displayBoundsBottomEdge).SpatialReference = displaySpatialReference;
- displayBoundsBottomEdge.AddPoint(displayBounds.LowerLeft, ref missing, ref missing);
- displayBoundsBottomEdge.AddPoint(displayBounds.LowerRight, ref missing, ref missing);
- IPointCollection displayBoundsLeftEdge = new PolylineClass();
- comReleaser.ManageLifetime(displayBoundsLeftEdge);
- ((IPolyline)displayBoundsLeftEdge).SpatialReference = displaySpatialReference;
- displayBoundsLeftEdge.AddPoint(displayBounds.LowerLeft, ref missing, ref missing);
- displayBoundsLeftEdge.AddPoint(displayBounds.UpperLeft, ref missing, ref missing);
- IPointCollection displayBoundsRightEdge = new PolylineClass();
- comReleaser.ManageLifetime(displayBoundsRightEdge);
- ((IPolyline)displayBoundsRightEdge).SpatialReference = displaySpatialReference;
- displayBoundsRightEdge.AddPoint(displayBounds.LowerRight, ref missing, ref missing);
- displayBoundsRightEdge.AddPoint(displayBounds.UpperRight, ref missing, ref missing);
-
- // Work out the display intervals of the graticule lines in graticule coordinates
- double[] intervals = System.Array.ConvertAll<string, double>(GDA94GraticuleCustomLayer.GraticuleIntervals.Split(Convert.ToChar(",")),
- delegate(string str) { return double.Parse(str); });
- //double longitudeActualInterval = (graticuleBounds.Width / Convert.ToDouble(UserSettings.Instance.DefaultMaxNumberOfGraticuleLines));
- //double latitudeActualInterval = (graticuleBounds.Height / Convert.ToDouble(UserSettings.Instance.DefaultMaxNumberOfGraticuleLines));
- double longitudeActualInterval = (graticuleBounds.Width / Convert.ToDouble(4));
- double latitudeActualInterval = (graticuleBounds.Height / Convert.ToDouble(4));
- double longitudeDisplayInterval = intervals.OrderBy(n => Math.Abs(longitudeActualInterval - n)).ElementAt(0); // Finds closest value in the interval array
- double latitudeDisplayInterval = intervals.OrderBy(n => Math.Abs(latitudeActualInterval - n)).ElementAt(0); // Finds closest value in the interval array
-
- // Work out the start positions of the graticule lines in graticule coordinates
- double longitudeLeft = (Math.Ceiling(graticuleBounds.XMin / longitudeDisplayInterval) * longitudeDisplayInterval);
- double latitudeBottom = (Math.Ceiling(graticuleBounds.YMin / latitudeDisplayInterval) * latitudeDisplayInterval);
-
- // Create the graticule lines (extend to expanded bounds), project back to the display coordinates and calculate label points
- List<GraticuleLine> graticuleLines = new List<GraticuleLine>();
- for (double i = longitudeLeft; i <= graticuleBounds.XMax; i += longitudeDisplayInterval)
- {
- if (i >= -180D && i <= 180D && graticuleBounds.YMin <= 90D && graticuleBounds.YMax >= -90D)
- {
- IPoint longitudeLineStart = new PointClass();
- comReleaser.ManageLifetime(longitudeLineStart);
- IPoint longitudeLineEnd = new PointClass();
- comReleaser.ManageLifetime(longitudeLineEnd);
- longitudeLineStart.PutCoords(i, graticuleBoundsExpanded.YMin);
- longitudeLineEnd.PutCoords(i, graticuleBoundsExpanded.YMax);
- IPolyline longitudeLine = new PolylineClass();
- longitudeLine.SpatialReference = graticuleSpatialReference;
- longitudeLine.FromPoint = longitudeLineStart;
- longitudeLine.ToPoint = longitudeLineEnd;
- ((IPolycurve)longitudeLine).Densify(longitudeLine.Length / Convert.ToDouble(GDA94GraticuleCustomLayer.DensifySegmentCount), 0);
- longitudeLine = (IPolyline)ProjectionMethods.Project((IGeometry)longitudeLine, displaySpatialReference);
-
- // Intersect the lines with the display bounds (top and bottom)
- List<GraticuleLabelPoint> graticuleLabelPoints = new List<GraticuleLabelPoint>();
- IGeometry topLabelPoint = ((ITopologicalOperator)longitudeLine).Intersect((IGeometry)displayBoundsTopEdge, esriGeometryDimension.esriGeometry0Dimension);
- if ((topLabelPoint as IMultipoint) != null && ((IPointCollection)topLabelPoint).PointCount == 1)
- {
- graticuleLabelPoints.Add(new GraticuleLabelPoint(((IPointCollection)topLabelPoint).get_Point(0),
- esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVATop, LatLongCoordinateFormatter.ConvertLongitudeDDtoDMS(i)));
- }
- IGeometry bottomLabelPoint = ((ITopologicalOperator)longitudeLine).Intersect((IGeometry)displayBoundsBottomEdge, esriGeometryDimension.esriGeometry0Dimension);
- if ((bottomLabelPoint as IMultipoint) != null && ((IPointCollection)bottomLabelPoint).PointCount == 1)
- {
- graticuleLabelPoints.Add(new GraticuleLabelPoint(((IPointCollection)bottomLabelPoint).get_Point(0),
- esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVABottom, LatLongCoordinateFormatter.ConvertLongitudeDDtoDMS(i)));
- }
- graticuleLines.Add(new GraticuleLine(longitudeLine, graticuleLabelPoints));
- }
- }
- for (double i = latitudeBottom; i <= graticuleBounds.YMax; i += latitudeDisplayInterval)
- {
- if (i >= -90D && i <= 90D && graticuleBounds.XMin <= 180D && graticuleBounds.XMax >= -180D)
- {
- IPoint latitudeLineStart = new PointClass();
- comReleaser.ManageLifetime(latitudeLineStart);
- IPoint latitudeLineEnd = new PointClass();
- comReleaser.ManageLifetime(latitudeLineEnd);
- latitudeLineStart.PutCoords(graticuleBoundsExpanded.XMin, i);
- latitudeLineEnd.PutCoords(graticuleBoundsExpanded.XMax, i);
- IPolyline latitudeLine = new PolylineClass();
- latitudeLine.SpatialReference = graticuleSpatialReference;
- latitudeLine.FromPoint = latitudeLineStart;
- latitudeLine.ToPoint = latitudeLineEnd;
- ((IPolycurve)latitudeLine).Densify(latitudeLine.Length / Convert.ToDouble(GDA94GraticuleCustomLayer.DensifySegmentCount), 0);
- latitudeLine = (IPolyline)ProjectionMethods.Project((IGeometry)latitudeLine, displaySpatialReference);
-
- // Intersect the lines with the display bounds (top and bottom)
- List<GraticuleLabelPoint> graticuleLabelPoints = new List<GraticuleLabelPoint>();
- IGeometry leftLabelPoint = ((ITopologicalOperator)latitudeLine).Intersect((IGeometry)displayBoundsLeftEdge, esriGeometryDimension.esriGeometry0Dimension);
- if ((leftLabelPoint as IMultipoint) != null && ((IPointCollection)leftLabelPoint).PointCount == 1)
- {
- graticuleLabelPoints.Add(new GraticuleLabelPoint(((IPointCollection)leftLabelPoint).get_Point(0),
- esriTextHorizontalAlignment.esriTHALeft, esriTextVerticalAlignment.esriTVACenter, LatLongCoordinateFormatter.ConvertLatitudeDDtoDMS(i)));
- }
- IGeometry rightLabelPoint = ((ITopologicalOperator)latitudeLine).Intersect((IGeometry)displayBoundsRightEdge, esriGeometryDimension.esriGeometry0Dimension);
- if ((rightLabelPoint as IMultipoint) != null && ((IPointCollection)rightLabelPoint).PointCount == 1)
- {
- graticuleLabelPoints.Add(new GraticuleLabelPoint(((IPointCollection)rightLabelPoint).get_Point(0),
- esriTextHorizontalAlignment.esriTHARight, esriTextVerticalAlignment.esriTVACenter, LatLongCoordinateFormatter.ConvertLatitudeDDtoDMS(i)));
- }
- graticuleLines.Add(new GraticuleLine(latitudeLine, graticuleLabelPoints));
- }
- }
-
- return graticuleLines;
- }
- }
-
- #endregion
-
- #region Data Transfer Objects
-
- /// <summary>
- /// Class to hold details of a graticule line
- /// </summary>
- private class GraticuleLine
- {
- #region Module Level Variables
-
- private IPolyline _line;
-
- private List<GraticuleLabelPoint> _labelPoints;
-
- #endregion
-
- #region Constructors
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GraticuleLine"/> class.
- /// </summary>
- /// <param name="line">The line.</param>
- /// <param name="labelPoints">The label points.</param>
- public GraticuleLine(IPolyline line, List<GraticuleLabelPoint> labelPoints)
- {
- _line = line;
- _labelPoints = labelPoints;
- }
-
- #endregion
-
- #region Properties
-
- /// <summary>
- /// Gets the line.
- /// </summary>
- /// <value>The line.</value>
- public IPolyline Line
- {
- get { return _line; }
- }
-
- /// <summary>
- /// Gets the label points.
- /// </summary>
- /// <value>The label points.</value>
- public List<GraticuleLabelPoint> LabelPoints
- {
- get { return _labelPoints; }
- }
-
- #endregion
- }
-
- /// <summary>
- /// Class to hold details of a graticule label point
- /// </summary>
- private class GraticuleLabelPoint
- {
- #region Module Level Variables
-
- private IPoint _anchorPoint;
-
- private esriTextHorizontalAlignment _horizontalAlignment;
-
- private esriTextVerticalAlignment _verticalAlignment;
-
- private string _text;
-
- #endregion
-
- #region Constructors
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GraticuleLabelPoint"/> class.
- /// </summary>
- /// <param name="anchorPoint">The anchor point.</param>
- /// <param name="horizontalAlignment">The horizontal alignment.</param>
- /// <param name="verticalAlignment">The vertical alignment.</param>
- /// <param name="text">The text.</param>
- public GraticuleLabelPoint(IPoint anchorPoint, esriTextHorizontalAlignment horizontalAlignment,
- esriTextVerticalAlignment verticalAlignment, string text)
- {
- _anchorPoint = anchorPoint;
- _horizontalAlignment = horizontalAlignment;
- _verticalAlignment = verticalAlignment;
- _text = text;
- }
-
- #endregion
-
- #region Properties
-
- /// <summary>
- /// Gets the anchor point.
- /// </summary>
- /// <value>The anchor point.</value>
- public IPoint AnchorPoint
- {
- get { return _anchorPoint; }
- }
-
- /// <summary>
- /// Gets the horizontal alignment.
- /// </summary>
- /// <value>The horizontal alignment.</value>
- public esriTextHorizontalAlignment HorizontalAlignment
- {
- get { return _horizontalAlignment; }
- }
-
- /// <summary>
- /// Gets the vertical alignment.
- /// </summary>
- /// <value>The vertical alignment.</value>
- public esriTextVerticalAlignment VerticalAlignment
- {
- get { return _verticalAlignment; }
- }
-
- /// <summary>
- /// Gets the text.
- /// </summary>
- /// <value>The text.</value>
- public string Text
- {
- get { return _text; }
- }
-
- #endregion
- }
-
- #endregion
- }
- }