Beispiel #1
0
_ccd_inline ccd_real_t __ccdVec3PointSegmentDist2(const ccd_vec3_t *P,
                                                  const ccd_vec3_t *x0,
                                                  const ccd_vec3_t *b,
                                                  ccd_vec3_t *witness)
{
    // The computation comes from solving equation of segment:
    //      S(t) = x0 + t.d
    //          where - x0 is initial point of segment
    //                - d is direction of segment from x0 (|d| > 0)
    //                - t belongs to <0, 1> interval
    // 
    // Than, distance from a segment to some point P can be expressed:
    //      D(t) = |x0 + t.d - P|^2
    //          which is distance from any point on segment. Minimization
    //          of this function brings distance from P to segment.
    // Minimization of D(t) leads to simple quadratic equation that's
    // solving is straightforward.
    //
    // Bonus of this method is witness point for free.

    ccd_real_t dist, t;
    ccd_vec3_t d, a;

    // direction of segment
    ccdVec3Sub2(&d, b, x0);

    // precompute vector from P to x0
    ccdVec3Sub2(&a, x0, P);

    t  = -CCD_REAL(1.) * ccdVec3Dot(&a, &d);
    t /= ccdVec3Len2(&d);

    if (t < CCD_ZERO || ccdIsZero(t)){
        dist = ccdVec3Dist2(x0, P);
        if (witness)
            ccdVec3Copy(witness, x0);
    }else if (t > CCD_ONE || ccdEq(t, CCD_ONE)){
        dist = ccdVec3Dist2(b, P);
        if (witness)
            ccdVec3Copy(witness, b);
    }else{
        if (witness){
            ccdVec3Copy(witness, &d);
            ccdVec3Scale(witness, t);
            ccdVec3Add(witness, x0);
            dist = ccdVec3Dist2(witness, P);
        }else{
            // recycling variables
            ccdVec3Scale(&d, t);
            ccdVec3Add(&d, &a);
            dist = ccdVec3Len2(&d);
        }
    }

    return dist;
}
Beispiel #2
0
_ccd_inline int portalReachTolerance(const ccd_simplex_t *portal,
                                     const ccd_support_t *v4,
                                     const ccd_vec3_t *dir,
                                     const ccd_t *ccd)
{
    ccd_vec3_t vec;
    ccd_real_t dot;

    ccdVec3Sub2(&vec, &v4->v, &ccdSimplexPoint(portal, 3)->v);
    dot = ccdVec3Dot(&vec, dir);

    return ccdEq(dot, ccd->mpr_tolerance) || dot < ccd->mpr_tolerance;
}
Beispiel #3
0
_ccd_inline int portalReachTolerance(const ccd_simplex_t *portal,
                                     const ccd_support_t *v4,
                                     const ccd_vec3_t *dir,
                                     const ccd_t *ccd)
{
    ccd_real_t dv1, dv2, dv3, dv4;
    ccd_real_t dot1, dot2, dot3;

    /* find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}*/

    dv1 = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, dir);
    dv2 = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, dir);
    dv3 = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, dir);
    dv4 = ccdVec3Dot(&v4->v, dir);

    dot1 = dv4 - dv1;
    dot2 = dv4 - dv2;
    dot3 = dv4 - dv3;

    dot1 = CCD_FMIN(dot1, dot2);
    dot1 = CCD_FMIN(dot1, dot3);

    return ccdEq(dot1, ccd->mpr_tolerance) || dot1 < ccd->mpr_tolerance;
}
Beispiel #4
0
ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P,
                                const ccd_vec3_t *x0, const ccd_vec3_t *B,
                                const ccd_vec3_t *C,
                                ccd_vec3_t *witness)
{
    // Computation comes from analytic expression for triangle (x0, B, C)
    //      T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
    // Then equation for distance is:
    //      D(s, t) = | T(s, t) - P |^2
    // This leads to minimization of quadratic function of two variables.
    // The solution from is taken only if s is between 0 and 1, t is
    // between 0 and 1 and t + s < 1, otherwise distance from segment is
    // computed.

    ccd_vec3_t d1, d2, a;
    ccd_real_t u, v, w, p, q, r, d;
    ccd_real_t s, t, dist, dist2;
    ccd_vec3_t witness2;

    ccdVec3Sub2(&d1, B, x0);
    ccdVec3Sub2(&d2, C, x0);
    ccdVec3Sub2(&a, x0, P);

    u = ccdVec3Dot(&a, &a);
    v = ccdVec3Dot(&d1, &d1);
    w = ccdVec3Dot(&d2, &d2);
    p = ccdVec3Dot(&a, &d1);
    q = ccdVec3Dot(&a, &d2);
    r = ccdVec3Dot(&d1, &d2);

    d = w * v - r * r;
    if (ccdIsZero(d)){
        // To avoid division by zero for zero (or near zero) area triangles
        s = t = -1.;
    }else{
        s = (q * r - w * p) / d;
        t = (-s * r - q) / w;
    }

    if ((ccdIsZero(s) || s > CCD_ZERO)
            && (ccdEq(s, CCD_ONE) || s < CCD_ONE)
            && (ccdIsZero(t) || t > CCD_ZERO)
            && (ccdEq(t, CCD_ONE) || t < CCD_ONE)
            && (ccdEq(t + s, CCD_ONE) || t + s < CCD_ONE)){

        if (witness){
            ccdVec3Scale(&d1, s);
            ccdVec3Scale(&d2, t);
            ccdVec3Copy(witness, x0);
            ccdVec3Add(witness, &d1);
            ccdVec3Add(witness, &d2);

            dist = ccdVec3Dist2(witness, P);
        }else{
            dist  = s * s * v;
            dist += t * t * w;
            dist += CCD_REAL(2.) * s * t * r;
            dist += CCD_REAL(2.) * s * p;
            dist += CCD_REAL(2.) * t * q;
            dist += u;
        }
    }else{
        dist = __ccdVec3PointSegmentDist2(P, x0, B, witness);

        dist2 = __ccdVec3PointSegmentDist2(P, x0, C, &witness2);
        if (dist2 < dist){
            dist = dist2;
            if (witness)
                ccdVec3Copy(witness, &witness2);
        }

        dist2 = __ccdVec3PointSegmentDist2(P, B, C, &witness2);
        if (dist2 < dist){
            dist = dist2;
            if (witness)
                ccdVec3Copy(witness, &witness2);
        }
    }

    return dist;
}