/**
Ported by David Turner from Visilibity, by Karl J. Obermeyer
This port undoubtedly introduced a number of bugs (and removed some features).
Bug reports should be directed to the OpenTripPlanner project, unless they
can be reproduced in the original VisiLibity.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.opentripplanner.visibility;
import java.lang.Math;
public class VLPoint implements Comparable<VLPoint>, Cloneable {
public double x, y;
public VLPoint() {
x = Double.NaN;
y = Double.NaN;
}
public VLPoint(double x, double y) {
this.x = x;
this.y = y;
}
public VLPoint(VLPoint p) {
x = p.x;
y = p.y;
}
public VLPoint projection_onto(LineSegment line_segment_temp) {
if (line_segment_temp.size() == 1)
return line_segment_temp.first();
// The projection of point_temp onto the line determined by
// line_segment_temp can be represented as an affine combination
// expressed in the form projection of Point =
// theta*line_segment_temp.first +
// (1.0-theta)*line_segment_temp.second. if theta is outside
// the interval [0,1], then one of the LineSegment's endpoints
// must be closest to calling Point.
double theta = ((line_segment_temp.second().x - x)
* (line_segment_temp.second().x - line_segment_temp.first().x) + (line_segment_temp
.second().y - y) * (line_segment_temp.second().y - line_segment_temp.first().y))
/ (Math.pow(line_segment_temp.second().x - line_segment_temp.first().x, 2) + Math
.pow(line_segment_temp.second().y - line_segment_temp.first().y, 2));
// std::cout << "\E[1;37;40m" << "Theta is: " << theta << "\x1b[0m"
// << std::endl;
if ((0.0 <= theta) && (theta <= 1.0))
return line_segment_temp.first().times(theta)
.plus(line_segment_temp.second().times(1.0 - theta));
// Else pick closest endpoint.
if (distance(line_segment_temp.first()) < distance(line_segment_temp.second()))
return line_segment_temp.first();
return line_segment_temp.second();
}
public VLPoint projection_onto(Ray ray_temp) {
// Construct a LineSegment parallel with the Ray which is so long,
// that the projection of the the calling Point onto that
// LineSegment must be the same as the projection of the calling
// Point onto the Ray.
double R = distance(ray_temp.base_point());
LineSegment seg_approx = new LineSegment(ray_temp.base_point(), ray_temp.base_point().plus(
new VLPoint(R * Math.cos(ray_temp.bearing().get()), R
* Math.sin(ray_temp.bearing().get()))));
return projection_onto(seg_approx);
}
public VLPoint projection_onto(Polyline polyline_temp) {
VLPoint running_projection = polyline_temp.get(0);
double running_min = distance(running_projection);
VLPoint point_temp;
for (int i = 0; i <= polyline_temp.size() - 1; i++) {
point_temp = projection_onto(new LineSegment(polyline_temp.get(i),
polyline_temp.get(i + 1)));
if (distance(point_temp) < running_min) {
running_projection = point_temp;
running_min = distance(running_projection);
}
}
return running_projection;
}
public VLPoint projection_onto_vertices_of(VLPolygon polygon_temp) {
VLPoint running_projection = polygon_temp.get(0);
double running_min = distance(running_projection);
for (int i = 1; i <= polygon_temp.n() - 1; i++) {
if (distance(polygon_temp.get(i)) < running_min) {
running_projection = polygon_temp.get(i);
running_min = distance(running_projection);
}
}
return running_projection;
}
public VLPoint projection_onto_vertices_of(Environment environment_temp) {
VLPoint running_projection = projection_onto_vertices_of(environment_temp.outer_boundary);
double running_min = distance(running_projection);
VLPoint point_temp;
for (int i = 0; i < environment_temp.h(); i++) {
point_temp = projection_onto_vertices_of(environment_temp.holes.get(i));
if (distance(point_temp) < running_min) {
running_projection = point_temp;
running_min = distance(running_projection);
}
}
return running_projection;
}
public VLPoint projection_onto_boundary_of(VLPolygon polygon_temp) {
VLPoint running_projection = polygon_temp.get(0);
double running_min = distance(running_projection);
VLPoint point_temp;
for (int i = 0; i <= polygon_temp.n() - 1; i++) {
point_temp = projection_onto(new LineSegment(polygon_temp.get(i),
polygon_temp.get(i + 1)));
if (distance(point_temp) < running_min) {
running_projection = point_temp;
running_min = distance(running_projection);
}
}
return running_projection;
}
public VLPoint projection_onto_boundary_of(Environment environment_temp) {
VLPoint running_projection = projection_onto_boundary_of(environment_temp.outer_boundary);
double running_min = distance(running_projection);
VLPoint point_temp;
for (int i = 0; i < environment_temp.h(); i++) {
point_temp = projection_onto_boundary_of(environment_temp.holes.get(i));
if (distance(point_temp) < running_min) {
running_projection = point_temp;
running_min = distance(running_projection);
}
}
return running_projection;
}
public boolean on_boundary_of(VLPolygon polygon_temp, double epsilon) {
if (distance(projection_onto_boundary_of(polygon_temp)) <= epsilon) {
return true;
}
return false;
}
public boolean on_boundary_of(Environment environment_temp, double epsilon) {
if (distance(projection_onto_boundary_of(environment_temp)) <= epsilon) {
return true;
}
return false;
}
public boolean in(LineSegment line_segment_temp, double epsilon) {
if (distance(line_segment_temp) < epsilon)
return true;
return false;
}
public boolean in_relative_interior_of(LineSegment line_segment_temp, double epsilon) {
return in(line_segment_temp, epsilon) && distance(line_segment_temp.first()) > epsilon
&& distance(line_segment_temp.second()) > epsilon;
}
public void set_y(double y) {
this.y = y;
}
public void set_x(double x) {
this.x = x;
}
public boolean in(VLPolygon polygon_temp)
{
return in(polygon_temp, 0);
}
public boolean in(VLPolygon polygon_temp, double epsilon) {
int n = polygon_temp.vertices.size();
if (on_boundary_of(polygon_temp, epsilon))
return true;
// Then check the number of times a ray emanating from the Point
// crosses the boundary of the Polygon. An odd number of
// crossings indicates the Point is in the interior of the
// Polygon. Based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
boolean c = false;
for (int i = 0, j = n - 1; i < n; j = i++) {
if ((((polygon_temp.get(i).y <= y) && (y < polygon_temp.get(j).y)) || ((polygon_temp
.get(j).y <= y) && (y < polygon_temp.get(i).y)))
&& (x < (polygon_temp.get(j).x - polygon_temp.get(i).x)
* (y - polygon_temp.get(i).y)
/ (polygon_temp.get(j).y - polygon_temp.get(i).y)
+ polygon_temp.get(i).x))
c = !c;
}
return c;
}
public boolean in(Environment environment_temp, double epsilon) {
// On outer boundary?
if (on_boundary_of(environment_temp, epsilon))
return true;
// Not in outer boundary?
if (!in(environment_temp.outer_boundary, epsilon))
return false;
// In hole?
for (int i = 0; i < environment_temp.h(); i++)
if (in(environment_temp.holes.get(i)))
return false;
// Must be in interior.
return true;
}
public boolean is_endpoint_of(LineSegment line_segment_temp, double epsilon) {
if (distance(line_segment_temp.first()) <= epsilon
|| distance(line_segment_temp.second()) <= epsilon)
return true;
return false;
}
// these mean that points are not immutable (aieee!) - DT
public void snap_to_vertices_of(VLPolygon polygon_temp, double epsilon) {
VLPoint point_temp = new VLPoint(projection_onto_vertices_of(polygon_temp));
if (distance(point_temp) <= epsilon) {
x = point_temp.x;
y = point_temp.y;
}
}
public void snap_to_vertices_of(Environment environment_temp, double epsilon) {
VLPoint point_temp = new VLPoint(projection_onto_vertices_of(environment_temp));
if (distance(point_temp) <= epsilon) {
x = point_temp.x;
y = point_temp.y;
}
}
public void snap_to_boundary_of(VLPolygon polygon_temp, double epsilon) {
VLPoint point_temp = new VLPoint(projection_onto_boundary_of(polygon_temp));
if (distance(point_temp) <= epsilon) {
x = point_temp.x;
y = point_temp.y;
}
}
public void snap_to_boundary_of(Environment environment_temp, double epsilon) {
VLPoint point_temp = new VLPoint(projection_onto_boundary_of(environment_temp));
{
if (distance(point_temp) <= epsilon) {
x = point_temp.x;
y = point_temp.y;
}
}
}
public boolean equals(Object o) {
if (!(o instanceof VLPoint)) {
return false;
}
VLPoint point2 = (VLPoint) o;
return x == point2.x && y == point2.y;
}
public int compareTo(VLPoint point2) {
if (x < point2.x)
return -1;
else if (x == point2.x) {
if (y < point2.y) {
return -1;
} else if (y == point2.y) {
return 0;
}
return 1;
}
return 1;
}
public VLPoint plus(VLPoint point2) {
return new VLPoint(x + point2.x, y + point2.y);
}
public VLPoint minus(VLPoint point2) {
return new VLPoint(x - point2.x, y - point2.y);
}
public VLPoint times(VLPoint point2) {
return new VLPoint(x * point2.x, y * point2.y);
}
public VLPoint times(double scalar) {
return new VLPoint(scalar * x, scalar * y);
}
public double cross(VLPoint point2) {
// The area of the parallelogram created by the Points viewed as vectors.
return x * point2.y - point2.x * y;
}
public double distance(VLPoint point2) {
return Math.sqrt(Math.pow(x - point2.x, 2) + Math.pow(y - point2.y, 2));
}
public double distance(LineSegment line_segment_temp) {
return distance(projection_onto(line_segment_temp));
}
public double distance(Ray ray_temp) {
return distance(projection_onto(ray_temp));
}
public double distance(Polyline polyline_temp) {
double running_min = distance(polyline_temp.get(0));
double distance_temp;
for (int i = 0; i < polyline_temp.size() - 1; i++) {
distance_temp = distance(new LineSegment(polyline_temp.get(i), polyline_temp.get(i + 1)));
if (distance_temp < running_min)
running_min = distance_temp;
}
return running_min;
}
public double boundary_distance(VLPolygon polygon_temp) {
double running_min = distance(polygon_temp.get(0));
double distance_temp;
for (int i = 0; i <= polygon_temp.n(); i++) {
distance_temp = distance(new LineSegment(polygon_temp.get(i), polygon_temp.get(i + 1)));
if (distance_temp < running_min)
running_min = distance_temp;
}
return running_min;
}
public double boundary_distance(Environment environment_temp) {
double running_min = distance(environment_temp.get(0).get(0));
double distance_temp;
for (int i = 0; i <= environment_temp.h(); i++) {
distance_temp = boundary_distance(environment_temp.get(i));
if (distance_temp < running_min)
running_min = distance_temp;
}
return running_min;
}
public String toString() {
return "\n" + x + ", " + y;
}
public VLPoint clone() {
return new VLPoint(x, y);
}
public int hashCode() {
return new Double(x).hashCode() + new Double(y).hashCode();
}
}