//--------------------------------------------------------------------
//
// Copyright 2013 Exelis Inc.
// Government Unlimited Rights (DFARs 252.227-7014)
//
//--------------------------------------------------------------------
namespace STTI.FAC.MapControl2d
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.DesktopEdition;
using EGL = STTI.FAC.EllipticalGeometry;
using STTI.FAC.CommonCodeLibrary;
using STTI.FAC.CommonCodeLibrary.IMsgLogger;
using STTI.FAC.CommonCodeLibrary.Forms;
using STTI.FAC.CommonCodeLibrary.Map2dCommon.MmMc;
using STTI.FAC.CommonCodeLibrary.Map2dCommon.MmWp;
using STTI.FAC.MapControl2d.CpExplorer;
///
/// This class is used to create contour isolines for a set of data points.
/// The isoline level count and cell column and row count are currently set as constants
/// but could be passed as parameters or prompted by user.
/// The input data is currently read from a CSV (comma separated data file as a Lat,Lng Point
/// with a corresponding data value for the contour.
///
class IsoLines
{
#region Logger
///
/// Logger used to instrument this class.
///
static readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(IsoLines).FullName);
#endregion Logger
#region Fields
private delegate void LayerCreationDelegate();
private delegate void LayerUpdateHandler();
private event LayerUpdateHandler LayerUpdateEvent;
public const double NoDataValue = -99999999;
public const string GridCellsLayerName = "Grid-";
public const string LabelsLayerName = "Label-";
public const string PlotNamesLayerName = "Name-";
public const string PlotLegendLayerName = "Legend-";
private const int GridIsoLineCellColumnCount = 25;
private const int GridIsoLineCellRowCount = 25;
private const int GridCellOptimizationFaster = 400;
///
/// Minimum number of data values required to plot contour lines.
///
private const int MinimumValuesRequiredToPlot = 5;
///
/// Grid Cell Limit for sync versus asynch thread to generate isolines.
///
private const int MaxNoOfCellsForSynchCalls = 500;
public const string GridFile = @"tempResult";
public const string GridFileSuffix = @".grid";
private string gridFilePath = @"..\..\Data\tempResult.grid";
private Dictionary contoursPointData;
private GridCell[,] gridCellMatrix;
private RectangleShape drawingExtent = null;
///
/// Transparency of Legend Background.
///
public const float LegendTransparency = 200.0F;
///
/// Max Characters in Legend Title for Word Wrap.
///
public const int MaxCharLegendTitle = 35;
///
/// Lock around target.
///
private readonly object stateLock = new object();
#endregion
#region Properties
///
/// Associates a map with this tool strip.
///
public STTI.FAC.MapControl2d.MapControl2DMapSuite AssociatedMap { get; set; }
///
/// Gets/Sets the Layer Name for the IsoLines.
///
private string LayerNameIsoLine { get; set; }
///
/// Gets/Sets the Layer Name for the Grid Cells.
///
private string LayerNameGridCells { get; set; }
///
/// Gets/Sets the Layer Name for the Grid Labels.
///
private string LayerNameIsoLineLabels { get; set; }
///
/// Gets/Sets the Layer Name for the Grid Plot Names.
///
private string LayerNameIsoLinePlotNames { get; set; }
///
/// Gets/Sets the Layer Name for the Plot Legend.
///
private string LayerNamePlotLegend { get; set; }
///
/// Gets/Sets the Layer Plot Legend Adornment Layer.
///
private LegendAdornmentLayer IsoLinesLegendLayer { get; set; }
///
/// Gets/Sets the Layer Grid IsoLines.
///
private Layer IsoLinesLayer { get; set; }
///
/// Gets/Sets the Layer for the Grid Labels.
///
private IsoLineLayer IsoLineLabelsLayer { get; set; }
///
/// Gets/Sets the Layer for the Grid Plot Names.
///
private FeatureLayer IsoLinePlotNamesLayer { get; set; }
///
/// Gets/Sets the Layer for the Grid Feature.
///
private FeatureLayer IsoLineFeatureLayer { get; set; }
///
/// Gets/Sets the Line Level Count for the Grid.
///
private int GridLineLevelCount { get; set; }
///
/// Gets/Sets the Cell Row Count for the Grid.
///
private int GridCellRowCount { get; set; }
///
/// Gets/Sets the Cell Column Count for the Grid.
///
private int GridCellColumnCount { get; set; }
///
/// Gets/Sets the Colors for the isoLines.
///
private SortedDictionary LineLevelsAndColors { get; set; }
///
/// Gets/Sets the Colors for the AreaStyle Fill.
///
private SortedDictionary FillLevelsAndColors { get; set; }
///
/// Gets/Sets LineWidth for Isoline Pen.
///
private int LineWidth { get; set; }
///
/// Gets/Sets Line DashStyle for Isoline Pen.
///
private LineDashStyle PenLineDashStyle { get; set; }
///
/// Gets/Sets the McPlot for the Grid.
///
public McPlot Plot { get; set; }
///
/// Gets/Sets the Min Variable Value for the DataTable.
///
private double MinVariableValue { get; set; }
///
/// Gets/Sets the Max Variable Value for the DataTable.
///
private double MaxVariableValue { get; set; }
///
/// Gets/Sets the Max Latitude for the Coverage Plot.
///
private double MaxLatitude { get; set; }
///
/// Gets/Sets the Max Longitude for the Coverage Plot.
///
private double MaxLongitude { get; set; }
///
/// Gets/Sets the Min Latitude for the Coverage Plot.
///
private double MinLatitude { get; set; }
///
/// Gets/Sets the Min Longitude for the Coverage Plot.
///
private double MinLongitude { get; set; }
///
/// Gets/Sets the CellWidth for the Coverage Plot.
///
private double CellWidth { get; set; }
///
/// Gets/Sets the CellWidth Rounding for the Coverage Plot.
///
private double RoundCellWidth { get; set; }
///
/// Gets/Sets a boolean for more than one data values in plot data.
///
private bool IsThereMoreThanOneValue { get; set; }
///
/// Gets/Sets a boolean for number of unique data values in plot data.
///
private bool IsThereEnoughUniqueValues { get; set; }
///
/// Gets/Sets a boolean to PlotResolutionOptForSpeed.
///
private bool IsPlotResolutionOptForSpeed { get; set; }
///
/// Gets/Sets a boolean to prompt for plot resolution optimization for large grids.
///
private bool IsPlotResolutionOptShowDialogPrompt { get; set; }
///
/// Gets/Sets value to optimize the Grid size for Map Display speed.
///
private int PlotResolutionGridSize { get; set; }
#endregion Properties
#region Constructors
///
/// Constructor with AssociatedMap for the IsoLines Contours.
///
/// The associated Map control.
/// The plot shape for the Isolines.
public IsoLines(MapControl2DMapSuite associatedMap, ref McPlot plot)
{
try
{
AssociatedMap = associatedMap;
Plot = plot;
if (String.IsNullOrEmpty(AssociatedMap.isoLinesOpenSaveInitialFolder))
{
//AssociatedMap.isoLinesOpenSaveInitialFolder =
// GlobalInteract.Instance.GetWorkspacePath(Environment.UserName);
AssociatedMap.isoLinesOpenSaveInitialFolder =
GlobalInteract.Instance.GetParameterValue("Temporary directory path.", "TempDirectoryPath");
}
gridFilePath = AssociatedMap.isoLinesOpenSaveInitialFolder + "\\" +
GridFile + Plot.ObjectId.ToString() + GridFileSuffix;
MinLatitude = MinLongitude = double.MaxValue;
MaxLatitude = MaxLongitude = double.MinValue;
MinVariableValue = double.MaxValue;
MaxVariableValue = double.MinValue;
double uniqueValueCheck = NoDataValue;
IsThereMoreThanOneValue = false;
IsThereEnoughUniqueValues = false;
double[] valuesRequiredToPlot = new double[MinimumValuesRequiredToPlot];
for (int index = 0; index < MinimumValuesRequiredToPlot; index++)
{
valuesRequiredToPlot[index] = NoDataValue;
}
//Load the PlotData into a Dictionary.
if (null != Plot && null != Plot.PlotData)
{
contoursPointData = new Dictionary();
Plot.PlotData.Rewind();
LatLngVal latLngVal = Plot.PlotData.GetLatLngVal();
while (null != latLngVal)
{
PointShape pointShape = new PointShape(latLngVal.Longitude,
latLngVal.Latitude);
if (latLngVal.Longitude < MinLongitude)
{
MinLongitude = latLngVal.Longitude;
}
if (latLngVal.Longitude > MaxLongitude)
{
MaxLongitude = latLngVal.Longitude;
}
if (latLngVal.Latitude < MinLatitude)
{
MinLatitude = latLngVal.Latitude;
}
if (latLngVal.Latitude > MaxLatitude)
{
MaxLatitude = latLngVal.Latitude;
}
if (latLngVal.Value.HasValue)
{
if (double.IsNaN(latLngVal.Value.Value) ||
double.IsNegativeInfinity(latLngVal.Value.Value) ||
double.IsPositiveInfinity(latLngVal.Value.Value))
{
//TODO determine how to handle the "NaN", "NegativeInfinity",
//and "PositiveInfinity" input values for now we skip them
}
else
{
//bypass all the "NoData" (null) Plot value in the List.
contoursPointData.Add(pointShape, latLngVal.Value.Value);
if (latLngVal.Value.Value != NoDataValue)
{
if (latLngVal.Value.Value < MinVariableValue)
{
MinVariableValue = latLngVal.Value.Value;
}
if (latLngVal.Value.Value > MaxVariableValue)
{
MaxVariableValue = latLngVal.Value.Value;
}
}
if (!IsThereMoreThanOneValue)
{
if (uniqueValueCheck == NoDataValue)
{
uniqueValueCheck = latLngVal.Value.Value;
}
else if (uniqueValueCheck != latLngVal.Value.Value)
{
IsThereMoreThanOneValue = true;
}
}
if (!IsThereEnoughUniqueValues)
{
IsThereEnoughUniqueValues = true;
for (int index = 0; index < MinimumValuesRequiredToPlot; index++ )
{
if (valuesRequiredToPlot[index] == latLngVal.Value.Value)
{
IsThereEnoughUniqueValues = false;
break;
}
if (valuesRequiredToPlot[index] == NoDataValue)
{
valuesRequiredToPlot[index] = latLngVal.Value.Value;
IsThereEnoughUniqueValues = false;
break;
}
}
}
}
}
//else
//{
// //FIll the "NoData" (null) Plot values with Designated NoDataValue in the List.
// contoursPointData.Add(pointShape, NoDataValue);
//}
latLngVal = Plot.PlotData.GetLatLngVal();
}
}
double latitudeHeight = System.Math.Abs(MaxLatitude - MinLatitude);
double longitudeWidth = System.Math.Abs(MaxLongitude - MinLongitude);
CpPlotDataList plotDataList = Plot.PlotData as CpPlotDataList;
if (null != plotDataList)
{
GridCellRowCount = (plotDataList.LatitudeCellCount > 0)
? plotDataList.LatitudeCellCount : GridIsoLineCellRowCount;
GridCellColumnCount = (plotDataList.LongitudeCellCount > 0)
? plotDataList.LongitudeCellCount : GridIsoLineCellColumnCount;
MinVariableValue = Plot.PlotData.DataTable.MinVariableValue;
MaxVariableValue = Plot.PlotData.DataTable.MaxVariableValue;
//The CellWidth from the Plot needs units conversion - since it may not be in decimal degrees
CellWidth = (Plot.PlotData.CellWidth > 0.0d) ? Plot.PlotData.CellWidth :
Math.Max(longitudeWidth / GridCellColumnCount, latitudeHeight / GridCellRowCount);
RoundCellWidth = CellWidth / 10000.0d; //Round the index up by one-tenthousand cellWidth.
//CpPlotDataList - use the Min and Max value from Plot.
MinLatitude = plotDataList.MinLatitude - (CellWidth / 2.0d); //MinCenterLatitude - half cellwidth.
MinLongitude = plotDataList.MinLongitude - (CellWidth / 2.0d); //MinCenterLongitude - half cellwidth.
MaxLatitude = plotDataList.MaxLatitude + (CellWidth / 2.0d); //MinCenterLatitude + half cellwidth.
MaxLongitude = plotDataList.MaxLongitude + (CellWidth / 2.0d); //MinCenterLongitude + half cellwidth.
latitudeHeight = System.Math.Abs(MaxLatitude - MinLatitude);
longitudeWidth = System.Math.Abs(MaxLongitude - MinLongitude);
if (CellWidth > 0.0d &&
GridCellRowCount > 0 && GridCellColumnCount > 0)
{
latitudeHeight = CellWidth * GridCellRowCount;
longitudeWidth = CellWidth * GridCellColumnCount;
}
}
else
{
//CpPlotDataDict - use the Min and Max values from from loading the Dict Values above.
//Use CellWidth from the loaded PlotData.
CellWidth = Plot.PlotData.CellWidth;
RoundCellWidth = CellWidth / 10000.0d; //Round the index up(Positive) by one-tenthousand cellWidth.
MinLatitude = MinLatitude - (CellWidth / 2.0d); //MinCenterLatitude - half cellwidth.
MinLongitude = MinLongitude - (CellWidth / 2.0d); //MinCenterLongitude - half cellwidth.
MaxLatitude = MaxLatitude + (CellWidth / 2.0d); //MinCenterLatitude + half cellwidth.
MaxLongitude = MaxLongitude + (CellWidth / 2.0d); //MinCenterLongitude + half cellwidth.
latitudeHeight = System.Math.Abs(MaxLatitude - MinLatitude);
longitudeWidth = System.Math.Abs(MaxLongitude - MinLongitude);
GridCellRowCount = (int)((latitudeHeight + RoundCellWidth) / CellWidth); //Round up by CellWidth/10000.
GridCellColumnCount = (int)((longitudeWidth + RoundCellWidth) / CellWidth); //Round up by CellWidth/10000.
}
//Get User Preferences settings for PlotResolutionOptimazation.
GetUserPreferencesForPlotResoutionOptimization();
//Get the current drawing extent since we use that to generate the grid.
drawingExtent = ExtentHelper.GetDrawingExtent(
new RectangleShape(
MinLongitude, MaxLatitude, MaxLongitude, MinLatitude),
(float)longitudeWidth,
(float)latitudeHeight);
//Load Collections of Colors for the LineStyle and AreaStyle.
//Sets the LineWidth and PenLineDashStyle
//Calculate the isoLineLevels.
LoadColorCollections();
if (LineLevelsAndColors.Count <= 0)
{
string errorMsg = String.Format("There are no isoLine levels defined. The Coverage Plot will not have any lines. " +
"No plot can be generated for {0}.", plot.Title);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
logger.ErrorFormat(errorMsg);
return;
}
if (GridCellRowCount < 2 || GridCellColumnCount < 2)
{
string errorMsg = String.Format("The plot data contains only a single latitude or a single longitude value. " +
"At least two latitudes and two longitudes are required to draw isolines for a coverage plot. " +
"No plot can be generated for {0}.", plot.Title);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
logger.ErrorFormat(errorMsg);
return;
}
if (!IsThereMoreThanOneValue)
{
string errorMsg = String.Format("The plot data contains only a single value. At least two values are required "+
"to draw isolines for a coverage plot. " +
"No plot can be generated for {0}.", plot.Title);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
logger.ErrorFormat(errorMsg);
//return;
}
//if (!IsThereEnoughUniqueValues)
//{
// string errorMsg = String.Format("The plot data contains less than {1} unique values. " +
// "At least {1} unique values are required to draw isolines for a coverage plot. " +
// "No plot can be generated for {0}.", plot.Title, MinimumValuesRequiredToPlot);
// this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
// logger.ErrorFormat(errorMsg);
// return;
//}
if (null != AssociatedMap.IsoLineOverlay)
{
//Create the names for the layers and generate the layers.
LayerNameIsoLine = plot.Title;
LayerNameGridCells = GridCellsLayerName + plot.Title;
LayerNameIsoLineLabels = LabelsLayerName + plot.Title;
LayerNameIsoLinePlotNames = PlotNamesLayerName + plot.Title;
LayerNamePlotLegend = PlotLegendLayerName + plot.Title;
//Remove layers from previous construct if they exist.
RemovePlotLayersFromOverlay(plot.Title);
AssociatedMap.RaiseEventStatusBar(
new MapControl2DMap.StatusBarUpdateEventArgs { StatusText = "Generating isolines...", Cancel = false });
if (longitudeWidth / CellWidth < MaxNoOfCellsForSynchCalls &&
latitudeHeight / CellWidth < MaxNoOfCellsForSynchCalls)
{
//Should be fast enough for synchronous calls to generate isolines.
//Do the actual work of creating the IsoLines layers.
CreateIsoLineLayers();
AddIsoLineLayersToOverlay();
}
else
{
//Generate Isolines in asynchronous secondary thread.
this.LayerUpdateEvent += new LayerUpdateHandler(AddIsoLineLayersToOverlay);
////Do the actual work of creating the IsoLines layers.
LayerCreationDelegate layerCreation =
new LayerCreationDelegate(CreateIsoLineLayers);
IAsyncResult itfAR = layerCreation.BeginInvoke(
new AsyncCallback(CreateIsoLineLayersCompleteAsyncCallback), null);
Application.DoEvents();
}
}
}
catch (Exception ex)
{
string errorMsg = String.Format("Unable to create isolines. Exception: {0}", ex);
logger.ErrorFormat(errorMsg);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
}
}
#endregion
#region Methods
///
/// Get the User Preferences for Plot Resolution Optimization.
///
private void GetUserPreferencesForPlotResoutionOptimization()
{
//Get User Preference for Plot Resolution Optimization Grid Size.
PlotResolutionGridSize = GridCellOptimizationFaster;
int plotGridSize;
string plotResolutionGridSize = UserParameters.Instance.GetValue
(UserParameters.ParamNames.PlotResolutionOptimizationGridKnots);
if (!string.IsNullOrEmpty(plotResolutionGridSize))
{
if (int.TryParse(plotResolutionGridSize, out plotGridSize))
{
PlotResolutionGridSize = Convert.ToInt32(Math.Sqrt(plotGridSize));
}
}
IsPlotResolutionOptForSpeed = true;
// Read the User Parameter settings for plot resolution speed optimization.
if (UserParameters.Instance.GetValue
(UserParameters.ParamNames.PlotResolutionOptimizationForSpeed) == UserParameters.PlotResolutionOptForSpeed.Details)
{
IsPlotResolutionOptForSpeed = false;
}
IsPlotResolutionOptShowDialogPrompt = true;
// Read the User Parameter settings for plot resolution speed optimization.
if (UserParameters.Instance.GetValue
(UserParameters.ParamNames.PlotResolutionOptimizationShowDialogPrompt) == UserParameters.PlotResolutionOptShowDialogPrompt.False)
{
IsPlotResolutionOptShowDialogPrompt = false;
}
else
{
if (GridCellRowCount > PlotResolutionGridSize ||
GridCellColumnCount > PlotResolutionGridSize)
{
PlotResolutionPromptDialog dialog = new PlotResolutionPromptDialog(IsPlotResolutionOptForSpeed,
!IsPlotResolutionOptShowDialogPrompt);
if (dialog.ShowDialog() == DialogResult.Cancel)
{
return;
};
if (IsPlotResolutionOptForSpeed != dialog.radioButtonMapSpeed.Checked)
{
if (dialog.radioButtonMapSpeed.Checked)
{
UserParameters.Instance.SaveValue
(UserParameters.ParamNames.PlotResolutionOptimizationForSpeed,
UserParameters.PlotResolutionOptForSpeed.Speed);
}
else
{
UserParameters.Instance.SaveValue
(UserParameters.ParamNames.PlotResolutionOptimizationForSpeed,
UserParameters.PlotResolutionOptForSpeed.Details);
}
IsPlotResolutionOptForSpeed = dialog.radioButtonMapSpeed.Checked;
}
if (IsPlotResolutionOptShowDialogPrompt == dialog.checkBoxShowDialog.Checked)
{
if (dialog.checkBoxShowDialog.Checked)
{
UserParameters.Instance.SaveValue
(UserParameters.ParamNames.PlotResolutionOptimizationShowDialogPrompt,
UserParameters.PlotResolutionOptShowDialogPrompt.False);
}
else
{
UserParameters.Instance.SaveValue
(UserParameters.ParamNames.PlotResolutionOptimizationShowDialogPrompt,
UserParameters.PlotResolutionOptShowDialogPrompt.True);
}
}
}
}
}
///
/// Remove the layers for a plot from the overlay.
///
/// Title of the plot.
public void RemovePlotLayersFromOverlay(string plotTitle)
{
LayerOverlay isoLineOverlay = AssociatedMap.IsoLineOverlay;
if (isoLineOverlay != null)
{
LayerNameIsoLine = plotTitle;
LayerNameGridCells = GridCellsLayerName + plotTitle;
LayerNameIsoLineLabels = LabelsLayerName + plotTitle;
LayerNameIsoLinePlotNames = PlotNamesLayerName + plotTitle;
LayerNamePlotLegend = PlotLegendLayerName + plotTitle;
if (isoLineOverlay.Layers.Count > 0)
{
if (isoLineOverlay.Layers.Contains(LayerNameIsoLine))
{
isoLineOverlay.Layers[LayerNameIsoLine].Close();
isoLineOverlay.Layers.Remove(LayerNameIsoLine);
}
if (isoLineOverlay.Layers.Contains(LayerNameIsoLineLabels))
{
isoLineOverlay.Layers[LayerNameIsoLineLabels].Close();
isoLineOverlay.Layers.Remove(LayerNameIsoLineLabels);
}
if (isoLineOverlay.Layers.Contains(LayerNameIsoLinePlotNames))
{
isoLineOverlay.Layers[LayerNameIsoLinePlotNames].Close();
isoLineOverlay.Layers.Remove(LayerNameIsoLinePlotNames);
}
if (isoLineOverlay.Layers.Contains(LayerNameGridCells))
{
isoLineOverlay.Layers[LayerNameGridCells].Close();
isoLineOverlay.Layers.Remove(LayerNameGridCells);
}
if (AssociatedMap.WinformsMap1.AdornmentOverlay.Layers.Contains(LayerNamePlotLegend))
{
AssociatedMap.WinformsMap1.AdornmentOverlay.Layers[LayerNamePlotLegend].Close();
AssociatedMap.WinformsMap1.AdornmentOverlay.Layers.Remove(LayerNamePlotLegend);
}
}
}
}
///
/// Create the IsoLine Contours Layers.
///
private void CreateIsoLineLayers()
{
try
{
MapControl2DMapSuite.IsoLineSemaphore.WaitOne();
lock (stateLock)
{
logger.InfoFormat("Starting CreateGridFile 2D Plot Data File. {0} ", Plot.ObjectId);
//AssociatedMap.ProgressValue += 5;
//Application.DoEvents();
//Create a grid file based the current extent.
//if (Plot.IsVisibleBoundary)
//{
// CreateGridFile();
//}
//else
//{
StreamDictionaryToGridFile();
//Free up the memory from the dictionary after the GridFile is written.
contoursPointData = null;
//}
//AssociatedMap.ProgressValue += 5;
//Application.DoEvents();
if (IsThereEnoughUniqueValues)
{
logger.InfoFormat("Creating GridIsoLineLayer 2D Plot Data File. {0} ", Plot.ObjectId);
IsoLinesLayer = GetGridIsoLineLayer(LayerNameIsoLine);
//AssociatedMap.ProgressValue += 5;
//Application.DoEvents();
logger.InfoFormat("Creating GridIsoLineLabelsLayer 2D Plot Data File. {0} ", Plot.ObjectId);
IsoLineLabelsLayer = GetGridIsoLineLabelsLayer(LayerNameIsoLineLabels);
}
else
{
IsoLinesLayer = null;
IsoLineLabelsLayer = null;
}
//AssociatedMap.ProgressValue += 5;
//Application.DoEvents();
logger.InfoFormat("Creating GridIsoLinePlotNamesLayer 2D Plot Data File. {0} ", Plot.ObjectId);
IsoLinePlotNamesLayer = GetGridIsoLinePlotNamesLayer(LayerNameIsoLinePlotNames);
logger.InfoFormat("Creating GridFeatureLayer 2D Plot Data File. {0} ", Plot.ObjectId);
IsoLineFeatureLayer = GetGridFeatureLayer(LayerNameGridCells);
logger.InfoFormat("Creating 2D Plot Data File completed. {0} ", Plot.ObjectId);
//AssociatedMap.ProgressValue += 5;
//Application.DoEvents();
//Create a legend for this plot.
IsoLinesLegendLayer = CreateLegendLayer();
}
//Now Invode the method to add these layer to the IsoLineOverlay.
//if (null != LayerUpdateEvent) LayerUpdateEvent.Invoke();
////Serialize the IsoLines.
//FileStream isolineFileStream = null;
//try
//{
// string isolineFilePath = AssociatedMap.isoLinesOpenSaveInitialFolder + "\\" +
// "Isolines-" + Plot.ObjectId.ToString() + ".stream";
// isolineFileStream = new FileStream(isolineFilePath, FileMode.Create, FileAccess.ReadWrite);
// //Serialize (save) the ioslines to a file.
// iosLinesLayer.Open();
// Collection features = iosLinesLayer.GetIsoLineFeatures();
// BinaryFormatter formatter = new BinaryFormatter();
// formatter.Serialize(isolineFileStream, features);
// iosLinesLayer.Close();
//}
//finally
//{
// if (isolineFileStream != null) { isolineFileStream.Close(); }
//}
}
catch (Exception ex)
{
string errorMsg = String.Format("Unable to create isolines. Exception: {0}", ex);
logger.ErrorFormat(errorMsg);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
MessageBox.Show(string.Format("Unable to create isolines. Please see the STTI log file for additional information. {0}",
ex.Message), "IsoLines Error", MessageBoxButtons.OK);
}
finally
{
Application.DoEvents();
MapControl2DMapSuite.IsoLineSemaphore.Release();
}
}
///
/// Add the IsoLine Layers to the overlay.
///
private void CreateIsoLineLayersCompleteAsyncCallback(IAsyncResult itfAR)
{
if (this.AssociatedMap.WinformsMap1.InvokeRequired)
{
//Fire the event to have the overlays added.
this.AssociatedMap.WinformsMap1.Invoke(new MethodInvoker(LayerUpdateEvent));
}
}
///
/// Add the IsoLine Layers to the overlay.
///
private void AddIsoLineLayersToOverlay()
{
try
{
lock (stateLock)
{
LayerOverlay isoLineOverlay = AssociatedMap.IsoLineOverlay;
if (null != isoLineOverlay)
{
if (null != IsoLineFeatureLayer)
{
isoLineOverlay.Layers.Add(LayerNameGridCells, IsoLineFeatureLayer);
}
if (null != IsoLinePlotNamesLayer)
{
isoLineOverlay.Layers.Add(LayerNameIsoLinePlotNames, IsoLinePlotNamesLayer);
}
if (null != IsoLinesLegendLayer)
{
AssociatedMap.WinformsMap1.AdornmentOverlay.Layers.Add(LayerNamePlotLegend, IsoLinesLegendLayer);
}
if (IsThereEnoughUniqueValues)
{
if (null != IsoLineLabelsLayer)
{
isoLineOverlay.Layers.Add(LayerNameIsoLineLabels, IsoLineLabelsLayer);
}
if (null != IsoLinesLayer)
{
isoLineOverlay.Layers.Add(LayerNameIsoLine, IsoLinesLayer); // add on top of Fill layer
}
}
Plot.IsConstructed = true;
AssociatedMap.WinformsMap1.Overlays.MoveToTop(isoLineOverlay);
gridCellMatrix = null;
}
if (!AssociatedMap.RefreshWinformsMap())
{
RemovePlotLayersFromOverlay(Plot.Title);
Plot.IsConstructed = false;
}
logger.InfoFormat("Background Thread completed and map refreshed for 2D Plot Data File. {0}", Plot.ObjectId);
AssociatedMap.RaiseEventStatusBar(
new MapControl2DMap.StatusBarUpdateEventArgs { StatusText = "Completed Generating isolines...", Cancel = false });
}
}
catch (Exception ex)
{
string errorMsg = String.Format("Exception while creating Coverage Plot on the Map2D. Exception: {0}", ex);
logger.ErrorFormat(errorMsg);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
//if Refresh causes the exception remove this plot to prevent repeated exceptions.
//RemovePlotFromMapByName(info.Title);
}
finally
{
Application.DoEvents();
}
}
///
/// Create a grid file for the isoline contours.
///
private void CreateGridFile()
{
//Greate the grid definition based on the extent, cell size etc.
GridDefinition gridDefinition = new GridDefinition(drawingExtent,
CellWidth, NoDataValue, contoursPointData);
FileStream gridFileStream = null;
try
{
gridFileStream = new FileStream(gridFilePath, FileMode.Create, FileAccess.ReadWrite);
//Generate the grid based on Inverse Distance Weighted interpolation model.
//You can define your own model if needed.
GridFeatureSource.GenerateGrid(gridDefinition,
new InverseDistanceWeightedGridInterpolationModel(2, double.MaxValue), gridFileStream);
}
finally
{
if (gridFileStream != null) { gridFileStream.Close(); }
}
}
///
/// Stream a grid file for the isoline contours from the Dictionary of Contour Points.
///
private void StreamDictionaryToGridFile()
{
StreamWriter gridFileStream = null;
try
{
double cellWidth = CellWidth;
int gridCellRowCountOptimized = GridCellRowCount;
int gridCellColumnCountOptimized = GridCellColumnCount;
int gridCellCountModulus = 0;
if (IsPlotResolutionOptForSpeed &&
(GridCellRowCount > PlotResolutionGridSize ||
GridCellColumnCount > PlotResolutionGridSize))
{
gridCellCountModulus = Math.Max(GridCellRowCount / PlotResolutionGridSize,
GridCellColumnCount / PlotResolutionGridSize);
gridCellRowCountOptimized = (GridCellRowCount / gridCellCountModulus) + 1;
gridCellColumnCountOptimized = (GridCellColumnCount / gridCellCountModulus) + 1;
double latitudeHeight = System.Math.Abs(MaxLatitude - MinLatitude);
double longitudeWidth = System.Math.Abs(MaxLongitude - MinLongitude);
cellWidth =
Math.Max(longitudeWidth / gridCellColumnCountOptimized,
latitudeHeight / gridCellRowCountOptimized);
}
gridCellMatrix = new GridCell[gridCellRowCountOptimized, gridCellColumnCountOptimized];
gridFileStream = new StreamWriter(gridFilePath);
gridFileStream.WriteLine("ncols " + gridCellColumnCountOptimized.ToString());
gridFileStream.WriteLine("nrows " + gridCellRowCountOptimized.ToString());
gridFileStream.WriteLine("xllcorner " + MinLongitude.ToString());
gridFileStream.WriteLine("yllcorner " + MinLatitude.ToString());
gridFileStream.WriteLine("cellsize " + cellWidth.ToString());
gridFileStream.WriteLine("NODATA_Value " + NoDataValue.ToString());
//Dump the Dictionary into a two dimensional array.
double[,] arraypoints = new double[gridCellRowCountOptimized, gridCellColumnCountOptimized];
for (int rindex = 0; rindex < gridCellRowCountOptimized; rindex++)
{
for (int cindex = 0; cindex < gridCellColumnCountOptimized; cindex++)
{
//Initialize all array values with NoDataValue.
arraypoints[rindex, cindex] = NoDataValue;
gridCellMatrix[rindex, cindex] =
new GridCell(MinLongitude + (cellWidth * rindex), MinLatitude + (cellWidth * cindex), NoDataValue);
}
}
int gridCellRowOffset = GridCellRowCount - 1;
foreach (KeyValuePair contourPoint in contoursPointData)
{
//Maximum Latitude to the top of the array so flip the latitude index. //Round by CellWidth/10000
int rowIndex = gridCellRowOffset - (int)Math.Abs(((contourPoint.Key.Y - MinLatitude) + RoundCellWidth) / CellWidth);
int colIndex = (int)Math.Abs(((contourPoint.Key.X - MinLongitude) + RoundCellWidth) / CellWidth);
if (rowIndex < 0 || rowIndex >= GridCellRowCount || colIndex < 0 || colIndex >= GridCellColumnCount)
{
System.Diagnostics.Debug.WriteLine("Error in coord indices: Lat: {0} Min: {1} Lng: {2} Min: {3} " +
"Cell: {4} Offset: {5} row: {6} col: {7}",
contourPoint.Key.Y, MinLatitude, contourPoint.Key.X, MinLongitude,
CellWidth, gridCellRowOffset, rowIndex, colIndex);
}
else
{
if (gridCellCountModulus > 0)
{
//Skip all the values between Indices with a modulus of 0
//so that the Grid will be every second or third or modulus value.
if (rowIndex % gridCellCountModulus == 0 &&
colIndex % gridCellCountModulus == 0)
{
int rowIndexMod = rowIndex / gridCellCountModulus;
int colIndexMod = colIndex / gridCellCountModulus;
arraypoints[rowIndexMod, colIndexMod] = contourPoint.Value;
gridCellMatrix[rowIndexMod, colIndexMod] =
new GridCell(contourPoint.Key.X, contourPoint.Key.Y, contourPoint.Value);
}
}
else
{
arraypoints[rowIndex, colIndex] = contourPoint.Value;
gridCellMatrix[rowIndex, colIndex] =
new GridCell(contourPoint.Key.X, contourPoint.Key.Y, contourPoint.Value);
}
}
}
//Stream the array rows with space separator between values.
for (int rindex = 0; rindex < gridCellRowCountOptimized; rindex++)
{
System.Text.StringBuilder line = new StringBuilder();
for (int cindex = 0; cindex < gridCellColumnCountOptimized; cindex++)
{
if (cindex > 0) line.Append(CpConstants.Spacer);
line.Append(arraypoints[rindex, cindex].ToString());
}
gridFileStream.WriteLine(line);
}
}
catch (Exception ex)
{
string errorMsg = String.Format("Exception while streaming Coverage Plot on the Map2D. Exception: {0}", ex);
logger.ErrorFormat(errorMsg);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
//We cannot continue without the grid matrix and gridfile
//so throw the exception so the caller will bypass generating isolines.
throw ex;
}
finally
{
if (gridFileStream != null) { gridFileStream.Close(); }
}
}
///
/// Get the layer for the grid IsoLine.
///
/// The name used for this Isolines layer.
/// Layer for GridIsoLineLayer.
private Layer GetGridIsoLineLayer(string layerName)
{
List boundaries = Plot.PlotData.DataTable.CpReportNode.CpBoundaries;
//Load the grid into the GridIsoLineLayer using the number of breaks
//defined by the isoLineLevels.
if (null == boundaries || (boundaries.Count == 1 && boundaries[0].ShapeEnum == McShapeEnum.Rectangle))
{
//GridIsoLineLayer isoLineLayer = new GridIsoLineLayer(gridFilePath, LineLevelsAndColors.Keys);
InMemoryGridIsoLineLayer isoLineLayer = new InMemoryGridIsoLineLayer(gridCellMatrix, LineLevelsAndColors.Keys);
isoLineLayer.Name = layerName;
//Setup a class break style based on the isoline levels and the colors.
ClassBreakStyle classBreakLineStyle = new ClassBreakStyle(isoLineLayer.DataValueColumnName);
foreach (double index in LineLevelsAndColors.Keys)
{
classBreakLineStyle.ClassBreaks.Add(new ClassBreak(index, GetLineStyle(index)));
}
isoLineLayer.CustomStyles.Add(classBreakLineStyle);
return isoLineLayer;
}
else
{
AreaBaseShape boundaryAreaShape = drawingExtent;
foreach (McShape cpBoundary in boundaries)
{
switch (cpBoundary.ShapeEnum)
{
case McShapeEnum.Circle:
McCircle circle = cpBoundary as McCircle;
if (null != circle)
{
PointShape centerPoint =
AssociatedMap.ConvertLngLatToPointShape(
circle.Center.Longitude_decdeg, circle.Center.Latitude_decdeg);
EllipseShape ellipseShape = new EllipseShape(centerPoint,
circle.Radius_km,
AssociatedMap.GeographyMapUnit, DistanceUnit.Kilometer);
ellipseShape.Id = circle.ObjectId.ToString();
// Adjust the clipping scaleDown percentage based
// the coarseness of the Cellwidth. Calculate the percentage
// as a ratio of the cellWidth to the circle radius.
EGL.Point center = new EGL.Point(circle.Center.Latitude_decdeg*EGL.Math.Degree2Rad,
circle.Center.Longitude_decdeg*EGL.Math.Degree2Rad);
double distanceRad = center.DistanceRad(circle.Radius_km);
//Scale the isolines down by a percentage of the cellwidth size
//divided by the radius of the circle in radians
//plus a rounding value to assure the percentage is greater than the ratio.
double scaleDownPercent = ((CellWidth * EGL.Math.Degree2Rad) /
(distanceRad * Math.Sqrt(2.0d))) * 100.0d +1.0;
ellipseShape.ScaleDown(scaleDownPercent);
boundaryAreaShape = ellipseShape;
}
break;
case McShapeEnum.Polyline:
McPolyline polyline = cpBoundary as McPolyline;
if (null != polyline)
{
PolygonShape polygonShape = AssociatedMap.
ConvertMmPointTimeListToPolygonShape(
polyline.PointTimeList, polyline.ObjectId.ToString());
polygonShape.ScaleDown(2.0);
MultipolygonShape multiPolygonShape = boundaryAreaShape as MultipolygonShape;
if (null == multiPolygonShape)
{
multiPolygonShape = new MultipolygonShape();
}
multiPolygonShape.Polygons.Add(polygonShape);
boundaryAreaShape = multiPolygonShape;
}
break;
case McShapeEnum.Rectangle:
McRectangle rectangle = cpBoundary as McRectangle;
if (null != rectangle)
{
boundaryAreaShape = new RectangleShape(
AssociatedMap.ConvertLngLatToPointShape(
rectangle.LowerLeft.Longitude_decdeg, rectangle.UpperRight.Latitude_decdeg),
AssociatedMap.ConvertLngLatToPointShape(
rectangle.UpperRight.Longitude_decdeg, rectangle.LowerLeft.Latitude_decdeg));
}
break;
default:
boundaryAreaShape = drawingExtent;
break;
}
}
InMemoryFeatureLayer isoFeatureLayer = new InMemoryFeatureLayer();
isoFeatureLayer.FeatureSource.Open();
isoFeatureLayer.Columns.Add(new FeatureSourceColumn("DataValueColumnName"));
isoFeatureLayer.Name = layerName;
Collection isoFeatures = IsoLineLayer.GetIsoFeatures(gridCellMatrix,
LineLevelsAndColors.Keys, "DataValueColumnName", IsoLineType.LinesOnly);
foreach (Feature feature in isoFeatures)
{
LineShape lineShape = (LineShape) feature.GetShape();
MultilineShape multilineShape = lineShape.GetIntersection(boundaryAreaShape);
if (multilineShape.Lines.Count < 1)
{
continue;
}
Feature multiLineFeature = new Feature(multilineShape);
multiLineFeature.ColumnValues.Add("DataValueColumnName", feature.ColumnValues["DataValueColumnName"]);
isoFeatureLayer.InternalFeatures.Add(multiLineFeature);
}
isoFeatureLayer.FeatureSource.Close();
//Setup a class break style based on the isoline levels and the colors.
ClassBreakStyle classBreakLineStyle = new ClassBreakStyle("DataValueColumnName");
foreach (double index in LineLevelsAndColors.Keys)
{
classBreakLineStyle.ClassBreaks.Add(new ClassBreak(index, GetLineStyle(index)));
}
isoFeatureLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(classBreakLineStyle);
isoFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
return isoFeatureLayer;
}
}
///
/// Get the layer for the grid IsoLine labels.
///
/// The name used for this Isolines layer.
/// Layer for GridIsoLineLayer.
private IsoLineLayer GetGridIsoLineLabelsLayer(string layerName)
{
//Create labels on a new layer for the isoLineLevels
//GridIsoLineLayer isoLineLayer = new GridIsoLineLayer(gridFilePath, LineLevelsAndColors.Keys);
InMemoryGridIsoLineLayer isoLineLayer = new InMemoryGridIsoLineLayer(gridCellMatrix, LineLevelsAndColors.Keys);
isoLineLayer.Name = layerName;
//Create the text styles to label the lines
TextStyle textStyle = TextStyles.CreateSimpleTextStyle(isoLineLayer.DataValueColumnName,
"Arial", 8, DrawingFontStyles.Bold, GetTextColor(), 0, 0);
textStyle.OverlappingRule = LabelOverlappingRule.NoOverlapping;
textStyle.SplineType = SplineType.StandardSplining;
textStyle.DuplicateRule = LabelDuplicateRule.UnlimitedDuplicateLabels;
textStyle.TextLineSegmentRatio = 9999999;
textStyle.FittingLineInScreen = true;
textStyle.SuppressPartialLabels = true;
double variableRange = LineLevelsAndColors.Count + 1;
if (null != Plot)
{
isoLineLayer.IsVisible = Plot.IsVisibleLabels;
if (null != Plot.PlotData && null != Plot.PlotData.VariableGraphicProperties)
{
variableRange = Math.Abs(Plot.PlotData.VariableGraphicProperties.MaxVariableValue -
Plot.PlotData.VariableGraphicProperties.MinVariableValue);
}
}
if (LineLevelsAndColors.Count < variableRange)
{
textStyle.NumericFormat = "0.#";
}
else
{
textStyle.NumericFormat = "0.###";
}
isoLineLayer.CustomStyles.Add(textStyle);
return isoLineLayer;
}
///
/// Get the layer for the grid IsoLine Plot Names.
///
/// The name used for this Isolines layer.
/// Layer for GridIsoLineLayer.
private FeatureLayer GetGridIsoLinePlotNamesLayer(string layerName)
{
//Load a new GridFeatureLayer based on the current grid file.
InMemoryFeatureLayer gridFeatureLayer = new InMemoryFeatureLayer();
gridFeatureLayer.Name = layerName;
//Setup a TextStyle for the plot title.
TextStyle textStyle = TextStyles.CreateSimpleTextStyle("Title", "Arial", 8,
DrawingFontStyles.Regular, GetTextColor(), 0, 4);
textStyle.OverlappingRule = LabelOverlappingRule.AllowOverlapping;
textStyle.SplineType = SplineType.StandardSplining;
textStyle.DuplicateRule = LabelDuplicateRule.UnlimitedDuplicateLabels;
textStyle.TextLineSegmentRatio = 9999999;
textStyle.FittingLineInScreen = true;
textStyle.SuppressPartialLabels = true;
textStyle.PointPlacement = PointPlacement.UpperCenter;
//Update the first feature in the gridFeatureLayer with the Plot.Title
gridFeatureLayer.FeatureSource.Open();
PointShape latLngPointShape = AssociatedMap.ConvertLngLatToPointShape(
MinLongitude + (MaxLongitude - MinLongitude) / 2, //Center by longitude.
MaxLatitude); // + (MaxLatitude - MinLatitude) / 20); //Lat plus percent lat.
gridFeatureLayer.FeatureSource.BeginTransaction();
gridFeatureLayer.FeatureSource.AddFeature(latLngPointShape);
gridFeatureLayer.FeatureSource.CommitTransaction();
Collection gridFeatures = gridFeatureLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns);
if (gridFeatures.Count > 0)
{
if (null != Plot.PlotData.VariableGraphicProperties &&
!String.IsNullOrEmpty(Plot.PlotData.VariableGraphicProperties.PlotLabel))
{
textStyle.LabelPositions.Add(
gridFeatureLayer.FeatureSource.GetAllFeatures(
ReturningColumnsType.AllColumns)[0].Id,
new WorldLabelingCandidate(Plot.PlotData.VariableGraphicProperties.PlotLabel,
latLngPointShape));
}
else
{
textStyle.LabelPositions.Add(
gridFeatureLayer.FeatureSource.GetAllFeatures(
ReturningColumnsType.AllColumns)[0].Id,
new WorldLabelingCandidate(
Plot.Title.Substring(0, Plot.Title.IndexOf(CpConstants.StartBracket)),
latLngPointShape));
}
}
gridFeatureLayer.FeatureSource.Close();
gridFeatureLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(textStyle);
gridFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
gridFeatureLayer.IsVisible = Plot.IsVisiblePlotNames;
gridFeatureLayer.Close();
return gridFeatureLayer;
}
///
/// Get the layer for the grid Feature layer.
///
/// The name used for this Isolines layer.
/// Layer for GridFeatureLayer.
private FeatureLayer GetGridFeatureLayer(string layerName)
{
//Load a new GridFeatureLayer based on the current grid file.
GridFeatureLayer gridFeatureLayer = new GridFeatureLayer(gridFilePath);
//InMemoryGridFeatureLayer gridFeatureLayer = new InMemoryGridFeatureLayer(gridCellMatrix);
gridFeatureLayer.Name = layerName;
//Create a class break style.
ClassBreakStyle classBreakLineStyle = new ClassBreakStyle(gridFeatureLayer.DataValueColumnName);
if (FillLevelsAndColors.Count > 0)
{
double holdFillLevelKey = double.MinValue;
//Setup a class break style based on the isoline levels and the colors.
foreach (double index in FillLevelsAndColors.Keys)
{
if (index <= MinVariableValue)
{
//This will bypass all threshold values less than MinVariableValue.
holdFillLevelKey = index;
}
else
{
AreaStyle fillAreaStyle = GetAreaStyle(index);
//for BelowContourLineLevel use color assigned to the previous level.
if (holdFillLevelKey == ThresholdDefault.FillAllValue)
{
classBreakLineStyle.ClassBreaks.Add(new ClassBreak(MaxVariableValue + EGL.Math.Eps,
fillAreaStyle));
}
else if (holdFillLevelKey == MinVariableValue)
{
classBreakLineStyle.ClassBreaks.Add(new ClassBreak(MinVariableValue - EGL.Math.Eps,
fillAreaStyle));
}
else
{
classBreakLineStyle.ClassBreaks.Add(new ClassBreak(holdFillLevelKey,
fillAreaStyle));
}
holdFillLevelKey = index;
}
}
//For BelowContourLineLevel add the final LineLevel with the Transparent color.
classBreakLineStyle.ClassBreaks.Add(new ClassBreak(holdFillLevelKey,
GetAreaStyle(MinVariableValue)));
gridFeatureLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(classBreakLineStyle);
}
gridFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
gridFeatureLayer.IsVisible = Plot.IsVisibleFill;
gridFeatureLayer.Close();
return gridFeatureLayer;
}
///
/// Create the Legend Items for the plot individual thresholds
///
private LegendAdornmentLayer CreateLegendLayer()
{
try
{
MapLegendAdornmentLayer legendAdornmentLayer = new MapLegendAdornmentLayer(250, 250, 15, 0);
if (null != AssociatedMap &&
null != legendAdornmentLayer &&
null != legendAdornmentLayer.LegendItems &&
Plot.PlotData.VariableGraphicProperties.AreIndividualLinesDisplayed &&
null != Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList &&
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList.Count > 0)
{
legendAdornmentLayer.Name = LayerNamePlotLegend;
legendAdornmentLayer.BackgroundMask.FillSolidBrush = new GeoSolidBrush(GeoColor.SimpleColors.Silver);
legendAdornmentLayer.Transparency = LegendTransparency;
legendAdornmentLayer.LegendItems.Clear();
//Add Plot Label as a Legend title with reportComment (RelTime) if defined.
legendAdornmentLayer.LegendItems.Add(CreateLegendTitle());
//Add LegendItems for the threshold LineStyles.
foreach (ThresholdDefault threshold in
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList)
{
if (Plot.PlotData.VariableGraphicProperties.CpFillChoices == CpFillChoicesEnum.NoFill ||
threshold.ContourLineColor != threshold.FillTrajLinkColor ||
threshold.ContourLineGraphicProperties.Opacity != threshold.FillGraphicProperties.Opacity)
{
LineStyle lineStyle = GetLineStyle(threshold.ThresholdValue);
if (lineStyle.OuterPen.Color.AlphaComponent > 0)
{
LegendItem legendItem = new LegendItem();
legendItem.TopPadding = 0;
legendItem.BottomPadding = 0;
legendItem.ImageTopPadding = 2;
legendItem.ImageBottomPadding = 2;
legendItem.Height = legendItem.ImageTopPadding +
legendItem.ImageBottomPadding + legendItem.ImageHeight;
legendItem.ImageStyle = lineStyle;
legendItem.TextStyle = new TextStyle(
FormatThresholdValue(threshold.ThresholdValue),
new GeoFont("Arial", 8),
new GeoSolidBrush(GeoColor.SimpleColors.DarkBlue));
legendAdornmentLayer.LegendItems.Add(legendItem);
}
}
}
//Add LegendItems for the Threshold Fill AreaStyles when IndividualLinesFill is set.
if (Plot.PlotData.VariableGraphicProperties.CpFillChoices ==
CpFillChoicesEnum.IndividualLinesFill &&
null != Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList &&
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList.Count > 0)
{
string currentThresholdRange = string.Empty;
string previousThresholdValue = string.Empty;
int thresholdIndex = 0;
foreach (ThresholdDefault threshold in
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList)
{
if (string.IsNullOrEmpty(previousThresholdValue))
{
currentThresholdRange = CpConstants.StartAngleBracket + CpConstants.Spacer +
FormatThresholdValue(threshold.ThresholdValue);
}
else if (thresholdIndex >=
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList.Count - 1)
{
currentThresholdRange = CpConstants.EndAngleBracket + CpConstants.Spacer +
previousThresholdValue;
}
else
{
currentThresholdRange = CpConstants.StartBracket +
previousThresholdValue + CpConstants.ColonSeparator +
FormatThresholdValue(threshold.ThresholdValue) + CpConstants.EndBracket;
}
previousThresholdValue = FormatThresholdValue(threshold.ThresholdValue);
thresholdIndex++;
AreaStyle fillAreaStyle = GetAreaStyle(threshold.ThresholdValue);
if (fillAreaStyle.FillSolidBrush.Color.AlphaComponent > 0)
{
LegendItem legendItem = new LegendItem();
legendItem.TopPadding = 0;
legendItem.BottomPadding = 0;
legendItem.ImageTopPadding = 2;
legendItem.ImageBottomPadding = 2;
legendItem.Height = legendItem.ImageTopPadding +
legendItem.ImageBottomPadding + legendItem.ImageHeight;
legendItem.ImageStyle = fillAreaStyle;
legendItem.TextStyle = new TextStyle(
currentThresholdRange,
new GeoFont("Arial", 8),
new GeoSolidBrush(GeoColor.SimpleColors.DarkBlue));
legendAdornmentLayer.LegendItems.Add(legendItem);
}
}
}
if (legendAdornmentLayer.LegendItems.Count > 1)
{
legendAdornmentLayer.Height = 30 + legendAdornmentLayer.LegendItems.Count *
(legendAdornmentLayer.LegendItems[1].Height +
legendAdornmentLayer.LegendItems[1].BottomPadding +
legendAdornmentLayer.LegendItems[1].TopPadding);
legendAdornmentLayer.Width = (legendAdornmentLayer.LegendItems[0].Width +
legendAdornmentLayer.LegendItems[0].LeftPadding +
legendAdornmentLayer.LegendItems[0].RightPadding);
}
legendAdornmentLayer.IsVisible = Plot.IsVisibleLegend;
return legendAdornmentLayer;
}
}
catch (Exception ex)
{
string errorMsg = String.Format("Exception while creating Legend for the plot. Exception: {0}", ex);
logger.ErrorFormat(errorMsg);
this.AssociatedMap.LogMessage(MessageLevel.Info, string.Empty, errorMsg);
}
return null;
}
///
/// Determine if threshold value should be exponential notation or just ToString().
///
///
///
private string FormatThresholdValue(double thresholdValue)
{
if ((thresholdValue != 0.0 &&
thresholdValue > -.0001 && thresholdValue < .0001)
|| thresholdValue < -10000 || thresholdValue > 10000)
{
return thresholdValue.ToString("e3",
System.Globalization.CultureInfo.InvariantCulture);
}
return thresholdValue.ToString();
}
///
/// Create the Legend Items for the plot individual thresholds
///
private LegendItem CreateLegendTitle()
{
LegendItem legendTitle = new LegendItem();
try
{
if (null != Plot.PlotData.DataTable &&
null != Plot.PlotData.DataTable.CpReportNode)
{
StringBuilder layerTitle = new StringBuilder();
string title = string.Empty;
if (null != Plot.PlotData.VariableGraphicProperties &&
!String.IsNullOrEmpty(Plot.PlotData.VariableGraphicProperties.PlotLabel))
{
int length = Plot.PlotData.VariableGraphicProperties.PlotLabel.IndexOf(CpConstants.StartBracket);
if (length > 0)
{
title = Plot.PlotData.VariableGraphicProperties.PlotLabel.Substring(0, length);
}
else
{
title = Plot.PlotData.VariableGraphicProperties.PlotLabel;
}
}
else
{
int length = Plot.Title.IndexOf(CpConstants.StartBracket);
if (length > 0)
{
title = Plot.Title.Substring(0, length);
}
else
{
title = Plot.Title;
}
}
if (null != Plot.PlotData.VariableGraphicProperties &&
!String.IsNullOrEmpty(Plot.PlotData.VariableGraphicProperties.VariableUnits))
{
title = title + CpConstants.Spacer + CpConstants.LeftParens +
Plot.PlotData.VariableGraphicProperties.VariableUnits +
CpConstants.RightParens;
}
if (title.Length > MaxCharLegendTitle)
{
//If title is longer than MaxCharLegendTitle char, split the title into multiple lines by
//inserting a newline "/n" at word wrap of less than 30 char.
int indexstart = 0;
while (indexstart < title.Length)
{
int indexend = MaxCharLegendTitle;
if (indexstart + MaxCharLegendTitle > title.Length)
{
indexend = title.Length - indexstart;
layerTitle.Append(title.Substring(indexstart, indexend));
indexstart = title.Length;
}
else
{
int indexendspacer =
title.Substring(indexstart, indexend).LastIndexOf(CpConstants.Spacer);
if (indexendspacer > 0)
{
layerTitle.Append(title.Substring(indexstart, indexendspacer));
layerTitle.Append("\n");
indexstart += indexendspacer;
}
else if (indexendspacer <= 0)
{
layerTitle.Append(title.Substring(indexstart, indexend));
layerTitle.Append("\n");
indexstart += indexend;
}
}
}
}
else
{
layerTitle.Append(title);
}
if (null != Plot.PlotData.DataTable.CpReportNode &&
!string.IsNullOrEmpty(Plot.PlotData.DataTable.CpReportNode.ReportComment))
{
layerTitle.Append("\n"); //always start time on next line
layerTitle.Append(Plot.PlotData.DataTable.CpReportNode.ReportComment);
}
GeoFont titleFont = new GeoFont("Arial", 7, DrawingFontStyles.Bold);
GdiPlusGeoCanvas test = new GdiPlusGeoCanvas();
float textWidth = test.MeasureText(layerTitle.ToString(), titleFont).Width;
legendTitle.TextStyle = new TextStyle(layerTitle.ToString(),
titleFont, new GeoSolidBrush(GeoColor.SimpleColors.DarkRed));
legendTitle.BackgroundMask = new AreaStyle(new GeoSolidBrush(GeoColor.SimpleColors.PastelBlue));
legendTitle.TextLeftPadding = 3;
legendTitle.TextRightPadding = 3;
legendTitle.Width = textWidth + legendTitle.TextLeftPadding + (legendTitle.TextRightPadding * 2);
legendTitle.Height = 35;
legendTitle.LeftPadding = 3;
legendTitle.RightPadding = 3;
legendTitle.TopPadding = 2;
legendTitle.BottomPadding = 5;
legendTitle.ImageWidth = 0;
legendTitle.ImageHeight = 0;
legendTitle.ImageLeftPadding = 0;
legendTitle.ImageRightPadding = 0;
//This dead code adds an icon to the legned title;
//legendTitle.ImageWidth = 16;
//legendTitle.ImageHeight = 16;
//legendTitle.ImageLeftPadding = 2;
//legendTitle.ImageRightPadding = 2;
//System.Drawing.Image dragdrop = global::MapControl2d.Properties.Resources.cursor_drag_arrow;
//MemoryStream stream = new MemoryStream();
//dragdrop.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
//legendTitle.ImageStyle = new PointStyle(new GeoImage(stream));
}
}
catch (Exception ex)
{
string errorMsg = String.Format("Exception while creating Legend title for the plot. Exception: {0}", ex);
logger.ErrorFormat(errorMsg);
}
return legendTitle;
}
///
/// Load the Color Collections for the LineStyle and AreaStyle breaks.
/// Sets the LineWidth, PenLineDashStyle, Line Opacity and Fill Opacity.
/// Calculate the isoLineLevels.
///
private void LoadColorCollections()
{
LineLevelsAndColors = new SortedDictionary();
FillLevelsAndColors = new SortedDictionary();
GridLineLevelCount = 0;
if (Plot.PlotData.VariableGraphicProperties.IsLineSetDisplayed)
{
//Add the IsoLineLevels and Line Color as Specified by the ContourLineSet.
if (null != Plot.PlotData.VariableGraphicProperties.ContourLineSetDefaults &&
Plot.PlotData.VariableGraphicProperties.ContourLineSetDefaults.LevelCount > 0)
{
ContourLineSetDefaults contourLineSet =
Plot.PlotData.VariableGraphicProperties.ContourLineSetDefaults;
GridLineLevelCount += contourLineSet.LevelCount;
GeoColor lineColorStart = new GeoColor(
contourLineSet.MinLevelColor.R,
contourLineSet.MinLevelColor.G,
contourLineSet.MinLevelColor.B);
GeoColor lineColorEnd = new GeoColor(
contourLineSet.MaxLevelColor.R,
contourLineSet.MaxLevelColor.G,
contourLineSet.MaxLevelColor.B);
//If only a single lineColor is given, generate a set of colors in the Hue family.
Collection lineColors = GeoColor.GetColorsInHueFamily(lineColorStart,
GridLineLevelCount);
if (!lineColorStart.Equals(lineColorEnd))
{
//Create a series of colors from blue to red that we will use for the isoLine breaks.
lineColors = GeoColor.GetColorsInQualityFamily(lineColorStart, lineColorEnd,
GridLineLevelCount, ColorWheelDirection.CounterClockwise);
}
//The IsoLineLevels are calculated by dividing the Range by the NumberOfLineLevels.
double incrementLevels = (contourLineSet.MaxLevel - contourLineSet.MinLevel) /
(double) contourLineSet.LevelCount;
for (int index = 0; index < contourLineSet.LevelCount; index++)
{
double lineLevel = contourLineSet.MinLevel +
(incrementLevels * (double) index);
//Use all the same color for the lineLevels for the ContourLineSet.
if (!LineLevelsAndColors.ContainsKey(lineLevel))
{
LineLevelsAndColors.Add(lineLevel, new GraphicColorProperties()
{
Color = System.Drawing.Color.FromArgb(
lineColors[index].RedComponent,
lineColors[index].GreenComponent,
lineColors[index].BlueComponent),
Pattern = contourLineSet.ContourLineGraphicProperties.Pattern,
Opacity = contourLineSet.ContourLineGraphicProperties.Opacity,
LineWidth = contourLineSet.ContourLineGraphicProperties.LineWidth,
IsFill = contourLineSet.ContourLineGraphicProperties.IsFill,
});
}
}
}
}
//Now add all the individual ContourLine settings to any already added from ContourLineSet.
if (Plot.PlotData.VariableGraphicProperties.AreIndividualLinesDisplayed &&
null != Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList &&
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList.Count > 0)
{
//Add the count of the Individual ContourLines to LineLevel Count.
GridLineLevelCount +=
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList.Count;
foreach (
ThresholdDefault threshold in
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList)
{
//Do not add LineLevel if it is a duplicate or if the
//DashStyle was the special case of "NoLine".
if (!LineLevelsAndColors.ContainsKey(threshold.ThresholdValue) &&
threshold.ContourLineGraphicProperties.Pattern !=
GraphicConstants.StyleNoLine)
{
LineLevelsAndColors.Add(threshold.ThresholdValue,
new GraphicColorProperties()
{
Color = threshold.ContourLineColor,
Pattern = threshold.ContourLineGraphicProperties.Pattern,
Opacity = threshold.ContourLineGraphicProperties.Opacity,
LineWidth = threshold.ContourLineGraphicProperties.LineWidth,
IsFill = threshold.ContourLineGraphicProperties.IsFill,
});
}
}
}
//Add one extra value for LineColors so that the minimum Line Value will be drawn.
LineLevelsAndColors.Add(double.MinValue, new GraphicColorProperties()
{
Color = GraphicConstants.DefaultLineColor,
Pattern = GraphicConstants.DefaultLineDashStyle.ToString(),
Opacity = GraphicConstants.DefaultLineOpacityPercent,
IsFill = false,
});
//Now create the Fill Levels and Colors.
//Add one extra value for FillColors to fill outside of lines (below the contour line).
if (!FillLevelsAndColors.ContainsKey(MinVariableValue))
{
FillLevelsAndColors.Add(MinVariableValue, new GraphicColorProperties()
{
//We expect these default to be reasonable
//i.e. Transparent and Opacity = 0 means no fill will be visible.
Color = GraphicConstants.DefaultFillColor,
Pattern = GraphicConstants.StyleSolid,
Opacity = GraphicConstants.DefaultFillNoOpacityPercent,
LineWidth = GraphicConstants.DefaultLineWidth,
IsFill = true,
});
}
if (Plot.PlotData.VariableGraphicProperties.CpFillChoices ==
CpFillChoicesEnum.LineSetFill)
{
//Add the IsoLineLevels and Fill Color as Specified by the ContourLineSet.
if (null != Plot.PlotData.VariableGraphicProperties.ContourLineSetDefaults &&
Plot.PlotData.VariableGraphicProperties.ContourLineSetDefaults.LevelCount > 0)
{
ContourLineSetDefaults contourLineSet =
Plot.PlotData.VariableGraphicProperties.ContourLineSetDefaults;
GeoColor lineColorStart = new GeoColor(
contourLineSet.MinLevelColor.R,
contourLineSet.MinLevelColor.G,
contourLineSet.MinLevelColor.B);
GeoColor lineColorEnd = new GeoColor(
contourLineSet.MaxLevelColor.R,
contourLineSet.MaxLevelColor.G,
contourLineSet.MaxLevelColor.B);
//If only a single lineColor is given, generate a set of colors in the Hue family.
Collection lineColors = GeoColor.GetColorsInHueFamily(lineColorStart,
contourLineSet.LevelCount + 1);
if (!lineColorStart.Equals(lineColorEnd))
{
//Create a series of colors from blue to red that we will use for the isoLine breaks.
lineColors = GeoColor.GetColorsInQualityFamily(lineColorStart, lineColorEnd,
contourLineSet.LevelCount + 1, ColorWheelDirection.CounterClockwise);
}
//The IsoLineLevels are calculated by dividing the Range by the NumberOfLineLevels.
double incrementLevels = (contourLineSet.MaxLevel - contourLineSet.MinLevel) /
(double) contourLineSet.LevelCount;
for (int index = 0; index < contourLineSet.LevelCount + 1; index++)
{
double lineLevel = contourLineSet.MinLevel +
(incrementLevels * (double) index);
if (index >= contourLineSet.LevelCount)
{
lineLevel = double.MaxValue;
}
//Use all the same fillcolor for the lineLevels for the ContourLineSet.
if (!FillLevelsAndColors.ContainsKey(lineLevel))
{
FillLevelsAndColors.Add(lineLevel, new GraphicColorProperties()
{
Color = System.Drawing.Color.FromArgb(
lineColors[index].RedComponent,
lineColors[index].GreenComponent,
lineColors[index].BlueComponent),
Pattern = contourLineSet.FillGraphicProperties.Pattern,
Opacity = contourLineSet.FillGraphicProperties.Opacity,
LineWidth = contourLineSet.FillGraphicProperties.LineWidth,
IsFill = contourLineSet.FillGraphicProperties.IsFill,
});
}
}
}
}
//Now add all the individual ContourLine settings to any already added from ContourLineSet.
if (Plot.PlotData.VariableGraphicProperties.CpFillChoices ==
CpFillChoicesEnum.IndividualLinesFill &&
null != Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList &&
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList.Count > 0)
{
//These Fill colors are to be created "Below Threshold".
foreach (
ThresholdDefault threshold in
Plot.PlotData.VariableGraphicProperties.ThresholdDefaultList)
{
if (!FillLevelsAndColors.ContainsKey(threshold.ThresholdValue))
{
FillLevelsAndColors.Add(threshold.ThresholdValue,
new GraphicColorProperties()
{
Color = threshold.FillTrajLinkColor,
Pattern = threshold.FillGraphicProperties.Pattern,
Opacity = threshold.FillGraphicProperties.Opacity,
LineWidth = threshold.FillGraphicProperties.LineWidth,
IsFill = threshold.FillGraphicProperties.IsFill,
});
}
}
}
}
///
/// Get the LineStyle for the IsoLineLevels.
///
/// Index to the IsoLineLevel for the color of the LineStyle.
/// LineStyle for GridIsoLineLayer.
private LineStyle GetLineStyle(Double index)
{
GraphicColorProperties graphicProperties = LineLevelsAndColors[index];
// Convert Opacity, Color, DashStyle to MapSuite Geo classes.
int geoOpacity = CpConstants.ConvertOpacityToAlphaColor(
graphicProperties.Opacity);
GeoColor geoColor = new GeoColor(geoOpacity,
graphicProperties.Color.R,
graphicProperties.Color.G,
graphicProperties.Color.B);
GeoPen lineStylePen = new GeoPen(geoColor, graphicProperties.LineWidth);
lineStylePen.DashStyle = CpConstants.ConvertDashStyle(graphicProperties.Pattern);
return new LineStyle(lineStylePen); ;
}
///
/// Get the AreaStyle for the IsoLineLevels.
///
/// Index to the IsoLineLevel for the color of the AreaStyle.
/// AreaStyle for GridIsoLineLayer.
private AreaStyle GetAreaStyle(double index)
{
GraphicColorProperties graphicProperties = FillLevelsAndColors[index];
// Convert Opacity, Color, DashStyle to MapSuite Geo classes.
int geoOpacity = CpConstants.ConvertOpacityToAlphaColor(
graphicProperties.Opacity);
GeoColor geoColor = new GeoColor(geoOpacity,
graphicProperties.Color.B,
graphicProperties.Color.R,
graphicProperties.Color.G);
GeoColor geoColorBack = new GeoColor(geoOpacity,
graphicProperties.Color.R,
graphicProperties.Color.G,
graphicProperties.Color.B);
// If Pattern is Solid, then just create GeoSolidBrush AreaStyle.
if (graphicProperties.Pattern == GraphicConstants.StyleSolid)
{
return new AreaStyle(new GeoSolidBrush(geoColorBack));
}
// If Pattern is a HatchStyle, then create a FillCustomBrush AreaStyle.
GeoHatchStyle geoHatchStyle = CpConstants.ConvertHatchStyle(graphicProperties.Pattern);
AreaStyle style = new AreaStyle();
style.Advanced.FillCustomBrush = new GeoHatchBrush(geoHatchStyle, geoColor, geoColorBack);
return style;
}
///
/// Get the TextColor for the IsoLineLevels Labels.
///
/// GeoColor for IsoLineLevels labels.
private GeoColor GetTextColor()
{
//GeoColor textColor = LineColors[0];
GeoColor textColor = GeoColor.StandardColors.Black;
return textColor;
}
#endregion
}
}