Files
create/src/Mod/Mesh/App/Core/TrimByPlane.cpp
2019-09-14 17:05:20 +02:00

169 lines
7.1 KiB
C++

/***************************************************************************
* Copyright (c) 2019 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 <algorithm>
#include "TrimByPlane.h"
#include "Grid.h"
#include "Iterator.h"
using namespace MeshCore;
MeshTrimByPlane::MeshTrimByPlane(MeshKernel &rclM)
: myMesh(rclM)
{
}
MeshTrimByPlane::~MeshTrimByPlane()
{
}
void MeshTrimByPlane::CheckFacets(const MeshFacetGrid& rclGrid, const Base::Vector3f& base, const Base::Vector3f& normal,
std::vector<unsigned long> &trimFacets, std::vector<unsigned long>& removeFacets) const
{
// Go through the grid and check for each cell if its bounding box intersects the plane.
// If the box is completely below the plane all facets will be kept, if it's above the
// plane all triangles will be removed.
std::vector<unsigned long> checkElements;
MeshGridIterator clGridIter(rclGrid);
for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) {
Base::BoundBox3f clBBox3d = clGridIter.GetBoundBox();
if (clBBox3d.IsCutPlane(base, normal)) {
// save all elements in checkElements
clGridIter.GetElements(checkElements);
}
else if (clBBox3d.CalcPoint(0).DistanceToPlane(base, normal) > 0.0f) {
// save all elements in removeFacets
clGridIter.GetElements(removeFacets);
}
}
// remove double elements
std::sort(checkElements.begin(), checkElements.end());
checkElements.erase(std::unique(checkElements.begin(), checkElements.end()), checkElements.end());
trimFacets.reserve(checkElements.size()/2); // reserve some memory
for (auto it = checkElements.begin(); it != checkElements.end(); ++it) {
MeshGeomFacet clFacet = myMesh.GetFacet(*it);
if (clFacet.IntersectWithPlane(base, normal)) {
trimFacets.push_back(*it);
removeFacets.push_back(*it);
}
else if (clFacet._aclPoints[0].DistanceToPlane(base, normal) > 0.0f) {
removeFacets.push_back(*it);
}
}
// remove double elements
std::sort(removeFacets.begin(), removeFacets.end());
removeFacets.erase(std::unique(removeFacets.begin(), removeFacets.end()), removeFacets.end());
}
void MeshTrimByPlane::CreateOneFacet(const Base::Vector3f& base, const Base::Vector3f& normal, unsigned short shift,
const MeshGeomFacet& facet, std::vector<MeshGeomFacet>& trimmedFacets) const
{
unsigned short nul = shift % 3;
unsigned short one = (shift + 1) % 3;
unsigned short two = (shift + 2) % 3;
Base::Vector3f p1, p2;
MeshGeomEdge edge;
edge._aclPoints[0] = facet._aclPoints[nul];
edge._aclPoints[1] = facet._aclPoints[one];
edge.IntersectWithPlane(base, normal, p1);
edge._aclPoints[0] = facet._aclPoints[nul];
edge._aclPoints[1] = facet._aclPoints[two];
edge.IntersectWithPlane(base, normal, p2);
MeshGeomFacet create;
create._aclPoints[0] = facet._aclPoints[nul];
create._aclPoints[1] = p1;
create._aclPoints[2] = p2;
trimmedFacets.push_back(create);
}
void MeshTrimByPlane::CreateTwoFacet(const Base::Vector3f& base, const Base::Vector3f& normal, unsigned short shift,
const MeshGeomFacet& facet, std::vector<MeshGeomFacet>& trimmedFacets) const
{
unsigned short nul = shift % 3;
unsigned short one = (shift + 1) % 3;
unsigned short two = (shift + 2) % 3;
Base::Vector3f p1, p2;
MeshGeomEdge edge;
edge._aclPoints[0] = facet._aclPoints[nul];
edge._aclPoints[1] = facet._aclPoints[two];
edge.IntersectWithPlane(base, normal, p1);
edge._aclPoints[0] = facet._aclPoints[one];
edge._aclPoints[1] = facet._aclPoints[two];
edge.IntersectWithPlane(base, normal, p2);
MeshGeomFacet create;
create._aclPoints[0] = facet._aclPoints[nul];
create._aclPoints[1] = facet._aclPoints[one];
create._aclPoints[2] = p1;
trimmedFacets.push_back(create);
create._aclPoints[0] = facet._aclPoints[one];
create._aclPoints[1] = p2;
create._aclPoints[2] = p1;
trimmedFacets.push_back(create);
}
void MeshTrimByPlane::TrimFacets(const std::vector<unsigned long>& trimFacets, const Base::Vector3f& base,
const Base::Vector3f& normal, std::vector<MeshGeomFacet>& trimmedFacets)
{
trimmedFacets.reserve(2 * trimFacets.size());
for (auto it = trimFacets.begin(); it != trimFacets.end(); ++it) {
MeshGeomFacet facet = myMesh.GetFacet(*it);
float dist1 = facet._aclPoints[0].DistanceToPlane(base, normal);
float dist2 = facet._aclPoints[1].DistanceToPlane(base, normal);
float dist3 = facet._aclPoints[2].DistanceToPlane(base, normal);
// only one point below
if (dist1 < 0.0f && dist2 > 0.0f && dist3 > 0.0f) {
CreateOneFacet(base, normal, 0, facet, trimmedFacets);
}
else if (dist1 > 0.0f && dist2 < 0.0f && dist3 > 0.0f) {
CreateOneFacet(base, normal, 1, facet, trimmedFacets);
}
else if (dist1 > 0.0f && dist2 > 0.0f && dist3 < 0.0f) {
CreateOneFacet(base, normal, 2, facet, trimmedFacets);
}
// two points below
else if (dist1 < 0.0f && dist2 < 0.0f && dist3 > 0.0f) {
CreateTwoFacet(base, normal, 0, facet, trimmedFacets);
}
else if (dist1 > 0.0f && dist2 < 0.0f && dist3 < 0.0f) {
CreateTwoFacet(base, normal, 1, facet, trimmedFacets);
}
else if (dist1 < 0.0f && dist2 > 0.0f && dist3 < 0.0f) {
CreateTwoFacet(base, normal, 2, facet, trimmedFacets);
}
}
}