geometry: bordermesh: fix bug with one-way routes, move route calculation into triangulate()

Fixes #19
This commit is contained in:
Torrie Fischer 2021-07-08 07:55:50 -07:00
parent 51fdc80542
commit e21115cc65

View File

@ -24,35 +24,11 @@ public class BorderMesh {
Map<Region, Polygon> m_polygons; Map<Region, Polygon> m_polygons;
Map<Region, Set<Region>> m_neighbors; Map<Region, Set<Region>> m_neighbors;
// TODO: Probably need to cache the neighbors after doing all this
// intersection work! Should be generated during triangulate()
public Collection<Region> neighbors(Region region) { public Collection<Region> neighbors(Region region) {
Collection<Region> ret = new ArrayList<Region>();
if (m_neighbors.containsKey(region)) { if (m_neighbors.containsKey(region)) {
Collection<Region> allNeighbors = m_neighbors.get(region); return m_neighbors.get(region);
for(Region neighbor : allNeighbors) {
int crossings = 0;
Vector2D start = new Vector2D(region.location().getBlockX(), region.location().getBlockZ());
Vector2D neighborEnd = new Vector2D(neighbor.location().getBlockX(), neighbor.location().getBlockZ());
for(Region distantNeighbor : m_regions) {
if (distantNeighbor.equals(neighbor)) {
continue;
}
Polygon poly = m_polygons.get(distantNeighbor);
for(Polygon.Segment edge : poly.segments()) {
// Check if the line from region->neighbor intersects with
// any polygon
if (doIntersect(start, neighborEnd, edge.start, edge.end)) {
crossings++;
}
}
}
if (crossings == 1 || crossings == 0) {
ret.add(neighbor);
}
}
} }
return ret; return new ArrayList<Region>();
} }
public BorderMesh(Collection<Region> regions) { public BorderMesh(Collection<Region> regions) {
@ -191,10 +167,12 @@ public class BorderMesh {
} }
} }
HashMap<Region, Set<Region>> allNeighborSet = new HashMap<Region, Set<Region>>();
// Now we go back through our region mesh to generate vornoi points // Now we go back through our region mesh to generate vornoi points
for(Region region : m_regions) { for(Region region : m_regions) {
ArrayList<Vector2D> points = new ArrayList<Vector2D>(); ArrayList<Vector2D> points = new ArrayList<Vector2D>();
HashSet<Region> neighbors = new HashSet<Region>(); HashSet<Region> allNeighbors = new HashSet<Region>();
log.info("Executing voronoi transform..."); log.info("Executing voronoi transform...");
for(Triangle tri : triangleSoup) { for(Triangle tri : triangleSoup) {
if (tri.region == region) { if (tri.region == region) {
@ -205,36 +183,58 @@ public class BorderMesh {
Location neighborLoc = neighbor.location(); Location neighborLoc = neighbor.location();
Vector2D neighborCenter = new Vector2D(neighborLoc.getBlockX(), neighborLoc.getBlockZ()); Vector2D neighborCenter = new Vector2D(neighborLoc.getBlockX(), neighborLoc.getBlockZ());
if (vecEquals(tri.a, neighborCenter) || vecEquals(tri.b, neighborCenter) || vecEquals(tri.c, neighborCenter)) { if (vecEquals(tri.a, neighborCenter) || vecEquals(tri.b, neighborCenter) || vecEquals(tri.c, neighborCenter)) {
neighbors.add(neighbor); allNeighbors.add(neighbor);
} }
} }
points.add(tri.circumcenter()); points.add(tri.circumcenter());
} }
} }
allNeighborSet.put(region, allNeighbors);
// Sort points into a renderable polygon based on direction to center // Sort points into a renderable polygon based on direction to center
Location loc = region.location(); Location loc = region.location();
Vector2D regionCenter = new Vector2D(loc.getBlockX(), loc.getBlockZ()); Vector2D regionCenter = new Vector2D(loc.getBlockX(), loc.getBlockZ());
points.sort((Vector2D a, Vector2D b) -> Double.compare(direction(a, regionCenter), direction(b, regionCenter))); points.sort((Vector2D a, Vector2D b) -> Double.compare(direction(a, regionCenter), direction(b, regionCenter)));
log.info("Border for " + region.name() + " is defined by " + points.size() + " points"); log.fine("Border for " + region.name() + " is defined by " + points.size() + " points");
Polygon polygon = new Polygon(points); Polygon polygon = new Polygon(points);
m_polygons.put(region, polygon); m_polygons.put(region, polygon);
m_neighbors.put(region, neighbors);
}
// Now that we have the borders, we generate valid routes that cross
// zero or one border lines at most.
for(Region region : m_regions) {
Set<Region> routedNeighbors = new HashSet<Region>();
for(Region neighbor : allNeighborSet.get(region)) {
int crossings = 0;
Vector2D start = new Vector2D(region.location().getBlockX(), region.location().getBlockZ());
Vector2D neighborEnd = new Vector2D(neighbor.location().getBlockX(), neighbor.location().getBlockZ());
for(Region distantNeighbor : m_regions) {
if (distantNeighbor.equals(neighbor) || distantNeighbor.equals(region)) {
continue;
}
Polygon poly = m_polygons.get(distantNeighbor);
for(Polygon.Segment edge : poly.segments()) {
// Check if the line from region->neighbor intersects with
// any polygon
if (doIntersect(start, neighborEnd, edge.start, edge.end)) {
log.fine("Intersect " + distantNeighbor.name());
crossings++;
}
}
}
log.fine("Route: " + region.name() + " -> " + neighbor.name() + "\t" + crossings);
if (crossings == 1 || crossings == 0) {
routedNeighbors.add(neighbor);
}
}
m_neighbors.put(region, routedNeighbors);
} }
return true; return true;
} }
/*public boolean validNeighbors(Region regionA, Region regionB) {
Polygon polyA = polygonForRegion(regionA);
Polygon polyB = polygonForRegion(regionA);
Location center = region.location();
if (poly.contains(center.getBlockX(), center.getBlockZ())) {
return false;
} else {
return true;
}
}*/
private boolean vecEquals(Vector2D a, Vector2D b) { private boolean vecEquals(Vector2D a, Vector2D b) {
return a.x == b.x && a.y == b.y; return a.x == b.x && a.y == b.y;
} }