Loading files
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1995-04-24
// Created by: Bruno DUMORTIER
// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Bisector_Bisec.hxx>
#include <Bisector_BisecAna.hxx>
#include <BRep_Tool.hxx>
#include <BRepFill_TrimEdgeTool.hxx>
#include <ElCLib.hxx>
#include <Geom2d_CartesianPoint.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2d_Geometry.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dAPI_ProjectPointOnCurve.hxx>
#include <Geom2dInt_GInter.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <IntRes2d_IntersectionPoint.hxx>
#include <IntRes2d_IntersectionSegment.hxx>
#include <Precision.hxx>
#include <StdFail_NotDone.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopExp.hxx>
#include <BRepAdaptor_Curve.hxx>
#ifdef OCCT_DEBUG
#endif
//=================================================================================================
static void SimpleExpression(const Bisector_Bisec& B, occ::handle<Geom2d_Curve>& Bis)
{
Bis = B.Value();
occ::handle<Standard_Type> BT = Bis->DynamicType();
if (BT == STANDARD_TYPE(Geom2d_TrimmedCurve))
{
occ::handle<Geom2d_TrimmedCurve> TrBis = occ::down_cast<Geom2d_TrimmedCurve>(Bis);
occ::handle<Geom2d_Curve> BasBis = TrBis->BasisCurve();
BT = BasBis->DynamicType();
if (BT == STANDARD_TYPE(Bisector_BisecAna))
{
Bis = occ::down_cast<Bisector_BisecAna>(BasBis)->Geom2dCurve();
Bis = new Geom2d_TrimmedCurve(Bis, TrBis->FirstParameter(), TrBis->LastParameter());
}
}
}
//=================================================================================================
BRepFill_TrimEdgeTool::BRepFill_TrimEdgeTool() = default;
//=================================================================================================
BRepFill_TrimEdgeTool::BRepFill_TrimEdgeTool(const Bisector_Bisec& Bisec,
const occ::handle<Geom2d_Geometry>& S1,
const occ::handle<Geom2d_Geometry>& S2,
const double Offset)
: myOffset(Offset),
myBisec(Bisec)
{
isPoint1 = (S1->DynamicType() == STANDARD_TYPE(Geom2d_CartesianPoint));
isPoint2 = (S2->DynamicType() == STANDARD_TYPE(Geom2d_CartesianPoint));
// return geometries of shapes.
// double f,l;
if (isPoint1)
{
myP1 = occ::down_cast<Geom2d_Point>(S1)->Pnt2d();
}
else
{
myC1 = occ::down_cast<Geom2d_Curve>(S1);
}
if (isPoint2)
{
myP2 = occ::down_cast<Geom2d_Point>(S2)->Pnt2d();
}
else
{
myC2 = occ::down_cast<Geom2d_Curve>(S2);
}
// return the simple expression of the bissectrice
occ::handle<Geom2d_Curve> Bis;
SimpleExpression(myBisec, Bis);
myBis = Geom2dAdaptor_Curve(Bis);
}
//=======================================================================
// function : Bubble
// purpose : Order the sequence of points by increasing x.
//=======================================================================
static void Bubble(NCollection_Sequence<gp_Pnt>& Seq)
{
bool Invert = true;
int NbPoints = Seq.Length();
while (Invert)
{
Invert = false;
for (int i = 1; i < NbPoints; i++)
{
gp_Pnt P1 = Seq.Value(i);
gp_Pnt P2 = Seq.Value(i + 1);
if (P2.X() < P1.X())
{
Seq.Exchange(i, i + 1);
Invert = true;
}
}
}
}
//=================================================================================================
static void EvalParameters(const Geom2dAdaptor_Curve& Bis,
const Geom2dAdaptor_Curve& AC,
NCollection_Sequence<gp_Pnt>& Params)
{
Geom2dInt_GInter Intersector;
constexpr double Tol = Precision::Confusion();
// double TolC = 1.e-9;
const Geom2dAdaptor_Curve& CBis(Bis);
const Geom2dAdaptor_Curve& CAC(AC);
// Intersector = Geom2dInt_GInter(CBis, CAC, TolC, Tol);
Intersector = Geom2dInt_GInter(CAC, CBis, Tol, Tol);
int NbPoints, NbSegments;
double U1, U2;
gp_Pnt P;
if (!Intersector.IsDone())
{
throw StdFail_NotDone("BRepFill_TrimSurfaceTool::IntersectWith");
}
NbPoints = Intersector.NbPoints();
if (NbPoints > 0)
{
for (int i = 1; i <= NbPoints; i++)
{
U1 = Intersector.Point(i).ParamOnSecond();
U2 = Intersector.Point(i).ParamOnFirst();
P = gp_Pnt(U1, U2, 0.);
Params.Append(P);
}
}
NbSegments = Intersector.NbSegments();
if (NbSegments > 0)
{
IntRes2d_IntersectionSegment Seg;
for (int i = 1; i <= NbSegments; i++)
{
Seg = Intersector.Segment(i);
U1 = Seg.FirstPoint().ParamOnSecond();
double Ulast = Seg.LastPoint().ParamOnSecond();
if (std::abs(U1 - CBis.FirstParameter()) <= Tol
&& std::abs(Ulast - CBis.LastParameter()) <= Tol)
{
P = gp_Pnt(U1, Seg.FirstPoint().ParamOnFirst(), 0.);
Params.Append(P);
P = gp_Pnt(Ulast, Seg.LastPoint().ParamOnFirst(), 0.);
Params.Append(P);
}
else
{
U1 += Seg.LastPoint().ParamOnSecond();
U1 /= 2.;
U2 = Seg.FirstPoint().ParamOnFirst();
U2 += Seg.LastPoint().ParamOnFirst();
U2 /= 2.;
P = gp_Pnt(U1, U2, 0.);
Params.Append(P);
}
}
}
// Order the sequence by growing parameter on the bissectrice.
Bubble(Params);
}
static void EvalParametersBis(const Geom2dAdaptor_Curve& Bis,
const Geom2dAdaptor_Curve& AC,
NCollection_Sequence<gp_Pnt>& Params,
const double Tol)
{
Geom2dInt_GInter Intersector;
double TolC = Tol;
const Geom2dAdaptor_Curve& CBis(Bis);
const Geom2dAdaptor_Curve& CAC(AC);
Intersector = Geom2dInt_GInter(CAC, CBis, TolC, Tol);
int NbPoints, NbSegments;
double U1, U2;
gp_Pnt P;
if (!Intersector.IsDone())
{
throw StdFail_NotDone("BRepFill_TrimSurfaceTool::IntersectWith");
}
NbPoints = Intersector.NbPoints();
if (NbPoints > 0)
{
for (int i = 1; i <= NbPoints; i++)
{
U1 = Intersector.Point(i).ParamOnSecond();
U2 = Intersector.Point(i).ParamOnFirst();
P = gp_Pnt(U1, U2, 0.);
Params.Append(P);
}
}
NbSegments = Intersector.NbSegments();
if (NbSegments > 0)
{
IntRes2d_IntersectionSegment Seg;
for (int i = 1; i <= NbSegments; i++)
{
Seg = Intersector.Segment(i);
U1 = Seg.FirstPoint().ParamOnSecond();
double Ulast = Seg.LastPoint().ParamOnSecond();
if (std::abs(U1 - CBis.FirstParameter()) <= Tol
&& std::abs(Ulast - CBis.LastParameter()) <= Tol)
{
P = gp_Pnt(U1, Seg.FirstPoint().ParamOnFirst(), 0.);
Params.Append(P);
P = gp_Pnt(Ulast, Seg.LastPoint().ParamOnFirst(), 0.);
Params.Append(P);
}
else
{
U1 += Seg.LastPoint().ParamOnSecond();
U1 /= 2.;
U2 = Seg.FirstPoint().ParamOnFirst();
U2 += Seg.LastPoint().ParamOnFirst();
U2 /= 2.;
P = gp_Pnt(U1, U2, 0.);
Params.Append(P);
}
}
}
// Order the sequence by parameter growing on the bissectrice.
Bubble(Params);
}
//=================================================================================================
void BRepFill_TrimEdgeTool::IntersectWith(const TopoDS_Edge& Edge1,
const TopoDS_Edge& Edge2,
const TopoDS_Shape& InitShape1,
const TopoDS_Shape& InitShape2,
const TopoDS_Vertex& End1,
const TopoDS_Vertex& End2,
const GeomAbs_JoinType theJoinType,
const bool IsOpenResult,
NCollection_Sequence<gp_Pnt>& Params)
{
Params.Clear();
// return curves associated to edges.
TopLoc_Location L;
double f, l;
occ::handle<Geom_Surface> Surf;
occ::handle<Geom2d_Curve> C1;
BRep_Tool::CurveOnSurface(Edge1, C1, Surf, L, f, l);
Geom2dAdaptor_Curve AC1(C1, f, l);
occ::handle<Geom2d_Curve> C2;
BRep_Tool::CurveOnSurface(Edge2, C2, Surf, L, f, l);
Geom2dAdaptor_Curve AC2(C2, f, l);
// Calculate intersection
NCollection_Sequence<gp_Pnt> Points2;
gp_Pnt PSeq;
EvalParameters(myBis, AC1, Params);
EvalParameters(myBis, AC2, Points2);
int SeanceDeRattrapage = 0;
double TolInit = 1.e-9;
int nn = 7;
if ((AC1.GetType() != GeomAbs_Circle && AC1.GetType() != GeomAbs_Line)
|| (AC2.GetType() != GeomAbs_Circle && AC2.GetType() != GeomAbs_Line))
{
TolInit = 1.e-8;
nn = 6;
}
if (Params.IsEmpty() && Points2.IsEmpty())
{
// Check, may be there are no intersections at all
// for case myBis == Line
if (myBis.GetType() == GeomAbs_Line)
{
double dmax = TolInit;
int n = 0;
while (n < nn)
{
dmax *= 10.0;
++n;
}
dmax *= dmax;
//
gp_Lin2d anL = myBis.Line();
bool isFar1 = true;
bool isFar2 = true;
gp_Pnt2d aP;
//
double d = RealLast();
AC1.D0(AC1.FirstParameter(), aP);
double par = ElCLib::Parameter(anL, aP);
if (par >= myBis.FirstParameter() && par <= myBis.LastParameter())
{
d = anL.SquareDistance(aP);
}
AC1.D0(AC1.LastParameter(), aP);
par = ElCLib::Parameter(anL, aP);
if (par >= myBis.FirstParameter() && par <= myBis.LastParameter())
{
d = std::min(anL.SquareDistance(aP), d);
}
isFar1 = d > dmax;
//
d = RealLast();
AC2.D0(AC2.FirstParameter(), aP);
par = ElCLib::Parameter(anL, aP);
if (par >= myBis.FirstParameter() && par <= myBis.LastParameter())
{
d = anL.SquareDistance(aP);
}
AC2.D0(AC2.LastParameter(), aP);
par = ElCLib::Parameter(anL, aP);
if (par >= myBis.FirstParameter() && par <= myBis.LastParameter())
{
d = std::min(anL.SquareDistance(aP), d);
}
isFar2 = d > dmax;
//
if (isFar1 && isFar2)
{
return;
}
}
}
while (
SeanceDeRattrapage < nn // TolInit <= 0.01
&& (Points2.Length() != Params.Length() || (Points2.Length() == 0 && Params.Length() == 0)))
{
#ifdef OCCT_DEBUG
std::cout << "BRepFill_TrimEdgeTool: incoherent intersection. Try with a greater tolerance"
<< std::endl;
#endif
Params.Clear();
Points2.Clear();
TolInit *= 10.0;
EvalParametersBis(myBis, AC1, Params, TolInit);
EvalParametersBis(myBis, AC2, Points2, TolInit);
SeanceDeRattrapage++;
}
#ifdef OCCT_DEBUG
if (SeanceDeRattrapage != 0)
std::cout << "SeanceDeRattrapage = " << SeanceDeRattrapage << std::endl;
if (SeanceDeRattrapage == nn)
{
std::cout << "BRepFill_TrimEdgeTool: incoherent intersection" << std::endl;
}
#endif
if (Params.Length() == 0 && Points2.Length() == 1)
{
// std::cout << "Params.Length() == 0 && Points2.Length() == 1" << std::endl;
double dmin, dmax = 0.25 * myOffset * myOffset;
double tBis = Points2(1).X();
gp_Pnt2d PBis = myBis.Value(tBis);
double t = AC1.FirstParameter();
gp_Pnt2d PC = AC1.Value(t);
dmin = PC.SquareDistance(PBis);
gp_Pnt P(tBis, t, 0.);
if (dmin < dmax)
{
Params.Append(P);
}
t = AC1.LastParameter();
PC = AC1.Value(t);
double dmin1 = PC.SquareDistance(PBis);
if (dmin > dmin1 && dmin1 < dmax)
{
P.SetY(t);
if (Params.IsEmpty())
{
Params.Append(P);
}
else
{
Params.SetValue(1, P);
}
}
}
else if (Params.Length() == 1 && Points2.Length() == 0)
{
// std::cout << "Params.Length() == 1 && Points2.Length() == 0" << std::endl;
double dmin, dmax = 0.25 * myOffset * myOffset;
double tBis = Params(1).X();
gp_Pnt2d PBis = myBis.Value(tBis);
double t = AC2.FirstParameter();
gp_Pnt2d PC = AC2.Value(t);
dmin = PC.SquareDistance(PBis);
gp_Pnt P(tBis, t, 0.);
if (dmin < dmax)
{
Points2.Append(P);
}
t = AC2.LastParameter();
PC = AC2.Value(t);
double dmin1 = PC.SquareDistance(PBis);
if (dmin > dmin1 && dmin1 < dmax)
{
P.SetY(t);
if (Points2.IsEmpty())
{
Points2.Append(P);
}
else
{
Points2.SetValue(1, P);
}
}
}
// small manipulation to remove incorrect intersections:
// return only common intersections (same parameter
// on the bissectrice.).
// The tolerance can be eventually changed.
gp_Pnt P1, P2;
constexpr double Tol = 4 * 100 * Precision::PConfusion();
int i = 1;
int NbPoints = Params.Length();
if (NbPoints == 1 && Points2.Length() == 1)
{
// std::cout << "NbPoints == 1 && Points2.Length() == 1" << std::endl;
for (i = 1; i <= NbPoints; i++)
{
PSeq = Params(i);
PSeq.SetZ((Points2.Value(i)).Y());
Params.SetValue(i, PSeq);
}
return;
}
i = 1;
while (i <= std::min(Params.Length(), Points2.Length()))
{
P1 = Params(i);
P2 = Points2(i);
double P1xP2x = std::abs(P1.X() - P2.X());
if (P1xP2x > Tol)
{
#ifdef OCCT_DEBUG
std::cout << "BRepFill_TrimEdgeTool: no same parameter on the bissectrice" << std::endl;
#endif
if (P1xP2x > TolInit)
{
#ifdef OCCT_DEBUG
std::cout << "BRepFill_TrimEdgeTool: Continue somehow" << std::endl;
#endif
i++;
}
else
{
if (P1.X() < P2.X())
{
Params.Remove(i);
}
else
{
Points2.Remove(i);
}
}
}
else
{
i++;
}
}
if (Params.Length() > Points2.Length())
{
Params.Remove(Points2.Length() + 1, Params.Length());
}
else if (Params.Length() < Points2.Length())
{
Points2.Remove(Params.Length() + 1, Points2.Length());
}
NbPoints = Params.Length();
// Now we define: if there are more than one point of intersection
// is it Ok ?
double init_fpar = RealFirst(), init_lpar = RealLast();
if (NbPoints > 1 && theJoinType == GeomAbs_Intersection && InitShape1.ShapeType() != TopAbs_VERTEX
&& InitShape2.ShapeType() != TopAbs_VERTEX)
{
// definition of initial first and last parameters:
// this is inverse procedure to extension of parameters
//(see BRepFill_OffsetWire, function MakeOffset, case of Circle)
const TopoDS_Edge& InitEdge1 = TopoDS::Edge(InitShape1);
bool ToExtendFirstPar = true;
bool ToExtendLastPar = true;
if (IsOpenResult)
{
TopoDS_Vertex V1, V2;
TopExp::Vertices(InitEdge1, V1, V2);
if (V1.IsSame(End1) || V1.IsSame(End2))
{
ToExtendFirstPar = false;
}
if (V2.IsSame(End1) || V2.IsSame(End2))
{
ToExtendLastPar = false;
}
}
BRepAdaptor_Curve IC1(InitEdge1);
if (IC1.GetType() == GeomAbs_Circle)
{
double Delta = 2 * M_PI - IC1.LastParameter() + IC1.FirstParameter();
if (ToExtendFirstPar && ToExtendLastPar)
{
init_fpar = AC1.FirstParameter() + Delta / 2;
}
else if (ToExtendFirstPar)
{
init_fpar = AC1.FirstParameter() + Delta;
}
else if (ToExtendLastPar)
{
init_fpar = AC1.FirstParameter();
}
init_lpar = init_fpar + IC1.LastParameter() - IC1.FirstParameter();
}
}
if (NbPoints > 1 && theJoinType == GeomAbs_Intersection)
{
// Remove all vertices with non-minimal parameter
// if they are out of initial range
int imin = 1;
for (i = 2; i <= NbPoints; i++)
{
if (Params(i).X() < Params(imin).X())
{
imin = i;
}
}
NCollection_Sequence<gp_Pnt> ParamsCopy = Params;
NCollection_Sequence<gp_Pnt> Points2Copy = Points2;
Params.Clear();
Points2.Clear();
for (i = 1; i <= ParamsCopy.Length(); i++)
{
if (imin == i || (ParamsCopy(i).Y() >= init_fpar && ParamsCopy(i).Y() <= init_lpar))
{
Params.Append(ParamsCopy(i));
Points2.Append(Points2Copy(i));
}
}
/*
gp_Pnt Pnt1 = Params(imin);
gp_Pnt Pnt2 = Points2(imin);
Params.Clear();
Points2.Clear();
Params.Append(Pnt1);
Points2.Append(Pnt2);
*/
}
NbPoints = Params.Length();
for (i = 1; i <= NbPoints; i++)
{
PSeq = Params(i);
PSeq.SetZ((Points2.Value(i)).Y());
Params.SetValue(i, PSeq);
}
}
//=======================================================================
// function : AddOrConfuse
// purpose : the first or the last point of the bissectrice is on the
// parallel if it was not found in the intersections,
// it is projected on parallel lines and added in the parameters
//=======================================================================
void BRepFill_TrimEdgeTool::AddOrConfuse(const bool Start,
const TopoDS_Edge& Edge1,
const TopoDS_Edge& Edge2,
NCollection_Sequence<gp_Pnt>& Params) const
{
bool ToProj = true;
gp_Pnt2d PBis;
constexpr double Tol = 10 * Precision::Confusion();
// return curves associated to edges.
TopLoc_Location L;
double f, l;
occ::handle<Geom_Surface> Surf;
occ::handle<Geom2d_Curve> C1;
BRep_Tool::CurveOnSurface(Edge1, C1, Surf, L, f, l);
Geom2dAdaptor_Curve AC1(C1, f, l);
if (Start)
{
PBis = myBis.Value(myBis.FirstParameter());
}
else
{
PBis = myBis.Value(myBis.LastParameter());
}
// Test if the end of the bissectrice is in the set of intersection points.
if (!Params.IsEmpty())
{
gp_Pnt2d P;
if (Start)
{
P = AC1.Value(Params.First().Y());
}
else
{
P = AC1.Value(Params.Last().Y());
}
ToProj = !PBis.IsEqual(P, Tol);
}
if (ToProj)
{
#ifdef OCCT_DEBUG
std::cout << " project extremity bissectrice on parallel." << std::endl;
#endif
// Project point on parallels and add in Params
double f2, l2;
occ::handle<Geom2d_Curve> C2;
BRep_Tool::CurveOnSurface(Edge2, C2, Surf, L, f2, l2);
Geom2dAPI_ProjectPointOnCurve Projector1(PBis, C1, f, l);
Geom2dAPI_ProjectPointOnCurve Projector2(PBis, C2, f2, l2);
if (Projector1.NbPoints() == 0)
{
#ifdef OCCT_DEBUG
std::cout << "Failed projection in BRepFill_TrimEdgeTool::AddOrConfuse" << std::endl;
#endif
return;
}
if (!Projector1.NearestPoint().IsEqual(PBis, Tol))
{
#ifdef OCCT_DEBUG
std::cout << "Incorrect solution in BRepFill_TrimEdgeTool::AddOrConfuse" << std::endl;
#endif
return;
}
if (Projector2.NbPoints() == 0)
{
#ifdef OCCT_DEBUG
std::cout << "Failed projection in BRepFill_TrimEdgeTool::AddOrConfuse" << std::endl;
#endif
return;
}
if (!Projector2.NearestPoint().IsEqual(PBis, Tol))
{
#ifdef OCCT_DEBUG
std::cout << " Mauvaisesolution dans BRepFill_TrimEdgeTool::AddOrConfuse" << std::endl;
#endif
return;
}
gp_Pnt PInt(0, Projector1.LowerDistanceParameter(), Projector2.LowerDistanceParameter());
if (Start)
{
PInt.SetX(myBis.FirstParameter());
Params.Prepend(PInt);
}
else
{
PInt.SetX(myBis.LastParameter());
Params.Append(PInt);
}
}
}
//=================================================================================================
bool BRepFill_TrimEdgeTool::IsInside(const gp_Pnt2d& P) const
{
// Modified by Sergey KHROMOV - Fri Sep 27 11:43:12 2002 Begin
// double Dist;
double Dist = RealLast();
// Modified by Sergey KHROMOV - Fri Sep 27 11:43:12 2002 End
if (isPoint1)
{
Dist = P.Distance(myP1);
}
else if (isPoint2)
{
Dist = P.Distance(myP2);
}
else
{
Geom2dAPI_ProjectPointOnCurve Projector(P, myC1);
if (Projector.NbPoints() > 0)
{
Dist = Projector.LowerDistance();
}
// Modified by Sergey KHROMOV - Fri Sep 27 11:43:43 2002 Begin
// else {
// gp_Pnt2d PF = myC1->Value(myC1->FirstParameter());
// gp_Pnt2d PL = myC1->Value(myC1->LastParameter());
// Dist = Min (P.Distance(PF),P.Distance(PL));
// }
// Check of distances between P and first and last point of the first curve
// should be performed in any case, despite of the results of projection.
gp_Pnt2d PF = myC1->Value(myC1->FirstParameter());
gp_Pnt2d PL = myC1->Value(myC1->LastParameter());
double aDistMin = std::min(P.Distance(PF), P.Distance(PL));
if (Dist > aDistMin)
{
Dist = aDistMin;
}
// Modified by Sergey KHROMOV - Fri Sep 27 11:43:44 2002 End
}
// return (Dist < std::abs(myOffset);
// return (Dist < std::abs(myOffset) + Precision::Confusion());
return (Dist < std::abs(myOffset) - Precision::Confusion());
}