0029729: Visualization, Graphic3d_ClipPlane - add support of clipping plane chains
[occt.git] / src / Graphic3d / Graphic3d_ClipPlane.hxx
index 11058e3..388ae39 100755 (executable)
@@ -19,6 +19,7 @@
 #include <Aspect_HatchStyle.hxx>
 #include <gp_Pln.hxx>
 #include <Graphic3d_AspectFillArea3d.hxx>
+#include <Graphic3d_BndBox3d.hxx>
 #include <Graphic3d_CappingFlags.hxx>
 #include <Graphic3d_TextureMap.hxx>
 #include <NCollection_Vec4.hxx>
 #include <Standard_TypeDef.hxx>
 #include <Standard_Transient.hxx>
 
-//! Container for properties describing graphic driver clipping planes.
-//! It is up to application to create instances of this class and specify its
-//! properties. The instances are passed into graphic driver or other facilities
-//! that implement clipping features (e.g. selection).
-//! Depending on usage context the class can be used to specify:
-//! - Global clipping applied over the whole scene.
-//! - Object-level clipping applied for each particular object.
+//! Clipping state.
+enum Graphic3d_ClipState
+{
+  Graphic3d_ClipState_Out, //!< fully outside (clipped) - should be discarded
+  Graphic3d_ClipState_In,  //!< fully inside  (NOT clipped) - should NOT be discarded
+  Graphic3d_ClipState_On,  //!< on (not clipped / partially clipped) - should NOT be discarded
+};
+
+//! Container for properties describing either a Clipping halfspace (single Clipping Plane),
+//! or a chain of Clipping Planes defining logical AND (conjunction) operation.
 //! The plane equation is specified in "world" coordinate system.
-//! Please note that the set of planes can define convex clipping volume.
-//! Be aware that number of clip planes supported by OpenGl is implementation
-//! dependent: at least 6 planes are available. Thus, take into account
-//! number of clipping planes passed for rendering: the object planes plus
-//! the view defined ones.
 class Graphic3d_ClipPlane : public Standard_Transient
 {
+  DEFINE_STANDARD_RTTIEXT(Graphic3d_ClipPlane,Standard_Transient)
 public:
 
-  typedef NCollection_Vec4<Standard_Real> Equation;
+  //! Type defining XYZW (ABCD) plane equation - left for compatibility with old code using Graphic3d_ClipPlane::Equation type.
+  typedef Graphic3d_Vec4d Equation;
+
+public:
 
   //! Default constructor.
   //! Initializes clip plane container with the following properties:
@@ -63,7 +66,7 @@ public:
   //! Construct clip plane for the passed equation.
   //! By default the plane is on, capping is turned off.
   //! @param theEquation [in] the plane equation.
-  Standard_EXPORT Graphic3d_ClipPlane (const Equation& theEquation);
+  Standard_EXPORT Graphic3d_ClipPlane (const Graphic3d_Vec4d& theEquation);
 
   //! Construct clip plane from the passed geometrical definition.
   //! By default the plane is on, capping is turned off.
@@ -78,14 +81,15 @@ public:
   //! Set 4-component equation vector for clipping plane.
   //! The equation is specified in "world" coordinate system.
   //! @param theEquation [in] the XYZW (or "ABCD") equation vector.
-  Standard_EXPORT void SetEquation (const Equation& theEquation);
+  Standard_EXPORT void SetEquation (const Graphic3d_Vec4d& theEquation);
 
   //! Get 4-component equation vector for clipping plane.
   //! @return clipping plane equation vector.
-  const Equation& GetEquation() const
-  {
-    return myEquation;
-  }
+  const Graphic3d_Vec4d& GetEquation() const { return myEquation; }
+
+  //! Get 4-component equation vector for clipping plane.
+  //! @return clipping plane equation vector.
+  const Graphic3d_Vec4d& ReversedEquation() const { return myEquationRev; }
 
   //! Check that the clipping plane is turned on.
   //! @return boolean flag indicating whether the plane is in on or off state.
@@ -123,6 +127,43 @@ public:
   //! @return new instance of clipping plane with same properties and attributes.
   Standard_EXPORT virtual Handle(Graphic3d_ClipPlane) Clone() const;
 
+public:
+
+  //! Return TRUE if this item defines a conjunction (logical AND) between a set of Planes.
+  //! Graphic3d_ClipPlane item defines either a Clipping halfspace (single Clipping Plane)
+  //! or a Clipping volume defined by a logical AND (conjunction) operation between a set of Planes defined as a Chain
+  //! (so that the volume cuts a space only in case if check fails for ALL Planes in the Chain).
+  //!
+  //! Note that Graphic3d_ClipPlane item cannot:
+  //! - Define a Chain with logical OR (disjunction) operation;
+  //!   this should be done through Graphic3d_SequenceOfHClipPlane.
+  //! - Define nested Chains.
+  //! - Disable Chain items; only entire Chain can be disabled (by disabled a head of Chain).
+  //!
+  //! The head of a Chain defines all visual properties of the Chain,
+  //! so that Graphic3d_ClipPlane of next items in a Chain merely defines only geometrical definition of the plane.
+  Standard_Boolean IsChain() const { return !myNextInChain.IsNull(); }
+
+  //! Return the previous plane in a Chain of Planes defining logical AND operation,
+  //! or NULL if there is no Chain or it is a first element in Chain.
+  //! When clipping is defined by a Chain of Planes,
+  //! it cuts a space only in case if check fails for all Planes in Chain.
+  Handle(Graphic3d_ClipPlane) ChainPreviousPlane() const { return myPrevInChain; }
+
+  //! Return the next plane in a Chain of Planes defining logical AND operation,
+  //! or NULL if there is no chain or it is a last element in chain.
+
+  const Handle(Graphic3d_ClipPlane)& ChainNextPlane() const { return myNextInChain; }
+
+  //! Return the number of chains in forward direction (including this item, so it is always >= 1).
+  //! For a head of Chain - returns the length of entire Chain.
+  Standard_Integer NbChainNextPlanes() const { return myChainLenFwd; }
+
+  //! Set the next plane in a Chain of Planes.
+  //! This operation also updates relationship between chains (Previous/Next items),
+  //! so that the previously set Next plane is cut off.
+  Standard_EXPORT void SetChainNextPlane (const Handle(Graphic3d_ClipPlane)& thePlane);
+
 public: // @name user-defined graphical attributes
 
   //! Set material for rendering capping surface.
@@ -209,6 +250,113 @@ public:
   //! Return true if some fill area aspect properties should be taken from object.
   bool ToUseObjectProperties() const { return myFlags != Graphic3d_CappingFlags_None; }
 
+public:
+
+  //! Check if the given point is outside / inside / on section.
+  Graphic3d_ClipState ProbePoint (const Graphic3d_Vec4d& thePoint) const
+  {
+    for (const Graphic3d_ClipPlane* aPlaneIter = this; aPlaneIter != NULL; aPlaneIter = aPlaneIter->myNextInChain.get())
+    {
+      Graphic3d_ClipState aPlnState = aPlaneIter->ProbePointHalfspace (thePoint);
+      if (aPlnState == Graphic3d_ClipState_On)
+      {
+        return Graphic3d_ClipState_On;
+      }
+      else if (aPlnState == Graphic3d_ClipState_Out
+            && aPlaneIter->myNextInChain.IsNull())
+      {
+        return Graphic3d_ClipState_Out;
+      }
+    }
+    return Graphic3d_ClipState_In;
+  }
+
+  //! Check if the given bounding box is fully outside / fully inside.
+  Graphic3d_ClipState ProbeBox (const Graphic3d_BndBox3d& theBox) const
+  {
+    Graphic3d_ClipState aPrevState = Graphic3d_ClipState_On;
+    for (const Graphic3d_ClipPlane* aPlaneIter = this; aPlaneIter != NULL; aPlaneIter = aPlaneIter->myNextInChain.get())
+    {
+      if (aPlaneIter->IsBoxFullOutHalfspace (theBox))
+      {
+        if (aPlaneIter->myNextInChain.IsNull())
+        {
+          return Graphic3d_ClipState_Out;
+        }
+        else if (aPrevState == Graphic3d_ClipState_In)
+        {
+          return Graphic3d_ClipState_On;
+        }
+        aPrevState = Graphic3d_ClipState_Out;
+      }
+      else if (aPlaneIter->IsBoxFullInHalfspace (theBox))
+      {
+        if (aPlaneIter->myNextInChain.IsNull())
+        {
+          return Graphic3d_ClipState_In;
+        }
+        else if (aPrevState == Graphic3d_ClipState_Out)
+        {
+          return Graphic3d_ClipState_On;
+        }
+        aPrevState = Graphic3d_ClipState_In;
+      }
+      else
+      {
+        return Graphic3d_ClipState_On;
+      }
+    }
+    return Graphic3d_ClipState_On;
+  }
+
+public:
+
+  //! Check if the given point is outside of the half-space (e.g. should be discarded by clipping plane).
+  Graphic3d_ClipState ProbePointHalfspace (const Graphic3d_Vec4d& thePoint) const
+  {
+    const Standard_Real aVal = myEquation.Dot (thePoint);
+    return aVal < 0.0
+         ? Graphic3d_ClipState_Out
+         : (aVal == 0.0
+          ? Graphic3d_ClipState_On
+          : Graphic3d_ClipState_In);
+  }
+
+  //! Check if the given bounding box is fully outside / fully inside the half-space.
+  Graphic3d_ClipState ProbeBoxHalfspace (const Graphic3d_BndBox3d& theBox) const
+  {
+    if (IsBoxFullOutHalfspace (theBox))
+    {
+      return Graphic3d_ClipState_Out;
+    }
+    return IsBoxFullInHalfspace (theBox)
+         ? Graphic3d_ClipState_In
+         : Graphic3d_ClipState_On;
+  }
+
+  //! Check if the given point is outside of the half-space (e.g. should be discarded by clipping plane).
+  bool IsPointOutHalfspace (const Graphic3d_Vec4d& thePoint) const { return ProbePointHalfspace (thePoint) == Graphic3d_ClipState_Out; }
+
+  //! Check if the given bounding box is fully outside of the half-space (e.g. should be discarded by clipping plane).
+  bool IsBoxFullOutHalfspace (const Graphic3d_BndBox3d& theBox) const
+  {
+    const Graphic3d_Vec4d aMaxPnt (myEquation.x() > 0.0 ? theBox.CornerMax().x() : theBox.CornerMin().x(),
+                                   myEquation.y() > 0.0 ? theBox.CornerMax().y() : theBox.CornerMin().y(),
+                                   myEquation.z() > 0.0 ? theBox.CornerMax().z() : theBox.CornerMin().z(),
+                                   1.0);
+    return IsPointOutHalfspace (aMaxPnt);
+  }
+
+  //! Check if the given bounding box is fully inside (or touches from inside) the half-space (e.g. NOT discarded by clipping plane).
+  bool IsBoxFullInHalfspace (const Graphic3d_BndBox3d& theBox) const
+  {
+    const Graphic3d_Vec4d aMinPnt (myEquation.x() > 0.0 ? theBox.CornerMin().x() : theBox.CornerMax().x(),
+                                   myEquation.y() > 0.0 ? theBox.CornerMin().y() : theBox.CornerMax().y(),
+                                   myEquation.z() > 0.0 ? theBox.CornerMin().z() : theBox.CornerMax().z(),
+                                   1.0);
+    return !IsPointOutHalfspace (aMinPnt);
+  }
+
 public: // @name modification counters
 
   //! @return modification counter for equation.
@@ -231,21 +379,33 @@ private:
   //! Set capping flag.
   Standard_EXPORT void setCappingFlag (bool theToUse, int theFlag);
 
+  //! Update chain length in backward direction.
+  void updateChainLen();
+
+  //! Update inversed plane definition from main plane.
+  void updateInversedPlane()
+  {
+    gp_Pln aPlane = myPlane;
+    aPlane.SetAxis (aPlane.Axis().Reversed());
+    aPlane.Coefficients (myEquationRev[0], myEquationRev[1], myEquationRev[2], myEquationRev[3]);
+  }
+
 private:
 
   Handle(Graphic3d_AspectFillArea3d) myAspect;    //!< fill area aspect
+  Handle(Graphic3d_ClipPlane)   myNextInChain;    //!< next     plane in a chain of planes defining logical AND operation
+  Graphic3d_ClipPlane*          myPrevInChain;    //!< previous plane in a chain of planes defining logical AND operation
   TCollection_AsciiString myId;                   //!< resource id
   gp_Pln                  myPlane;                //!< plane definition
-  Equation                myEquation;             //!< plane equation vector
+  Graphic3d_Vec4d         myEquation;             //!< plane equation vector
+  Graphic3d_Vec4d         myEquationRev;          //!< reversed plane equation
+  Standard_Integer        myChainLenFwd;          //!< chain length in forward direction (including this item)
   unsigned int            myFlags;                //!< capping flags
   unsigned int            myEquationMod;          //!< modification counter for equation
   unsigned int            myAspectMod;            //!< modification counter of aspect
   Standard_Boolean        myIsOn;                 //!< state of the clipping plane
   Standard_Boolean        myIsCapping;            //!< state of graphic driver capping
 
-public:
-
-  DEFINE_STANDARD_RTTIEXT(Graphic3d_ClipPlane,Standard_Transient)
 };
 
 DEFINE_STANDARD_HANDLE (Graphic3d_ClipPlane, Standard_Transient)