Mesh: add function section() to Mesh class
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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, ""))
|
||||
|
||||
Reference in New Issue
Block a user