private void AddUntouchedLoop(SectorConstrainedOSMAreaGraph map, List <Way> superLoop) { List <AreaNode> newNodes = new List <AreaNode>(); var broken = BreakDownSuperLoop(superLoop); for (int i = 0; i < broken.Count - 1; i++) // since our loops end in a duplicate { AreaNode curr = new AreaNode() { id = broken[i] }; newNodes.Add(curr); if (!map.nodes.ContainsKey(broken[i])) { map.nodes[broken[i]] = new List <AreaNode>(); } map.nodes[broken[i]].Add(curr); } for (int i = 0; i < newNodes.Count; i++) { AreaNode prev = newNodes[i]; AreaNode next = newNodes[(i + 1) % newNodes.Count]; prev.next = next; next.prev = prev; } }
private SectorConstrainedOSMAreaGraph GridToArea(bool[,] grid, int size, BlobCollection blobs) { SectorConstrainedOSMAreaGraph newMap = new SectorConstrainedOSMAreaGraph(); for (int i = 0; i < size * size; i++) { if (grid[i / size, i % size]) { int x1 = i / size; int y1 = i % size; int x2 = i / size + 1; int y2 = i % size + 1; if (x1 == 0 || !grid[x1 - 1, y1]) { AddLine(blobs.nodes, newMap, x1, y1, x1, y2, true); // down } if (y2 == size || !grid[x1, y2]) { AddLine(blobs.nodes, newMap, x1, y2, x2, y2, true); // right } if (x2 == size || !grid[x2, y1]) { AddLine(blobs.nodes, newMap, x2, y2, x2, y1, true); // up } if (y1 == 0 || !grid[x1, y1 - 1]) { AddLine(blobs.nodes, newMap, x2, y1, x1, y1, true); // left } } } return(newMap); }
private void RandomSubtractTest(Random rand) { var blobs = new BlobCollection(); int size = 2; bool[,] grid1 = RandomGrid(rand, size); bool[,] grid2 = RandomGrid(rand, size); bool[,] grid3 = SubtractGrids(grid1, grid2, size); if (!IsValidGrid(grid1, size)) { return; } if (!IsValidGrid(grid2, size)) { return; } int expectedArea = AreaOfGrid(grid3, size); SectorConstrainedOSMAreaGraph asGraph1 = GridToArea(grid1, size, blobs); SectorConstrainedOSMAreaGraph asGraph2 = GridToArea(grid2, size, blobs); double area = GetArea(asGraph1.Subtract(asGraph2, blobs).Finalize(blobs).GetTesselationVertices(Color.White)); if (expectedArea != area) { throw new NotImplementedException(); } }
private static SectorConstrainedOSMAreaGraph MakeOpenRect(Dictionary <long, Vector2d> nodes, int x1, int y1, int x2, int y2, bool leftOpen, bool cornersOnly) { SectorConstrainedOSMAreaGraph graph = new SectorConstrainedOSMAreaGraph(); if (!leftOpen) { AddLine(nodes, graph, x1, y1, x1, y2, cornersOnly); // down } AddLine(nodes, graph, x1, y2, x2, y2, cornersOnly); // right if (leftOpen) { AddLine(nodes, graph, x2, y2, x2, y1, cornersOnly); // up } AddLine(nodes, graph, x2, y1, x1, y1, cornersOnly); // left if (leftOpen) { MarkStartPoint(graph, x1, y2); MarkEndPoint(graph, x1, y1); } else { MarkStartPoint(graph, x2, y1); MarkEndPoint(graph, x2, y2); } return(graph); }
private static void AddLine(Dictionary <long, Vector2d> nodes, SectorConstrainedOSMAreaGraph graph, int x1, int y1, int x2, int y2, bool cornersOnly) { if (cornersOnly) { AddLineSeg(nodes, graph, x1, y1, x2, y2); } else { if (x1 == x2) { int length = Math.Abs(y2 - y1); int inc = (y2 - y1) / length; for (int i = 0; i < length; i++) { AddLineSeg(nodes, graph, x1, y1 + i * inc, x2, y1 + (i + 1) * inc); } } else if (y1 == y2) { int length = Math.Abs(x2 - x1); int inc = (x2 - x1) / length; for (int i = 0; i < length; i++) { AddLineSeg(nodes, graph, x1 + i * inc, y1, x1 + (i + 1) * inc, y2); } } else { throw new NotImplementedException(); } } }
public void Load(BlobCollection blobs) { if (loaded) { return; } graph = isCoast ? blobs.GetCoastAreaMap(key, value) : blobs.GetAreaMap(key, value); loaded = true; }
public void Load(BlobCollection blobs) { if (loaded) { return; } polygonSource.Load(blobs); graph = polygonSource.GetGraph(); loaded = true; }
private static SectorConstrainedOSMAreaGraph MakeRect(Dictionary <long, Vector2d> nodes, int x1, int y1, int x2, int y2, bool cornersOnly) { SectorConstrainedOSMAreaGraph graph = new SectorConstrainedOSMAreaGraph(); AddLine(nodes, graph, x1, y1, x1, y2, cornersOnly); // down AddLine(nodes, graph, x1, y2, x2, y2, cornersOnly); // right AddLine(nodes, graph, x2, y2, x2, y1, cornersOnly); // up AddLine(nodes, graph, x2, y1, x1, y1, cornersOnly); // left return(graph); }
private static void TestAddThenSubtract(int size1, int offsetX1, int offsetY1, int size2, int offsetX2, int offsetY2, int size3, int area, BlobCollection blobs, bool cornersOnly) { SectorConstrainedOSMAreaGraph square1 = MakeRect(blobs.nodes, 0, 0, size1, size1, cornersOnly); SectorConstrainedOSMAreaGraph square2 = MakeRect(blobs.nodes, offsetX1, offsetY1, offsetX1 + size2, offsetY1 + size2, cornersOnly); SectorConstrainedOSMAreaGraph square3 = MakeRect(blobs.nodes, offsetX2, offsetY2, offsetX2 + size3, offsetY2 + size3, cornersOnly); double areaAns = GetArea(square1.Subtract(square2.Add(square3, blobs), blobs).Finalize(blobs).GetTesselationVertices(Color.White)); if (areaAns != area) { throw new NotImplementedException(); } }
public void Dispose() { if (polygonSource1 != null) { polygonSource1.Dispose(); } if (polygonSource2 != null) { polygonSource2.Dispose(); } graph = null; map = null; }
public void Dispose() { if (polygonSource != null) { polygonSource.Dispose(); } graph = null; lineGraph = null; foreach (var pair in bufferCache) { pair.Value.Dispose(); } }
public void Load(BlobCollection blobs) { if (loaded) { return; } polygonSource1.Load(blobs); polygonSource2.Load(blobs); graph = polygonSource1.GetGraph().Subtract(polygonSource2.GetGraph(), blobs); if (Constants.DEBUG_MODE) { graph.CheckValid(); } loaded = true; }
internal SectorConstrainedOSMAreaGraph GetCoastAreaMap(string key, string value) { // remember: "If you regard this as tracing around an area of land, then the coastline way should be running counterclockwise." // gather ways with matching starts/ends to form a super-way, coast ways should always run the same direction, so this becomes easier SuperWayCollection superWays = GenerateSuperWayCollection(EnumerateWays().Where(x => x.keyValues.ContainsKey(key) && x.keyValues[key] == value), false); SectorConstrainedOSMAreaGraph map = DoMultipolygon(superWays); if (OSMMetaFinal.IsPixelLand(sector) || borderWay.refs.Count > 5) // just return a big ol' square { SectorConstrainedOSMAreaGraph temp = new SectorConstrainedOSMAreaGraph(); for (int i = 1; i < borderWay.refs.Count; i++) { if (!temp.nodes.ContainsKey(borderWay.refs[i])) { temp.nodes[borderWay.refs[i]] = new List <AreaNode>(); temp.nodes[borderWay.refs[i]].Add(new AreaNode() { id = borderWay.refs[i] }); } } for (int i = 1; i < borderWay.refs.Count; i++) { AreaNode prev = temp.nodes[borderWay.refs[i - 1]].Single(); AreaNode next = temp.nodes[borderWay.refs[i]].Single(); if (prev.id != next.id) { prev.next = next; next.prev = prev; } } map = map.Intersect(temp, this); } BlobsIntersector.FixLoops(new List <SectorConstrainedOSMAreaGraph>() { map }, this); if (Constants.DEBUG_MODE) { map.CheckValid(); } return(map); }
private SectorConstrainedOSMAreaGraph DoMultipolygon(SuperWayCollection superWays) { SectorConstrainedOSMAreaGraph map = new SectorConstrainedOSMAreaGraph(); foreach (var superWay in superWays.linkedWays) // we expect these to always start and end outside the sector { AddConstrainedPaths(map, superWay); } map.CloseLines(this); map.RemoveDuplicateLines(); if (Constants.DEBUG_MODE) { map.CheckValid(); } foreach (var superLoop in superWays.loopedWays) { double wayArea = GetArea(superLoop); if (Math.Abs(wayArea) < SMALLEST_ALLOWED_AREA) { continue; // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? } bool isCW = wayArea < 0; var temp = new SectorConstrainedOSMAreaGraph(); bool untouchedLoop = CheckIfUntouchedAndSpin(superLoop); if (untouchedLoop) { AddUntouchedLoop(temp, superLoop); } else { AddConstrainedPaths(temp, superLoop); } temp.CloseLines(this); temp.RemoveDuplicateLines(); if (Constants.DEBUG_MODE) { temp.CheckValid(); } map.Add(temp, this); } return(map); }
private static void TestAddAndSubtract(int size1, int offsetX, int offsetY, int size2, BlobCollection blobs, int addArea, int subArea, bool testOpen, bool cornersOnly) { if (!testOpen) { SectorConstrainedOSMAreaGraph square1 = MakeRect(blobs.nodes, 0, 0, size1, size1, cornersOnly); SectorConstrainedOSMAreaGraph square2 = MakeRect(blobs.nodes, offsetX, offsetY, offsetX + size2, offsetY + size2, cornersOnly); var blobs2 = Clone(blobs); // clone since we modify blobs now //if (square1.Clone().Add(square2, blobs).Area(blobs) != addArea) throw new NotImplementedException(); //if (square1.Clone().Subtract(square2, blobs).Area(blobs) != subArea) throw new NotImplementedException(); double area1 = GetArea(square1.Clone().Add(square2, blobs).Finalize(blobs).GetTesselationVertices(Color.White)); double area2 = GetArea(square1.Clone().Subtract(square2, blobs2).Finalize(blobs2).GetTesselationVertices(Color.White)); if (area1 != addArea) { throw new NotImplementedException(); } if (area2 != subArea) { throw new NotImplementedException(); } } else { // test some coastline stuff SectorConstrainedOSMAreaGraph square1 = MakeOpenRect(blobs.nodes, 0, 0, size1, size1, true, cornersOnly); // leave left open SectorConstrainedOSMAreaGraph square2 = MakeOpenRect(blobs.nodes, offsetX, offsetY, offsetX + size2, offsetY + size2, false, cornersOnly); // leave right open var blobs2 = Clone(blobs); // clone since we modify blobs now double area1 = GetArea(square1.Clone().Add(square2, blobs).Finalize(blobs).GetTesselationVertices(Color.White)); double area2 = GetArea(square1.Clone().Subtract(square2, blobs2).Finalize(blobs2).GetTesselationVertices(Color.White)); if (area1 != addArea) { throw new NotImplementedException(); } if (area2 != subArea) { throw new NotImplementedException(); } } }
private static void AddLineSeg(Dictionary <long, Vector2d> nodes, SectorConstrainedOSMAreaGraph graph, int x1, int y1, int x2, int y2) { long n1 = (x1 + 500) * 1000 + (y1 + 500); long n2 = (x2 + 500) * 1000 + (y2 + 500); if (!graph.nodes.ContainsKey(n1)) { graph.nodes.Add(n1, new List <AreaNode>() { new AreaNode() { id = n1 } }); } if (!nodes.ContainsKey(n1)) { nodes[n1] = new Vector2d(x1, y1); } if (!graph.nodes.ContainsKey(n2)) { graph.nodes.Add(n2, new List <AreaNode>() { new AreaNode() { id = n2 } }); } if (!nodes.ContainsKey(n2)) { nodes[n2] = new Vector2d(x2, y2); } graph.nodes[n1].Single().next = graph.nodes[n2].Single(); graph.nodes[n2].Single().prev = graph.nodes[n1].Single(); }
private static void MarkStartPoint(SectorConstrainedOSMAreaGraph graph, int x, int y) { long n = (x + 500) * 1000 + (y + 500); graph.nodes.Remove(n); }
private void OrientSuperWays(SuperWayCollection superInnerWays, SuperWayCollection superOuterWays, bool topLeftIsInside) { List <List <Way> > allLinkedWays = new List <List <Way> >(); allLinkedWays.AddRange(superInnerWays.linkedWays); allLinkedWays.AddRange(superOuterWays.linkedWays); List <List <Way> > allLoopedWays = new List <List <Way> >(); allLoopedWays.AddRange(superInnerWays.loopedWays); allLoopedWays.AddRange(superOuterWays.loopedWays); // assume all loops dont touch the edge for now (they can be corrected later) foreach (var superLoop in allLoopedWays) { SectorConstrainedOSMAreaGraph temp = new SectorConstrainedOSMAreaGraph(); bool isCW = ApproximateCW(superLoop); if (isCW) // TODO: why did I have this has the opposite logic before?? { // force to be an "outer" superLoop.Reverse(); foreach (var way in superLoop) { way.refs.Reverse(); } } } // now do the -real- orienting List <SuperWayIntersection> intersections = new List <SuperWayIntersection>(); foreach (var superWay in superOuterWays.linkedWays) // we expect these to always start and end outside the sector { AddIntersections(intersections, superWay, false); } foreach (var superLoop in superOuterWays.loopedWays) { bool untouchedLoop = CheckIfUntouchedAndSpin(superLoop); if (!untouchedLoop) { AddIntersections(intersections, superLoop, false); } } if (intersections.Count == 0 && topLeftIsInside) { // we are inside some quite large relation - let's add the big ol' box so we can subtract from it superOuterWays.loopedWays.Add(new List <Way>() { borderWay }); } foreach (var superWay in superInnerWays.linkedWays) // we expect these to always start and end outside the sector { AddIntersections(intersections, superWay, true); } foreach (var superLoop in superInnerWays.loopedWays) { bool untouchedLoop = CheckIfUntouchedAndSpin(superLoop); if (!untouchedLoop) { AddIntersections(intersections, superLoop, true); } } if (intersections.Count % 2 != 0) { throw new NotImplementedException(); } intersections = intersections.OrderBy(x => (Math.Atan2(x.intersection.Y - 0.5, x.intersection.X - 0.5) + 8 * Math.PI - (-Math.PI * 3 / 4)) % (2 * Math.PI)).ToList(); // clockwise order starting at top-left // look for duplicates that are near each other, had this issue with relation 534928, if they're close enough we'll just ignore them for now - TODO: this may cause issues later HashSet <int> ignore = new HashSet <int>(); for (int i = 0; i < intersections.Count; i++) { int j = (i + 1) % intersections.Count; if ((intersections[i].intersection - intersections[j].intersection).Length() < 0.0000001) { ignore.Add(i); ignore.Add(j); } } HashSet <List <Way> > correctDirectionHash = new HashSet <List <Way> >(); HashSet <List <Way> > incorrectDirectionHash = new HashSet <List <Way> >(); for (int i = 0; i < intersections.Count; i++) { if (ignore.Contains(i)) { continue; } bool correctDirection = intersections[i].leaving == (topLeftIsInside ^ (i % 2 == 1)); if (intersections[i].inner) { correctDirection = !correctDirection; // flip all of the inners back, since we're about to subtract them } if (correctDirection) { correctDirectionHash.Add(intersections[i].superWay); if (incorrectDirectionHash.Contains(intersections[i].superWay)) { throw new NotImplementedException(); // disagreement } } else { incorrectDirectionHash.Add(intersections[i].superWay); if (correctDirectionHash.Contains(intersections[i].superWay)) { throw new NotImplementedException(); // disagreement } } } foreach (var superWay in incorrectDirectionHash) { superWay.Reverse(); foreach (var way in superWay) { way.refs.Reverse(); } } }
internal SectorConstrainedOSMAreaGraph GetAreaMap(string key, string value) { var simpleWays = EnumerateWays().Where(x => x.keyValues.ContainsKey(key) && x.keyValues[key] == value); // we expect all of these to be closed loops // copy this dang multipolygon way id gathering logic Dictionary <long, Way> wayLookup = new Dictionary <long, Way>(); foreach (var way in EnumerateWays()) { wayLookup[way.id] = way; } List <List <long> > inners = new List <List <long> >(); List <List <long> > outers = new List <List <long> >(); List <long> relationIds = new List <long>(); HashSet <long> otherInnerOuters = new HashSet <long>(); foreach (var blob in blobs) { if (blob.type != "OSMData") { continue; } int typeIndex = blob.pBlock.stringtable.vals.IndexOf("type"); int multipolygonIndex = blob.pBlock.stringtable.vals.IndexOf("multipolygon"); int outerIndex = blob.pBlock.stringtable.vals.IndexOf("outer"); int innerIndex = blob.pBlock.stringtable.vals.IndexOf("inner"); int keyIndex = blob.pBlock.stringtable.vals.IndexOf(key); int valueIndex = blob.pBlock.stringtable.vals.IndexOf(value); if (new[] { typeIndex, multipolygonIndex, outerIndex, innerIndex, keyIndex, valueIndex }.Contains(-1)) { continue; } foreach (var pGroup in blob.pBlock.primitivegroup) { foreach (var relation in pGroup.relations) { bool isKeyValue = false; bool isTypeMultipolygon = false; for (int i = 0; i < relation.keys.Count; i++) { if (relation.keys[i] == keyIndex && relation.vals[i] == valueIndex) { isKeyValue = true; } if (relation.keys[i] == typeIndex && relation.vals[i] == multipolygonIndex) { isTypeMultipolygon = true; } } if (isTypeMultipolygon) { if (isKeyValue) { List <long> innerWayIds = new List <long>(); List <long> outerWayIds = new List <long>(); for (int i = 0; i < relation.roles_sid.Count; i++) { // just outer for now if (relation.types[i] == 1) { if (relation.roles_sid[i] == 0 && innerIndex != 0 && outerIndex != 0) { // some ways are in a relation without any inner/outer tag // ex: 359181377 in relation 304768 outerWayIds.Add(relation.memids[i]); } else { if (relation.roles_sid[i] == innerIndex) { innerWayIds.Add(relation.memids[i]); } if (relation.roles_sid[i] == outerIndex) { outerWayIds.Add(relation.memids[i]); } } } } inners.Add(innerWayIds); outers.Add(outerWayIds); relationIds.Add(relation.id); } else { for (int i = 0; i < relation.roles_sid.Count; i++) { // just outer for now if (relation.types[i] == 1) { otherInnerOuters.Add(relation.memids[i]); } } } } } } } HashSet <long> innersAndOuters = new HashSet <long>(); foreach (var innerList in inners) { foreach (var inner in innerList) { innersAndOuters.Add(inner); } } foreach (var outerList in outers) { foreach (var outer in outerList) { innersAndOuters.Add(outer); } } // end gathering logic // add each simple way, flipping them where necessary List <SectorConstrainedOSMAreaGraph> addingMaps = new List <SectorConstrainedOSMAreaGraph>(); foreach (var way in simpleWays) { if (innersAndOuters.Contains(way.id)) { continue; // sometimes lake multipolygons also tag several pieces - at best this is redundant, and at worst causes errors } if (way.refs.Count < 3) { continue; // we -usually- only ever see lines with multipolygons, but I found a weird way like 43435045 } if (way.selfIntersects) { continue; // just ignore ways like 43410874 to keep you sane } SectorConstrainedOSMAreaGraph simpleMap = new SectorConstrainedOSMAreaGraph(); var superLoop = new List <Way>() { way }; if (way.refs.Last() != way.refs.First()) { if (otherInnerOuters.Contains(way.id)) { continue; // unsure of how else to ignore bad ways like 43815149 } way.refs.Add(way.refs.First()); // some folks forget to close a simple way, or perhaps the mistake is tagging subcomponents of a relation } if (!IsValid(superLoop)) { continue; // ignore relations like 512080985 which contain duplicate nodes } double wayArea = GetArea(superLoop); if (Math.Abs(wayArea) < SMALLEST_ALLOWED_AREA) { continue; // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? } bool isCW = wayArea < 0; if (isCW) { way.refs.Reverse(); // the simple polygons are always "outers" } bool untouchedLoop = CheckIfUntouchedAndSpin(superLoop); if (untouchedLoop) { AddUntouchedLoop(simpleMap, superLoop); } else { AddConstrainedPaths(simpleMap, superLoop); simpleMap.CloseLines(this); if (Constants.DEBUG_MODE) { simpleMap.CheckValid(); } } simpleMap.RemoveDuplicateLines(); if (Constants.DEBUG_MODE) { simpleMap.CheckValid(); } addingMaps.Add(simpleMap); } // construct each multipolygon to add separately for (int i = 0; i < inners.Count; i++) // foreach multipolygon, basically { if (OSMMetaFinal.GLOBAL_FINAL.badRelations.Contains(relationIds[i])) { continue; } // TODO: with islands inside of ponds inside of islands inside of ponds, etc. we wouldn't expect this to work // however, we're taking advantage of the fact that Add/Subtract doesn't check for that for now (until Finalize) SuperWayCollection superInnerWays = GenerateSuperWayCollection(inners[i].Where(x => wayLookup.ContainsKey(x)).Select(x => Copy(wayLookup[x])), true); SuperWayCollection superOuterWays = GenerateSuperWayCollection(outers[i].Where(x => wayLookup.ContainsKey(x)).Select(x => Copy(wayLookup[x])), true); superInnerWays.loopedWays = superInnerWays.loopedWays.Where(x => Math.Abs(GetArea(x)) >= SMALLEST_ALLOWED_AREA).ToList(); // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? superOuterWays.loopedWays = superOuterWays.loopedWays.Where(x => Math.Abs(GetArea(x)) >= SMALLEST_ALLOWED_AREA).ToList(); // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? if (!IsValid(superInnerWays)) { continue; } if (!IsValid(superOuterWays)) { continue; } OrientSuperWays(superInnerWays, superOuterWays, gridPointInfo.relations.Contains(relationIds[i])); SectorConstrainedOSMAreaGraph innerMap = DoMultipolygon(superInnerWays); SectorConstrainedOSMAreaGraph outerMap = DoMultipolygon(superOuterWays); if (Constants.DEBUG_MODE) { innerMap.CheckValid(); } if (Constants.DEBUG_MODE) { outerMap.CheckValid(); } SectorConstrainedOSMAreaGraph multiPolygon = outerMap.Subtract(innerMap, this); if (Constants.DEBUG_MODE) { multiPolygon.CheckValid(); } addingMaps.Add(multiPolygon); } SectorConstrainedOSMAreaGraph map = new SectorConstrainedOSMAreaGraph(); BlobsIntersector.FixLoops(addingMaps, this); foreach (var addingMap in addingMaps) { map.Add(addingMap, this); } if (Constants.DEBUG_MODE) { map.CheckValid(); } return(map); }
private void AddConstrainedPaths(SectorConstrainedOSMAreaGraph map, List <Way> superWay) { if (sector.ContainsCoord(nodes[superWay.First().refs.First()])) { throw new NotImplementedException(); } if (sector.ContainsCoord(nodes[superWay.Last().refs.Last()])) { throw new NotImplementedException(); } List <AreaNode> nodesToAdd = new List <AreaNode>(); for (int i = 0; i < superWay.Count; i++) { for (int j = 1; j < superWay[i].refs.Count; j++) { long next = superWay[i].refs[j]; nodesToAdd.Add(new AreaNode() { id = next }); } } for (int i = 0; i < nodesToAdd.Count; i++) { var prev = nodesToAdd[(i + nodesToAdd.Count - 1) % nodesToAdd.Count]; var curr = nodesToAdd[i]; var next = nodesToAdd[(i + 1) % nodesToAdd.Count]; if (sector.BorderContainsCoord(nodes[curr.id])) { bool add = false; if (!sector.BorderContainsCoord(nodes[next.id]) && sector.ContainsCoord(nodes[next.id])) { curr.next = next; next.prev = curr; add = true; } if (!sector.BorderContainsCoord(nodes[prev.id]) && sector.ContainsCoord(nodes[prev.id])) { curr.prev = prev; prev.next = curr; add = true; } if (sector.BorderContainsCoord(nodes[prev.id]) && nodes[prev.id].X != nodes[curr.id].X && nodes[prev.id].Y != nodes[curr.id].Y) { prev.next = curr; curr.prev = prev; add = true; if (!map.nodes.ContainsKey(prev.id)) { map.nodes[prev.id] = new List <AreaNode>(); } map.nodes[prev.id].Add(prev); } if (add) { if (!map.nodes.ContainsKey(curr.id)) { map.nodes[curr.id] = new List <AreaNode>(); } map.nodes[curr.id].Add(curr); } } else if (sector.ContainsCoord(nodes[curr.id])) { if (!map.nodes.ContainsKey(curr.id)) { map.nodes[curr.id] = new List <AreaNode>(); } map.nodes[curr.id].Add(curr); if (!sector.ContainsCoord(nodes[prev.id])) { throw new NotImplementedException(); // previous should be border point or inside } if (!sector.ContainsCoord(nodes[next.id])) { throw new NotImplementedException(); // next should be border point or inside } if (!sector.BorderContainsCoord(nodes[prev.id])) { curr.prev = prev; // edges will handle their prev/next logic } if (!sector.BorderContainsCoord(nodes[next.id])) { curr.next = next; } } } }
private void ToughTest() { var blobs = new BlobCollection(); SectorConstrainedOSMAreaGraph coast = new SectorConstrainedOSMAreaGraph(); AddLineSeg(blobs.nodes, coast, 6, 6, 6, 5); AddLineSeg(blobs.nodes, coast, 6, 5, 6, 4); AddLineSeg(blobs.nodes, coast, 6, 4, 6, 3); AddLineSeg(blobs.nodes, coast, 6, 3, 5, 2); AddLineSeg(blobs.nodes, coast, 5, 2, 3, 2); AddLineSeg(blobs.nodes, coast, 3, 2, 2, 2); AddLineSeg(blobs.nodes, coast, 2, 2, 1, 2); MarkStartPoint(coast, 6, 6); MarkEndPoint(coast, 1, 2); SectorConstrainedOSMAreaGraph bigLake = new SectorConstrainedOSMAreaGraph(); AddLineSeg(blobs.nodes, bigLake, 7, 0, 3, 0); AddLineSeg(blobs.nodes, bigLake, 3, 0, 3, 1); AddLineSeg(blobs.nodes, bigLake, 3, 1, 4, 1); AddLineSeg(blobs.nodes, bigLake, 4, 1, 5, 2); AddLineSeg(blobs.nodes, bigLake, 5, 2, 6, 3); AddLineSeg(blobs.nodes, bigLake, 6, 3, 6, 4); AddLineSeg(blobs.nodes, bigLake, 6, 4, 6, 5); AddLineSeg(blobs.nodes, bigLake, 6, 5, 7, 5); AddLineSeg(blobs.nodes, bigLake, 7, 5, 7, 0); SectorConstrainedOSMAreaGraph smallLake = new SectorConstrainedOSMAreaGraph(); AddLineSeg(blobs.nodes, smallLake, 2, 1, 2, 2); AddLineSeg(blobs.nodes, smallLake, 2, 2, 3, 2); AddLineSeg(blobs.nodes, smallLake, 3, 2, 5, 4); AddLineSeg(blobs.nodes, smallLake, 5, 4, 6, 4); AddLineSeg(blobs.nodes, smallLake, 6, 4, 3, 1); AddLineSeg(blobs.nodes, smallLake, 3, 1, 2, 1); double coastArea = GetArea(coast.Finalize(blobs).GetTesselationVertices(Color.White)); if (coastArea != 19.5 - 10) { throw new NotImplementedException(); // sure, minus 10 because everything's scaled up and we can't properly close } double bigLakeArea = GetArea(bigLake.Finalize(blobs).GetTesselationVertices(Color.White)); if (bigLakeArea != 10) { throw new NotImplementedException(); } double smallLakeArea = GetArea(smallLake.Finalize(blobs).GetTesselationVertices(Color.White)); if (smallLakeArea != 3.5) { throw new NotImplementedException(); } var lakes = bigLake.Clone().Add(smallLake, blobs); double lakesArea = GetArea(lakes.Finalize(blobs).GetTesselationVertices(Color.White)); // if (lakesArea != 13.5) throw new NotImplementedException(); // looks like the tesselator is filling in the hole? var final = coast.Clone().Subtract(lakes, blobs); double finalArea = GetArea(final.Finalize(blobs).GetTesselationVertices(Color.White)); if (finalArea != 17.5 - 10) { throw new NotImplementedException(); // sure, minus 10 because everything's scaled up and we can't properly close } }
public void Dispose() { graph = null; map = null; }