Download src/Mod/MeshPart/App/CurveProjector.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 36.9 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/MeshPart/App/CurveProjector.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/MeshPart/App/CurveProjector.cpp
-
curl -L -o CurveProjector.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/MeshPart/App/CurveProjector.cpp
36.9 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2008 Juergen Riegel <juergen.riegel@web.de> * | |
| * * | |
| * 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 * | |
| * * | |
| ***************************************************************************/ | |
| using namespace MeshPart; | |
| using MeshCore::MeshAlgorithm; | |
| using MeshCore::MeshFacet; | |
| using MeshCore::MeshFacetGrid; | |
| using MeshCore::MeshFacetIterator; | |
| using MeshCore::MeshKernel; | |
| using MeshCore::MeshPointIterator; | |
| CurveProjector::CurveProjector(const TopoDS_Shape& aShape, const MeshKernel& pMesh) | |
| : _Shape(aShape) | |
| , _Mesh(pMesh) | |
| {} | |
| void CurveProjector::writeIntersectionPointsToFile(const char* name) | |
| { | |
| // export points | |
| Base::FileInfo fi(name); | |
| Base::ofstream str(fi, std::ios::out | std::ios::binary); | |
| str.precision(4); | |
| str.setf(std::ios::fixed | std::ios::showpoint); | |
| for (const auto& it1 : mvEdgeSplitPoints) { | |
| for (const auto& it2 : it1.second) { | |
| str << it2.p1.x << " " << it2.p1.y << " " << it2.p1.z << std::endl; | |
| } | |
| } | |
| str.close(); | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // Separator for additional classes | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| CurveProjectorShape::CurveProjectorShape(const TopoDS_Shape& aShape, const MeshKernel& pMesh) | |
| : CurveProjector(aShape, pMesh) | |
| { | |
| CurveProjectorShape::Do(); | |
| } | |
| void CurveProjectorShape::Do() | |
| { | |
| TopExp_Explorer Ex; | |
| for (Ex.Init(_Shape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); | |
| projectCurve(aEdge, mvEdgeSplitPoints[aEdge]); | |
| } | |
| } | |
| void CurveProjectorShape::projectCurve(const TopoDS_Edge& aEdge, std::vector<FaceSplitEdge>& vSplitEdges) | |
| { | |
| Standard_Real fFirst, fLast; | |
| Handle(Geom_Curve) hCurve = BRep_Tool::Curve(aEdge, fFirst, fLast); | |
| // getting start point | |
| gp_Pnt gpPt = hCurve->Value(fFirst); | |
| // projection of the first point | |
| Base::Vector3f cStartPoint = Base::Vector3f((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()); | |
| Base::Vector3f cResultPoint, cSplitPoint, cPlanePnt, cPlaneNormal; | |
| MeshCore::FacetIndex uStartFacetIdx, uCurFacetIdx; | |
| MeshCore::FacetIndex uLastFacetIdx = MeshCore::FACET_INDEX_MAX | |
| - 1; // use another value as FACET_INDEX_MAX | |
| MeshCore::FacetIndex auNeighboursIdx[3]; | |
| bool GoOn; | |
| if (!findStartPoint(_Mesh, cStartPoint, cResultPoint, uStartFacetIdx)) { | |
| return; | |
| } | |
| uCurFacetIdx = uStartFacetIdx; | |
| do { | |
| MeshGeomFacet cCurFacet = _Mesh.GetFacet(uCurFacetIdx); | |
| _Mesh.GetFacetNeighbours( | |
| uCurFacetIdx, | |
| auNeighboursIdx[0], | |
| auNeighboursIdx[1], | |
| auNeighboursIdx[2] | |
| ); | |
| Base::Vector3f PointOnEdge[3]; | |
| GoOn = false; | |
| int NbrOfHits = 0, HitIdx = 0; | |
| for (int i = 0; i < 3; i++) { | |
| // ignore last visited facet | |
| if (auNeighboursIdx[i] == uLastFacetIdx) { | |
| continue; | |
| } | |
| // get points of the edge i | |
| const Base::Vector3f& cP0 = cCurFacet._aclPoints[i]; | |
| const Base::Vector3f& cP1 = cCurFacet._aclPoints[(i + 1) % 3]; | |
| if (auNeighboursIdx[i] != MeshCore::FACET_INDEX_MAX) { | |
| // calculate the normal by the edge vector and the middle between the two face | |
| // normals | |
| MeshGeomFacet N = _Mesh.GetFacet(auNeighboursIdx[i]); | |
| cPlaneNormal = (N.GetNormal() + cCurFacet.GetNormal()) % (cP1 - cP0); | |
| cPlanePnt = cP0; | |
| } | |
| else { | |
| // with no neighbours the face normal is used | |
| cPlaneNormal = cCurFacet.GetNormal() % (cP1 - cP0); | |
| cPlanePnt = cP0; | |
| } | |
| Handle(Geom_Plane) hPlane = new Geom_Plane(gp_Pln( | |
| gp_Pnt(cPlanePnt.x, cPlanePnt.y, cPlanePnt.z), | |
| gp_Dir(cPlaneNormal.x, cPlaneNormal.y, cPlaneNormal.z) | |
| )); | |
| GeomAPI_IntCS Alg(hCurve, hPlane); | |
| if (Alg.IsDone()) { | |
| // deciding by the number of result points (intersections) | |
| if (Alg.NbPoints() == 1) { | |
| gp_Pnt P = Alg.Point(1); | |
| float l = ((Base::Vector3f((float)P.X(), (float)P.Y(), (float)P.Z()) - cP0) | |
| * (cP1 - cP0)) | |
| / ((cP1 - cP0) * (cP1 - cP0)); | |
| // is the Point on the Edge of the facet? | |
| if (l < 0.0 || l > 1.0) { | |
| PointOnEdge[i] = Base::Vector3f(std::numeric_limits<float>::max(), 0, 0); | |
| } | |
| else { | |
| cSplitPoint = (1 - l) * cP0 + l * cP1; | |
| PointOnEdge[i] = (1 - l) * cP0 + l * cP1; | |
| NbrOfHits++; | |
| HitIdx = i; | |
| } | |
| // no intersection | |
| } | |
| else if (Alg.NbPoints() == 0) { | |
| PointOnEdge[i] = Base::Vector3f(std::numeric_limits<float>::max(), 0, 0); | |
| // more the one intersection (@ToDo) | |
| } | |
| else if (Alg.NbPoints() > 1) { | |
| PointOnEdge[i] = Base::Vector3f(std::numeric_limits<float>::max(), 0, 0); | |
| Base::Console().log( | |
| "MeshAlgos::projectCurve(): More then one intersection in " | |
| "Facet %lu, Edge %d\n", | |
| uCurFacetIdx, | |
| i | |
| ); | |
| } | |
| } | |
| } | |
| uLastFacetIdx = uCurFacetIdx; | |
| if (NbrOfHits == 1) { | |
| uCurFacetIdx = auNeighboursIdx[HitIdx]; | |
| FaceSplitEdge splitEdge; | |
| splitEdge.ulFaceIndex = uCurFacetIdx; | |
| splitEdge.p1 = cResultPoint; | |
| splitEdge.p2 = cSplitPoint; | |
| vSplitEdges.push_back(splitEdge); | |
| cResultPoint = cSplitPoint; | |
| GoOn = true; | |
| } | |
| else { | |
| Base::Console().log( | |
| "MeshAlgos::projectCurve(): Possible reentry in Facet %lu\n", | |
| uCurFacetIdx | |
| ); | |
| } | |
| if (uCurFacetIdx == uStartFacetIdx) { | |
| GoOn = false; | |
| } | |
| } while (GoOn); | |
| } | |
| bool CurveProjectorShape::findStartPoint( | |
| const MeshKernel& MeshK, | |
| const Base::Vector3f& Pnt, | |
| Base::Vector3f& Rslt, | |
| MeshCore::FacetIndex& FaceIndex | |
| ) | |
| { | |
| Base::Vector3f TempResultPoint; | |
| float MinLength = std::numeric_limits<float>::max(); | |
| bool bHit = false; | |
| // go through the whole Mesh | |
| MeshFacetIterator It(MeshK); | |
| for (It.Init(); It.More(); It.Next()) { | |
| // try to project (with angle) to the face | |
| if (It->Foraminate(Pnt, It->GetNormal(), TempResultPoint)) { | |
| // distance to the projected point | |
| float Dist = (Pnt - TempResultPoint).Length(); | |
| if (Dist < MinLength) { | |
| // remember the point with the closest distance | |
| bHit = true; | |
| MinLength = Dist; | |
| Rslt = TempResultPoint; | |
| FaceIndex = It.Position(); | |
| } | |
| } | |
| } | |
| return bHit; | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // Separator for CurveProjectorSimple classes | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| CurveProjectorSimple::CurveProjectorSimple(const TopoDS_Shape& aShape, const MeshKernel& pMesh) | |
| : CurveProjector(aShape, pMesh) | |
| { | |
| Do(); | |
| } | |
| void CurveProjectorSimple::Do() | |
| { | |
| TopExp_Explorer Ex; | |
| std::vector<Base::Vector3f> vEdgePolygon; | |
| for (Ex.Init(_Shape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); | |
| projectCurve(aEdge, vEdgePolygon, mvEdgeSplitPoints[aEdge]); | |
| } | |
| } | |
| void CurveProjectorSimple::GetSampledCurves( | |
| const TopoDS_Edge& aEdge, | |
| std::vector<Base::Vector3f>& rclPoints, | |
| unsigned long ulNbOfPoints | |
| ) | |
| { | |
| rclPoints.clear(); | |
| Standard_Real fBegin, fEnd; | |
| Handle(Geom_Curve) hCurve = BRep_Tool::Curve(aEdge, fBegin, fEnd); | |
| float fLen = float(fEnd - fBegin); | |
| for (unsigned long i = 0; i < ulNbOfPoints; i++) { | |
| gp_Pnt gpPt = hCurve->Value(fBegin + (fLen * float(i)) / float(ulNbOfPoints - 1)); | |
| rclPoints.emplace_back((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()); | |
| } | |
| } | |
| // projectToNeighbours(Handle(Geom_Curve) hCurve,float pos | |
| void CurveProjectorSimple::projectCurve( | |
| const TopoDS_Edge& aEdge, | |
| const std::vector<Base::Vector3f>&, | |
| std::vector<FaceSplitEdge>& | |
| ) | |
| { | |
| Base::Vector3f TempResultPoint; | |
| bool bFirst = true; | |
| Standard_Real fBegin, fEnd; | |
| Handle(Geom_Curve) hCurve = BRep_Tool::Curve(aEdge, fBegin, fEnd); | |
| float fLen = float(fEnd - fBegin); | |
| unsigned long ulNbOfPoints = 1000, PointCount = 0; | |
| MeshFacetIterator It(_Mesh); | |
| Base::SequencerLauncher seq("Building up projection map...", ulNbOfPoints + 1); | |
| Base::FileInfo fi("projected.asc"); | |
| Base::ofstream str(fi, std::ios::out | std::ios::binary); | |
| str.precision(4); | |
| str.setf(std::ios::fixed | std::ios::showpoint); | |
| std::map<MeshCore::FacetIndex, std::vector<Base::Vector3f>> FaceProjctMap; | |
| for (unsigned long i = 0; i <= ulNbOfPoints; i++) { | |
| seq.next(); | |
| gp_Pnt gpPt = hCurve->Value(fBegin + (fLen * float(i)) / float(ulNbOfPoints - 1)); | |
| // go through the whole Mesh | |
| for (It.Init(); It.More(); It.Next()) { | |
| // try to project (with angle) to the face | |
| if (It->IntersectWithLine( | |
| Base::Vector3f((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()), | |
| It->GetNormal(), | |
| TempResultPoint | |
| )) { | |
| FaceProjctMap[It.Position()].push_back(TempResultPoint); | |
| str << TempResultPoint.x << " " << TempResultPoint.y << " " << TempResultPoint.z | |
| << std::endl; | |
| Base::Console().log("IDX %d\n", It.Position()); | |
| if (bFirst) { | |
| bFirst = false; | |
| } | |
| PointCount++; | |
| } | |
| } | |
| } | |
| str.close(); | |
| Base::Console().log("Projection map [%d facets with %d points]\n", FaceProjctMap.size(), PointCount); | |
| } | |
| bool CurveProjectorSimple::findStartPoint( | |
| const MeshKernel& MeshK, | |
| const Base::Vector3f& Pnt, | |
| Base::Vector3f& Rslt, | |
| MeshCore::FacetIndex& FaceIndex | |
| ) | |
| { | |
| Base::Vector3f TempResultPoint; | |
| float MinLength = std::numeric_limits<float>::max(); | |
| bool bHit = false; | |
| // go through the whole Mesh | |
| MeshFacetIterator It(MeshK); | |
| for (It.Init(); It.More(); It.Next()) { | |
| // try to project (with angle) to the face | |
| if (It->Foraminate(Pnt, It->GetNormal(), TempResultPoint)) { | |
| // distance to the projected point | |
| float Dist = (Pnt - TempResultPoint).Length(); | |
| if (Dist < MinLength) { | |
| // remember the point with the closest distance | |
| bHit = true; | |
| MinLength = Dist; | |
| Rslt = TempResultPoint; | |
| FaceIndex = It.Position(); | |
| } | |
| } | |
| } | |
| return bHit; | |
| } | |
| //************************************************************************** | |
| //************************************************************************** | |
| // Separator for CurveProjectorSimple classes | |
| //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| CurveProjectorWithToolMesh::CurveProjectorWithToolMesh( | |
| const TopoDS_Shape& aShape, | |
| const MeshKernel& pMesh, | |
| MeshKernel& rToolMesh | |
| ) | |
| : CurveProjector(aShape, pMesh) | |
| , ToolMesh(rToolMesh) | |
| { | |
| Do(); | |
| } | |
| void CurveProjectorWithToolMesh::Do() | |
| { | |
| TopExp_Explorer Ex; | |
| std::vector<MeshGeomFacet> cVAry; | |
| for (Ex.Init(_Shape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); | |
| makeToolMesh(aEdge, cVAry); | |
| } | |
| ToolMesh.AddFacets(cVAry); | |
| } | |
| // projectToNeighbours(Handle(Geom_Curve) hCurve,float pos | |
| void CurveProjectorWithToolMesh::makeToolMesh(const TopoDS_Edge& aEdge, std::vector<MeshGeomFacet>& cVAry) | |
| { | |
| Standard_Real fBegin, fEnd; | |
| Handle(Geom_Curve) hCurve = BRep_Tool::Curve(aEdge, fBegin, fEnd); | |
| float fLen = float(fEnd - fBegin); | |
| Base::Vector3f cResultPoint; | |
| unsigned long ulNbOfPoints = 15, PointCount = 0 /*,uCurFacetIdx*/; | |
| std::vector<LineSeg> LineSegs; | |
| MeshFacetIterator It(_Mesh); | |
| Base::SequencerLauncher seq("Building up tool mesh...", ulNbOfPoints + 1); | |
| std::map<MeshCore::FacetIndex, std::vector<Base::Vector3f>> FaceProjctMap; | |
| for (unsigned long i = 0; i < ulNbOfPoints; i++) { | |
| seq.next(); | |
| gp_Pnt gpPt = hCurve->Value(fBegin + (fLen * float(i)) / float(ulNbOfPoints - 1)); | |
| Base::Vector3f LinePoint((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()); | |
| Base::Vector3f ResultNormal; | |
| // go through the whole Mesh | |
| for (It.Init(); It.More(); It.Next()) { | |
| // try to project (with angle) to the face | |
| if (It->IntersectWithLine( | |
| Base::Vector3f((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()), | |
| It->GetNormal(), | |
| cResultPoint | |
| )) { | |
| if (Base::Distance(LinePoint, cResultPoint) < 0.5) { | |
| ResultNormal += It->GetNormal(); | |
| } | |
| } | |
| } | |
| LineSeg s; | |
| s.p = Base::Vector3f((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()); | |
| s.n = ResultNormal.Normalize(); | |
| LineSegs.push_back(s); | |
| } | |
| Base::Console().log("Projection map [%d facets with %d points]\n", FaceProjctMap.size(), PointCount); | |
| // build up the new mesh | |
| Base::Vector3f lp(std::numeric_limits<float>::max(), 0, 0), ln, p1, p2, p3, p4, p5, p6; | |
| float ToolSize = 0.2f; | |
| for (const auto& It2 : LineSegs) { | |
| if (lp.x != std::numeric_limits<float>::max()) { | |
| p1 = lp + (ln * (-ToolSize)); | |
| p2 = lp + (ln * ToolSize); | |
| p3 = lp; | |
| p4 = It2.p; | |
| p5 = It2.p + (It2.n * (-ToolSize)); | |
| p6 = It2.p + (It2.n * ToolSize); | |
| cVAry.emplace_back(p3, p2, p6); | |
| cVAry.emplace_back(p3, p6, p4); | |
| cVAry.emplace_back(p1, p3, p4); | |
| cVAry.emplace_back(p1, p4, p5); | |
| } | |
| lp = It2.p; | |
| ln = It2.n; | |
| } | |
| } | |
| // ---------------------------------------------------------------------------- | |
| MeshProjection::MeshProjection(const MeshKernel& rMesh) | |
| : _rcMesh(rMesh) | |
| {} | |
| void MeshProjection::discretize( | |
| const TopoDS_Edge& aEdge, | |
| std::vector<Base::Vector3f>& polyline, | |
| std::size_t minPoints | |
| ) const | |
| { | |
| BRepAdaptor_Curve clCurve(aEdge); | |
| Standard_Real fFirst = clCurve.FirstParameter(); | |
| Standard_Real fLast = clCurve.LastParameter(); | |
| GCPnts_UniformDeflection clDefl(clCurve, 0.01f, fFirst, fLast); | |
| if (clDefl.IsDone() == Standard_True) { | |
| Standard_Integer nNbPoints = clDefl.NbPoints(); | |
| for (Standard_Integer i = 1; i <= nNbPoints; i++) { | |
| gp_Pnt gpPt = clCurve.Value(clDefl.Parameter(i)); | |
| polyline.emplace_back((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()); | |
| } | |
| } | |
| if (polyline.size() < minPoints) { | |
| GCPnts_UniformAbscissa clAbsc(clCurve, static_cast<Standard_Integer>(minPoints), fFirst, fLast); | |
| if (clAbsc.IsDone() == Standard_True) { | |
| polyline.clear(); | |
| Standard_Integer nNbPoints = clAbsc.NbPoints(); | |
| for (Standard_Integer i = 1; i <= nNbPoints; i++) { | |
| gp_Pnt gpPt = clCurve.Value(clAbsc.Parameter(i)); | |
| polyline.emplace_back((float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z()); | |
| } | |
| } | |
| } | |
| } | |
| void MeshProjection::splitMeshByShape(const TopoDS_Shape& aShape, float fMaxDist) const | |
| { | |
| std::vector<PolyLine> rPolyLines; | |
| projectToMesh(aShape, fMaxDist, rPolyLines); | |
| Base::FileInfo fi("output.asc"); | |
| Base::ofstream str(fi, std::ios::out | std::ios::binary); | |
| str.precision(4); | |
| str.setf(std::ios::fixed | std::ios::showpoint); | |
| for (const auto& it : rPolyLines) { | |
| for (const auto& jt : it.points) { | |
| str << jt.x << " " << jt.y << " " << jt.z << std::endl; | |
| } | |
| } | |
| str.close(); | |
| } | |
| bool MeshProjection::findIntersection( | |
| const Edge& edgeSegm, | |
| const Edge& meshEdge, | |
| const Base::Vector3f& dir, | |
| Base::Vector3f& res | |
| ) const | |
| { | |
| Base::Vector3f planeNormal; | |
| planeNormal = dir.Cross(edgeSegm.cPt2 - edgeSegm.cPt1); | |
| float dist1 = planeNormal.Dot(meshEdge.cPt1 - edgeSegm.cPt1); | |
| float dist2 = planeNormal.Dot(meshEdge.cPt2 - edgeSegm.cPt1); | |
| if (dist1 * dist2 < 0) { | |
| planeNormal = dir.Cross(meshEdge.cPt2 - meshEdge.cPt1); | |
| dist1 = planeNormal.Dot(edgeSegm.cPt1 - meshEdge.cPt1); | |
| dist2 = planeNormal.Dot(edgeSegm.cPt2 - meshEdge.cPt1); | |
| if (dist1 * dist2 < 0) { | |
| // intersection detected | |
| float t = planeNormal.Dot(meshEdge.cPt1 - edgeSegm.cPt1) | |
| / planeNormal.Dot(edgeSegm.cPt2 - edgeSegm.cPt1); | |
| res = edgeSegm.cPt1 * (1 - t) + edgeSegm.cPt2 * t; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| void MeshProjection::findSectionParameters( | |
| const TopoDS_Edge& edge, | |
| const Base::Vector3f& dir, | |
| std::set<double>& parameters | |
| ) const | |
| { | |
| MeshAlgorithm clAlg(_rcMesh); | |
| float fAvgLen = clAlg.GetAverageEdgeLength(); | |
| BRepAdaptor_Curve adapt(edge); | |
| double edgeLen = GCPnts_AbscissaPoint::Length(adapt, Precision::Confusion()); | |
| std::vector<Base::Vector3f> polyline; | |
| discretize(edge, polyline, std::max<size_t>(10, static_cast<size_t>(edgeLen / fAvgLen))); | |
| if (polyline.empty()) { | |
| return; | |
| } | |
| std::vector<Edge> lines; | |
| Base::Vector3f start = polyline.front(); | |
| for (auto it = polyline.begin() + 1; it != polyline.end(); ++it) { | |
| Edge line; | |
| line.cPt1 = start; | |
| line.cPt2 = *it; | |
| start = line.cPt2; | |
| lines.push_back(line); | |
| } | |
| const MeshCore::MeshFacetArray& facets = _rcMesh.GetFacets(); | |
| const MeshCore::MeshPointArray& points = _rcMesh.GetPoints(); | |
| Base::Vector3f res; | |
| for (const auto& it : facets) { | |
| for (int i = 0; i < 3; i++) { | |
| Base::Vector3f pt1 = points[it._aulPoints[i]]; | |
| Base::Vector3f pt2 = points[it._aulPoints[(i + 1) % 3]]; | |
| Edge line; | |
| line.cPt1 = pt1; | |
| line.cPt2 = pt2; | |
| for (auto jt : lines) { | |
| if (findIntersection(jt, line, dir, res)) { | |
| try { | |
| BRepBuilderAPI_MakeVertex aBuilder(gp_Pnt(res.x, res.y, res.z)); | |
| BRepExtrema_DistShapeShape extss(aBuilder.Vertex(), edge); | |
| if (extss.NbSolution() == 1) { | |
| Standard_Real par; | |
| extss.ParOnEdgeS2(1, par); | |
| parameters.insert(par); | |
| break; | |
| } | |
| } | |
| catch (const Standard_Failure&) { | |
| // ignore | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| void MeshProjection::projectToMesh( | |
| const TopoDS_Shape& aShape, | |
| float fMaxDist, | |
| std::vector<PolyLine>& rPolyLines | |
| ) const | |
| { | |
| // calculate the average edge length and create a grid | |
| MeshAlgorithm clAlg(_rcMesh); | |
| float fAvgLen = clAlg.GetAverageEdgeLength(); | |
| MeshFacetGrid cGrid(_rcMesh, 5.0f * fAvgLen); | |
| TopExp_Explorer Ex; | |
| int iCnt = 0; | |
| for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| iCnt++; | |
| } | |
| Base::SequencerLauncher seq("Project curve on mesh", iCnt); | |
| for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); | |
| std::vector<SplitEdge> rSplitEdges; | |
| projectEdgeToEdge(aEdge, fMaxDist, cGrid, rSplitEdges); | |
| PolyLine polyline; | |
| polyline.points.reserve(rSplitEdges.size()); | |
| for (auto it : rSplitEdges) { | |
| polyline.points.push_back(it.cPt); | |
| } | |
| rPolyLines.push_back(polyline); | |
| seq.next(); | |
| } | |
| } | |
| void MeshProjection::projectOnMesh( | |
| const std::vector<Base::Vector3f>& pointsIn, | |
| const Base::Vector3f& dir, | |
| float tolerance, | |
| std::vector<Base::Vector3f>& pointsOut | |
| ) const | |
| { | |
| // calculate the average edge length and create a grid | |
| MeshAlgorithm clAlg(_rcMesh); | |
| float fAvgLen = clAlg.GetAverageEdgeLength(); | |
| MeshFacetGrid cGrid(_rcMesh, 5.0f * fAvgLen); | |
| // get all boundary points and edges of the mesh | |
| std::vector<Base::Vector3f> boundaryPoints; | |
| std::vector<MeshCore::MeshGeomEdge> boundaryEdges; | |
| const MeshCore::MeshFacetArray& facets = _rcMesh.GetFacets(); | |
| const MeshCore::MeshPointArray& points = _rcMesh.GetPoints(); | |
| for (const auto& it : facets) { | |
| for (int i = 0; i < 3; i++) { | |
| if (!it.HasNeighbour(i)) { | |
| boundaryPoints.push_back(points[it._aulPoints[i]]); | |
| MeshCore::MeshGeomEdge edge; | |
| edge._bBorder = true; | |
| edge._aclPoints[0] = points[it._aulPoints[i]]; | |
| edge._aclPoints[1] = points[it._aulPoints[(i + 1) % 3]]; | |
| boundaryEdges.push_back(edge); | |
| } | |
| } | |
| } | |
| Base::SequencerLauncher seq("Project points on mesh", pointsIn.size()); | |
| for (auto it : pointsIn) { | |
| Base::Vector3f result; | |
| MeshCore::FacetIndex index; | |
| if (clAlg.NearestFacetOnRay(it, dir, cGrid, result, index)) { | |
| MeshCore::MeshGeomFacet geomFacet = _rcMesh.GetFacet(index); | |
| if (tolerance > 0 && geomFacet.IntersectPlaneWithLine(it, dir, result)) { | |
| if (geomFacet.IsPointOfFace(result, tolerance)) { | |
| pointsOut.push_back(result); | |
| } | |
| } | |
| else { | |
| pointsOut.push_back(result); | |
| } | |
| } | |
| else { | |
| // go through the boundary points and check if the point can be directly projected | |
| // onto one of them | |
| auto boundaryPnt = std::find_if( | |
| boundaryPoints.begin(), | |
| boundaryPoints.end(), | |
| [&it, &dir](const Base::Vector3f& pnt) -> bool { | |
| Base::Vector3f vec = pnt - it; | |
| float angle = vec.GetAngle(dir); | |
| return angle < 1e-6f; | |
| } | |
| ); | |
| if (boundaryPnt != boundaryPoints.end()) { | |
| pointsOut.push_back(*boundaryPnt); | |
| } | |
| else { | |
| // go through the boundary edges and check if the point can be directly projected | |
| // onto one of them | |
| Base::Vector3f result1, result2; | |
| for (auto jt : boundaryEdges) { | |
| jt.ClosestPointsToLine(it, dir, result1, result2); | |
| float dot = (result1 - jt._aclPoints[0]).Dot(result1 - jt._aclPoints[1]); | |
| Base::Vector3f vec = result1 - it; | |
| float angle = vec.GetAngle(dir); | |
| if (dot <= 0 && angle < 1e-6f) { | |
| pointsOut.push_back(result1); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| seq.next(); | |
| } | |
| } | |
| void MeshProjection::projectParallelToMesh( | |
| const TopoDS_Shape& aShape, | |
| const Base::Vector3f& dir, | |
| std::vector<PolyLine>& rPolyLines | |
| ) const | |
| { | |
| // calculate the average edge length and create a grid | |
| MeshAlgorithm clAlg(_rcMesh); | |
| float fAvgLen = clAlg.GetAverageEdgeLength(); | |
| MeshFacetGrid cGrid(_rcMesh, 5.0f * fAvgLen); | |
| TopExp_Explorer Ex; | |
| int iCnt = 0; | |
| for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| iCnt++; | |
| } | |
| Base::SequencerLauncher seq("Project curve on mesh", iCnt); | |
| for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) { | |
| const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); | |
| std::vector<Base::Vector3f> points; | |
| discretize(aEdge, points, 5); | |
| using HitPoint = std::pair<Base::Vector3f, MeshCore::FacetIndex>; | |
| std::vector<HitPoint> hitPoints; | |
| using HitPoints = std::pair<HitPoint, HitPoint>; | |
| std::vector<HitPoints> hitPointPairs; | |
| for (auto it : points) { | |
| Base::Vector3f result; | |
| MeshCore::FacetIndex index; | |
| if (clAlg.NearestFacetOnRay(it, dir, cGrid, result, index)) { | |
| hitPoints.emplace_back(result, index); | |
| if (hitPoints.size() > 1) { | |
| HitPoint p1 = hitPoints[hitPoints.size() - 2]; | |
| HitPoint p2 = hitPoints[hitPoints.size() - 1]; | |
| hitPointPairs.emplace_back(p1, p2); | |
| } | |
| } | |
| } | |
| MeshCore::MeshProjection meshProjection(_rcMesh); | |
| PolyLine polyline; | |
| for (auto it : hitPointPairs) { | |
| points.clear(); | |
| if (meshProjection.projectLineOnMesh( | |
| cGrid, | |
| it.first.first, | |
| it.first.second, | |
| it.second.first, | |
| it.second.second, | |
| dir, | |
| points | |
| )) { | |
| polyline.points.insert(polyline.points.end(), points.begin(), points.end()); | |
| } | |
| } | |
| rPolyLines.push_back(polyline); | |
| seq.next(); | |
| } | |
| } | |
| void MeshProjection::projectParallelToMesh( | |
| const std::vector<PolyLine>& aEdges, | |
| const Base::Vector3f& dir, | |
| std::vector<PolyLine>& rPolyLines | |
| ) const | |
| { | |
| // calculate the average edge length and create a grid | |
| MeshAlgorithm clAlg(_rcMesh); | |
| float fAvgLen = clAlg.GetAverageEdgeLength(); | |
| MeshFacetGrid cGrid(_rcMesh, 5.0f * fAvgLen); | |
| Base::SequencerLauncher seq("Project curve on mesh", aEdges.size()); | |
| for (const auto& it : aEdges) { | |
| std::vector<Base::Vector3f> points = it.points; | |
| using HitPoint = std::pair<Base::Vector3f, MeshCore::FacetIndex>; | |
| std::vector<HitPoint> hitPoints; | |
| using HitPoints = std::pair<HitPoint, HitPoint>; | |
| std::vector<HitPoints> hitPointPairs; | |
| for (auto it : points) { | |
| Base::Vector3f result; | |
| MeshCore::FacetIndex index; | |
| if (clAlg.NearestFacetOnRay(it, dir, cGrid, result, index)) { | |
| hitPoints.emplace_back(result, index); | |
| if (hitPoints.size() > 1) { | |
| HitPoint p1 = hitPoints[hitPoints.size() - 2]; | |
| HitPoint p2 = hitPoints[hitPoints.size() - 1]; | |
| hitPointPairs.emplace_back(p1, p2); | |
| } | |
| } | |
| } | |
| MeshCore::MeshProjection meshProjection(_rcMesh); | |
| PolyLine polyline; | |
| for (auto it : hitPointPairs) { | |
| points.clear(); | |
| if (meshProjection.projectLineOnMesh( | |
| cGrid, | |
| it.first.first, | |
| it.first.second, | |
| it.second.first, | |
| it.second.second, | |
| dir, | |
| points | |
| )) { | |
| polyline.points.insert(polyline.points.end(), points.begin(), points.end()); | |
| } | |
| } | |
| rPolyLines.push_back(polyline); | |
| seq.next(); | |
| } | |
| } | |
| void MeshProjection::projectEdgeToEdge( | |
| const TopoDS_Edge& aEdge, | |
| float fMaxDist, | |
| const MeshFacetGrid& rGrid, | |
| std::vector<SplitEdge>& rSplitEdges | |
| ) const | |
| { | |
| std::vector<MeshCore::FacetIndex> auFInds; | |
| std::map<std::pair<MeshCore::PointIndex, MeshCore::PointIndex>, std::list<MeshCore::FacetIndex>> | |
| pEdgeToFace; | |
| const std::vector<MeshFacet>& rclFAry = _rcMesh.GetFacets(); | |
| // search the facets in the local area of the curve | |
| std::vector<Base::Vector3f> acPolyLine; | |
| discretize(aEdge, acPolyLine); | |
| MeshAlgorithm(_rcMesh).SearchFacetsFromPolyline(acPolyLine, fMaxDist, rGrid, auFInds); | |
| // remove duplicated elements | |
| std::sort(auFInds.begin(), auFInds.end()); | |
| auFInds.erase(std::unique(auFInds.begin(), auFInds.end()), auFInds.end()); | |
| // facet to edge | |
| for (MeshCore::FacetIndex index : auFInds) { | |
| const MeshFacet& rF = rclFAry[index]; | |
| for (int i = 0; i < 3; i++) { | |
| MeshCore::PointIndex ulPt0 | |
| = std::min<MeshCore::PointIndex>(rF._aulPoints[i], rF._aulPoints[(i + 1) % 3]); | |
| MeshCore::PointIndex ulPt1 | |
| = std::max<MeshCore::PointIndex>(rF._aulPoints[i], rF._aulPoints[(i + 1) % 3]); | |
| pEdgeToFace[std::pair<MeshCore::PointIndex, MeshCore::PointIndex>(ulPt0, ulPt1)].push_front( | |
| index | |
| ); | |
| } | |
| } | |
| // sort intersection points by parameter | |
| std::map<Standard_Real, SplitEdge> rParamSplitEdges; | |
| BRepAdaptor_Curve clCurve(aEdge); | |
| Standard_Real fFirst = clCurve.FirstParameter(); | |
| Standard_Real fLast = clCurve.LastParameter(); | |
| Handle(Geom_Curve) hCurve = BRep_Tool::Curve(aEdge, fFirst, fLast); | |
| MeshPointIterator cPI(_rcMesh); | |
| MeshFacetIterator cFI(_rcMesh); | |
| Base::SequencerLauncher seq("Project curve on mesh", pEdgeToFace.size()); | |
| std::map<std::pair<MeshCore::PointIndex, MeshCore::PointIndex>, std::list<MeshCore::FacetIndex>>::iterator | |
| it; | |
| for (it = pEdgeToFace.begin(); it != pEdgeToFace.end(); ++it) { | |
| seq.next(); | |
| // edge points | |
| MeshCore::PointIndex uE0 = it->first.first; | |
| cPI.Set(uE0); | |
| Base::Vector3f cE0 = *cPI; | |
| MeshCore::PointIndex uE1 = it->first.second; | |
| cPI.Set(uE1); | |
| Base::Vector3f cE1 = *cPI; | |
| const std::list<MeshCore::FacetIndex>& auFaces = it->second; | |
| if (auFaces.size() > 2) { | |
| continue; // non-manifold edge -> don't handle this | |
| } | |
| Base::Vector3f cEdgeNormal; | |
| for (MeshCore::FacetIndex itF : auFaces) { | |
| cFI.Set(itF); | |
| cEdgeNormal += cFI->GetNormal(); | |
| } | |
| // create a plane from the edge normal and point | |
| Base::Vector3f cPlaneNormal = cEdgeNormal % (cE1 - cE0); | |
| Handle(Geom_Plane) hPlane = new Geom_Plane( | |
| gp_Pln(gp_Pnt(cE0.x, cE0.y, cE0.z), gp_Dir(cPlaneNormal.x, cPlaneNormal.y, cPlaneNormal.z)) | |
| ); | |
| // get intersection of curve and plane | |
| GeomAPI_IntCS Alg(hCurve, hPlane); | |
| if (Alg.IsDone()) { | |
| Standard_Integer nNbPoints = Alg.NbPoints(); | |
| if (nNbPoints == 1) { | |
| Standard_Real fU, fV, fW; | |
| Alg.Parameters(1, fU, fV, fW); | |
| gp_Pnt P = Alg.Point(1); | |
| Base::Vector3f cP0((float)P.X(), (float)P.Y(), (float)P.Z()); | |
| float l = ((cP0 - cE0) * (cE1 - cE0)) / ((cE1 - cE0) * (cE1 - cE0)); | |
| // lies the point inside the edge? | |
| if (l >= 0.0f && l <= 1.0f) { | |
| Base::Vector3f cSplitPoint = (1 - l) * cE0 + l * cE1; | |
| float fDist = Base::Distance(cP0, cSplitPoint); | |
| if (fDist <= fMaxDist) { | |
| SplitEdge splitEdge; | |
| splitEdge.uE0 = uE0; | |
| splitEdge.uE1 = uE1; | |
| splitEdge.cPt = cSplitPoint; | |
| rParamSplitEdges[fW] = splitEdge; | |
| } | |
| } | |
| } | |
| // search for the right solution | |
| else if (nNbPoints > 1) { | |
| int nCntSol = 0; | |
| Base::Vector3f cSplitPoint; | |
| Standard_Real fSol; | |
| Base::Vector3f cP0; | |
| for (int j = 1; j <= nNbPoints; j++) { | |
| Standard_Real fU, fV, fW; | |
| Alg.Parameters(j, fU, fV, fW); | |
| gp_Pnt P = Alg.Point(j); | |
| cP0.Set((float)P.X(), (float)P.Y(), (float)P.Z()); | |
| float l = ((cP0 - cE0) * (cE1 - cE0)) / ((cE1 - cE0) * (cE1 - cE0)); | |
| // lies the point inside the edge? | |
| if (l >= 0.0 && l <= 1.0) { | |
| cSplitPoint = (1 - l) * cE0 + l * cE1; | |
| float fDist = Base::Distance(cP0, cSplitPoint); | |
| if (fDist <= fMaxDist) { | |
| nCntSol++; | |
| fSol = fW; | |
| } | |
| } | |
| } | |
| // ok, only one sensible solution | |
| if (nCntSol == 1) { | |
| SplitEdge splitEdge; | |
| splitEdge.uE0 = uE0; | |
| splitEdge.uE1 = uE1; | |
| splitEdge.cPt = cSplitPoint; | |
| rParamSplitEdges[fSol] = splitEdge; | |
| } | |
| else if (nCntSol > 1) { | |
| Base::Console().log("More than one possible intersection points\n"); | |
| } | |
| } | |
| } | |
| } | |
| // sorted by parameter | |
| for (const auto& itS : rParamSplitEdges) { | |
| rSplitEdges.push_back(itS.second); | |
| } | |
| } | |