diff --git a/ChangeLog.md b/ChangeLog.md index f932121fd..c3e02d3a2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,10 +6,15 @@ Changes since last release 10/01/2025 - Fixes + - #936 A particular defined positioning (of the C++-type CCPACSPositioning) was not available via Python bindings since the std::vector> is not exposed to swig. New getter functions have been implemented in CCPACSPositioning.h to make these elements accesible via index, similar to the implementation of for several other classes. For more information see https://github.com/RISCSoftware/cpacs_tigl_gen/issues/59. + - New API functions: + + - New function `::tiglComponentTransformPointToGlobal` to transform component-local coordinates into global coordinates (#1064) -- General changes: + - General changes: + - Update the C++ standard to C++17 (#1045). - Added the possibility to switch between two algorithms in the `CCSTCurveBuilder`. The default algorithm based on a Chebychev approximation results in a small number of control points, but introduces small discontinuities in the curvature. The new option is to use OCCT's `GeomAPI_PointsToBSpline`, which results in a C3 continuous B-Spline. diff --git a/TIGLViewer/src/TIGLScriptProxy.cpp b/TIGLViewer/src/TIGLScriptProxy.cpp index 1442917ee..1ee6ca292 100644 --- a/TIGLViewer/src/TIGLScriptProxy.cpp +++ b/TIGLViewer/src/TIGLScriptProxy.cpp @@ -517,6 +517,23 @@ QScriptValue TIGLScriptProxy::wingGetSegmentEtaXsi(int wingIdx, double px, doubl } +QScriptValue TIGLScriptProxy::componentTransformPointToGlobal(QString componentUID, double localX, double localY, double localZ) +{ + double gx, gy, gz; + + TiglReturnCode ret = ::tiglComponentTransformPointToGlobal(getTiglHandle(), componentUID.toStdString().c_str(), + localX, localY, localZ, + &gx, &gy, &gz); + + if (ret != TIGL_SUCCESS) { + return context()->throwError(tiglGetErrorString(ret)); + } + else { + QScriptValue Point3dCtor = engine()->globalObject().property("Point3d"); + return Point3dCtor.construct(QScriptValueList() << gx << gy << gz); + } +} + QScriptValue TIGLScriptProxy::getShape(QString uid) { diff --git a/TIGLViewer/src/TIGLScriptProxy.h b/TIGLViewer/src/TIGLScriptProxy.h index a2c79f532..82acfb36c 100644 --- a/TIGLViewer/src/TIGLScriptProxy.h +++ b/TIGLViewer/src/TIGLScriptProxy.h @@ -96,6 +96,12 @@ public slots: QScriptValue wingGetSegmentEtaXsi(int wingIdx, double px, double py, double pz); + // Component + QScriptValue componentTransformPointToGlobal(QString componentUID, + double localX, + double localY, + double localZ); + QString getErrorString(int errorCode); QScriptValue getShape(QString uid); diff --git a/src/api/tigl.cpp b/src/api/tigl.cpp index 1d43ac4c8..1e84e7b54 100644 --- a/src/api/tigl.cpp +++ b/src/api/tigl.cpp @@ -7529,3 +7529,65 @@ TiglReturnCode tiglConfigurationGetWithDuctCutouts(TiglCPACSConfigurationHandle return TIGL_ERROR; } } + +TiglReturnCode tiglComponentTransformPointToGlobal(TiglCPACSConfigurationHandle cpacsHandle, + const char *componentUID, + double localX, + double localY, + double localZ, + double *globalX, + double *globalY, + double *globalZ) +{ + if (!componentUID) { + LOG(ERROR) << "Null pointer for argument componentUID in tiglComponentTransformPointToGlobal"; + return TIGL_NULL_POINTER; + } + + if (!globalX) { + LOG(ERROR) << "Null pointer for argument globalX in tiglComponentTransformPointToGlobal"; + return TIGL_NULL_POINTER; + } + + + if (!globalY) { + LOG(ERROR) << "Null pointer for argument globalY in tiglComponentTransformPointToGlobal"; + return TIGL_NULL_POINTER; + } + + if (!globalZ) { + LOG(ERROR) << "Null pointer for argument globalZ in tiglComponentTransformPointToGlobal"; + return TIGL_NULL_POINTER; + } + + + try { + // try to resolve the object for the given uid and get the flag + tigl::CCPACSConfigurationManager& manager = tigl::CCPACSConfigurationManager::GetInstance(); + tigl::CCPACSConfiguration& config = manager.GetConfiguration(cpacsHandle); + + tigl::CTiglRelativelyPositionedComponent& component = config.GetUIDManager().GetRelativeComponent(componentUID); + + gp_Pnt pGlobal = component.GetTransformationMatrix().Transform(gp_Pnt(localX, localY, localZ)); + + *globalX = pGlobal.X(); + *globalY = pGlobal.Y(); + *globalZ = pGlobal.Z(); + + + return TIGL_SUCCESS; + + } + catch (const tigl::CTiglError& ex) { + LOG(ERROR) << ex.what(); + return ex.getCode(); + } + catch (std::exception& ex) { + LOG(ERROR) << ex.what(); + return TIGL_ERROR; + } + catch (...) { + LOG(ERROR) << "Caught an exception in tiglComponentTransformPointToGlobal!"; + return TIGL_ERROR; + } +} diff --git a/src/api/tigl.h b/src/api/tigl.h index 3441a9b95..6209c9b26 100644 --- a/src/api/tigl.h +++ b/src/api/tigl.h @@ -5028,6 +5028,29 @@ TIGL_COMMON_EXPORT TiglReturnCode tiglComponentGetType(TiglCPACSConfigurationHan const char* componentUID, TiglGeometricComponentType* typePtr); +/** + * @brief Transforms a local point in a component to the global coordinate system + * + * @param[in] cpacsHandle Handle for the CPACS configuration + * @param[in] componentUID The uid of the component for which the hash should be computed + * @param[in] localX X-Coordinate of the local point + * @param[in] localY Y-Coordinate of the local point + * @param[in] localZ Z-Coordinate of the local point + * @param[out] globalX X-Coordinate of the result in global coordinates + * @param[out] globalY Y-Coordinate of the result in global coordinates + * @param[out] globalZ Z-Coordinate of the result in global coordinates + * + * @return + * - TIGL_SUCCESS if no error occurred + * - TIGL_NOT_FOUND if no configuration was found for the given handle + * - TIGL_UID_ERROR if the uid is invalid or not a known geometric component + * + */ +TIGL_COMMON_EXPORT TiglReturnCode tiglComponentTransformPointToGlobal(TiglCPACSConfigurationHandle cpacsHandle, + const char* componentUID, + double localX, double localY, double localZ, + double* globalX, double* globalY, double* globalZ); + /** * @brief Translates an error code into a string * diff --git a/src/cpacs_other/CTiglUIDManager.cpp b/src/cpacs_other/CTiglUIDManager.cpp index 7199ac84c..3d58929a6 100644 --- a/src/cpacs_other/CTiglUIDManager.cpp +++ b/src/cpacs_other/CTiglUIDManager.cpp @@ -367,12 +367,12 @@ ITiglGeometricComponent& CTiglUIDManager::GetGeometricComponent(const std::strin CTiglRelativelyPositionedComponent& CTiglUIDManager::GetRelativeComponent(const std::string& uid) const { if (uid.empty()) { - throw CTiglError("Empty UID in CTiglUIDManager::GetGeometricComponent", TIGL_XML_ERROR); + throw CTiglError("Empty UID in CTiglUIDManager::GetGeometricComponent", TIGL_UID_ERROR); } const RelativeComponentContainerType::const_iterator it = relativeComponents.find(uid); if (it == relativeComponents.end()) { - throw CTiglError("UID '"+uid+"' not found in CTiglUIDManager::GetGeometricComponent", TIGL_XML_ERROR); + throw CTiglError("UID '"+uid+"' not found in CTiglUIDManager::GetGeometricComponent", TIGL_UID_ERROR); } return *it->second; diff --git a/src/cpacs_other/CTiglUIDManager.h b/src/cpacs_other/CTiglUIDManager.h index c399e3c4f..a9c3307b6 100644 --- a/src/cpacs_other/CTiglUIDManager.h +++ b/src/cpacs_other/CTiglUIDManager.h @@ -133,6 +133,9 @@ class CTiglUIDManager // Returns the parent component for a component or a null pointer if there is no parent. TIGL_EXPORT CTiglRelativelyPositionedComponent* GetParentGeometricComponent(const std::string& uid) const; + // Returns a pointer to the geometric component for the given unique id. + TIGL_EXPORT CTiglRelativelyPositionedComponent& GetRelativeComponent(const std::string& uid) const; + // Returns the container with all root components of the geometric topology that have children. TIGL_EXPORT const RelativeComponentContainerType& GetRootGeometricComponents() const; @@ -170,8 +173,6 @@ class CTiglUIDManager // Builds the parent child relationships and finds the root components void BuildTree(); - // Returns a pointer to the geometric component for the given unique id. - CTiglRelativelyPositionedComponent& GetRelativeComponent(const std::string& uid) const; private: typedef std::map CPACSObjectMap; diff --git a/tests/unittests/tiglTransformationBenchmark.cpp b/tests/unittests/tiglTransformationBenchmark.cpp index 05d99b690..9fa1895c6 100644 --- a/tests/unittests/tiglTransformationBenchmark.cpp +++ b/tests/unittests/tiglTransformationBenchmark.cpp @@ -88,3 +88,45 @@ TEST_F(TiglTransformationBenchmark, checkProfilePositions) EXPECT_NEAR(3.0, py, 1e-10); EXPECT_NEAR(0.0, pz, 1e-10); } + +TEST_F(TiglTransformationBenchmark, transformPointToGlobal) +{ + double px, py, pz; + + ASSERT_EQ(TIGL_SUCCESS, tiglComponentTransformPointToGlobal(tiglHandle, "Wing0", 0., 0., 0., &px, &py, &pz)); + EXPECT_NEAR(1.0, px, 1e-10); + EXPECT_NEAR(0.0, py, 1e-10); + EXPECT_NEAR(0.0, pz, 1e-10); + + ASSERT_EQ(TIGL_SUCCESS, tiglComponentTransformPointToGlobal(tiglHandle, "Wing1", 0., 0., 0., &px, &py, &pz)); + EXPECT_NEAR(1.0, px, 1e-10); + EXPECT_NEAR(1.0, py, 1e-10); + EXPECT_NEAR(0.0, pz, 1e-10); + + ASSERT_EQ(TIGL_SUCCESS, tiglComponentTransformPointToGlobal(tiglHandle, "Wing2", 0., 0., 0., &px, &py, &pz)); + EXPECT_NEAR(1.5, px, 1e-10); + EXPECT_NEAR(2.0, py, 1e-10); + EXPECT_NEAR(0.0, pz, 1e-10); + + ASSERT_EQ(TIGL_SUCCESS, tiglComponentTransformPointToGlobal(tiglHandle, "Wing3", 0., 0., 0., &px, &py, &pz)); + EXPECT_NEAR(1.5, px, 1e-10); + EXPECT_NEAR(3.0, py, 1e-10); + EXPECT_NEAR(0.0, pz, 1e-10); +} + +TEST_F(TiglTransformationBenchmark, transformPointToGlobalErrors) +{ + double px, py, pz; + + // Invalid handle + EXPECT_EQ(TIGL_NOT_FOUND, tiglComponentTransformPointToGlobal(-1, "Wing3", 0., 0., 0., &px, &py, &pz)); + + // Invalid UUID + EXPECT_EQ(TIGL_UID_ERROR, tiglComponentTransformPointToGlobal(tiglHandle, "UUID_NOT_EXIST", 0, 0., 0., &px, &py, &pz)); + + // nullptrs + EXPECT_EQ(TIGL_NULL_POINTER, tiglComponentTransformPointToGlobal(tiglHandle, nullptr, 0., 0., 0., &px, &py, &pz)); + EXPECT_EQ(TIGL_NULL_POINTER, tiglComponentTransformPointToGlobal(tiglHandle, "Wing3", 0., 0., 0., nullptr, &py, &pz)); + EXPECT_EQ(TIGL_NULL_POINTER, tiglComponentTransformPointToGlobal(tiglHandle, "Wing3", 0., 0., 0., &px, nullptr, &pz)); + EXPECT_EQ(TIGL_NULL_POINTER, tiglComponentTransformPointToGlobal(tiglHandle, "Wing3", 0., 0., 0., &px, &py, nullptr)); +}