home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / noodle / LineManip.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  12.7 KB  |  504 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. //
  18. // A very specialized node; this manipulator completely takes care of
  19. // editing a set of line segments.  This is somewhat different from
  20. // other manipulators, because you insert it in the scene graph and it
  21. // edits itself (instead of pointing it at the thing you want it to
  22. // edit).
  23. //
  24.  
  25. #include <stdio.h>
  26. #include <assert.h>
  27.  
  28. #include <Inventor/SbColor.h>
  29. #include <Inventor/SoPickedPoint.h>
  30. #include <Inventor/actions/SoHandleEventAction.h>
  31. #include <Inventor/details/SoDetail.h>
  32. #include <Inventor/details/SoLineDetail.h>
  33. #include <Inventor/details/SoPointDetail.h>
  34. #include <Inventor/elements/SoViewVolumeElement.h>
  35. #include <Inventor/elements/SoViewportRegionElement.h>
  36. #include <Inventor/events/SoEvent.h>
  37. #include <Inventor/events/SoKeyboardEvent.h>
  38. #include <Inventor/events/SoLocation2Event.h>
  39. #include <Inventor/events/SoMouseButtonEvent.h>
  40. #include <Inventor/misc/SoState.h>
  41. #include <Inventor/nodes/SoCoordinate3.h>
  42. #include <Inventor/nodes/SoDrawStyle.h>
  43. #include <Inventor/nodes/SoLightModel.h>
  44. #include <Inventor/nodes/SoLineSet.h>
  45. #include <Inventor/nodes/SoPointSet.h>
  46. #include <Inventor/nodes/SoTransform.h>
  47. #include <Inventor/projectors/SbLineProjector.h>
  48. #include <Inventor/projectors/SbPlaneProjector.h>
  49.  
  50. #include "LineManip.h"
  51.  
  52. //
  53. // Constructor; sets up scene graph
  54. //
  55. LineManip2::LineManip2()
  56. {
  57.     coord = new SoCoordinate3();
  58.     addChild(coord);
  59.     coord->point.deleteValues(0);
  60.  
  61.     pset = new SoPointSet;
  62.     pset->numPoints.setValue(SO_POINT_SET_USE_REST_OF_POINTS);
  63.     addChild(pset);
  64.  
  65.     drawStyle = new SoDrawStyle;
  66.     drawStyle->style = SoDrawStyle::LINES;
  67.     addChild(drawStyle);
  68.  
  69.     lset = new SoLineSet;
  70.     lset->numVertices.setValue(SO_LINE_SET_USE_REST_OF_VERTICES);
  71.     addChild(lset);
  72.  
  73.     current_coord = -1;
  74.     planeProj = new SbPlaneProjector(FALSE);
  75.     planeProj->setPlane( SbPlane( SbVec3f(0,0,1), 0 ) );
  76.     lineProj = new SbLineProjector();
  77.     lineProj->setLine( SbLine(  SbVec3f(0,0,0),SbVec3f(0,0,1) ) );
  78.  
  79.     hilightSize = 0.05;
  80.  
  81.     initHilightStuff();
  82.  
  83.     myHandleEventAction = NULL;
  84. }
  85.  
  86. //
  87. // Destructor.  This will be called when this is unref'ed.
  88. LineManip2::~LineManip2()
  89. {
  90.     //
  91.     // Don't need to delete children; they will have already been
  92.     // unref'ed and deleted (since this is derived from SoGroup).
  93.     //
  94.  
  95.     delete planeProj;
  96.     delete lineProj;
  97. }
  98.  
  99. //
  100. // Magic stuff to register this node with the database
  101. //
  102. SO_NODE_SOURCE(LineManip2);
  103. void
  104. LineManip2::initClass()
  105. {
  106.     SO_NODE_INIT_CLASS(LineManip2, SoSeparator, "Separator");
  107. }
  108.  
  109. //
  110. // This tiny routine is how this Node gets used.  After creating a
  111. // LineManip2, call this routine and put a data sensor on the Coordinate3
  112. // returned.
  113. //
  114. SoCoordinate3 *
  115. LineManip2::getCoordinate3()
  116. {
  117.     return coord;
  118. }
  119.  
  120. //
  121. // This tiny routine is how this Node gets used.  After creating a
  122. // LineManip2, call this routine and put a data sensor on the Coordinate3
  123. // returned.
  124. //
  125. void
  126. LineManip2::setCoordinate3( SoCoordinate3 *newNode )
  127. {
  128.     if ( newNode == coord)
  129.     return;
  130.  
  131.     if ( coord != NULL )
  132.     removeChild( coord );
  133.     if ( newNode != NULL )
  134.     insertChild(newNode,0);
  135.     coord = newNode;
  136. }
  137.  
  138. //
  139. // For setting the plane that the manip works in. You pass it a normal.
  140. //
  141. void
  142. LineManip2::setPlaneNormal( const SbVec3f &newNormal )
  143. {
  144.     SbVec3f zeroVec(0,0,0);
  145.     planeNormal = newNormal;
  146.     planeProj->setPlane( SbPlane( planeNormal, zeroVec ) );
  147.     lineProj->setLine( SbLine( zeroVec, zeroVec + planeNormal ) );
  148.     hilightTransform->rotation.setValue( SbRotation(SbVec3f(0,0,1), SbVec3f(planeNormal)));
  149. }
  150.  
  151. //
  152. // Note:
  153. // This node eats events.  It uses the entire surface of the render
  154. // area as its playground, sucking up mouse motion, left mouse and
  155. // backspace/delete events, even if the mouse isn't on top of it.
  156. //
  157. void
  158. LineManip2::handleEvent(SoHandleEventAction *ha)
  159. {
  160.     myHandleEventAction = ha;
  161.  
  162.     const SoEvent *e = ha->getEvent();
  163.  
  164.     if (SO_MOUSE_PRESS_EVENT(e, BUTTON1)) {
  165.     if (dragStart())
  166.         ha->setHandled();
  167.     }
  168.     else if (e->isOfType(SoLocation2Event::getClassTypeId())) {
  169.     // If not dragging, locate hilight
  170.     if (ha->getGrabber() != this) {
  171.         if (locateHilight())
  172.             ha->setHandled();
  173.     }
  174.     else {    // Are dragging, move coordinate:
  175.         moveCoord();
  176.         ha->setHandled();
  177.     }
  178.     }
  179.     else if (SO_MOUSE_RELEASE_EVENT(e, BUTTON1) &&
  180.          ha->getGrabber() == this) {
  181.     ha->releaseGrabber();
  182.     ha->setHandled();
  183.     }
  184.     else if (SO_KEY_PRESS_EVENT(e, BACKSPACE) ||
  185.          SO_KEY_PRESS_EVENT(e, DELETE)) {
  186.     if (remove())
  187.         ha->setHandled();
  188.     // If we are in mid-motion and we remove the point, 
  189.     // we better stop grabber, cause we got nothin to grab anymore.
  190.     if (ha->getGrabber() == this)
  191.         ha->releaseGrabber();
  192.         current_coord = -1;
  193.     }
  194. }
  195.  
  196. static SbColor locateColor(0.5, 0.5, 0.5);
  197. static SbColor pickColor(0.9, 0.9, 0.9);
  198.  
  199. //
  200. // Figures out which part of the line manipulator is picked by the
  201. // given detail.  This will also set current_position and
  202. // current_coord. 
  203. //
  204. #ifdef __C_PLUS_PLUS_2
  205. LineManipPart
  206. #else
  207. LineManip2::Part
  208. #endif
  209. LineManip2::whichPart()
  210. {
  211.     // Can't pick if we don't have an action, now can we?
  212.     if (myHandleEventAction == NULL)
  213.     return NOTHING;
  214.  
  215.     // We're also out of luck if there's no coord node.
  216.     if (coord == NULL)
  217.     return NOTHING;
  218.  
  219.     const SoPickedPoint *picked_point = myHandleEventAction->getPickedPoint();
  220.  
  221.     projectMouse(current_position);
  222.  
  223.     if (picked_point == NULL) {
  224.     //
  225.     // Endpoints
  226.     // Pick the endPoint that's closer to where the mouse is now.
  227.     int n = coord->point.getNum();
  228.     if (n == 0) {
  229.         current_coord = -1;
  230.     }
  231.     else {
  232.         SbVec3f v1, v2;
  233.         v1 = current_position - coord->point[0];
  234.         v2 = current_position - coord->point[n-1];
  235.         //
  236.         // Choose the endPoint closer to the current position.
  237.         //
  238.         if (v1.dot(v1) < v2.dot(v2)) {
  239.         current_coord = 0;
  240.         }
  241.         else {
  242.         current_coord = n;
  243.         }
  244.     }
  245.     return ENDPOINTS;
  246.     }
  247.  
  248.     const SoPath *dpath = picked_point->getPath();
  249.     const SoDetail *detail = picked_point->getDetail();
  250.  
  251.     if (dpath->containsNode(pset)) {
  252.     current_coord =
  253.         ((SoPointDetail *)detail)->getCoordinateIndex();
  254.     return POINTS;
  255.     }
  256.     if (dpath->containsNode(lset)) {
  257.     current_coord =
  258.         ((SoLineDetail *)detail)->getPartIndex();
  259.     return LINES;
  260.     }
  261. }
  262.  
  263. //
  264. // Called when the mouse goes down to figure out what is being picked.
  265. //
  266. SbBool
  267. LineManip2::dragStart()
  268. {
  269.     if ( coord == NULL)
  270.     return FALSE;
  271.  
  272.     SbBool gotSomething = TRUE;
  273.  
  274.     switch(whichPart()) {
  275.       case POINTS:
  276.     myHandleEventAction->setGrabber(this);
  277.     hilightVertex(coord->point[current_coord], pickColor);
  278.     break;
  279.  
  280.       case LINES:
  281.     // Create a new vertex
  282.     coord->point.insertSpace(current_coord+1, 1);
  283.     coord->point.set1Value(current_coord+1, current_position);
  284.     myHandleEventAction->setGrabber(this);
  285.     ++current_coord;
  286.     hilightVertex(coord->point[current_coord], pickColor);
  287.     break;
  288.  
  289.       case ENDPOINTS:
  290.     // Create a new vertex
  291.     if (current_coord != -1) {
  292.         coord->point.insertSpace(current_coord, 1);
  293.     }
  294.     else current_coord = 0;
  295.     coord->point.set1Value(current_coord, current_position);
  296.     myHandleEventAction->setGrabber(this);
  297.     hilightVertex(coord->point[current_coord], pickColor);
  298.     break;
  299.  
  300.       case NOTHING:
  301.     current_coord = -1;
  302.     removeHilights();
  303.     gotSomething = FALSE;
  304.     break;
  305.     }
  306.  
  307.     return gotSomething;
  308. }
  309.  
  310. //
  311. // Called by SoHandleEventAction when we grab events 
  312. // using myHandleEventAction->setGrabber( this );
  313. //
  314. // We will record the viewport and viewvolume.
  315. // This is because once we've grabbed, we can't rely on the new handleEvent
  316. // action to have correct view information.
  317. // Why? Because grabbing bypasses traversal and sends the event directly
  318. // to this node. The camera node has no chance to modify the state.
  319. //
  320.  
  321. void
  322. LineManip2::grabEventsSetup()
  323. {
  324.     extractViewingParams(myHandleEventAction);
  325.     savedRenderCachingVal 
  326.     = (SoSeparator::CacheEnabled) renderCaching.getValue();
  327.     renderCaching = OFF;
  328. }
  329.  
  330.  
  331. void
  332. LineManip2::grabEventsCleanup()
  333. {
  334.     removeHilights();
  335.     current_coord = -1;
  336.  
  337.     renderCaching = savedRenderCachingVal;
  338. }
  339.  
  340. void 
  341. LineManip2::extractViewingParams( SoHandleEventAction *ha )
  342. {
  343.     if (ha == NULL) {
  344.         // If the action is NULL, use default values for view info.
  345.     myViewVolume.ortho(-1,1,-1,1,1,10);
  346.     myVpRegion = SbViewportRegion(1,1);
  347.     }
  348.     else {
  349.     // Get the view info from the action.
  350.     SoState *state = ha->getState();
  351.     myViewVolume = SoViewVolumeElement::get( state );
  352.     myVpRegion = SoViewportRegionElement::get( state );
  353.     }
  354. }
  355.  
  356. //
  357. // Called when the backspace or delete keys is hit.  Note that if the
  358. // mouse is close to the middle of a line segment (so a pick would
  359. // insert a point) nothing is done.  This used to delete the entire
  360. // line segment, but that was not intuitive.  That might be a good
  361. // interface for creating disconnected line segments, though...
  362. //
  363. SbBool
  364. LineManip2::remove()
  365. {
  366.     if (coord == NULL)
  367.     return FALSE;
  368.  
  369.     SbBool removedSomething = TRUE;
  370.  
  371.     if ( myHandleEventAction->getGrabber() == this ) {
  372.     // Remove whatever we're working on.
  373.     if (current_coord != -1)
  374.         coord->point.deleteValues(current_coord, 1);
  375.     }
  376.     else {
  377.     // Remove whatever the cursor indicates should be gone.
  378.     switch (whichPart()) {
  379.       case POINTS:
  380.         coord->point.deleteValues(current_coord, 1);
  381.         break;
  382.  
  383.       case LINES:
  384.         // Do nothing.
  385.         break;
  386.  
  387.       case ENDPOINTS:
  388.         if (current_coord != -1) {
  389.         if (current_coord != coord->point.getNum())
  390.             coord->point.deleteValues(current_coord, 1);
  391.         else 
  392.             coord->point.deleteValues(current_coord-1, 1);
  393.         }
  394.         break;
  395.  
  396.       case NOTHING:
  397.         removedSomething = FALSE;
  398.         break;
  399.     }
  400.     }
  401.  
  402.     removeHilights();
  403.  
  404.     return removedSomething;
  405. }
  406.  
  407. //
  408. // Called when the mouse is moving around, but the left mouse button
  409. // is up.
  410. //
  411. SbBool
  412. LineManip2::locateHilight()
  413. {
  414.     if (coord == NULL )
  415.     return FALSE;
  416.  
  417.     SbBool hilitSomething = TRUE;
  418.  
  419.     switch (whichPart()) {
  420.       case POINTS:
  421.     hilightVertex(coord->point[current_coord], locateColor);
  422.     break;
  423.  
  424.       case LINES:
  425.     hilightLine(current_coord, current_position, locateColor);
  426.     break;
  427.  
  428.       case ENDPOINTS:
  429.     if (current_coord == -1) {
  430.         // There are no coordinates at all. We can't perform a
  431.         // hilight.
  432.         hilitSomething = FALSE;
  433.     }
  434.     else if (current_coord == 0)
  435.         hilightLine(-1, current_position, locateColor);
  436.     else
  437.         hilightLine(current_coord-1, current_position, locateColor);
  438.     break;
  439.  
  440.       case NOTHING:
  441.         hilitSomething = FALSE;
  442.     break;
  443.     }
  444.  
  445.     return hilitSomething;
  446. }
  447.  
  448. //
  449. // Called to move the selected point when the mouse is moved and the
  450. // left mouse button is pressed.
  451. //
  452. void
  453. LineManip2::moveCoord()
  454. {
  455.     if (coord == NULL)
  456.     return;
  457.  
  458.     assert(current_coord > -1 && current_coord < coord->point.getNum());
  459.     updateProjectors( coord->point[current_coord] );
  460.     SbVec3f t; 
  461.     projectMouse(t);
  462.     coord->point.set1Value(current_coord, t);
  463.  
  464.     hilightVertex(coord->point[current_coord], pickColor);
  465. }
  466.  
  467. void
  468. LineManip2::updateProjectors( const SbVec3f &curPt )
  469. {
  470.     SbVec3f  dir = lineProj->getLine().getDirection();
  471.     lineProj->setLine( SbLine( curPt, curPt + dir ) );
  472.  
  473.     dir = planeProj->getPlane().getNormal();
  474.     planeProj->setPlane( SbPlane( dir, curPt ) );
  475. }
  476.  
  477. //
  478. // Does the grunt work of projecting the mouse onto the plane
  479. // containing the line manipulator.
  480. //
  481. void
  482. LineManip2::projectMouse(SbVec3f &result)
  483. {
  484.     const SoEvent *e = myHandleEventAction->getEvent();
  485.  
  486.     // If we're grabbing, we've already got our view parameters.
  487.     // If not, then we'd better get them now.
  488.     // NOTE: If you're grabbing and you try to get view parameters, you'll
  489.     //       get a bad answer. Grabbing causes you to skip over camera
  490.     //       nodes directly to this one. So the state has no valid view info.
  491.     if ( myHandleEventAction->getGrabber() != this )
  492.     extractViewingParams(myHandleEventAction);
  493.  
  494.     // If alt key is down, then we move in line perpendicular to plane
  495.     if ( e->wasAltDown() == FALSE ) {
  496.     planeProj->setViewVolume(myViewVolume);
  497.     result = planeProj->project(e->getNormalizedPosition(myVpRegion));
  498.     }
  499.     else {
  500.     lineProj->setViewVolume(myViewVolume);
  501.     result = lineProj->project(e->getNormalizedPosition(myVpRegion));
  502.     }
  503. }
  504.