Hi all,

The volume story continues. :)

The current cyl<->cyl test is quite naive and does not handle the common case with cylinders of non-infinite length.

I've picked up some code from the net which fixes this, and this time it is useful in OpenSG. However, it uses capsules (cyls with hemispheres at the ends) instead of cylinders, so it is not entirely accurate either, although much better than the existing test. Capsules are faster and easier to handle than flat-capped cylinders, so a replacement might be an idea for 2.0?

See attached file for source code on the test (it's an extract from my sources, thus lacking of includes and such stuff). I hope it'll be useful.

Best regards,
/Marcus

P.S. W.r.t. some comments in osg::Line on handling of infinite/semi-infinite/non-infinite lines, I think it should be split into separate classes for Line, Ray and Segment, respectively. Makes it easier to understand and reason about geometric code. Naturally, they could all use a common parent class if deemed useful. (Updating CylVol to use an Segment would then be a nice touch. :)
bool myCylIntersect(const CylinderVolume * cyl1, const CylinderVolume * cyl2)
{
    Pnt3f p1, p2;
    Vec3f v1, v2;
    cyl1->getAxis(p1, v1);
    cyl2->getAxis(p2, v2);
    return dist3D_Segment_to_Segment(p1, v1, p2, v2) <= (cyl1->getRadius() + 
cyl2->getRadius());
}


// 
http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm#dist3D_Segment_to_Segment()
// Adapted for OpenSG by Marcus Lindblom 2005-09-06

// Copyright 2001, softSurfer (www.softsurfer.com)
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// SoftSurfer makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.

// Assume that classes are already given for the objects:
//    Point and Vector with
//        coordinates {float x, y, z;}
//        operators for:
//            Point  = Point ± Vector
//            Vector = Point - Point
//            Vector = Vector ± Vector
//            Vector = Scalar * Vector
//    Line and Segment with defining points {Point P0, P1;}
//    Track with initial position and velocity vector
//            {Point P0; Vector v;}
//===================================================================

float dist3D_Segment_to_Segment( const Pnt3f& s1p, const Vec3f& s1d,
                                const Pnt3f& s2p, const Vec3f& s2d)
{
    const float SMALL_NUM = 1e-9f; // anything that avoids division overflow
    const Vec3f& u = s1d;
    const Vec3f& v = s2d;
    Vec3f w = s1p - s2p;

    float    a = u.dot(u);        // always >= 0
    float    b = u.dot(v);
    float    c = v.dot(v);        // always >= 0
    float    d = u.dot(w);
    float    e = v.dot(w);
    float    D = a*c - b*b;       // always >= 0
    float    sc, sN, sD = D;      // sc = sN / sD, default sD = D >= 0
    float    tc, tN, tD = D;      // tc = tN / tD, default tD = D >= 0

    // compute the line parameters of the two closest points
    if (D < SMALL_NUM) { // the lines are almost parallel
        sN = 0.0;        // force using point P0 on segment S1
        sD = 1.0;        // to prevent possible division by 0.0 later
        tN = e;
        tD = c;
    }
    else {                // get the closest points on the infinite lines
        sN = (b*e - c*d);
        tN = (a*e - b*d);
        if (sN < 0.0) {       // sc < 0 => the s=0 edge is visible
            sN = 0.0;
            tN = e;
            tD = c;
        }
        else if (sN > sD) {  // sc > 1 => the s=1 edge is visible
            sN = sD;
            tN = e + b;
            tD = c;
        }
    }

    if (tN < 0.0) {           // tc < 0 => the t=0 edge is visible
        tN = 0.0;
        // recompute sc for this edge
        if (-d < 0.0)
            sN = 0.0;
        else if (-d > a)
            sN = sD;
        else {
            sN = -d;
            sD = a;
        }
    }
    else if (tN > tD) {      // tc > 1 => the t=1 edge is visible
        tN = tD;
        // recompute sc for this edge
        if ((-d + b) < 0.0)
            sN = 0;
        else if ((-d + b) > a)
            sN = sD;
        else {
            sN = (-d + b);
            sD = a;
        }
    }
    // finally do the division to get sc and tc
    sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD);
    tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD);

    // get the difference of the two closest points
    Vec3f dP = w + (sc * u) - (tc * v);  // = S1(sc) - S2(tc)

    return dP.length();   // return the squared distance
}

Reply via email to