Mesh trimming tool

This commit is contained in:
wmayer
2012-03-02 12:47:11 +01:00
parent bacc263cb1
commit 8fbfd5496d
10 changed files with 978 additions and 31 deletions

View File

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

View File

@@ -1603,40 +1603,36 @@ bool MeshAlgorithm::ConnectPolygons(std::list<std::vector<Base::Vector3f> > &clP
void MeshAlgorithm::GetFacetsFromPlane (const MeshFacetGrid &rclGrid, const Base::Vector3f& clNormal, float d, const Base::Vector3f &rclLeft,
const Base::Vector3f &rclRight, std::vector<unsigned long> &rclRes) const
{
std::vector<unsigned long> aulFacets;
std::vector<unsigned long> 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<unsigned long>::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<unsigned long>::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<unsigned long> &rvecIndices, std::vector<Base::Vector3f> &rvecPoints) const

View File

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

View File

@@ -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 <Base/Sequencer.h>
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<unsigned long> &raulFacets) const
{
std::vector<unsigned long>::iterator it;
MeshFacetIterator clIter(myMesh, 0);
// cut inner: use grid to accelerate search
if (myInner) {
Base::BoundBox3f clBBox3d;
Base::BoundBox2D clViewBBox, clPolyBBox;
std::vector<unsigned long> 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<myPoly.GetCtVectors(); j++) {
if (clPoly.Contains(myPoly[j]))
return true;
}
// check for other intersections
for (j=0; j<myPoly.GetCtVectors(); j++) {
clPolyLine.clV1 = myPoly[j];
clPolyLine.clV2 = myPoly[(j+1)%myPoly.GetCtVectors()];
for (i=0; i<3; i++) {
clFacLine.clV1 = clPoly[i];
clFacLine.clV2 = clPoly[(i+1)%3];
if (clPolyLine.IntersectAndContain(clFacLine, S))
return true;
}
}
// no intersection
return false;
}
bool MeshTrimming::PolygonContainsCompleteFacet(bool bInner, unsigned long ulIndex) const
{
const MeshFacet &rclFacet = myMesh._aclFacetArray[ulIndex];
for (int i=0; i<3; i++) {
const MeshPoint &rclFacPt = myMesh._aclPointArray[rclFacet._aulPoints[i]];
Base::Vector3f clPt = (*myProj)(rclFacPt);
if (myPoly.Contains(Base::Vector2D(clPt.x, clPt.y)) != bInner)
return false;
}
return true;
}
bool MeshTrimming::IsPolygonPointInFacet(unsigned long ulIndex, Base::Vector3f& clPoint)
{
Base::Vector2D A, B, C, P;
float u,v,w, fDetPAC, fDetPBC, fDetPAB, fDetABC;
Base::Polygon2D clFacPoly;
const MeshGeomFacet &rclFacet = myMesh.GetFacet(ulIndex);
for (int i=0; i<3; i++) {
Base::Vector3f clPt = (*myProj)(rclFacet._aclPoints[i]);
clFacPoly.Add(Base::Vector2D(clPt.x, clPt.y));
}
A = clFacPoly[0];
B = clFacPoly[1];
C = clFacPoly[2];
fDetABC = A.fX*B.fY+A.fY*C.fX+B.fX*C.fY-(B.fY*C.fX+A.fY*B.fX+A.fX*C.fY);
for (unsigned long j=0; j<myPoly.GetCtVectors(); j++) {
// facet contains a polygon point -> 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<Base::Vector3f>& 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<myPoly.GetCtVectors(); i++) {
// totally only four intersections allowed
if (iIntersections == 4)
break;
Base::Vector2D P3(myPoly[i]), P4(myPoly[(i+1)%myPoly.GetCtVectors()]);
clPolyLine.clV1 = P3;
clPolyLine.clV2 = P4;
for (int j=0; j<3; j++) {
Base::Vector3f clP1((*myProj)(clFac._aclPoints[j]));
Base::Vector3f clP2((*myProj)(clFac._aclPoints[(j+1)%3]));
Base::Vector2D P1(clP1.x, clP1.y);
Base::Vector2D P2(clP2.x, clP2.y);
clFacLine.clV1 = P1;
clFacLine.clV2 = P2;
if (clPolyLine.Intersect(clFacLine, S)) {
bool bPushBack=true;
float fP1P2 = (P2-P1).Length();
float fSP1 = (P1-S).Length();
float fSP2 = (P2-S).Length();
float fP3P4 = (P4-P3).Length();
float fSP3 = (P3-S).Length();
float fSP4 = (P4-S).Length();
// compute propotion of length
float l = fSP1 / fP1P2;
float m = fSP2 / fP1P2;
float r = fSP3 / fP3P4;
float s = fSP4 / fP3P4;
// is intersection point convex combination?
if ((fabs(l+m-1.0f) < 0.001) && (fabs(r+s-1.0f) < 0.001)) {
#ifdef _DEBUG
Base::Vector3f clIntersection(m*clFac._aclPoints[j]+l*clFac._aclPoints[(j+1)%3]);
#endif
iIntersections++;
// only two intersections points per edge allowed
if (j == 0) {
if (iIntsctWithEdge0 == 2)
bPushBack = false;
else
iIntsctWithEdge0++;
}
else if (j == 1) {
if (iIntsctWithEdge1 == 2)
bPushBack = false;
else
iIntsctWithEdge1++;
}
else {
if (iIntsctWithEdge2 == 2)
bPushBack = false;
else
iIntsctWithEdge2++;
}
if (bPushBack == true)
raclPoints.push_back(m*clFac._aclPoints[j]+l*clFac._aclPoints[(j+1)%3]);
}
}
}
}
// check for rotating facet later
if (iIntsctWithEdge0 == 0)
iSide = 0;
else if (iIntsctWithEdge1 == 0)
iSide = 1;
else if (iIntsctWithEdge2 == 0)
iSide = 2;
// further check (for rotating the facet)
if (iIntsctWithEdge0 == 0 && iIntsctWithEdge1 == 0)
iSide = 1;
else if (iIntsctWithEdge0 == 0 && iIntsctWithEdge2 == 0)
iSide = 0;
else if (iIntsctWithEdge1 == 0 && iIntsctWithEdge2 == 0)
iSide = 2;
// and last another check
if (iIntsctWithEdge0 * iIntsctWithEdge1 * iIntsctWithEdge2 > 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<Base::Vector3f>& raclPoints, std::vector<MeshGeomFacet>& 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<Base::Vector3f>& raclPoints, Base::Vector3f& clP3,
std::vector<MeshGeomFacet>& 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<unsigned long>& raulFacets, std::vector<MeshGeomFacet>& aclNewFacets)
{
Base::Vector3f clP;
std::vector<Base::Vector3f> clIntsct;
int iSide;
Base::SequencerLauncher seq("trimming facets...", raulFacets.size());
for (std::vector<unsigned long>::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;
}

View File

@@ -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 <Mod/Mesh/App/Core/Elements.h>
#include <Mod/Mesh/App/Core/MeshKernel.h>
#include <Base/Tools2D.h>
#include <Base/ViewProj.h>
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<unsigned long>& raulFacets) const;
/**
* The facets from raulFacets will be trimmed or deleted and aclNewFacets gives the new generated facets
*/
void TrimFacets(const std::vector<unsigned long>& raulFacets, std::vector<MeshGeomFacet>& 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<Base::Vector3f>& raclPoints,
std::vector<MeshGeomFacet>& 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<Base::Vector3f>& raclPoints,
Base::Vector3f& clP3, std::vector<MeshGeomFacet>& 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<Base::Vector3f>& raclPoints) const;
void AdjustFacet(MeshFacet& facet, int iInd);
private:
MeshKernel& myMesh;
bool myInner;
std::vector<MeshGeomFacet> myTriangles;
const Base::ViewProjMethod* myProj;
const Base::Polygon2D& myPoly;
};
} //namespace MeshCore
#endif //MESHTRIM_H

View File

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

View File

@@ -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<App::DocumentObject*> docObj = Gui::Selection().getObjectsOfType(Mesh::Feature::getClassTypeId());
for (std::vector<App::DocumentObject*>::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<Gui::View3DInventor*>(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());

View File

@@ -77,6 +77,8 @@
#include <Mod/Mesh/App/Core/Iterator.h>
#include <Mod/Mesh/App/Core/MeshIO.h>
#include <Mod/Mesh/App/Core/Triangulation.h>
#include <Mod/Mesh/App/Core/Trim.h>
#include <Mod/Mesh/App/Core/TopoAlgorithm.h>
#include <Mod/Mesh/App/Core/Visitor.h>
#include <Mod/Mesh/App/Mesh.h>
#include <Mod/Mesh/App/MeshFeature.h>
@@ -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<Gui::View3DInventorViewer*>(n->getUserData());
view->setEditing(false);
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), trimMeshCallback,ud);
n->setHandled();
SbBool clip_inner;
std::vector<SbVec2f> clPoly = view->getGLPolygon(&clip_inner);
if (clPoly.size() < 3)
return;
if (clPoly.front() != clPoly.back())
clPoly.push_back(clPoly.front());
std::vector<Gui::ViewProvider*> views = view->getViewProvidersOfType(ViewProviderMesh::getClassTypeId());
if (!views.empty()) {
Gui::Application::Instance->activeDocument()->openCommand("Cut");
for (std::vector<Gui::ViewProvider*>::iterator it = views.begin(); it != views.end(); ++it) {
ViewProviderMesh* that = static_cast<ViewProviderMesh*>(*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<SbVec2f>& picked,
pcObject->purgeTouched();
}
void ViewProviderMesh::trimMesh(const std::vector<SbVec2f>& 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<unsigned long> indices;
Mesh::MeshObject* mesh = static_cast<Mesh::Feature*>(pcObject)->Mesh.startEditing();
MeshCore::MeshFacetGrid meshGrid(mesh->getKernel());
MeshCore::MeshAlgorithm meshAlg(mesh->getKernel());
#if 0
for (std::vector<SbVec2f>::const_iterator it = polygon.begin(); it != polygon.end(); ++it) {
// the following element
std::vector<SbVec2f>::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<SbVec2f>::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<unsigned long> check;
std::vector<MeshCore::MeshGeomFacet> 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<Mesh::Feature*>(pcObject)->Mesh.finishEditing();
pcObject->purgeTouched();
}
void ViewProviderMesh::splitMesh(const MeshCore::MeshKernel& toolMesh, const Base::Vector3f& normal, SbBool clip_inner)
{
// Get the attached mesh property

View File

@@ -153,6 +153,7 @@ protected:
virtual void showOpenEdges(bool);
void setOpenEdgeColorFrom(const App::Color& col);
virtual void cutMesh(const std::vector<SbVec2f>& picked, Gui::View3DInventorViewer &Viewer, SbBool inner);
virtual void trimMesh(const std::vector<SbVec2f>& 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);

View File

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