/*************************************************************************** * 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 #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), myInner(true), myProj(pclProj), myPoly(rclPoly) { } 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 clFacet = myMesh.GetFacet(*it); if (HasIntersection(clFacet)) 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 = (float)(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 = (float)(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 = (float)(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; }