private static void CalculateAveragePolylabelCellSize(AIXMBasicMessage msg, out double averageCellSize) { // Calculate the average polylabel cell size to "guestimate" what the font scaling value should be double aggregatedCellSize = 0; int totalTests = 0; foreach (var member in msg.hasMember) { var polygonTest = new List <MyPoint>(); var coords = member.Airspace.timeSlice.AirspaceTimeSlice1.geometryComponent.AirspaceGeometryComponent .theAirspaceVolume.AirspaceVolume.horizontalProjection.Surface.patches.PolygonPatch.exterior .LinearRing.posList.Split(' '); ReverseArray(coords); var interiorCoords = new List <string>(); if (member.Airspace.timeSlice.AirspaceTimeSlice1.geometryComponent .AirspaceGeometryComponent.theAirspaceVolume.AirspaceVolume.horizontalProjection.Surface.patches .PolygonPatch.interior != null) { foreach (var tmp in member.Airspace.timeSlice.AirspaceTimeSlice1.geometryComponent .AirspaceGeometryComponent.theAirspaceVolume.AirspaceVolume.horizontalProjection.Surface.patches .PolygonPatch.interior.Select(interior => interior.LinearRing.posList.Split(' '))) { ReverseArray(tmp); interiorCoords.AddRange(tmp); } } var combined = new List <LatLng>(); if (interiorCoords.Count > 0) { // If the polygons are overlapping, then we need to do some extra // magic to ensure the mva label is placed in the correct polygon. // To do this, we combine the exterior and interior coordinate groups // which will be used to calculate the polylabel bounding box. var combinedCoords = coords.Concat(interiorCoords).ToArray(); for (var i = 0; i < combinedCoords.Length; i += 2) { combined.Add(new LatLng(double.Parse(combinedCoords[i]), double.Parse(combinedCoords[i + 1]))); } for (var i = 0; i < combined.Count; i++) { var x1 = i == 0 ? (combined[i].Lat) : (combined[i - 1].Lat); var y1 = i == 0 ? (combined[i].Lon) : (combined[i - 1].Lon); var geo = GeoUtils.GeoToPixels(x1, y1, mCenterLat, mCenterLon); polygonTest.Add(new MyPoint(geo.X, geo.Y)); } } var temp = new List <LatLng>(); for (var i = 0; i < coords.Length; i += 2) { temp.Add(new LatLng(double.Parse(coords[i]), double.Parse(coords[i + 1]))); } for (var i = 0; i < temp.Count; i++) { var x1 = i == 0 ? (temp[i].Lat) : (temp[i - 1].Lat); var y1 = i == 0 ? (temp[i].Lon) : (temp[i - 1].Lon); if (interiorCoords.Count == 0) { var geo = GeoUtils.GeoToPixels(x1, y1, mCenterLat, mCenterLon); polygonTest.Add(new MyPoint(geo.X, geo.Y)); } } var poly = PolyLabel.GetPolyLabel(polygonTest); aggregatedCellSize += poly.Radius / 100; totalTests++; } averageCellSize = aggregatedCellSize / totalTests; }
public static PolyLabel GetPolyLabel(List <MyPoint> polygon, float precision = 1.0f, bool debug = false) { float minX = float.MaxValue; float minY = float.MaxValue; float maxX = float.MinValue; float maxY = float.MinValue; for (int i = 0; i < polygon.Count; i++) { MyPoint p = polygon[i]; if (i == 0 || p.X < minX) { minX = p.X; } if (i == 0 || p.Y < minY) { minY = p.Y; } if (i == 0 || p.X > maxX) { maxX = p.X; } if (i == 0 || p.Y > maxY) { maxY = p.Y; } } float width = maxX - minX; float height = maxY - minY; float cellSize = Math.Min(width, height); float h = cellSize / 2; SimplePriorityQueue <Cell> cellQueue = new SimplePriorityQueue <Cell>(); if (cellSize == 0) { PolyLabel degeneratePoleOfInaccessibility = new PolyLabel() { Centroid = new MyPoint(minX, minY), Radius = 0 }; return(degeneratePoleOfInaccessibility); } for (var x = minX; x < maxX; x += cellSize) { for (var y = minY; y < maxY; y += cellSize) { Cell cell = new Cell(x + h, y + h, h, polygon); cellQueue.Enqueue(cell, cell.Max); } } Cell bestCell = GetCentroidCell(polygon); Cell bBoxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon); if (bBoxCell.D > bestCell.D) { bestCell = bBoxCell; } int numProbes = cellQueue.Count; while (cellQueue.Count != 0) { // pick the most promising cell from the queue var cell = cellQueue.Dequeue(); // update the best cell if we found a better one if (cell.D > bestCell.D) { bestCell = cell; if (debug) { Console.WriteLine("found best {0} after {1} probes", Math.Round(1e4 * cell.D) / 1e4, numProbes); } } // do not drill down further if there's no chance of a better solution if (cell.Max - bestCell.D <= precision) { continue; } // split the cell into four cells h = cell.H / 2; Cell temp; temp = new Cell(cell.X - h, cell.Y - h, h, polygon); cellQueue.Enqueue(temp, temp.Max); temp = new Cell(cell.X + h, cell.Y - h, h, polygon); cellQueue.Enqueue(temp, temp.Max); temp = new Cell(cell.X - h, cell.Y + h, h, polygon); cellQueue.Enqueue(temp, temp.Max); temp = new Cell(cell.X + h, cell.Y + h, h, polygon); cellQueue.Enqueue(temp, temp.Max); numProbes += 4; } if (debug) { Console.WriteLine("num probes: " + numProbes); Console.WriteLine("best distance: " + bestCell.D); } PolyLabel poleOfInaccessibility = new PolyLabel() { Centroid = new MyPoint(bestCell.X, bestCell.Y), Radius = bestCell.D }; return(poleOfInaccessibility); }
private static void CreateMvaTextLabels(StringBuilder sb, double averageCellSize, string mvaLabel, List <MyPoint> polygonPoints) { if (string.IsNullOrEmpty(mvaLabel)) { return; } var scale = Math.Min(Math.Max(0.03f, averageCellSize), 0.5f); var polyLabel = PolyLabel.GetPolyLabel(polygonPoints); var x = polyLabel.Centroid.X - (mvaLabel.Length - 1) * 20 * scale; var y = polyLabel.Centroid.Y; foreach (var digit in mvaLabel.ToCharArray()) { switch (digit) { case '0': GetCharacterLines(HersheyFont.Zero, x, y, scale, sb); break; case '1': GetCharacterLines(HersheyFont.One, x, y, scale, sb); break; case '2': GetCharacterLines(HersheyFont.Two, x, y, scale, sb); break; case '3': GetCharacterLines(HersheyFont.Three, x, y, scale, sb); break; case '4': GetCharacterLines(HersheyFont.Four, x, y, scale, sb); break; case '5': GetCharacterLines(HersheyFont.Five, x, y, scale, sb); break; case '6': GetCharacterLines(HersheyFont.Six, x, y, scale, sb); break; case '7': GetCharacterLines(HersheyFont.Seven, x, y, scale, sb); break; case '8': GetCharacterLines(HersheyFont.Eight, x, y, scale, sb); break; case '9': GetCharacterLines(HersheyFont.Nine, x, y, scale, sb); break; } x += (20 * scale); } }