User Tools

Site Tools


source_code_serviceseditionsample_splitpolygonintogridbasedonarea_cs_120321.zip

Source Code ServicesEditionSample SplitPolygonintoGridBasedOnArea CS 120321.zip

Program.cs

using System;
using System.Windows.Forms;
 
namespace SplitPolygonsBasedOnGrid
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmSplitPolygons());
        }
    }
}
 

DynamicGridPolygonIndexer.cs

using System.Collections.Generic;
using System.Collections.ObjectModel;
 
namespace ThinkGeo.MapSuite.Core
{
    public static class DynamicGridPolygonIndexer
    {
        //Get all Cells without cutting polygon.  restricts how many levels to iterate based on minimum cell area
        public static GeoCollection<Feature> GetIntersectingGridCells(BaseShape source, GeographyUnit sourceUnit, double minimumCellArea, AreaUnit minimumCellAreaUnit)
        {
            //find bounding box of set of boundary
            RectangleShape boundingBox = source.GetBoundingBox();
 
            Stack<RectangleShape> processingStack = new Stack<RectangleShape>();
            processingStack.Push(boundingBox);
 
            Collection<RectangleShape> insideRectangles = new Collection<RectangleShape>();
            Collection<RectangleShape> intersectingRectangles = new Collection<RectangleShape>();
 
            while (processingStack.Count > 0)
            {
                RectangleShape currentBoundingBox = processingStack.Pop();
                bool toBeSplit = false;
 
                if (source.Contains(currentBoundingBox))
                {
                    //if inside a boundary add to inside rectangles holder
                    insideRectangles.Add(currentBoundingBox);
                }
                else if (source.Intersects(currentBoundingBox))
                {
                    //if intersecting
                    //we multiply the minimum cell area by 9 to do this check because if it is below it we are splitting it into 9 equal parts
                    //this guarantees that after it is split they new cells are still larger than the minimum area.
                    if (currentBoundingBox.GetArea(sourceUnit, minimumCellAreaUnit) > minimumCellArea * 9)
                    {
                        //if it is too big it needs to be split
                        toBeSplit = true;
                    }
                    else
                    {
                        //if small enough add to intersecting rectangles holder
                        intersectingRectangles.Add(currentBoundingBox);
                    }
                }
 
                if (toBeSplit)
                {
                    //split bounding boxes
                    Collection<RectangleShape> splitBoundingBoxes = splitRectangles(currentBoundingBox);
                    //and add each to stack
                    foreach (RectangleShape splitBoundingBox in splitBoundingBoxes)
                    {
                        processingStack.Push(splitBoundingBox);
                    }
                }
            }
 
            GeoCollection<Feature> cells = new GeoCollection<Feature>();
 
            insideRectangles = combineRectangles(insideRectangles);
 
            foreach (var rect in insideRectangles)
            {
                RectangleShape bboxShape = rect;
                Feature bbox = new Feature(bboxShape);
 
                bbox.ColumnValues["type"] = "in";
                cells.Add(bbox);
            }
 
            foreach (var rect in intersectingRectangles)
            {
                RectangleShape bboxShape = rect;
                Feature bbox = new Feature(bboxShape);
 
                bbox.ColumnValues["type"] = "intersecting";
                cells.Add(bbox);
            }
 
            return cells;
        }
 
        private static Collection<RectangleShape> splitRectangles(RectangleShape currentBoundingBox)
        {
            // Split to 9 parts
            double x1, x2, x3, x4, y1, y2, y3, y4;
 
            x1 = currentBoundingBox.UpperLeftPoint.X;
            x4 = currentBoundingBox.UpperRightPoint.X;
 
            x2 = x1 + (x4 - x1) / 3.0;
            x3 = x4 - (x4 - x1) / 3.0;
 
            y1 = currentBoundingBox.UpperLeftPoint.Y;
            y4 = currentBoundingBox.LowerLeftPoint.Y;
 
            y2 = y1 + (y4 - y1) / 3.0;
            y3 = y4 - (y4 - y1) / 3.0;
 
            Collection<RectangleShape> splitBoundingBoxes = new Collection<RectangleShape>();
            splitBoundingBoxes.Add(new RectangleShape(x1, y1, x2, y2));
            splitBoundingBoxes.Add(new RectangleShape(x2, y1, x3, y2));
            splitBoundingBoxes.Add(new RectangleShape(x3, y1, x4, y2));
            splitBoundingBoxes.Add(new RectangleShape(x1, y2, x2, y3));
            splitBoundingBoxes.Add(new RectangleShape(x2, y2, x3, y3));
            splitBoundingBoxes.Add(new RectangleShape(x3, y2, x4, y3));
            splitBoundingBoxes.Add(new RectangleShape(x1, y3, x2, y4));
            splitBoundingBoxes.Add(new RectangleShape(x2, y3, x3, y4));
            splitBoundingBoxes.Add(new RectangleShape(x3, y3, x4, y4));
 
            return splitBoundingBoxes;
        }
 
        private static Collection<RectangleShape> combineRectangles(Collection<RectangleShape> rectangles)
        {
            Collection<RectangleShape> finalList = new Collection<RectangleShape>();
 
            bool NeedCombine = true;
            while (NeedCombine)
            {
                int sourceNumber = rectangles.Count;
                finalList = combineRectanglesInList(rectangles);
                if (finalList.Count == sourceNumber) // Cannot combine again
                {
                    NeedCombine = false;
                }
                else
                {
                    rectangles = finalList.Clone();
                }
            }
 
            return finalList;
        }
 
        private static Collection<RectangleShape> combineRectanglesInList(Collection<RectangleShape> rectangles)
        {
            Collection<RectangleShape> returnList = new Collection<RectangleShape>();
 
            while (rectangles.Count > 0)
            {
                RectangleShape rect = rectangles[0];
                rectangles.RemoveAt(0); // Remove itself from old list
 
                for (int i = 0; i < rectangles.Count; i++)
                {
                    if (NeedCombine(rect, rectangles[i]))
                    {
                        RectangleShape newRect = CombineTwoRectangles(rect, rectangles[i]);
                        rectangles.RemoveAt(i); // Remove neighbour rect from old list
                        rect = newRect;
                    }
                }
 
                returnList.Add(rect);
            }
 
            return returnList;
        }
 
        // Two rectangles share one edge will return true
        private static bool NeedCombine(RectangleShape rect1, RectangleShape rect2)
        {
            int sameVertex = 0;
 
            if (IsVertex(rect2, rect1.UpperLeftPoint)) sameVertex++;
            if (IsVertex(rect2, rect1.UpperRightPoint)) sameVertex++;
            if (IsVertex(rect2, rect1.LowerLeftPoint)) sameVertex++;
            if (IsVertex(rect2, rect1.LowerRightPoint)) sameVertex++;
 
            if (sameVertex == 2)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 
        private static bool IsVertex(RectangleShape rect, PointShape point)
        {
            string wkt = point.GetWellKnownText();
            if (rect.UpperLeftPoint.GetWellKnownText() == wkt) return true;
            if (rect.UpperRightPoint.GetWellKnownText() == wkt) return true;
            if (rect.LowerLeftPoint.GetWellKnownText() == wkt) return true;
            if (rect.LowerRightPoint.GetWellKnownText() == wkt) return true;
 
            return false;
        }
 
        private static RectangleShape CombineTwoRectangles(RectangleShape rect1, RectangleShape rect2)
        {
            return rect1.Union(rect2).GetBoundingBox();
        }
    }
}

SplitPolygons.cs

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Forms;
using ThinkGeo.MapSuite.Core;
 
namespace SplitPolygonsBasedOnGrid
{
    public partial class frmSplitPolygons : Form
    {
        private int featureCount = 0;
        private int featureIndex = 0;
        private int cellCount = 0;
        private int cellIndex = 0;
        private double miniCellArea = 0;
        private GeographyUnit sourceUnit = GeographyUnit.DecimalDegree;
        private AreaUnit miniCellUnit = AreaUnit.SquareMiles;
 
        public frmSplitPolygons()
        {
            InitializeComponent();
        }
 
        private void frmSplitPolygons_Load(object sender, EventArgs e)
        {
            txtSourceDirectory.Text = @"..\..\SampleData";
 
            cbSourceUnit.DataSource = Enum.GetNames(typeof(GeographyUnit));
            cbSourceUnit.SelectedIndex = 1;
 
            txtMinCellArea.Text = "10000";
            cbCellAreaUnit.DataSource = Enum.GetNames(typeof(AreaUnit));
            cbCellAreaUnit.SelectedIndex = 5;
        }
 
        private void btnLookupSource_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.ShowNewFolderButton = false;
            folderBrowserDialog.ShowDialog();
            txtSourceDirectory.Text = folderBrowserDialog.SelectedPath;
        }
 
        private void btnProcess_Click(object sender, EventArgs e)
        {
            btnProcess.Enabled = false;
 
            string filePath = txtSourceDirectory.Text;
 
            if (!Directory.Exists(filePath))
            {
                btnProcess.Enabled = true;
                MessageBox.Show("Source Directory is invalid");
                return;
            }
 
            if (!Double.TryParse(txtMinCellArea.Text, out miniCellArea))
            {
                btnProcess.Enabled = true;
                MessageBox.Show("Minimum Cell Area is invalid");
                return;
            }
 
            txtStatus.Text = "Process start";
            Application.DoEvents();
 
            sourceUnit = (GeographyUnit)Enum.Parse(typeof(GeographyUnit), cbSourceUnit.Text);
            miniCellUnit = (AreaUnit)Enum.Parse(typeof(AreaUnit), cbCellAreaUnit.Text);
            string[] filesToDelete = Directory.GetFiles(filePath, "*SplitTemp.*");
 
            foreach (string file in filesToDelete)
            {
                File.Delete(file);
            }
 
            string[] shapefiles = Directory.GetFiles(filePath, "*.shp", SearchOption.TopDirectoryOnly);
 
            foreach (string shapefile in shapefiles)
            {
                if (!shapefile.Contains("_split.shp"))
                {
                    CreateGridForShapefile(shapefile);
                }
            }
 
            MessageBox.Show("Finished!");
            txtStatus.Text = "Finished!";
            btnProcess.Enabled = true;
        }
 
        private void CreateGridForShapefile(string file)
        {
            ShapeFileFeatureSource.BuildIndexFile(file, BuildIndexMode.DoNotRebuild);
            ShapeFileFeatureSource shapeFile = new ShapeFileFeatureSource(file, ShapeFileReadWriteMode.ReadOnly);
            shapeFile.Open();
            if (shapeFile.GetShapeFileType() == ShapeFileType.Polygon)
            {
                ShapeFileFeatureSource.CreateShapeFile(ShapeFileType.Polygon, file.Replace(".shp", "_AreaSplitTemp.shp"), new Collection<DbfColumn>() { new DbfColumn("RECID", DbfColumnType.Character, 10, 0) });
                ShapeFileFeatureSource.CreateShapeFile(ShapeFileType.Polyline, file.Replace(".shp", "_LineSplitTemp.shp"), new Collection<DbfColumn>() { new DbfColumn("RECID", DbfColumnType.Character, 10, 0) });
 
                ShapeFileFeatureSource targetAreaShapeFile = new ShapeFileFeatureSource(file.Replace(".shp", "_AreaSplitTemp.shp"), ShapeFileReadWriteMode.ReadWrite);
                targetAreaShapeFile.Open();
                targetAreaShapeFile.BeginTransaction();
 
                ShapeFileFeatureSource targetLineShapeFile = new ShapeFileFeatureSource(file.Replace(".shp", "_LineSplitTemp.shp"), ShapeFileReadWriteMode.ReadWrite);
                targetLineShapeFile.Open();
                targetLineShapeFile.BeginTransaction();
 
                Collection<Feature> allFeatures = shapeFile.GetAllFeatures(ReturningColumnsType.AllColumns);
 
                featureCount = allFeatures.Count;
                featureIndex = 0;
 
                foreach (Feature targetFeature in allFeatures)
                {
                    featureIndex++;
                    CreateGridForFeature(shapeFile, targetAreaShapeFile, targetLineShapeFile, targetFeature);
                }
 
                targetLineShapeFile.CommitTransaction();
                targetAreaShapeFile.CommitTransaction();
 
                targetAreaShapeFile.Close();
                targetLineShapeFile.Close();
 
                RenameTempFiles(file.Replace(".shp", "_AreaSplitTemp.shp"));
                RenameTempFiles(file.Replace(".shp", "_LineSplitTemp.shp"));
            }
            shapeFile.Close();
        }
 
        private void CreateGridForFeature(ShapeFileFeatureSource shapeFile, ShapeFileFeatureSource targetAreaShapeFile, ShapeFileFeatureSource targetLineShapeFile, Feature targetFeature)
        {
            GeoCollection<Feature> splitCells = DynamicGridPolygonIndexer.GetIntersectingGridCells(targetFeature.GetShape(), sourceUnit, miniCellArea, miniCellUnit);
            cellCount = splitCells.Count;
            cellIndex = 0;
 
            foreach (Feature cell in splitCells)
            {
                cellIndex++;
                ProcessOneGridCell(targetAreaShapeFile, targetLineShapeFile, targetFeature, cell);
                txtStatus.Text = string.Format("Cell {0} of {1}, Feature {2} of {3} in {4}", cellIndex, cellCount, featureIndex, featureCount, Path.GetFileName(shapeFile.ShapePathFileName));
                Application.DoEvents();
            }
        }
 
        private void ProcessOneGridCell(ShapeFileFeatureSource targetAreaShapeFile, ShapeFileFeatureSource targetLineShapeFile, Feature targetFeature, Feature cell)
        {
            BaseShape areaIntersection = null;
            BaseShape lineIntersection = null;
            MultipolygonShape polygon = (MultipolygonShape)targetFeature.GetShape();
 
            areaIntersection = polygon.GetIntersection(cell.GetShape() as PolygonShape);
            MultilineShape multiLine = new MultilineShape();
 
            foreach (PolygonShape singlePolygon in polygon.Polygons)
            {
                multiLine.Lines.Add(new LineShape(singlePolygon.OuterRing.Vertices));
 
                foreach (RingShape ring in singlePolygon.InnerRings)
                {
                    multiLine.Lines.Add(new LineShape(ring.Vertices));
                }
            }
 
            lineIntersection = multiLine.GetIntersection(cell.GetShape() as PolygonShape);
 
            if (lineIntersection is MultilineShape)
            {
                if (((MultilineShape)lineIntersection).Lines.Count == 0)
                {
                    lineIntersection = null;
                }
            }
 
            if (areaIntersection != null)
            {
                Feature newFeature = new Feature(areaIntersection);
                newFeature.ColumnValues.Add("ID", targetFeature.Id.ToString());
                targetAreaShapeFile.AddFeature(newFeature);
            }
            if (lineIntersection != null)
            {
                Feature newFeature = new Feature(lineIntersection);
                newFeature.ColumnValues.Add("ID", targetFeature.Id.ToString());
                targetLineShapeFile.AddFeature(newFeature);
            }
        }
 
        private void btnCancel_Click(object sender, EventArgs e)
        {
            Environment.Exit(0);
        }
 
        private void RenameTempFiles(string shapePathFileName)
        {
            File.Move(shapePathFileName, shapePathFileName.Replace("SplitTemp", "Split"));
            File.Move(shapePathFileName.Replace(".shp", ".dbf"), shapePathFileName.Replace(".shp", ".dbf").Replace("SplitTemp", "Split"));
            File.Move(shapePathFileName.Replace(".shp", ".shx"), shapePathFileName.Replace(".shp", ".shx").Replace("SplitTemp", "Split"));
            File.Move(shapePathFileName.Replace(".shp", ".idx"), shapePathFileName.Replace(".shp", ".idx").Replace("SplitTemp", "Split"));
            File.Move(shapePathFileName.Replace(".shp", ".ids"), shapePathFileName.Replace(".shp", ".ids").Replace("SplitTemp", "Split"));
        }
    }
}

Extensions.cs

using System.Collections.ObjectModel;
using System.Linq;
 
namespace ThinkGeo.MapSuite.Core
{
    public static class Extensions
    {
        public static Collection<RectangleShape> Clone(this Collection<RectangleShape> collectionToClone)
        {
            return new Collection<RectangleShape>(collectionToClone.Select(item => item.CloneDeep() as RectangleShape).ToList());
        }
    }
}
source_code_serviceseditionsample_splitpolygonintogridbasedonarea_cs_120321.zip.txt · Last modified: 2016/09/23 11:39 by tgwikiupdate