diff --git a/src/Mod/Mesh/App/CMakeLists.txt b/src/Mod/Mesh/App/CMakeLists.txt index fa355f18c6..e68840bab2 100644 --- a/src/Mod/Mesh/App/CMakeLists.txt +++ b/src/Mod/Mesh/App/CMakeLists.txt @@ -357,6 +357,8 @@ SET(Mesh_SRCS MeshProperties.cpp MeshProperties.h MeshPyImp.cpp + MeshTexture.cpp + MeshTexture.h PreCompiled.cpp PreCompiled.h Segment.cpp diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index 357ba7aed9..1e61e23f7b 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -252,6 +252,30 @@ float MeshAlgorithm::GetAverageEdgeLength() const return fLen; } +float MeshAlgorithm::GetMinimumEdgeLength() const +{ + float fLen = FLOAT_MAX; + MeshFacetIterator cF(_rclMesh); + for (cF.Init(); cF.More(); cF.Next()) { + for (int i=0; i<3; i++) + fLen = std::min(fLen, Base::Distance(cF->_aclPoints[i], cF->_aclPoints[(i+1)%3])); + } + + return fLen; +} + +float MeshAlgorithm::GetMaximumEdgeLength() const +{ + float fLen = 0.0f; + MeshFacetIterator cF(_rclMesh); + for (cF.Init(); cF.More(); cF.Next()) { + for (int i=0; i<3; i++) + fLen = std::max(fLen, Base::Distance(cF->_aclPoints[i], cF->_aclPoints[(i+1)%3])); + } + + return fLen; +} + Base::Vector3f MeshAlgorithm::GetGravityPoint() const { Base::Vector3f center; @@ -260,7 +284,7 @@ Base::Vector3f MeshAlgorithm::GetGravityPoint() const center += *cP; } - return center / (float)_rclMesh.CountPoints(); + return center / static_cast(_rclMesh.CountPoints()); } void MeshAlgorithm::GetMeshBorders (std::list > &rclBorders) const @@ -409,7 +433,7 @@ void MeshAlgorithm::GetFacetBorders (const std::vector &raulInd, std::list > aclEdges; for (std::vector::const_iterator it = raulInd.begin(); it != raulInd.end(); ++it) { const MeshFacet &rclFacet = rclFAry[*it]; - for (int i = 0; i < 3; i++) { + for (unsigned short i = 0; i < 3; i++) { unsigned long ulNB = rclFacet._aulNeighbours[i]; if (ulNB != ULONG_MAX) { if (rclFAry[ulNB].IsFlag(MeshFacet::VISIT) == true) @@ -497,7 +521,7 @@ void MeshAlgorithm::GetMeshBorder(unsigned long uFacet, std::list return; // add the open edge to the beginning of the list MeshFacetArray::_TConstIterator face = rFAry.begin() + uFacet; - for (int i = 0; i < 3; i++) + for (unsigned short i = 0; i < 3; i++) { if (face->_aulNeighbours[i] == ULONG_MAX) openEdges.push_back(face->GetEdge(i)); @@ -510,7 +534,7 @@ void MeshAlgorithm::GetMeshBorder(unsigned long uFacet, std::list { if (it == face) continue; - for (int i = 0; i < 3; i++) + for (unsigned short i = 0; i < 3; i++) { if (it->_aulNeighbours[i] == ULONG_MAX) openEdges.push_back(it->GetEdge(i)); @@ -1036,7 +1060,7 @@ int MeshAlgorithm::Surround(const Base::BoundBox3f& rBox, const Base::Vector3f& std::vector cFacet(12); int id=0; - for (int ii=0; ii<12; ii++) { + for (size_t ii=0; ii<12; ii++) { cFacet[ii]._aclPoints[0]=cCorner[triangles[id++]]; cFacet[ii]._aclPoints[1]=cCorner[triangles[id++]]; cFacet[ii]._aclPoints[2]=cCorner[triangles[id++]]; @@ -1679,10 +1703,10 @@ bool MeshAlgorithm::Distance (const Base::Vector3f &rclPt, unsigned long ulFacet float MeshAlgorithm::CalculateMinimumGridLength(float fLength, const Base::BoundBox3f& rBBox, unsigned long maxElements) const { // Max. limit of grid elements - float fMaxGridElements=(float)maxElements; + float fMaxGridElements=static_cast(maxElements); // estimate the minimum allowed grid length - float fMinGridLen = (float)pow((rBBox.LengthX()*rBBox.LengthY()*rBBox.LengthZ()/fMaxGridElements), 0.3333f); + float fMinGridLen = static_cast(pow((rBBox.LengthX()*rBBox.LengthY()*rBBox.LengthZ()/fMaxGridElements), 0.3333f)); return std::max(fMinGridLen, fLength); } @@ -1806,6 +1830,28 @@ MeshRefPointToFacets::operator[] (unsigned long pos) const return _map[pos]; } +std::vector +MeshRefPointToFacets::GetIndices(unsigned long pos1, unsigned long pos2) const +{ + std::vector intersection; + std::back_insert_iterator > result(intersection); + const std::set& set1 = _map[pos1]; + const std::set& set2 = _map[pos2]; + std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), result); + return intersection; +} + +std::vector +MeshRefPointToFacets::GetIndices(unsigned long pos1, unsigned long pos2, unsigned long pos3) const +{ + std::vector intersection; + std::back_insert_iterator > result(intersection); + std::vector set1 = GetIndices(pos1, pos2); + const std::set& set2 = _map[pos3]; + std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), result); + return intersection; +} + void MeshRefPointToFacets::AddNeighbour(unsigned long pos, unsigned long facet) { _map[pos].insert(facet); @@ -1852,6 +1898,17 @@ MeshRefFacetToFacets::operator[] (unsigned long pos) const return _map[pos]; } +std::vector +MeshRefFacetToFacets::GetIndices(unsigned long pos1, unsigned long pos2) const +{ + std::vector intersection; + std::back_insert_iterator > result(intersection); + const std::set& set1 = _map[pos1]; + const std::set& set2 = _map[pos2]; + std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), result); + return intersection; +} + //---------------------------------------------------------------------------- void MeshRefPointToPoints::Rebuild (void) diff --git a/src/Mod/Mesh/App/Core/Algorithm.h b/src/Mod/Mesh/App/Core/Algorithm.h index 23084c5c36..424ffda122 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.h +++ b/src/Mod/Mesh/App/Core/Algorithm.h @@ -115,6 +115,14 @@ public: * Calculates the average length of edges. */ float GetAverageEdgeLength() const; + /** + * Calculates the minimum length of edges. + */ + float GetMinimumEdgeLength() const; + /** + * Calculates the maximum length of edges. + */ + float GetMaximumEdgeLength() const; /** * Calculates the gravity point of the mesh. */ @@ -373,6 +381,8 @@ public: /// Rebuilds up data structure void Rebuild (void); const std::set& operator[] (unsigned long) const; + std::vector GetIndices(unsigned long, unsigned long) const; + std::vector GetIndices(unsigned long, unsigned long, unsigned long) const; MeshFacetArray::_TConstIterator GetFacet (unsigned long) const; std::set NeighbourPoints(const std::vector& , int level) const; std::set NeighbourPoints(unsigned long) const; @@ -412,6 +422,8 @@ public: /// Returns a set of facets sharing one or more points with the facet with /// index \a ulFacetIndex. const std::set& operator[] (unsigned long) const; + /// Returns an array of common facets of the passed facet indexes. + std::vector GetIndices(unsigned long, unsigned long) const; protected: const MeshKernel &_rclMesh; /**< The mesh kernel. */ diff --git a/src/Mod/Mesh/App/MeshTexture.cpp b/src/Mod/Mesh/App/MeshTexture.cpp new file mode 100644 index 0000000000..0018ef1a95 --- /dev/null +++ b/src/Mod/Mesh/App/MeshTexture.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (c) 2019 Werner Mayer * + * * + * 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" +#ifndef _PreComp_ +#endif + +#include "MeshTexture.h" + +using namespace Mesh; + +MeshTexture::MeshTexture(const Mesh::MeshObject& mesh, const MeshCore::Material &material) + : materialRefMesh(material) +{ + countPointsRefMesh = mesh.countPoints(); + unsigned long countFacets = mesh.countFacets(); + + if (material.binding == MeshCore::MeshIO::PER_VERTEX && material.diffuseColor.size() == countPointsRefMesh) { + binding = MeshCore::MeshIO::PER_VERTEX; + kdTree.reset(new MeshCore::MeshKDTree(mesh.getKernel().GetPoints())); + } + else if (material.binding == MeshCore::MeshIO::PER_FACE && material.diffuseColor.size() == countFacets) { + binding = MeshCore::MeshIO::PER_FACE; + kdTree.reset(new MeshCore::MeshKDTree(mesh.getKernel().GetPoints())); + refPnt2Fac.reset(new MeshCore::MeshRefPointToFacets(mesh.getKernel())); + } +} + +void MeshTexture::apply(const Mesh::MeshObject& mesh, MeshCore::Material &material) +{ + // copy the color values because the passed material could be the same instance as 'materialRefMesh' + std::vector textureColor = materialRefMesh.diffuseColor; + material.diffuseColor.clear(); + material.binding = MeshCore::MeshIO::OVERALL; + + if (kdTree.get()) { + // the points of the current mesh + std::vector diffuseColor; + const MeshCore::MeshPointArray& points = mesh.getKernel().GetPoints(); + const MeshCore::MeshFacetArray& facets = mesh.getKernel().GetFacets(); + + if (binding == MeshCore::MeshIO::PER_VERTEX) { + diffuseColor.reserve(points.size()); + for (size_t index=0; indexFindExact(points[index]); + if (pos < countPointsRefMesh) { + diffuseColor.push_back(textureColor[pos]); + } + } + + if (diffuseColor.size() == points.size()) { + material.diffuseColor.swap(diffuseColor); + material.binding = MeshCore::MeshIO::PER_VERTEX; + } + } + else if (binding == MeshCore::MeshIO::PER_FACE) { + // the values of the map give the point indices before the cut + std::vector pointMap; + pointMap.reserve(points.size()); + for (size_t index=0; indexFindExact(points[index]); + if (pos < countPointsRefMesh) { + pointMap.push_back(pos); + } + } + + // now determine the facet indices before the cut + if (pointMap.size() == points.size()) { + diffuseColor.reserve(facets.size()); + for (auto it : facets) { + std::vector found = refPnt2Fac->GetIndices(pointMap[it._aulPoints[0]], + pointMap[it._aulPoints[1]], + pointMap[it._aulPoints[2]]); + if (found.size() == 1) { + diffuseColor.push_back(textureColor[found.front()]); + } + } + } + + if (diffuseColor.size() == facets.size()) { + material.diffuseColor.swap(diffuseColor); + material.binding = MeshCore::MeshIO::PER_FACE; + } + } + } +} diff --git a/src/Mod/Mesh/App/MeshTexture.h b/src/Mod/Mesh/App/MeshTexture.h new file mode 100644 index 0000000000..c0eff198da --- /dev/null +++ b/src/Mod/Mesh/App/MeshTexture.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (c) 2019 Werner Mayer * + * * + * 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 MESH_MESHTEXTURE_H +#define MESH_MESHTEXTURE_H + +#include +#include "Core/Algorithm.h" +#include "Core/MeshKernel.h" +#include "Core/KDTree.h" +#include "Mesh.h" + + +namespace Mesh +{ + +/*! The MeshTexture class. + This algorithm is useful to update the material after a mesh has been modified + by removing points or facets. It can't be used if the coordinates of points have + changed or if new points have been added. + @author Werner Mayer + */ +class MeshExport MeshTexture +{ +public: + /*! + A mesh with material. The number of points or facets must match with the number of colors. + */ + MeshTexture(const Mesh::MeshObject& mesh, const MeshCore::Material &material); + /*! + The \a mesh must be a sub-set of the mesh passed to the constructor. This means + that points or facets can be removed but neither changed nor new points added. + */ + void apply(const Mesh::MeshObject& mesh, MeshCore::Material &material); + +private: + const MeshCore::Material &materialRefMesh; + unsigned long countPointsRefMesh; + std::unique_ptr kdTree; + std::unique_ptr refPnt2Fac; + MeshCore::MeshIO::Binding binding = MeshCore::MeshIO::OVERALL; +}; + +} // namespace Mesh + +#endif // MESH_MESHTEXTURE_H