Skip to content

Instantly share code, notes, and snippets.

@quommit
Last active July 25, 2022 19:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save quommit/4605854 to your computer and use it in GitHub Desktop.
Save quommit/4605854 to your computer and use it in GitHub Desktop.
Sample C# code implementing medial axis transform of a polygon using Voronoi diagram. In order to compile this code, download and reference NetTopologySuite, an open source spatial analysis library.
using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
using NetTopologySuite.Densify;
using NetTopologySuite.Triangulate;
namespace Skeleton
{
class MainClass
{
public static void Main (string[] args)
{
IGeometryFactory gfactory = GeometryFactory.Fixed;
WKTReader greader = new WKTReader (gfactory);
//Create a new polygon instance
IGeometry polygon = greader.Read ("POLYGON((0 0, 0 10, 20 10, 20 20, 25 20, 25 10, 40 10, 40 0, 0 0))");
//Densify polygon and store vertices in point array
IGeometry densification = Densifier.Densify (polygon, 1);
IGeometry[] points = new IGeometry[densification.NumPoints - 1];
for (int i = 0; i <= points.GetUpperBound (0); i++) {
points[i] = gfactory.CreatePoint (densification.Coordinates[i]);
}
//Create a new point collection
IGeometryCollection pointsCollection = gfactory.CreateGeometryCollection (points);
//Build Voronoi diagram from point collection
VoronoiDiagramBuilder voronoiBuilder = new VoronoiDiagramBuilder ();
voronoiBuilder.SetSites (pointsCollection.Coordinates);
IGeometryCollection diagram = voronoiBuilder.GetDiagram (gfactory);
//Intersect Voronoi diagram with target polygon to get crust
IGeometry crust = diagram.Intersection (polygon);
//Create an empty geometry collection for the skeleton
IList<IGeometry> skeleton = new List<IGeometry> ();
//Populate skeleton from edges in crust
for (int i = 0; i < crust.NumGeometries; i++) {
IGeometry g = crust.GetGeometryN (i);
for (int j = 1; j < g.Coordinates.Length; j++) {
//For each polygon in crust get each edge
IGeometry edge = gfactory.CreateLineString (new Coordinate[] {g.Coordinates[j-1], g.Coordinates[j]});
if (!edge.Touches (polygon.Boundary) && edge.Within (polygon)) {
skeleton.Add (edge); //If this edge does not touch polygon perimeter add to skeleton
}
}
}
}
}
}
@qubsl
Copy link

qubsl commented Apr 28, 2016

when i change the polygon to (0 0, 20 0, 20 10, 10 4,5 30, 0 10, 0 0), it has a error. The "densification.NumPoints" is zero.

@sshirazi
Copy link

sshirazi commented Mar 30, 2017

Using the skeleton I want to find the longest continuous edge. I want to do this to find the bearing of such edge and determine the orientation of the polygon in general. Any ideas for better ways to find the orientation of the polygon?

@sztepen
Copy link

sztepen commented Jul 25, 2022

Using the skeleton I want to find the longest continuous edge. I want to do this to find the bearing of such edge and determine the orientation of the polygon in general. Any ideas for better ways to find the orientation of the polygon?

maybe try moments of inertia/ellipsoid of inertia/principal axes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment