public List <VertexPositionColor> GetTesselationVertices(Color color) { var fakeSector = new CubeSector(CubeSector.CubeSectorFace.FRONT, 0, 0, 8); List <List <ContourVertex> > contours = new List <List <ContourVertex> >(); foreach (var inner in inners) { var innerContour = inner.Skip(1).Select(x => Vector2DToContourVertex(x, true)).ToList(); // skip 1 since our loops end in a duplicate if (innerContour.Count == 3) { // TODO: the tesselator just doesn't like triangles!? seriously?? var avg01 = new ContourVertex() { Position = new Vec3() { X = innerContour[0].Position.X / 2 + innerContour[1].Position.X / 2, Y = innerContour[0].Position.Y / 2 + innerContour[1].Position.Y / 2, Z = 0 }, Data = innerContour[0].Data }; innerContour.Insert(1, avg01); } contours.Add(innerContour); } foreach (var outer in outers) { var outerContours = new List <List <ContourVertex> >() { outer.Skip(1).Select(y => Vector2DToContourVertex(y)).ToList() }; // skip 1 since our loops end in a duplicate contours.AddRange(outerContours); } var vertices = OSMPolygonBufferGenerator.Tesselate(contours, color); return(vertices); }
// move some of our files to the Android assets folder private static void HelpZenithAndroid() { LongLat longLat = new LongLat(-87.3294527 * Math.PI / 180, 30.4668536 * Math.PI / 180); // Pensacola CubeSector ourRoot = new CubeSector(CubeSector.CubeSectorFace.LEFT, 0, 0, 0); Vector2d relativeCoord = ourRoot.ProjectToLocalCoordinates(longLat.ToSphereVector()); HashSet <ISector> sectorsToLoad = new HashSet <ISector>(); foreach (var r in ZCoords.GetSectorManager().GetTopmostOSMSectors()) { sectorsToLoad.Add(r); for (int z = 1; z <= 3; z++) { foreach (var child in r.GetChildrenAtLevel(z)) { sectorsToLoad.Add(child); } } } for (int z = 4; z <= 8; z++) { ISector sector = ourRoot.GetSectorAt(relativeCoord.X, relativeCoord.Y, z); for (int i = 0; i < 25; i++) { sectorsToLoad.Add(new CubeSector(((CubeSector)sector).sectorFace, sector.X + i / 5 - 2, sector.Y + i % 5 - 2, sector.Zoom)); } } foreach (var sector in sectorsToLoad) { MoveSectorImage(sector); MoveSectorOSM(sector); } }
public void TestParallelPerformance() { LongLat longLat = new LongLat(-87.3294527 * Math.PI / 180, 30.4668536 * Math.PI / 180); CubeSector root = new CubeSector(CubeSector.CubeSectorFace.LEFT, 0, 0, 0); Vector2d relativeCoord = root.ProjectToLocalCoordinates(longLat.ToSphereVector()); List <ISector> sectors = root.GetSectorAt(relativeCoord.X, relativeCoord.Y, 6).GetChildrenAtLevel(8); Stopwatch sw = new Stopwatch(); sw.Start(); foreach (var sector in sectors) { ProceduralTileBuffer buffer = new ProceduralTileBuffer(sector); buffer.LoadLinesFromFile(); buffer.GenerateVertices(); buffer.Dispose(); } double sequentialSecs = sw.Elapsed.TotalSeconds; // 5.585 secs sw.Restart(); Parallel.ForEach(sectors, sector => { ProceduralTileBuffer buffer = new ProceduralTileBuffer(sector); buffer.LoadLinesFromFile(); buffer.GenerateVertices(); buffer.Dispose(); }); double parallelSecs = sw.Elapsed.TotalSeconds; // 5.056 secs double speedMultiplier = sequentialSecs / parallelSecs; // 1.105 (seems to vary between 1.7 at highest and 1.1 at lowest, not the best multiplier but could still be worthwhile) }
private static void LoadAll() { GLOBAL_FINAL = new OSMMetaFinal(); // init GLOBAL_FINAL.gridPoints = new Dictionary <ISector, GridPointInfo[, ]>(); foreach (var root in ZCoords.GetSectorManager().GetTopmostOSMSectors()) { GridPointInfo[,] gp = new GridPointInfo[257, 257]; for (int x = 0; x < 257; x++) { for (int y = 0; y < 257; y++) { gp[x, y] = new GridPointInfo(); } } GLOBAL_FINAL.gridPoints[root] = gp; } for (int r = 0; r < 6; r++) { var frRoot = new CubeSector((CubeSector.CubeSectorFace)r, 0, 0, 0); string filePath = Path.Combine(OSMPaths.GetRenderRoot(), $"Coastline{frRoot.sectorFace.GetFaceAcronym()}.txt"); using (var writer = File.Open(filePath, FileMode.Open)) { using (var br = new BinaryReader(writer)) { int badRelationsCount = br.ReadInt32(); for (int i = 0; i < badRelationsCount; i++) { GLOBAL_FINAL.badRelations.Add(br.ReadInt64()); } for (int i = 0; i < 257; i++) { for (int j = 0; j < 257; j++) { GridPointInfo gridPoint = GLOBAL_FINAL.gridPoints[frRoot][i, j]; int naturalTypesCount = br.ReadInt32(); for (int k = 0; k < naturalTypesCount; k++) { gridPoint.naturalTypes.Add(br.ReadInt32()); } int relationsCount = br.ReadInt32(); for (int k = 0; k < relationsCount; k++) { gridPoint.relations.Add(br.ReadInt64()); } int waysCount = br.ReadInt32(); for (int k = 0; k < waysCount; k++) { gridPoint.ways.Add(br.ReadInt64()); } } } } } } }
private void SaveAsFile(OSMMetaManager manager, CubeSector root) { for (int i = 0; i < 257; i++) { for (int j = 0; j < 257; j++) { for (int k = 1; k < naturalTypes.Count; k++) { bool containsThisType = false; containsThisType |= gridPoints[root][i, j].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", naturalTypes[k])); containsThisType |= gridPoints[root][i, j].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", naturalTypes[k])); if (containsThisType) { gridPoints[root][i, j].naturalTypes.Add(k); } } } } string filePath = Path.Combine(OSMPaths.GetRenderRoot(), $"Coastline{root.sectorFace.GetFaceAcronym()}.txt"); using (var writer = File.Open(filePath, FileMode.Create)) { using (var bw = new BinaryWriter(writer)) { bw.Write(badRelations.Count); foreach (var relation in badRelations) { bw.Write(relation); } for (int i = 0; i < 257; i++) { for (int j = 0; j < 257; j++) { GridPointInfo gridPoint = gridPoints[root][i, j]; bw.Write(gridPoint.naturalTypes.Count); foreach (var naturalType in gridPoint.naturalTypes) { bw.Write(naturalType); } bw.Write(gridPoint.relations.Count); foreach (var relation in gridPoint.relations) { bw.Write(relation); } bw.Write(gridPoint.ways.Count); foreach (var way in gridPoint.ways) { bw.Write(way); } } } } } }
private void DoCubeFaceTest(CubeSectorFace face, LongLat longLat, bool doXNotY, double expectedAnswer) { var front = new CubeSector(face, 0, 0, 0); Vector3d normal = front.sectorFace.GetFaceNormal(); Vector3d down = front.sectorFace.GetFaceDownDirection(); Vector3d right = front.sectorFace.GetFaceRightDirection(); if (doXNotY) { ZAssert.AssertIsClose(front.GetRel(normal, right, longLat.ToSphereVector()), expectedAnswer); } else { ZAssert.AssertIsClose(front.GetRel(normal, down, longLat.ToSphereVector()), expectedAnswer); } }
public void TestSectorLoadPerformance() { LongLat longLat = new LongLat(-87.3294527 * Math.PI / 180, 30.4668536 * Math.PI / 180); CubeSector root = new CubeSector(CubeSector.CubeSectorFace.LEFT, 0, 0, 0); Vector2d relativeCoord = root.ProjectToLocalCoordinates(longLat.ToSphereVector()); ISector sector = root.GetSectorAt(relativeCoord.X, relativeCoord.Y, 8); Stopwatch sw = new Stopwatch(); sw.Start(); ProceduralTileBuffer buffer = new ProceduralTileBuffer(sector); buffer.LoadLinesFromFile(); double loadTimeSecs = sw.Elapsed.TotalSeconds; // 0.842 secs (1.781 tablet) sw.Restart(); buffer.GenerateVertices(); double vertSecs = sw.Elapsed.TotalSeconds; // 0.404 secs (0.773 tablet) }
// took 21.117584 hours to save 4.19 GB // saved to 6 different files in case it crashes public void LoadAllDetailsFromSource() { int i = 0; foreach (CubeSector root in ZCoords.GetSectorManager().GetTopmostOSMSectors()) { for (int x = 0; x < 256; x++) { for (int y = 0; y < 256; y++) { var sector = new CubeSector(root.sectorFace, x, y, 8); LoadDetailsFromSource(sector); } } SaveAll("planet-meta" + i + ".data"); Clear(); i++; } }
internal void LoadAll(string fileName) { OSMMetaManager manager = new OSMMetaManager(); if (fileName.Contains("*")) { for (int i = 0; i < 6; i++) { manager.LoadAll(fileName.Replace("*", i + "")); } } else { manager.LoadAll(fileName); } // init gridPoints = new Dictionary <ISector, GridPointInfo[, ]>(); gridTops = new Dictionary <ISector, GridPointInfo[, ]>(); gridLefts = new Dictionary <ISector, GridPointInfo[, ]>(); foreach (var root in ZCoords.GetSectorManager().GetTopmostOSMSectors()) { GridPointInfo[,] gp = new GridPointInfo[257, 257]; GridPointInfo[,] gt = new GridPointInfo[256, 257]; GridPointInfo[,] gl = new GridPointInfo[257, 256]; for (int x = 0; x < 257; x++) { for (int y = 0; y < 257; y++) { gp[x, y] = new GridPointInfo(); if (x < 256) { gt[x, y] = new GridPointInfo(); } if (y < 256) { gl[x, y] = new GridPointInfo(); } } } gridPoints[root] = gp; gridTops[root] = gt; gridLefts[root] = gl; } // find bad relations foreach (var relation in manager.relationInfo) { if (!IsValidRelation(manager, relation.Key)) { badRelations.Add(relation.Key); } } // process all edge info foreach (var edge in manager.edgeInfo) { if (!manager.wayInfo.ContainsKey(edge.wayID)) { continue; // probably doesn't exist because we've removed it to try and save some memory } foreach (var root in ZCoords.GetSectorManager().GetTopmostOSMSectors()) { var local1 = root.ProjectToLocalCoordinates(edge.longLat1.ToSphereVector()); var local2 = root.ProjectToLocalCoordinates(edge.longLat2.ToSphereVector()); if ((local1 - local2).Length() > 0.2) { continue; } // first, order by X if (local1.X > local2.X) { var temp = local2; local2 = local1; local1 = temp; } for (int x = (int)Math.Ceiling(local1.X * 256); x <= local2.X * 256; x++) { if (x == local1.X * 256) { continue; } double t = (x / 256.0 - local1.X) / (local2.X - local1.X); int y = (int)Math.Floor((local1.Y + t * (local2.Y - local1.Y)) * 256); if (x >= 0 && x < 257 && y >= 0 && y < 256) { XORWithEdge(manager, gridLefts[root][x, y], edge); } } // now, order by Y if (local1.Y > local2.Y) { var temp = local2; local2 = local1; local1 = temp; } for (int y = (int)Math.Ceiling(local1.Y * 256); y <= local2.Y * 256; y++) // BUG: can't believe this was required, but we do sometimes have nodes on exactly the edge, apparently { // ignore the edge that bruhes up exactly against the top (assuming it exists at all, since our original load logic can exclude such an edge) // with a point exactly on an edge, the -other- edge that matches exactly on bottom should trigger the flag instead (double-flag would be bad) if (y == local1.Y * 256) { continue; } double t = (y / 256.0 - local1.Y) / (local2.Y - local1.Y); int x = (int)Math.Floor((local1.X + t * (local2.X - local1.X)) * 256); // BUG: (int) is NOT THE SAME AS Math.Floor! if (x >= 0 && x < 256 && y >= 0 && y < 257) { XORWithEdge(manager, gridTops[root][x, y], edge); } } } } // now actually figure out the points // TODO: we're just doing front for now var frRoot = new CubeSector((CubeSector.CubeSectorFace) int.Parse(Regex.Match(fileName, "[0-9]").Value), 0, 0, 0); if (frRoot.sectorFace == CubeSector.CubeSectorFace.RIGHT || frRoot.sectorFace == CubeSector.CubeSectorFace.BACK) { // invert these faces gridPoints[frRoot][0, 0].naturalTypes.Add(0); } for (int y = 0; y < 257; y++) { for (int x = 0; x < 257; x++) { GridPointInfo prev; GridPointInfo next; GridPointInfo edge; if (x == 0) { if (y == 0) { continue; } prev = gridPoints[frRoot][0, y - 1]; next = gridPoints[frRoot][0, y]; edge = gridLefts[frRoot][0, y - 1]; } else { prev = gridPoints[frRoot][x - 1, y]; next = gridPoints[frRoot][x, y]; edge = gridTops[frRoot][x - 1, y]; } foreach (var n in prev.naturalTypes) { next.naturalTypes.Add(n); } foreach (var n in prev.relations) { next.relations.Add(n); } foreach (var n in prev.ways) { next.ways.Add(n); } foreach (var n in edge.naturalTypes) { if (next.naturalTypes.Contains(n)) { next.naturalTypes.Remove(n); } else { next.naturalTypes.Add(n); } } foreach (var n in edge.relations) { if (next.relations.Contains(n)) { next.relations.Remove(n); } else { next.relations.Add(n); } } foreach (var n in edge.ways) { if (next.ways.Contains(n)) { next.ways.Remove(n); } else { next.ways.Add(n); } } } } SaveAsImage(manager, frRoot); SaveAsFile(manager, frRoot); }
private void SaveAsImage(OSMMetaManager manager, CubeSector frRoot) { // finally, render those coast images string mapFile = OSMPaths.GetCoastlineImagePath(frRoot); Bitmap map = new Bitmap(256, 256); for (int i = 0; i < 256; i++) { for (int j = 0; j < 256; j++) { int land1 = gridPoints[frRoot][i, j].naturalTypes.Contains(0) ? 0 : -1; int land2 = gridPoints[frRoot][i + 1, j].naturalTypes.Contains(0) ? 0 : -1; int land3 = gridPoints[frRoot][i, j + 1].naturalTypes.Contains(0) ? 0 : -1; int land4 = gridPoints[frRoot][i + 1, j + 1].naturalTypes.Contains(0) ? 0 : -1; if (gridPoints[frRoot][i, j].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land1 = 1; } if (gridPoints[frRoot][i, j].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land1 = 1; } if (gridPoints[frRoot][i + 1, j].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land2 = 1; } if (gridPoints[frRoot][i + 1, j].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land2 = 1; } if (gridPoints[frRoot][i, j + 1].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land3 = 1; } if (gridPoints[frRoot][i, j + 1].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land3 = 1; } if (gridPoints[frRoot][i + 1, j + 1].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land4 = 1; } if (gridPoints[frRoot][i + 1, j + 1].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "water"))) { land4 = 1; } if (gridPoints[frRoot][i, j].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land1 = 2; } if (gridPoints[frRoot][i, j].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land1 = 2; } if (gridPoints[frRoot][i + 1, j].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land2 = 2; } if (gridPoints[frRoot][i + 1, j].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land2 = 2; } if (gridPoints[frRoot][i, j + 1].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land3 = 2; } if (gridPoints[frRoot][i, j + 1].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land3 = 2; } if (gridPoints[frRoot][i + 1, j + 1].relations.Any(x => manager.relationInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land4 = 2; } if (gridPoints[frRoot][i + 1, j + 1].ways.Any(x => manager.wayInfo[x].ContainsKeyValue(manager, "natural", "glacier"))) { land4 = 2; } Color color = Color.FromArgb(128, 128, 128); if (land1 == 2 && land2 == 2 && land3 == 2 && land4 == 2) { color = Color.FromArgb(255, 255, 255); } if (land1 == 1 && land2 == 1 && land3 == 1 && land4 == 1) { color = Color.FromArgb(0, 0, 255); } if (land1 == 0 && land2 == 0 && land3 == 0 && land4 == 0) { color = Color.FromArgb(0, 255, 0); } if (land1 == -1 && land2 == -1 && land3 == -1 && land4 == -1) { color = Color.FromArgb(0, 0, 255); } //color = Color.FromArgb(255, 255, 255); //if (gridTops[frRoot][i, j].relations.Any(x => x == 1279614)) color = Color.FromArgb(0, 255, 0); //if (gridLefts[frRoot][i, j].relations.Any(x => x == 1279614)) color = Color.FromArgb(255, 0, 0); //if (gridLefts[frRoot][i, j].relations.Any(x => x == 1279614) && gridTops[frRoot][i, j].relations.Any(x => x == 1279614)) color = Color.FromArgb(0, 0, 0); map.SetPixel(i, j, color); } } map.Save(mapFile, ImageFormat.Png); }