From 8447eeb051be3b8117763ca0a3c241a594629000 Mon Sep 17 00:00:00 2001 From: El Hadi Moussi Date: Tue, 13 Aug 2024 10:48:47 +0200 Subject: [PATCH] Add ShapeRecognMeshBuilder to build ShapeRecognMesh --- src/ShapeRecogn/CMakeLists.txt | 1 + src/ShapeRecogn/NodesBuilder.cxx | 25 ++ src/ShapeRecogn/NodesBuilder.hxx | 1 + src/ShapeRecogn/ShapeRecognMesh.cxx | 306 ++++++--------------- src/ShapeRecogn/ShapeRecognMesh.hxx | 81 +++--- src/ShapeRecogn/ShapeRecognMeshBuilder.cxx | 250 +++++++++++++++++ src/ShapeRecogn/ShapeRecognMeshBuilder.hxx | 85 ++++++ src/ShapeRecogn/Swig/ShapeRecogn.i | 2 + src/ShapeRecogn/Test/ConeTest.cxx | 4 +- src/ShapeRecogn/Test/ConeTest.hxx | 4 +- src/ShapeRecogn/Test/CylinderTest.cxx | 4 +- src/ShapeRecogn/Test/CylinderTest.hxx | 4 +- src/ShapeRecogn/Test/PlaneTest.cxx | 4 +- src/ShapeRecogn/Test/PlaneTest.hxx | 4 +- src/ShapeRecogn/Test/SphereTest.cxx | 4 +- src/ShapeRecogn/Test/SphereTest.hxx | 4 +- src/ShapeRecogn/Test/TorusTest.cxx | 4 +- src/ShapeRecogn/Test/TorusTest.hxx | 4 +- 18 files changed, 506 insertions(+), 285 deletions(-) create mode 100644 src/ShapeRecogn/ShapeRecognMeshBuilder.cxx create mode 100644 src/ShapeRecogn/ShapeRecognMeshBuilder.hxx diff --git a/src/ShapeRecogn/CMakeLists.txt b/src/ShapeRecogn/CMakeLists.txt index 9c4b506d8..1f63ae163 100644 --- a/src/ShapeRecogn/CMakeLists.txt +++ b/src/ShapeRecogn/CMakeLists.txt @@ -47,6 +47,7 @@ SET(shaperecogn_SOURCES NodesBuilder.cxx Areas.cxx AreasBuilder.cxx + ShapeRecognMeshBuilder.cxx ShapeRecognMesh.cxx ) diff --git a/src/ShapeRecogn/NodesBuilder.cxx b/src/ShapeRecogn/NodesBuilder.cxx index d8752f8f0..1302d3203 100644 --- a/src/ShapeRecogn/NodesBuilder.cxx +++ b/src/ShapeRecogn/NodesBuilder.cxx @@ -172,6 +172,31 @@ PrimitiveType NodesBuilder::findPrimitiveType(double k1, double k2, double kdiff return PrimitiveType::Unknown; } +PrimitiveType NodesBuilder::findPrimitiveType2(double k1, double k2, double kdiff0, double kis0) const +{ + double epsilon2 = pow(EPSILON_PRIMITIVE, 2); + double diffCurvature = fabs(k1 - k2); + double gaussianCurvature = k1 * k2; + double meanCurvature = (k1 + k2) / 2.0; + if (fabs(k1) < EPSILON_PRIMITIVE && + fabs(k2) < EPSILON_PRIMITIVE && + gaussianCurvature < epsilon2 && + meanCurvature < EPSILON_PRIMITIVE) + return PrimitiveType::Plane; + else if (diffCurvature < EPSILON_PRIMITIVE && k1 > EPSILON_PRIMITIVE && k2 > EPSILON_PRIMITIVE) + return PrimitiveType::Sphere; + else if ( + (fabs(k1) > EPSILON_PRIMITIVE && fabs(k2) < EPSILON_PRIMITIVE) || + (fabs(k1) < EPSILON_PRIMITIVE && fabs(k2) > EPSILON_PRIMITIVE)) + return PrimitiveType::Cylinder; + else if ( + std::signbit(k1) != std::signbit(k2) || + (fabs(k1) < EPSILON_PRIMITIVE && fabs(k2) < EPSILON_PRIMITIVE)) + return PrimitiveType::Torus; + else + return PrimitiveType::Unknown; +} + std::vector NodesBuilder::computeNormalCurvatureCoefficients( const std::vector &discreteCurvatures, const std::vector &tangents, diff --git a/src/ShapeRecogn/NodesBuilder.hxx b/src/ShapeRecogn/NodesBuilder.hxx index bfe137685..190118064 100644 --- a/src/ShapeRecogn/NodesBuilder.hxx +++ b/src/ShapeRecogn/NodesBuilder.hxx @@ -42,6 +42,7 @@ namespace MEDCoupling void computeCurvatures(double tol = 0.000001); void computeCurvatures(mcIdType nodeId, double tol); PrimitiveType findPrimitiveType(double k1, double k2, double kdiff0, double kis0) const; + PrimitiveType findPrimitiveType2(double k1, double k2, double kdiff0, double kis0) const; std::vector computeNormalCurvatureCoefficients( const std::vector &discreteCurvatures, const std::vector &tangents, diff --git a/src/ShapeRecogn/ShapeRecognMesh.cxx b/src/ShapeRecogn/ShapeRecognMesh.cxx index 3da7a0d11..4c8ee5f9f 100644 --- a/src/ShapeRecogn/ShapeRecognMesh.cxx +++ b/src/ShapeRecogn/ShapeRecognMesh.cxx @@ -1,293 +1,155 @@ #include "ShapeRecognMesh.hxx" -#include "NodesBuilder.hxx" -#include "AreasBuilder.hxx" #include "MEDLoader.hxx" -#include "MEDCouplingFieldDouble.hxx" using namespace MEDCoupling; -ShapeRecognMesh::ShapeRecognMesh(const std::string &fileName, int meshDimRelToMax) +ShapeRecognMesh::ShapeRecognMesh() + : nodeK1(0), nodeK2(0), nodePrimitiveType(0), + nodeNormal(0), areaId(0), areaPrimitiveType(0), + areaNormal(0), minorRadius(0), radius(0), + angle(0), center(0), axis(0), apex(0) { - mesh = ReadUMeshFromFile(fileName, meshDimRelToMax); - if (mesh->getMeshDimension() != 2) - throw INTERP_KERNEL::Exception("Expect a mesh with a dimension equal to 2"); - if (mesh->getNumberOfCellsWithType(INTERP_KERNEL::NORM_TRI3) != mesh->getNumberOfCells()) - throw INTERP_KERNEL::Exception("Expect a mesh containing exclusively triangular cells"); } - ShapeRecognMesh::~ShapeRecognMesh() { - if (areas != nullptr) - delete areas; - if (nodes != nullptr) - delete nodes; - mesh->decrRef(); + nodeK1->decrRef(); + nodeK2->decrRef(); + nodePrimitiveType->decrRef(); + nodeNormal->decrRef(); + areaId->decrRef(); + areaPrimitiveType->decrRef(); + areaNormal->decrRef(); + minorRadius->decrRef(); + radius->decrRef(); + angle->decrRef(); + center->decrRef(); + axis->decrRef(); + apex->decrRef(); +} + +std::size_t ShapeRecognMesh::getHeapMemorySizeWithoutChildren() const +{ + return 0; +} + +std::vector ShapeRecognMesh::getDirectChildrenWithNull() const +{ + std::vector ret; + ret.push_back(nodeK1); + ret.push_back(nodeK2); + ret.push_back(nodePrimitiveType); + ret.push_back(nodeNormal); + ret.push_back(areaId); + ret.push_back(areaPrimitiveType); + ret.push_back(areaNormal); + ret.push_back(minorRadius); + ret.push_back(radius); + ret.push_back(angle); + ret.push_back(center); + ret.push_back(axis); + ret.push_back(apex); + return ret; } -void ShapeRecognMesh::recognize() +ShapeRecognMesh *ShapeRecognMesh::New() { - mesh->incrRef(); - NodesBuilder nodesBuilder(mesh); - nodes = nodesBuilder.build(); - AreasBuilder areasBuilder(nodes); - areasBuilder.build(); - areas = areasBuilder.getAreas(); + return new ShapeRecognMesh; } -void ShapeRecognMesh::recognize(const std::string &outputFile, bool writeFromScratch) +void ShapeRecognMesh::save(const std::string &outputFile, bool writeFromScratch) const { - recognize(); // Nodes // - k1 - MEDCouplingFieldDouble *fieldNodeK1 = buildNodeK1(); - WriteField(outputFile, fieldNodeK1, writeFromScratch); - fieldNodeK1->decrRef(); + WriteField(outputFile, nodeK1, writeFromScratch); // - k2 - MEDCouplingFieldDouble *fieldNodeK2 = buildNodeK2(); - WriteField(outputFile, fieldNodeK2, false); - fieldNodeK2->decrRef(); + WriteField(outputFile, nodeK2, false); // - primitive types - MEDCouplingFieldDouble *fieldNodePrimitiveType = buildNodePrimitiveType(); - WriteField(outputFile, fieldNodePrimitiveType, false); - fieldNodePrimitiveType->decrRef(); + WriteField(outputFile, nodePrimitiveType, false); // - Normal - MEDCouplingFieldDouble *fieldNodeNormal = buildNodeNormal(); - WriteField(outputFile, fieldNodeNormal, false); - fieldNodeNormal->decrRef(); + WriteField(outputFile, nodeNormal, false); // Areas // - Area Id - MEDCouplingFieldDouble *fieldAreaId = buildAreaId(); - WriteField(outputFile, fieldAreaId, false); - fieldAreaId->decrRef(); + WriteField(outputFile, areaId, false); // - Primitive Types - MEDCouplingFieldDouble *fieldAreaPrimitiveType = buildAreaPrimitiveType(); - WriteField(outputFile, fieldAreaPrimitiveType, false); - fieldAreaPrimitiveType->decrRef(); + WriteField(outputFile, areaPrimitiveType, false); // - Normal - auto fieldAreaNormal = buildAreaNormal(); - WriteField(outputFile, fieldAreaNormal, false); - fieldAreaNormal->decrRef(); + WriteField(outputFile, areaNormal, false); // - Minor Radius - MEDCouplingFieldDouble *fieldAreaMinorRadius = buildMinorRadius(); - WriteField(outputFile, fieldAreaMinorRadius, false); - fieldAreaMinorRadius->decrRef(); + WriteField(outputFile, minorRadius, false); // - Radius - MEDCouplingFieldDouble *fieldAreaRadius = buildRadius(); - WriteField(outputFile, fieldAreaRadius, false); - fieldAreaRadius->decrRef(); + WriteField(outputFile, radius, false); // - Angle - MEDCouplingFieldDouble *fieldAreaAngle = buildAngle(); - WriteField(outputFile, fieldAreaAngle, false); - fieldAreaAngle->decrRef(); + WriteField(outputFile, angle, false); // - Center - MEDCouplingFieldDouble *fieldAreaCenter = buildCenter(); - WriteField(outputFile, fieldAreaCenter, false); - fieldAreaCenter->decrRef(); + WriteField(outputFile, center, false); // - Axis - MEDCouplingFieldDouble *fieldAreaAxis = buildAxis(); - WriteField(outputFile, fieldAreaAxis, false); - fieldAreaAxis->decrRef(); + WriteField(outputFile, axis, false); // - Apex - MEDCouplingFieldDouble *fieldAreaApex = buildApex(); - WriteField(outputFile, fieldAreaApex, false); - fieldAreaApex->decrRef(); -} - -const Nodes *ShapeRecognMesh::getNodes() const -{ - return nodes; -} - -const Areas *ShapeRecognMesh::getAreas() const -{ - return areas; -} - -MEDCouplingFieldDouble *ShapeRecognMesh::buildNodeK1() const -{ - if (nodes == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - return buildField("K1 (Node)", 1, nodes->getK1()); -} - -MEDCouplingFieldDouble *ShapeRecognMesh::buildNodeK2() const -{ - if (nodes == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - return buildField("K2 (Node)", 1, nodes->getK2()); -} - -MEDCouplingFieldDouble *ShapeRecognMesh::buildNodePrimitiveType() const -{ - if (nodes == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - return buildField("Primitive Type (Node)", 1, nodes->getPrimitiveType()); -} - -MEDCouplingFieldDouble *ShapeRecognMesh::buildNodeNormal() const -{ - if (nodes == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - return buildField("Normal (Node)", 3, nodes->getNormals()); -} - -MEDCouplingFieldDouble *ShapeRecognMesh::buildAreaId() const -{ - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - return buildField("Area Id", 1, areas->getAreaIdByNodes()); + WriteField(outputFile, apex, false); } -MEDCouplingFieldDouble *ShapeRecognMesh::buildAreaPrimitiveType() const +MEDCouplingFieldDouble *ShapeRecognMesh::getNodeK1() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double - { return (double)areas->getPrimitiveType(areaId); }); - return buildField("Primitive Type (Area)", 1, values); + return nodeK1; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildAreaNormal() const +MEDCouplingFieldDouble *ShapeRecognMesh::getNodeK2() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & - { return areas->getNormal(areaId); }); - return buildField("Normal (Area)", 3, values); + return nodeK2; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildMinorRadius() const +MEDCouplingFieldDouble *ShapeRecognMesh::getNodePrimitiveType() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double - { return areas->getMinorRadius(areaId); }); - return buildField("Minor Radius (Area)", 1, values); + return nodePrimitiveType; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildRadius() const +MEDCouplingFieldDouble *ShapeRecognMesh::getNodeNormal() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double - { return areas->getRadius(areaId); }); - return buildField("Radius (Area)", 1, values); + return nodeNormal; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildAngle() const +MEDCouplingFieldDouble *ShapeRecognMesh::getAreaId() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double - { return areas->getAngle(areaId); }); - return buildField("Angle (Area)", 1, values); + return areaId; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildCenter() const +MEDCouplingFieldDouble *ShapeRecognMesh::getAreaPrimitiveType() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & - { return areas->getCenter(areaId); }); - return buildField("Center (Area)", 3, values); + return areaPrimitiveType; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildAxis() const +MEDCouplingFieldDouble *ShapeRecognMesh::getAreaNormal() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & - { return areas->getAxis(areaId); }); - return buildField("Axis (Area)", 3, values); + return areaNormal; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildApex() const +MEDCouplingFieldDouble *ShapeRecognMesh::getMinorRadius() const { - if (areas == nullptr) - throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); - double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & - { return areas->getApex(areaId); }); - return buildField("Apex (Area)", 3, values); + return minorRadius; } -template -MEDCouplingFieldDouble *ShapeRecognMesh::buildField( - const std::string &name, - size_t nbOfCompo, - const std::vector &values) const +MEDCouplingFieldDouble *ShapeRecognMesh::getRadius() const { - DataArrayDouble *data = DataArrayDouble::New(); - data->setName(name); - data->alloc(nodes->getNbNodes(), nbOfCompo); - std::copy(values.begin(), values.end(), data->getPointer()); - data->declareAsNew(); - return buildField(name, nbOfCompo, data); + return radius; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildField( - const std::string &name, - size_t nbOfCompo, - double *values) const +MEDCouplingFieldDouble *ShapeRecognMesh::getAngle() const { - DataArrayDouble *data = DataArrayDouble::New(); - data->setName(name); - data->useArray( - values, - true, - MEDCoupling::DeallocType::CPP_DEALLOC, - nodes->getNbNodes(), - nbOfCompo); - return buildField(name, nbOfCompo, data); + return angle; } -MEDCouplingFieldDouble *ShapeRecognMesh::buildField( - const std::string &name, - size_t nbOfCompo, - DataArrayDouble *data) const +MEDCouplingFieldDouble *ShapeRecognMesh::getCenter() const { - MEDCouplingFieldDouble *field = MEDCouplingFieldDouble::New(ON_NODES); - field->setName(name); - field->setMesh(mesh); - if (nbOfCompo == 3) - { - data->setInfoOnComponent(0, "X"); - data->setInfoOnComponent(1, "Y"); - data->setInfoOnComponent(2, "Z"); - } - field->setArray(data); - data->decrRef(); - return field; + return center; } -double *ShapeRecognMesh::buildArea3DArray( - const std::array &(*areaFunc)(Areas *, mcIdType)) const +MEDCouplingFieldDouble *ShapeRecognMesh::getAxis() const { - double *values = new double[3 * nodes->getNbNodes()]; - const std::vector &areaIdByNodes = areas->getAreaIdByNodes(); - for (size_t nodeId = 0; nodeId < areaIdByNodes.size(); ++nodeId) - { - mcIdType areaId = areaIdByNodes[nodeId]; - if (areaId != -1) - { - const std::array &areaValues = areaFunc(areas, areaId); - values[3 * nodeId] = areaValues[0]; - values[3 * nodeId + 1] = areaValues[1]; - values[3 * nodeId + 2] = areaValues[2]; - } - } - return values; + return axis; } -double *ShapeRecognMesh::buildAreaArray(double (*areaFunc)(Areas *, mcIdType)) const +MEDCouplingFieldDouble *ShapeRecognMesh::getApex() const { - const std::vector &areaIdByNodes = areas->getAreaIdByNodes(); - double *values = new double[nodes->getNbNodes()]; - for (size_t nodeId = 0; nodeId < areaIdByNodes.size(); ++nodeId) - { - mcIdType areaId = areaIdByNodes[nodeId]; - if (areaId != -1) - values[nodeId] = areaFunc(areas, areaId); - } - return values; + return apex; } diff --git a/src/ShapeRecogn/ShapeRecognMesh.hxx b/src/ShapeRecogn/ShapeRecognMesh.hxx index 6defd49a4..02983e34a 100644 --- a/src/ShapeRecogn/ShapeRecognMesh.hxx +++ b/src/ShapeRecogn/ShapeRecognMesh.hxx @@ -24,61 +24,56 @@ #include "MEDCouplingUMesh.hxx" #include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingRefCountObject.hxx" namespace MEDCoupling { - class Nodes; - class Areas; - - class ShapeRecognMesh + class ShapeRecognMesh : public RefCountObject { - public: - ShapeRecognMesh(const std::string &fileName, int meshDimRelToMax = 0); - ~ShapeRecognMesh(); + friend class ShapeRecognMeshBuilder; - const Nodes *getNodes() const; - const Areas *getAreas() const; + public: + static ShapeRecognMesh *New(); + std::size_t getHeapMemorySizeWithoutChildren() const; + std::vector getDirectChildrenWithNull() const; - void recognize(); - void recognize(const std::string &outputFile, bool writeFromScratch = true); + void save(const std::string &outputFile, bool writeFromScratch = true) const; // Node properties - MEDCoupling::MEDCouplingFieldDouble *buildNodeK1() const; - MEDCoupling::MEDCouplingFieldDouble *buildNodeK2() const; - MEDCoupling::MEDCouplingFieldDouble *buildNodePrimitiveType() const; - MEDCoupling::MEDCouplingFieldDouble *buildNodeNormal() const; + MEDCoupling::MEDCouplingFieldDouble *getNodeK1() const; + MEDCoupling::MEDCouplingFieldDouble *getNodeK2() const; + MEDCoupling::MEDCouplingFieldDouble *getNodePrimitiveType() const; + MEDCoupling::MEDCouplingFieldDouble *getNodeNormal() const; // Area properties - MEDCoupling::MEDCouplingFieldDouble *buildAreaId() const; - MEDCoupling::MEDCouplingFieldDouble *buildAreaPrimitiveType() const; - MEDCoupling::MEDCouplingFieldDouble *buildAreaNormal() const; - MEDCoupling::MEDCouplingFieldDouble *buildMinorRadius() const; - MEDCoupling::MEDCouplingFieldDouble *buildRadius() const; - MEDCoupling::MEDCouplingFieldDouble *buildAngle() const; - MEDCoupling::MEDCouplingFieldDouble *buildCenter() const; - MEDCoupling::MEDCouplingFieldDouble *buildAxis() const; - MEDCoupling::MEDCouplingFieldDouble *buildApex() const; + MEDCoupling::MEDCouplingFieldDouble *getAreaId() const; + MEDCoupling::MEDCouplingFieldDouble *getAreaPrimitiveType() const; + MEDCoupling::MEDCouplingFieldDouble *getAreaNormal() const; + MEDCoupling::MEDCouplingFieldDouble *getMinorRadius() const; + MEDCoupling::MEDCouplingFieldDouble *getRadius() const; + MEDCoupling::MEDCouplingFieldDouble *getAngle() const; + MEDCoupling::MEDCouplingFieldDouble *getCenter() const; + MEDCoupling::MEDCouplingFieldDouble *getAxis() const; + MEDCoupling::MEDCouplingFieldDouble *getApex() const; - private: - template - MEDCouplingFieldDouble *buildField( - const std::string &name, - size_t nbOfCompo, - const std::vector &values) const; - MEDCouplingFieldDouble *buildField( - const std::string &name, - size_t nbOfCompo, - double *values) const; - MEDCouplingFieldDouble *buildField( - const std::string &name, - size_t nbOfCompo, - DataArrayDouble *values) const; - double *buildArea3DArray(const std::array &(*areaFunc)(Areas *, mcIdType)) const; - double *buildAreaArray(double (*areaFunc)(Areas *, mcIdType)) const; + protected: + ShapeRecognMesh(); + ~ShapeRecognMesh(); - const MEDCouplingUMesh *mesh; - Nodes *nodes = nullptr; - Areas *areas = nullptr; + private: + MEDCoupling::MEDCouplingFieldDouble *nodeK1; + MEDCoupling::MEDCouplingFieldDouble *nodeK2; + MEDCoupling::MEDCouplingFieldDouble *nodePrimitiveType; + MEDCoupling::MEDCouplingFieldDouble *nodeNormal; + MEDCoupling::MEDCouplingFieldDouble *areaId; + MEDCoupling::MEDCouplingFieldDouble *areaPrimitiveType; + MEDCoupling::MEDCouplingFieldDouble *areaNormal; + MEDCoupling::MEDCouplingFieldDouble *minorRadius; + MEDCoupling::MEDCouplingFieldDouble *radius; + MEDCoupling::MEDCouplingFieldDouble *angle; + MEDCoupling::MEDCouplingFieldDouble *center; + MEDCoupling::MEDCouplingFieldDouble *axis; + MEDCoupling::MEDCouplingFieldDouble *apex; }; }; diff --git a/src/ShapeRecogn/ShapeRecognMeshBuilder.cxx b/src/ShapeRecogn/ShapeRecognMeshBuilder.cxx new file mode 100644 index 000000000..f0a2b0581 --- /dev/null +++ b/src/ShapeRecogn/ShapeRecognMeshBuilder.cxx @@ -0,0 +1,250 @@ +#include "ShapeRecognMeshBuilder.hxx" + +#include "NodesBuilder.hxx" +#include "AreasBuilder.hxx" +#include "MEDLoader.hxx" +#include "ShapeRecognMesh.hxx" +#include "MEDCouplingFieldDouble.hxx" + +using namespace MEDCoupling; + +ShapeRecognMeshBuilder::ShapeRecognMeshBuilder(const std::string &fileName, int meshDimRelToMax) +{ + mesh = ReadUMeshFromFile(fileName, meshDimRelToMax); + if (mesh->getMeshDimension() != 2) + throw INTERP_KERNEL::Exception("Expect a mesh with a dimension equal to 2"); + if (mesh->getNumberOfCellsWithType(INTERP_KERNEL::NORM_TRI3) != mesh->getNumberOfCells()) + throw INTERP_KERNEL::Exception("Expect a mesh containing exclusively triangular cells"); +} + +ShapeRecognMeshBuilder::~ShapeRecognMeshBuilder() +{ + if (areas != nullptr) + delete areas; + if (nodes != nullptr) + delete nodes; + mesh->decrRef(); +} + +ShapeRecognMesh *ShapeRecognMeshBuilder::recognize() +{ + mesh->incrRef(); + NodesBuilder nodesBuilder(mesh); + nodes = nodesBuilder.build(); + AreasBuilder areasBuilder(nodes); + areasBuilder.build(); + areas = areasBuilder.getAreas(); + MCAuto recognMesh = ShapeRecognMesh::New(); + recognMesh->nodeK1 = buildNodeK1(); + recognMesh->nodeK2 = buildNodeK2(); + recognMesh->nodePrimitiveType = buildNodePrimitiveType(); + recognMesh->nodeNormal = buildNodeNormal(); + recognMesh->areaId = buildAreaId(); + recognMesh->areaPrimitiveType = buildAreaPrimitiveType(); + recognMesh->areaNormal = buildAreaNormal(); + recognMesh->minorRadius = buildMinorRadius(); + recognMesh->radius = buildRadius(); + recognMesh->angle = buildAngle(); + recognMesh->center = buildCenter(); + recognMesh->axis = buildAxis(); + recognMesh->apex = buildApex(); + return recognMesh.retn(); +} + +const Nodes *ShapeRecognMeshBuilder::getNodes() const +{ + return nodes; +} + +const Areas *ShapeRecognMeshBuilder::getAreas() const +{ + return areas; +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildNodeK1() const +{ + if (nodes == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + return buildField("K1 (Node)", 1, nodes->getK1()); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildNodeK2() const +{ + if (nodes == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + return buildField("K2 (Node)", 1, nodes->getK2()); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildNodePrimitiveType() const +{ + if (nodes == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + return buildField("Primitive Type (Node)", 1, nodes->getPrimitiveType()); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildNodeNormal() const +{ + if (nodes == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + return buildField("Normal (Node)", 3, nodes->getNormals()); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildAreaId() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + return buildField("Area Id", 1, areas->getAreaIdByNodes()); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildAreaPrimitiveType() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double + { return (double)areas->getPrimitiveType(areaId); }); + return buildField("Primitive Type (Area)", 1, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildAreaNormal() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & + { return areas->getNormal(areaId); }); + return buildField("Normal (Area)", 3, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildMinorRadius() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double + { return areas->getMinorRadius(areaId); }); + return buildField("Minor Radius (Area)", 1, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildRadius() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double + { return areas->getRadius(areaId); }); + return buildField("Radius (Area)", 1, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildAngle() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildAreaArray([](Areas *areas, mcIdType areaId) -> double + { return areas->getAngle(areaId); }); + return buildField("Angle (Area)", 1, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildCenter() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & + { return areas->getCenter(areaId); }); + return buildField("Center (Area)", 3, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildAxis() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & + { return areas->getAxis(areaId); }); + return buildField("Axis (Area)", 3, values); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildApex() const +{ + if (areas == nullptr) + throw INTERP_KERNEL::Exception("recognize must be called before building any fields"); + double *values = buildArea3DArray([](Areas *areas, mcIdType areaId) -> const std::array & + { return areas->getApex(areaId); }); + return buildField("Apex (Area)", 3, values); +} + +template +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildField( + const std::string &name, + size_t nbOfCompo, + const std::vector &values) const +{ + DataArrayDouble *data = DataArrayDouble::New(); + data->setName(name); + data->alloc(nodes->getNbNodes(), nbOfCompo); + std::copy(values.begin(), values.end(), data->getPointer()); + data->declareAsNew(); + return buildField(name, nbOfCompo, data); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildField( + const std::string &name, + size_t nbOfCompo, + double *values) const +{ + DataArrayDouble *data = DataArrayDouble::New(); + data->setName(name); + data->useArray( + values, + true, + MEDCoupling::DeallocType::CPP_DEALLOC, + nodes->getNbNodes(), + nbOfCompo); + return buildField(name, nbOfCompo, data); +} + +MEDCouplingFieldDouble *ShapeRecognMeshBuilder::buildField( + const std::string &name, + size_t nbOfCompo, + DataArrayDouble *data) const +{ + MEDCouplingFieldDouble *field = MEDCouplingFieldDouble::New(ON_NODES); + field->setName(name); + field->setMesh(mesh); + if (nbOfCompo == 3) + { + data->setInfoOnComponent(0, "X"); + data->setInfoOnComponent(1, "Y"); + data->setInfoOnComponent(2, "Z"); + } + field->setArray(data); + data->decrRef(); + return field; +} + +double *ShapeRecognMeshBuilder::buildArea3DArray( + const std::array &(*areaFunc)(Areas *, mcIdType)) const +{ + double *values = new double[3 * nodes->getNbNodes()]; + const std::vector &areaIdByNodes = areas->getAreaIdByNodes(); + for (size_t nodeId = 0; nodeId < areaIdByNodes.size(); ++nodeId) + { + mcIdType areaId = areaIdByNodes[nodeId]; + if (areaId != -1) + { + const std::array &areaValues = areaFunc(areas, areaId); + values[3 * nodeId] = areaValues[0]; + values[3 * nodeId + 1] = areaValues[1]; + values[3 * nodeId + 2] = areaValues[2]; + } + } + return values; +} + +double *ShapeRecognMeshBuilder::buildAreaArray(double (*areaFunc)(Areas *, mcIdType)) const +{ + const std::vector &areaIdByNodes = areas->getAreaIdByNodes(); + double *values = new double[nodes->getNbNodes()]; + for (size_t nodeId = 0; nodeId < areaIdByNodes.size(); ++nodeId) + { + mcIdType areaId = areaIdByNodes[nodeId]; + if (areaId != -1) + values[nodeId] = areaFunc(areas, areaId); + } + return values; +} diff --git a/src/ShapeRecogn/ShapeRecognMeshBuilder.hxx b/src/ShapeRecogn/ShapeRecognMeshBuilder.hxx new file mode 100644 index 000000000..eee7c1507 --- /dev/null +++ b/src/ShapeRecogn/ShapeRecognMeshBuilder.hxx @@ -0,0 +1,85 @@ +// Copyright (C) 2007-2024 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __SHAPERECOGNMESHBUILDER_HXX__ +#define __SHAPERECOGNMESHBUILDER_HXX__ + +#include + +#include "MEDCouplingUMesh.hxx" +#include "MEDCouplingFieldDouble.hxx" + +namespace MEDCoupling +{ + class Nodes; + class Areas; + class ShapeRecognMesh; + + class ShapeRecognMeshBuilder + { + public: + ShapeRecognMeshBuilder(const std::string &fileName, int meshDimRelToMax = 0); + ~ShapeRecognMeshBuilder(); + + const Nodes *getNodes() const; + const Areas *getAreas() const; + + ShapeRecognMesh *recognize(); + + private: + // Node properties + MEDCoupling::MEDCouplingFieldDouble *buildNodeK1() const; + MEDCoupling::MEDCouplingFieldDouble *buildNodeK2() const; + MEDCoupling::MEDCouplingFieldDouble *buildNodePrimitiveType() const; + MEDCoupling::MEDCouplingFieldDouble *buildNodeNormal() const; + + // Area properties + MEDCoupling::MEDCouplingFieldDouble *buildAreaId() const; + MEDCoupling::MEDCouplingFieldDouble *buildAreaPrimitiveType() const; + MEDCoupling::MEDCouplingFieldDouble *buildAreaNormal() const; + MEDCoupling::MEDCouplingFieldDouble *buildMinorRadius() const; + MEDCoupling::MEDCouplingFieldDouble *buildRadius() const; + MEDCoupling::MEDCouplingFieldDouble *buildAngle() const; + MEDCoupling::MEDCouplingFieldDouble *buildCenter() const; + MEDCoupling::MEDCouplingFieldDouble *buildAxis() const; + MEDCoupling::MEDCouplingFieldDouble *buildApex() const; + + template + MEDCouplingFieldDouble *buildField( + const std::string &name, + size_t nbOfCompo, + const std::vector &values) const; + MEDCouplingFieldDouble *buildField( + const std::string &name, + size_t nbOfCompo, + double *values) const; + MEDCouplingFieldDouble *buildField( + const std::string &name, + size_t nbOfCompo, + DataArrayDouble *values) const; + double *buildArea3DArray(const std::array &(*areaFunc)(Areas *, mcIdType)) const; + double *buildAreaArray(double (*areaFunc)(Areas *, mcIdType)) const; + + const MEDCouplingUMesh *mesh; + Nodes *nodes = nullptr; + Areas *areas = nullptr; + }; +}; + +#endif // __SHAPERECOGNMESHBUILDER_HXX__ diff --git a/src/ShapeRecogn/Swig/ShapeRecogn.i b/src/ShapeRecogn/Swig/ShapeRecogn.i index f97e5f9ea..58893b0c6 100644 --- a/src/ShapeRecogn/Swig/ShapeRecogn.i +++ b/src/ShapeRecogn/Swig/ShapeRecogn.i @@ -5,9 +5,11 @@ %{ #include "ShapeRecognMesh.hxx" +#include "ShapeRecognMeshBuilder.hxx" using namespace MEDCoupling; %} %ignore getAreas() const; %ignore getNodes() const; %include "ShapeRecognMesh.hxx" +%include "ShapeRecognMeshBuilder.hxx" diff --git a/src/ShapeRecogn/Test/ConeTest.cxx b/src/ShapeRecogn/Test/ConeTest.cxx index d22fae620..d25f4a792 100644 --- a/src/ShapeRecogn/Test/ConeTest.cxx +++ b/src/ShapeRecogn/Test/ConeTest.cxx @@ -1,6 +1,6 @@ #include "ConeTest.hxx" -#include "ShapeRecognMesh.hxx" +#include "ShapeRecognMeshBuilder.hxx" #include "Areas.hxx" #include "MathOps.hxx" #include "TestInterpKernelUtils.hxx" // getResourceFile() @@ -10,7 +10,7 @@ using namespace MEDCoupling; void ConeTest::setUp() { std::string file = INTERP_TEST::getResourceFile("ShapeRecognCone.med", 3); - srMesh = new ShapeRecognMesh(file); + srMesh = new ShapeRecognMeshBuilder(file); srMesh->recognize(); areas = srMesh->getAreas(); } diff --git a/src/ShapeRecogn/Test/ConeTest.hxx b/src/ShapeRecogn/Test/ConeTest.hxx index 283bfc845..20b1bef3f 100644 --- a/src/ShapeRecogn/Test/ConeTest.hxx +++ b/src/ShapeRecogn/Test/ConeTest.hxx @@ -25,7 +25,7 @@ namespace MEDCoupling { - class ShapeRecognMesh; + class ShapeRecognMeshBuilder; class Areas; class ConeTest : public CppUnit::TestFixture @@ -54,7 +54,7 @@ namespace MEDCoupling void testThirdArea(); private: - ShapeRecognMesh *srMesh = 0; + ShapeRecognMeshBuilder *srMesh = 0; const Areas *areas; }; }; diff --git a/src/ShapeRecogn/Test/CylinderTest.cxx b/src/ShapeRecogn/Test/CylinderTest.cxx index ee01878a0..47f6ac3d3 100644 --- a/src/ShapeRecogn/Test/CylinderTest.cxx +++ b/src/ShapeRecogn/Test/CylinderTest.cxx @@ -1,6 +1,6 @@ #include "CylinderTest.hxx" -#include "ShapeRecognMesh.hxx" +#include "ShapeRecognMeshBuilder.hxx" #include "Areas.hxx" #include "MathOps.hxx" #include "TestInterpKernelUtils.hxx" // getResourceFile() @@ -10,7 +10,7 @@ using namespace MEDCoupling; void CylinderTest::setUp() { std::string file = INTERP_TEST::getResourceFile("ShapeRecognCylinder.med", 3); - srMesh = new ShapeRecognMesh(file); + srMesh = new ShapeRecognMeshBuilder(file); srMesh->recognize(); areas = srMesh->getAreas(); } diff --git a/src/ShapeRecogn/Test/CylinderTest.hxx b/src/ShapeRecogn/Test/CylinderTest.hxx index 98f32ff54..a35ac1481 100644 --- a/src/ShapeRecogn/Test/CylinderTest.hxx +++ b/src/ShapeRecogn/Test/CylinderTest.hxx @@ -25,7 +25,7 @@ namespace MEDCoupling { - class ShapeRecognMesh; + class ShapeRecognMeshBuilder; class Areas; class CylinderTest : public CppUnit::TestFixture @@ -47,7 +47,7 @@ namespace MEDCoupling void testThirdArea(); private: - ShapeRecognMesh *srMesh = 0; + ShapeRecognMeshBuilder *srMesh = 0; const Areas *areas; }; }; diff --git a/src/ShapeRecogn/Test/PlaneTest.cxx b/src/ShapeRecogn/Test/PlaneTest.cxx index 3bd1b62a9..6f47f161c 100644 --- a/src/ShapeRecogn/Test/PlaneTest.cxx +++ b/src/ShapeRecogn/Test/PlaneTest.cxx @@ -1,6 +1,6 @@ #include "PlaneTest.hxx" -#include "ShapeRecognMesh.hxx" +#include "ShapeRecognMeshBuilder.hxx" #include "Areas.hxx" #include "MathOps.hxx" #include "TestInterpKernelUtils.hxx" // getResourceFile() @@ -10,7 +10,7 @@ using namespace MEDCoupling; void PlaneTest::setUp() { std::string file = INTERP_TEST::getResourceFile("ShapeRecognPlane.med", 3); - srMesh = new ShapeRecognMesh(file); + srMesh = new ShapeRecognMeshBuilder(file); srMesh->recognize(); areas = srMesh->getAreas(); } diff --git a/src/ShapeRecogn/Test/PlaneTest.hxx b/src/ShapeRecogn/Test/PlaneTest.hxx index b728d9c31..af6eb4755 100644 --- a/src/ShapeRecogn/Test/PlaneTest.hxx +++ b/src/ShapeRecogn/Test/PlaneTest.hxx @@ -25,7 +25,7 @@ namespace MEDCoupling { - class ShapeRecognMesh; + class ShapeRecognMeshBuilder; class Areas; class PlaneTest : public CppUnit::TestFixture @@ -41,7 +41,7 @@ namespace MEDCoupling void testArea(); private: - ShapeRecognMesh *srMesh = 0; + ShapeRecognMeshBuilder *srMesh = 0; const Areas *areas; }; }; diff --git a/src/ShapeRecogn/Test/SphereTest.cxx b/src/ShapeRecogn/Test/SphereTest.cxx index 0cf12728f..4d7f64ecb 100644 --- a/src/ShapeRecogn/Test/SphereTest.cxx +++ b/src/ShapeRecogn/Test/SphereTest.cxx @@ -1,6 +1,6 @@ #include "SphereTest.hxx" -#include "ShapeRecognMesh.hxx" +#include "ShapeRecognMeshBuilder.hxx" #include "Areas.hxx" #include "MathOps.hxx" #include "TestInterpKernelUtils.hxx" // getResourceFile() @@ -10,7 +10,7 @@ using namespace MEDCoupling; void SphereTest::setUp() { std::string file = INTERP_TEST::getResourceFile("ShapeRecognSphere.med", 3); - srMesh = new ShapeRecognMesh(file); + srMesh = new ShapeRecognMeshBuilder(file); srMesh->recognize(); areas = srMesh->getAreas(); } diff --git a/src/ShapeRecogn/Test/SphereTest.hxx b/src/ShapeRecogn/Test/SphereTest.hxx index abcfbfc8a..6500def00 100644 --- a/src/ShapeRecogn/Test/SphereTest.hxx +++ b/src/ShapeRecogn/Test/SphereTest.hxx @@ -25,7 +25,7 @@ namespace MEDCoupling { - class ShapeRecognMesh; + class ShapeRecognMeshBuilder; class Areas; class SphereTest : public CppUnit::TestFixture @@ -41,7 +41,7 @@ namespace MEDCoupling void testArea(); private: - ShapeRecognMesh *srMesh = 0; + ShapeRecognMeshBuilder *srMesh = 0; const Areas *areas; }; }; diff --git a/src/ShapeRecogn/Test/TorusTest.cxx b/src/ShapeRecogn/Test/TorusTest.cxx index 612913881..6e24d10ee 100644 --- a/src/ShapeRecogn/Test/TorusTest.cxx +++ b/src/ShapeRecogn/Test/TorusTest.cxx @@ -1,6 +1,6 @@ #include "TorusTest.hxx" -#include "ShapeRecognMesh.hxx" +#include "ShapeRecognMeshBuilder.hxx" #include "Areas.hxx" #include "MathOps.hxx" #include "TestInterpKernelUtils.hxx" // getResourceFile() @@ -10,7 +10,7 @@ using namespace MEDCoupling; void TorusTest::setUp() { std::string file = INTERP_TEST::getResourceFile("ShapeRecognTorus.med", 3); - srMesh = new ShapeRecognMesh(file); + srMesh = new ShapeRecognMeshBuilder(file); srMesh->recognize(); areas = srMesh->getAreas(); } diff --git a/src/ShapeRecogn/Test/TorusTest.hxx b/src/ShapeRecogn/Test/TorusTest.hxx index 4999f579b..07ae86d3a 100644 --- a/src/ShapeRecogn/Test/TorusTest.hxx +++ b/src/ShapeRecogn/Test/TorusTest.hxx @@ -25,7 +25,7 @@ namespace MEDCoupling { - class ShapeRecognMesh; + class ShapeRecognMeshBuilder; class Areas; class TorusTest : public CppUnit::TestFixture @@ -41,7 +41,7 @@ namespace MEDCoupling void testArea(); private: - ShapeRecognMesh *srMesh = 0; + ShapeRecognMeshBuilder *srMesh = 0; const Areas *areas; }; }; -- 2.39.2