in commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractConvexPolygon3D.java [215:281]
public Vector3D closest(final Vector3D pt) {
final Vector3D normal = plane.getNormal();
final Precision.DoubleEquivalence precision = plane.getPrecision();
final List<Vector3D> vertices = getVertices();
final Vector3D projPt = plane.project(pt);
Vector3D edgeVec;
Vector3D edgePlusVec;
Vector3D testVec;
Vector3D offsetVec;
double offsetSign;
double offset;
int cmp;
Vector3D boundaryVec;
double boundaryPointT;
Vector3D boundaryPoint;
double boundaryPointDistSq;
double closestBoundaryPointDistSq = Double.POSITIVE_INFINITY;
Vector3D closestBoundaryPoint = null;
Vector3D startVertex = vertices.get(vertices.size() - 1);
for (final Vector3D nextVertex : vertices) {
edgeVec = startVertex.vectorTo(nextVertex);
edgePlusVec = edgeVec.cross(normal);
testVec = startVertex.vectorTo(projPt);
offsetVec = testVec.reject(edgeVec);
offsetSign = Math.signum(offsetVec.dot(edgePlusVec));
offset = offsetSign * offsetVec.norm();
cmp = precision.compare(offset, 0.0);
if (cmp >= 0) {
// the point is on directly on the boundary or on its plus side; project the point onto the
// boundary, taking care to restrict the point to the actual extent of the boundary,
// and select the point with the shortest distance
boundaryVec = testVec.subtract(offsetVec);
boundaryPointT =
Math.signum(boundaryVec.dot(edgeVec)) * (boundaryVec.norm() / Vectors.checkedNorm(edgeVec));
boundaryPointT = Math.max(0, Math.min(1, boundaryPointT));
boundaryPoint = startVertex.lerp(nextVertex, boundaryPointT);
boundaryPointDistSq = boundaryPoint.distanceSq(projPt);
if (boundaryPointDistSq < closestBoundaryPointDistSq) {
closestBoundaryPointDistSq = boundaryPointDistSq;
closestBoundaryPoint = boundaryPoint;
}
}
startVertex = nextVertex;
}
if (closestBoundaryPoint != null) {
// the point is on the outside of the polygon; return the closest point on the boundary
return closestBoundaryPoint;
}
// the projected point is on the inside of all boundaries and therefore on the inside of the subset
return projPt;
}