/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.geospatial.services;
import org.onebusaway.geospatial.model.Point;
import org.onebusaway.geospatial.model.PointVector;
public class GeometryLibrary {
/***************************************************************************
* General Methods
**************************************************************************/
/**
*
*/
public static final boolean inRange(double r1, double r2, double v) {
return Math.min(r1, r2) <= v && v <= Math.max(r1, r2);
}
/***************************************************************************
* Angle Methods
**************************************************************************/
public static double normalizeAngle(double radians) {
while (radians > Math.PI)
radians -= Math.PI * 2;
while (radians < -Math.PI)
radians += Math.PI * 2;
return radians;
}
public static double getAngleDifference(double radiansA, double radiansB) {
double diff = Math.abs(normalizeAngle(radiansA) - normalizeAngle(radiansB));
if (diff > Math.PI)
diff = 2 * Math.PI - diff;
return diff;
}
public static double getRelativeAngleDifference(double from, double to) {
from = normalizeAngle(from);
to = normalizeAngle(to);
double delta = to - from;
if (delta > Math.PI)
delta -= Math.PI * 2;
if (delta < -Math.PI)
delta += Math.PI * 2;
return delta;
}
/***************************************************************************
*
**************************************************************************/
public static <P extends Point> double distance(P a, P b) {
return a.getDistance(b);
}
public static <P extends Point> double getAngle(P origin, P a, P b) {
PointVector va = PointVector.create(origin, a);
PointVector vb = PointVector.create(origin, b);
return va.getAngle(vb);
}
public static <P extends Point> P projectPointToLine(P point, P lineStart,
P lineEnd) {
PointVector v = PointVector.create(lineStart, point);
PointVector line = PointVector.create(lineStart, lineEnd);
return line.getProjection(v).addToPoint(lineStart);
}
public static <P extends Point> P projectPointToSegment(P point,
P segmentStart, P segmentEnd) {
PointVector v = PointVector.create(segmentStart, point);
PointVector line = PointVector.create(segmentStart, segmentEnd);
P p = line.getProjection(v).addToPoint(segmentStart);
if (isBetween(p, segmentStart, segmentEnd))
return p;
double a = p.getDistance(segmentStart);
double b = p.getDistance(segmentEnd);
return a <= b ? segmentStart : segmentEnd;
}
/**
* Consider a line segment defined by points 'lineStart' and 'lineEnd'.
* Consider two planes, each perpendicular to the line segment and each
* intersecting one of the endpoints of the segment. Method returns true when
* the target 'point' falls on or between these two planes.
*
* @param point
* @param lineStart
* @param lineEnd
* @return
*/
public static <P extends Point> boolean isBetween(P point, P lineStart,
P lineEnd) {
if (point.equals(lineStart) || point.equals(lineEnd))
return true;
P proj = projectPointToLine(point, lineStart, lineEnd);
double segmentLength = lineStart.getDistance(lineEnd);
double lenA = lineStart.getDistance(proj);
double lenB = lineEnd.getDistance(proj);
return lenA <= segmentLength && lenB <= segmentLength;
}
}