OSG_BASE_DLLMAPPING void extend(SphereVolume &srcVol, const CylinderVolume &vol) { Pnt3f min, max, min1, max1, min2, max2, c; Real32 r; if((!srcVol.isValid () && !srcVol.isEmpty()) || srcVol.isInfinite() || srcVol.isStatic () ) { return; } if(!vol.isValid()) return; if(srcVol.isEmpty()) { if(vol.isEmpty()) { return; } else { vol.getBounds(min, max); vol.getCenter(c); r = (min - c).length(); srcVol.setValue(c, r); return; } } else if(vol.isEmpty()) { return; } srcVol.getBounds(min, max); vol .getBounds(min1, max1); min2 = Pnt3f(osgMin(min.x(), min1.x()), osgMin(min.y(), min1.y()), osgMin(min.z(), min1.z())); max2 = Pnt3f(osgMax(max.x(), max1.x()), osgMax(max.y(), max1.y()), osgMax(max.z(), max1.z())); c = Pnt3f((min2.x() + max2.x()) * 0.5f, (min2.y() + max2.y()) * 0.5f, (min2.z() + max2.z()) * 0.5f); r = ((max2 - min2).length()) * 0.5f; srcVol.setValue(c, r); return; }
OSG_BASE_DLLMAPPING void extend(CylinderVolume &srcVol, const CylinderVolume &vol) { Pnt3f min, max, min1, max1, min2, max2, apos; Vec2f p; Vec3f adir; Real32 r; if((!srcVol.isValid () && !srcVol.isEmpty()) || srcVol.isInfinite() || srcVol.isStatic () ) { return; } if(!vol.isValid()) return; if(srcVol.isEmpty()) { if(vol.isEmpty()) { return; } else { srcVol = vol; return; } } else if(vol.isEmpty()) { return; } srcVol.getBounds(min, max); vol .getBounds(min1, max1); min2 = Pnt3f(osgMin(min.x(), min1.x()), osgMin(min.y(), min1.y()), osgMin(min.z(), min1.z())); max2 = Pnt3f(osgMax(max.x(), max1.x()), osgMax(max.y(), max1.y()), osgMax(max.z(), max1.z())); p = Vec2f(max2.x() - min2.x(), max2.y() - min2.y()); r = (p.length()) * 0.5f; adir = Vec3f(0.f, 0.f, max2.z() - min2.z()); apos = Pnt3f(p.x(), p.y(), min2.z()); srcVol.setValue(apos, adir, r); return; }
OSG_BASE_DLLMAPPING bool intersect(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()); }
OSG_BASE_DLLMAPPING void extend(BoxVolume &srcVol, const CylinderVolume &vol) { Pnt3f min, max; if((!srcVol.isValid () && !srcVol.isEmpty()) || srcVol.isInfinite() || srcVol.isStatic () ) { return; } if(!vol.isValid()) return; if(srcVol.isEmpty()) { if(vol.isEmpty()) { return; } else { vol .getBounds(min, max); srcVol.setBounds(min, max); return; } } else if(vol.isEmpty()) { return; } vol.getBounds(min, max); srcVol.setBounds(osgMin(min.x(), srcVol.getMin().x()), osgMin(min.y(), srcVol.getMin().y()), osgMin(min.z(), srcVol.getMin().z()), osgMax(max.x(), srcVol.getMax().x()), osgMax(max.y(), srcVol.getMax().y()), osgMax(max.z(), srcVol.getMax().z())); if(vol.isInfinite()) srcVol.setInfinite(true); return; }
OSG_BASE_DLLMAPPING void extend(CylinderVolume &srcVol, const Volume &vol) { const Volume *v = &vol; const CylinderVolume *cylinder; #ifndef OSG_2_PREP const DynamicVolume *dynamic = dynamic_cast<const DynamicVolume *>(v); if(dynamic) { v = &(dynamic->getInstance()); } #endif if((cylinder = dynamic_cast<const CylinderVolume *>(v)) != NULL) { OSG::extend(srcVol, *cylinder); } else { CylinderVolume localCylinder; Pnt3f min, max, apos; Vec3f adir; Real32 r; Vec2f p; v->getBounds(min, max); p = Vec2f(max.x() - min.x(), max.y() - min.y()); r = (p.length()) * 0.5f; adir = Vec3f(0.f, 0.f, max.z() - min.z()); apos = Pnt3f(p.x(), p.y(), min.z()); localCylinder.setValue(apos, adir, r); OSG::extend(srcVol, localCylinder); } return; }
OSG_BASE_DLLMAPPING bool intersect(const CylinderVolume &cylinder, const FrustumVolume &frustum) { Pnt3f min, max; cylinder.getBounds(min, max); const Plane *frust = frustum.getPlanes(); // check each point of the box to the 6 planes for(Int32 i = 0; i < 6; i++) { if(frust[i].isOutHalfSpace(min, max)) return false; } return true; }
OSG_BASE_DLLMAPPING bool intersect(const SphereVolume &sphere, const CylinderVolume &cylinder) { bool retCode; Pnt3f apos; Vec3f adir; cylinder.getAxis(apos, adir); if(sphere.isEmpty() || cylinder.isEmpty()) { retCode = false; } else if(sphere.isInfinite() || cylinder.isInfinite()) { retCode = true; } else { Real32 d = 0.f, s1 = 0.f, s2 = 0.f; Pnt3f c; Vec3f u, u1, u2; //get the distance between the upper and lower point of the cylinder // and the sphere center s1 = (apos - sphere.getCenter()).length(); s2 = (apos + adir - sphere.getCenter()).length(); if ((s1<=DBL_EPSILON) || (s2<=DBL_EPSILON)) return true; //check the smallest distance and set the vector coordinate if(s1 <= s2) { d = s1; c = apos; } else { d = s2; c = apos + adir; } // decompose the vector in u1 and u2 which are parallel and // perpendicular to the cylinder axis respectively u = ((d - sphere.getRadius()) / d) * (c - sphere.getCenter()); u1 = (u[0] * adir[0] + u[1] * adir[1] + u[2] * adir[2]) / (adir.length() * adir.length()) * adir; u2 = u - u1; if(u2.length() <= 10e-6) { retCode = (d <= sphere.getRadius()); } else { retCode = (u2.length() <= cylinder.getRadius()); } } return retCode; }
OSG_BASE_DLLMAPPING bool intersect(const BoxVolume &box, const CylinderVolume &cylinder) { bool retCode; Pnt3f apos; Vec3f adir; cylinder.getAxis(apos, adir); if(box.isEmpty() == true || cylinder.isEmpty() == true) { retCode = false; } else if(box.isInfinite() == true || cylinder.isInfinite() == true) { retCode = true; } else { Real32 s1 = 0, s2 = 0, s3 = 0, s4 = 0, d = 0, d1 = 0, d2 = 0; Pnt3f c, p, p1, p2; Vec3f u, u1, u2; // find the distance between the min and the max of the box //with the lower point and the upper point of the cylinder respectively s1 = (apos - box.getMin()).length(); s2 = (apos - box.getMax()).length(); s3 = (apos + adir - box.getMin()).length(); s4 = (apos + adir - box.getMax()).length(); //Check the minimum of the above distances if(s1 <= s2) { d1 = s1; p1 = box.getMin(); } else { d1 = s2; p1 = box.getMax(); } if(s3 <= s4) { d2 = s3; p2 = box.getMin(); } else { d2 = s4; p2 = box.getMax(); } //set the value of the vector corresponding to the shortest distance if(d1 <= d2) { d = d1; c = apos; p = p1; } else { d = d2; c = apos + adir; p = p2; } // decompose the vector in u1 and u2 which are parallel and // perpendicular to the cylinder axis respectively u = p - c; u1 = (u[0] * adir[0] + u[1] * adir[1] + u[2] * adir[2]) / (adir.length() * adir.length()) * adir; u2 = u - u1; if(u1.length() <= 10e-6) { retCode = true; } else if(u2.length() <= 10e-6) { retCode = (d <= 10e-6); } else { retCode = (u2.length() <= cylinder.getRadius()); } } return retCode; }
int main (int argc, char **argv) { Real32 ent, ex; int i; //Lines: const int nlines = 10; Line lines[nlines]; Pnt3f pnts[nlines * 2] = { Pnt3f(0,0,0), Pnt3f(0,1,0), Pnt3f(0,0,0), Pnt3f(2,1,0), Pnt3f(2,0,0), Pnt3f(2,1,0), Pnt3f(-2,0,0), Pnt3f(0,2,0), Pnt3f(-4,2,0), Pnt3f(0,2,0), Pnt3f(-3,0,0), Pnt3f(-2,1,0), Pnt3f(3,4,0), Pnt3f(1,3,0), Pnt3f(-1,0,0), Pnt3f(-1,1,0), Pnt3f(-4,0,0), Pnt3f(-3,1,0), Pnt3f(-4,6,0), Pnt3f(0,6,0) }; for ( i = 0; i < nlines; i++ ) lines[i].setValue( pnts[i*2], pnts[i*2+1] ); BoxVolume b; float xmin, ymin, zmin, xmax, ymax, zmax; xmin = 0; ymin = 0.5; zmin = 0; xmax = 1; ymax = .5; zmax = 1; b.setBounds(xmin, ymin, zmin, xmax, ymax, zmax); std::cout << std::endl; b.dump(); std::cout << std::endl; for ( i = 0 ; i < nlines; i++ ) { std::cout << "Line: (" << lines[i].getPosition() << ") (" << lines[i].getDirection() << ")" << std::endl; bool res = lines[i].intersect( b, ent, ex ); Pnt3f ep = lines[i].getPosition() + ent * lines[i].getDirection(), xp = lines[i].getPosition() + ex * lines[i].getDirection(); std::cout << "Result: " << res; if ( res ) { std::cout << " enter " << ent << "=(" << ep << ") "; bool es = ( b.isOnSurface( ep ) || b.intersect( ep ) ), xs = b.isOnSurface( xp ); if ( ( res && es ) || !res ) std::cout << "ok"; else std::cout << "**BAD**"; std::cout << "; exit " << ex << "=(" << xp << ") "; if ( ( res && xs ) || !res ) std::cout << "ok"; else std::cout << "**BAD**"; } std::cout << std::endl; } return 0; SphereVolume s; float radius; Vec3f center; center[0] = 0; center[1] = 0; center[2] = 0; radius = 1; s.setCenter(center); s.setRadius(radius); std::cout << std::endl; s.dump(); std::cout << std::endl; for ( i = 0 ; i < nlines; i++ ) { std::cout << "Line: (" << lines[i].getPosition() << ") (" << lines[i].getDirection() << ")" << std::endl; bool res = lines[i].intersect( s, ent, ex ); Pnt3f ep = lines[i].getPosition() + ent * lines[i].getDirection(), xp = lines[i].getPosition() + ex * lines[i].getDirection(); std::cout << "Result: " << res; if ( res ) { std::cout << " enter " << ent << "=(" << ep << ") "; bool es = ( s.isOnSurface( ep ) || s.intersect( ep ) ), xs = s.isOnSurface( xp ); if ( ( res && es ) || !res ) std::cout << "ok"; else std::cout << "**BAD**"; std::cout << "; exit " << ex << "=(" << xp << ") "; if ( ( res && xs ) || !res ) std::cout << "ok"; else std::cout << "**BAD**"; } std::cout << std::endl; } // Intersect the line with a cylinder. Pnt3f p; Vec3f d; float rad; p[0] = 0; p[1] = 1; p[2] = 0; d[0] = 0; d[1] = 4; d[2] = 0; rad = 2; CylinderVolume c; c.setValue(p, d, rad); // c.setAxis(p, d); // c.setRadius(rad); std::cout << std::endl; c.dump(); std::cout << std::endl; for ( i = 0 ; i < nlines; i++ ) { std::cout << "Line: (" << lines[i].getPosition() << ") (" << lines[i].getDirection() << ")" << std::endl; bool res = lines[i].intersect( c, ent, ex ); Pnt3f ep = lines[i].getPosition() + ent * lines[i].getDirection(), xp = lines[i].getPosition() + ex * lines[i].getDirection(); std::cout << "Result: " << res; if ( res ) { std::cout << " enter " << ent << "=(" << ep << ") "; bool es = ( c.isOnSurface( ep ) || c.intersect( ep ) ), xs = c.isOnSurface( xp ); if ( ( res && es ) || !res ) std::cout << "ok"; else std::cout << "**BAD**"; std::cout << "; exit " << ex << "=(" << xp << ") "; if ( ( res && xs ) || !res ) std::cout << "ok"; else std::cout << "**BAD**"; } std::cout << std::endl; } //### volume intersection ############################################## std::cout << "### volume intersection test ###" << std::endl; BoxVolume box(-1,-1,-1,1,1,1); BoxVolume boxOut (5,5,5,10,10,10); BoxVolume boxIn(-1,-1,-1,2,2,2); SphereVolume sphere(Pnt3f(0,0,0),2); SphereVolume sphereOut(Pnt3f(2,2,2),1); SphereVolume sphereIn(Pnt3f(1,0,0),1); CylinderVolume cylinder(Pnt3f(0,0,0),Vec3f(1,1,1),1); CylinderVolume cylinderOut(Pnt3f(0,9,9),Vec3f(0,0,1),1); CylinderVolume cylinderIn(Pnt3f(1,0,0),Vec3f(0,1,0),1); // Frustum defined by normal vector and distance Plane pnear(Vec3f(0,0,-1),2); Plane pfar(Vec3f(0,0,1),7); Plane pright(Vec3f(-0.7071,0,-0.7071),0); Plane pleft(Vec3f(0.7071,0,-0.7071),0); Plane ptop(Vec3f(0,-0.7071,-0.7071),0); Plane pbottom(Vec3f(0,0.7071,-0.7071),0); FrustumVolume frustum(pnear, pfar, pleft, pright, ptop, pbottom); //Frustum defined by a clipMatrix Matrix matrix; matrix.setValue(0.7071,0,0,0, 0,0.7071,0,0, 0,0,-1.27,-3.959, 0,0,-0.7071,0); FrustumVolume frustum1; frustum1.setPlanes(matrix); // Frustum defined by 8 points Pnt3f nlt(-2,2,-2); Pnt3f nlb(-2,-2,-2); Pnt3f nrt(2,2,-2); Pnt3f nrb(2,-2,-2); Pnt3f flt(-7,7,-7); Pnt3f flb(-7,-7,-7); Pnt3f frt(7,7,-7); Pnt3f frb(7,-7,-7); FrustumVolume frustum2; frustum2.setPlanes(nlt, nlb, nrt, nrb, flt, flb, frt, frb); //Tests std::cout << "Box/box outside test: " << std::flush; std::cout << (box.intersect(boxOut) ? "**BAD**" : "ok") << std::endl; std::cout << "Box/box inside test: " << std::flush; std::cout << (box.intersect(boxIn) ? "ok" : "**BAD**") << std::endl; std::cout << "Box/sphere outside test: " << std::flush; std::cout << (box.intersect(sphereOut) ? "**BAD**" : "ok") << std::endl; std::cout << "Box/sphere inside test: " << std::flush; std::cout << (box.intersect(sphereIn) ? "ok" : "**BAD**")<< std::endl; std::cout << "Sphere/sphere outside test: " << std::flush; std::cout << (sphere.intersect(sphereOut) ? "**BAD**" : "ok") << std::endl; std::cout << "Sphere/sphere inside test: " << std::flush; std::cout << (sphere.intersect(sphereIn) ? "ok" : "**BAD**") << std::endl; std::cout << "Box/cylinder outside test: " << std::flush; std::cout << (box.intersect(cylinderOut) ? "**BAD**" : "ok") << std::endl; std::cout << "Box/cylinder inside test: " << std::flush; std::cout << (box.intersect(cylinderIn) ? "ok" : "**BAD**") << std::endl; std::cout << "Sphere/cylinder outside test: " << std::flush; std::cout << (sphere.intersect(cylinderOut) ? "**BAD**" : "ok") << std::endl; std::cout << "Sphere/cylinder inside test: " << std::flush; std::cout << (sphere.intersect(cylinderIn) ? "ok" : " **BAD**") << std::endl; std::cout << "Cylinder/cylinder outside test: "<<std::flush; std::cout << (cylinder.intersect(cylinderOut) ? "**BAD**" : "ok")<<std::endl; std::cout << "Cylinder/cylinder inside test: "<<std::flush; std::cout << (cylinder.intersect(cylinderIn) ? "ok" : " **BAD** ")<<std::endl; std::cout << "Box/Frustum outside test : " << std::flush; std::cout << (boxOut.intersect(frustum) ? "**BAD**" : "ok") << std::endl; std::cout << "Box/Frustum inside test : " << std::flush; std::cout << (boxIn.intersect(frustum) ? "ok" : "**BAD**") << std::endl; std::cout << "Sphere/Frustum outside test : " << std::flush; std::cout << (sphereOut.intersect(frustum) ? "**BAD**" : "ok") << std::endl; std::cout << "Sphere/Frustum inside test : " << std::flush; std::cout << (sphereIn.intersect(frustum) ? "ok" : "**BAD**") << std::endl; std::cout << "Cylinder/Frustum outside test : " << std::flush; std::cout << (cylinderOut.intersect(frustum) ? "**BAD**" : "ok") << std::endl; std::cout << "Cylinder/Frustum inside test : " << std::flush; std::cout << (cylinderIn.intersect(frustum) ? "ok" : "**BAD**") << std::endl; std::cout << "Cylinder/Sphere outside test: " << std::flush; std::cout << (cylinderOut.intersect(sphere) ? "**BAD**" : "ok") << std::endl; //###VOLUME EXTENSION################################################ std::cout << "### volume extension test ###" << std::endl; Pnt3f min,max; //Box extension extend(box, boxIn); box.getBounds(min,max); std::cout<< "min of the box : " <<min<<std::endl; std::cout<< "max of the box : " <<max<<std::endl; extend(box,sphere); box.getBounds(min,max); std::cout<< "min of the box : " <<min<<std::endl; std::cout<< "max of the box : " <<max<<std::endl; extend(box,cylinder); box.getBounds(min,max); std::cout<< "min of the box : " <<min<<std::endl; std::cout<< "max of the box : " <<max<<std::endl; //Sphere extension extend(sphere, box); std::cout<<"Center of the sphere : " <<sphere.getCenter()<<std::endl; std::cout<<"Radius of the sphere : " <<sphere.getRadius()<<std::endl; extend(sphere, sphereOut); std::cout<<"Center of the sphere : " <<sphere.getCenter()<<std::endl; std::cout<<"Radius of the sphere : " <<sphere.getRadius()<<std::endl; extend(sphere, cylinder); std::cout<<"Center of the sphere : " <<sphere.getCenter()<<std::endl; std::cout<<"Radius of the sphere : " <<sphere.getRadius()<<std::endl; //Cylinder extension extend (cylinder, box); cylinder.getBounds(min,max); std::cout<< "min of the cylinder : " <<min<<std::endl; std::cout<< "max of the cylinder : " <<max<<std::endl; extend (cylinder, sphere); cylinder.getBounds(min,max); std::cout<< "min of the cylinder : " <<min<<std::endl; std::cout<< "max of the cylinder : " <<max<<std::endl; extend (cylinder, cylinder); cylinder.getBounds(min,max); std::cout<< "min of the cylinder : " <<min<<std::endl; std::cout<< "max of the cylinder : " <<max<<std::endl; return 0; }
bool Line::intersect(const CylinderVolume &cyl, Real &enter, Real &exit ) const { Real radius = cyl.getRadius(); Vec3r adir; Vec3r o_adir; Pnt3r apos; cyl.getAxis(apos, adir); o_adir = adir; adir.normalize(); bool isect; Real ln; Real dl; Vec3r RC; Vec3r n; Vec3r D; RC = _pos - apos; n = _dir.cross (adir); ln = n .length( ); if(ln == 0.f) // IntersectionLine is parallel to CylinderAxis { D = RC - (RC.dot(adir)) * adir; dl = D.length(); if(dl <= radius) // line lies in cylinder { enter = 0.f; exit = Inf; } else { return false; } } else { n.normalize(); dl = osgAbs(RC.dot(n)); //shortest distance isect = (dl <= radius); if(isect) { // if ray hits cylinder Real t; Real s; Vec3r O; O = RC.cross(adir); t = - (O.dot(n)) / ln; O = n.cross(adir); O.normalize(); s = osgAbs ( (osgSqrt ((radius * radius) - (dl * dl))) / (_dir.dot(O))); exit = t + s; if(exit < 0.f) return false; enter = t - s; if(enter < 0.f) enter = 0.f; } else { return false; } } Real t; Plane bottom(-adir, apos); if(bottom.intersect(*this, t)) { if(bottom.isInHalfSpace(_pos)) { if(t > enter) enter = t; } else { if(t < exit) exit = t; } } else { if(bottom.isInHalfSpace(_pos)) return false; } Plane top(adir, apos + o_adir); if(top.intersect(*this, t)) { if(top.isInHalfSpace(_pos)) { if(t > enter) enter = t; } else { if(t < exit) exit = t; } } else { if(top.isInHalfSpace(_pos)) return false; } return (enter < exit); }