Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-25 09:20:02

0001 // Created on: 2015-06-18
0002 // Created by: Anton POLETAEV
0003 // Copyright (c) 2015 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #ifndef _Graphic3d_TransformPers_HeaderFile
0017 #define _Graphic3d_TransformPers_HeaderFile
0018 
0019 #include <Aspect_TypeOfTriedronPosition.hxx>
0020 #include <BVH_Box.hxx>
0021 #include <Graphic3d_Camera.hxx>
0022 #include <Graphic3d_TransformUtils.hxx>
0023 #include <Graphic3d_TransModeFlags.hxx>
0024 #include <NCollection_Vec2.hxx>
0025 #include <Standard_TypeDef.hxx>
0026 #include <NCollection_Vec3.hxx>
0027 #include <NCollection_Vec4.hxx>
0028 #include <NCollection_Mat4.hxx>
0029 
0030 //! Transformation Persistence definition.
0031 //!
0032 //! Transformation Persistence defines a mutable Local Coordinate system which depends on camera
0033 //! position, so that visual appearance of the object becomes partially immutable while camera
0034 //! moves. Object visually preserves particular property such as size, placement, rotation or their
0035 //! combination.
0036 //!
0037 //! Graphic3d_TMF_ZoomPers, Graphic3d_TMF_RotatePers and Graphic3d_TMF_ZoomRotatePers define Local
0038 //! Coordinate system having origin in specified anchor point defined in World Coordinate system,
0039 //! while Graphic3d_TMF_TriedronPers and Graphic3d_TMF_2d define origin as 2D offset from screen
0040 //! corner in pixels.
0041 //!
0042 //! Graphic3d_TMF_2d, Graphic3d_TMF_TriedronPers and Graphic3d_TMF_ZoomPers defines Local Coordinate
0043 //! system where length units are pixels. Beware that Graphic3d_RenderingParams::ResolutionRatio()
0044 //! will be ignored! For other Persistence flags, normal (world) length units will apply.
0045 //!
0046 //! Graphic3d_TMF_AxialPers and Graphic3d_TMF_AxialZoomPers defines persistence in the axial scale,
0047 //! i.e., keeps the object visual coherence when the camera's axial scale is changed.
0048 //! Meant to be used by objects such as Manipulators and trihedrons.
0049 //! WARNING: Graphic3d_TMF_None is not permitted for defining instance of this class - NULL handle
0050 //! should be used for this purpose!
0051 class Graphic3d_TransformPers : public Standard_Transient
0052 {
0053   DEFINE_STANDARD_RTTIEXT(Graphic3d_TransformPers, Standard_Transient)
0054 public:
0055   //! Return true if specified mode is zoom/rotate transformation persistence.
0056   static bool IsZoomOrRotate(Graphic3d_TransModeFlags theMode)
0057   {
0058     return (theMode & (Graphic3d_TMF_ZoomPers | Graphic3d_TMF_RotatePers)) != 0;
0059   }
0060 
0061   //! Return true if specified mode is 2d/trihedron transformation persistence.
0062   static bool IsTrihedronOr2d(Graphic3d_TransModeFlags theMode)
0063   {
0064     return (theMode & (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_2d)) != 0;
0065   }
0066 
0067   //! Return true if specified mode is orthographic projection transformation persistence.
0068   static bool IsOrthoPers(Graphic3d_TransModeFlags theMode)
0069   {
0070     return (theMode & Graphic3d_TMF_OrthoPers) != 0;
0071   }
0072 
0073   //! Return true if specified mode is axial transformation persistence.
0074   static bool IsAxial(Graphic3d_TransModeFlags theMode)
0075   {
0076     return (theMode & Graphic3d_TMF_AxialScalePers) != 0;
0077   }
0078 
0079 public:
0080   //! Set transformation persistence.
0081   Graphic3d_TransformPers(const Graphic3d_TransModeFlags theMode)
0082       : myMode(theMode)
0083   {
0084     if (IsZoomOrRotate(theMode) || IsAxial(theMode))
0085     {
0086       SetPersistence(theMode, gp_Pnt(0.0, 0.0, 0.0));
0087     }
0088     else if (IsTrihedronOr2d(theMode))
0089     {
0090       SetPersistence(theMode, Aspect_TOTP_LEFT_LOWER, NCollection_Vec2<int>(0, 0));
0091     }
0092     else if (theMode == Graphic3d_TMF_CameraPers)
0093     {
0094       myMode = theMode;
0095     }
0096     else
0097     {
0098       throw Standard_ProgramError(
0099         "Graphic3d_TransformPers::SetPersistence(), wrong persistence mode.");
0100     }
0101   }
0102 
0103   //! Set Zoom/Rotate transformation persistence with an anchor 3D point.
0104   //! Anchor point defines the origin of Local Coordinate system within World Coordinate system.
0105   //! Throws an exception if persistence mode is not Graphic3d_TMF_ZoomPers,
0106   //! Graphic3d_TMF_ZoomRotatePers or Graphic3d_TMF_RotatePers.
0107   Graphic3d_TransformPers(const Graphic3d_TransModeFlags theMode, const gp_Pnt& thePnt)
0108       : myMode(Graphic3d_TMF_None)
0109   {
0110     SetPersistence(theMode, thePnt);
0111   }
0112 
0113   //! Set 2d/trihedron transformation persistence with a corner and 2D offset.
0114   //! 2D offset defines the origin of Local Coordinate system as projection of 2D point on screen
0115   //! plane into World Coordinate system. Throws an exception if persistence mode is not
0116   //! Graphic3d_TMF_TriedronPers or Graphic3d_TMF_2d. The offset is a positive displacement from the
0117   //! view corner in pixels.
0118   Graphic3d_TransformPers(const Graphic3d_TransModeFlags      theMode,
0119                           const Aspect_TypeOfTriedronPosition theCorner,
0120                           const NCollection_Vec2<int>& theOffset = NCollection_Vec2<int>(0, 0))
0121       : myMode(Graphic3d_TMF_None)
0122   {
0123     SetPersistence(theMode, theCorner, theOffset);
0124   }
0125 
0126   //! Return true for Graphic3d_TMF_ZoomPers, Graphic3d_TMF_ZoomRotatePers or
0127   //! Graphic3d_TMF_RotatePers modes.
0128   bool IsZoomOrRotate() const { return IsZoomOrRotate(myMode); }
0129 
0130   //! Return true for Graphic3d_TMF_TriedronPers and Graphic3d_TMF_2d modes.
0131   bool IsTrihedronOr2d() const { return IsTrihedronOr2d(myMode); }
0132 
0133   //! Return true for Graphic3d_TMF_OrthoPers mode.
0134   bool IsOrthoPers() const { return IsOrthoPers(myMode); }
0135 
0136   //! Return true for Graphic3d_TMF_AxialScalePers modes.
0137   bool IsAxial() const { return IsAxial(myMode); }
0138 
0139   //! Transformation persistence mode flags.
0140   Graphic3d_TransModeFlags Mode() const { return myMode; }
0141 
0142   //! Transformation persistence mode flags.
0143   Graphic3d_TransModeFlags Flags() const { return myMode; }
0144 
0145   //! Set Zoom/Rotate transformation persistence with an anchor 3D point.
0146   //! Throws an exception if persistence mode is not Graphic3d_TMF_ZoomPers,
0147   //! Graphic3d_TMF_ZoomRotatePers or Graphic3d_TMF_RotatePers.
0148   void SetPersistence(const Graphic3d_TransModeFlags theMode, const gp_Pnt& thePnt)
0149   {
0150     if (!IsZoomOrRotate(theMode) && !IsAxial(theMode))
0151     {
0152       throw Standard_ProgramError(
0153         "Graphic3d_TransformPers::SetPersistence(), wrong persistence mode.");
0154     }
0155 
0156     myMode                 = theMode;
0157     myParams.Params3d.PntX = thePnt.X();
0158     myParams.Params3d.PntY = thePnt.Y();
0159     myParams.Params3d.PntZ = thePnt.Z();
0160   }
0161 
0162   //! Set 2d/trihedron transformation persistence with a corner and 2D offset.
0163   //! Throws an exception if persistence mode is not Graphic3d_TMF_TriedronPers or Graphic3d_TMF_2d.
0164   void SetPersistence(const Graphic3d_TransModeFlags      theMode,
0165                       const Aspect_TypeOfTriedronPosition theCorner,
0166                       const NCollection_Vec2<int>&        theOffset)
0167   {
0168     if (!IsTrihedronOr2d(theMode))
0169     {
0170       throw Standard_ProgramError(
0171         "Graphic3d_TransformPers::SetPersistence(), wrong persistence mode.");
0172     }
0173 
0174     myMode                    = theMode;
0175     myParams.Params2d.Corner  = theCorner;
0176     myParams.Params2d.OffsetX = theOffset.x();
0177     myParams.Params2d.OffsetY = theOffset.y();
0178   }
0179 
0180 public:
0181   //! Return the anchor point for zoom/rotate transformation persistence.
0182   gp_Pnt AnchorPoint() const
0183   {
0184     if (!IsZoomOrRotate() && !IsAxial())
0185     {
0186       throw Standard_ProgramError(
0187         "Graphic3d_TransformPers::AnchorPoint(), wrong persistence mode.");
0188     }
0189 
0190     return gp_Pnt(myParams.Params3d.PntX, myParams.Params3d.PntY, myParams.Params3d.PntZ);
0191   }
0192 
0193   //! Set the anchor point for zoom/rotate transformation persistence.
0194   void SetAnchorPoint(const gp_Pnt& thePnt)
0195   {
0196     if (!IsZoomOrRotate() && !IsAxial())
0197     {
0198       throw Standard_ProgramError(
0199         "Graphic3d_TransformPers::SetAnchorPoint(), wrong persistence mode.");
0200     }
0201 
0202     myParams.Params3d.PntX = thePnt.X();
0203     myParams.Params3d.PntY = thePnt.Y();
0204     myParams.Params3d.PntZ = thePnt.Z();
0205   }
0206 
0207   //! Return the corner for 2d/trihedron transformation persistence.
0208   Aspect_TypeOfTriedronPosition Corner2d() const
0209   {
0210     if (!IsTrihedronOr2d())
0211     {
0212       throw Standard_ProgramError("Graphic3d_TransformPers::Corner2d(), wrong persistence mode.");
0213     }
0214 
0215     return myParams.Params2d.Corner;
0216   }
0217 
0218   //! Set the corner for 2d/trihedron transformation persistence.
0219   void SetCorner2d(const Aspect_TypeOfTriedronPosition thePos)
0220   {
0221     if (!IsTrihedronOr2d())
0222     {
0223       throw Standard_ProgramError(
0224         "Graphic3d_TransformPers::SetCorner2d(), wrong persistence mode.");
0225     }
0226 
0227     myParams.Params2d.Corner = thePos;
0228   }
0229 
0230   //! Return the offset from the corner for 2d/trihedron transformation persistence.
0231   NCollection_Vec2<int> Offset2d() const
0232   {
0233     if (!IsTrihedronOr2d())
0234     {
0235       throw Standard_ProgramError("Graphic3d_TransformPers::Offset2d(), wrong persistence mode.");
0236     }
0237 
0238     return NCollection_Vec2<int>(myParams.Params2d.OffsetX, myParams.Params2d.OffsetY);
0239   }
0240 
0241   //! Set the offset from the corner for 2d/trihedron transformation persistence.
0242   void SetOffset2d(const NCollection_Vec2<int>& theOffset)
0243   {
0244     if (!IsTrihedronOr2d())
0245     {
0246       throw Standard_ProgramError(
0247         "Graphic3d_TransformPers::SetOffset2d(), wrong persistence mode.");
0248     }
0249 
0250     myParams.Params2d.OffsetX = theOffset.x();
0251     myParams.Params2d.OffsetY = theOffset.y();
0252   }
0253 
0254 public:
0255   //! Find scale value based on the camera position and view dimensions
0256   //! @param[in] theCamera  camera definition
0257   //! @param[in] theViewportWidth  the width of viewport.
0258   //! @param[in] theViewportHeight  the height of viewport.
0259   virtual double persistentScale(const occ::handle<Graphic3d_Camera>& theCamera,
0260                                  const int                            theViewportWidth,
0261                                  const int                            theViewportHeight) const
0262   {
0263     (void)theViewportWidth;
0264     // use total size when tiling is active
0265     const int aVPSizeY =
0266       theCamera->Tile().IsValid() ? theCamera->Tile().TotalSize.y() : theViewportHeight;
0267 
0268     gp_Vec aVecToEye(theCamera->Direction());
0269     gp_Vec aVecToObj(
0270       theCamera->Eye(),
0271       gp_Pnt(myParams.Params3d.PntX, myParams.Params3d.PntY, myParams.Params3d.PntZ));
0272     const double aFocus   = aVecToObj.Dot(aVecToEye);
0273     const gp_XYZ aViewDim = theCamera->ViewDimensions(aFocus);
0274     return std::abs(aViewDim.Y()) / double(aVPSizeY);
0275   }
0276 
0277   //! Create orientation matrix based on camera and view dimensions.
0278   //! Default implementation locks rotation by nullifying rotation component.
0279   //! Camera and view dimensions are not used, by default.
0280   //! @param[in] theCamera  camera definition
0281   //! @param[in] theViewportWidth  the width of viewport
0282   //! @param[in] theViewportHeight  the height of viewport
0283   virtual NCollection_Mat3<double> persistentRotationMatrix(
0284     const occ::handle<Graphic3d_Camera>& theCamera,
0285     const int                            theViewportWidth,
0286     const int                            theViewportHeight) const
0287   {
0288     (void)theCamera;
0289     (void)theViewportWidth;
0290     (void)theViewportHeight;
0291 
0292     NCollection_Mat3<double> aRotMat;
0293     return aRotMat;
0294   }
0295 
0296   //! Apply transformation to bounding box of presentation.
0297   //! @param[in] theCamera  camera definition
0298   //! @param[in] theProjection  the projection transformation matrix.
0299   //! @param[in] theWorldView  the world view transformation matrix.
0300   //! @param[in] theViewportWidth  the width of viewport (for 2d persistence).
0301   //! @param[in] theViewportHeight  the height of viewport (for 2d persistence).
0302   //! @param theBoundingBox [in/out] the bounding box to transform.
0303   template <class T>
0304   void Apply(const occ::handle<Graphic3d_Camera>& theCamera,
0305              const NCollection_Mat4<T>&           theProjection,
0306              const NCollection_Mat4<T>&           theWorldView,
0307              const int                            theViewportWidth,
0308              const int                            theViewportHeight,
0309              Bnd_Box&                             theBoundingBox) const;
0310 
0311   //! Apply transformation to bounding box of presentation
0312   //! @param[in] theCamera  camera definition
0313   //! @param[in] theProjection  the projection transformation matrix.
0314   //! @param[in] theWorldView  the world view transformation matrix.
0315   //! @param[in] theViewportWidth  the width of viewport (for 2d persistence).
0316   //! @param[in] theViewportHeight  the height of viewport (for 2d persistence).
0317   //! @param theBoundingBox [in/out] the bounding box to transform.
0318   template <class T>
0319   void Apply(const occ::handle<Graphic3d_Camera>& theCamera,
0320              const NCollection_Mat4<T>&           theProjection,
0321              const NCollection_Mat4<T>&           theWorldView,
0322              const int                            theViewportWidth,
0323              const int                            theViewportHeight,
0324              BVH_Box<T, 3>&                       theBoundingBox) const;
0325 
0326   //! Compute transformation.
0327   //! Computed matrix can be applied to model world transformation
0328   //! of an object to implement effect of transformation persistence.
0329   //! @param[in] theCamera  camera definition
0330   //! @param[in] theProjection  the projection transformation matrix.
0331   //! @param[in] theWorldView  the world view transformation matrix.
0332   //! @param[in] theViewportWidth  the width of viewport (for 2d persistence).
0333   //! @param[in] theViewportHeight  the height of viewport (for 2d persistence).
0334   //! @param[in] theToApplyProjPers  if should apply projection persistence to matrix (for
0335   //! orthographic persistence).
0336   //! @return transformation matrix to be applied to model world transformation of an object.
0337   template <class T>
0338   NCollection_Mat4<T> Compute(const occ::handle<Graphic3d_Camera>& theCamera,
0339                               const NCollection_Mat4<T>&           theProjection,
0340                               const NCollection_Mat4<T>&           theWorldView,
0341                               const int                            theViewportWidth,
0342                               const int                            theViewportHeight,
0343                               const bool theToApplyProjPers = false) const;
0344 
0345   //! Apply transformation persistence on specified matrices.
0346   //! @param[in] theCamera  camera definition
0347   //! @param[in] theProjection  projection matrix to modify
0348   //! @param theWorldView [in/out]  world-view matrix to modify
0349   //! @param[in] theViewportWidth   viewport width
0350   //! @param[in] theViewportHeight  viewport height
0351   //! @param[in] theAnchor  if not NULL, overrides anchor point
0352   //! @param[in] theToApplyProjPers  if should apply projection persistence to matrix (for
0353   //! orthographic persistence).
0354   template <class T>
0355   void Apply(const occ::handle<Graphic3d_Camera>& theCamera,
0356              const NCollection_Mat4<T>&           theProjection,
0357              NCollection_Mat4<T>&                 theWorldView,
0358              const int                            theViewportWidth,
0359              const int                            theViewportHeight,
0360              const gp_Pnt*                        theAnchor          = nullptr,
0361              const bool                           theToApplyProjPers = true) const;
0362 
0363   //! Perform computations for applying transformation persistence on specified matrices.
0364   //! @param[in] theCamera  camera definition
0365   //! @param[in] theViewportWidth   viewport width
0366   //! @param[in] theViewportHeight  viewport height
0367   //! @param[in] theAnchor  if not NULL, overrides anchor point
0368   virtual NCollection_Mat4<double> ComputeApply(occ::handle<Graphic3d_Camera>& theCamera,
0369                                                 const int                      theViewportWidth,
0370                                                 const int                      theViewportHeight,
0371                                                 const gp_Pnt* theAnchor = nullptr) const
0372   {
0373     (void)theViewportWidth;
0374     occ::handle<Graphic3d_Camera> aProxyCamera = theCamera;
0375     if (IsOrthoPers() && !aProxyCamera->IsOrthographic())
0376     {
0377       // clang-format off
0378       aProxyCamera = new Graphic3d_Camera(*theCamera); // If OrthoPers, copy camera and set to orthographic projection
0379       // clang-format on
0380       aProxyCamera->SetProjectionType(Graphic3d_Camera::Projection_Orthographic);
0381     }
0382 
0383     NCollection_Mat4<double> aWorldView = aProxyCamera->OrientationMatrix();
0384 
0385     // use total size when tiling is active
0386     const int aVPSizeY =
0387       aProxyCamera->Tile().IsValid() ? aProxyCamera->Tile().TotalSize.y() : theViewportHeight;
0388 
0389     // a small enough jitter compensation offset
0390     // to avoid image dragging within single pixel in corner cases
0391     const double aJitterComp = 0.001;
0392     if ((myMode & Graphic3d_TMF_TriedronPers) != 0)
0393     {
0394       // reset Z focus for trihedron persistence
0395       const double aFocus = aProxyCamera->IsOrthographic()
0396                               ? aProxyCamera->Distance()
0397                               : (aProxyCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
0398                                    ? double(aProxyCamera->ZFocus() * aProxyCamera->Distance())
0399                                    : double(aProxyCamera->ZFocus()));
0400 
0401       // scale factor to pixels
0402       const gp_XYZ aViewDim = aProxyCamera->ViewDimensions(aFocus);
0403       const double aScale   = std::abs(aViewDim.Y()) / double(aVPSizeY);
0404       const gp_Dir aForward = aProxyCamera->Direction();
0405       gp_XYZ       aCenter =
0406         aProxyCamera->Center().XYZ() + aForward.XYZ() * (aFocus - aProxyCamera->Distance());
0407       if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
0408       {
0409         const double anOffsetX = (double(myParams.Params2d.OffsetX) + aJitterComp) * aScale;
0410         const gp_Dir aSide     = aForward.Crossed(aProxyCamera->Up());
0411         const gp_XYZ aDeltaX =
0412           aSide.XYZ() * (std::abs(aViewDim.X()) * aProxyCamera->NDC2dOffsetX() - anOffsetX);
0413         if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
0414         {
0415           aCenter += aDeltaX;
0416         }
0417         else
0418         {
0419           aCenter -= aDeltaX;
0420         }
0421       }
0422       if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
0423       {
0424         const double anOffsetY = (double(myParams.Params2d.OffsetY) + aJitterComp) * aScale;
0425         const gp_XYZ aDeltaY =
0426           aProxyCamera->Up().XYZ()
0427           * (std::abs(aViewDim.Y()) * aProxyCamera->NDC2dOffsetY() - anOffsetY);
0428         if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
0429         {
0430           aCenter += aDeltaY;
0431         }
0432         else
0433         {
0434           aCenter -= aDeltaY;
0435         }
0436       }
0437       Graphic3d_TransformUtils::Scale(aWorldView,
0438                                       1.0 / theCamera->AxialScale().X(),
0439                                       1.0 / theCamera->AxialScale().Y(),
0440                                       1.0 / theCamera->AxialScale().Z());
0441       Graphic3d_TransformUtils::Translate(aWorldView, aCenter.X(), aCenter.Y(), aCenter.Z());
0442       Graphic3d_TransformUtils::Scale(aWorldView, aScale, aScale, aScale);
0443     }
0444     else if ((myMode & Graphic3d_TMF_2d) != 0)
0445     {
0446       const double aFocus = aProxyCamera->IsOrthographic()
0447                               ? aProxyCamera->Distance()
0448                               : (aProxyCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
0449                                    ? double(aProxyCamera->ZFocus() * aProxyCamera->Distance())
0450                                    : double(aProxyCamera->ZFocus()));
0451 
0452       // scale factor to pixels
0453       const gp_XYZ aViewDim = aProxyCamera->ViewDimensions(aFocus);
0454       const double aScale   = std::abs(aViewDim.Y()) / double(aVPSizeY);
0455       gp_XYZ       aCenter(0.0, 0.0, -aFocus);
0456       if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
0457       {
0458         aCenter.SetX(-aViewDim.X() * aProxyCamera->NDC2dOffsetX()
0459                      + (double(myParams.Params2d.OffsetX) + aJitterComp) * aScale);
0460         if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
0461         {
0462           aCenter.SetX(-aCenter.X());
0463         }
0464       }
0465       if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
0466       {
0467         aCenter.SetY(-aViewDim.Y() * aProxyCamera->NDC2dOffsetY()
0468                      + (double(myParams.Params2d.OffsetY) + aJitterComp) * aScale);
0469         if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
0470         {
0471           aCenter.SetY(-aCenter.Y());
0472         }
0473       }
0474 
0475       aWorldView.InitIdentity();
0476       Graphic3d_TransformUtils::Translate(aWorldView, aCenter.X(), aCenter.Y(), aCenter.Z());
0477       Graphic3d_TransformUtils::Scale(aWorldView, aScale, aScale, aScale);
0478     }
0479     else if ((myMode & Graphic3d_TMF_CameraPers) != 0)
0480     {
0481       aWorldView.InitIdentity();
0482     }
0483     else
0484     {
0485       // Compute reference point for transformation in untransformed projection space.
0486       if (theAnchor != nullptr)
0487       {
0488         Graphic3d_TransformUtils::Translate(aWorldView,
0489                                             theAnchor->X(),
0490                                             theAnchor->Y(),
0491                                             theAnchor->Z());
0492       }
0493       else
0494       {
0495         Graphic3d_TransformUtils::Translate(aWorldView,
0496                                             myParams.Params3d.PntX,
0497                                             myParams.Params3d.PntY,
0498                                             myParams.Params3d.PntZ);
0499       }
0500 
0501       if ((myMode & Graphic3d_TMF_RotatePers) != 0)
0502       {
0503         NCollection_Mat3<double> aRotMat =
0504           persistentRotationMatrix(theCamera, theViewportWidth, theViewportHeight);
0505 
0506         aWorldView.SetValue(0, 0, aRotMat.GetColumn(0).x());
0507         aWorldView.SetValue(1, 0, aRotMat.GetColumn(0).y());
0508         aWorldView.SetValue(2, 0, aRotMat.GetColumn(0).z());
0509 
0510         aWorldView.SetValue(0, 1, aRotMat.GetColumn(1).x());
0511         aWorldView.SetValue(1, 1, aRotMat.GetColumn(1).y());
0512         aWorldView.SetValue(2, 1, aRotMat.GetColumn(1).z());
0513 
0514         aWorldView.SetValue(0, 2, aRotMat.GetColumn(2).x());
0515         aWorldView.SetValue(1, 2, aRotMat.GetColumn(2).y());
0516         aWorldView.SetValue(2, 2, aRotMat.GetColumn(2).z());
0517       }
0518       if (IsAxial())
0519       {
0520         Graphic3d_TransformUtils::Scale(aWorldView,
0521                                         1.0 / theCamera->AxialScale().X(),
0522                                         1.0 / theCamera->AxialScale().Y(),
0523                                         1.0 / theCamera->AxialScale().Z());
0524       }
0525       if ((myMode & Graphic3d_TMF_ZoomPers) != 0)
0526       {
0527         // lock zooming
0528         double aScale = persistentScale(aProxyCamera, theViewportWidth, theViewportHeight);
0529         Graphic3d_TransformUtils::Scale(aWorldView, aScale, aScale, aScale);
0530       }
0531     }
0532     theCamera = aProxyCamera;
0533     return aWorldView;
0534   }
0535 
0536   //! Dumps the content of me into the stream
0537   Standard_EXPORT virtual void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const;
0538 
0539 private:
0540   //! 3D anchor point for zoom/rotate transformation persistence.
0541   struct PersParams3d
0542   {
0543     double PntX;
0544     double PntY;
0545     double PntZ;
0546 
0547     //! Dumps the content of me into the stream
0548     Standard_EXPORT void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const;
0549   };
0550 
0551   //! 2d/trihedron transformation persistence parameters.
0552   struct PersParams2d
0553   {
0554     int                           OffsetX;
0555     int                           OffsetY;
0556     Aspect_TypeOfTriedronPosition Corner;
0557 
0558     //! Dumps the content of me into the stream
0559     Standard_EXPORT void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const;
0560   };
0561 
0562 private:
0563   Graphic3d_TransModeFlags myMode; //!< Transformation persistence mode flags
0564 
0565   union {
0566     PersParams3d Params3d;
0567     PersParams2d Params2d;
0568   } myParams;
0569 };
0570 
0571 // =======================================================================
0572 // function : Apply
0573 // purpose  : Apply transformation to world view and projection matrices.
0574 // =======================================================================
0575 template <class T>
0576 void Graphic3d_TransformPers::Apply(const occ::handle<Graphic3d_Camera>& theCamera,
0577                                     const NCollection_Mat4<T>&           theProjection,
0578                                     NCollection_Mat4<T>&                 theWorldView,
0579                                     const int                            theViewportWidth,
0580                                     const int                            theViewportHeight,
0581                                     const gp_Pnt*                        theAnchor,
0582                                     const bool                           theToApplyProjPers) const
0583 {
0584   (void)theViewportWidth;
0585   if (myMode == Graphic3d_TMF_None || theViewportHeight == 0)
0586   {
0587     return;
0588   }
0589 
0590   occ::handle<Graphic3d_Camera> aCamera = new Graphic3d_Camera(*theCamera);
0591   NCollection_Mat4<double>      aWorldView =
0592     ComputeApply(aCamera, theViewportWidth, theViewportHeight, theAnchor);
0593 
0594   if (!theCamera->IsOrthographic() && IsOrthoPers() && theToApplyProjPers)
0595   {
0596     NCollection_Mat4<double> aProjInv;
0597     aProjInv.ConvertFrom(theProjection.Inverted());
0598     aWorldView = (aProjInv * aCamera->ProjectionMatrix()) * aWorldView;
0599   }
0600 
0601   theWorldView.ConvertFrom(aWorldView);
0602 }
0603 
0604 // =======================================================================
0605 // function : Apply
0606 // purpose  : Apply transformation to bounding box of presentation.
0607 // =======================================================================
0608 template <class T>
0609 void Graphic3d_TransformPers::Apply(const occ::handle<Graphic3d_Camera>& theCamera,
0610                                     const NCollection_Mat4<T>&           theProjection,
0611                                     const NCollection_Mat4<T>&           theWorldView,
0612                                     const int                            theViewportWidth,
0613                                     const int                            theViewportHeight,
0614                                     Bnd_Box&                             theBoundingBox) const
0615 {
0616   if (theBoundingBox.IsVoid())
0617   {
0618     return;
0619   }
0620 
0621   T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
0622 
0623   theBoundingBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
0624 
0625   typename BVH_Box<T, 3>::BVH_VecNt aMin(aXmin, aYmin, aZmin);
0626   typename BVH_Box<T, 3>::BVH_VecNt aMax(aXmax, aYmax, aZmax);
0627   BVH_Box<T, 3>                     aBBox(aMin, aMax);
0628 
0629   Apply(theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox);
0630 
0631   theBoundingBox = Bnd_Box();
0632   theBoundingBox.Update(aBBox.CornerMin().x(),
0633                         aBBox.CornerMin().y(),
0634                         aBBox.CornerMin().z(),
0635                         aBBox.CornerMax().x(),
0636                         aBBox.CornerMax().y(),
0637                         aBBox.CornerMax().z());
0638 }
0639 
0640 // =======================================================================
0641 // function : Apply
0642 // purpose  : Apply transformation to bounding box of presentation.
0643 // =======================================================================
0644 template <class T>
0645 void Graphic3d_TransformPers::Apply(const occ::handle<Graphic3d_Camera>& theCamera,
0646                                     const NCollection_Mat4<T>&           theProjection,
0647                                     const NCollection_Mat4<T>&           theWorldView,
0648                                     const int                            theViewportWidth,
0649                                     const int                            theViewportHeight,
0650                                     BVH_Box<T, 3>&                       theBoundingBox) const
0651 {
0652   NCollection_Mat4<T> aTPers =
0653     Compute(theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, false);
0654   if (aTPers.IsIdentity() || !theBoundingBox.IsValid())
0655   {
0656     return;
0657   }
0658 
0659   const typename BVH_Box<T, 3>::BVH_VecNt& aMin = theBoundingBox.CornerMin();
0660   const typename BVH_Box<T, 3>::BVH_VecNt& aMax = theBoundingBox.CornerMax();
0661 
0662   typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8];
0663   anArrayOfCorners[0] =
0664     typename BVH_Box<T, 4>::BVH_VecNt(aMin.x(), aMin.y(), aMin.z(), static_cast<T>(1.0));
0665   anArrayOfCorners[1] =
0666     typename BVH_Box<T, 4>::BVH_VecNt(aMin.x(), aMin.y(), aMax.z(), static_cast<T>(1.0));
0667   anArrayOfCorners[2] =
0668     typename BVH_Box<T, 4>::BVH_VecNt(aMin.x(), aMax.y(), aMin.z(), static_cast<T>(1.0));
0669   anArrayOfCorners[3] =
0670     typename BVH_Box<T, 4>::BVH_VecNt(aMin.x(), aMax.y(), aMax.z(), static_cast<T>(1.0));
0671   anArrayOfCorners[4] =
0672     typename BVH_Box<T, 4>::BVH_VecNt(aMax.x(), aMin.y(), aMin.z(), static_cast<T>(1.0));
0673   anArrayOfCorners[5] =
0674     typename BVH_Box<T, 4>::BVH_VecNt(aMax.x(), aMin.y(), aMax.z(), static_cast<T>(1.0));
0675   anArrayOfCorners[6] =
0676     typename BVH_Box<T, 4>::BVH_VecNt(aMax.x(), aMax.y(), aMin.z(), static_cast<T>(1.0));
0677   anArrayOfCorners[7] =
0678     typename BVH_Box<T, 4>::BVH_VecNt(aMax.x(), aMax.y(), aMax.z(), static_cast<T>(1.0));
0679 
0680   theBoundingBox.Clear();
0681   for (int anIt = 0; anIt < 8; ++anIt)
0682   {
0683     typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt];
0684     aCorner                                    = aTPers * aCorner;
0685     aCorner                                    = aCorner / aCorner.w();
0686     theBoundingBox.Add(typename BVH_Box<T, 3>::BVH_VecNt(aCorner.x(), aCorner.y(), aCorner.z()));
0687   }
0688 }
0689 
0690 //=================================================================================================
0691 
0692 template <class T>
0693 NCollection_Mat4<T> Graphic3d_TransformPers::Compute(const occ::handle<Graphic3d_Camera>& theCamera,
0694                                                      const NCollection_Mat4<T>& theProjection,
0695                                                      const NCollection_Mat4<T>& theWorldView,
0696                                                      const int                  theViewportWidth,
0697                                                      const int                  theViewportHeight,
0698                                                      const bool theToApplyProjPers) const
0699 {
0700   if (myMode == Graphic3d_TMF_None)
0701   {
0702     return NCollection_Mat4<T>();
0703   }
0704 
0705   NCollection_Mat4<T> aWorldView(theWorldView);
0706   NCollection_Mat4<T> anUnviewMat;
0707   if (!theWorldView.Inverted(anUnviewMat))
0708   {
0709     return NCollection_Mat4<T>();
0710   }
0711 
0712   // compute only world-view matrix difference to avoid floating point instability
0713   // caused by projection matrix modifications outside of this algorithm (e.g. by Z-fit)
0714   Apply(theCamera,
0715         theProjection,
0716         aWorldView,
0717         theViewportWidth,
0718         theViewportHeight,
0719         nullptr,
0720         theToApplyProjPers);
0721   return anUnviewMat * aWorldView;
0722 }
0723 
0724 #endif // _Graphic3d_TransformPers_HeaderFile