2012-05-15 11 views
5

Lo siento si esto es una repetición, pero estoy tratando de averiguar la implementación de SoRayPickAction en Open Inventor. Estoy tratando de implementarlo para que, cuando se hace clic en el mouse, seleccione un nodo particular para que pueda traducir, rotar, etc. Tengo tres nodos: escritorio, lámpara y marco (marco de imagen). Sin embargo, no creo que mi código esté bien. También tengo varios métodos, como MouseButtonCallback (que comprobará si se hace clic en el mouse y luego usar un navegador) y MouseMoveCallback (misma idea). Así que aquí está el código que tengo, ¿pero tienes alguna sugerencia? En este momento, bueno, no hace nada.SoRayPickAction en Open Inventor?

SbViewportRegion viewport(400,300); 
    SoRayPickAction m(viewport); 
    m.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0)); 
    m.apply(callback_node); 
    const SoPickedPoint *mpp = m.getPickedPoint(); 
    if(mpp != NULL) { 
     std::cout << "test" << std::endl; 
    } 

Podría también conocer de una acción en OpenInventor que puede "colocar" un nodo en la escena, es decir, colocar la lámpara en la parte superior de la mesa, marco en la pared, etc. Es con las rutas? Ni siquiera sé lo que estoy buscando, desafortunadamente. ¡¡Muchas gracias por su ayuda!!

Editar: ¿Cómo se ve esto? SoSeparador * escritorio2; SoSeparador * lamp2; SoSeparador * pic_frame2; SoSeparador * elegido;

void MouseButtonCallback(void* data, SoEventCallback* node) 
{ 
    SoHandleEventAction* action = node->getAction(); 
    const SoMouseButtonEvent* event = static_cast<const SoMouseButtonEvent*>(action-   >getEvent()); 
    Navigator* nav = static_cast<Navigator*>(data); 

    if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton())) 
     nav->OnMouseDown(event, action); 
    else 
     nav->OnMouseUp(event, action); 

    const SbViewportRegion & viewportRegion = action->getViewportRegion(); 
    SoRayPickAction pickAction(viewportRegion); 

    SbVec2s mousePos = event->getPosition(viewportRegion); 
    pickAction.setPoint(mousePos); 
    pickAction.setPickAll(TRUE); 
    pickAction.setRadius(2.0F); 
    pickAction.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0)); 
    pickAction.apply(node); 
    const SoPickedPoint *mpp = pickAction.getPickedPoint(); 
    if(mpp != NULL) { 
    SoPath *path = mpp->getPath(); 

if(desk2 != NULL && path->containsNode(desk2)) 
    {    //but this doesn't respond with cout when I try to test it :(
     if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton())) 
     *picked = *desk2; 
    } 
    else if(lamp2 != NULL && path->containsNode(lamp2)) 
    { 
     if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton())) 
     *picked = *lamp2; 
    } 
    else if(pic_frame2 != NULL && path->containsNode(pic_frame2)) 
    { 
     if (SoMouseButtonEvent::isButtonPressEvent(event, event->getButton())) 
     *picked = *pic_frame2; 
    } 

      action->setHandled(); 
    } 
void MouseMoveCallback(void* data, SoEventCallback* node) 
{ 
    SoHandleEventAction* action = node->getAction(); 
    const SoLocation2Event* event = static_cast<const SoLocation2Event*>(action->getEvent()); 
    Navigator* nav = static_cast<Navigator*>(data); 

    nav->OnMouseMove(event, action); 

    const SbViewportRegion & viewportRegion = action->getViewportRegion(); 
    SoRayPickAction pickAction(viewportRegion); 

    SbVec2s mousePos = event->getPosition(viewportRegion); 
    pickAction.setPoint(mousePos); 
    pickAction.setPickAll(TRUE); 
    pickAction.setRadius(2.0F); 
    pickAction.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0)); 
    pickAction.apply(node); 
    const SoPickedPoint *mpp = pickAction.getPickedPoint(); 
    if(mpp != NULL) { 
    SoPath *path = mpp->getPath(); 
    if(desk2 != NULL && path->containsNode(desk2)) 
    { 
     *picked = *desk2; //can't remember how to set pointers, will figure that out 
    } 
    else if(lamp2 != NULL && path->containsNode(lamp2)) 
    { 
     *picked = *lamp2; 
    } 
    else if(pic_frame2 != NULL && path->containsNode(pic_frame2)) 
    { 
     *picked = *pic_frame2; 
    } 
    } 
     action->setHandled(); 
    } 

    (part of main method) 

//desk 
SoTransform *desk_transform = new SoTransform; 
desk_transform->translation.setValue(SbVec3f(380,340,330)); 
SoSeparator* desk2 = new SoSeparator(); 
desk2->addChild(desk_transform); 
desk2->addChild(desk); 
root->addChild(desk2); 

    SoTransformerManip* picked_transform = new SoTransformerManip(); 
    picked_transform->translation.setValue(SbVec3f(200,340,330)); 
    SoSeparator* pick2 = new SoSeparator(); 
    pick2->addChild(picked_transform); 
    pick2->addChild(picked); 
    root->addChild(pick2); 

std::auto_ptr<btCollisionShape> picked_shape(new btBoxShape(btVector3(10.0f, 10.0f, 10.0f))); 
    CollisionEngine* picked_collision = new CollisionEngine(collision_world.get(),  picked_shape.get()); 
    picked_collision->translation_in.connectFrom(&picked_transform->translation); 
    picked_collision->rotation_in.connectFrom(&picked_transform->rotation); 
    picked_transform->translation.connectFrom(&picked_collision->translation_out); 

Respuesta

2

Tiene el punto elegido. Luego obtienes un SoPath como lo has adivinado. Luego vea si la ruta contiene un nodo con el que desea hacer algo.

SbViewportRegion viewport(400,300); 
    SoRayPickAction m(viewport); 
    m.setRay(SbVec3f(0.0,0.0,0.0), SbVec3f(0.0,0.0,-1.0)); 
    m.apply(callback_node); 
    const SoPickedPoint *mpp = m.getPickedPoint(); 
    if(mpp != NULL) { 
     std::cout << "test" << std::endl; 
     SoPath * path = pickedPoint->getPath(); 

     if (deskSeparator != NULL && path->containsNode(deskSeparator) 
     { 
     } 
     else if (lampSeparator != NULL && path->containsNode(lampSeparator) 
     { 
     } 
     else if (radomeSeparator != NULL && path->containsNode(radomeSeparator) 
     { 
      if ( SoMouseButtonEvent::isButtonPressEvent(event, SoMouseButtonEvent::BUTTON2) 
       || (SoMouseButtonEvent::isButtonPressEvent(event, SoMouseButtonEvent::BUTTON1) && event->wasShiftDown())) 
      { 
       modelPointMoving = true; 
       const SoDetail * detail = modelPickedPoint->getDetail(0); 
       int face = -1; 
       if (detail && detail->isOfType(SoFaceDetail::getClassTypeId())) 
       { 
        const SoFaceDetail * faceDetail = static_cast<const SoFaceDetail *>(detail); 
        face = faceDetail->getFaceIndex(); 
       } 
       updateStatusBar(face, point.getValue(), normal.getValue()); 
       graphicModel.postNote(pickedPoint); 
       break; 
      } 
      else if (SoMouseButtonEvent::isButtonPressEvent(event, SoMouseButtonEvent::BUTTON1)) 
      { 
      } 
      else if (SoMouseButtonEvent::isButtonReleaseEvent(event, SoMouseButtonEvent::BUTTON1)) 
      { 
      } 
     } 
    } 

que finalmente va a desea conectar el rayo de selección para la posición del ratón algo así como esto:

// Set an 2-pixel wide region around the pixel. 
SbVec2s mousePosition = event->getPosition(viewportRegion); 
pickAction.setPoint(mousePosition); 
pickAction.setPickAll(TRUE); 
pickAction.setRadius(2.0F); 

Esto se hace antes de .apply() la accion de captura por supuesto.

Creo que mi código es una mezcla entre la tuya y la mía, pero creo que debería comenzar. Además, este está sentado dentro de una función para procesar los eventos del ratón:

void 
RenderWindow::mouseEvent(void *, SoEventCallback * eventCallback) 
{ 
    const SoEvent *event = eventCallback->getEvent(); 

    if (! event) 
    { 
     qDebug() << " ** Error in mousePressCallback: Event not found."; 
     return; 
    } 

    //SoType eventType = event->getTypeId(); 
    //SbName eventTypeName = eventType.getName(); 
    //const char * eventTypeString = eventTypeName.getString(); 
    SoHandleEventAction * action = eventCallback->getAction(); 
    const SbViewportRegion & viewportRegion = action->getViewportRegion(); 
    SoRayPickAction pickAction(viewportRegion); 

Up en principal o una rutina de instalación me registro del evento de ratón (tanto para la acción de clic y la ubicación (que se mueve el puntero del ratón sobre la ventana gráfica):

// Add a mouse event callback to catch mouse button presses. 
SoEventCallback * mouseEventCallback = new SoEventCallback(); 
mouseEventCallback->setName("MOUSE_EVENT_CALLBACK"); 
mouseEventCallback->addEventCallback(SoMouseButtonEvent::getClassTypeId(), &::mouseEvent, static_cast<void *>(this)); 
// Add a mouse event callback to catch mouse motion. 
mouseEventCallback->addEventCallback(SoLocation2Event::getClassTypeId(), &::mouseEvent, static_cast<void *>(this)); 
rootSeparator->addChild(mouseEventCallback); 

Ahora que lo miro escribí los trozos en orden inverso ;-). Lo siento.

Buena suerte

+1

Genial, wow, muchas gracias, emsr !! Tu código tiene mucho sentido ahora. Disculpe, ¿qué es "RadomeSeparador"? ¿Y este código cambia si me doy cuenta de que, desafortunadamente, el escritorio, la lámpara y el marco son separadores en lugar de nodos? ¡Otra vez, gracias por tu ayuda! – m00nbeam360

+0

Lo siento, radomeSeparador es de mi código ;-) Yo trabajo con aviones. Olvidé cambiarlo para que parezca tu código. Obviamente, querrás usar tus propios separadores. Además, un SoSeparator es un SoNode - es decir, SoSeparator hereda de SoNode (a través de SoGroup y tal vez algo más). SoNode es el padre de un montón de cosas en Inventor para que pueda elegir SoMaterial, SoTransform o lo que sea. – emsr

+0

Lo siento, así que estoy un poco perdido. ¡Realmente odio las variables locales! Ya tengo los métodos MouseMoveCallback y MouseButtonCallback. Sin embargo, ¿cómo crees que puedo conectar los tres a un RayPickAction? ¡Muchas gracias por tu ayuda! – m00nbeam360