diff --git a/src/Mod/Mesh/App/CMakeLists.txt b/src/Mod/Mesh/App/CMakeLists.txt index fc7e996531..ee813be7bc 100644 --- a/src/Mod/Mesh/App/CMakeLists.txt +++ b/src/Mod/Mesh/App/CMakeLists.txt @@ -71,6 +71,8 @@ SET(Core_SRCS Core/TopoAlgorithm.h Core/Triangulation.cpp Core/Triangulation.h + Core/Trim.cpp + Core/Trim.h Core/tritritest.h Core/Visitor.cpp Core/Visitor.h diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index cf051fef95..40d4907d4a 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -1603,40 +1603,36 @@ bool MeshAlgorithm::ConnectPolygons(std::list > &clP void MeshAlgorithm::GetFacetsFromPlane (const MeshFacetGrid &rclGrid, const Base::Vector3f& clNormal, float d, const Base::Vector3f &rclLeft, const Base::Vector3f &rclRight, std::vector &rclRes) const { - std::vector aulFacets; + std::vector aulFacets; - Base::Vector3f clBase = d * clNormal; + Base::Vector3f clBase = d * clNormal; - Base::Vector3f clPtNormal(rclLeft - rclRight); - clPtNormal.Normalize(); + Base::Vector3f clPtNormal(rclLeft - rclRight); + clPtNormal.Normalize(); - // search grid - MeshGridIterator clGridIter(rclGrid); - for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) - { - // add facets from grid if the plane if cut the grid-voxel - if (clGridIter.GetBoundBox().IsCutPlane(clBase, clNormal) == true) - clGridIter.GetElements(aulFacets); - } - - // testing facet against planes - for (std::vector::iterator pI = aulFacets.begin(); pI != aulFacets.end(); pI++) - { - MeshGeomFacet clSFacet = _rclMesh.GetFacet(*pI); - if (clSFacet.IntersectWithPlane(clBase, clNormal) == true) - { - bool bInner = false; - for (int i = 0; (i < 3) && (bInner == false); i++) - { - Base::Vector3f clPt = clSFacet._aclPoints[i]; - if ((clPt.DistanceToPlane(rclLeft, clPtNormal) <= 0.0f) && (clPt.DistanceToPlane(rclRight, clPtNormal) >= 0.0f)) - bInner = true; - } - - if (bInner == true) - rclRes.push_back(*pI); + // search grid + MeshGridIterator clGridIter(rclGrid); + for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) { + // add facets from grid if the plane if cut the grid-voxel + if (clGridIter.GetBoundBox().IsCutPlane(clBase, clNormal) == true) + clGridIter.GetElements(aulFacets); + } + + // testing facet against planes + for (std::vector::iterator pI = aulFacets.begin(); pI != aulFacets.end(); ++pI) { + MeshGeomFacet clSFacet = _rclMesh.GetFacet(*pI); + if (clSFacet.IntersectWithPlane(clBase, clNormal) == true) { + bool bInner = false; + for (int i = 0; (i < 3) && (bInner == false); i++) { + Base::Vector3f clPt = clSFacet._aclPoints[i]; + if ((clPt.DistanceToPlane(rclLeft, clPtNormal) <= 0.0f) && (clPt.DistanceToPlane(rclRight, clPtNormal) >= 0.0f)) + bInner = true; + } + + if (bInner == true) + rclRes.push_back(*pI); + } } - } } void MeshAlgorithm::PointsFromFacetsIndices (const std::vector &rvecIndices, std::vector &rvecPoints) const diff --git a/src/Mod/Mesh/App/Core/MeshKernel.h b/src/Mod/Mesh/App/Core/MeshKernel.h index d1a12f6e1e..cceb4b1227 100644 --- a/src/Mod/Mesh/App/Core/MeshKernel.h +++ b/src/Mod/Mesh/App/Core/MeshKernel.h @@ -440,6 +440,7 @@ protected: friend class MeshFixDegeneratedFacets; friend class MeshFixDuplicatePoints; friend class MeshBuilder; + friend class MeshTrimming; }; inline MeshPoint MeshKernel::GetPoint (unsigned long ulIndex) const diff --git a/src/Mod/Mesh/App/Core/Trim.cpp b/src/Mod/Mesh/App/Core/Trim.cpp new file mode 100644 index 0000000000..cf6479ab3b --- /dev/null +++ b/src/Mod/Mesh/App/Core/Trim.cpp @@ -0,0 +1,684 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include "Trim.h" +#include "Grid.h" +#include "Iterator.h" +#include + +using namespace MeshCore; + +MeshTrimming::MeshTrimming(MeshKernel &rclM, const Base::ViewProjMethod* pclProj, + const Base::Polygon2D& rclPoly) + : myMesh(rclM), myProj(pclProj), myPoly(rclPoly), myInner(true) +{ +} + +MeshTrimming::~MeshTrimming() +{ +} + +void MeshTrimming::SetInnerOrOuter(TMode tMode) +{ + switch (tMode) + { + case INNER: + myInner = true; + break; + case OUTER: + myInner = false; + break; + } +} + +void MeshTrimming::CheckFacets(const MeshFacetGrid& rclGrid, std::vector &raulFacets) const +{ + std::vector::iterator it; + MeshFacetIterator clIter(myMesh, 0); + + // cut inner: use grid to accelerate search + if (myInner) { + Base::BoundBox3f clBBox3d; + Base::BoundBox2D clViewBBox, clPolyBBox; + std::vector aulAllElements; + + // BBox of polygon + clPolyBBox = myPoly.CalcBoundBox(); + MeshGridIterator clGridIter(rclGrid); + // traverse all BBoxes + for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) { + clBBox3d = clGridIter.GetBoundBox(); + clViewBBox = clBBox3d.ProjectBox(myProj); + if (clViewBBox || clPolyBBox) { + // save all elements in AllElements + clGridIter.GetElements(aulAllElements); + } + } + + // remove double elements + std::sort(aulAllElements.begin(), aulAllElements.end()); + aulAllElements.erase(std::unique(aulAllElements.begin(), aulAllElements.end()), aulAllElements.end()); + + Base::SequencerLauncher seq("Check facets for intersection...", aulAllElements.size()); + + for (it = aulAllElements.begin(); it != aulAllElements.end(); it++) { + MeshGeomFacet &rclFacet = myMesh.GetFacet(*it); + if (HasIntersection(rclFacet)) + raulFacets.push_back(*it); + seq.next(); + } + } + // cut outer + else { + Base::SequencerLauncher seq("Check facets for intersection...", myMesh.CountFacets()); + for (clIter.Init(); clIter.More(); clIter.Next()) { + if (HasIntersection(*clIter)) + raulFacets.push_back(clIter.Position()); + seq.next(); + } + } +} + +bool MeshTrimming::HasIntersection(const MeshGeomFacet& rclFacet) const +{ + int i; + unsigned long j; + Base::Polygon2D clPoly; + Base::Line2D clFacLine, clPolyLine; + Base::Vector2D S; + // is corner of facet inside the polygon + for (i=0; i<3; i++) { + Base::Vector3f clPt2d = myProj->operator ()(rclFacet._aclPoints[i]); + if (myPoly.Contains(Base::Vector2D(clPt2d.x, clPt2d.y)) == myInner) + return true; + else + clPoly.Add(Base::Vector2D(clPt2d.x, clPt2d.y)); + } + + // is corner of polygon inside the facet + for (j=0; j calculate the corresponding 3d-point + if (clFacPoly.Contains(myPoly[j])) { + P = myPoly[j]; + fDetPAC = A.fX*P.fY+A.fY*C.fX+P.fX*C.fY-(P.fY*C.fX+A.fY*P.fX+A.fX*C.fY); + fDetPBC = P.fX*B.fY+P.fY*C.fX+B.fX*C.fY-(B.fY*C.fX+P.fY*B.fX+P.fX*C.fY); + fDetPAB = A.fX*B.fY+A.fY*P.fX+B.fX*P.fY-(B.fY*P.fX+A.fY*B.fX+A.fX*P.fY); + u = fDetPBC / fDetABC; + v = fDetPAC / fDetABC; + w = fDetPAB / fDetABC; + + // point is on edge or no valid convex combination + if (u == 0.0f || v == 0.0f || w == 0.0f || fabs(u+v+w-1.0f) >= 0.001) + return false; + // 3d point + clPoint = u*rclFacet._aclPoints[0]+v*rclFacet._aclPoints[1]+w*rclFacet._aclPoints[2]; + + return true; + } + } + + return false; +} + +bool MeshTrimming::GetIntersectionPointsOfPolygonAndFacet(unsigned long ulIndex, int& iSide, std::vector& raclPoints) const +{ + MeshGeomFacet clFac(myMesh.GetFacet(ulIndex)); + Base::Vector2D S; + Base::Line2D clFacLine, clPolyLine; + int iIntersections=0; + int iIntsctWithEdge0=0, iIntsctWithEdge1=0, iIntsctWithEdge2=0; + // Edge with no intersection + iSide = -1; + + for (unsigned long i=0; i 0) { + if (iIntsctWithEdge0 == 2) + iSide = 2; + else if (iIntsctWithEdge1 == 2) + iSide = 0; + else if (iIntsctWithEdge2 == 2) + iSide = 1; + } + + return iIntersections > 0; +} + +void MeshTrimming::AdjustFacet(MeshFacet& facet, int iInd) +{ + unsigned long tmp; + + if (iInd == 1) { + tmp = facet._aulPoints[0]; + facet._aulPoints[0] = facet._aulPoints[1]; + facet._aulPoints[1] = facet._aulPoints[2]; + facet._aulPoints[2] = tmp; + tmp = facet._aulNeighbours[0]; + facet._aulNeighbours[0] = facet._aulNeighbours[1]; + facet._aulNeighbours[1] = facet._aulNeighbours[2]; + facet._aulNeighbours[2] = tmp; + } + else if (iInd == 2) { + tmp = facet._aulPoints[0]; + facet._aulPoints[0] = facet._aulPoints[2]; + facet._aulPoints[2] = facet._aulPoints[1]; + facet._aulPoints[1] = tmp; + tmp = facet._aulNeighbours[0]; + facet._aulNeighbours[0] = facet._aulNeighbours[2]; + facet._aulNeighbours[2] = facet._aulNeighbours[1]; + facet._aulNeighbours[1] = tmp; + } +} + +bool MeshTrimming::CreateFacets(unsigned long ulFacetPos, int iSide, const std::vector& raclPoints, std::vector& aclNewFacets) +{ + MeshGeomFacet clFac; + + // no valid triangulation possible + if (iSide == -1) + return false; + + // two points found + if (raclPoints.size() == 2) { + MeshFacet& facet = myMesh._aclFacetArray[ulFacetPos]; + AdjustFacet(facet, iSide); + Base::Vector3f clP1(raclPoints[0]), clP2(raclPoints[1]); + + if (iSide == 1) { + // swap P1 and P2 + clP1 = raclPoints[1]; + clP2 = raclPoints[0]; + } + + // check which facets can be inserted + int iCtPts=0; + Base::Vector3f clFacPnt; + Base::Vector2D clProjPnt; + for (int i=0; i<3; i++) { + clFacPnt = (*myProj)(myMesh._aclPointArray[facet._aulPoints[i]]); + clProjPnt = Base::Vector2D(clFacPnt.x, clFacPnt.y); + if (myPoly.Contains(clProjPnt) == myInner) + ++iCtPts; + } + + if (iCtPts == 2) { + // erstes Dreieck + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[2]]; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + } + else if (iCtPts == 1) { + // erstes Dreieck + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + // zweites Dreieck + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[1] = clP1; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + } + else + return false; + } + // four points found + else if (raclPoints.size() == 4) { + MeshFacet& facet = myMesh._aclFacetArray[ulFacetPos]; + AdjustFacet(facet, iSide); + + MeshFacet clOrg(myMesh._aclFacetArray[ulFacetPos]); + clFac = myMesh.GetFacet(ulFacetPos); + // intersection points + Base::Vector3f clP1(raclPoints[0]), clP2(raclPoints[1]), clP3(raclPoints[2]), clP4(raclPoints[3]); + + // check which facets can be inserted + int iCtPts=0; + Base::Vector3f clFacPnt; + Base::Vector2D clProjPnt; + for (int i=0; i<3; i++) { + clFacPnt = (*myProj)(myMesh._aclPointArray[facet._aulPoints[i]]); + clProjPnt = Base::Vector2D(clFacPnt.x, clFacPnt.y); + if (myPoly.Contains(clProjPnt) == myInner) + ++iCtPts; + } + + // sort the intersection points in a certain order + if (iCtPts == 0 || iCtPts == 3) { + if (iSide == 1) { + // swap the points + clP1 = clP2; + clP2 = raclPoints[0]; + clP3 = clP4; + clP4 = raclPoints[2]; + } + + if ((clP1-clFac._aclPoints[1]).Length() > (clP3-clFac._aclPoints[1]).Length()) { + // swap P1 and P3 + Base::Vector3f tmp(clP1); + clP1 = clP3; + clP3 = tmp; + } + if ((clP2-clFac._aclPoints[0]).Length() > (clP4-clFac._aclPoints[0]).Length()) { + // swap P2 and P4 + Base::Vector3f tmp(clP2); + clP2 = clP4; + clP4 = tmp; + } + } + else { + if (iSide == 0) { + Base::Vector3f clNormal(clFac.GetNormal()); + MeshGeomFacet clTmpFac; clTmpFac._aclPoints[0] = clFac._aclPoints[1]; + clTmpFac._aclPoints[1] = clP2; clTmpFac._aclPoints[2] = clP1; + if (clTmpFac.GetNormal() * clNormal > 0) { + Base::Vector3f tmp(clP1); + clP1 = clP2; + clP2 = tmp; + } + else { + Base::Vector3f tmp(clP1); + clP1 = clP4; + clP4 = clP2; + clP2 = clP3; + clP3 = tmp; + } + } + else if (iSide == 1) { + if ((clP2-clFac._aclPoints[1]).Length() > (clP4-clFac._aclPoints[1]).Length()) { + Base::Vector3f tmp(clP1); + clP1 = clP4; + clP4 = tmp; + tmp = clP2; + clP2 = clP3; + clP3 = tmp; + } + else { + Base::Vector3f tmp(clP1); + clP1 = clP2; + clP2 = tmp; + tmp = clP3; + clP3 = clP4; + clP4 = tmp; + } + } + else { + if ((clP1-clFac._aclPoints[1]).Length() > (clP3-clFac._aclPoints[1]).Length()) { + Base::Vector3f tmp(clP1); + clP1 = clP3; + clP3 = tmp; + tmp = clP2; + clP2 = clP4; + clP4 = tmp; + } + } + } + + // now create the new facets + if (iCtPts == 0) { + // insert first facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[2] = clP1; + aclNewFacets.push_back(clFac); + // insert second facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = clP1; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + // finally insert third facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[2]]; + clFac._aclPoints[1] = clP4; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + } + else if (iCtPts == 1) { + // insert first facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = clP2; + clFac._aclPoints[2] = myMesh._aclPointArray[facet._aulPoints[1]]; + aclNewFacets.push_back(clFac); + // finally insert second facet + clFac._aclPoints[0] = clP4; + clFac._aclPoints[1] = clP3; + clFac._aclPoints[2] = myMesh._aclPointArray[facet._aulPoints[2]]; + aclNewFacets.push_back(clFac); + } + else if (iCtPts == 2) { + // insert first facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = clP2; + clFac._aclPoints[2] = clP4; + aclNewFacets.push_back(clFac); + // insert second facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = clP4; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + // finally insert third facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = clP3; + clFac._aclPoints[2] = clP4; + aclNewFacets.push_back(clFac); + } + else { + // insert first facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = clP3; + clFac._aclPoints[2] = clP4; + aclNewFacets.push_back(clFac); + // finally insert second facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = clP4; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + } + } + else + return false; + + return true; +} + +bool MeshTrimming::CreateFacets(unsigned long ulFacetPos, int iSide, const std::vector& raclPoints, Base::Vector3f& clP3, + std::vector& aclNewFacets) +{ + // no valid triangulation possible + if (iSide == -1 || raclPoints.size() < 2) + return false; + + Base::Vector3f clP1(raclPoints[0]); + Base::Vector3f clP2(raclPoints[1]); + + MeshFacet& facet = myMesh._aclFacetArray[ulFacetPos]; + AdjustFacet(facet, iSide); + + MeshGeomFacet clFac; + + Base::Vector3f pnt = myMesh._aclPointArray[facet._aulPoints[1]]; + Base::Vector3f dir = myMesh._aclPointArray[facet._aulPoints[2]] - + myMesh._aclPointArray[facet._aulPoints[1]]; + + float fDistEdgeP1 = clP1.DistanceToLineSegment( + myMesh._aclPointArray[facet._aulPoints[1]], + myMesh._aclPointArray[facet._aulPoints[2]]).Length(); + float fDistEdgeP2 = clP2.DistanceToLineSegment( + myMesh._aclPointArray[facet._aulPoints[1]], + myMesh._aclPointArray[facet._aulPoints[2]]).Length(); + + // swap P1 and P2 + if (fDistEdgeP2 < fDistEdgeP1) { + Base::Vector3f tmp(clP1); + clP1 = clP2; + clP2 = tmp; + } + + // check which facets should be inserted + int iCtPts=0; + Base::Vector3f clFacPnt; + Base::Vector2D clProjPnt; + for (int i=0; i<3; i++) { + clFacPnt = (*myProj)(myMesh._aclPointArray[facet._aulPoints[i]]); + clProjPnt = Base::Vector2D(clFacPnt.x, clFacPnt.y); + if (myPoly.Contains(clProjPnt) == myInner) + ++iCtPts; + } + if (iCtPts == 3) { + clFac = myMesh.GetFacet(ulFacetPos); + if ((clP1-clFac._aclPoints[1]).Length() > (clP2-clFac._aclPoints[1]).Length()) { + Base::Vector3f tmp(clP1); + clP1 = clP2; + clP2 = tmp; + } + // only one facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = clP2; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + } + else if (iCtPts == 2) { + // first facet + clFac._aclPoints[0] = clP1; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[2]]; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + // second facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[2]]; + clFac._aclPoints[1] = clP2; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + } + else if (iCtPts == 1) { + // first facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + // second facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[1] = clP1; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + // third facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = clP3; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + } + else if (iCtPts == 0) { + clFac = myMesh.GetFacet(ulFacetPos); + if ((clP1-clFac._aclPoints[1]).Length() > (clP2-clFac._aclPoints[1]).Length()) { + Base::Vector3f tmp(clP1); + clP1 = clP2; + clP2 = tmp; + } + // first facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[2]]; + clFac._aclPoints[1] = clP3; + clFac._aclPoints[2] = clP2; + aclNewFacets.push_back(clFac); + // second facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[2]]; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + // third facet + clFac._aclPoints[0] = myMesh._aclPointArray[facet._aulPoints[0]]; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[2] = clP3; + aclNewFacets.push_back(clFac); + // and finally fourth facet + clFac._aclPoints[0] = clP3; + clFac._aclPoints[1] = myMesh._aclPointArray[facet._aulPoints[1]]; + clFac._aclPoints[2] = clP1; + aclNewFacets.push_back(clFac); + } + + return true; +} + +void MeshTrimming::TrimFacets(const std::vector& raulFacets, std::vector& aclNewFacets) +{ + Base::Vector3f clP; + std::vector clIntsct; + int iSide; + + Base::SequencerLauncher seq("trimming facets...", raulFacets.size()); + for (std::vector::const_iterator it=raulFacets.begin(); it!=raulFacets.end(); it++) { + clIntsct.clear(); + if (IsPolygonPointInFacet(*it, clP) == false) { + // facet must be trimmed + if (PolygonContainsCompleteFacet(myInner, *it) == false) { + // generate new facets + if (GetIntersectionPointsOfPolygonAndFacet(*it, iSide, clIntsct)) + CreateFacets(*it, iSide, clIntsct, myTriangles); + } + } + // facet contains a polygon point + else { + // generate new facets + if (GetIntersectionPointsOfPolygonAndFacet(*it, iSide, clIntsct)) + CreateFacets(*it, iSide, clIntsct, clP, myTriangles); + } + seq.next(); + } + + aclNewFacets = myTriangles; +} diff --git a/src/Mod/Mesh/App/Core/Trim.h b/src/Mod/Mesh/App/Core/Trim.h new file mode 100644 index 0000000000..a87f65ab33 --- /dev/null +++ b/src/Mod/Mesh/App/Core/Trim.h @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef MESHTRIM_H +#define MESHTRIM_H + +#include +#include +#include +#include + +namespace MeshCore { + +/** + * Checks the facets in 2D and then trim them in 3D + */ +class MeshExport MeshTrimming +{ +public: + enum TMode {INNER, OUTER}; + +public: + MeshTrimming(MeshKernel& mesh, const Base::ViewProjMethod* pclProj, const Base::Polygon2D& rclPoly); + ~MeshTrimming(); + +public: + /** + * Checks all facets for intersection with the polygon and writes all touched facets into the vector + */ + void CheckFacets(const MeshFacetGrid& rclGrid, std::vector& raulFacets) const; + + /** + * The facets from raulFacets will be trimmed or deleted and aclNewFacets gives the new generated facets + */ + void TrimFacets(const std::vector& raulFacets, std::vector& aclNewFacets); + + /** + * Setter: Trimm INNER or OUTER + */ + void SetInnerOrOuter(TMode tMode); + +private: + /** + * Checks if the polygon cuts the facet + */ + bool HasIntersection(const MeshGeomFacet& rclFacet) const; + + /** + * Checks if a facet lies totally within a polygon + */ + bool PolygonContainsCompleteFacet(bool bInner, unsigned long ulIndex) const; + + /** + * Creates new facets from edge points of the facet + */ + bool CreateFacets(unsigned long ulFacetPos, int iSide, const std::vector& raclPoints, + std::vector& aclNewFacets); + + /** + * Creates new facets from edge points of the facet and a point inside the facet + */ + bool CreateFacets(unsigned long ulFacetPos, int iSide, const std::vector& raclPoints, + Base::Vector3f& clP3, std::vector& aclNewFacets); + + /** + * Checks if a polygon point lies within a facet + */ + bool IsPolygonPointInFacet(unsigned long ulIndex, Base::Vector3f& clPoint); + + /** + * Calculates the two intersection points between polygonline and facet in 2D + * and project the points back into 3D (not very exactly) + */ + bool GetIntersectionPointsOfPolygonAndFacet(unsigned long ulIndex, int& iSide, + std::vector& raclPoints) const; + + void AdjustFacet(MeshFacet& facet, int iInd); + +private: + MeshKernel& myMesh; + bool myInner; + std::vector myTriangles; + const Base::ViewProjMethod* myProj; + const Base::Polygon2D& myPoly; +}; + +} //namespace MeshCore + +#endif //MESHTRIM_H diff --git a/src/Mod/Mesh/App/Makefile.am b/src/Mod/Mesh/App/Makefile.am index 0af44d9a3d..6309f0d912 100644 --- a/src/Mod/Mesh/App/Makefile.am +++ b/src/Mod/Mesh/App/Makefile.am @@ -49,6 +49,8 @@ libMesh_la_SOURCES=\ Core/tritritest.h \ Core/Triangulation.cpp \ Core/Triangulation.h \ + Core/Trim.cpp \ + Core/Trim.h \ Core/Tools.cpp \ Core/Tools.h \ Core/TopoAlgorithm.cpp \ diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 9121155ca6..35228e7780 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -743,6 +743,61 @@ bool CmdMeshPolyCut::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdMeshPolyTrim); + +CmdMeshPolyTrim::CmdMeshPolyTrim() + : Command("Mesh_PolyTrim") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Trim mesh"); + sToolTipText = QT_TR_NOOP("Trims a mesh with a picked polygon"); + sWhatsThis = "Mesh_PolyTrim"; + sStatusTip = QT_TR_NOOP("Trims a mesh with a picked polygon"); +} + +void CmdMeshPolyTrim::activated(int iMsg) +{ + std::vector docObj = Gui::Selection().getObjectsOfType(Mesh::Feature::getClassTypeId()); + for (std::vector::iterator it = docObj.begin(); it != docObj.end(); ++it) { + if (it == docObj.begin()) { + Gui::Document* doc = getActiveGuiDocument(); + Gui::MDIView* view = doc->getActiveView(); + if (view->getTypeId().isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { + Gui::View3DInventorViewer* viewer = ((Gui::View3DInventor*)view)->getViewer(); + viewer->setEditing(true); + viewer->startSelection(Gui::View3DInventorViewer::Clip); + viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), + MeshGui::ViewProviderMeshFaceSet::trimMeshCallback); + } + else { + return; + } + } + + Gui::ViewProvider* pVP = getActiveGuiDocument()->getViewProvider(*it); + if (pVP->isVisible()) + pVP->startEditing(); + } +} + +bool CmdMeshPolyTrim::isActive(void) +{ + // Check for the selected mesh feature (all Mesh types) + if (getSelection().countObjectsOfType(Mesh::Feature::getClassTypeId()) == 0) + return false; + + Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); + if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { + Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); + return !viewer->isEditing(); + } + + return false; +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdMeshPolySplit); CmdMeshPolySplit::CmdMeshPolySplit() @@ -1328,6 +1383,7 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshAddFacet()); rcCmdMgr.addCommand(new CmdMeshPolyCut()); rcCmdMgr.addCommand(new CmdMeshPolySplit()); + rcCmdMgr.addCommand(new CmdMeshPolyTrim()); rcCmdMgr.addCommand(new CmdMeshToolMesh()); rcCmdMgr.addCommand(new CmdMeshTransform()); rcCmdMgr.addCommand(new CmdMeshEvaluation()); diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index 3b5ba3f17e..db7e99057c 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -77,6 +77,8 @@ #include #include #include +#include +#include #include #include #include @@ -616,6 +618,41 @@ void ViewProviderMesh::clipMeshCallback(void * ud, SoEventCallback * n) } } +void ViewProviderMesh::trimMeshCallback(void * ud, SoEventCallback * n) +{ + // show the wait cursor because this could take quite some time + Gui::WaitCursor wc; + + // When this callback function is invoked we must in either case leave the edit mode + Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData()); + view->setEditing(false); + view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), trimMeshCallback,ud); + n->setHandled(); + + SbBool clip_inner; + std::vector clPoly = view->getGLPolygon(&clip_inner); + if (clPoly.size() < 3) + return; + if (clPoly.front() != clPoly.back()) + clPoly.push_back(clPoly.front()); + + std::vector views = view->getViewProvidersOfType(ViewProviderMesh::getClassTypeId()); + if (!views.empty()) { + Gui::Application::Instance->activeDocument()->openCommand("Cut"); + for (std::vector::iterator it = views.begin(); it != views.end(); ++it) { + ViewProviderMesh* that = static_cast(*it); + if (that->getEditingMode() > -1) { + that->finishEditing(); + that->trimMesh(clPoly, *view, clip_inner); + } + } + + Gui::Application::Instance->activeDocument()->commitCommand(); + + view->render(); + } +} + void ViewProviderMesh::partMeshCallback(void * ud, SoEventCallback * cb) { // show the wait cursor because this could take quite some time @@ -1017,6 +1054,65 @@ void ViewProviderMesh::cutMesh(const std::vector& picked, pcObject->purgeTouched(); } +void ViewProviderMesh::trimMesh(const std::vector& polygon, + Gui::View3DInventorViewer& viewer, SbBool inner) +{ + // get the drawing plane + SbViewVolume vol = viewer.getCamera()->getViewVolume(); + SbPlane drawPlane = vol.getPlane(viewer.getCamera()->focalDistance.getValue()); + + std::vector indices; + Mesh::MeshObject* mesh = static_cast(pcObject)->Mesh.startEditing(); + MeshCore::MeshFacetGrid meshGrid(mesh->getKernel()); + MeshCore::MeshAlgorithm meshAlg(mesh->getKernel()); + +#if 0 + for (std::vector::const_iterator it = polygon.begin(); it != polygon.end(); ++it) { + // the following element + std::vector::const_iterator nt = it + 1; + if (nt == polygon.end()) + break; + else if (*it == *nt) + continue; // two adjacent vertices are equal + + SbVec3f p1,p2; + SbLine l1, l2; + vol.projectPointToLine(*it, l1); + drawPlane.intersect(l1, p1); + vol.projectPointToLine(*nt, l2); + drawPlane.intersect(l2, p2); + + SbPlane plane(l1.getPosition(), l2.getPosition(), + l1.getPosition()+l1.getDirection()); + const SbVec3f& n = plane.getNormal(); + float d = plane.getDistanceFromOrigin(); + meshAlg.GetFacetsFromPlane(meshGrid, + Base::Vector3f(n[0],n[1],n[2]), d, + Base::Vector3f(p1[0],p1[1],p1[2]), + Base::Vector3f(p2[0],p2[1],p2[2]), indices); + } +#endif + + Gui::ViewVolumeProjection proj(vol); + Base::Polygon2D polygon2d; + for (std::vector::const_iterator it = polygon.begin(); it != polygon.end(); ++it) + polygon2d.Add(Base::Vector2D((*it)[0],(*it)[1])); + MeshCore::MeshTrimming trim(mesh->getKernel(), &proj, polygon2d); + std::vector check; + std::vector triangle; + trim.SetInnerOrOuter(inner ? MeshCore::MeshTrimming::INNER : MeshCore::MeshTrimming::OUTER); + trim.CheckFacets(meshGrid, check); + trim.TrimFacets(check, triangle); + mesh->deleteFacets(check); + if (!triangle.empty()) { + mesh->getKernel().AddFacets(triangle); + } + //Remove the facets from the mesh and open a transaction object for the undo/redo stuff + //mesh->deleteFacets(indices); + static_cast(pcObject)->Mesh.finishEditing(); + pcObject->purgeTouched(); +} + void ViewProviderMesh::splitMesh(const MeshCore::MeshKernel& toolMesh, const Base::Vector3f& normal, SbBool clip_inner) { // Get the attached mesh property diff --git a/src/Mod/Mesh/Gui/ViewProvider.h b/src/Mod/Mesh/Gui/ViewProvider.h index 6390eb53a8..ce0de6b8c9 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.h +++ b/src/Mod/Mesh/Gui/ViewProvider.h @@ -153,6 +153,7 @@ protected: virtual void showOpenEdges(bool); void setOpenEdgeColorFrom(const App::Color& col); virtual void cutMesh(const std::vector& picked, Gui::View3DInventorViewer &Viewer, SbBool inner); + virtual void trimMesh(const std::vector& picked, Gui::View3DInventorViewer &Viewer, SbBool inner); virtual void splitMesh(const MeshCore::MeshKernel& toolMesh, const Base::Vector3f& normal, SbBool inner); virtual void segmentMesh(const MeshCore::MeshKernel& toolMesh, const Base::Vector3f& normal, SbBool inner); virtual void faceInfo(unsigned long facet); @@ -169,6 +170,7 @@ public: static void fillHoleCallback(void * ud, SoEventCallback * n); static void markPartCallback(void * ud, SoEventCallback * n); static void clipMeshCallback(void * ud, SoEventCallback * n); + static void trimMeshCallback(void * ud, SoEventCallback * n); static void partMeshCallback(void * ud, SoEventCallback * n); static void segmMeshCallback(void * ud, SoEventCallback * n); static void selectGLCallback(void * ud, SoEventCallback * n); diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index 409d97017e..e365f7152a 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -87,7 +87,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_FillupHoles" << "Mesh_FillInteractiveHole" << "Mesh_RemoveComponents" << "Mesh_RemoveCompByHand" << "Mesh_AddFacet" << "Mesh_Smoothing" << "Separator" << "Mesh_BuildRegularSolid" << boolean << "Separator" << "Mesh_PolySelect" << "Mesh_PolyCut" - << "Mesh_PolySplit" << "Mesh_PolySegm" << /*"Mesh_ToolMesh" <<*/ "Mesh_VertexCurvature"; + << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_VertexCurvature"; return root; }