| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
package org.locationtech.jts.algorithm; |
| 14 |
|
| 15 |
import org.locationtech.jts.geom.Coordinate; |
| 16 |
import org.locationtech.jts.math.Vector3D; |
| 17 |
|
| 18 |
/** |
| 19 |
* Basic computational geometry algorithms |
| 20 |
* for geometry and coordinates defined in 3-dimensional Cartesian space. |
| 21 |
* |
| 22 |
* @author mdavis |
| 23 |
* |
| 24 |
*/ |
| 25 |
public class CGAlgorithms3D |
| 26 |
{ |
| 27 |
private CGAlgorithms3D() {} |
| 28 |
|
| 29 |
public static double distance(Coordinate p0, Coordinate p1) |
| 30 |
{ |
| 31 |
|
| 32 |
if (Double.isNaN(p0.getZ()) || Double.isNaN(p1.getZ())) |
| 33 |
return p0.distance(p1); |
| 34 |
|
| 35 |
double dx = p0.x - p1.x; |
| 36 |
double dy = p0.y - p1.y; |
| 37 |
double dz = p0.getZ() - p1.getZ(); |
| 38 |
return Math.sqrt(dx * dx + dy * dy + dz * dz); |
| 39 |
} |
| 40 |
|
| 41 |
public static double distancePointSegment(Coordinate p, |
| 42 |
Coordinate A, Coordinate B) { |
| 43 |
|
| 44 |
if (A.equals3D(B)) |
| 45 |
return distance(p, A); |
| 46 |
|
| 47 |
|
| 48 |
|
| 49 |
|
| 50 |
|
| 51 |
|
| 52 |
|
| 53 |
|
| 54 |
|
| 55 |
|
| 56 |
|
| 57 |
|
| 58 |
|
| 59 |
|
| 60 |
|
| 61 |
double len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y) + (B.getZ() - A.getZ()) * (B.getZ() - A.getZ()); |
| 62 |
if (Double.isNaN(len2)) |
| 63 |
throw new IllegalArgumentException("Ordinates must not be NaN"); |
| 64 |
double r = ((p.x - A.x) * (B.x - A.x) + (p.y - A.y) * (B.y - A.y) + (p.getZ() - A.getZ()) * (B.getZ() - A.getZ())) |
| 65 |
/ len2; |
| 66 |
|
| 67 |
if (r <= 0.0) |
| 68 |
return distance(p, A); |
| 69 |
if (r >= 1.0) |
| 70 |
return distance(p, B); |
| 71 |
|
| 72 |
|
| 73 |
double qx = A.x + r * (B.x - A.x); |
| 74 |
double qy = A.y + r * (B.y - A.y); |
| 75 |
double qz = A.getZ() + r * (B.getZ() - A.getZ()); |
| 76 |
|
| 77 |
double dx = p.x - qx; |
| 78 |
double dy = p.y - qy; |
| 79 |
double dz = p.getZ() - qz; |
| 80 |
return Math.sqrt(dx*dx + dy*dy + dz*dz); |
| 81 |
} |
| 82 |
|
| 83 |
|
| 84 |
/** |
| 85 |
* Computes the distance between two 3D segments. |
| 86 |
* |
| 87 |
* @param A the start point of the first segment |
| 88 |
* @param B the end point of the first segment |
| 89 |
* @param C the start point of the second segment |
| 90 |
* @param D the end point of the second segment |
| 91 |
* @return the distance between the segments |
| 92 |
*/ |
| 93 |
public static double distanceSegmentSegment( |
| 94 |
Coordinate A, Coordinate B, Coordinate C, Coordinate D) |
| 95 |
{ |
| 96 |
/** |
| 97 |
* This calculation is susceptible to roundoff errors when |
| 98 |
* passed large ordinate values. |
| 99 |
* It may be possible to improve this by using {@link DD} arithmetic. |
| 100 |
*/ |
| 101 |
if (A.equals3D(B)) |
| 102 |
return distancePointSegment(A, C, D); |
| 103 |
if (C.equals3D(B)) |
| 104 |
return distancePointSegment(C, A, B); |
| 105 |
|
| 106 |
/** |
| 107 |
* Algorithm derived from http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm |
| 108 |
*/ |
| 109 |
double a = Vector3D.dot(A, B, A, B); |
| 110 |
double b = Vector3D.dot(A, B, C, D); |
| 111 |
double c = Vector3D.dot(C, D, C, D); |
| 112 |
double d = Vector3D.dot(A, B, C, A); |
| 113 |
double e = Vector3D.dot(C, D, C, A); |
| 114 |
|
| 115 |
double denom = a*c - b*b; |
| 116 |
if (Double.isNaN(denom)) |
| 117 |
throw new IllegalArgumentException("Ordinates must not be NaN"); |
| 118 |
|
| 119 |
double s; |
| 120 |
double t; |
| 121 |
if (denom <= 0.0) { |
| 122 |
/** |
| 123 |
* The lines are parallel. |
| 124 |
* In this case solve for the parameters s and t by assuming s is 0. |
| 125 |
*/ |
| 126 |
s = 0; |
| 127 |
|
| 128 |
if (b > c) |
| 129 |
t = d/b; |
| 130 |
else |
| 131 |
t = e/c; |
| 132 |
} |
| 133 |
else { |
| 134 |
s = (b*e - c*d) / denom; |
| 135 |
t = (a*e - b*d) / denom; |
| 136 |
} |
| 137 |
if (s < 0) |
| 138 |
return distancePointSegment(A, C, D); |
| 139 |
else if (s > 1) |
| 140 |
return distancePointSegment(B, C, D); |
| 141 |
else if (t < 0) |
| 142 |
return distancePointSegment(C, A, B); |
| 143 |
else if(t > 1) { |
| 144 |
return distancePointSegment(D, A, B); |
| 145 |
} |
| 146 |
/** |
| 147 |
* The closest points are in interiors of segments, |
| 148 |
* so compute them directly |
| 149 |
*/ |
| 150 |
double x1 = A.x + s * (B.x - A.x); |
| 151 |
double y1 = A.y + s * (B.y - A.y); |
| 152 |
double z1 = A.getZ() + s * (B.getZ() - A.getZ()); |
| 153 |
|
| 154 |
double x2 = C.x + t * (D.x - C.x); |
| 155 |
double y2 = C.y + t * (D.y - C.y); |
| 156 |
double z2 = C.getZ() + t * (D.getZ() - C.getZ()); |
| 157 |
|
| 158 |
|
| 159 |
return distance(new Coordinate(x1, y1, z1), new Coordinate(x2, y2, z2)); |
| 160 |
} |
| 161 |
|
| 162 |
|
| 163 |
} |
| 164 |
|