Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,21 @@ AreaGroup areaGroup() {
* indexed {@link #areasCrossedBy} crossing test on this same group.
*/
boolean containsSegment(Coordinate from, Coordinate to) {
return preparedGroup().contains(createShrunkLine(from, to));
}

/**
* Whether the area group polygon contains the given point.
*/
boolean containsPoint(Coordinate point) {
return preparedGroup().contains(GEOMETRY_FACTORY.createPoint(point));
}

private PreparedGeometry preparedGroup() {
if (preparedGroup == null) {
preparedGroup = PreparedGeometryFactory.prepare(areaGroup.getGeometry());
}
return preparedGroup.contains(createShrunkLine(from, to));
return preparedGroup;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,11 @@ private StreetVertex snapAndLink(
edge instanceof AreaEdge aEdge
) {
AreaGroup ag = aEdge.getArea();
var area = new PreparedAreaGroup(ag);
// is area already linked ?
start = linkedAreas.get(ag);
if (start == null) {
if (ag.getGeometry().contains(GEOMETRY_FACTORY.createPoint(vertex.getCoordinate()))) {
if (area.containsPoint(vertex.getCoordinate())) {
// vertex is inside an area
if (distSquared(vertex, split) <= DUPLICATE_NODE_EPSILON_DEGREES_SQUARED) {
// vertex is so close to the edge that we can use the split point directly
Expand All @@ -473,14 +474,14 @@ private StreetVertex snapAndLink(
// vertex is inside the area. try connecting the vertex to the edge's split point, because
// connections to visibility vertices may fail or do not always provide an optimal route
// note that by definition, connection to closest edge cannot be blocked and edge can be forced
addVisibilityEdges(start, split, new PreparedAreaGroup(ag), scope, tempEdges, true);
addVisibilityEdges(start, split, area, scope, tempEdges, true);
} else {
// vertex is outside an area. Use split point for area connections
start = split;
}
// connect start point to area visibility points to achieve optimal paths
if (!ag.visibilityVertices().contains(start)) {
addAreaVertex(start, ag, scope, tempEdges, false);
addAreaVertex(start, area, scope, tempEdges, false);
}
} else {
start = split;
Expand Down Expand Up @@ -661,7 +662,7 @@ public boolean equals(Object o) {
* Link a new vertex permanently with area geometry
*/
public boolean addPermanentAreaVertex(IntersectionVertex newVertex, AreaGroup areaGroup) {
return addAreaVertex(newVertex, areaGroup, Scope.PERMANENT, null, true);
return addAreaVertex(newVertex, new PreparedAreaGroup(areaGroup), Scope.PERMANENT, null, true);
}

/**
Expand All @@ -681,14 +682,13 @@ private double distSquared(Vertex a, Vertex b) {
*/
private boolean addAreaVertex(
IntersectionVertex newVertex,
AreaGroup areaGroup,
PreparedAreaGroup area,
Scope scope,
DisposableEdgeCollection tempEdges,
boolean force
) {
AreaGroup areaGroup = area.areaGroup();
Geometry polygon = areaGroup.getGeometry();
// Reused across all candidate contains() checks below so the spatial index is built only once.
var area = new PreparedAreaGroup(areaGroup);

int added = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ void doesNotContainExteriorSegment() {
assertFalse(area.containsSegment(new Coordinate(11, 11), new Coordinate(12, 12)));
}

@Test
void containsInteriorPoint() {
assertTrue(area.containsPoint(new Coordinate(1, 1)));
}

@Test
void doesNotContainPointInHole() {
// The 2x2 hole is centred at x,y in (4,6); a point in its middle is not inside the area.
assertFalse(area.containsPoint(new Coordinate(5, 5)));
}

@Test
void doesNotContainExteriorPoint() {
assertFalse(area.containsPoint(new Coordinate(11, 11)));
}

@Test
void exposesWrappedAreaGroup() {
var ag = new AreaGroup(SQUARE_WITH_HOLE);
Expand Down