Mesh: add function section() to Mesh class

This commit is contained in:
wmayer
2021-09-16 17:31:45 +02:00
parent 666f67f8d9
commit 3ab5dadd82
6 changed files with 350 additions and 1 deletions

View File

@@ -618,3 +618,232 @@ bool SetOperations::CollectFacetVisitor::AllowVisit (const MeshFacet& rclFacet,
return true;
}
// ----------------------------------------------------------------------------
bool MeshIntersection::hasIntersection() const
{
Base::BoundBox3f bbox1 = kernel1.GetBoundBox();
Base::BoundBox3f bbox2 = kernel2.GetBoundBox();
if (!(bbox1 && bbox2))
return false;
if (testIntersection(kernel1, kernel2))
return true;
return false;
}
void MeshIntersection::getIntersection(std::list<MeshIntersection::Tuple>& intsct) const
{
const MeshKernel& k1 = kernel1;
const MeshKernel& k2 = kernel2;
// Contains bounding boxes for every facet of 'k1'
std::vector<Base::BoundBox3f> boxes1;
MeshFacetIterator cMFI1(k1);
for (cMFI1.Begin(); cMFI1.More(); cMFI1.Next()) {
boxes1.push_back((*cMFI1).GetBoundBox());
}
// Contains bounding boxes for every facet of 'k2'
std::vector<Base::BoundBox3f> boxes2;
MeshFacetIterator cMFI2(k2);
for (cMFI2.Begin(); cMFI2.More(); cMFI2.Next()) {
boxes2.push_back((*cMFI2).GetBoundBox());
}
// Splits the mesh using grid for speeding up the calculation
MeshFacetGrid cMeshFacetGrid(k1);
const MeshFacetArray& rFaces2 = k2.GetFacets();
Base::SequencerLauncher seq("Checking for intersections...", rFaces2.size());
int index = 0;
MeshGeomFacet facet1, facet2;
Base::Vector3f pt1, pt2;
// Iterate over the facets of the 2nd mesh and find the grid elements of the 1st mesh
for (MeshFacetArray::_TConstIterator it = rFaces2.begin(); it != rFaces2.end(); ++it, index++) {
seq.next();
std::vector<FacetIndex> elements;
cMeshFacetGrid.Inside(boxes2[index], elements, true);
cMFI2.Set(index);
facet2 = *cMFI2;
for (std::vector<FacetIndex>::iterator jt = elements.begin(); jt != elements.end(); ++jt) {
if (boxes2[index] && boxes1[*jt]) {
cMFI1.Set(*jt);
facet1 = *cMFI1;
int ret = facet1.IntersectWithFacet(facet2, pt1, pt2);
if (ret == 2) {
Tuple d;
d.p1 = pt1;
d.p2 = pt2;
d.f1 = *jt;
d.f2 = index;
intsct.push_back(d);
}
}
}
}
}
bool MeshIntersection::testIntersection(const MeshKernel& k1,
const MeshKernel& k2)
{
// Contains bounding boxes for every facet of 'k1'
std::vector<Base::BoundBox3f> boxes1;
MeshFacetIterator cMFI1(k1);
for (cMFI1.Begin(); cMFI1.More(); cMFI1.Next()) {
boxes1.push_back((*cMFI1).GetBoundBox());
}
// Contains bounding boxes for every facet of 'k2'
std::vector<Base::BoundBox3f> boxes2;
MeshFacetIterator cMFI2(k2);
for (cMFI2.Begin(); cMFI2.More(); cMFI2.Next()) {
boxes2.push_back((*cMFI2).GetBoundBox());
}
// Splits the mesh using grid for speeding up the calculation
MeshFacetGrid cMeshFacetGrid(k1);
const MeshFacetArray& rFaces2 = k2.GetFacets();
Base::SequencerLauncher seq("Checking for intersections...", rFaces2.size());
int index = 0;
MeshGeomFacet facet1, facet2;
Base::Vector3f pt1, pt2;
// Iterate over the facets of the 2nd mesh and find the grid elements of the 1st mesh
for (MeshFacetArray::_TConstIterator it = rFaces2.begin(); it != rFaces2.end(); ++it, index++) {
seq.next();
std::vector<FacetIndex> elements;
cMeshFacetGrid.Inside(boxes2[index], elements, true);
cMFI2.Set(index);
facet2 = *cMFI2;
for (std::vector<FacetIndex>::iterator jt = elements.begin(); jt != elements.end(); ++jt) {
if (boxes2[index] && boxes1[*jt]) {
cMFI1.Set(*jt);
facet1 = *cMFI1;
int ret = facet1.IntersectWithFacet(facet2, pt1, pt2);
if (ret == 2) {
// abort after the first detected self-intersection
return true;
}
}
}
}
return false;
}
void MeshIntersection::connectLines(bool onlyclosed, const std::list<MeshIntersection::Tuple>& rdata,
std::list< std::list<MeshIntersection::Triple> >& lines)
{
float fMinEps = minDistance * minDistance;
std::list<Tuple> data = rdata;
while (!data.empty()) {
std::list<Tuple>::iterator pF;
std::list<Triple> newPoly;
// add first line and delete from the list
Triple front, back;
front.f1 = data.begin()->f1;
front.f2 = data.begin()->f2;
front.p = data.begin()->p1; // current start point of the polyline
back.f1 = data.begin()->f1;
back.f2 = data.begin()->f2;
back.p = data.begin()->p2; // current end point of the polyline
newPoly.push_back(front);
newPoly.push_back(back);
data.erase(data.begin());
// search for the next line on the begin/end of the polyline and add it
std::list<Tuple>::iterator pFront, pEnd;
bool bFoundLine;
do {
float fFrontMin = fMinEps, fEndMin = fMinEps;
bool bFrontFirst=false, bEndFirst=false;
pFront = data.end();
pEnd = data.end();
bFoundLine = false;
for (pF = data.begin(); pF != data.end(); ++pF) {
if (Base::DistanceP2(front.p, pF->p1) < fFrontMin) {
fFrontMin = Base::DistanceP2(front.p, pF->p1);
pFront = pF;
bFrontFirst = true;
}
else if (Base::DistanceP2(back.p, pF->p1) < fEndMin) {
fEndMin = Base::DistanceP2(back.p, pF->p1);
pEnd = pF;
bEndFirst = true;
}
else if (Base::DistanceP2(front.p, pF->p2) < fFrontMin) {
fFrontMin = Base::DistanceP2(front.p, pF->p2);
pFront = pF;
bFrontFirst = false;
}
else if (Base::DistanceP2(back.p, pF->p2) < fEndMin) {
fEndMin = Base::DistanceP2(back.p, pF->p2);
pEnd = pF;
bEndFirst = false;
}
if (fFrontMin == 0.0f || fEndMin == 0.0f) {
break;
}
}
if (pFront != data.end()) {
bFoundLine = true;
if (bFrontFirst) {
front.f1 = pFront->f1;
front.f2 = pFront->f2;
front.p = pFront->p2;
newPoly.push_front(front);
}
else {
front.f1 = pFront->f1;
front.f2 = pFront->f2;
front.p = pFront->p1;
newPoly.push_front(front);
}
data.erase(pFront);
}
if (pEnd != data.end()) {
bFoundLine = true;
if (bEndFirst) {
back.f1 = pEnd->f1;
back.f2 = pEnd->f2;
back.p = pEnd->p2;
newPoly.push_back(back);
}
else {
back.f1 = pEnd->f1;
back.f2 = pEnd->f2;
back.p = pEnd->p1;
newPoly.push_back(back);
}
data.erase(pEnd);
}
}
while (bFoundLine);
if (onlyclosed) {
if (newPoly.size() > 2 && Base::DistanceP2(newPoly.front().p, newPoly.back().p) < fMinEps)
lines.push_back(newPoly);
}
else {
lines.push_back(newPoly);
}
}
}

View File

@@ -184,6 +184,54 @@ private:
};
/*!
Determine the intersections between two meshes.
*/
class MeshExport MeshIntersection
{
public:
struct Tuple {
Base::Vector3f p1, p2;
FacetIndex f1, f2;
};
struct Triple {
Base::Vector3f p;
FacetIndex f1, f2;
};
struct Pair {
Base::Vector3f p;
FacetIndex f;
};
MeshIntersection(const MeshKernel& m1,
const MeshKernel& m2,
float dist)
: kernel1(m1)
, kernel2(m2)
, minDistance(dist)
{
}
~MeshIntersection()
{
}
bool hasIntersection() const;
void getIntersection(std::list<Tuple>&) const;
/*!
From an unsorted list of intersection points make a list of sorted intersection points. If parameter \a onlyclosed
is set to true then only closed intersection curves are taken and all other curves are filtered out.
*/
void connectLines(bool onlyclosed, const std::list<Tuple>&, std::list< std::list<Triple> >&);
private:
static bool testIntersection(const MeshKernel& k1, const MeshKernel& k2);
private:
const MeshKernel& kernel1;
const MeshKernel& kernel2;
float minDistance;
};
} // namespace MeshCore

View File

@@ -1176,6 +1176,44 @@ MeshObject* MeshObject::outer(const MeshObject& mesh) const
return new MeshObject(result);
}
std::vector< std::vector<Base::Vector3f> >
MeshObject::section(const MeshObject& mesh, bool connectLines, float fMinDist) const
{
MeshCore::MeshKernel kernel1(this->_kernel);
kernel1.Transform(this->_Mtrx);
MeshCore::MeshKernel kernel2(mesh._kernel);
kernel2.Transform(mesh._Mtrx);
std::vector< std::vector<Base::Vector3f> > lines;
MeshCore::MeshIntersection sec(kernel1, kernel2, fMinDist);
std::list<MeshCore::MeshIntersection::Tuple> tuple;
sec.getIntersection(tuple);
if (!connectLines) {
for (const auto& it : tuple) {
std::vector<Base::Vector3f> curve;
curve.push_back(it.p1);
curve.push_back(it.p2);
lines.push_back(curve);
}
}
else {
std::list< std::list<MeshCore::MeshIntersection::Triple> > triple;
sec.connectLines(false, tuple, triple);
for (const auto& it : triple) {
std::vector<Base::Vector3f> curve;
curve.reserve(it.size());
for (const auto& jt : it)
curve.push_back(jt.p);
lines.push_back(curve);
}
}
return lines;
}
void MeshObject::refine()
{
unsigned long cnt = _kernel.CountFacets();

View File

@@ -252,6 +252,7 @@ public:
MeshObject* subtract(const MeshObject&) const;
MeshObject* inner(const MeshObject&) const;
MeshObject* outer(const MeshObject&) const;
std::vector< std::vector<Base::Vector3f> > section(const MeshObject&, bool connectLines, float fMinDist) const;
//@}
/** @name Topological operations */

View File

@@ -91,7 +91,14 @@ mesh.write(Stream=file,Format='STL',[Name='Object name',Material=colors])</UserD
<UserDocu>Get the part outside the intersection</UserDocu>
</Documentation>
</Methode>
<Methode Name="coarsen">
<Methode Name="section" Const="true" Keyword="true">
<Documentation>
<UserDocu>Get the section curves of this and the given mesh object.
lines = mesh.section(mesh2, [ConnectLines=True, MinDist=0.0001])
</UserDocu>
</Documentation>
</Methode>
<Methode Name="coarsen">
<Documentation>
<UserDocu>Coarse the mesh</UserDocu>
</Documentation>

View File

@@ -514,6 +514,32 @@ PyObject* MeshPy::outer(PyObject *args)
Py_Return;
}
PyObject* MeshPy::section(PyObject *args, PyObject *kwds)
{
PyObject *pcObj;
PyObject *connectLines = Py_True;
float fMinDist = 0.0001f;
static char* keywords_section[] = {"Mesh", "ConnectLines", "MinDist", nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!f",keywords_section,
&(MeshPy::Type), &pcObj, &PyBool_Type, &connectLines, &fMinDist))
return nullptr;
MeshPy* pcObject = static_cast<MeshPy*>(pcObj);
std::vector< std::vector<Base::Vector3f> > curves = getMeshObjectPtr()->section(*pcObject->getMeshObjectPtr(), PyObject_IsTrue(connectLines), fMinDist);
Py::List outer;
for (const auto& it : curves) {
Py::List inner;
for (const auto& jt : it) {
inner.append(Py::Vector(jt));
}
outer.append(inner);
}
return Py::new_reference_to(outer);
}
PyObject* MeshPy::coarsen(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))