ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
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()); } } }
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(); } } }
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")); } } }
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()); } } }