Files
create/src/Mod/MeshPart/App/CurveProjector.cpp
2016-09-24 00:42:52 +02:00

672 lines
21 KiB
C++

/***************************************************************************
* Copyright (c) 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 *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# ifdef FC_OS_LINUX
# include <unistd.h>
# endif
#endif
#include "MeshAlgos.h"
#include "CurveProjector.h"
#include <Mod/Mesh/App/Core/MeshIO.h>
#include <Mod/Mesh/App/Core/MeshKernel.h>
#include <Mod/Mesh/App/Core/Iterator.h>
#include <Mod/Mesh/App/Core/Algorithm.h>
#include <Mod/Mesh/App/Mesh.h>
#include <Base/Exception.h>
#include <Base/Console.h>
#include <Base/Sequencer.h>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Plane.hxx>
#include <BRep_Tool.hxx>
#include <GeomAPI_IntCS.hxx>
using namespace MeshPart;
using namespace MeshCore;
CurveProjector::CurveProjector(const TopoDS_Shape &aShape, const MeshKernel &pMesh)
: _Shape(aShape), _Mesh(pMesh)
{
}
void CurveProjector::writeIntersectionPointsToFile(const char *name)
{
// export points
std::ofstream str(name, std::ios::out | std::ios::binary);
str.precision(4);
str.setf(std::ios::fixed | std::ios::showpoint);
for (result_type::const_iterator it1 = mvEdgeSplitPoints.begin();it1!=mvEdgeSplitPoints.end();++it1) {
for (std::vector<FaceSplitEdge>::const_iterator it2 = it1->second.begin();it2!=it1->second.end();++it2) {
str << it2->p1.x << " " << it2->p1.y << " " << it2->p1.z << std::endl;
}
}
str.close();
}
//**************************************************************************
//**************************************************************************
// Seperator for additional classes
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CurveProjectorShape::CurveProjectorShape(const TopoDS_Shape &aShape, const MeshKernel &pMesh)
: CurveProjector(aShape,pMesh)
{
Do();
}
void CurveProjectorShape::Do(void)
{
TopExp_Explorer Ex;
TopoDS_Shape Edge;
for (Ex.Init(_Shape, TopAbs_EDGE); Ex.More(); Ex.Next())
{
const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current());
//std::vector<FaceSplitEdge> vSplitEdges;
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;
unsigned long uStartFacetIdx,uCurFacetIdx;
unsigned long uLastFacetIdx=ULONG_MAX-1; // use another value as ULONG_MAX
unsigned long 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] != ULONG_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(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(FLOAT_MAX,0,0);
// more the one intersection (@ToDo)
}else if(Alg.NbPoints() > 1){
PointOnEdge[i] = Base::Vector3f(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,unsigned long &FaceIndex)
{
Base::Vector3f TempResultPoint;
float MinLength = 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;
}
//**************************************************************************
//**************************************************************************
// Seperator for CurveProjectorSimple classe
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CurveProjectorSimple::CurveProjectorSimple(const TopoDS_Shape &aShape, const MeshKernel &pMesh)
: CurveProjector(aShape,pMesh)
{
Do();
}
void CurveProjectorSimple::Do(void)
{
TopExp_Explorer Ex;
TopoDS_Shape Edge;
std::vector<Base::Vector3f> vEdgePolygon;
for (Ex.Init(_Shape, TopAbs_EDGE); Ex.More(); Ex.Next())
{
const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current());
// GetSampledCurves(aEdge,vEdgePolygon,2000);
//std::vector<FaceSplitEdge> vSplitEdges;
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.push_back(Base::Vector3f((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> &/*rclPoints*/,
std::vector<FaceSplitEdge> &/*vSplitEdges*/)
{
Base::Vector3f /*cResultPoint, cSplitPoint, cPlanePnt, cPlaneNormal,*/TempResultPoint;
bool bFirst = true;
//unsigned long auNeighboursIdx[3];
//std::map<unsigned long,std::vector<Base::Vector3f> >::iterator N1,N2,N3;
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);
std::ofstream str("projected.asc", std::ios::out | std::ios::binary);
str.precision(4);
str.setf(std::ios::fixed | std::ios::showpoint);
std::map<unsigned long,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);
// estimate the first face
// gp_Pnt gpPt = hCurve->Value(fBegin);
// if( !findStartPoint(MeshK,Base::Vector3f(gpPt.X(),gpPt.Y(),gpPt.Z()),cResultPoint,uCurFacetIdx) )
// uCurFacetIdx = FaceProjctMap.begin()->first;
/*
do{
Base::Console().Log("Grow on %d %d left\n",uCurFacetIdx,FaceProjctMap.size());
if(FaceProjctMap[uCurFacetIdx].size() == 1)
{
Base::Console().Log("Single hit\n");
}else{
}
FaceProjctMap.erase(uCurFacetIdx);
// estimate next facet
MeshGeomFacet cCurFacet= MeshK.GetFacet(uCurFacetIdx);
MeshK.GetFacetNeighbours ( uCurFacetIdx, auNeighboursIdx[0], auNeighboursIdx[1], auNeighboursIdx[2]);
uCurFacetIdx = ULONG_MAX;
PointCount = 0;
for(int i=0; i<3; i++)
{
N1 = FaceProjctMap.find(auNeighboursIdx[i]);
// if the i'th neighbour is valid
if ( N1 != FaceProjctMap.end() )
{
unsigned long temp = N1->second.size();
if(temp >= PointCount){
PointCount = N1->second.size();
uCurFacetIdx = auNeighboursIdx[i];
}
}
}
}while(uCurFacetIdx != ULONG_MAX);
*/
}
/*
void CurveProjectorSimple::projectCurve( const TopoDS_Edge& aEdge,
const std::vector<Base::Vector3f> &rclPoints,
std::vector<FaceSplitEdge> &vSplitEdges)
{
const MeshKernel &MeshK = *(_Mesh.getKernel());
Standard_Real fFirst, fLast, fAct;
Handle(Geom_Curve) hCurve = BRep_Tool::Curve( aEdge,fFirst,fLast );
// getting start point
gp_Pnt gpPt = hCurve->Value(fFirst);
fAct = fFirst;
// projection of the first point
Base::Vector3f cStartPoint = Base::Vector3f(gpPt.X(),gpPt.Y(),gpPt.Z());
Base::Vector3f cResultPoint, cSplitPoint, cPlanePnt, cPlaneNormal,TempResultPoint;
unsigned long uStartFacetIdx,uCurFacetIdx;
unsigned long uLastFacetIdx=ULONG_MAX-1; // use another value as ULONG_MAX
unsigned long auNeighboursIdx[3];
bool GoOn;
// go through the whole Mesh, find the first projection
MeshFacetIterator It(MeshK);
GoOn = false;
for(It.Init();It.More();It.Next())
{
// try to project (with angle) to the face
if(MeshFacetFunc::IntersectWithLine (*It, cStartPoint, It->GetNormal(), cResultPoint) )
{
uCurFacetIdx = It.Position();
GoOn = true;
break;
}
}
if(!GoOn)
{
Base::Console().Log("Starting point not projectable\n");
return;
}
{
float fStep = (fLast-fFirst)/20;
unsigned long HitCount,Sentinel = 0 ;
MeshGeomFacet cCurFacet= MeshK.GetFacet(uCurFacetIdx);
MeshK.GetFacetNeighbours ( uCurFacetIdx, auNeighboursIdx[0], auNeighboursIdx[1], auNeighboursIdx[2]);
do{
// lower the step until you find a neigbourfacet to project...
fStep /= 2.0;
// still on the same facet?
gpPt = hCurve->Value(fAct+fStep);
if(MeshFacetFunc::IntersectWithLine (cCurFacet, Base::Vector3f(gpPt.X(),gpPt.Y(),gpPt.Z()), cCurFacet.GetNormal(), cResultPoint) )
{
fAct += fStep;
fStep *= 2.0;
continue;
}
HitCount = 0;
for(int i=0; i<3; i++)
{
// if the i'th neighbour is valid
if ( auNeighboursIdx[i] != ULONG_MAX )
{
// try to project next intervall
MeshGeomFacet N = MeshK.GetFacet( auNeighboursIdx[i] );
gpPt = hCurve->Value(fAct+fStep);
if(MeshFacetFunc::IntersectWithLine (*It, Base::Vector3f(gpPt.X(),gpPt.Y(),gpPt.Z()), It->GetNormal(), cResultPoint) )
{
HitCount++;
uStartFacetIdx = auNeighboursIdx[i];
}
}
}
Sentinel++;
}while(HitCount!=1 && Sentinel < 20);
}
}
*/
/*
void CurveProjectorSimple::projectCurve( const TopoDS_Edge& aEdge,
const std::vector<Base::Vector3f> &rclPoints,
std::vector<FaceSplitEdge> &vSplitEdges)
{
const MeshKernel &MeshK = *(_Mesh.getKernel());
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(gpPt.X(),gpPt.Y(),gpPt.Z());
Base::Vector3f cResultPoint, cSplitPoint, cPlanePnt, cPlaneNormal;
unsigned long uStartFacetIdx,uCurFacetIdx;
unsigned long uLastFacetIdx=ULONG_MAX-1; // use another value as ULONG_MAX
unsigned long auNeighboursIdx[3];
bool GoOn;
if( !findStartPoint(MeshK,cStartPoint,cResultPoint,uStartFacetIdx) )
return;
FILE* file = fopen("projected.asc", "w");
// go through the whole Mesh
MeshFacetIterator It1(MeshK);
for(It1.Init();It1.More();It1.Next())
{
// cycling through the points and find the first projecteble point ( if the curve starts outside the mesh)
for( std::vector<Base::Vector3f>::const_iterator It = rclPoints.begin()+1;It!=rclPoints.end();++It)
{
// MeshGeomFacet facet = MeshK.GetFacet(uStartFacetIdx);
MeshGeomFacet facet = *It1;
if(MeshFacetFunc::IntersectWithLine(facet, *It, facet.GetNormal(), cResultPoint) )
fprintf(file, "%.4f %.4f %.4f\n", cResultPoint.x, cResultPoint.y, cResultPoint.z);
}
}
fclose(file);
}
*/
bool CurveProjectorSimple::findStartPoint(const MeshKernel &MeshK,const Base::Vector3f &Pnt,Base::Vector3f &Rslt,unsigned long &FaceIndex)
{
Base::Vector3f TempResultPoint;
float MinLength = 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;
}
//**************************************************************************
//**************************************************************************
// Seperator for CurveProjectorSimple classe
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CurveProjectorWithToolMesh::CurveProjectorWithToolMesh(const TopoDS_Shape &aShape, const MeshKernel &pMesh,MeshKernel &rToolMesh)
: CurveProjector(aShape,pMesh),ToolMesh(rToolMesh)
{
Do();
}
void CurveProjectorWithToolMesh::Do(void)
{
TopExp_Explorer Ex;
TopoDS_Shape Edge;
std::vector<MeshGeomFacet> cVAry;
std::vector<Base::Vector3f> vEdgePolygon;
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<unsigned long,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(FLOAT_MAX,0,0), ln, p1, p2, p3, p4,p5,p6;
float ToolSize = 0.2f;
for (std::vector<LineSeg>::iterator It2=LineSegs.begin(); It2!=LineSegs.end();++It2)
{
if(lp.x != 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.push_back(MeshGeomFacet(p3,p2,p6));
cVAry.push_back(MeshGeomFacet(p3,p6,p4));
cVAry.push_back(MeshGeomFacet(p1,p3,p4));
cVAry.push_back(MeshGeomFacet(p1,p4,p5));
}
lp = (*It2).p;
ln = (*It2).n;
}
}