bool isVisibleFace(int faceIndex, const SbVec2f& pos, Gui::View3DInventorViewer* viewer) { SoSeparator* root = new SoSeparator; root->ref(); root->addChild(viewer->getSoRenderManager()->getCamera()); root->addChild(vp->getRoot()); SoSearchAction searchAction; searchAction.setType(PartGui::SoBrepFaceSet::getClassTypeId()); searchAction.setInterest(SoSearchAction::FIRST); searchAction.apply(root); SoPath* selectionPath = searchAction.getPath(); SoRayPickAction rp(viewer->getSoRenderManager()->getViewportRegion()); rp.setNormalizedPoint(pos); rp.apply(selectionPath); root->unref(); SoPickedPoint* pick = rp.getPickedPoint(); if (pick) { const SoDetail* detail = pick->getDetail(); if (detail && detail->isOfType(SoFaceDetail::getClassTypeId())) { int index = static_cast<const SoFaceDetail*>(detail)->getPartIndex(); if (faceIndex != index) return false; SbVec3f dir = viewer->getViewDirection(); const SbVec3f& nor = pick->getNormal(); if (dir.dot(nor) > 0) return false; // bottom side points to user return true; } } return false; }
void SoOrthoSlice::rayPick(SoRayPickAction * action) { if (!this->shouldRayPick(action)) return; SoState * state = action->getState(); if (!PRIVATE(this)->confirmValidInContext(state)) { return; } const CvrVoxelBlockElement * vbelem = CvrVoxelBlockElement::getInstance(state); if (vbelem == NULL) { return; } this->computeObjectSpaceRay(action); const SbLine & ray = action->getLine(); const SbPlane sliceplane = PRIVATE(this)->getSliceAsPlane(action); SbVec3f intersection; if (sliceplane.intersect(ray, intersection) && // returns FALSE if parallel action->isBetweenPlanes(intersection)) { SbVec3s ijk = vbelem->objectCoordsToIJK(intersection); const SbVec3s & voxcubedims = vbelem->getVoxelCubeDimensions(); const SbBox3s voxcubebounds(SbVec3s(0, 0, 0), voxcubedims - SbVec3s(1, 1, 1)); if (voxcubebounds.intersect(ijk)) { SoPickedPoint * pp = action->addIntersection(intersection); // if NULL, something else is obstructing the view to the // volume, the app programmer only want the nearest, and we // don't need to continue our intersection tests if (pp == NULL) return; pp->setObjectNormal(sliceplane.getNormal()); SoOrthoSliceDetail * detail = new SoOrthoSliceDetail; pp->setDetail(detail, this); detail->objectcoords = intersection; detail->ijkcoords = ijk; detail->voxelvalue = vbelem->getVoxelValue(ijk); if (CvrUtil::useFlippedYAxis()) { static SbBool flag = FALSE; if (!flag) { SoDebugError::postWarning("SoOrthoSlice::rayPick", "RayPick'ing will not be correct for SoOrthoSlice when the " "obsolete CVR_USE_FLIPPED_Y_AXIS envvar is active."); flag = TRUE; } } } } // Common clipping plane handling. SoOrthoSlice::doAction(action); }
void myMouseCB(void *userData, SoEventCallback *eventCB) { const SoEvent *event = eventCB->getEvent(); SoSeparator * scenegraph = (SoSeparator*) userData; if (SO_MOUSE_PRESS_EVENT(event, BUTTON2)) { std::cout << "mouse button 2" << std::endl; if (global_render_manager) { // attempting raypick in the event_cb() callback method SoRayPickAction rp( global_render_manager->getViewportRegion() ); rp.setPoint(event->getPosition()); rp.setPickAll(true); std::cout << "event position: " << event->getPosition()[0] << " " << event->getPosition()[1] << std::endl; rp.apply(global_render_manager->getSceneGraph()); const SoPickedPointList& pickedPoints = rp.getPickedPointList(); std::cout << "# of picked points: " << pickedPoints.getLength() << std::endl; for (int i=0; i<pickedPoints.getLength(); ++i) { SoPickedPoint * pickedPoint = pickedPoints[i]; SbVec3f point = pickedPoint->getPoint(); std::cout << "point " << i << " : " << point[0] << " " << point[1] << " " << point[2] << std::endl; } } eventCB->setHandled(); } else if (SO_MOUSE_PRESS_EVENT(event, BUTTON1)) { //std::cout << "mouse button 1" << std::endl; eventCB->setHandled(); } else if (SO_MOUSE_PRESS_EVENT(event, BUTTON3)) { //std::cout << "mouse button 3" << std::endl; eventCB->setHandled(); } }
void _SoNurbsPickV4SurfaceMap::intersectTriangle() // //////////////////////////////////////////////////////////////////////// { SbVec3f point; SbVec3f barycentric; SbBool onFrontSide; SoPickedPoint *pp; if (!pickAction->intersect(SP[cacheIndices[0]].p, SP[cacheIndices[1]].p, SP[curPrimIndex].p, point, barycentric, onFrontSide)) return; pp = pickAction->addIntersection(point); if (pp != NULL) { SbVec3f norm, n0, n1, n2; SbVec4f texCoord; // Compute normal by interpolating vertex normals using // barycentric coordinates n0 = SP[0].norm; n1 = SP[1].norm; n2 = SP[2].norm; norm.setValue(barycentric, n0, n1, n2); norm.normalize(); pp->setObjectNormal(norm); pp->setMaterialIndex(0); // Compute texture coordinates the same way texCoord[0] = barycentric[0] * TP[cacheIndices[0]][0] + barycentric[1] * TP[cacheIndices[1]][0] + barycentric[2] * TP[curPrimIndex][0]; texCoord[1] = barycentric[0] * TP[cacheIndices[0]][1] + barycentric[1] * TP[cacheIndices[1]][1] + barycentric[2] * TP[curPrimIndex][1]; texCoord[2] = 0.0; texCoord[3] = 1.0; pp->setObjectTextureCoords(texCoord); } }
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)); } } }
SbBool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::seekToPoint(const SbVec2s screenpos) { SoRayPickAction rpaction(getSoRenderManager()->getViewportRegion()); rpaction.setPoint(screenpos); rpaction.setRadius(2); rpaction.apply(getSoRenderManager()->getSceneGraph()); SoPickedPoint* picked = rpaction.getPickedPoint(); if(!picked) { this->interactiveCountInc(); // decremented in setSeekMode(FALSE) this->setSeekMode(FALSE); return FALSE; } SbVec3f hitpoint; hitpoint = picked->getPoint(); this->seekToPoint(hitpoint); return TRUE; }
void _SoNurbsPickV4CurveMap::intersectLine() // //////////////////////////////////////////////////////////////////////// { SbVec3f point; SoPickedPoint *pp; if (!pickAction->intersect(CP[0], CP[1], point)) return; pp = pickAction->addIntersection(point); if (pp != NULL) { SbVec3f norm; SbVec4f texCoord; float ratioFromV1; // Compute normal as vector pointing back along the pick ray. norm = -pickAction->getLine().getDirection(); norm.normalize(); pp->setObjectNormal(norm); pp->setMaterialIndex(0); // Compute interpolated texture coordinate ratioFromV1 = ((point - CP[0]).length() / (CP[1] - CP[0]).length()); texCoord[0] = (TP[0][0] * (1.0 - ratioFromV1) + TP[1][0] * ratioFromV1); texCoord[1] = (TP[0][1] * (1.0 - ratioFromV1) + TP[1][1] * ratioFromV1); texCoord[2] = 0.0; texCoord[3] = 1.0; pp->setObjectTextureCoords(texCoord); } }
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); } } } }
void SmTextureText2::rayPick(SoRayPickAction * action) { //FIXME: Support multiple strings at one position (multiline text)? //For now, assumes 1 string at each position SoState * state = action->getState(); const SbString * strings; const int numstrings = this->getStrings(state, strings); const int32_t * indices; const int numindices = this->getStringIndices(state, indices); const int num = numindices > 0 ? numindices : numstrings; this->computeObjectSpaceRay(action); const SmTextureFont::FontImage * font = SmTextureFontElement::get(state); SoMaterialBindingElement::Binding binding = SoMaterialBindingElement::get(state); for (int i = 0; i < num; i++){ int idx = numindices > 0 ? indices[i] : i; SbVec3f p0, p1, p2, p3; this->buildStringQuad(action, idx, p0, p1, p2, p3); SbVec3f isect; SbVec3f bary; SbBool front; SbBool hit = action->intersect(p0, p1, p2, isect, bary, front); if (!hit) hit = action->intersect(p0, p2, p3, isect, bary, front); if (hit && action->isBetweenPlanes(isect)) { if (!this->pickOnPixel.getValue()){ SoPickedPoint * pp = action->addIntersection(isect); if (pp) { SoTextDetail * detail = new SoTextDetail; detail->setStringIndex(idx); detail->setCharacterIndex(0); pp->setDetail(detail, this); pp->setMaterialIndex(binding == SoMaterialBindingElement::OVERALL ? 0 : idx); pp->setObjectNormal(SbVec3f(0.0f, 0.0f, 1.0f)); } return;//We only calculate 1 picked point per SmTextureText2 instance } //else: //FIXME: Pixel coordinates are off by at least one pixel. //Probably a rounding issue, or related to using center vs lowerleft coordinates of each pixel //Find out if the fault lies here, in buildStringQuad or in renderString... wiesener 20091102 // find normalized 2D hitpoint on quad float h = (p3-p0).length(); float w = (p1-p0).length(); SbLine horizontal(p2, p3); SbVec3f ptonline = horizontal.getClosestPoint(isect); float vdist = (ptonline-isect).length(); vdist /= h; SbLine vertical(p0, p3); ptonline = vertical.getClosestPoint(isect); float hdist = (ptonline-isect).length(); hdist /= w; const SbString & string = strings[idx]; int width_pixels = font->stringWidth(string); int height_pixels = font->height(); int px = static_cast<int>(width_pixels * hdist); int py = static_cast<int>(height_pixels * vdist); const char * cstr = string.getString(); int charindex = 0; int lastwidth = 0; while (charindex < string.getLength()){ unsigned char c = cstr[charindex]; int width = font->getKerning(c, 0);//should return "true width" of the glyph int xoffset = font->getXOffset(c);//will be negative for fonts extending to the left if (lastwidth + width > px){//we have a character, now let's see if it is a pixel hit SbVec2s glyphpos = font->getGlyphPositionPixels(c);//upper left pixel int x = px - lastwidth - xoffset + glyphpos[0]; int y = py + glyphpos[1]; const SbImage * img = font->getGLImage()->getImage(); SbVec2s size; int nc; const unsigned char * pixels = img->getValue(size, nc); //#define DEBUG_CHARACTER #ifdef DEBUG_CHARACTER for (int fooy = 0; fooy < font->height(); fooy++){ for (int foox = 0; foox < width - xoffset; foox++){ int line = glyphpos[1] + fooy; char transparency = pixels[(line * size[0] + foox + glyphpos[0]) * nc]; if (fooy == py && foox == px - lastwidth - xoffset) printf("X"); else printf(transparency != 0 ? "O" : " "); } printf("\n"); } printf("--------\n"); #endif //DEBUG_CHARACTER const unsigned char * pixel = &pixels[(y * size[0] + x) * nc]; if (pixel[0] != 0){//not completely transparent SoPickedPoint * pp = action->addIntersection(isect); if (pp) { SoTextDetail * detail = new SoTextDetail; detail->setStringIndex(idx); detail->setCharacterIndex(0); pp->setDetail(detail, this); pp->setMaterialIndex(binding == SoMaterialBindingElement::OVERALL ? 0 : idx); pp->setObjectNormal(SbVec3f(0.0f, 0.0f, 1.0f)); } return;//We only calculate 1 picked point per SmTextureText2 instance } } unsigned char c2 = cstr[charindex + 1]; lastwidth += font->getKerning(c, c2);//add the kerning instead of width here if (lastwidth + font->getXOffset(c2) > px) break;//passed the point clicked charindex++; } } } }
/*! The string returned from this function is only valid until the next variable is requested. */ const char * SoScXMLStateMachine::getVariable(const char * key) const { if (strncmp(key, "_event.", 7) == 0) { // printf("scan for key '%s'\n", key); const char * subkey = key + 7; const ScXMLEvent * ev = this->getCurrentEvent(); if (ev->isOfType(SoScXMLEvent::getClassTypeId())) { const SoScXMLEvent * soev = static_cast<const SoScXMLEvent *>(ev); const SoEvent * coinev = soev->getSoEvent(); if (strcmp(subkey, "getTime()") == 0) { SbTime timeval = coinev->getTime(); double doubletime = timeval.getValue(); PRIVATE(this)->varstring = SbStringConvert::toString(doubletime); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getPosition().x") == 0) { SbVec2s pos = coinev->getPosition(); PRIVATE(this)->varstring = SbStringConvert::toString(static_cast<double>(pos[0])); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getPosition().y") == 0) { SbVec2s pos = coinev->getPosition(); PRIVATE(this)->varstring = SbStringConvert::toString(static_cast<double>(pos[1])); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getPosition()") == 0) { SbVec2s pos = coinev->getPosition(); PRIVATE(this)->varstring = SbStringConvert::toString(pos); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getNormalizedPosition().x") == 0) { SbVec2f pos = coinev->getNormalizedPosition(this->getViewportRegion()); PRIVATE(this)->varstring = SbStringConvert::toString(static_cast<double>(pos[0])); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getNormalizedPosition().y") == 0) { SbVec2f pos = coinev->getNormalizedPosition(this->getViewportRegion()); PRIVATE(this)->varstring = SbStringConvert::toString(static_cast<double>(pos[1])); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getNormalizedPosition()") == 0) { SbVec2f pos = coinev->getNormalizedPosition(this->getViewportRegion()); PRIVATE(this)->varstring = SbStringConvert::toString(pos); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "wasShiftDown()") == 0) { SbBool wasdown = coinev->wasShiftDown(); PRIVATE(this)->varstring = SbStringConvert::toString<bool>(wasdown); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "wasCtrlDown()") == 0) { SbBool wasdown = coinev->wasCtrlDown(); PRIVATE(this)->varstring = SbStringConvert::toString<bool>(wasdown); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "wasAltDown()") == 0) { SbBool wasdown = coinev->wasAltDown(); PRIVATE(this)->varstring = SbStringConvert::toString<bool>(wasdown); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getState()") == 0 && coinev->isOfType(SoButtonEvent::getClassTypeId())) { const SoButtonEvent * bevent = coin_assert_cast<const SoButtonEvent *>(coinev); SbString enumname; SoButtonEvent::enumToString(bevent->getState(), enumname); PRIVATE(this)->varstring.sprintf("'%s'", enumname.getString()); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getKey()") == 0 && coinev->isOfType(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * kbevent = coin_assert_cast<const SoKeyboardEvent *>(coinev); SbString enumname; SoKeyboardEvent::enumToString(kbevent->getKey(), enumname); PRIVATE(this)->varstring.sprintf("'%s'", enumname.getString()); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getPrintableCharacter()") == 0 && coinev->isOfType(SoKeyboardEvent::getClassTypeId())) { const SoKeyboardEvent * kbevent = coin_assert_cast<const SoKeyboardEvent *>(coinev); char printable = kbevent->getPrintableCharacter(); PRIVATE(this)->varstring.sprintf("'%c'", printable); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getButton()") == 0 && coinev->isOfType(SoMouseButtonEvent::getClassTypeId())) { const SoMouseButtonEvent * mbevent = coin_assert_cast<const SoMouseButtonEvent *>(coinev); SbString enumname; SoMouseButtonEvent::enumToString(mbevent->getButton(), enumname); PRIVATE(this)->varstring.sprintf("'%s'", enumname.getString()); return PRIVATE(this)->varstring.getString(); } else if (strcmp(subkey, "getButton()") == 0 && coinev->isOfType(SoSpaceballButtonEvent::getClassTypeId())) { const SoSpaceballButtonEvent * mbevent = coin_assert_cast<const SoSpaceballButtonEvent *>(coinev); SbString enumname; SoSpaceballButtonEvent::enumToString(mbevent->getButton(), enumname); PRIVATE(this)->varstring.sprintf("'%s'", enumname.getString()); return PRIVATE(this)->varstring.getString(); } // FIXME: x., .y, .z else if (strcmp(subkey, "getTranslation()") == 0 && coinev->isOfType(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * m3event = coin_assert_cast<const SoMotion3Event *>(coinev); SbVec3f translation = m3event->getTranslation(); PRIVATE(this)->varstring = SbStringConvert::toString(translation); return PRIVATE(this)->varstring.getString(); } // FIXME: .angle, .axis else if (strcmp(subkey, "getRotation()") == 0 && coinev->isOfType(SoMotion3Event::getClassTypeId())) { const SoMotion3Event * m3event = coin_assert_cast<const SoMotion3Event *>(coinev); SbRotation rotation = m3event->getRotation(); PRIVATE(this)->varstring = SbStringConvert::toString(rotation); return PRIVATE(this)->varstring.getString(); } // FIXME: make this into a evaluator-level RayPick(SbVec2f) function instead else if (strcmp(key + 7, "pickposition3") == 0) { SbVec2s location2 = coinev->getPosition(); SoRayPickAction rpa(this->getViewportRegion()); rpa.setPoint(location2); rpa.apply(this->getSceneGraphRoot()); SoPickedPoint * pp = rpa.getPickedPoint(); if (pp) { SbVec3f pickpos = pp->getPoint(); PRIVATE(this)->varstring = SbStringConvert::toString(pickpos); } else { PRIVATE(this)->varstring.sprintf("FALSE"); // need a valid undefined-value } return PRIVATE(this)->varstring.getString(); } } } else if (strncmp(key, "coin:", 5) == 0) { const char * subkey = key + 5; if (strncmp(subkey, "camera.", 7) == 0) { SoCamera * camera = this->getActiveCamera(); if (!camera) { SoDebugError::post("SoScXMLStateMachine::getVariable", "queried for camera, but no camera is set."); return NULL; } const char * detail = subkey + 7; if (strcmp(detail, "getTypeId()") == 0) { PRIVATE(this)->varstring.sprintf("'%s'", camera->getTypeId().getName().getString()); return PRIVATE(this)->varstring.getString(); } } // get generic field access working and intercept for more So-specific stuff // coin:viewport // coin:camera // coin:scene } //else { //} // couldn't resolve the symbol - try parent class to get '_data' and other '_event' // locations resolved return inherited::getVariable(key); }