User Tools

Site Tools


source_code_wpfdesktopeditionsample_clusterpoint_cs_160627.zip

Source Code WpfDesktopEditionSample ClusterPoint CS 160627.zip

MainWindow.cs

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.WpfDesktopEdition;
 
namespace ClusterPointSample
{
    public partial class MainWindow : Window
    {
        private const string ThemeName = "Default";
        private const string assetCollectionType = "Value";
        private const string withAssetCollection = "1";
 
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void WpfMap_Loaded(object sender, RoutedEventArgs e)
        {
            wpfMap.MapUnit = GeographyUnit.DecimalDegree;
 
            // Set up the value style. 
            ValueStyle valueStyle = GetValueStyle(assetCollectionType, "green.png", "grey.png");
 
            // Set up the cluster style. 
            ClusterPointStyle clusterPointStyle = new ClusterPointStyle();
            clusterPointStyle.DrawingClusteredFeature += ClusterPointStyle_DrawingClusteredFeature;
            clusterPointStyle.Styles.Add(valueStyle);
            clusterPointStyle.LowerScale = 2000;
            clusterPointStyle.TextStyle = new TextStyle("FeatureCount", new GeoFont("Arial", 10), GeoBrushes.Black);
            clusterPointStyle.TextStyle.OverlappingRule = LabelOverlappingRule.AllowOverlapping;
            // Set the minimum features in per cell. If the count is less than the value it will invisible.
            clusterPointStyle.MinimumFeaturesPerCellToCluster = 2;
 
            ShapeFileFeatureLayer markerLayer = new ShapeFileFeatureLayer("Data/random.shp");
            markerLayer.ZoomLevelSet.ZoomLevel06.CustomStyles.Add(clusterPointStyle);
            markerLayer.ZoomLevelSet.ZoomLevel06.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            markerLayer.Open();
 
            // Set batch limit to number of features in the featuresource to avoid overlapping clusterpoints
            markerLayer.ProgressiveDrawingRecordsCount = markerLayer.FeatureSource.GetCount();
 
            wpfMap.Overlays.Add(new WorldMapKitWmsWpfOverlay() { Projection = WorldMapKitProjection.DecimalDegrees });
 
            LayerOverlay markerOverlay = new LayerOverlay();
            markerOverlay.Layers.Add("markerLayer", markerLayer);
 
            // Set up cached InMemoryFeatureLayers for zoom levels 1-5
            Collection<ZoomLevel> zoomLevels = markerLayer.ZoomLevelSet.GetZoomLevels();
            Collection<Feature> features = markerLayer.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns);
 
            // Iterate over first 5 zoom layers
            for (int i = 1; i <= 5; i++)
            {
                InMemoryFeatureLayer zoomLevelLayer = GetInMemoryFeatureLayerForZoomLevel(markerLayer, features, i);
                markerOverlay.Layers.Add("layerForZoomLevel" + i, zoomLevelLayer);
            }
 
            wpfMap.Overlays.Add(markerOverlay);
 
            wpfMap.CurrentExtent = new RectangleShape(-130, 60, -60, 15);
        }
 
        private InMemoryFeatureLayer GetInMemoryFeatureLayerForZoomLevel(ShapeFileFeatureLayer featureLayer, Collection<Feature> features, int zoomLevelNumber)
        {
            InMemoryFeatureLayer layerForZoomLevel = new InMemoryFeatureLayer();
            ZoomLevel zoomLevel = layerForZoomLevel.ZoomLevelSet.GetZoomLevels()[zoomLevelNumber-1];
 
            // Get features in zoom level and add them to the FeatureLayer
            List<Feature> featuresForZoomLevel = GetFeatures(features, zoomLevel.Scale, featureLayer.GetBoundingBox(), GeographyUnit.DecimalDegree, 2, 100);
            layerForZoomLevel.Open();
 
            layerForZoomLevel.Columns.Add(new FeatureSourceColumn("FeatureCount"));
            foreach (Feature feature in featuresForZoomLevel)
            {
                layerForZoomLevel.InternalFeatures.Add(feature);
            }
 
            // Add drawing styles
            zoomLevel.CustomStyles.Add(GetClassBreakStyle(layerForZoomLevel.Columns[0].ColumnName));
            zoomLevel.CustomStyles.Add(GetValueStyle(assetCollectionType, "green.png", "grey.png"));
 
            return layerForZoomLevel;
        }
 
        private void ClusterPointStyle_DrawingClusteredFeature(object sender, DrawingClusteredFeatureClusterPointStyleEventArgs e)
        {
            bool useGreenIcon = false;
            foreach (Feature clusteringFeature in e.ClusteringFeatures)
            {
                if (clusteringFeature.ColumnValues[assetCollectionType] == withAssetCollection)
                {
                    useGreenIcon = true;
                    break;
                }
            }
 
            // Get the feature count and based on the count to render the different style.
            int featureCount = int.Parse(e.ClusteredFeature.ColumnValues["FeatureCount"]);
            TextStyle textStyle = (TextStyle)e.Styles[1];
 
            GeoImage geoImage = new GeoImage();
 
            if (featureCount > 99)
            {
                textStyle.XOffsetInPixel = -13;
                textStyle.YOffsetInPixel = 13;
                geoImage = GetGeoImage(useGreenIcon ? "largegreen.png": "largegrey.png", ThemeName);
            }
            else if (featureCount > 9)
            {
                textStyle.XOffsetInPixel = -10;
                textStyle.YOffsetInPixel = 8;
                geoImage = GetGeoImage(useGreenIcon ? "green.png" : "grey.png", ThemeName);
            }
            else if (featureCount > 1)
            {
                textStyle.XOffsetInPixel = -6;
                textStyle.YOffsetInPixel = 6;
                geoImage = GetGeoImage(useGreenIcon ? "smallgreen.png" : "smallgrey.png", ThemeName);
            }
 
            PointStyle pointStyle = new PointStyle(geoImage);
            pointStyle.DrawingLevel = DrawingLevel.LabelLevel;
 
            e.Styles.RemoveAt(0);
            e.Styles.Insert(0, pointStyle);
        }
 
        private ClassBreakStyle GetClassBreakStyle(string columnName)
        {
            ClassBreakStyle classBreakStyle = new ClassBreakStyle();
            classBreakStyle.ColumnName = columnName;
 
            ValueStyle valueStyle = GetValueStyle("WithValue", "largegreen.png", "largegrey.png");
            TextStyle textStyle = GetTextStyle(-15, 12, 7);
            Collection<ThinkGeo.MapSuite.Core.Style> styles = new Collection<ThinkGeo.MapSuite.Core.Style>() { valueStyle, textStyle };
            classBreakStyle.ClassBreaks.Add(new ClassBreak(9999, styles));
 
            textStyle = GetTextStyle(-14, 12, 8);
            styles = new Collection<ThinkGeo.MapSuite.Core.Style>() { valueStyle, textStyle };
            classBreakStyle.ClassBreaks.Add(new ClassBreak(999, styles));
 
            textStyle = GetTextStyle(-13, 12, 10);
            styles = new Collection<ThinkGeo.MapSuite.Core.Style>() { valueStyle, textStyle };
            classBreakStyle.ClassBreaks.Add(new ClassBreak(99, styles));
 
            valueStyle = GetValueStyle("WithValue", "green.png", "grey.png");
            textStyle = GetTextStyle(-10, 8, 10);
            styles = new Collection<ThinkGeo.MapSuite.Core.Style>() { valueStyle, textStyle };
            classBreakStyle.ClassBreaks.Add(new ClassBreak(9, styles));
 
            valueStyle = GetValueStyle("WithValue", "smallgreen.png", "smallgrey.png");
            textStyle = GetTextStyle(-6, 6, 10);
            styles = new Collection<ThinkGeo.MapSuite.Core.Style>() { valueStyle, textStyle };
            classBreakStyle.ClassBreaks.Add(new ClassBreak(2, styles));
 
            return classBreakStyle;
        }
 
        private ValueStyle GetValueStyle(string columnName, string withImageStyleFilename, string withoutImageStyleFilename)
        {
            ValueStyle valueStyle = new ValueStyle();
            valueStyle.ColumnName = columnName;
            PointStyle withImageStyle = new PointStyle(GetGeoImage(withImageStyleFilename, ThemeName));
            PointStyle withoutImageStyle = new PointStyle(GetGeoImage(withoutImageStyleFilename, ThemeName));
            valueStyle.ValueItems.Add(new ValueItem("1", withImageStyle));
            valueStyle.ValueItems.Add(new ValueItem("0", withoutImageStyle));
            return valueStyle;
        }
 
        private TextStyle GetTextStyle(int xOffsetInPixel, int yOffsetInPixel, int fontSize)
        {
            TextStyle textStyle = new TextStyle("FeatureCount", new GeoFont("Arial", fontSize), GeoBrushes.Black);
            textStyle.OverlappingRule = LabelOverlappingRule.AllowOverlapping;
            textStyle.XOffsetInPixel = xOffsetInPixel;
            textStyle.YOffsetInPixel = yOffsetInPixel;
 
            return textStyle;
        }
 
        private GeoImage GetGeoImage(string imageName, string themeName)
        {
            GeoImage image = new GeoImage(string.Format("Theme/{0}/{1}", themeName, imageName));
            return image;
        }
 
        public static List<Feature> GetFeatures(Collection<Feature> features, double scale, RectangleShape currentWorldExtent, GeographyUnit mapUnit, int minimumFeaturesPerCellToCluster, int cellSize)
        {
            List<Feature> results = new List<Feature>();
            // Make sure that we set the feature threashold greater than 0 otherwise we will never draw the cluster styles
            // Also ensure that the total number of features is greater than the threshold otherwise we will never draw a cluster style
            // Check that the current extent is between the upper and lower bounds
            MapSuiteTileMatrix mapSuiteTileMatrix = new MapSuiteTileMatrix(scale, cellSize, cellSize, mapUnit);
 
            IEnumerable<TileMatrixCell> tileMatrixCells = mapSuiteTileMatrix.GetIntersectingCells(currentWorldExtent);
 
            List<Feature> validFeatures = new List<Feature>();
            Dictionary<string, PointShape> validPoints = new Dictionary<string, PointShape>();
 
            foreach (Feature feature in features)
            {
                WellKnownType wellKnownType = feature.GetWellKnownType();
 
                if (wellKnownType == WellKnownType.Point)
                {
                    validFeatures.Add(feature);
                    validPoints.Add(feature.Id, (PointShape)feature.GetShape());
                }
                else if (wellKnownType == WellKnownType.Multipoint)
                {
                    validFeatures.Add(feature);
                    validPoints.Add(feature.Id, ((MultipointShape)feature.GetShape()).GetCenterPoint());
                }
            }
 
            // Loop through each cell and find the features that fit inside of it
            foreach (TileMatrixCell cell in tileMatrixCells)
            {
                Collection<Feature> featuresInCell = new Collection<Feature>();
                int featureCount = 0;
                MultipointShape tempMultiPointShape = new MultipointShape();
 
                for (int i = validFeatures.Count - 1; i >= 0; i--)
                {
                    Feature currentFeature = validFeatures[i];
                    PointShape currentShape = validPoints[currentFeature.Id];// currentFeature.GetShape();
 
                    // Check if the cell contains the feature
                    if (IsContained(cell.BoundingBox, currentShape))
                    {
                        featuresInCell.Add(currentFeature);
                        featureCount++;
                        validFeatures.RemoveAt(i);
 
                        tempMultiPointShape.Points.Add(currentShape);
                    }
                }
                if (featuresInCell.Count >= minimumFeaturesPerCellToCluster)
                {
                    // Add the feature count to the new feature we created.  The feature will be placed
                    // at the center of gravity of all the clustered features of the cell we created.
                    Dictionary<string, string> featureValues = new Dictionary<string, string>();
                    featureValues.Add("FeatureCount", featureCount.ToString(CultureInfo.InvariantCulture));
                    featureValues.Add("WithValue", "0");
 
                    Feature clusteredFeature = new Feature(tempMultiPointShape.GetCenterPoint(), featureValues);
 
                    foreach (Feature clusteringFeature in featuresInCell)
                    {
                        //if (clusteringFeature.ColumnValues[_assetCollectionType] == _withAssetCollection)
                        if (clusteringFeature.ColumnValues["Value"] == "1")
                        {
                            clusteredFeature.ColumnValues["WithValue"] = "1";
                            break;
                        }
                    }
                    results.Add(clusteredFeature);
                }
                else
                {
                    results.AddRange(featuresInCell);
                }
            }
 
            return results;
        }
 
        private static bool IsContained(RectangleShape boundingBox, PointShape point)
        {
            return (boundingBox.LowerLeftPoint.X < point.X && boundingBox.UpperRightPoint.X > point.X) && (boundingBox.UpperLeftPoint.Y > point.Y && boundingBox.LowerRightPoint.Y < point.Y);
        }
    }
}
 
source_code_wpfdesktopeditionsample_clusterpoint_cs_160627.zip.txt · Last modified: 2016/06/20 20:45 by ryanduan