00001 /*======================================================================= 00002 * Copyright 1991-1996, Silicon Graphics, Inc. 00003 * ALL RIGHTS RESERVED 00004 * 00005 * UNPUBLISHED -- Rights reserved under the copyright laws of the United 00006 * States. Use of a copyright notice is precautionary only and does not 00007 * imply publication or disclosure. 00008 * 00009 * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND: 00010 * Use, duplication or disclosure by the Government is subject to restrictions 00011 * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights 00012 * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or 00013 * in similar or successor clauses in the FAR, or the DOD or NASA FAR 00014 * Supplement. Contractor/manufacturer is Silicon Graphics, Inc., 00015 * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311. 00016 * 00017 * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY 00018 * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION, 00019 * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY 00020 * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON 00021 * GRAPHICS, INC. 00022 **=======================================================================*/ 00023 /*======================================================================= 00024 ** Author : Paul S. Strauss (MMM yyyy) 00025 ** Modified by : Nick Thompson (MMM yyyy) 00026 **=======================================================================*/ 00027 /*======================================================================= 00028 *** THE CONTENT OF THIS WORK IS PROPRIETARY TO FEI S.A.S, (FEI S.A.S.), *** 00029 *** AND IS DISTRIBUTED UNDER A LICENSE AGREEMENT. *** 00030 *** *** 00031 *** REPRODUCTION, DISCLOSURE, OR USE, IN WHOLE OR IN PART, OTHER THAN AS *** 00032 *** SPECIFIED IN THE LICENSE ARE NOT TO BE UNDERTAKEN EXCEPT WITH PRIOR *** 00033 *** WRITTEN AUTHORIZATION OF FEI S.A.S. *** 00034 *** *** 00035 *** RESTRICTED RIGHTS LEGEND *** 00036 *** USE, DUPLICATION, OR DISCLOSURE BY THE GOVERNMENT OF THE CONTENT OF THIS *** 00037 *** WORK OR RELATED DOCUMENTATION IS SUBJECT TO RESTRICTIONS AS SET FORTH IN *** 00038 *** SUBPARAGRAPH (C)(1) OF THE COMMERCIAL COMPUTER SOFTWARE RESTRICTED RIGHT *** 00039 *** CLAUSE AT FAR 52.227-19 OR SUBPARAGRAPH (C)(1)(II) OF THE RIGHTS IN *** 00040 *** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 52.227-7013. *** 00041 *** *** 00042 *** COPYRIGHT (C) 1996-2018 BY FEI S.A.S, *** 00043 *** MERIGNAC, FRANCE *** 00044 *** ALL RIGHTS RESERVED *** 00045 **=======================================================================*/ 00046 /*======================================================================= 00047 ** Modified by : VSG (MMM YYYY) 00048 **=======================================================================*/ 00049 00050 00051 #ifndef _SO_RAY_PICK_ACTION_ 00052 #define _SO_RAY_PICK_ACTION_ 00053 00054 #include <Inventor/SoLists.h> 00055 #include <Inventor/nodes/SoCamera.h> 00056 #include <Inventor/actions/SoPickAction.h> 00057 #include <Inventor/SbBox.h> 00058 #include <Inventor/lists/SoPickedPointList.h> 00059 00060 class PickedPointListImpl; 00061 class HomTransfData; 00062 00064 // 00065 // Class: SoRayPickAction 00066 // 00067 // Picking action that intersects a ray with objects in the scene 00068 // graph. The ray can be specified by calling setPoint() with a point 00069 // in a viewport in a rendering window or by calling setRay() with a 00070 // world-space ray. In the setPoint() case, a valid camera must be 00071 // encountered in the graph to set up the mapping to world space. 00072 // 00073 // The "pickAll" flag indicates whether all intersections along the 00074 // ray should be returned (sorted by distance from the starting point 00075 // of the ray), or just the closest one. In either case, the 00076 // intersections are returned as an SoPickedPointList. Each 00077 // intersection can be examined by accessing the appropriate 00078 // SoPickedPoint in the list. The SoPickedPoint class provides 00079 // methods to get the intersection point, normal, and other info. 00080 // 00082 00328 class SoRayPickAction : public SoPickAction { 00329 00330 SO_ACTION_HEADER(SoRayPickAction); 00331 00332 public: 00333 00340 static void setStereoMode(SoCamera::StereoMode stereoMode); 00341 00344 static SoCamera::StereoMode getStereoMode(); 00345 00351 SoRayPickAction(const SbViewportRegion &viewportRegion); 00352 00361 virtual void clearApplyResult(); 00362 00363 // Destructor 00364 #ifndef HIDDEN_FROM_DOC 00365 virtual ~SoRayPickAction(); 00366 #endif // HIDDEN_FROM_DOC 00367 00369 // 00370 // Setting up the action before it is applied: 00371 // 00372 00373 enum PickingMode { 00380 DEFAULT, 00381 00396 POINT_PICKING 00397 00398 // EDGE_PICKING, 00399 // FACE_PICKING 00400 }; 00401 00407 void setPickingMode(PickingMode pickingMode); 00408 00412 PickingMode getPickingMode() const; 00413 00422 virtual void setPoint(const SbVec2s &viewportPoint); 00423 00432 virtual void setPoint(const SbVec2f &viewportPoint); 00433 00438 const SbVec2s& getPoint() const { return VPPoint; } 00439 00445 const SbVec2f& getPointFloat() const { return VPPointFloat; } 00446 00454 virtual void setNormalizedPoint(const SbVec2f &normPoint); 00455 00465 const SbVec2f getNormalizedPoint() const 00466 { return normVPPoint; } 00467 00488 void setRadius(float radius); 00489 00493 float getRadius() const 00494 { return VPRadius; } 00495 00513 virtual void setRay(const SbVec3f &start, const SbVec3f &direction, 00514 float nearDistance = -1.0, 00515 float farDistance = -1.0); 00516 00536 virtual void setRay(float fovy, const SbVec3f &start, const SbVec3f &direction, 00537 float nearDistance = -1.0, 00538 float farDistance = -1.0); 00539 00544 void setPickAll(SbBool flag) 00545 { pickAll = flag; } 00546 00551 SbBool isPickAll() const 00552 { return pickAll; } 00553 00555 // 00556 // Examining results after the action is applied: 00557 // 00558 00566 const SoPickedPointList &getPickedPointList() const; 00567 00585 SoPickedPoint *getPickedPoint(int index = 0) const; 00586 SoDEPRECATED 00596 void clearPickedPointList(); 00597 00607 void enableRadiusForTriangles(SbBool flag); 00608 00613 SbBool isRadiusEnableForTriangles(); 00614 00621 static void enableTriangleCulling(SbBool flag) ; 00622 00623 00627 static SbBool isTriangleCulling() 00628 { return s_triangleCullingEnabled; } 00629 00635 void enableTexCoordsGeneration(const SbBool enable); 00636 00641 void enableNormalsGeneration(const SbBool enable); 00642 00647 SbBool isTexCoordsGenerationEnabled() const; 00648 00653 SbBool isNormalsGenerationEnabled() const; 00654 00668 void enableConicPickVolume(SbBool flag); 00669 00673 inline SbBool isConicPickVolume() 00674 { return m_conicPickVolume; } 00675 00676 private: 00677 00678 // If a ray was not defined with setRay(), this causes the world 00679 // space pick ray to be computed from the screen space point and 00680 // radius, using the current view specification from the state. 00681 // This is typically done when a camera is encountered during 00682 // traversal. 00683 void computeWorldSpaceRay(); 00684 00685 // This returns TRUE if the action has had a world space ray set 00686 // or computed 00687 SbBool hasWorldSpaceRay() const; 00688 00689 // This is called by shapes to set up object space picking. It 00690 // uses the current state matrices to determine how to map between 00691 // world and object spaces. It should be called before calling any 00692 // of the intersection methods. 00693 // The second form takes a matrix to concatenate with the current 00694 // objToWorld matrix. It can be used, for example, if a shape has 00695 // sizing or positioning info built into it. 00696 // 00697 // These methods are also in charge of resetting the cached picked point 00698 // shape path, so the application must call the appropriate one once for 00699 // any shape that redefines the rayPick method before calling addIntersection(). 00700 void setObjectSpace(); 00701 void setObjectSpace(const SbMatrix &matrix); 00702 00703 // These intersect the current object-space ray with a variety of 00704 // primitives: triangle, line, point, bounding-box. Intersection 00705 // with a triangle uses only the ray, while intersection with a 00706 // line or point uses the cone or cylinder around the ray. The 00707 // intersection with a bounding-box uses the cone/cylinder also, 00708 // since the contents of the box may be lines or points. NOTE: you 00709 // must call setObjectSpace() before calling any of these. 00710 00711 // Triangle: returns intersection point, barycentric coordinates, 00712 // and whether the front side (defined by right-hand-rule) was hit. 00713 SbBool intersect(const SbVec3f &v0, 00714 const SbVec3f &v1, 00715 const SbVec3f &v2, 00716 SbVec3f &intersection, SbVec3f &barycentric, 00717 SbBool &front) ; 00718 00719 // Line: 00720 SbBool intersect(const SbVec3f &v0, const SbVec3f &v1, 00721 SbVec3f &intersection) const; 00722 00723 // Point: 00724 SbBool intersect(const SbVec3f &point) const; 00725 00732 inline SbBool intersect(const SbBox3f &box, SbBool useFullViewVolume = TRUE) 00733 { 00734 SbXfBox3f xbox(box); 00735 return intersect(xbox, useFullViewVolume); 00736 } 00737 00744 SbBool intersect(const SbXfBox3f &box, SbBool useFullViewVolume = TRUE); 00745 00746 00747 // Returns an SbViewVolume that represents the object-space ray to 00748 // pick along. The projection point of the view volume is the 00749 // starting point of the ray. The projection direction is the 00750 // direction of the ray. The distance to the near plane is the 00751 // same as the distance to the near plane for the ray. The 00752 // distance to the far plane is the sum of the near distance and 00753 // the depth of the view volume. 00754 const SbViewVolume &getViewVolume() const 00755 { return objVol; } 00756 00757 // Returns SbLine that can be used for other intersection tests. 00758 // The line's position is the starting point and the direction is 00759 // the direction of the ray. Given an intersection with this ray, 00760 // you can call isBetweenPlanes() to see if the intersection is 00761 // between the near and far clipping planes. 00762 const SbLine &getLine() const 00763 { return objLine; } 00764 00765 // Returns TRUE if the given object-space intersection point is 00766 // between the near and far planes of the object-space view 00767 // volume, as well as any clipping planes that have been defined. 00768 // This test can be used to determine whether the point of 00769 // intersection of the ray with an object is valid with respect to 00770 // the clipping planes. 00771 SbBool isBetweenPlanes(const SbVec3f &intersection) const; 00772 00782 SoPickedPoint *addIntersection(const SbVec3f &objectSpacePoint); 00783 00784 // Adds an SoPickedPoint instance representing the given object 00785 // space point to the current list and returns a pointer to it. If 00786 // pickAll is TRUE, this inserts the instance in correct sorted 00787 // order. If it is FALSE, it replaces the one instance in the list 00788 // only if the new one is closer; if the new one is farther away, 00789 // no instance is created and NULL is returned, meaning that no 00790 // more work has to be done to set up the SoPickedPoint. 00791 SoPickedPoint *addIntersection_ ( const SbVec3f &objectSpacePoint, PickedPointListImpl* ppimplptr ); 00792 SoPickedPoint *addIntersection_( SoPickedPoint *pp, PickedPointListImpl* ppimplptr ); 00793 SoPickedPoint *addIntersection_( SoPickedPoint *pp ); 00794 00795 00796 // Get PickedPoints during a traversal without sorting them by distance 00797 // this method must be used instead of the getPickedPointList 00798 // that should be used instead only AFTER the rayPick traversal is completed 00799 SoPickedPoint *getUnsortedPickedPoint( int i ) const; 00800 00801 // Use preferably this method to get just the number of picked points 00802 // instead of getPickedPointList()->getLenght(), for performance reason 00803 int getPickedPointsListLength() const; 00804 00805 private: 00806 // Initiates action on graph 00807 virtual void beginTraversal(SoNode *node); 00808 00809 private: 00810 static void initClass(); 00811 static void exitClass(); 00812 00813 // return whether OIV_PICK_OPTIM is set to TRUE 00814 static SbBool isPickOptimSet() 00815 { return s_useAlternateIntersection; } 00816 00817 // utility method to test if culling occurs because of clipping planes 00818 // worldCoord is used to use world coordinates instead of object space coordinates 00819 static bool isPtCulledByClippingPlanes( const SbVec3f &worldPt, SoState *state, bool worldCoord = true ); 00820 00821 // utility method to test if culling occurs because of clipping planes 00822 // worldCoord is used to use world coordinates instead of object space coordinates 00823 static bool isBboxCompletelyCulledByClippingPlanes( const SbBox3d& worldBBox, SoState* state, bool worldCoord = true ); 00824 // worldCoord is used to use world coordinates instead of object space coordinates 00825 static bool isBboxCompletelyCulledByClippingPlanes( const SbBox3f& worldBBox, SoState* state, bool worldCoord = true ); 00826 // worldCoord is used to use world coordinates instead of object space coordinates 00827 static bool arePointsCulledByAClippingPlane( const std::vector< SbVec3f>& pointVector, SoState* state, bool worldCoord = true ); 00828 00834 enum PickedProperties 00835 { 00837 NORMALS = 1 << 0, 00839 TEXCOORDS = 1 << 1, 00840 00842 ALL = ~0 00843 }; 00844 00848 void enablePickedProperties(const enum PickedProperties pickedProperty, const SbBool enable); 00849 00853 SbBool isPickedPropertiesEnabled(const enum PickedProperties pickedProperty) const; 00854 00855 // Returns TRUE if the two SoPickedPoint are the same. 00856 SbBool isEqual(const SoPickedPoint *pp0, const SoPickedPoint *pp1) const; 00857 00858 // Returns TRUE if the first intersection point is closer to the 00859 // starting point of the ray than the second. 00860 SbBool isCloser(const SoPickedPoint *pp0, const SoPickedPoint *pp1) const; 00861 SbBool isCloser(const SbVec3f& p0, const SbVec3f& p1) const; 00862 00863 // get depth for ray picking sorting 00864 double getDepth(const SbVec3f& p0) const; 00865 00866 //interface exposed to share SoPath among SoPickedPoints 00867 inline void resetCurrPathCache(); 00868 00869 enum PointPositionClassification 00870 { 00871 INSIDE = 0, 00872 BEHIND_FAR = 1, 00873 BEFORE_NEAR = 2, 00874 BESIDE_LEFT = 3, 00875 BESIDE_RIGHT = 4, 00876 UNDER_BOTTOM = 5, 00877 ABOVE_TOP = 6 00878 }; 00879 00880 PointPositionClassification homogeneSpaceIntersection( const SbVec3f &point, SbVec4f &pPoint ) const; 00881 SoPath *getClonedCurrPath(); 00882 00883 static bool isMTPickingActive(); 00884 00885 // get VPradius in pixels (even if it was provided in world coords) 00886 float getVPRadiusPixel() const ; 00887 00888 /* Because picking points should take care of pointSize without modifying 00889 * the internal projection matrix, 00890 * a distosion depending of the size of viewPortRegion is introduced 00891 * This distorsion can be computed from pointSize 00892 * By default pointSize is (0, 0) 00893 * Normal usage should be setPointSizeForPicking( WidthInPixels, HeightInPixels) 00894 * WARNING: Don't forget to restore previous pointSize after your traversal to avoid side effect 00895 */ 00896 void setPointSizeForPicking( float pointWidth, float pointHeight); 00897 00898 // Same as previous with an SbVec2f 00899 void setPointSizeForPicking( const SbVec2f & pointSize) 00900 { setPointSizeForPicking(pointSize[0], pointSize[1]); } 00901 00902 // Return current pointSize for picking points 00903 SbVec2f getPointSizeForPicking() 00904 { return SbVec2f(m_pointWidthForPicking, m_pointHeightForPicking); } 00905 00906 private: 00907 SbBool lineWasSet; // TRUE if a world-space line was set 00908 SbBool rayWasComputed; // TRUE if ray computed by camera 00909 SbBool pickAll; // Pick all objects or just closest 00910 SbVec2s VPPoint; // Point in viewport coordinates 00911 SbVec2f VPPointFloat; // Point in viewport coordinates 00912 SbVec2f normVPPoint; // Point in normalized vp coordinates 00913 SbBool normPointSet; // TRUE if setNormalizedPoint called 00914 float VPRadius; // Radius in viewport space pixels 00915 SbMatrix objToWorld; // Object-to-world space matrix 00916 SbMatrix worldToObj; // World-to-object space matrix 00917 00918 // The ray is defined as an SbViewVolume as in the 00919 // SoPickRayElement, and is usually stored in an instance of the 00920 // element. This stores the ray if it is set using setRay(). 00921 SbViewVolume worldVol; 00922 00923 // Users can specify negative near and far distances to indicate 00924 // that picks should not be clipped to those planes. These flags 00925 // store that info, since the distances in the view volume can't 00926 // be negative. 00927 SbBool clipToNear, clipToFar; 00928 00929 // These store the object-space ray info as a view volume and a 00930 // line. See the comments on getViewVolume() and getLine(). 00931 SbLine objLine; // Line representing ray 00932 SbLined objLineD; 00933 SbViewVolume objVol; // View volume representing ray 00934 00935 // If the caller passes a matrix to setObjectSpace(), the inverse 00936 // of it is stored here so the object-space angle can be computed 00937 // correctly later. The extraMatrixSet flag is set to TRUE in this 00938 // case. 00939 SbBool extraMatrixSet; 00940 SbMatrix extraMatrix; 00941 00942 // Computes matrices to go between object and world space 00943 void computeMatrices(); 00944 00945 // Computes object-space view volume and line 00946 void computeObjVolAndLine(); 00947 00948 // updates RayBBox and WMat 00949 void setUpRayBBoxAndWMat( const SbVec3f ¢erPt ); 00950 00951 void evalCenterPts( SbVec3f ¢erPt, SbVec3d ¢erPtD, SbVec3d &projPtD ); 00952 00953 // get VPRadius in world coordinates (even if it was provided in pixels) 00954 float getVPRadiusWorld() const ; 00955 00956 // Computes distance t of a point along a ray: point = start + t * direction. 00957 // The point has to be on the ray for this to work 00958 static float rayDistance(const SbVec3f &start, 00959 const SbVec3f &direction, 00960 const SbVec3f &point); 00961 00962 // Set commons properties of the action (called by the setRay method) 00963 void setRayCommonProperties (const SbVec3f &start, const SbVec3f &direction, 00964 float fovy, float aspectRatio = 1.0f, float nearDistance=-1.0f, float farDistance=-1.0f); 00965 00966 // Initialize some members variable when a new point in viewport has been set 00967 void initializeMembersAfterVPPointSet(bool normalizedPointSet); 00968 00969 00970 00971 // check if the intersection is inside conic picking volume 00972 inline SbBool isInConicPickingVolume( const SbVec3f &intersection ) const; 00973 00974 void initSetRayData ( const SbVec3f &start, const SbVec3f &direction, 00975 float fovy, float aspectRatio = 1.0f, 00976 float nearDistance = -1.0f, float farDistance = -1.0f ); 00977 00978 // Store the current ray bounding box for triangle culling 00979 SbBool m_canUseTriangleCulling; 00980 SbBox3f m_rayBBox ; 00981 00982 00983 // store the current viewvolume matrix and near far in homogene space 00984 // to optimize intersection computation 00985 SbMatrixd m_wmat; 00986 double m_wnear; 00987 double m_wfar; 00988 HomTransfData *m_htdta; 00989 00990 // Indicate if triangle are culled by ray frustum. 00991 SbBool canUseTriangleCulling() const 00992 { return (s_triangleCullingEnabled && m_canUseTriangleCulling); } 00993 00994 static SbBool s_triangleCullingEnabled ; 00995 00996 // generate all picked point properties? (OIV_PICK_GENERATE_ALL_PROPERTIES) 00997 static SbBool s_generateAllPickedProperties; 00998 00999 // 01000 static SoCamera::StereoMode s_stereoMode; 01001 01002 // Use faster intersection method (OIV_PICK_OPTIM) 01003 static SbBool s_useAlternateIntersection; 01004 01005 // Force the raypick action to take ray radius in account 01006 SbBool m_bEnableRadiusForTriangles; 01007 01008 // Store ray properties 01009 SbVec3f m_direction; 01010 SbVec3f m_start; 01011 01012 private: 01013 int m_pickedPropertiesMask; 01014 PickingMode m_pickingMode; 01015 01016 int m_VPRadiusState; // how VPRadius has been initialized 01017 01018 // data buffered for the lineWasSet case 01019 float m_fovy; 01020 float m_nearDistance; 01021 float m_farDistance; 01022 float m_aspectRatio; 01023 01024 // to force pick volume to be a cone (perspective pick) or a cylinder (orthogonal pick) 01025 SbBool m_conicPickVolume; 01026 01027 PickedPointListImpl *m_pickedPointListlImpl; 01028 01029 // Only computed by setPointSizeForPicking() 01030 // Only used in homogeneSpaceIntersection() 01031 // Store picking error depending of viewPort 01032 float m_pointPickingErrorX; 01033 float m_pointPickingErrorY; 01034 // Store extended pick trap depending of pointSize 01035 float m_projSpaceWidth; 01036 float m_projSpaceHeight; 01037 // Store pointSize for picking point 01038 float m_pointWidthForPicking; 01039 float m_pointHeightForPicking; 01040 }; 01041 01042 inline 01043 void SoRayPickAction::enableRadiusForTriangles(SbBool flag) 01044 { 01045 m_bEnableRadiusForTriangles = flag; 01046 } 01047 01048 inline 01049 SbBool SoRayPickAction::isRadiusEnableForTriangles() 01050 { 01051 return m_bEnableRadiusForTriangles; 01052 } 01053 #endif /* _SO_RAY_PICK_ACTION_ */ 01054 01055