org.openstreetmap.atlas.utilities.direction.EdgeDirectionComparator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of atlas Show documentation
Show all versions of atlas Show documentation
"Library to load OSM data into an Atlas format"
package org.openstreetmap.atlas.utilities.direction;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.openstreetmap.atlas.geography.Heading;
import org.openstreetmap.atlas.geography.PolyLine;
import org.openstreetmap.atlas.geography.Segment;
import org.openstreetmap.atlas.geography.atlas.builder.store.AtlasPrimitiveEdge;
import org.openstreetmap.atlas.geography.atlas.items.Edge;
import org.openstreetmap.atlas.utilities.scalars.Angle;
/**
* A set of utilities that work with {@link Edge} direction and {@link Heading}.
*
* @author Sid
*/
public final class EdgeDirectionComparator
{
/**
* Default {@link Angle} limits are used for {@link Heading} comparison. To keep it simple we
* keep the limits contiguous.
*/
public static final Angle DEFAULT_OPPOSITE_DIRECTION_LOWER_LIMIT = Angle.degrees(171);
public static final Angle DEFAULT_OPPOSITE_DIRECTION_UPPER_LIMIT = Angle.degrees(-171);
public static final Angle DEFAULT_SAME_DIRECTION_LOWER_LIMIT = Angle.degrees(-9);
public static final Angle DEFAULT_SAME_DIRECTION_UPPER_LIMIT = Angle.degrees(9);
/*
* Limit for the heading difference used for detecting if edges are in opposite direction.
*/
private final Angle oppositeDirectionLowerLimit;
private final Angle oppositeDirectionUpperLimit;
/*
* Limit for the heading difference used for detecting if edges are in same direction.
*/
private final Angle sameDirectionLowerLimit;
private final Angle sameDirectionUpperLimit;
public EdgeDirectionComparator()
{
this(DEFAULT_OPPOSITE_DIRECTION_LOWER_LIMIT, DEFAULT_OPPOSITE_DIRECTION_UPPER_LIMIT,
DEFAULT_SAME_DIRECTION_LOWER_LIMIT, DEFAULT_SAME_DIRECTION_UPPER_LIMIT);
}
public EdgeDirectionComparator(final Angle oppositeDirectionLowerLimit,
final Angle oppositeDirectionUpperLimit, final Angle sameDirectionLowerLimit,
final Angle sameDirectionUpperLimit)
{
this.oppositeDirectionLowerLimit = oppositeDirectionLowerLimit;
this.oppositeDirectionUpperLimit = oppositeDirectionUpperLimit;
this.sameDirectionLowerLimit = sameDirectionLowerLimit;
this.sameDirectionUpperLimit = sameDirectionUpperLimit;
}
public boolean isOppositeDirection(final AtlasPrimitiveEdge incomingEdge,
final AtlasPrimitiveEdge outgoingEdge, final boolean useOverallHeading)
{
if (incomingEdge.isReversedEdge(outgoingEdge))
{
return true;
}
return isOppositeDirection(incomingEdge.getPolyLine(), outgoingEdge.getPolyLine(),
useOverallHeading);
}
/*
* Detects if given edges are in opposite direction
*/
public boolean isOppositeDirection(final Edge incomingEdge, final Edge outgoingEdge,
final boolean useOverallHeading)
{
if (incomingEdge.isReversedEdge(outgoingEdge))
{
return true;
}
return isOppositeDirection(incomingEdge.asPolyLine(), outgoingEdge.asPolyLine(),
useOverallHeading);
}
public boolean isOppositeDirection(final Heading incomingEdgeHeading,
final Heading outgoingEdgeHeading)
{
final Angle headingDifference = incomingEdgeHeading.subtract(outgoingEdgeHeading);
return headingDifference.isGreaterThanOrEqualTo(this.oppositeDirectionLowerLimit)
|| headingDifference.isLessThan(this.oppositeDirectionUpperLimit);
}
public boolean isOppositeDirection(final PolyLine incomingEdgePolyline,
final PolyLine outgoingEdgePolyline, final boolean useOverallHeading)
{
return useOverallHeading
? isOppositeDirectionUsingOverallHeading(incomingEdgePolyline, outgoingEdgePolyline)
: isOppositeDirectionUsingSegmentHeading(incomingEdgePolyline,
outgoingEdgePolyline);
}
public boolean isOppositeDirectionUsingOverallHeading(final PolyLine incomingEdgePolyline,
final PolyLine outgoingEdgePolyline)
{
boolean oppositeDirection = false;
if (Math.min(incomingEdgePolyline.size(), outgoingEdgePolyline.size()) > 1)
{
final Optional incomingSegmentHeading = incomingEdgePolyline.overallHeading();
final Optional outgoingSegmentHeading = outgoingEdgePolyline.overallHeading();
if (incomingSegmentHeading.isPresent() && outgoingSegmentHeading.isPresent())
{
oppositeDirection = isOppositeDirection(incomingSegmentHeading.get(),
outgoingSegmentHeading.get());
}
}
return oppositeDirection;
}
/*
* Detects if given polylines are in opposite direction. Comparing the overall edge Heading
* might not work in case of long curvy edges. The last segment of incomingEdgePolyline and
* first segment of outgoingEdgePolyline are used to compute the heading difference. Order of
* the input polyLine matters in computation of heading.
*/
public boolean isOppositeDirectionUsingSegmentHeading(final PolyLine incomingEdgePolyline,
final PolyLine outgoingEdgePolyline)
{
boolean oppositeDirection = false;
if (Math.min(incomingEdgePolyline.size(), outgoingEdgePolyline.size()) > 1)
{
final List incomingSegments = incomingEdgePolyline.segments();
final Optional incomingSegmentHeading = incomingSegments
.get(incomingSegments.size() - 1).heading();
final Optional outgoingSegmentHeading = outgoingEdgePolyline.segments().get(0)
.heading();
if (incomingSegmentHeading.isPresent() && outgoingSegmentHeading.isPresent())
{
oppositeDirection = isOppositeDirection(incomingSegmentHeading.get(),
outgoingSegmentHeading.get());
}
}
return oppositeDirection;
}
/*
* Detects if edgeA is parallel to any of the given edges
*/
public boolean isParallel(final Edge edgeA, final Collection edges,
final boolean useOverallHeading)
{
return edges.stream().anyMatch(edge -> isParallel(edgeA, edge, useOverallHeading));
}
/*
* Detects if edgeA is parallel to edgeB. Direction doesn't matter
*/
public boolean isParallel(final Edge edgeA, final Edge edgeB, final boolean useOverallHeading)
{
return isSameDirection(edgeA, edgeB, useOverallHeading)
|| isOppositeDirection(edgeA, edgeB, useOverallHeading);
}
/*
* Detects if given Atlas Primitive edges are in same direction
*/
public boolean isSameDirection(final AtlasPrimitiveEdge edgeA, final AtlasPrimitiveEdge edgeB,
final boolean useOverallHeading)
{
// If they are reversed edges, then they are in opposite directions
if (!edgeA.isReversedEdge(edgeB))
{
return isSameDirection(edgeA.getPolyLine(), edgeB.getPolyLine(), useOverallHeading);
}
return false;
}
/*
* Detects if given edges are in same direction
*/
public boolean isSameDirection(final Edge edgeA, final Edge edgeB,
final boolean useOverallHeading)
{
// If they are reversed edges, then they are in opposite directions
if (!edgeA.isReversedEdge(edgeB))
{
return isSameDirection(edgeA.asPolyLine(), edgeB.asPolyLine(), useOverallHeading);
}
return false;
}
/*
* Detects if given headings of polylines are in same direction
*/
public boolean isSameDirection(final Heading headingA, final Heading headingB)
{
final Angle headingDifference = headingB.subtract(headingA);
final boolean sameDirection = headingDifference
.isGreaterThanOrEqualTo(this.sameDirectionLowerLimit)
&& headingDifference.isLessThan(this.sameDirectionUpperLimit);
return sameDirection;
}
/**
* Detects if given {@link PolyLine} are in same direction
*
* @param polyLineA
* First {@link PolyLine}
* @param polyLineB
* Second {@link PolyLine}
* @param useOverallHeading
* flag to indicate whether to use overall {@link Heading} or segment {@link Heading}
* @return true if {@link PolyLine}s are in same direction
*/
public boolean isSameDirection(final PolyLine polyLineA, final PolyLine polyLineB,
final boolean useOverallHeading)
{
return useOverallHeading ? isSameDirectionUsingOverallHeading(polyLineA, polyLineB)
: isSameDirectionUsingSegmentHeading(polyLineA, polyLineB);
}
/*
* Detects if given polylines are in same direction using overall heading
*/
public boolean isSameDirectionUsingOverallHeading(final PolyLine polyLineA,
final PolyLine polyLineB)
{
boolean sameDirection = false;
if (!polyLineA.isPoint() && !polyLineB.isPoint())
{
final Optional headingA = polyLineA.overallHeading();
final Optional headingB = polyLineB.overallHeading();
if (headingA.isPresent() && headingB.isPresent())
{
sameDirection = isSameDirection(headingA.get(), headingB.get());
}
}
return sameDirection;
}
/*
* Detects if given polylines are in same direction using segment heading
*/
public boolean isSameDirectionUsingSegmentHeading(final PolyLine incomingEdgePolyline,
final PolyLine outgoingEdgePolyline)
{
boolean sameDirection = false;
if (!incomingEdgePolyline.isPoint() && !outgoingEdgePolyline.isPoint())
{
final Optional incomingSegmentHeading = incomingEdgePolyline.segments()
.get(incomingEdgePolyline.segments().size() - 1).heading();
final Optional outgoingSegmentHeading = outgoingEdgePolyline.segments().get(0)
.heading();
if (incomingSegmentHeading.isPresent() && outgoingSegmentHeading.isPresent())
{
sameDirection = isSameDirection(incomingSegmentHeading.get(),
outgoingSegmentHeading.get());
}
}
return sameDirection;
}
}