From b5c012a3016a4bd7163570884012e33fab6323bf Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 6 Oct 2021 17:19:38 +0200 Subject: [PATCH] Mesh: implement sub-element handling --- src/Mod/Mesh/App/AppMesh.cpp | 1 + src/Mod/Mesh/App/Mesh.cpp | 51 ++++++++++++++++++++++++-------- src/Mod/Mesh/App/Mesh.h | 18 ++++++++++- src/Mod/Mesh/App/MeshPy.xml | 7 ++++- src/Mod/Mesh/App/MeshPyImp.cpp | 21 +++++++++++++ src/Mod/Mesh/App/MeshTestsApp.py | 41 +++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/Mod/Mesh/App/AppMesh.cpp b/src/Mod/Mesh/App/AppMesh.cpp index 7a6d759612..e179e90de6 100644 --- a/src/Mod/Mesh/App/AppMesh.cpp +++ b/src/Mod/Mesh/App/AppMesh.cpp @@ -76,6 +76,7 @@ PyMOD_INIT_FUNC(Mesh) Mesh::PropertyMeshKernel ::init(); Mesh::MeshObject ::init(); + Mesh::MeshSegment ::init(); Mesh::Feature ::init(); Mesh::FeatureCustom ::init(); diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index bc533ecaa5..f0427d8acd 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -62,6 +62,7 @@ using namespace Mesh; float MeshObject::Epsilon = 1.0e-5f; TYPESYSTEM_SOURCE(Mesh::MeshObject, Data::ComplexGeoData) +TYPESYSTEM_SOURCE(Mesh::MeshSegment, Data::Segment) MeshObject::MeshObject() { @@ -93,7 +94,7 @@ MeshObject::~MeshObject() std::vector MeshObject::getElementTypes() const { std::vector temp; - temp.push_back("Face"); // that's the mesh itself + temp.push_back("Mesh"); temp.push_back("Segment"); return temp; @@ -102,31 +103,47 @@ std::vector MeshObject::getElementTypes() const unsigned long MeshObject::countSubElements(const char* Type) const { std::string element(Type); - if (element == "Face") + if (element == "Mesh") return 1; else if (element == "Segment") return countSegments(); return 0; } -Data::Segment* MeshObject::getSubElement(const char* Type, unsigned long /*n*/) const +Data::Segment* MeshObject::getSubElement(const char* Type, unsigned long n) const { - //TODO std::string element(Type); - if (element == "Face") - return nullptr; - else if (element == "Segment") - return nullptr; + if (element == "Mesh" && n == 0) { + MeshSegment* segm = new MeshSegment(); + segm->mesh = new MeshObject(*this); + return segm; + } + else if (element == "Segment" && n < countSegments()) { + MeshSegment* segm = new MeshSegment(); + segm->mesh = new MeshObject(*this); + const Segment& faces = getSegment(n); + segm->segment.reset(new Segment(static_cast(segm->mesh), faces.getIndices(), false)); + return segm; + } + return nullptr; } -void MeshObject::getFacesFromSubelement(const Data::Segment* /*segm*/, - std::vector &Points, - std::vector &/*PointNormals*/, +void MeshObject::getFacesFromSubelement(const Data::Segment* element, + std::vector &points, + std::vector &/*pointNormals*/, std::vector &faces) const { - //TODO - this->getFaces(Points, faces, 0.0f); + if (element && element->getTypeId() == MeshSegment::getClassTypeId()) { + const MeshSegment* segm = static_cast(element); + if (segm->segment) { + Base::Reference submesh(segm->mesh->meshFromSegment(segm->segment->getIndices())); + submesh->getFaces(points, faces, 0.0f); + } + else { + segm->mesh->getFaces(points, faces, 0.0f); + } + } } void MeshObject::transformGeometry(const Base::Matrix4D &rclMat) @@ -161,6 +178,14 @@ Base::BoundBox3d MeshObject::getBoundBox()const return Bnd2; } +bool MeshObject::getCenterOfGravity(Base::Vector3d& center) const +{ + MeshCore::MeshAlgorithm alg(_kernel); + Base::Vector3f pnt = alg.GetGravityPoint(); + center = transformToOutside(pnt); + return true; +} + void MeshObject::copySegments(const MeshObject& mesh) { // After copying the segments the mesh pointers must be adjusted diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index 7b307b2e78..f6bfe262e3 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -60,6 +60,21 @@ class AbstractPolygonTriangulator; namespace Mesh { + +class MeshObject; +class MeshExport MeshSegment : public Data::Segment +{ + TYPESYSTEM_HEADER(); + +public: + virtual std::string getName() const { + return "MeshSegment"; + } + + Base::Reference mesh; + std::unique_ptr segment; +}; + /** * The MeshObject class provides an interface for the underlying MeshKernel class and * most of its algorithm on it. @@ -142,7 +157,8 @@ public: const MeshCore::MeshKernel& getKernel() const { return _kernel; } - virtual Base::BoundBox3d getBoundBox()const; + virtual Base::BoundBox3d getBoundBox() const; + virtual bool getCenterOfGravity(Base::Vector3d& center) const; /** @name I/O */ //@{ diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index b0f2992ad9..9cfacb9a84 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -184,7 +184,12 @@ lines = mesh.section(mesh2, [ConnectLines=True, MinDist=0.0001]) - + + + Add a list of facet indices that describes a segment to the mesh + + + Get the number of segments which may also be 0 diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index 7f368488b7..30b1277b3c 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -845,6 +845,27 @@ PyObject* MeshPy::getPointNormals(PyObject *args) } PY_CATCH; } +PyObject* MeshPy::addSegment(PyObject *args) +{ + PyObject* pylist; + if (!PyArg_ParseTuple(args, "O", &pylist)) + return nullptr; + + Py::Sequence list(pylist); + std::vector segment; + unsigned long numFacets = getMeshObjectPtr()->countFacets(); + segment.reserve(list.size()); + for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { + Py::Long value(*it); + Mesh::FacetIndex index = static_cast(value); + if (index < numFacets) + segment.push_back(index); + } + + getMeshObjectPtr()->addSegment(segment); + Py_Return; +} + PyObject* MeshPy::countSegments(PyObject *args) { if (!PyArg_ParseTuple(args, "")) diff --git a/src/Mod/Mesh/App/MeshTestsApp.py b/src/Mod/Mesh/App/MeshTestsApp.py index 9091e4d74e..cdad28c8e1 100644 --- a/src/Mod/Mesh/App/MeshTestsApp.py +++ b/src/Mod/Mesh/App/MeshTestsApp.py @@ -5,6 +5,7 @@ # LGPL import FreeCAD, os, sys, unittest, Mesh +from FreeCAD import Base import time, tempfile, math # http://python-kurs.eu/threads.php try: @@ -363,3 +364,43 @@ class NastranReader(unittest.TestCase): def tearDown(self): pass + +class MeshSubElement(unittest.TestCase): + def setUp(self): + self.mesh = Mesh.createBox(1.0, 1.0, 1.0) + + def testCenterOfGravity(self): + c = self.mesh.CenterOfGravity + self.assertEqual(c, Base.Vector(0.0, 0.0, 0.0)) + + def testSubElements(self): + types = self.mesh.getElementTypes() + self.assertIn("Mesh", types) + self.assertIn("Segment", types) + + def testCountSubElements(self): + self.assertEqual(self.mesh.countSubElements("Mesh"), 1) + self.assertEqual(self.mesh.countSubElements("Segment"), 0) + + def testFacesFromSubElement(self): + element = self.mesh.getFacesFromSubelement("Mesh", 0) + self.assertIsInstance(element, tuple) + self.assertEqual(len(element), 2) + self.assertEqual(len(element[0]), 8) + self.assertEqual(len(element[1]), 12) + + def testSegmentSubElement(self): + self.mesh.addSegment([0, 2, 4, 6, 8]) + self.assertEqual(self.mesh.countSegments(), 1) + self.assertEqual(self.mesh.countSubElements("Segment"), 1) + element = self.mesh.getFacesFromSubelement("Segment", 0) + self.assertIsInstance(element, tuple) + self.assertEqual(len(element), 2) + self.assertEqual(len(element[0]), 7) + self.assertEqual(len(element[1]), 5) + segment = self.mesh.meshFromSegment(self.mesh.getSegment(0)) + self.assertEqual(segment.CountPoints, 7) + self.assertEqual(segment.CountFacets, 5) + + def tearDown(self): + pass