public Vector3D closest()

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;
    }