// Copyright (c) 2025 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #ifndef _GeomGridEval_Plane_HeaderFile #define _GeomGridEval_Plane_HeaderFile #include "Geom_Plane.hxx" #include "GeomGridEval.hxx" #include "gp_Pln.hxx" #include "gp_Pnt2d.hxx" #include "NCollection_Array1.hxx" #include "NCollection_Array2.hxx" #include "Standard_DefineAlloc.hxx" //! @brief Efficient batch evaluator for plane grid points. //! //! Uses direct analytical formula: P(u,v) = Location + u * XDir + v * YDir //! This is a header-only implementation for maximum performance. //! //! Usage: //! @code //! GeomGridEval_Plane anEvaluator(myGeomPlane); //! NCollection_Array2 aGrid = anEvaluator.EvaluateGrid(myUParams, myVParams); //! @endcode class GeomGridEval_Plane { public: DEFINE_STANDARD_ALLOC //! Constructor with geometry. //! @param thePlane the plane geometry to evaluate GeomGridEval_Plane(const occ::handle& thePlane) : myGeom(thePlane) { } //! Non-copyable and non-movable. GeomGridEval_Plane(const GeomGridEval_Plane&) = delete; GeomGridEval_Plane& operator=(const GeomGridEval_Plane&) = delete; GeomGridEval_Plane(GeomGridEval_Plane&&) = delete; GeomGridEval_Plane& operator=(GeomGridEval_Plane&&) = delete; //! Returns the geometry handle. const occ::handle& Geometry() const { return myGeom; } //! Evaluate grid points at Cartesian product of U and V parameters. //! @param theUParams array of U parameter values //! @param theVParams array of V parameter values //! @return 2D array of evaluated points (1-based indexing) NCollection_Array2 EvaluateGrid(const NCollection_Array1& theUParams, const NCollection_Array1& theVParams) const { const int aNbU = theUParams.Length(); const int aNbV = theVParams.Length(); if (myGeom.IsNull() || aNbU == 0 || aNbV == 0) { return NCollection_Array2(); } NCollection_Array2 aResult(1, aNbU, 1, aNbV); // Extract plane data from geometry const gp_Pln& aPln = myGeom->Pln(); const gp_Pnt& aLoc = aPln.Location(); const gp_Dir& aXDir = aPln.Position().XDirection(); const gp_Dir& aYDir = aPln.Position().YDirection(); // Pre-extract coordinates for performance const double aLocX = aLoc.X(); const double aLocY = aLoc.Y(); const double aLocZ = aLoc.Z(); const double aXX = aXDir.X(); const double aXY = aXDir.Y(); const double aXZ = aXDir.Z(); const double aYX = aYDir.X(); const double aYY = aYDir.Y(); const double aYZ = aYDir.Z(); for (int iU = 1; iU <= aNbU; ++iU) { const double u = theUParams.Value(theUParams.Lower() + iU - 1); const double uX = aLocX + u * aXX; const double uY = aLocY + u * aXY; const double uZ = aLocZ + u * aXZ; for (int iV = 1; iV <= aNbV; ++iV) { const double v = theVParams.Value(theVParams.Lower() + iV - 1); aResult.SetValue(iU, iV, gp_Pnt(uX + v * aYX, uY + v * aYY, uZ + v * aYZ)); } } return aResult; } //! Evaluate grid points with first partial derivatives. //! @param theUParams array of U parameter values //! @param theVParams array of V parameter values //! @return 2D array of SurfD1 (1-based indexing) NCollection_Array2 EvaluateGridD1( const NCollection_Array1& theUParams, const NCollection_Array1& theVParams) const { const int aNbU = theUParams.Length(); const int aNbV = theVParams.Length(); if (myGeom.IsNull() || aNbU == 0 || aNbV == 0) { return NCollection_Array2(); } NCollection_Array2 aResult(1, aNbU, 1, aNbV); const gp_Pln& aPln = myGeom->Pln(); const gp_Pnt& aLoc = aPln.Location(); const gp_Dir& aXDir = aPln.Position().XDirection(); const gp_Dir& aYDir = aPln.Position().YDirection(); const double aLocX = aLoc.X(); const double aLocY = aLoc.Y(); const double aLocZ = aLoc.Z(); const double aXX = aXDir.X(); const double aXY = aXDir.Y(); const double aXZ = aXDir.Z(); const double aYX = aYDir.X(); const double aYY = aYDir.Y(); const double aYZ = aYDir.Z(); // D1U and D1V are constant for a plane const gp_Vec aD1U(aXX, aXY, aXZ); const gp_Vec aD1V(aYX, aYY, aYZ); for (int iU = 1; iU <= aNbU; ++iU) { const double u = theUParams.Value(theUParams.Lower() + iU - 1); const double uX = aLocX + u * aXX; const double uY = aLocY + u * aXY; const double uZ = aLocZ + u * aXZ; for (int iV = 1; iV <= aNbV; ++iV) { const double v = theVParams.Value(theVParams.Lower() + iV - 1); aResult.ChangeValue(iU, iV) = {gp_Pnt(uX + v * aYX, uY + v * aYY, uZ + v * aYZ), aD1U, aD1V}; } } return aResult; } //! Evaluate grid points with first and second partial derivatives. //! @param theUParams array of U parameter values //! @param theVParams array of V parameter values //! @return 2D array of SurfD2 (1-based indexing) NCollection_Array2 EvaluateGridD2( const NCollection_Array1& theUParams, const NCollection_Array1& theVParams) const { const int aNbU = theUParams.Length(); const int aNbV = theVParams.Length(); if (myGeom.IsNull() || aNbU == 0 || aNbV == 0) { return NCollection_Array2(); } NCollection_Array2 aResult(1, aNbU, 1, aNbV); const gp_Pln& aPln = myGeom->Pln(); const gp_Pnt& aLoc = aPln.Location(); const gp_Dir& aXDir = aPln.Position().XDirection(); const gp_Dir& aYDir = aPln.Position().YDirection(); const double aLocX = aLoc.X(); const double aLocY = aLoc.Y(); const double aLocZ = aLoc.Z(); const double aXX = aXDir.X(); const double aXY = aXDir.Y(); const double aXZ = aXDir.Z(); const double aYX = aYDir.X(); const double aYY = aYDir.Y(); const double aYZ = aYDir.Z(); const gp_Vec aD1U(aXX, aXY, aXZ); const gp_Vec aD1V(aYX, aYY, aYZ); const gp_Vec aZero(0, 0, 0); // All second derivatives are zero for a plane for (int iU = 1; iU <= aNbU; ++iU) { const double u = theUParams.Value(theUParams.Lower() + iU - 1); const double uX = aLocX + u * aXX; const double uY = aLocY + u * aXY; const double uZ = aLocZ + u * aXZ; for (int iV = 1; iV <= aNbV; ++iV) { const double v = theVParams.Value(theVParams.Lower() + iV - 1); aResult.ChangeValue( iU, iV) = {gp_Pnt(uX + v * aYX, uY + v * aYY, uZ + v * aYZ), aD1U, aD1V, aZero, aZero, aZero}; } } return aResult; } //! Evaluate grid points with derivatives up to third order. //! @param theUParams array of U parameter values //! @param theVParams array of V parameter values //! @return 2D array of SurfD3 (1-based indexing) NCollection_Array2 EvaluateGridD3( const NCollection_Array1& theUParams, const NCollection_Array1& theVParams) const { const int aNbU = theUParams.Length(); const int aNbV = theVParams.Length(); if (myGeom.IsNull() || aNbU == 0 || aNbV == 0) { return NCollection_Array2(); } NCollection_Array2 aResult(1, aNbU, 1, aNbV); const gp_Pln& aPln = myGeom->Pln(); const gp_Pnt& aLoc = aPln.Location(); const gp_Dir& aXDir = aPln.Position().XDirection(); const gp_Dir& aYDir = aPln.Position().YDirection(); const double aLocX = aLoc.X(); const double aLocY = aLoc.Y(); const double aLocZ = aLoc.Z(); const double aXX = aXDir.X(); const double aXY = aXDir.Y(); const double aXZ = aXDir.Z(); const double aYX = aYDir.X(); const double aYY = aYDir.Y(); const double aYZ = aYDir.Z(); const gp_Vec aD1U(aXX, aXY, aXZ); const gp_Vec aD1V(aYX, aYY, aYZ); const gp_Vec aZero(0, 0, 0); // All derivatives of order >= 2 are zero for a plane for (int iU = 1; iU <= aNbU; ++iU) { const double u = theUParams.Value(theUParams.Lower() + iU - 1); const double uX = aLocX + u * aXX; const double uY = aLocY + u * aXY; const double uZ = aLocZ + u * aXZ; for (int iV = 1; iV <= aNbV; ++iV) { const double v = theVParams.Value(theVParams.Lower() + iV - 1); aResult.ChangeValue(iU, iV) = {gp_Pnt(uX + v * aYX, uY + v * aYY, uZ + v * aYZ), aD1U, aD1V, aZero, aZero, aZero, aZero, aZero, aZero, aZero}; } } return aResult; } //! Evaluate partial derivative d^(NU+NV)S/(dU^NU dV^NV) at all grid points. //! @param theUParams array of U parameter values //! @param theVParams array of V parameter values //! @param theNU derivative order in U direction //! @param theNV derivative order in V direction //! @return 2D array of derivative vectors (1-based indexing) NCollection_Array2 EvaluateGridDN(const NCollection_Array1& theUParams, const NCollection_Array1& theVParams, int theNU, int theNV) const { const int aNbU = theUParams.Length(); const int aNbV = theVParams.Length(); if (myGeom.IsNull() || aNbU == 0 || aNbV == 0 || theNU < 0 || theNV < 0 || (theNU + theNV) < 1) { return NCollection_Array2(); } NCollection_Array2 aResult(1, aNbU, 1, aNbV); // For a plane, only D1U (1,0) and D1V (0,1) are non-zero gp_Vec aDerivative(0, 0, 0); if (theNU == 1 && theNV == 0) { // D1U = XDir const gp_Dir aXDir = myGeom->Pln().Position().XDirection(); aDerivative = gp_Vec(aXDir.X(), aXDir.Y(), aXDir.Z()); } else if (theNU == 0 && theNV == 1) { // D1V = YDir const gp_Dir aYDir = myGeom->Pln().Position().YDirection(); aDerivative = gp_Vec(aYDir.X(), aYDir.Y(), aYDir.Z()); } // All other derivatives are zero for (int iU = 1; iU <= aNbU; ++iU) { for (int iV = 1; iV <= aNbV; ++iV) { aResult.SetValue(iU, iV, aDerivative); } } return aResult; } private: occ::handle myGeom; }; #endif // _GeomGridEval_Plane_HeaderFile