Split Polygon by Multiple LineSegments - c#

I am trying to split a LinearRing into multiple LinearRings using multiple lines. The expected result is a collection of LinearRings (as in the attached image). Expected result is here attached in the image. (https://i.stack.imgur.com/Kuzr8.jpg) I am not understanding how to call the recursive function. Below is the code I tried.
If it was one single line which was cutting the polygon, I could have done that. But the problem here is that we have multiple linesstrings cutting the polygon, into multiple 'pieces'. Also, I know that each time if the current line is cutting and making two pieces of the current polygon, the current polygon should be removed from the final result. This seems a bit complicated for me.
The Main Function:
static void Main(string[] args)
{
Coordinate c22 = new Coordinate(2889.0, 1277.0);
Coordinate c23 = new Coordinate(2894.0, 1288.0);
Coordinate c24 = new Coordinate(2901.0, 1284.0);
Coordinate c25 = new Coordinate(2909.0, 1289.0);
Coordinate c26 = new Coordinate(2916.0, 1281.0);
Coordinate c27 = new Coordinate(2912.0, 1270.0);
Coordinate c28 = new Coordinate(2906.0, 1275.0);
Coordinate c29 = new Coordinate(2898.0, 1273.0);
LinearRing outerBoundary = new LinearRing(new Coordinate[] { c22, c23, c24, c25, c26, c27, c28, c29, c22 });
List<LineString> lines = new List<LineString>();
Coordinate p30 = new Coordinate(2892.0, 1270.0);
Coordinate p31 = new Coordinate(2900.0, 1294.0);
LineString ln1 = new LineString(new Coordinate[] { p30, p31 });
lines.Add(ln1);
Coordinate p32 = new Coordinate(2909.0, 1268.0);
Coordinate p33 = new Coordinate(2907.0, 1294.0);
LineString ln2 = new LineString(new Coordinate[] {p32, p33});
lines.Add(ln2);
Coordinate p34 = new Coordinate(2886.0, 1286.0);
Coordinate p35 = new Coordinate(2922.0, 1278.0);
LineString ln3 = new LineString(new Coordinate[] {p34, p35});
lines.Add(ln3);
Coordinate p36 = new Coordinate(2883.0, 1281.0);
Coordinate p37 = new Coordinate(2923.0, 1273.0);
LineString ln4 = new LineString(new Coordinate[] {p36, p37});
lines.Add(ln4);
Geometry polygons = CookieCutter(outerBoundary, new List<LineString>() { ln1, ln2, ln3, ln4 });
}
The Recursive function. This is where I am stuck;
public static Geometry CookieCutter(LinearRing polygon, List<LineString> cuttingEdges, Geometry pieces = null)
{
if (pieces == null) { pieces = Polygonize(polygon.Union(cuttingEdges[0])); }
foreach (var cuttingEdge in cuttingEdges)
{
for (int i = 0; i < pieces.NumGeometries; i++)
{
pieces = pieces.GetGeometryN(i);
Geometry newPieces = Polygonize(polygon.Union(cuttingEdge));
// I know somewhere here it should call CookieCutter on new pieces
// But how to...?
}
}
}
Here is the function to polygonize;
public static Geometry Polygonize(Geometry geometry)
{
var lines = LineStringExtracter.GetLines(geometry);
var polygonizer = new Polygonizer(false);
polygonizer.Add(lines);
var polys = new List<Geometry>(polygonizer.GetPolygons());
var polyArray = GeometryFactory.ToGeometryArray(polys);
return geometry.Factory.BuildGeometry(polyArray);
}

Ohh... the solution was simple. I was trying to complicate it unnecessarily. There was no need of any recursion. I resolved it like this;
public static Geometry CookieCutter(
Geometry polygon,
List<LineString> cuttingEdges
)
{
MultiLineString mls = new MultiLineString(cuttingEdges.ToArray());
var union = polygon.Union(mls);
var polygons = Polygonize(union);
return polygons;
}

Related

CvInvoke.Undistort Is making the image more distorted, not less

My first time working with OpenCV. The code below uses the Emgu package, but I've also tried it using OpenCVSharp and have got exactly the same results.
I am calibrating the camera using 6 chessboard photos, then using the calibration to Undistort an image. The test image is a photo of some squared paper. The camera really isn't very distorted - I can't tell that it is distorted by eye, only when I draw a straight line over the lines in a paint program.
However - the resulting image comes out way more distorted than the original - adding a lot of barrel distortion.
When I run the commented out lines, the "DrawChessboardCorners" show that it is identifying the points perfectly.
What am I doing wrong here?
static void Main(string[] args)
{
Size patternSize = new Size(9, 6);
List<VectorOfPointF> ListOfCornerPoints = new List<VectorOfPointF>();
DirectoryInfo dir = new DirectoryInfo(#"Z:\Simon\Dropbox\Apps\OpenCVPlay\Image Processing\Chessboard Pattern Photos With Pixel");
Size calibrationImageSize = new Size(0,0) ;
foreach (var file in dir.GetFiles())
{
VectorOfPointF corners = new VectorOfPointF();
var calibrationImage = new Image<Rgb, byte>(file.FullName);
bool find = CvInvoke.FindChessboardCorners(calibrationImage, patternSize, corners, CalibCbType.AdaptiveThresh | CalibCbType.FilterQuads);
//CvInvoke.DrawChessboardCorners(calibrationImage, patternSize, corners, find);
//calibrationImage.Save(#"Z:\Simon\Dropbox\Apps\OpenCVPlay\Image Processing\Chessboard Pattern Photos With Pixel\test\" + file.Name);
ListOfCornerPoints.Add(corners);
calibrationImageSize = calibrationImage.Size;
}
PointF[][] arrayOfCornerPoints = ListOfCornerPoints.Select(a => a.ToArray()).ToArray();
var modelPoints = CreateModelPoints(ListOfCornerPoints.Count, patternSize.Width, patternSize.Height);
var arrayOfModelPoints = modelPoints.Select(a => a.ToArray()).ToArray();
Matrix<double> cameraDistortionCoeffs = new Matrix<double>(5, 1);
Matrix<double> cameraMatrix = new Matrix<double>(3, 3);
Mat[] rotationVectors;
Mat[] translationVectors;
CvInvoke.CalibrateCamera(
arrayOfModelPoints,
arrayOfCornerPoints,
calibrationImageSize,
cameraMatrix,
cameraDistortionCoeffs,
CalibType.Default,
new MCvTermCriteria(),
out rotationVectors,
out translationVectors);
var imageToProcess = new Image<Rgb, byte>(#"Z:\Simon\Dropbox\Apps\OpenCVPlay\Image Processing\Test data\squarePaper.jpg");
Rectangle Rect2 = new Rectangle();
var newCameraMatrix = CvInvoke.GetOptimalNewCameraMatrix(cameraMatrix, cameraDistortionCoeffs, calibrationImageSize, 1, imageToProcess.Size, ref Rect2, true);
Image<Rgb, byte> processedImage = imageToProcess.Clone();
CvInvoke.Undistort(imageToProcess, processedImage, cameraMatrix, cameraDistortionCoeffs);
processedImage.Save(#"Z:\Simon\Dropbox\Apps\OpenCVPlay\Image Processing\Test data\squarePaperFixed.jpg");
}
static List<List<MCvPoint3D32f>> CreateModelPoints(int length, int chessboardCols, int chessboardRows)
{
var modelPoints = new List<List<MCvPoint3D32f>>();
for (var k = 0; k < length; k++)
{
var chessboard = new List<MCvPoint3D32f>();
for (var y = 0; y < chessboardRows; y++)
{
for (var x = 0; x < chessboardCols; x++)
{
chessboard.Add(new MCvPoint3D32f(x, y, 0));
}
}
modelPoints.Add(chessboard);
}
return modelPoints;
}

GMap.NET how can I make an accurate routing?

So what I am trying to do is showing a route on a winforms application using the GMap.NET nugget.
But the problem I encountered is that it doesn't show the route using the roads. It's literately showing the shortest distances between 2 points, so to make it more accurate I did an extra API call to google maps Directions. So I have some extra points to make it more accurate but still between 2 points its just a straight line, not on roads.
route problem
Here you can see how I am loading the points.
public void ShowRoute(Coordinate[] coordinates)
{
if (coordinates.Length > 1)
{
List<PointLatLng> points = new List<PointLatLng>();
foreach (var cor in coordinates)
{
Coordinate c = geo.ConvertCoordinates(cor);
var corstring = geo.GetAdresByCor(c);
var point = new PointLatLng(Convert.ToDouble(c.Latitude.Replace(".", ",")), Convert.ToDouble(c.Longitude.Replace(".", ",")));
var marker = new GMarkerGoogle(point, GMarkerGoogleType.pink_pushpin);
routeMarkers.Markers.Add(marker);
}
var routes = geo.DirectionsByCor(coordinates);
foreach (var route in routes)
{
foreach (var step in route.Legs[0].Steps)
{
var point = new PointLatLng(step.EndLocation.Latitude, step.EndLocation.Longitude);
points.Add(point);
}
}
var r = new GMapRoute(points, "route");
var routesOverlay = new GMapOverlay("routes");
routesOverlay.Routes.Add(r);
map.Overlays.Add(routeMarkers);
map.Overlays.Add(routesOverlay);
}
}
Here is how my Map is loaded.
private void map_Load(object sender, EventArgs e)
{
GMapProviders.GoogleMap.ApiKey = Properties.Settings.Default.ApiKey;
geo = new GeocoderXY();
map.MouseWheelZoomEnabled = true;
map.DragButton = MouseButtons.Left;
map.MapProvider = GMapProviders.GoogleMap;
lng = 3.7074218;
lat = 51.008157;
GMapMarker marker = new GMarkerGoogle(new PointLatLng(lat, lng), GMarkerGoogleType.blue_pushpin);
searchMarker = marker;
markers.Markers.Add(marker);
markers.Markers.Add(mouseMarker);
map.Position = new NET.PointLatLng(lat, lng);
map.MouseWheelZoomType = NET.MouseWheelZoomType.MousePositionWithoutCenter;
map.MinZoom = 5;
map.MaxZoom = 100;
map.Zoom = 15;
map.ShowCenter = false;
}
I don't see what I'm doing wrong, if someone does see it, please let me know!
Thanks
Still it's not clear why you're doing extra calls.Anyway, to get a route all it's needed a start and end locations and call GetDirections (apparently GoogleMapProvider is obsolete):
GDirections myDirections;
var route = GMapProviders.GoogleMap.GetDirections(out myDirections, start, end, false, false, false, false, false);
then use the directions to draw
var route = new GMapRoute(myDirections.Route, "route");
var routesOverlay = new GMapOverlay("routes");
routesOverlay.Routes.Add(route);
Unfortunately I dont have the VS to test but you got the idea.

Partial Convex Hull

I have a polygon with vertices P1, P2,P3,.....P11. My vertex coordinate data types are double.
I also have a line between P1, P7.
I want to create a partial convex hull between P1 and P7 and keep my original polygon vertices after P7.
So final polygon will be as follow;
So far I convert the whole polygon to convex hull, delete vertices in convex hull and add hull vertices. It works fine with small polygons but it won't be easy to manage that way when vertex number increases.
I tried to look for c# algorithms available for partial convex hull but i couldn't find anything except some researches.
Any ideas?
Remove vertices P8 through P11 from your polygon and store them off, then run the convex hull conversion on what's left (P1 through P7). After, re-insert vertices P8 through P11 (between P7 and P1).
I clipped the polygon by using DotSpatial
internal static IGeometry Polygonize(IGeometry geometry)
{
var lines = LineStringExtracter.GetLines(geometry);
var polygonizer = new Polygonizer();
polygonizer.Add(lines);
var polys = polygonizer.GetPolygons();
var polyArray = GeometryFactory.ToGeometryArray(polys);
return geometry.Factory.CreateGeometryCollection(polyArray);
}
internal static IGeometry PolygonizeForClip(IGeometry geometry, IPreparedGeometry clip)
{
var lines = LineStringExtracter.GetLines(geometry);
var clippedLines = new List<IGeometry>();
foreach (ILineString line in lines)
{
if (clip.Contains(line))
clippedLines.Add(line);
}
var polygonizer = new Polygonizer();
polygonizer.Add(clippedLines);
var polys = polygonizer.GetPolygons();
var polyArray = GeometryFactory.ToGeometryArray(polys);
return geometry.Factory.CreateGeometryCollection(polyArray);
}
internal static IGeometry SplitPolygon(IGeometry polygon, IGeometry line)
{
var nodedLinework = polygon.Boundary.Union(line);
var polygons = Polygonize(nodedLinework);
// only keep polygons which are inside the input
var output = new List<IGeometry>();
for (var i = 0; i < polygons.NumGeometries; i++)
{
var candpoly = (IPolygon)polygons.GetGeometryN(i);
if (polygon.Contains(candpoly.InteriorPoint))
output.Add(candpoly);
}
return polygon.Factory.BuildGeometry(output);
}
internal static IGeometry ClipPolygon(IGeometry polygon, IPolygonal clipPolygonal)
{
var clipPolygon = (IGeometry)clipPolygonal;
var nodedLinework = polygon.Boundary.Union(clipPolygon.Boundary);
var polygons = Polygonize(nodedLinework);
// only keep polygons which are inside the input
var output = new List<IGeometry>();
for (var i = 0; i < polygons.NumGeometries; i++)
{
var candpoly = (IPolygon)polygons.GetGeometryN(i);
var interiorPoint = candpoly.InteriorPoint;
if (polygon.Contains(interiorPoint) &&
clipPolygon.Contains(interiorPoint))
output.Add(candpoly);
}
return polygon.Factory.BuildGeometry(output);
}
then
var Splitted = SplitPolygon(Polygon, Line);
Then added parts.

Calculate area of polygon having WGS coordinates using DotSpatial?

Calculating area:
var coordinates = new List<Coordinate> {
new Coordinate(55, 35),
new Coordinate(55, 35.1),
new Coordinate(55.1, 35.1),
new Coordinate(55.1, 35),
};
Console.WriteLine(new Polygon(coordinates).Area); // ~0.01
Calculation is right, because it's happen in orthogonal coordinate system.
But how to mark that coordinates are in WGS?
It seems that task is more complicated that I've expected. I found this useful discussion on google groups
Firstly we need to found projection system, that is most suitable for our region where we need to compute area. For example you can take one of UTM zones
using DotSpatial.Projections;
using DotSpatial.Topology;
public static double CalculateArea(IEnumerable<double> latLonPoints)
{
// source projection is WGS1984
var projFrom = KnownCoordinateSystems.Geographic.World.WGS1984;
// most complicated problem - you have to find most suitable projection
var projTo = KnownCoordinateSystems.Projected.UtmWgs1984.WGS1984UTMZone37N;
// prepare for ReprojectPoints (it mutates array)
var z = new double[latLonPoints.Count() / 2];
var pointsArray = latLonPoints.ToArray();
Reproject.ReprojectPoints(pointsArray, z, projFrom, projTo, 0, pointsArray.Length / 2);
// assemblying new points array to create polygon
var points = new List<Coordinate>(pointsArray.Length / 2);
for (int i = 0; i < pointsArray.Length / 2; i++)
points.Add(new Coordinate(pointsArray[i * 2], pointsArray[i * 2 + 1]));
var poly = new Polygon(points);
return poly.Area;
}
You can get the area directly from IGeometry or from Feature.Geometry. Also You need to repeat the first coordinate to close your polygon.
FeatureSet fs = new FeatureSet(FeatureType.Polygon);
Coordinate[] coord = new Coordinate[]
{
new Coordinate(55, 35),
new Coordinate(55, 35.1),
new Coordinate(55.1, 35.1),
new Coordinate(55.1, 35),
new Coordinate(55, 35)
};
fs.AddFeature(new Polygon(new LinearRing(coord)));
var area = fs.Features.First().Geometry.Area;

ilNumerics keeps flipping my matrix to 3x4 causing the plot to become wonky. How do I fix this?

I have the following code (Test only right now)
PlotPoint[] starLocations = new PlotPoint[4];
starLocations[0] = new PlotPoint(9,-2,1);
starLocations[1] = new PlotPoint(-3,6,1);
starLocations[2] = new PlotPoint(4,2,-3);
starLocations[3] = new PlotPoint(7,-8,9);
//draw the sector map
SectorMap ourMap = new SectorMap();
ourMap.reDraw(PlotPoint.getILLocs(starLocations));
SectorMap.cs
public void reDraw(float[,] givenLocs){
ILArray<float> ourPositions = givenLocs;
textBox1.Text = ourPositions.ToString();
var scene = new ILScene();
var plotCube = scene.Add(new ILPlotCube(false));
var ourPosBuffer = new ILPoints();
ourPosBuffer.Positions = ourPositions;
ourPosBuffer.Size = 3;
plotCube.Add(ourPosBuffer);
iLStarChart.Scene = scene;
}
Doing this, when I check the matrix at PlotPoint.getILLocs, I get a 4x3 matrix. When I check the passed matrix, it's again a 3x4
When I check ourPositions in SectorMap.cs, it has become a 3x4 matrix. Which is something I did not intend. What am I doing wrong?
I messed up, and I'm providing how here for other people's refrence:
1) It was, as Haymo Kutschbach said, a difference in storage scheme.
2) The confusion and lack of 3D grid was due to
var plotCube = scene.Add(new ILPlotCube(false));
instead of the
var plotCube = scene.Add(new IPlotCube(null,false));

Categories

Resources