public static void WriteToStream(this TiledBarrierGraph.BarrierGraphEnumerator enumerator, Stream stream) { var graph = enumerator.Graph; stream.Write(enumerator.GetEdgeGuid().ToByteArray()); var vertex2Guid = graph.GetVertexGuid(enumerator.Vertex2); stream.Write(vertex2Guid.ToByteArray()); var shape = enumerator.Shape; stream.Write(BitConverter.GetBytes(shape.Length)); for (var s = 0; s < shape.Length; s++) { stream.Write(TileStatic.ToLocalTileCoordinates(graph.Zoom, shape[s], 16384).GetBytes()); } var tags = enumerator.Tags; stream.Write(BitConverter.GetBytes(tags.Count)); foreach (var tag in tags) { stream.WriteWithSize(tag.Key); stream.WriteWithSize(tag.Value); } }
/// <summary> /// Builds a guid for the given face. /// </summary> /// <param name="graph">The graph.</param> /// <param name="face">The face.</param> public static Guid?GetFaceGuid(this TiledBarrierGraph graph, int face) { var locations = graph.FaceToClockwiseCoordinates(face).Select(x => TileStatic.ToLocalTileCoordinates(14, x, 16384)).ToArray(); return(GetFaceGuidFor(locations)); }
internal static void AddTileFor(this TiledBarrierGraph graph, int vertex, Func <uint, IEnumerable <OsmGeo> > getTile, Func <TagsCollectionBase, bool> isBarrier) { var vLocation = graph.GetVertex(vertex); var t = TileStatic.WorldTileLocalId(vLocation.longitude, vLocation.latitude, graph.Zoom); graph.AddTiles(new[] { t }, getTile, isBarrier); }
/// <summary> /// Builds a guid for the given vertex. /// </summary> /// <param name="graph">The graph.</param> /// <param name="vertex">The vertex.</param> public static Guid GetVertexGuid(this TiledBarrierGraph graph, int vertex) { // we have a planar graph so location <-> guid. // we generate an id based on the vertex location relative in a tile. var location = graph.GetVertex(vertex); var tileLocation = TileStatic.ToLocalTileCoordinates(graph.Zoom, location, 16384); return(GuidUtility.Create(Namespace, tileLocation.GetBytes())); }
public IActionResult GetMvt(int z, uint x, uint y) { if (z != 14) { return(NotFound()); } var tile = TileStatic.ToLocalId(x, y, z); try { var box = TileStatic.Box(z, tile); var landusePolygons = LandusePolygons.GetLandusePolygons(box, z, Startup.TileSource.GetTile, t => { if (DefaultMergeFactorCalculator.Landuses.TryCalculateValue(t, out var type)) { return(type); } return(null); }).Select(p => new Feature(p.polygon, new AttributesTable { { "type", p.landuseType } })); var layer = new Layer { Name = "landuse" }; foreach (var loc in landusePolygons) { layer.Features.Add(loc); } var vectorTile = new VectorTile { TileId = new NetTopologySuite.IO.VectorTiles.Tiles.Tile((int)x, (int)y, z).Id }; vectorTile.Layers.Add(layer); var memoryStream = new MemoryStream(); vectorTile.Write(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); return(new FileStreamResult(memoryStream, "application/x-protobuf")); } catch (Exception e) { Console.WriteLine(e); throw; } }
public IEnumerable <OsmGeo> GetTile(uint t) { // TODO: async this and use task.delay below to prevent thread starvation! // wait until tile is removed from queue. while (true) { lock (Lock) { if (_tiles.ContainsKey(t)) { Thread.Sleep(200); } else { _tiles[t] = t; break; } } } try { var z = 14; var(x, y) = TileStatic.ToTile(z, t); var tileUrlFormatted = _tileUrl.Replace("{x}", x.ToString()) .Replace("{y}", y.ToString()) .Replace("{z}", z.ToString()); var stream = _downloader.Download(tileUrlFormatted, _cachePath); if (stream == null) { return(Enumerable.Empty <OsmGeo>()); } try { return((new XmlOsmStreamSource(stream)).ToList()); } catch (Exception e) { _logger.LogWarning(e, "Failed to parse tile: {z}{x}/{y}.", 14, x, y); return(Enumerable.Empty <OsmGeo>()); } } finally { _tiles.Remove(t, out _); } }
static async Task Main(string[] args) { var logFile = Path.Combine("logs", "log-{Date}.txt"); Log.Logger = new LoggerConfiguration() #if DEBUG .MinimumLevel.Debug() #else .MinimumLevel.Information() #endif .Enrich.FromLogContext() .WriteTo.RollingFile(new JsonFormatter(), logFile) .WriteTo.Console() .CreateLogger(); var cacheFolder = "/media/xivk/2T-SSD-EXT/temp"; var tileUrl = "https://data1.anyways.eu/tiles/full/20200628-150902/14/{x}/{y}.osm"; var osmTileSource = new OsmTileSource(tileUrl, cacheFolder); bool IsBarrier(TagsCollectionBase?tags) { if (tags == null) { return(false); } return(DefaultMergeFactorCalculator.Barriers.TryCalculateValue(tags, out _)); } var box = ((4.604644775390625, 51.382066781130575), (4.94384765625, 51.19655766797793)); var tiles = box.TilesFor(14).Select(x => TileStatic.ToLocalId(x, 14)); foreach (var tile in tiles) { Log.Information($"Processing tile {TileStatic.ToTile(14, tile)}..."); await TiledBarrierGraphBuilder.BuildForTile(tile, cacheFolder, x => { Log.Information($"Fetching OSM data tile {TileStatic.ToTile(14, x)}..."); return(osmTileSource.GetTile(x)); }, IsBarrier); } }
public IEnumerable <Feature> Get(int z, uint x, uint y) { var tile = TileStatic.ToLocalId(x, y, z); var box = TileStatic.Box(z, tile); var landusePolygons = LandusePolygons.GetLandusePolygons(box, z, Startup.TileSource.GetTile, t => { if (DefaultMergeFactorCalculator.Landuses.TryCalculateValue(t, out var type)) { return(type); } return(null); }).Select(p => new Feature(p.polygon, new AttributesTable { { "type", p.landuseType } })); return(landusePolygons); }
/// <summary> /// Builds a guid for the given edge. /// </summary> /// <param name="enumerator">The enumerator moved to the edge.</param> public static Guid GetEdgeGuid(this TiledBarrierGraph.BarrierGraphEnumerator enumerator) { var bytes = new List <byte>(); if (!enumerator.Forward) { var otherEnumerator = enumerator.Graph.GetEnumerator(); otherEnumerator.MoveTo(enumerator.Vertex2); otherEnumerator.MoveNextUntil(enumerator.Edge); enumerator = otherEnumerator; } foreach (var c in enumerator.CompleteShape()) { var tiledLocation = TileStatic.ToLocalTileCoordinates(enumerator.Graph.Zoom, c, 16384); bytes.AddRange(tiledLocation.GetBytes()); } return(GuidUtility.Create(Namespace, bytes)); }
public void LoadWorld(int id) { Logger.Log("Loading world id " + id, true); //Clear ALL enemies/projectiles/tiles/etc entityLivings.Clear(); tiles.Clear(); if (id == 0) { player = Player.CreatePlayer(new Vector2(0, 0), 1); TileStatic.CreateTileStatic(new Rectangle(0, 0, 512, 512), Assets.tile_grass1, 0); TileStatic.CreateTileStatic(new Rectangle(512, 0, 64, 512), Assets.tile_rockwall, 4, true, Directions.West); TileStatic.CreateTileStatic(new Rectangle(0, 512, 512, 64), Assets.tile_rockwall, 4, true, Directions.North); TileStatic.CreateTileStatic(new Rectangle(512, 512, 64, 64), Assets.tile_rockwall, 4, true, Directions.NorthWest); //TileTrigger.CreateTileTrigger(new Rectangle(64, 0, 64, 64), true, 5, "<intro_3>"); TileTrigger.CreateTileTriggerDialogue(new Rectangle(64, 0, 64, 64), false, "<default>"); TileTrigger.CreateTileTriggerKillBox(new Rectangle(128, 0, 64, 64), false); ItemEntity.CreateItemEntity(new Vector2(576 + 64, 576), Vector2.Zero, ItemStack.CreateItemStack(ItemWeapon.CreateItemWeapon(0), 1), 1); ItemEntity.CreateItemEntity(new Vector2(576 + 128, 576 - 36), Vector2.Zero, ItemStack.CreateItemStack(ItemWeapon.CreateItemWeapon(1), 58), 1); Enemy.CreateEnemy(new Vector2(576, 0), 2, 0); ambientColor = new Color(25, 25, 50, 100); } if (id == 1) { player = Player.CreatePlayer(Vector2.Zero, 1); Enemy.CreateEnemy(new Vector2(500, 300), 1, 0); Enemy.CreateEnemy(new Vector2(300, 500), 1, 1); TileStatic.CreateTileStatic(new Rectangle(128, 128, 64, 64), "tile_grass1", 0); TileStatic.CreateTileStatic(new Rectangle(128, 360, 128, 64), "tile_grass1", 0); } drawnTileRenderTarget = false; }
static void Main(string[] args) { var logFile = Path.Combine("logs", "log-{Date}.txt"); Log.Logger = new LoggerConfiguration() #if DEBUG .MinimumLevel.Debug() #else .MinimumLevel.Information() #endif .Enrich.FromLogContext() .WriteTo.RollingFile(new JsonFormatter(), logFile) .WriteTo.Console() .CreateLogger(); var cacheFolder = "/media/xivk/2T-SSD-EXT/temp"; var tileUrl = "https://data1.anyways.eu/tiles/full/20200628-150902/14/{x}/{y}.osm"; var osmTileSource = new OsmTileSource(tileUrl, cacheFolder); bool IsBarrier(TagsCollectionBase?tags) { if (tags == null) { return(false); } return(DefaultMergeFactorCalculator.Barriers.TryCalculateValue(tags, out _)); } var wechelderzande1 = (4.801913201808929, 51.26797859372288); var wechelderzande2 = (4.774868488311768, 51.267366046233136); var wechelderzande3 = (4.774868488311768, 51.267366046233136); var wechelderzande4 = (4.774868488311768, 51.267366046233136); var staden = (3.0198, 50.9743); var leyton = (-0.00303, 51.56436); var lille = (4.82594, 51.24203); var lilleLinksIndustrie = (4.803589582443237, 51.2536864893987); var lilleIndustrie = (4.815917015075683, 51.248807861598635); var lilleZagerijstraat = (4.8164963722229, 51.233426555935694); var vorselaarSassenhout = (4.807709455490112, 51.21146402264062); var vorselaarBeek = (4.7949743270874015, 51.204624839889235); var tile1 = TileStatic.WorldTileLocalId(wechelderzande1, 14); var tile2 = TileStatic.WorldTileLocalId(wechelderzande2, 14); var tile = TileStatic.WorldTileLocalId(vorselaarBeek, 14); var graph = LoadForTileTest.Default.RunPerformance((tile, osmTileSource, IsBarrier), 1); var result = AssignFaceTest.Default.RunPerformance((graph, tile)); File.WriteAllText("barriers.geojson", graph.ToFeatures().ToFeatureCollection().ToGeoJson()); return; while (!result.success) { // extra tiles need loading. AddTilesTest.Default.RunPerformance((graph, result.missingTiles, osmTileSource, IsBarrier)); // try again. result = AssignFaceTest.Default.RunPerformance((graph, tile)); } // assign landuse. // // var landuseFeatures = NTSExtensions.FromGeoJson(File.ReadAllText("test.geojson")); // // IEnumerable<(Polygon polygon, string type)> GetLanduse(((double longitude, double latitude) topLeft, (double longitude, double latitude) bottomRight) box) // { // return new (Polygon polygon, string type)[] { (landuseFeatures.First().Geometry as Polygon, "residential") }; // } IEnumerable <(Polygon polygon, string type)> GetLanduse( ((double longitude, double latitude)topLeft, (double longitude, double latitude)bottomRight) box) { return(LandusePolygons.GetLandusePolygons(box, graph.Zoom, osmTileSource.GetTile, t => { if (DefaultMergeFactorCalculator.Landuses.TryCalculateValue(t, out var type)) { return type; } return null; })); } graph.AssignLanduse(tile, GetLanduse); File.WriteAllText("barriers.geojson", graph.ToFeatures().ToFeatureCollection().ToGeoJson()); var outerBox = graph.OuterBox(tile); // get all landuse polygon in the larger box. var landuse = GetLanduse(outerBox).ToList(); File.WriteAllText("landuse.geojson", landuse.Select(x => new Feature(x.polygon, new AttributesTable { { "type", x.type } })).ToFeatureCollection().ToGeoJson()); // var tile = TileStatic.ToLocalId(8411,5466, 14); // // // load data for tile. // var graph = new TiledBarrierGraph(); // graph.LoadForTile(tile, osmTileSource.GetTile, IsBarrier); // // // run face assignment for the tile. // var result = graph.AssignFaces(tile); // while (!result.success) // { // // extra tiles need loading.- // graph.AddTiles(result.missingTiles, osmTileSource.GetTile, IsBarrier); // // // try again. // result = graph.AssignFaces(tile); // } // // File.WriteAllText("barriers.geojson", graph.ToFeatures().ToFeatureCollection().ToGeoJson()); // // var landuse = NTSExtensions.FromGeoJson(File.ReadAllText("test.geojson")); // // IEnumerable<(Polygon polygon, string type)> GetLanduse(((double longitude, double latitude) topLeft, (double longitude, double latitude) bottomRight) box) // { // return new (Polygon polygon, string type)[] { (landuse.First().Geometry as Polygon, "residential") }; // } // graph.AssignLanduse(tile, GetLanduse); // // File.WriteAllText("barriers.geojson", graph.ToFeatures().ToFeatureCollection().ToGeoJson()); // // TiledBarrierGraphBuilder.BuildForTile(tile, cacheFolder, osmTileSource.GetTile, IsBarrier); // //TiledBarrierGraphBuilder.BuildForTile(tile2, "cache", GetTile, IsBarrier); // // var polygonGraph = new TiledPolygonGraph(); // polygonGraph.AddTileFromStream(tile, // new GZipStream(File.OpenRead(Path.Combine(cacheFolder, $"{tile1}.tile.graph.zip")), // CompressionMode.Decompress)); // // polygonGraph.AddTileFromStream(tile2, // // new GZipStream(File.OpenRead(Path.Combine("cache", $"{tile2}.tile.graph.zip")), // // CompressionMode.Decompress)); // // File.WriteAllText("barriers.geojson", polygonGraph.ToFeatures().ToFeatureCollection().ToGeoJson()); }
private static IEnumerable <uint> Add(this TiledBarrierGraph graph, IEnumerable <OsmGeo> osmGeos, Func <TagsCollectionBase, bool> isBarrier) { var uncoveredTiles = new HashSet <uint>(); // collect all nodes with more than one barrier way. var nodes = new Dictionary <long, (double longitude, double latitude)?>(); var vertexNodes = new Dictionary <long, int>(); foreach (var osmGeo in osmGeos) { if (!(osmGeo is Way way)) { continue; } if (way.Nodes == null) { continue; } if (!isBarrier(way.Tags)) { continue; } for (var n = 0; n < way.Nodes.Length; n++) { var nodeId = way.Nodes[n]; if (graph.TryGetVertex(nodeId, out var vertex)) { // node already there as a vertex. vertexNodes[nodeId] = vertex; } else { // not yet a vertex. // keep first, last and reused nodes are intersections. if (n == 0 || n == way.Nodes.Length - 1 || nodes.ContainsKey(nodeId)) { vertexNodes[nodeId] = int.MaxValue; } } nodes[nodeId] = null; } } // add all vertices new vertices and store node locations. using var enumerator = osmGeos.GetEnumerator(); var hasNext = true; while (hasNext) { hasNext = enumerator.MoveNext(); if (!hasNext) { break; } if (!(enumerator.Current is Node node)) { break; } if (node.Id == null || node.Latitude == null || node.Longitude == null) { continue; } if (graph.TryGetVertex(node.Id.Value, out _)) { continue; } if (!nodes.ContainsKey(node.Id.Value)) { continue; // not part of a barrier way. } nodes[node.Id.Value] = (node.Longitude.Value, node.Latitude.Value); var tile = TileStatic.WorldTileLocalId(node.Longitude.Value, node.Latitude.Value, graph.Zoom); if (!vertexNodes.ContainsKey(node.Id.Value) && graph.HasTile(tile)) { continue; // node is not a vertex and inside a loaded tile. } var vertex = graph.AddVertex(node.Longitude.Value, node.Latitude.Value, node.Id.Value); vertexNodes[node.Id.Value] = vertex; if (!graph.HasTile(tile)) { uncoveredTiles.Add(tile); } } // add all edges. var shape = new List <(double longitude, double latitude)>(); while (hasNext) { if (!hasNext) { break; } if (!(enumerator.Current is Way way)) { break; } if (way.Nodes == null || way.Tags == null || way.Id == null) { hasNext = enumerator.MoveNext(); continue; } if (!isBarrier(way.Tags)) { hasNext = enumerator.MoveNext(); continue; } if (graph.HasWay(way.Id.Value)) { hasNext = enumerator.MoveNext(); continue; } // way is a barrier, add it as one or more edges. shape.Clear(); var vertex1 = int.MaxValue; foreach (var node in way.Nodes) { if (!vertexNodes.TryGetValue(node, out var vertex)) { if (!nodes.TryGetValue(node, out var nodeLocation)) { throw new InvalidDataException( $"Node {node} in way {way.Id} not found!"); } if (nodeLocation == null) { OsmSharp.Logging.Logger.Log(nameof(TiledBarrierGraphBuilder), TraceEventType.Warning, $"Node location for node {node} in way {way.Id} not found!"); } else { shape.Add(nodeLocation.Value); } continue; } else if (vertex == int.MaxValue) { OsmSharp.Logging.Logger.Log(nameof(TiledBarrierGraphBuilder), TraceEventType.Warning, $"Node {node} in way {way.Id} not found in tile!"); continue; } if (vertex1 == int.MaxValue) { vertex1 = vertex; continue; } graph.AddEdgeFlattened(vertex1, vertex, shape, way.Tags, way.Id.Value); vertex1 = vertex; shape.Clear(); } hasNext = enumerator.MoveNext(); } return(uncoveredTiles); }
internal static uint TileFor(this TiledBarrierGraph graph, int vertex) { var l = graph.GetVertex(vertex); return(TileStatic.WorldTileLocalId(l.longitude, l.latitude, graph.Zoom)); }
public static (bool success, IEnumerable <uint> missingTiles) AssignFaces(this TiledBarrierGraph graph, uint tile) { if (!graph.HasTile(tile)) { return(false, new[] { tile }); } var tileBox = TileStatic.Box(graph.Zoom, tile); var tilesMissing = new HashSet <uint>(); graph.ResetFaces(); // the default face for the case where a loop cannot be found. var unAssignableFace = graph.AddFace(); // check each edges for faces and if missing assign them. var enumerator = graph.GetEnumerator(); for (var v = 0; v < graph.VertexCount; v++) { if (!enumerator.MoveTo(v)) { continue; } if (!enumerator.MoveNext()) { continue; } var vBox = graph.GetVertexBox(v); if (vBox == null || !vBox.Value.Overlaps(tileBox)) { continue; } // var vTile = TileStatic.WorldTileLocalId(vLocation.longitude, vLocation.latitude, graph.Zoom); // if (vTile != tile) continue; enumerator.MoveTo(v); while (enumerator.MoveNext()) { if (enumerator.Forward && enumerator.FaceRight != int.MaxValue) { continue; } if (!enumerator.Forward && enumerator.FaceLeft != int.MaxValue) { continue; } // check if the edge bbox overlaps the tiles. var eBox = enumerator.Box; if (!eBox.Overlaps(tileBox)) { continue; } // ok this edge has an undetermined face. var result = enumerator.AssignFace(unAssignableFace); if (!result.success) { tilesMissing.UnionWith(result.missingTiles); } } } if (tilesMissing.Count > 0) { return(false, tilesMissing); } return(true, Enumerable.Empty <uint>()); }
public void LoadWorldFromFile(string mapFilePath, bool playerDefaultPos = true) { tiles.Clear(); entityLivings.Clear(); itemEntities.Clear(); player = Player.CreatePlayer(new Vector2(0, 0), 1); string[] data = Utilities.ReadFile(mapFilePath, "<data>"); int numberTiles = Int32.Parse(data[0]), numberEntities = Int32.Parse(data[1]); for (int i = 0; i < numberTiles; i++) { string[] tileData = Utilities.ReadFile(mapFilePath, "<tile" + (i + 1) + ">"); string type = tileData[0]; switch (type) { case "static": { Rectangle bounds = Utilities.CreateRectangleFromStrings(tileData[1].Split(',')); string texName = tileData[2]; int createLayer = Int32.Parse(tileData[3]); string rawisWall = tileData[4]; bool isWall = rawisWall == "true" ? true : false; TileStatic.CreateTileStatic(bounds, texName, createLayer, isWall, ParseDirections.ParseStringToDirections(tileData[5])); break; } case "trigger": { string triggerType = tileData[1]; string[] bounds = tileData[2].Split(','); switch (triggerType) { case "dialogue": { string rawtriggerOnce = tileData[3]; bool triggerOnce = rawtriggerOnce == "true" ? true : false; string dialogueKey = tileData[4]; TileTrigger.CreateTileTriggerDialogue(Utilities.CreateRectangleFromStrings(bounds), triggerOnce, dialogueKey); break; } case "damage": { TileTrigger.CreateTileTriggerDamageBox(Utilities.CreateRectangleFromStrings(bounds), false, 0); //todo implement damage tile trigger break; } case "kill": { TileTrigger.CreateTileTriggerKillBox(Utilities.CreateRectangleFromStrings(bounds), false); break; } } break; } } } for (int i = 0; i < numberEntities; i++) { string[] entityData = Utilities.ReadFile(mapFilePath, "<entity" + (i + 1) + ">"); string type = entityData[0]; int id = Int32.Parse(entityData[1]); Vector2 pos = Utilities.CreateVector2FromStrings(entityData[2].Split(',')); int layer = Int32.Parse(entityData[3]); switch (type) { case "enemy": { Enemy.CreateEnemy(pos, layer, id); break; } case "item": { //ItemEntity.CreateItemEntity(pos, ) break; } } } }
/*public void DrawTileRenderTarget(GraphicsDeviceManager graphics, SpriteBatch batch) * { //More efficent to do this way, as static tiles never move and so never need to be redrawn * graphics.GraphicsDevice.SetRenderTarget(tileRenderTarget); * graphics.GraphicsDevice.Clear(new Color(0, 0, 0, 0)); * * foreach (Tile tile in tiles) * { * tile.Draw(batch); * } * * graphics.GraphicsDevice.SetRenderTarget(null); * * drawnTileRenderTarget = true; * }*/ public void Draw(GraphicsDeviceManager graphics, GraphicsDevice device, SpriteBatch batch) { drawBGLayers(batch); //batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullCounterClockwise, null); //if (!drawnTileRenderTarget) //DrawTileRenderTarget(graphics, batch); //batch.End(); //camera.Pos += camera.Offset; batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullCounterClockwise, null, camera.GetTransformation()); //PrimiviteDrawing.DrawRectangle(null, batch, finalRect, 1, Color.Red); batch.Draw((Texture2D)tileRenderTarget, Vector2.Zero, null, Color.White, 0f, new Vector2(0, 0), 1f, SpriteEffects.None, 0f); Rectangle finalRect = new Rectangle((int)camera.Pos.X - cameraRect.Width / 2, (int)camera.Pos.Y - cameraRect.Height / 2, 1280, 720); foreach (Tile tile in tiles) { if (tile.rect.Intersects(finalRect)) { tile.Draw(batch); } if (tile is TileStatic) { TileStatic staticTile = (TileStatic)tile; if (drawTileDEBUG) { staticTile.DrawDEBUG(batch, camera); } } } foreach (EntityLiving living in entityLivings) { if (living.hitbox.Intersects(finalRect)) { living.Draw(batch); } } foreach (Particle particle in particles) { if (particle.hitbox.Intersects(finalRect)) { particle.Draw(batch); } } foreach (ItemEntity iEnt in itemEntities) { if (iEnt.hitbox.Intersects(finalRect)) { iEnt.Draw(batch); } } batch.End(); batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null); player.guiHUD.Draw(batch); player.guiInventory.Draw(batch); batch.End(); }
private static byte[] GetVertexLocationBytes(this TiledBarrierGraph graph, int v) { return(TileStatic.ToLocalTileCoordinates(graph.Zoom, graph.GetVertex(v), 16384).GetBytes()); }