Mesh: implement sub-element handling

This commit is contained in:
wmayer
2021-10-06 17:19:38 +02:00
parent ca65026246
commit b5c012a301
6 changed files with 124 additions and 15 deletions

View File

@@ -76,6 +76,7 @@ PyMOD_INIT_FUNC(Mesh)
Mesh::PropertyMeshKernel ::init();
Mesh::MeshObject ::init();
Mesh::MeshSegment ::init();
Mesh::Feature ::init();
Mesh::FeatureCustom ::init();

View File

@@ -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<const char*> MeshObject::getElementTypes() const
{
std::vector<const char*> 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<const char*> 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<MeshObject*>(segm->mesh), faces.getIndices(), false));
return segm;
}
return nullptr;
}
void MeshObject::getFacesFromSubelement(const Data::Segment* /*segm*/,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &/*PointNormals*/,
void MeshObject::getFacesFromSubelement(const Data::Segment* element,
std::vector<Base::Vector3d> &points,
std::vector<Base::Vector3d> &/*pointNormals*/,
std::vector<Facet> &faces) const
{
//TODO
this->getFaces(Points, faces, 0.0f);
if (element && element->getTypeId() == MeshSegment::getClassTypeId()) {
const MeshSegment* segm = static_cast<const MeshSegment*>(element);
if (segm->segment) {
Base::Reference<MeshObject> 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

View File

@@ -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<MeshObject> mesh;
std::unique_ptr<Mesh::Segment> 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 */
//@{

View File

@@ -184,7 +184,12 @@ lines = mesh.section(mesh2, [ConnectLines=True, MinDist=0.0001])
</UserDocu>
</Documentation>
</Methode>
<Methode Name="countSegments" Const="true">
<Methode Name="addSegment">
<Documentation>
<UserDocu>Add a list of facet indices that describes a segment to the mesh</UserDocu>
</Documentation>
</Methode>
<Methode Name="countSegments" Const="true">
<Documentation>
<UserDocu>Get the number of segments which may also be 0</UserDocu>
</Documentation>

View File

@@ -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<Mesh::FacetIndex> 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<unsigned long>(value);
if (index < numFacets)
segment.push_back(index);
}
getMeshObjectPtr()->addSegment(segment);
Py_Return;
}
PyObject* MeshPy::countSegments(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))

View File

@@ -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