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-2022 BY FEI S.A.S, *** 00043 *** BORDEAUX, 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 00344 class SoRayPickAction : public SoPickAction { 00345 00346 SO_ACTION_HEADER(SoRayPickAction); 00347 00348 public: 00349 00356 static void setStereoMode(SoCamera::StereoMode stereoMode); 00357 00360 static SoCamera::StereoMode getStereoMode(); 00361 00367 SoRayPickAction(const SbViewportRegion &viewportRegion); 00368 00377 virtual void clearApplyResult(); 00378 00379 // Destructor 00380 #ifndef HIDDEN_FROM_DOC 00381 virtual ~SoRayPickAction(); 00382 #endif // HIDDEN_FROM_DOC 00383 00385 // 00386 // Setting up the action before it is applied: 00387 // 00388 00389 enum PickingMode { 00396 DEFAULT, 00397 00412 POINT_PICKING 00413 00414 // EDGE_PICKING, 00415 // FACE_PICKING 00416 }; 00417 00423 void setPickingMode(PickingMode pickingMode); 00424 00428 PickingMode getPickingMode() const; 00429 00438 void setPoint(const SbVec2s &viewportPoint); 00439 00448 void setPoint(const SbVec2f &viewportPoint); 00449 00454 const SbVec2s& getPoint() const { return VPPoint; } 00455 00461 const SbVec2f& getPointFloat() const { return VPPointFloat; } 00462 00470 void setNormalizedPoint(const SbVec2f &normPoint); 00471 00480 const SbVec2f getNormalizedPoint() const 00481 { return normVPPoint; } 00482 00503 void setRadius(float radius); 00504 00508 float getRadius() const 00509 { return VPRadius; } 00510 00528 void setRay(const SbVec3f &start, const SbVec3f &direction, 00529 float nearDistance = -1.0, 00530 float farDistance = -1.0); 00531 00551 void setRay(float fovy, const SbVec3f &start, const SbVec3f &direction, 00552 float nearDistance = -1.0, 00553 float farDistance = -1.0); 00554 00559 void setPickAll(SbBool flag) 00560 { pickAll = flag; } 00561 00566 SbBool isPickAll() const 00567 { return pickAll; } 00568 00570 // 00571 // Examining results after the action is applied: 00572 // 00573 00581 const SoPickedPointList &getPickedPointList() const; 00582 00600 SoPickedPoint *getPickedPoint(int index = 0) const; 00601 SoDEPRECATED 00611 void clearPickedPointList(); 00612 00622 void enableRadiusForTriangles(SbBool flag); 00623 00628 SbBool isRadiusEnableForTriangles(); 00629 00636 static void enableTriangleCulling(SbBool flag) ; 00637 00638 00642 static SbBool isTriangleCulling() 00643 { return s_triangleCullingEnabled; } 00644 00650 void enableTexCoordsGeneration(const SbBool enable); 00651 00656 void enableNormalsGeneration(const SbBool enable); 00657 00662 SbBool isTexCoordsGenerationEnabled() const; 00663 00668 SbBool isNormalsGenerationEnabled() const; 00669 00683 void enableConicPickVolume(SbBool flag); 00684 00688 inline SbBool isConicPickVolume() 00689 { return m_conicPickVolume; } 00690 00691 private: 00692 00693 // If a ray was not defined with setRay(), this causes the world 00694 // space pick ray to be computed from the screen space point and 00695 // radius, using the current view specification from the state. 00696 // This is typically done when a camera is encountered during 00697 // traversal. 00698 void computeWorldSpaceRay(); 00699 00700 // This returns TRUE if the action has had a world space ray set 00701 // or computed 00702 SbBool hasWorldSpaceRay() const; 00703 00704 // This is called by shapes to set up object space picking. It 00705 // uses the current state matrices to determine how to map between 00706 // world and object spaces. It should be called before calling any 00707 // of the intersection methods. 00708 // The second form takes a matrix to concatenate with the current 00709 // objToWorld matrix. It can be used, for example, if a shape has 00710 // sizing or positioning info built into it. 00711 // 00712 // These methods are also in charge of resetting the cached picked point 00713 // shape path, so the application must call the appropriate one once for 00714 // any shape that redefines the rayPick method before calling addIntersection(). 00715 void setObjectSpace(); 00716 void setObjectSpace(const SbMatrix &matrix); 00717 00718 // These intersect the current object-space ray with a variety of 00719 // primitives: triangle, line, point, bounding-box. Intersection 00720 // with a triangle uses only the ray, while intersection with a 00721 // line or point uses the cone or cylinder around the ray. The 00722 // intersection with a bounding-box uses the cone/cylinder also, 00723 // since the contents of the box may be lines or points. NOTE: you 00724 // must call setObjectSpace() before calling any of these. 00725 00726 // Triangle: returns intersection point, barycentric coordinates, 00727 // and whether the front side (defined by right-hand-rule) was hit. 00728 SbBool intersect(const SbVec3f &v0, 00729 const SbVec3f &v1, 00730 const SbVec3f &v2, 00731 SbVec3f &intersection, SbVec3f &barycentric, 00732 SbBool &front) ; 00733 00734 // Line: 00735 SbBool intersect(const SbVec3f &v0, const SbVec3f &v1, 00736 SbVec3f &intersection) const; 00737 00738 // Point: 00739 SbBool intersect(const SbVec3f &point) const; 00740 00747 inline SbBool intersect(const SbBox3f &box, SbBool useFullViewVolume = TRUE) 00748 { 00749 SbXfBox3f xbox(box); 00750 return intersect(xbox, useFullViewVolume); 00751 } 00752 00759 SbBool intersect(const SbXfBox3f &box, SbBool useFullViewVolume = TRUE); 00760 00761 00762 // Returns an SbViewVolume that represents the object-space ray to 00763 // pick along. The projection point of the view volume is the 00764 // starting point of the ray. The projection direction is the 00765 // direction of the ray. The distance to the near plane is the 00766 // same as the distance to the near plane for the ray. The 00767 // distance to the far plane is the sum of the near distance and 00768 // the depth of the view volume. 00769 const SbViewVolume &getViewVolume() const 00770 { return objVol; } 00771 00772 // Returns SbLine that can be used for other intersection tests. 00773 // The line's position is the starting point and the direction is 00774 // the direction of the ray. Given an intersection with this ray, 00775 // you can call isBetweenPlanes() to see if the intersection is 00776 // between the near and far clipping planes. 00777 const SbLine &getLine() const 00778 { return objLine; } 00779 00780 // Returns TRUE if the given object-space intersection point is 00781 // between the near and far planes of the object-space view 00782 // volume, as well as any clipping planes that have been defined. 00783 // This test can be used to determine whether the point of 00784 // intersection of the ray with an object is valid with respect to 00785 // the clipping planes. 00786 SbBool isBetweenPlanes(const SbVec3f &intersection) const; 00787 00797 SoPickedPoint *addIntersection(const SbVec3f &objectSpacePoint); 00798 00799 // Get PickedPoints during a traversal without sorting them by distance 00800 // this method must be used instead of the getPickedPointList 00801 // that should be used instead only AFTER the rayPick traversal is completed 00802 SoPickedPoint *getUnsortedPickedPoint( int i ) const; 00803 00804 // Use preferably this method to get just the number of picked points 00805 // instead of getPickedPointList()->getLenght(), for performance reason 00806 int getPickedPointsListLength() const; 00807 00808 private: 00809 // Initiates action on graph 00810 virtual void beginTraversal(SoNode *node); 00811 00812 private: 00813 static void initClass(); 00814 static void exitClass(); 00815 00816 // return whether OIV_PICK_OPTIM is set to TRUE 00817 static SbBool isPickOptimSet() 00818 { return s_useAlternateIntersection; } 00819 00820 // utility method to test if culling occurs because of clipping planes 00821 // worldCoord is used to use world coordinates instead of object space coordinates 00822 static bool isPtCulledByClippingPlanes( const SbVec3f &worldPt, SoState *state, bool worldCoord = true ); 00823 00824 // utility method to test if culling occurs because of clipping planes 00825 // worldCoord is used to use world coordinates instead of object space coordinates 00826 static bool isBboxCompletelyCulledByClippingPlanes( const SbBox3d& worldBBox, SoState* state, bool worldCoord = true ); 00827 // worldCoord is used to use world coordinates instead of object space coordinates 00828 static bool isBboxCompletelyCulledByClippingPlanes( const SbBox3f& worldBBox, SoState* state, bool worldCoord = true ); 00829 // worldCoord is used to use world coordinates instead of object space coordinates 00830 static bool arePointsCulledByAClippingPlane( const std::vector< SbVec3f>& pointVector, SoState* state, bool worldCoord = true ); 00831 00837 enum PickedProperties 00838 { 00840 NORMALS = 1 << 0, 00842 TEXCOORDS = 1 << 1, 00843 00845 ALL = ~0 00846 }; 00847 00851 void enablePickedProperties(const enum PickedProperties pickedProperty, const SbBool enable); 00852 00856 SbBool isPickedPropertiesEnabled(const enum PickedProperties pickedProperty) const; 00857 00858 // Returns TRUE if the two SoPickedPoint are the same. 00859 SbBool isEqual(const SoPickedPoint *pp0, const SoPickedPoint *pp1) const; 00860 00861 // Returns TRUE if the first intersection point is closer to the 00862 // starting point of the ray than the second. 00863 SbBool isCloser(const SoPickedPoint *pp0, const SoPickedPoint *pp1) const; 00864 SbBool isCloser(const SbVec3f& p0, const SbVec3f& p1) const; 00865 00866 // get depth for ray picking sorting 00867 double getDepth(const SbVec3f& p0) const; 00868 00869 //interface exposed to share SoPath among SoPickedPoints 00870 inline void resetCurrPathCache(); 00871 00872 enum PointPositionClassification 00873 { 00874 INSIDE = 0, 00875 BEHIND_FAR = 1, 00876 BEFORE_NEAR = 2, 00877 BESIDE_LEFT = 3, 00878 BESIDE_RIGHT = 4, 00879 UNDER_BOTTOM = 5, 00880 ABOVE_TOP = 6 00881 }; 00882 00883 PointPositionClassification homogeneSpaceIntersection( const SbVec3f &point, SbVec4f &pPoint ) const; 00884 SoPath *getClonedCurrPath(); 00885 00886 // get VPradius in pixels (even if it was provided in world coords) 00887 float getVPRadiusPixel() const ; 00888 00889 /* Because picking points should take care of pointSize without modifying 00890 * the internal projection matrix, 00891 * a distosion depending of the size of viewPortRegion is introduced 00892 * This distorsion can be computed from pointSize 00893 * By default pointSize is (0, 0) 00894 * Normal usage should be setPointSizeForPicking( WidthInPixels, HeightInPixels) 00895 * WARNING: Don't forget to restore previous pointSize after your traversal to avoid side effect 00896 */ 00897 void setPointSizeForPicking( float pointWidth, float pointHeight); 00898 00899 // Same as previous with an SbVec2f 00900 void setPointSizeForPicking( const SbVec2f & pointSize) 00901 { setPointSizeForPicking(pointSize[0], pointSize[1]); } 00902 00903 // Return current pointSize for picking points 00904 SbVec2f getPointSizeForPicking() 00905 { return SbVec2f(m_pointWidthForPicking, m_pointHeightForPicking); } 00906 00907 private: 00908 SbBool lineWasSet; // TRUE if a world-space line was set 00909 SbBool rayWasComputed; // TRUE if ray computed by camera 00910 SbBool pickAll; // Pick all objects or just closest 00911 SbVec2s VPPoint; // Point in viewport coordinates 00912 SbVec2f VPPointFloat; // Point in viewport coordinates 00913 SbVec2f normVPPoint; // Point in normalized vp coordinates 00914 SbBool normPointSet; // TRUE if setNormalizedPoint called 00915 float VPRadius; // Radius in viewport space pixels 00916 SbMatrix objToWorld; // Object-to-world space matrix 00917 SbMatrix worldToObj; // World-to-object space matrix 00918 00919 // The ray is defined as an SbViewVolume as in the 00920 // SoPickRayElement, and is usually stored in an instance of the 00921 // element. This stores the ray if it is set using setRay(). 00922 SbViewVolume worldVol; 00923 00924 // Users can specify negative near and far distances to indicate 00925 // that picks should not be clipped to those planes. These flags 00926 // store that info, since the distances in the view volume can't 00927 // be negative. 00928 SbBool clipToNear, clipToFar; 00929 00930 // These store the object-space ray info as a view volume and a 00931 // line. See the comments on getViewVolume() and getLine(). 00932 SbLine objLine; // Line representing ray 00933 SbLined objLineD; 00934 SbViewVolume objVol; // View volume representing ray 00935 00936 // If the caller passes a matrix to setObjectSpace(), the inverse 00937 // of it is stored here so the object-space angle can be computed 00938 // correctly later. The extraMatrixSet flag is set to TRUE in this 00939 // case. 00940 SbBool extraMatrixSet; 00941 SbMatrix extraMatrix; 00942 00943 // Computes matrices to go between object and world space 00944 void computeMatrices(); 00945 00946 // Computes object-space view volume and line 00947 void computeObjVolAndLine(); 00948 00949 // updates RayBBox and WMat 00950 void setUpRayBBoxAndWMat( const SbVec3f ¢erPt ); 00951 00952 void evalCenterPts( SbVec3f ¢erPt, SbVec3d ¢erPtD, SbVec3d &projPtD ); 00953 00954 // get VPRadius in world coordinates (even if it was provided in pixels) 00955 float getVPRadiusWorld() const ; 00956 00957 // Computes distance t of a point along a ray: point = start + t * direction. 00958 // The point has to be on the ray for this to work 00959 static float rayDistance(const SbVec3f &start, 00960 const SbVec3f &direction, 00961 const SbVec3f &point); 00962 00963 // Set commons properties of the action (called by the setRay method) 00964 void setRayCommonProperties (const SbVec3f &start, const SbVec3f &direction, 00965 float fovy, float aspectRatio = 1.0f, float nearDistance=-1.0f, float farDistance=-1.0f); 00966 00967 // Initialize some members variable when a new point in viewport has been set 00968 void initializeMembersAfterVPPointSet(bool normalizedPointSet); 00969 00970 00971 00972 // check if the intersection is inside conic picking volume 00973 inline SbBool isInConicPickingVolume( const SbVec3f &intersection ) const; 00974 00975 void initSetRayData ( const SbVec3f &start, const SbVec3f &direction, 00976 float fovy, float aspectRatio = 1.0f, 00977 float nearDistance = -1.0f, float farDistance = -1.0f ); 00978 00979 // Store the current ray bounding box for triangle culling 00980 SbBool m_canUseTriangleCulling; 00981 SbBox3f m_rayBBox ; 00982 00983 00984 // store the current viewvolume matrix and near far in homogene space 00985 // to optimize intersection computation 00986 SbMatrixd m_wmat; 00987 double m_wnear; 00988 double m_wfar; 00989 HomTransfData *m_htdta; 00990 00991 // Indicate if triangle are culled by ray frustum. 00992 SbBool canUseTriangleCulling() const 00993 { return (s_triangleCullingEnabled && m_canUseTriangleCulling); } 00994 00995 static SbBool s_triangleCullingEnabled ; 00996 00997 // generate all picked point properties? (OIV_PICK_GENERATE_ALL_PROPERTIES) 00998 static SbBool s_generateAllPickedProperties; 00999 01000 // 01001 static SoCamera::StereoMode s_stereoMode; 01002 01003 // Use faster intersection method (OIV_PICK_OPTIM) 01004 static SbBool s_useAlternateIntersection; 01005 01006 // Force the raypick action to take ray radius in account 01007 SbBool m_bEnableRadiusForTriangles; 01008 01009 // Store ray properties 01010 SbVec3f m_direction; 01011 SbVec3f m_start; 01012 01013 private: 01014 float getAdjustedVPRadius() const; 01015 01016 int m_pickedPropertiesMask; 01017 PickingMode m_pickingMode; 01018 01019 int m_VPRadiusState; // how VPRadius has been initialized 01020 01021 // data buffered for the lineWasSet case 01022 float m_fovy; 01023 float m_nearDistance; 01024 float m_farDistance; 01025 float m_aspectRatio; 01026 01027 // to force pick volume to be a cone (perspective pick) or a cylinder (orthogonal pick) 01028 SbBool m_conicPickVolume; 01029 01030 PickedPointListImpl *m_pickedPointListlImpl; 01031 01032 // Only computed by setPointSizeForPicking() 01033 // Only used in homogeneSpaceIntersection() 01034 // Store picking error depending of viewPort 01035 float m_pointPickingErrorX; 01036 float m_pointPickingErrorY; 01037 // Store extended pick trap depending of pointSize 01038 float m_projSpaceWidth; 01039 float m_projSpaceHeight; 01040 // Store pointSize for picking point 01041 float m_pointWidthForPicking; 01042 float m_pointHeightForPicking; 01043 }; 01044 01045 inline 01046 void SoRayPickAction::enableRadiusForTriangles(SbBool flag) 01047 { 01048 m_bEnableRadiusForTriangles = flag; 01049 } 01050 01051 inline 01052 SbBool SoRayPickAction::isRadiusEnableForTriangles() 01053 { 01054 return m_bEnableRadiusForTriangles; 01055 } 01056 #endif /* _SO_RAY_PICK_ACTION_ */ 01057 01058