void SoNurbsSurface::rayPick(SoRayPickAction *action) // //////////////////////////////////////////////////////////////////////// { // First see if the object is pickable if (! shouldRayPick(action)) return; // Tell the action about our current object space action->setObjectSpace(); // // Create an SoPickRender class which performs picking with the // software NURBS library. // _SoNurbsPickRender pickRender(action); // // Set NURBS properties telling the NURBS library to pick filled // triangles, use screen space tessellation with the pixel tolerance very // low. Notify the library that the sampling and culling matrices will be // passed in. // pickRender.setnurbsproperty (N_DISPLAY, N_FILL); pickRender.setnurbsproperty (N_T2D, N_PIXEL_TOLERANCE, 2.0 ); pickRender.setnurbsproperty (N_V3D, N_PIXEL_TOLERANCE, 2.0 ); pickRender.setnurbsproperty (N_V3DR, N_PIXEL_TOLERANCE, 2.0 ); pickRender.setnurbsproperty (N_T2D,N_SAMPLINGMETHOD, N_PARAMETRICDISTANCE); pickRender.setnurbsproperty (N_V3D,N_SAMPLINGMETHOD, N_PARAMETRICDISTANCE); pickRender.setnurbsproperty (N_V3DR,N_SAMPLINGMETHOD,N_PARAMETRICDISTANCE); pickRender.setnurbsproperty (N_V3D, N_CULLING, N_CULLINGON); pickRender.setnurbsproperty (N_V3DR, N_CULLING, N_CULLINGON); // // Calculate the total viewing matrix by concatenating the modeling // matrix, the camera's viewing matrix, and the projection matrix. // Pass the resulting matrix to the NURBS library for use in determining // sampling and culling of the surface. // const SbViewportRegion & vpRegion = SoViewportRegionElement::get(action->getState()); const SbVec2s & vpSize = vpRegion.getViewportSizePixels(); SbMatrix totalMat; calcTotalMatrix(action->getState(), totalMat); pickRender.loadMatrices(totalMat, vpSize); // Determine whether a texture coordinate surface must be generated SbBool generateTexCoords = TRUE; if (SoTextureCoordinateElement::getType(action->getState()) == SoTextureCoordinateElement::FUNCTION) generateTexCoords = FALSE; // // Draw the NURBS surface. The SoPickRender class will receive primitive // drawn by the NURBS library and test them for intersection. // drawNURBS(&pickRender, action->getState(), generateTexCoords); }
// Doc in parent void SoVRMLBox::rayPick(SoRayPickAction * action) { if (!shouldRayPick(action)) return; SbVec3f s = this->size.getValue(); sopick_pick_cube(s[0], s[1], s[2], 0, this, action); }
// Doc in parent void SoVRMLCylinder::rayPick(SoRayPickAction * action) { if (!shouldRayPick(action)) return; unsigned int flags = 0; if (this->side.getValue()) flags |= SOPICK_SIDES; if (this->top.getValue()) flags |= SOPICK_TOP; if (this->bottom.getValue()) flags |= SOPICK_BOTTOM; sopick_pick_cylinder(this->radius.getValue(), this->height.getValue(), flags, this, action); }
void SoRing::rayPick(SoRayPickAction * action) { // Is it pickable ? if ( ! shouldRayPick(action) ) return; // compute the picking ray in our current object space computeObjectSpaceRay(action); SoPickedPoint* pp; SbVec3f intersection; SbPlane XY(SbVec3f(0,0,1),0); if ( XY.intersect(action->getLine(), intersection) ) { float x, y, z; intersection.getValue(x, y, z); // back to the case of a disk centered at (0,0) float Xc, Yc; center.getValue().getValue(Xc,Yc); x -= Xc; y -= Yc; // within radius ? if ( sqrt(x*x+y*y+z*z) > outerRadius.getValue() ) return; if ( sqrt(x*x+y*y+z*z) < innerRadius.getValue() ) return; // within angular section ? float theta = sweepAngle.getValue(); float angle = atan2(y,x); if ( angle < 0. ) angle += 2*M_PI; if ( theta != 360 && angle*180.F/M_PI > theta ) return; if ( action->isBetweenPlanes(intersection) && (pp = action->addIntersection(intersection)) != NULL ) { pp->setObjectNormal(normal); pp->setObjectTextureCoords(SbVec4f(0.5f*(1+cos(angle)), 0.5f*(1+sin(angle)), 0, 1)); } } }
// Doc in parent. void SoCylinder::rayPick(SoRayPickAction * action) { if (!shouldRayPick(action)) return; unsigned int flags = 0; SoCylinder::Part p = (SoCylinder::Part) this->parts.getValue(); if (p & SIDES) flags |= SOPICK_SIDES; if (p & TOP) flags |= SOPICK_TOP; if (p & BOTTOM) flags |= SOPICK_BOTTOM; SoMaterialBindingElement::Binding bind = SoMaterialBindingElement::get(action->getState()); if (bind == SoMaterialBindingElement::PER_PART || bind == SoMaterialBindingElement::PER_PART_INDEXED) flags |= SOPICK_MATERIAL_PER_PART; sopick_pick_cylinder(this->radius.getValue(), this->height.getValue(), flags, this, action); }
void SoCylinder::rayPick(SoRayPickAction *action) // //////////////////////////////////////////////////////////////////////// { // First see if the object is pickable if (! shouldRayPick(action)) return; int curParts =(parts.isIgnored() ? ALL : parts.getValue()); SbLine pickLine; float radius, halfHeight; SbVec3f enterPoint, exitPoint, normal; SbVec4f texCoord; SoPickedPoint *pp; SoCylinderDetail *detail; SbBool materialPerPart; int numHits = 0; // Compute the picking ray in our current object space computeObjectSpaceRay(action); // Get size of this cylinder getSize(radius, halfHeight); // Construct an infinite cylinder to test sides for intersection SbCylinder infiniteCyl; infiniteCyl.setRadius(radius); SoMaterialBindingElement::Binding mbe = SoMaterialBindingElement::get(action->getState()); materialPerPart = (mbe == SoMaterialBindingElement::PER_PART_INDEXED || mbe == SoMaterialBindingElement::PER_PART); // See if the line intersects the cylinder if (HAS_PART(curParts, SIDES) && infiniteCyl.intersect(action->getLine(), enterPoint, exitPoint)) { // See if the enter point is within the real cylinder and is // between the near and far clipping planes. if (enterPoint[1] <= halfHeight && enterPoint[1] >= -halfHeight) { numHits++; if (action->isBetweenPlanes(enterPoint) && (pp = action->addIntersection(enterPoint)) != NULL) { // The normal at the point is the same as the point but // with a 0 y coordinate normal.setValue(enterPoint[0], 0.0, enterPoint[2]); normal.normalize(); pp->setObjectNormal(normal); texCoord.setValue(atan2f(enterPoint[0], enterPoint[2]) * (1.0 / (2.0 * M_PI)) + 0.5, (enterPoint[1] + halfHeight) / (2.0 * halfHeight), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); detail = new SoCylinderDetail(); detail->setPart(SIDES); pp->setDetail(detail, this); } } // Do same for exit point if (exitPoint[1] <= halfHeight && exitPoint[1] >= -halfHeight) { numHits++; if (action->isBetweenPlanes(exitPoint) && (pp = action->addIntersection(exitPoint)) != NULL) { normal.setValue(exitPoint[0], 0.0, exitPoint[2]); normal.normalize(); pp->setObjectNormal(normal); texCoord.setValue(atan2f(exitPoint[0], exitPoint[2]) * (1.0 / (2.0 * M_PI)) + 0.5, (exitPoint[1] + halfHeight) / (2.0 * halfHeight), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); detail = new SoCylinderDetail(); detail->setPart(SIDES); pp->setDetail(detail, this); } } } // If we haven't hit the cylinder twice already, check for an // intersection with the top face if (numHits < 2 && HAS_PART(curParts, TOP)) { SbVec3f norm(0.0, 1.0, 0.0); // Construct a plane containing the top face SbPlane topFacePlane(norm, halfHeight); // See if the ray hits this plane if (topFacePlane.intersect(action->getLine(), enterPoint)) { // See if the intersection is within the correct radius // and is within the clipping planes float distFromYAxisSquared = (enterPoint[0] * enterPoint[0] + enterPoint[2] * enterPoint[2]); if (distFromYAxisSquared <= radius * radius) { numHits++; if (action->isBetweenPlanes(enterPoint) && (pp = action->addIntersection(enterPoint)) != NULL) { pp->setObjectNormal(norm); texCoord.setValue(0.5 + enterPoint[0] / (2.0 * radius), 0.5 - enterPoint[2] / (2.0 * radius), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); if (materialPerPart) pp->setMaterialIndex(1); detail = new SoCylinderDetail(); detail->setPart(TOP); pp->setDetail(detail, this); } } } } // If we haven't hit the cylinder twice already, check for an // intersection with the bottom face if (numHits < 2 && HAS_PART(curParts, BOTTOM)) { SbVec3f norm(0.0, -1.0, 0.0); // Construct a plane containing the bottom face SbPlane bottomFacePlane(norm, halfHeight); // See if the ray hits this plane if (bottomFacePlane.intersect(action->getLine(), enterPoint)) { // See if the intersection is within the correct radius // and is within the clipping planes float distFromYAxisSquared = (enterPoint[0] * enterPoint[0] + enterPoint[2] * enterPoint[2]); if (distFromYAxisSquared <= radius * radius && action->isBetweenPlanes(enterPoint) && (pp = action->addIntersection(enterPoint)) != NULL) { pp->setObjectNormal(norm); texCoord.setValue(0.5 + enterPoint[0] / (2.0 * radius), 0.5 + enterPoint[2] / (2.0 * radius), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); if (materialPerPart) pp->setMaterialIndex(2); detail = new SoCylinderDetail(); detail->setPart(BOTTOM); pp->setDetail(detail, this); } } } }