mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-06-14 11:37:02 +08:00
Implementation of the 3D model De-featuring algorithm intended for the removal of the unwanted parts (or features) from the model consisting of solids. The features can be the holes, protrusions, gaps, chamfers, fillets etc. The algorithm removes all possible requested features from the shape and builds the new shape as a result. The input model is not modified. On the API level the algorithm is implemented in the class *BRepAlgoAPI_Defeaturing*. The actual features removal is performed by the low-level algorithm *BOPAlgo_RemoveFeatures*. Documentation of the new classes. Implementation of the DRAW commands for working with new algorithm. Test cases for the new functionality. Changes in other algorithms used by De-featuring algorithm: - Provide history support for the solids in *ShapeUpgrade_UnifySameDomain* algorithm; - Implementation of the mechanism to merge History of any Algorithm with standard history methods such as IsDeleted(), Modified() and Generated() into *BRepTools_History*.
1856 lines
65 KiB
C++
1856 lines
65 KiB
C++
// Created on: 2012-06-09
|
|
// Created by: jgv@ROLEX
|
|
// Copyright (c) 2012-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 <BRep_Builder.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
#include <BRepLib.hxx>
|
|
#include <BRepLib_MakeEdge.hxx>
|
|
#include <BRepTopAdaptor_TopolTool.hxx>
|
|
#include <GC_MakeCircle.hxx>
|
|
#include <Geom2d_Line.hxx>
|
|
#include <Geom2d_TrimmedCurve.hxx>
|
|
#include <Geom2dConvert.hxx>
|
|
#include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
|
|
#include <Geom_BezierCurve.hxx>
|
|
#include <Geom_BSplineCurve.hxx>
|
|
#include <Geom_Circle.hxx>
|
|
#include <Geom_CylindricalSurface.hxx>
|
|
#include <Geom_ElementarySurface.hxx>
|
|
#include <Geom_Line.hxx>
|
|
#include <Geom_OffsetSurface.hxx>
|
|
#include <Geom_Plane.hxx>
|
|
#include <Geom_RectangularTrimmedSurface.hxx>
|
|
#include <Geom_Surface.hxx>
|
|
#include <Geom_SurfaceOfLinearExtrusion.hxx>
|
|
#include <Geom_SurfaceOfRevolution.hxx>
|
|
#include <Geom_SweptSurface.hxx>
|
|
#include <Geom_TrimmedCurve.hxx>
|
|
#include <GeomAdaptor_HSurface.hxx>
|
|
#include <GeomConvert.hxx>
|
|
#include <GeomConvert_CompCurveToBSplineCurve.hxx>
|
|
#include <GeomLib_IsPlanarSurface.hxx>
|
|
#include <gp_Cylinder.hxx>
|
|
#include <gp_Dir.hxx>
|
|
#include <gp_Lin.hxx>
|
|
#include <IntPatch_ImpImpIntersection.hxx>
|
|
#include <ShapeAnalysis_Edge.hxx>
|
|
#include <ShapeAnalysis_WireOrder.hxx>
|
|
#include <ShapeBuild_Edge.hxx>
|
|
#include <ShapeBuild_ReShape.hxx>
|
|
#include <ShapeFix_Edge.hxx>
|
|
#include <ShapeFix_Face.hxx>
|
|
#include <ShapeFix_Shell.hxx>
|
|
#include <ShapeFix_Wire.hxx>
|
|
#include <ShapeUpgrade_UnifySameDomain.hxx>
|
|
#include <Standard_Type.hxx>
|
|
#include <TColGeom2d_Array1OfBSplineCurve.hxx>
|
|
#include <TColGeom2d_HArray1OfBSplineCurve.hxx>
|
|
#include <TColGeom2d_SequenceOfBoundedCurve.hxx>
|
|
#include <TColGeom_Array1OfBSplineCurve.hxx>
|
|
#include <TColGeom_HArray1OfBSplineCurve.hxx>
|
|
#include <TColGeom_SequenceOfSurface.hxx>
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
#include <TColStd_MapOfInteger.hxx>
|
|
#include <TopExp.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Face.hxx>
|
|
#include <TopoDS_Shape.hxx>
|
|
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
|
#include <TopTools_IndexedMapOfShape.hxx>
|
|
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
|
#include <TopTools_MapOfShape.hxx>
|
|
#include <TopTools_SequenceOfShape.hxx>
|
|
#include <gp_Circ.hxx>
|
|
#include <BRepAdaptor_Curve.hxx>
|
|
#include <BRepAdaptor_Curve2d.hxx>
|
|
#include <gp_Vec2d.hxx>
|
|
|
|
IMPLEMENT_STANDARD_RTTIEXT(ShapeUpgrade_UnifySameDomain,Standard_Transient)
|
|
|
|
struct SubSequenceOfEdges
|
|
{
|
|
TopTools_SequenceOfShape SeqsEdges;
|
|
TopoDS_Edge UnionEdges;
|
|
};
|
|
|
|
static Standard_Boolean IsLikeSeam(const TopoDS_Edge& anEdge,
|
|
const TopoDS_Face& aFace,
|
|
const Handle(Geom_Surface)& aBaseSurface)
|
|
{
|
|
if (!aBaseSurface->IsUPeriodic() && !aBaseSurface->IsVPeriodic())
|
|
return Standard_False;
|
|
|
|
BRepAdaptor_Curve2d BAcurve2d(anEdge, aFace);
|
|
gp_Pnt2d FirstPoint, LastPoint;
|
|
gp_Vec2d FirstDir, LastDir;
|
|
BAcurve2d.D1(BAcurve2d.FirstParameter(), FirstPoint, FirstDir);
|
|
BAcurve2d.D1(BAcurve2d.LastParameter(), LastPoint, LastDir);
|
|
Standard_Real Length = FirstDir.Magnitude();
|
|
if (Length <= gp::Resolution())
|
|
return Standard_False;
|
|
else
|
|
FirstDir /= Length;
|
|
Length = LastDir.Magnitude();
|
|
if (Length <= gp::Resolution())
|
|
return Standard_False;
|
|
else
|
|
LastDir /= Length;
|
|
|
|
Standard_Real Tol = 1.e-7;
|
|
if (aBaseSurface->IsUPeriodic() &&
|
|
(Abs(FirstDir.X()) < Tol) &&
|
|
(Abs(LastDir.X()) < Tol))
|
|
return Standard_True;
|
|
|
|
if (aBaseSurface->IsVPeriodic() &&
|
|
(Abs(FirstDir.Y()) < Tol) &&
|
|
(Abs(LastDir.Y()) < Tol))
|
|
return Standard_True;
|
|
|
|
return Standard_False;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : AddOrdinaryEdges
|
|
//purpose : auxilary
|
|
//=======================================================================
|
|
// adds edges from the shape to the sequence
|
|
// seams and equal edges are dropped
|
|
// Returns true if one of original edges dropped
|
|
static Standard_Boolean AddOrdinaryEdges(TopTools_SequenceOfShape& edges,
|
|
const TopoDS_Shape aShape,
|
|
Standard_Integer& anIndex)
|
|
{
|
|
//map of edges
|
|
TopTools_IndexedMapOfShape aNewEdges;
|
|
//add edges without seams
|
|
for(TopExp_Explorer exp(aShape,TopAbs_EDGE); exp.More(); exp.Next()) {
|
|
TopoDS_Shape edge = exp.Current();
|
|
if(aNewEdges.Contains(edge))
|
|
aNewEdges.RemoveKey(edge);
|
|
else
|
|
aNewEdges.Add(edge);
|
|
}
|
|
|
|
Standard_Boolean isDropped = Standard_False;
|
|
//merge edges and drop seams
|
|
Standard_Integer i;
|
|
for (i = 1; i <= edges.Length(); i++) {
|
|
TopoDS_Shape current = edges(i);
|
|
if(aNewEdges.Contains(current)) {
|
|
|
|
aNewEdges.RemoveKey(current);
|
|
edges.Remove(i);
|
|
i--;
|
|
|
|
if(!isDropped) {
|
|
isDropped = Standard_True;
|
|
anIndex = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
//add edges to the sequence
|
|
for (i = 1; i <= aNewEdges.Extent(); i++)
|
|
edges.Append(aNewEdges(i));
|
|
|
|
return isDropped;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : getCylinder
|
|
//purpose : auxilary
|
|
//=======================================================================
|
|
static Standard_Boolean getCylinder(Handle(Geom_Surface)& theInSurface,
|
|
gp_Cylinder& theOutCylinder)
|
|
{
|
|
Standard_Boolean isCylinder = Standard_False;
|
|
|
|
if (theInSurface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface))) {
|
|
Handle(Geom_CylindricalSurface) aGC = Handle(Geom_CylindricalSurface)::DownCast(theInSurface);
|
|
|
|
theOutCylinder = aGC->Cylinder();
|
|
isCylinder = Standard_True;
|
|
}
|
|
else if (theInSurface->IsKind(STANDARD_TYPE(Geom_SurfaceOfRevolution))) {
|
|
Handle(Geom_SurfaceOfRevolution) aRS =
|
|
Handle(Geom_SurfaceOfRevolution)::DownCast(theInSurface);
|
|
Handle(Geom_Curve) aBasis = aRS->BasisCurve();
|
|
if (aBasis->IsKind(STANDARD_TYPE(Geom_Line))) {
|
|
Handle(Geom_Line) aBasisLine = Handle(Geom_Line)::DownCast(aBasis);
|
|
gp_Dir aDir = aRS->Direction();
|
|
gp_Dir aBasisDir = aBasisLine->Position().Direction();
|
|
if (aBasisDir.IsParallel(aDir, Precision::Angular())) {
|
|
// basis line is parallel to the revolution axis: it is a cylinder
|
|
gp_Pnt aLoc = aRS->Location();
|
|
Standard_Real aR = aBasisLine->Lin().Distance(aLoc);
|
|
gp_Ax3 aCylAx (aLoc, aDir);
|
|
|
|
theOutCylinder = gp_Cylinder(aCylAx, aR);
|
|
isCylinder = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
else if (theInSurface->IsKind(STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion))) {
|
|
Handle(Geom_SurfaceOfLinearExtrusion) aLES =
|
|
Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(theInSurface);
|
|
Handle(Geom_Curve) aBasis = aLES->BasisCurve();
|
|
if (aBasis->IsKind(STANDARD_TYPE(Geom_Circle))) {
|
|
Handle(Geom_Circle) aBasisCircle = Handle(Geom_Circle)::DownCast(aBasis);
|
|
gp_Dir aDir = aLES->Direction();
|
|
gp_Dir aBasisDir = aBasisCircle->Position().Direction();
|
|
if (aBasisDir.IsParallel(aDir, Precision::Angular())) {
|
|
// basis circle is normal to the extrusion axis: it is a cylinder
|
|
gp_Pnt aLoc = aBasisCircle->Location();
|
|
Standard_Real aR = aBasisCircle->Radius();
|
|
gp_Ax3 aCylAx (aLoc, aDir);
|
|
|
|
theOutCylinder = gp_Cylinder(aCylAx, aR);
|
|
isCylinder = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
}
|
|
|
|
return isCylinder;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : ClearRts
|
|
//purpose : auxilary
|
|
//=======================================================================
|
|
static Handle(Geom_Surface) ClearRts(const Handle(Geom_Surface)& aSurface)
|
|
{
|
|
if(aSurface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
|
|
Handle(Geom_RectangularTrimmedSurface) rts =
|
|
Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
|
|
return rts->BasisSurface();
|
|
}
|
|
return aSurface;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetNormalToSurface
|
|
//purpose : Gets the normal to surface by the given parameter on edge.
|
|
// Returns True if normal was computed.
|
|
//=======================================================================
|
|
static Standard_Boolean GetNormalToSurface(const TopoDS_Face& theFace,
|
|
const TopoDS_Edge& theEdge,
|
|
const Standard_Real theP,
|
|
gp_Dir& theNormal)
|
|
{
|
|
Standard_Real f, l;
|
|
// get 2d curve to get point in 2d
|
|
const Handle(Geom2d_Curve)& aC2d = BRep_Tool::CurveOnSurface(theEdge, theFace, f, l);
|
|
if (aC2d.IsNull()) {
|
|
return Standard_False;
|
|
}
|
|
//
|
|
// 2d point
|
|
gp_Pnt2d aP2d;
|
|
aC2d->D0(theP, aP2d);
|
|
//
|
|
// get D1
|
|
gp_Vec aDU, aDV;
|
|
gp_Pnt aP3d;
|
|
TopLoc_Location aLoc;
|
|
const Handle(Geom_Surface)& aS = BRep_Tool::Surface(theFace, aLoc);
|
|
aS->D1(aP2d.X(), aP2d.Y(), aP3d, aDU, aDV);
|
|
//
|
|
// compute normal
|
|
gp_Vec aVNormal = aDU.Crossed(aDV);
|
|
if (aVNormal.Magnitude() < Precision::Confusion()) {
|
|
return Standard_False;
|
|
}
|
|
//
|
|
if (theFace.Orientation() == TopAbs_REVERSED) {
|
|
aVNormal.Reverse();
|
|
}
|
|
//
|
|
aVNormal.Transform(aLoc.Transformation());
|
|
theNormal = gp_Dir(aVNormal);
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IsSameDomain
|
|
//purpose :
|
|
//=======================================================================
|
|
static Standard_Boolean IsSameDomain(const TopoDS_Face& aFace,
|
|
const TopoDS_Face& aCheckedFace,
|
|
const Standard_Real theLinTol,
|
|
const Standard_Real theAngTol)
|
|
{
|
|
//checking the same handles
|
|
TopLoc_Location L1, L2;
|
|
Handle(Geom_Surface) S1, S2;
|
|
|
|
S1 = BRep_Tool::Surface(aFace,L1);
|
|
S2 = BRep_Tool::Surface(aCheckedFace,L2);
|
|
|
|
if (S1 == S2 && L1 == L2)
|
|
return Standard_True;
|
|
|
|
S1 = BRep_Tool::Surface(aFace);
|
|
S2 = BRep_Tool::Surface(aCheckedFace);
|
|
|
|
S1 = ClearRts(S1);
|
|
S2 = ClearRts(S2);
|
|
|
|
//Handle(Geom_OffsetSurface) aGOFS1, aGOFS2;
|
|
//aGOFS1 = Handle(Geom_OffsetSurface)::DownCast(S1);
|
|
//aGOFS2 = Handle(Geom_OffsetSurface)::DownCast(S2);
|
|
//if (!aGOFS1.IsNull()) S1 = aGOFS1->BasisSurface();
|
|
//if (!aGOFS2.IsNull()) S2 = aGOFS2->BasisSurface();
|
|
|
|
// case of two planar surfaces:
|
|
// all kinds of surfaces checked, including b-spline and bezier
|
|
GeomLib_IsPlanarSurface aPlanarityChecker1(S1, theLinTol);
|
|
if (aPlanarityChecker1.IsPlanar()) {
|
|
GeomLib_IsPlanarSurface aPlanarityChecker2(S2, theLinTol);
|
|
if (aPlanarityChecker2.IsPlanar()) {
|
|
gp_Pln aPln1 = aPlanarityChecker1.Plan();
|
|
gp_Pln aPln2 = aPlanarityChecker2.Plan();
|
|
|
|
if (aPln1.Position().Direction().IsParallel(aPln2.Position().Direction(), theAngTol) &&
|
|
aPln1.Distance(aPln2) < theLinTol) {
|
|
return Standard_True;
|
|
}
|
|
}
|
|
}
|
|
|
|
// case of two elementary surfaces: use OCCT tool
|
|
// elementary surfaces: ConicalSurface, CylindricalSurface,
|
|
// Plane, SphericalSurface and ToroidalSurface
|
|
if (S1->IsKind(STANDARD_TYPE(Geom_ElementarySurface)) &&
|
|
S2->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
|
|
{
|
|
Handle(GeomAdaptor_HSurface) aGA1 = new GeomAdaptor_HSurface(S1);
|
|
Handle(GeomAdaptor_HSurface) aGA2 = new GeomAdaptor_HSurface(S2);
|
|
|
|
Handle(BRepTopAdaptor_TopolTool) aTT1 = new BRepTopAdaptor_TopolTool();
|
|
Handle(BRepTopAdaptor_TopolTool) aTT2 = new BRepTopAdaptor_TopolTool();
|
|
|
|
try {
|
|
IntPatch_ImpImpIntersection anIIInt(aGA1, aTT1, aGA2, aTT2, theLinTol, theLinTol);
|
|
if (!anIIInt.IsDone() || anIIInt.IsEmpty())
|
|
return Standard_False;
|
|
|
|
return anIIInt.TangentFaces();
|
|
}
|
|
catch (Standard_Failure) {
|
|
return Standard_False;
|
|
}
|
|
}
|
|
|
|
// case of two cylindrical surfaces, at least one of which is a swept surface
|
|
// swept surfaces: SurfaceOfLinearExtrusion, SurfaceOfRevolution
|
|
if ((S1->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ||
|
|
S1->IsKind(STANDARD_TYPE(Geom_SweptSurface))) &&
|
|
(S2->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ||
|
|
S2->IsKind(STANDARD_TYPE(Geom_SweptSurface))))
|
|
{
|
|
gp_Cylinder aCyl1, aCyl2;
|
|
if (getCylinder(S1, aCyl1) && getCylinder(S2, aCyl2)) {
|
|
if (fabs(aCyl1.Radius() - aCyl2.Radius()) < theLinTol) {
|
|
gp_Dir aDir1 = aCyl1.Position().Direction();
|
|
gp_Dir aDir2 = aCyl2.Position().Direction();
|
|
if (aDir1.IsParallel(aDir2, Precision::Angular())) {
|
|
gp_Pnt aLoc1 = aCyl1.Location();
|
|
gp_Pnt aLoc2 = aCyl2.Location();
|
|
gp_Vec aVec12 (aLoc1, aLoc2);
|
|
if (aVec12.SquareMagnitude() < theLinTol*theLinTol ||
|
|
aVec12.IsParallel(aDir1, Precision::Angular())) {
|
|
return Standard_True;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Standard_False;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : UpdateMapOfShapes
|
|
//purpose :
|
|
//=======================================================================
|
|
static void UpdateMapOfShapes(TopTools_MapOfShape& theMapOfShapes,
|
|
Handle(ShapeBuild_ReShape)& theContext)
|
|
{
|
|
for (TopTools_MapIteratorOfMapOfShape it(theMapOfShapes); it.More(); it.Next()) {
|
|
const TopoDS_Shape& aShape = it.Value();
|
|
TopoDS_Shape aContextShape = theContext->Apply(aShape);
|
|
if (!aContextShape.IsSame(aShape))
|
|
theMapOfShapes.Add(aContextShape);
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GlueEdgesWithPCurves
|
|
//purpose : Glues the pcurves of the sequence of edges
|
|
// and glues their 3d curves
|
|
//=======================================================================
|
|
static TopoDS_Edge GlueEdgesWithPCurves(const TopTools_SequenceOfShape& aChain,
|
|
const TopoDS_Vertex& FirstVertex,
|
|
const TopoDS_Vertex& LastVertex)
|
|
{
|
|
Standard_Integer i, j;
|
|
|
|
TopoDS_Edge FirstEdge = TopoDS::Edge(aChain(1));
|
|
TColGeom_SequenceOfSurface SurfSeq;
|
|
NCollection_Sequence<TopLoc_Location> LocSeq;
|
|
|
|
for (int aCurveIndex = 0;; aCurveIndex++)
|
|
{
|
|
Handle(Geom2d_Curve) aCurve;
|
|
Handle(Geom_Surface) aSurface;
|
|
TopLoc_Location aLocation;
|
|
Standard_Real aFirst, aLast;
|
|
BRep_Tool::CurveOnSurface (FirstEdge, aCurve, aSurface, aLocation, aFirst, aLast, aCurveIndex);
|
|
if (aCurve.IsNull())
|
|
break;
|
|
|
|
SurfSeq.Append(aSurface);
|
|
LocSeq.Append(aLocation);
|
|
}
|
|
|
|
Standard_Real fpar, lpar;
|
|
BRep_Tool::Range(FirstEdge, fpar, lpar);
|
|
TopoDS_Edge PrevEdge = FirstEdge;
|
|
TopoDS_Vertex CV;
|
|
Standard_Real MaxTol = 0.;
|
|
|
|
TopoDS_Edge ResEdge;
|
|
BRep_Builder BB;
|
|
|
|
Standard_Integer nb_curve = aChain.Length(); //number of curves
|
|
TColGeom_Array1OfBSplineCurve tab_c3d(0,nb_curve-1); //array of the curves
|
|
TColStd_Array1OfReal tabtolvertex(0,nb_curve-1); //(0,nb_curve-2); //array of the tolerances
|
|
|
|
TopoDS_Vertex PrevVertex = FirstVertex;
|
|
for (i = 1; i <= nb_curve; i++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(aChain(i));
|
|
TopoDS_Vertex VF, VL;
|
|
TopExp::Vertices(anEdge, VF, VL);
|
|
Standard_Boolean ToReverse = (!VF.IsSame(PrevVertex));
|
|
|
|
Standard_Real Tol1 = BRep_Tool::Tolerance(VF);
|
|
Standard_Real Tol2 = BRep_Tool::Tolerance(VL);
|
|
if (Tol1 > MaxTol)
|
|
MaxTol = Tol1;
|
|
if (Tol2 > MaxTol)
|
|
MaxTol = Tol2;
|
|
|
|
if (i > 1)
|
|
{
|
|
TopExp::CommonVertex(PrevEdge, anEdge, CV);
|
|
Standard_Real Tol = BRep_Tool::Tolerance(CV);
|
|
tabtolvertex(i-2) = Tol;
|
|
}
|
|
|
|
Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, fpar, lpar);
|
|
Handle(Geom_TrimmedCurve) aTrCurve = new Geom_TrimmedCurve(aCurve, fpar, lpar);
|
|
tab_c3d(i-1) = GeomConvert::CurveToBSplineCurve(aTrCurve);
|
|
GeomConvert::C0BSplineToC1BSplineCurve(tab_c3d(i-1), Precision::Confusion());
|
|
if (ToReverse)
|
|
tab_c3d(i-1)->Reverse();
|
|
PrevVertex = (ToReverse)? VF : VL;
|
|
PrevEdge = anEdge;
|
|
}
|
|
Handle(TColGeom_HArray1OfBSplineCurve) concatcurve; //array of the concatenated curves
|
|
Handle(TColStd_HArray1OfInteger) ArrayOfIndices; //array of the remining Vertex
|
|
GeomConvert::ConcatC1(tab_c3d,
|
|
tabtolvertex,
|
|
ArrayOfIndices,
|
|
concatcurve,
|
|
Standard_False,
|
|
Precision::Confusion()); //C1 concatenation
|
|
|
|
if (concatcurve->Length() > 1)
|
|
{
|
|
GeomConvert_CompCurveToBSplineCurve Concat(concatcurve->Value(concatcurve->Lower()));
|
|
|
|
for (i = concatcurve->Lower()+1; i <= concatcurve->Upper(); i++)
|
|
Concat.Add( concatcurve->Value(i), MaxTol, Standard_True );
|
|
|
|
concatcurve->SetValue(concatcurve->Lower(), Concat.BSplineCurve());
|
|
}
|
|
Handle(Geom_BSplineCurve) ResCurve = concatcurve->Value(concatcurve->Lower());
|
|
|
|
TColGeom2d_SequenceOfBoundedCurve ResPCurves;
|
|
for (j = 1; j <= SurfSeq.Length(); j++)
|
|
{
|
|
TColGeom2d_Array1OfBSplineCurve tab_c2d(0,nb_curve-1); //array of the pcurves
|
|
|
|
PrevVertex = FirstVertex;
|
|
PrevEdge = FirstEdge;
|
|
for (i = 1; i <= nb_curve; i++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(aChain(i));
|
|
TopoDS_Vertex VF, VL;
|
|
TopExp::Vertices(anEdge, VF, VL);
|
|
Standard_Boolean ToReverse = (!VF.IsSame(PrevVertex));
|
|
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, SurfSeq(j), LocSeq(j), fpar, lpar);
|
|
if (aPCurve.IsNull())
|
|
continue;
|
|
Handle(Geom2d_TrimmedCurve) aTrPCurve = new Geom2d_TrimmedCurve(aPCurve, fpar, lpar);
|
|
tab_c2d(i-1) = Geom2dConvert::CurveToBSplineCurve(aTrPCurve);
|
|
Geom2dConvert::C0BSplineToC1BSplineCurve(tab_c2d(i-1), Precision::Confusion());
|
|
if (ToReverse)
|
|
tab_c2d(i-1)->Reverse();
|
|
PrevVertex = (ToReverse)? VF : VL;
|
|
PrevEdge = anEdge;
|
|
}
|
|
Handle(TColGeom2d_HArray1OfBSplineCurve) concatc2d; //array of the concatenated curves
|
|
Handle(TColStd_HArray1OfInteger) ArrayOfInd2d; //array of the remining Vertex
|
|
Geom2dConvert::ConcatC1(tab_c2d,
|
|
tabtolvertex,
|
|
ArrayOfInd2d,
|
|
concatc2d,
|
|
Standard_False,
|
|
Precision::Confusion()); //C1 concatenation
|
|
|
|
if (concatc2d->Length() > 1)
|
|
{
|
|
Geom2dConvert_CompCurveToBSplineCurve Concat2d(concatc2d->Value(concatc2d->Lower()));
|
|
|
|
for (i = concatc2d->Lower()+1; i <= concatc2d->Upper(); i++)
|
|
Concat2d.Add( concatc2d->Value(i), MaxTol, Standard_True );
|
|
|
|
concatc2d->SetValue(concatc2d->Lower(), Concat2d.BSplineCurve());
|
|
}
|
|
Handle(Geom2d_BSplineCurve) aResPCurve = concatc2d->Value(concatc2d->Lower());
|
|
ResPCurves.Append(aResPCurve);
|
|
}
|
|
|
|
ResEdge = BRepLib_MakeEdge(ResCurve,
|
|
FirstVertex, LastVertex,
|
|
ResCurve->FirstParameter(), ResCurve->LastParameter());
|
|
BB.SameRange(ResEdge, Standard_False);
|
|
BB.SameParameter(ResEdge, Standard_False);
|
|
for (j = 1; j <= ResPCurves.Length(); j++)
|
|
{
|
|
BB.UpdateEdge(ResEdge, ResPCurves(j), SurfSeq(j), LocSeq(j), MaxTol);
|
|
BB.Range(ResEdge, SurfSeq(j), LocSeq(j), ResPCurves(j)->FirstParameter(), ResPCurves(j)->LastParameter());
|
|
}
|
|
|
|
BRepLib::SameParameter(ResEdge, MaxTol, Standard_True);
|
|
|
|
return ResEdge;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MergeSubSeq
|
|
//purpose : Merges a sequence of edges into one edge if possible
|
|
//=======================================================================
|
|
|
|
static Standard_Boolean MergeSubSeq(const TopTools_SequenceOfShape& aChain,
|
|
TopoDS_Edge& OutEdge,
|
|
double theAngTol,
|
|
Standard_Boolean ConcatBSplines,
|
|
Standard_Boolean isSafeInputMode,
|
|
Handle(ShapeBuild_ReShape)& theContext)
|
|
{
|
|
ShapeAnalysis_Edge sae;
|
|
BRep_Builder B;
|
|
// union edges in chain
|
|
int j;
|
|
Standard_Real fp1,lp1,fp2,lp2;
|
|
Standard_Boolean IsUnionOfLinesPossible = Standard_True;
|
|
Standard_Boolean IsUnionOfCirclesPossible = Standard_True;
|
|
Handle(Geom_Curve) c3d1, c3d2;
|
|
for(j=1; j<aChain.Length(); j++)
|
|
{
|
|
TopoDS_Edge edge1 = TopoDS::Edge(aChain.Value(j));
|
|
c3d1 = BRep_Tool::Curve(edge1,fp1,lp1);
|
|
|
|
TopoDS_Edge edge2 = TopoDS::Edge(aChain.Value(j+1));
|
|
c3d2 = BRep_Tool::Curve(edge2,fp2,lp2);
|
|
|
|
if(c3d1.IsNull() || c3d2.IsNull())
|
|
return Standard_False;
|
|
|
|
while(c3d1->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
|
|
Handle(Geom_TrimmedCurve) tc =
|
|
Handle(Geom_TrimmedCurve)::DownCast(c3d1);
|
|
c3d1 = tc->BasisCurve();
|
|
}
|
|
while(c3d2->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
|
|
Handle(Geom_TrimmedCurve) tc =
|
|
Handle(Geom_TrimmedCurve)::DownCast(c3d2);
|
|
c3d2 = tc->BasisCurve();
|
|
}
|
|
if( c3d1->IsKind(STANDARD_TYPE(Geom_Line)) && c3d2->IsKind(STANDARD_TYPE(Geom_Line)) ) {
|
|
Handle(Geom_Line) L1 = Handle(Geom_Line)::DownCast(c3d1);
|
|
Handle(Geom_Line) L2 = Handle(Geom_Line)::DownCast(c3d2);
|
|
gp_Dir Dir1 = L1->Position().Direction();
|
|
gp_Dir Dir2 = L2->Position().Direction();
|
|
if(!Dir1.IsParallel(Dir2,theAngTol))
|
|
IsUnionOfLinesPossible = Standard_False;
|
|
}
|
|
else
|
|
IsUnionOfLinesPossible = Standard_False;
|
|
if( c3d1->IsKind(STANDARD_TYPE(Geom_Circle)) && c3d2->IsKind(STANDARD_TYPE(Geom_Circle)) ) {
|
|
Handle(Geom_Circle) C1 = Handle(Geom_Circle)::DownCast(c3d1);
|
|
Handle(Geom_Circle) C2 = Handle(Geom_Circle)::DownCast(c3d2);
|
|
gp_Pnt P01 = C1->Location();
|
|
gp_Pnt P02 = C2->Location();
|
|
if (P01.Distance(P02) > Precision::Confusion())
|
|
IsUnionOfCirclesPossible = Standard_False;
|
|
}
|
|
else
|
|
IsUnionOfCirclesPossible = Standard_False;
|
|
}
|
|
if (IsUnionOfLinesPossible && IsUnionOfCirclesPossible)
|
|
return Standard_False;
|
|
|
|
//union of lines is possible
|
|
if (IsUnionOfLinesPossible)
|
|
{
|
|
TopoDS_Vertex V[2];
|
|
V[0] = sae.FirstVertex(TopoDS::Edge(aChain.First()));
|
|
gp_Pnt PV1 = BRep_Tool::Pnt(V[0]);
|
|
V[1] = sae.LastVertex(TopoDS::Edge(aChain.Last()));
|
|
gp_Pnt PV2 = BRep_Tool::Pnt(V[1]);
|
|
gp_Vec Vec(PV1, PV2);
|
|
if (isSafeInputMode) {
|
|
for (int k = 0; k < 2; k++) {
|
|
if (!theContext->IsRecorded(V[k])) {
|
|
TopoDS_Vertex Vcopy = TopoDS::Vertex(V[k].EmptyCopied());
|
|
theContext->Replace(V[k], Vcopy);
|
|
V[k] = Vcopy;
|
|
}
|
|
else
|
|
V[k] = TopoDS::Vertex(theContext->Apply(V[k]));
|
|
}
|
|
}
|
|
Handle(Geom_Line) L = new Geom_Line(gp_Ax1(PV1,Vec));
|
|
Standard_Real dist = PV1.Distance(PV2);
|
|
Handle(Geom_TrimmedCurve) tc = new Geom_TrimmedCurve(L,0.0,dist);
|
|
TopoDS_Edge E;
|
|
B.MakeEdge (E, tc ,Precision::Confusion());
|
|
B.Add (E,V[0]); B.Add (E,V[1]);
|
|
B.UpdateVertex(V[0], 0., E, 0.);
|
|
B.UpdateVertex(V[1], dist, E, 0.);
|
|
OutEdge = E;
|
|
return Standard_True;
|
|
}
|
|
|
|
if (IsUnionOfCirclesPossible)
|
|
{
|
|
double f,l;
|
|
TopoDS_Edge FE = TopoDS::Edge(aChain.First());
|
|
Handle(Geom_Curve) c3d = BRep_Tool::Curve(FE,f,l);
|
|
|
|
while(c3d->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
|
|
Handle(Geom_TrimmedCurve) tc =
|
|
Handle(Geom_TrimmedCurve)::DownCast(c3d);
|
|
c3d = tc->BasisCurve();
|
|
}
|
|
Handle(Geom_Circle) Cir = Handle(Geom_Circle)::DownCast(c3d);
|
|
|
|
TopoDS_Vertex V[2];
|
|
V[0] = sae.FirstVertex(FE);
|
|
V[1] = sae.LastVertex(TopoDS::Edge(aChain.Last()));
|
|
TopoDS_Edge E;
|
|
if (V[0].IsSame(V[1])) {
|
|
// closed chain
|
|
BRepAdaptor_Curve adef(FE);
|
|
Handle(Geom_Circle) Cir1;
|
|
double FP, LP;
|
|
if ( FE.Orientation() == TopAbs_FORWARD)
|
|
{
|
|
FP = adef.FirstParameter();
|
|
LP = adef.LastParameter();
|
|
}
|
|
else
|
|
{
|
|
FP = adef.LastParameter();
|
|
LP = adef.FirstParameter();
|
|
}
|
|
if (Abs(FP) < Precision::PConfusion())
|
|
{
|
|
B.MakeEdge (E,Cir, Precision::Confusion());
|
|
B.Add(E,V[0]);
|
|
B.Add(E,V[1]);
|
|
E.Orientation(FE.Orientation());
|
|
}
|
|
else
|
|
{
|
|
GC_MakeCircle MC1 (adef.Value(FP), adef.Value((FP + LP) * 0.5), adef.Value(LP));
|
|
if (MC1.IsDone())
|
|
Cir1 = MC1.Value();
|
|
else
|
|
return Standard_False;
|
|
B.MakeEdge (E, Cir1, Precision::Confusion());
|
|
B.Add(E,V[0]);
|
|
B.Add(E,V[1]);
|
|
}
|
|
}
|
|
else {
|
|
if (isSafeInputMode) {
|
|
for (int k = 0; k < 2; k++) {
|
|
if (!theContext->IsRecorded(V[k])) {
|
|
TopoDS_Vertex Vcopy = TopoDS::Vertex(V[k].EmptyCopied());
|
|
theContext->Replace(V[k], Vcopy);
|
|
V[k] = Vcopy;
|
|
}
|
|
else
|
|
V[k] = TopoDS::Vertex(theContext->Apply(V[k]));
|
|
}
|
|
}
|
|
gp_Pnt PV1 = BRep_Tool::Pnt(V[0]);
|
|
gp_Pnt PV2 = BRep_Tool::Pnt(V[1]);
|
|
TopoDS_Vertex VM = sae.LastVertex(FE);
|
|
gp_Pnt PVM = BRep_Tool::Pnt(VM);
|
|
GC_MakeCircle MC (PV1,PVM,PV2);
|
|
Handle(Geom_Circle) C = MC.Value();
|
|
gp_Pnt P0 = C->Location();
|
|
gp_Dir D1(gp_Vec(P0,PV1));
|
|
gp_Dir D2(gp_Vec(P0,PV2));
|
|
Standard_Real fpar = C->XAxis().Direction().Angle(D1);
|
|
if(fabs(fpar)>Precision::Confusion()) {
|
|
// check orientation
|
|
gp_Dir ND = C->XAxis().Direction().Crossed(D1);
|
|
if(ND.IsOpposite(C->Axis().Direction(),Precision::Confusion())) {
|
|
fpar = -fpar;
|
|
}
|
|
}
|
|
Standard_Real lpar = C->XAxis().Direction().Angle(D2);
|
|
if(fabs(lpar)>Precision::Confusion()) {
|
|
// check orientation
|
|
gp_Dir ND = C->XAxis().Direction().Crossed(D2);
|
|
if(ND.IsOpposite(C->Axis().Direction(),Precision::Confusion())) {
|
|
lpar = -lpar;
|
|
}
|
|
}
|
|
if (lpar < fpar) lpar += 2*M_PI;
|
|
Handle(Geom_TrimmedCurve) tc = new Geom_TrimmedCurve(C,fpar,lpar);
|
|
B.MakeEdge (E,tc,Precision::Confusion());
|
|
B.Add(E,V[0]);
|
|
B.Add(E,V[1]);
|
|
B.UpdateVertex(V[0], fpar, E, 0.);
|
|
B.UpdateVertex(V[1], lpar, E, 0.);
|
|
}
|
|
OutEdge = E;
|
|
return Standard_True;
|
|
}
|
|
if (aChain.Length() > 1 && ConcatBSplines) {
|
|
// second step: union edges with various curves
|
|
// skl for bug 0020052 from Mantis: perform such unions
|
|
// only if curves are bspline or bezier
|
|
|
|
TopoDS_Vertex VF = sae.FirstVertex(TopoDS::Edge(aChain.First()));
|
|
TopoDS_Vertex VL = sae.LastVertex(TopoDS::Edge(aChain.Last()));
|
|
Standard_Boolean NeedUnion = Standard_True;
|
|
for(j=1; j<=aChain.Length(); j++) {
|
|
TopoDS_Edge edge = TopoDS::Edge(aChain.Value(j));
|
|
TopLoc_Location Loc;
|
|
Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge,Loc,fp1,lp1);
|
|
if(c3d.IsNull()) continue;
|
|
while(c3d->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
|
|
Handle(Geom_TrimmedCurve) tc =
|
|
Handle(Geom_TrimmedCurve)::DownCast(c3d);
|
|
c3d = tc->BasisCurve();
|
|
}
|
|
if( ( c3d->IsKind(STANDARD_TYPE(Geom_BSplineCurve)) ||
|
|
c3d->IsKind(STANDARD_TYPE(Geom_BezierCurve)) ) ) continue;
|
|
NeedUnion = Standard_False;
|
|
break;
|
|
}
|
|
if(NeedUnion) {
|
|
#ifdef OCCT_DEBUG
|
|
cout<<"can not make analitical union => make approximation"<<endl;
|
|
#endif
|
|
TopoDS_Edge E = GlueEdgesWithPCurves(aChain, VF, VL);
|
|
OutEdge = E;
|
|
return Standard_True;
|
|
}
|
|
else {
|
|
#ifdef OCCT_DEBUG
|
|
cout<<"can not make approximation for such types of curves"<<endl;
|
|
#endif
|
|
return Standard_False;
|
|
}
|
|
}
|
|
return Standard_False;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IsMergingPossible
|
|
//purpose : Checks if merging of two edges is possible
|
|
//=======================================================================
|
|
|
|
static Standard_Boolean IsMergingPossible(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2,
|
|
double theAngTol, double theLinTol,
|
|
const TopTools_MapOfShape& AvoidEdgeVrt, const bool theLineDirectionOk,
|
|
const gp_Pnt& theFirstPoint, const gp_Vec& theDirectionVec)
|
|
{
|
|
TopoDS_Vertex CV = TopExp::LastVertex(edge1, Standard_True);
|
|
if (CV.IsNull() || AvoidEdgeVrt.Contains(CV))
|
|
return Standard_False;
|
|
|
|
BRepAdaptor_Curve ade1(edge1);
|
|
BRepAdaptor_Curve ade2(edge2);
|
|
|
|
GeomAbs_CurveType t1 = ade1.GetType();
|
|
GeomAbs_CurveType t2 = ade2.GetType();
|
|
|
|
if( t1 == GeomAbs_Circle && t2 == GeomAbs_Circle)
|
|
{
|
|
if (ade1.Circle().Location().Distance(ade2.Circle().Location()) > Precision::Confusion())
|
|
return Standard_False;
|
|
}
|
|
|
|
if( ( (t1 != GeomAbs_BezierCurve && t1 != GeomAbs_BSplineCurve) ||
|
|
(t2 != GeomAbs_BezierCurve && t2 != GeomAbs_BSplineCurve)) && t1 != t2)
|
|
return Standard_False;
|
|
|
|
gp_Vec Diff1, Diff2;
|
|
gp_Pnt P1, P2;
|
|
if (edge1.Orientation() == TopAbs_FORWARD)
|
|
ade1.D1(ade1.LastParameter(), P1, Diff1);
|
|
else
|
|
{
|
|
ade1.D1(ade1.FirstParameter(), P1, Diff1);
|
|
Diff1 = -Diff1;
|
|
}
|
|
|
|
if (edge2.Orientation() == TopAbs_FORWARD)
|
|
ade2.D1(ade2.FirstParameter(), P2, Diff2);
|
|
else
|
|
{
|
|
ade2.D1(ade2.LastParameter(), P2, Diff2);
|
|
Diff2 = -Diff2;
|
|
}
|
|
|
|
if (Diff1.Angle(Diff2) > theAngTol)
|
|
return Standard_False;
|
|
|
|
if (theLineDirectionOk && t2 == GeomAbs_Line)
|
|
{
|
|
Standard_Real aLast = (edge2.Orientation() == TopAbs_FORWARD) ?
|
|
ade2.LastParameter() : ade2.FirstParameter();
|
|
gp_Vec aCurV(theFirstPoint, ade2.Value(aLast));
|
|
Standard_Real aDD = theDirectionVec.CrossSquareMagnitude(aCurV);
|
|
if (aDD > theLinTol*theLinTol)
|
|
return Standard_False;
|
|
}
|
|
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetLineEdgePoints
|
|
//purpose :
|
|
//=======================================================================
|
|
static Standard_Boolean GetLineEdgePoints(const TopoDS_Edge& theInpEdge, gp_Pnt& theFirstPoint, gp_Vec& theDirectionVec)
|
|
{
|
|
double f, l;
|
|
Handle(Geom_Curve) aCur = BRep_Tool::Curve(theInpEdge, f, l);
|
|
if(aCur.IsNull())
|
|
return Standard_False;
|
|
|
|
Handle(Geom_TrimmedCurve) aTC = Handle(Geom_TrimmedCurve)::DownCast(aCur);
|
|
if (!aTC.IsNull())
|
|
aCur = aTC->BasisCurve();
|
|
|
|
if (aCur->DynamicType() != STANDARD_TYPE(Geom_Line))
|
|
return Standard_False;
|
|
|
|
if (theInpEdge.Orientation() == TopAbs_REVERSED) {
|
|
Standard_Real tmp = f;
|
|
f = l;
|
|
l = tmp;
|
|
}
|
|
theFirstPoint = aCur->Value(f);
|
|
gp_Pnt aLP = aCur->Value(l);
|
|
theDirectionVec = aLP.XYZ().Subtracted(theFirstPoint.XYZ());
|
|
theDirectionVec.Normalize();
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GenerateSubSeq
|
|
//purpose : Generates sub-sequences of edges from sequence of edges
|
|
//Edges from each subsequences can be merged into the one edge
|
|
//=======================================================================
|
|
|
|
static void GenerateSubSeq (const TopTools_SequenceOfShape& anInpEdgeSeq,
|
|
NCollection_Sequence<SubSequenceOfEdges>& SeqOfSubSeqOfEdges,
|
|
Standard_Boolean IsClosed, double theAngTol, double theLinTol,
|
|
const TopTools_MapOfShape& AvoidEdgeVrt)
|
|
{
|
|
Standard_Boolean isOk = Standard_False;
|
|
TopoDS_Edge edge1, edge2;
|
|
|
|
SubSequenceOfEdges SubSeq;
|
|
TopoDS_Edge RefEdge = TopoDS::Edge(anInpEdgeSeq(1));
|
|
SubSeq.SeqsEdges.Append(RefEdge);
|
|
SeqOfSubSeqOfEdges.Append(SubSeq);
|
|
|
|
gp_Pnt aFirstPoint;
|
|
gp_Vec aDirectionVec;
|
|
Standard_Boolean isLineDirectionOk = GetLineEdgePoints(RefEdge, aFirstPoint, aDirectionVec);
|
|
|
|
for (int i = 1; i < anInpEdgeSeq.Length(); i++)
|
|
{
|
|
edge1 = TopoDS::Edge(anInpEdgeSeq(i));
|
|
edge2 = TopoDS::Edge(anInpEdgeSeq(i+1));
|
|
isOk = IsMergingPossible(edge1, edge2, theAngTol, theLinTol, AvoidEdgeVrt, isLineDirectionOk, aFirstPoint, aDirectionVec);
|
|
if (!isOk)
|
|
{
|
|
SubSequenceOfEdges aSubSeq;
|
|
aSubSeq.SeqsEdges.Append(edge2);
|
|
SeqOfSubSeqOfEdges.Append(aSubSeq);
|
|
isLineDirectionOk = GetLineEdgePoints(edge2, aFirstPoint, aDirectionVec);
|
|
}
|
|
else
|
|
SeqOfSubSeqOfEdges.ChangeLast().SeqsEdges.Append(edge2);
|
|
}
|
|
/// check first and last chain segments
|
|
if (IsClosed && SeqOfSubSeqOfEdges.Length() > 1)
|
|
{
|
|
edge1 = TopoDS::Edge(anInpEdgeSeq.Last());
|
|
edge2 = TopoDS::Edge(anInpEdgeSeq.First());
|
|
if (IsMergingPossible(edge1, edge2, theAngTol, theLinTol, AvoidEdgeVrt, Standard_False, aFirstPoint, aDirectionVec))
|
|
{
|
|
SeqOfSubSeqOfEdges.ChangeLast().SeqsEdges.Append(SeqOfSubSeqOfEdges.ChangeFirst().SeqsEdges);
|
|
SeqOfSubSeqOfEdges.Remove(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MergeEdges
|
|
//purpose : auxilary
|
|
//=======================================================================
|
|
static Standard_Boolean MergeEdges(TopTools_SequenceOfShape& SeqEdges,
|
|
const Standard_Real theAngTol,
|
|
const Standard_Real theLinTol,
|
|
const Standard_Boolean ConcatBSplines,
|
|
const Standard_Boolean isSafeInputMode,
|
|
Handle(ShapeBuild_ReShape)& theContext,
|
|
NCollection_Sequence<SubSequenceOfEdges>& SeqOfSubSeqOfEdges,
|
|
const TopTools_MapOfShape& NonMergVrt)
|
|
{
|
|
// skip degenerated edges, and forbid merging through them
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapVE;
|
|
Standard_Integer j;
|
|
TopTools_MapOfShape VerticesToAvoid;
|
|
for (j = 1; j <= SeqEdges.Length(); j++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(SeqEdges(j));
|
|
if (BRep_Tool::Degenerated(anEdge))
|
|
{
|
|
TopoDS_Vertex V1, V2;
|
|
TopExp::Vertices(anEdge, V1, V2);
|
|
VerticesToAvoid.Add(V1);
|
|
VerticesToAvoid.Add(V2);
|
|
SeqEdges.Remove(j--);
|
|
}
|
|
else
|
|
{
|
|
// fill in the map V-E
|
|
for (TopoDS_Iterator it(anEdge.Oriented(TopAbs_FORWARD)); it.More(); it.Next())
|
|
{
|
|
TopoDS_Shape aV = it.Value();
|
|
if (aV.Orientation() == TopAbs_FORWARD || aV.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
if (!aMapVE.Contains(aV))
|
|
aMapVE.Add(aV, TopTools_ListOfShape());
|
|
aMapVE.ChangeFromKey(aV).Append(anEdge);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
VerticesToAvoid.Unite(NonMergVrt);
|
|
|
|
// do loop while there are unused edges
|
|
TopTools_MapOfShape aUsedEdges;
|
|
for (;;)
|
|
{
|
|
TopoDS_Edge edge;
|
|
for(j=1; j <= SeqEdges.Length(); j++)
|
|
{
|
|
edge = TopoDS::Edge(SeqEdges.Value(j));
|
|
if (!aUsedEdges.Contains(edge))
|
|
break;
|
|
}
|
|
if (j > SeqEdges.Length())
|
|
break; // all edges have been used
|
|
|
|
// make chain for unite
|
|
TopTools_SequenceOfShape aChain;
|
|
aChain.Append(edge);
|
|
aUsedEdges.Add(edge);
|
|
TopoDS_Vertex V[2];
|
|
TopExp::Vertices(edge, V[0], V[1], Standard_True);
|
|
|
|
// connect more edges to the chain in both directions
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
Standard_Boolean isAdded = Standard_True;
|
|
while (isAdded)
|
|
{
|
|
isAdded = Standard_False;
|
|
if (V[j].IsNull())
|
|
break;
|
|
const TopTools_ListOfShape& aLE = aMapVE.FindFromKey(V[j]);
|
|
for (TopTools_ListIteratorOfListOfShape itL(aLE); itL.More(); itL.Next())
|
|
{
|
|
edge = TopoDS::Edge(itL.Value());
|
|
if (!aUsedEdges.Contains(edge))
|
|
{
|
|
TopoDS_Vertex V2[2];
|
|
TopExp::Vertices(edge, V2[0], V2[1], Standard_True);
|
|
// the neighboring edge must have V[j] reversed and located on the opposite end
|
|
if (V2[1 - j].IsEqual(V[j].Reversed()))
|
|
{
|
|
if (j == 0)
|
|
aChain.Prepend(edge);
|
|
else
|
|
aChain.Append(edge);
|
|
aUsedEdges.Add(edge);
|
|
V[j] = V2[j];
|
|
isAdded = Standard_True;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aChain.Length() < 2)
|
|
continue;
|
|
|
|
Standard_Boolean IsClosed = Standard_False;
|
|
if (V[0].IsSame ( V[1] ))
|
|
IsClosed = Standard_True;
|
|
|
|
// split chain by vertices at which merging is not possible
|
|
NCollection_Sequence<SubSequenceOfEdges> aOneSeq;
|
|
GenerateSubSeq(aChain, aOneSeq, IsClosed, theAngTol, theLinTol, VerticesToAvoid);
|
|
|
|
// put sub-chains in the result
|
|
SeqOfSubSeqOfEdges.Append(aOneSeq);
|
|
}
|
|
|
|
for (int i = 1; i <= SeqOfSubSeqOfEdges.Length(); i++)
|
|
{
|
|
TopoDS_Edge UE;
|
|
if (SeqOfSubSeqOfEdges(i).SeqsEdges.Length() < 2)
|
|
continue;
|
|
if (MergeSubSeq(SeqOfSubSeqOfEdges(i).SeqsEdges, UE, theAngTol,
|
|
ConcatBSplines, isSafeInputMode, theContext))
|
|
SeqOfSubSeqOfEdges(i).UnionEdges = UE;
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MergeSeq
|
|
//purpose : Tries to unify the sequence of edges with the set of
|
|
// another edges which lies on the same geometry
|
|
//=======================================================================
|
|
static Standard_Boolean MergeSeq (TopTools_SequenceOfShape& SeqEdges,
|
|
const Standard_Real theAngTol,
|
|
const Standard_Real theLinTol,
|
|
const Standard_Boolean ConcatBSplines,
|
|
const Standard_Boolean isSafeInputMode,
|
|
Handle(ShapeBuild_ReShape)& theContext,
|
|
const TopTools_MapOfShape& nonMergVert)
|
|
{
|
|
NCollection_Sequence<SubSequenceOfEdges> SeqOfSubsSeqOfEdges;
|
|
if (MergeEdges(SeqEdges, theAngTol, theLinTol, ConcatBSplines, isSafeInputMode,
|
|
theContext, SeqOfSubsSeqOfEdges, nonMergVert))
|
|
{
|
|
for (Standard_Integer i = 1; i <= SeqOfSubsSeqOfEdges.Length(); i++ )
|
|
{
|
|
if (SeqOfSubsSeqOfEdges(i).UnionEdges.IsNull())
|
|
continue;
|
|
|
|
theContext->Merge(SeqOfSubsSeqOfEdges(i).SeqsEdges,
|
|
SeqOfSubsSeqOfEdges(i).UnionEdges);
|
|
}
|
|
return Standard_True;
|
|
}
|
|
return Standard_False;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CheckSharedVertices
|
|
//purpose : Checks the sequence of edges on the presence of shared vertex
|
|
//=======================================================================
|
|
|
|
static void CheckSharedVertices(const TopTools_SequenceOfShape& theSeqEdges,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theMapEdgesVertex,
|
|
const TopTools_MapOfShape& theMapKeepShape,
|
|
TopTools_MapOfShape& theShareVertMap)
|
|
{
|
|
ShapeAnalysis_Edge sae;
|
|
TopTools_SequenceOfShape SeqVertexes;
|
|
TopTools_MapOfShape MapVertexes;
|
|
for (Standard_Integer k = 1; k <= theSeqEdges.Length(); k++ )
|
|
{
|
|
TopoDS_Vertex aV1 = sae.FirstVertex(TopoDS::Edge(theSeqEdges(k)));
|
|
TopoDS_Vertex aV2 = sae.LastVertex(TopoDS::Edge(theSeqEdges(k)));
|
|
if (!MapVertexes.Add(aV1))
|
|
SeqVertexes.Append(aV1);
|
|
if (!MapVertexes.Add(aV2))
|
|
SeqVertexes.Append(aV2);
|
|
}
|
|
|
|
for (Standard_Integer k = 1; k <= SeqVertexes.Length()/* && !IsSharedVertexPresent*/; k++ )
|
|
{
|
|
const TopTools_ListOfShape& ListEdgesV1 = theMapEdgesVertex.FindFromKey(SeqVertexes(k));
|
|
if (ListEdgesV1.Extent() > 2 || theMapKeepShape.Contains(SeqVertexes(k)))
|
|
theShareVertMap.Add(SeqVertexes(k));
|
|
}
|
|
//return theShareVertMap.IsEmpty() ? false : true;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : ShapeUpgrade_UnifySameDomain
|
|
//purpose : Constructor
|
|
//=======================================================================
|
|
|
|
ShapeUpgrade_UnifySameDomain::ShapeUpgrade_UnifySameDomain()
|
|
: myLinTol(Precision::Confusion()),
|
|
myAngTol(Precision::Angular()),
|
|
myUnifyFaces(Standard_True),
|
|
myUnifyEdges (Standard_True),
|
|
myConcatBSplines (Standard_False),
|
|
myAllowInternal (Standard_False),
|
|
mySafeInputMode(Standard_True),
|
|
myHistory(new BRepTools_History)
|
|
{
|
|
myContext = new ShapeBuild_ReShape;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : ShapeUpgrade_UnifySameDomain
|
|
//purpose : Constructor
|
|
//=======================================================================
|
|
|
|
ShapeUpgrade_UnifySameDomain::ShapeUpgrade_UnifySameDomain(const TopoDS_Shape& aShape,
|
|
const Standard_Boolean UnifyEdges,
|
|
const Standard_Boolean UnifyFaces,
|
|
const Standard_Boolean ConcatBSplines)
|
|
: myInitShape (aShape),
|
|
myLinTol(Precision::Confusion()),
|
|
myAngTol(Precision::Angular()),
|
|
myUnifyFaces(UnifyFaces),
|
|
myUnifyEdges (UnifyEdges),
|
|
myConcatBSplines (ConcatBSplines),
|
|
myAllowInternal (Standard_False),
|
|
mySafeInputMode (Standard_True),
|
|
myShape (aShape),
|
|
myHistory(new BRepTools_History)
|
|
{
|
|
myContext = new ShapeBuild_ReShape;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Initialize
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::Initialize(const TopoDS_Shape& aShape,
|
|
const Standard_Boolean UnifyEdges,
|
|
const Standard_Boolean UnifyFaces,
|
|
const Standard_Boolean ConcatBSplines)
|
|
{
|
|
myInitShape = aShape;
|
|
myShape = aShape;
|
|
myUnifyEdges = UnifyEdges;
|
|
myUnifyFaces = UnifyFaces;
|
|
myConcatBSplines = ConcatBSplines;
|
|
|
|
myContext->Clear();
|
|
myKeepShapes.Clear();
|
|
myHistory->Clear();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : AllowInternalEdges
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::AllowInternalEdges (const Standard_Boolean theValue)
|
|
{
|
|
myAllowInternal = theValue;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetSafeInputMode
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::SetSafeInputMode(Standard_Boolean theValue)
|
|
{
|
|
mySafeInputMode = theValue;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : KeepShape
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::KeepShape(const TopoDS_Shape& theShape)
|
|
{
|
|
if (theShape.ShapeType() == TopAbs_EDGE || theShape.ShapeType() == TopAbs_VERTEX)
|
|
myKeepShapes.Add(theShape);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : KeepShapes
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::KeepShapes(const TopTools_MapOfShape& theShapes)
|
|
{
|
|
for (TopTools_MapIteratorOfMapOfShape it(theShapes); it.More(); it.Next()) {
|
|
if (it.Value().ShapeType() == TopAbs_EDGE || it.Value().ShapeType() == TopAbs_VERTEX)
|
|
myKeepShapes.Add(it.Value());
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : UnifyFaces
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::UnifyFaces()
|
|
{
|
|
// creating map of edge faces for the whole shape
|
|
TopTools_IndexedDataMapOfShapeListOfShape aGMapEdgeFaces;
|
|
TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, aGMapEdgeFaces);
|
|
|
|
// unify faces in each shell separately
|
|
TopExp_Explorer exps;
|
|
for (exps.Init(myShape, TopAbs_SHELL); exps.More(); exps.Next())
|
|
IntUnifyFaces(exps.Current(), aGMapEdgeFaces);
|
|
|
|
// gather all faces out of shells in one compound and unify them at once
|
|
BRep_Builder aBB;
|
|
TopoDS_Compound aCmp;
|
|
aBB.MakeCompound(aCmp);
|
|
Standard_Integer nbf = 0;
|
|
for (exps.Init(myShape, TopAbs_FACE, TopAbs_SHELL); exps.More(); exps.Next(), nbf++)
|
|
aBB.Add(aCmp, exps.Current());
|
|
|
|
if (nbf > 0)
|
|
IntUnifyFaces(aCmp, aGMapEdgeFaces);
|
|
|
|
myShape = myContext->Apply(myShape);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetFixWireModes
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
static void SetFixWireModes(ShapeFix_Face& theSff)
|
|
{
|
|
Handle(ShapeFix_Wire) aFixWire = theSff.FixWireTool();
|
|
aFixWire->FixSelfIntersectionMode() = 0;
|
|
aFixWire->FixNonAdjacentIntersectingEdgesMode() = 0;
|
|
aFixWire->FixLackingMode() = 0;
|
|
aFixWire->FixNotchedEdgesMode() = 0;
|
|
aFixWire->ModifyTopologyMode() = Standard_False;
|
|
aFixWire->ModifyRemoveLoopMode() = 0;
|
|
aFixWire->FixGapsByRangesMode() = Standard_False;
|
|
aFixWire->FixSmallMode() = 0;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IntUnifyFaces
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::IntUnifyFaces(const TopoDS_Shape& theInpShape,
|
|
TopTools_IndexedDataMapOfShapeListOfShape& theGMapEdgeFaces)
|
|
{
|
|
// creating map of edge faces for the shape
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
|
|
TopExp::MapShapesAndAncestors(theInpShape, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
|
|
|
|
// map of processed shapes
|
|
TopTools_MapOfShape aProcessed;
|
|
|
|
// processing each face
|
|
TopExp_Explorer exp;
|
|
for (exp.Init(theInpShape, TopAbs_FACE); exp.More(); exp.Next()) {
|
|
const TopoDS_Face& aFaceOriginal = TopoDS::Face(exp.Current());
|
|
TopoDS_Face aFace = TopoDS::Face(aFaceOriginal.Oriented(TopAbs_FORWARD));
|
|
|
|
if (aProcessed.Contains(aFace))
|
|
continue;
|
|
|
|
// Boundary edges for the new face
|
|
TopTools_SequenceOfShape edges;
|
|
|
|
Standard_Integer dummy;
|
|
AddOrdinaryEdges(edges, aFace, dummy);
|
|
|
|
// Faces to get unified with the current faces
|
|
TopTools_SequenceOfShape faces;
|
|
|
|
// Add the current face for unification
|
|
faces.Append(aFace);
|
|
|
|
// surface and location to construct result
|
|
TopLoc_Location aBaseLocation;
|
|
Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(aFace,aBaseLocation);
|
|
aBaseSurface = ClearRts(aBaseSurface);
|
|
|
|
// find adjacent faces to union
|
|
Standard_Integer i;
|
|
for (i = 1; i <= edges.Length(); i++) {
|
|
TopoDS_Edge edge = TopoDS::Edge(edges(i));
|
|
if (BRep_Tool::Degenerated(edge))
|
|
continue;
|
|
|
|
// get connectivity of the edge in the global shape
|
|
const TopTools_ListOfShape& aGList = theGMapEdgeFaces.FindFromKey(edge);
|
|
if (!myAllowInternal && (aGList.Extent() != 2 || myKeepShapes.Contains(edge))) {
|
|
// non manifold case is not processed unless myAllowInternal
|
|
continue;
|
|
}
|
|
//
|
|
// Get the faces connected through the edge in the current shape
|
|
const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
|
|
if (aList.Extent() < 2) {
|
|
continue;
|
|
}
|
|
|
|
// for a planar face create and store pcurve of edge on face
|
|
// to speed up all operations
|
|
if (!mySafeInputMode && aBaseSurface->IsKind(STANDARD_TYPE(Geom_Plane)))
|
|
BRepLib::BuildPCurveForEdgeOnPlane(edge, aFace);
|
|
|
|
// get normal of the face to compare it with normals of other faces
|
|
gp_Dir aDN1;
|
|
//
|
|
// take intermediate point on edge to compute the normal
|
|
Standard_Real f, l;
|
|
BRep_Tool::Range(edge, f, l);
|
|
Standard_Real aTMid = (f + l) * .5;
|
|
//
|
|
Standard_Boolean bCheckNormals = GetNormalToSurface(aFaceOriginal, edge, aTMid, aDN1);
|
|
//
|
|
// Process the faces
|
|
TopTools_ListIteratorOfListOfShape anIter(aList);
|
|
for (; anIter.More(); anIter.Next()) {
|
|
const TopoDS_Face& aCheckedFaceOriginal = TopoDS::Face(anIter.Value());
|
|
TopoDS_Face anCheckedFace = TopoDS::Face(aCheckedFaceOriginal.Oriented(TopAbs_FORWARD));
|
|
if (anCheckedFace.IsSame(aFace))
|
|
continue;
|
|
|
|
if (aProcessed.Contains(anCheckedFace))
|
|
continue;
|
|
|
|
if (bCheckNormals) {
|
|
// get normal of checked face using the same parameter on edge
|
|
gp_Dir aDN2;
|
|
if (GetNormalToSurface(aCheckedFaceOriginal, edge, aTMid, aDN2)) {
|
|
// and check if the adjacent faces are having approximately same normals
|
|
Standard_Real anAngle = aDN1.Angle(aDN2);
|
|
if (anAngle > myAngTol) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (IsSameDomain(aFace,anCheckedFace, myLinTol, myAngTol)) {
|
|
|
|
// hotfix for 27271: prevent merging along periodic direction.
|
|
if (IsLikeSeam(edge, anCheckedFace, aBaseSurface))
|
|
continue;
|
|
|
|
if (AddOrdinaryEdges(edges,anCheckedFace,dummy)) {
|
|
// sequence edges is modified
|
|
i = dummy;
|
|
}
|
|
|
|
faces.Append(anCheckedFace);
|
|
aProcessed.Add(anCheckedFace);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (faces.Length() > 1) {
|
|
// fill in the connectivity map for selected faces
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapEF;
|
|
for (i = 1; i <= faces.Length(); i++) {
|
|
TopExp::MapShapesAndAncestors(faces(i), TopAbs_EDGE, TopAbs_FACE, aMapEF);
|
|
}
|
|
// Collect keep edges and multi-connected edges, i.e. edges that are internal to
|
|
// the set of selected faces and have connections to other faces.
|
|
TopTools_ListOfShape aKeepEdges;
|
|
for (i = 1; i <= aMapEF.Extent(); i++) {
|
|
const TopTools_ListOfShape& aLF = aMapEF(i);
|
|
if (aLF.Extent() == 2) {
|
|
const TopoDS_Shape& aE = aMapEF.FindKey(i);
|
|
const TopTools_ListOfShape& aGLF = theGMapEdgeFaces.FindFromKey(aE);
|
|
if (aGLF.Extent() > 2 || myKeepShapes.Contains(aE)) {
|
|
aKeepEdges.Append(aE);
|
|
}
|
|
}
|
|
}
|
|
if (!aKeepEdges.IsEmpty()) {
|
|
if (!myAllowInternal) {
|
|
// Remove from the selection the faces which have no other connect edges
|
|
// and contain multi-connected edges and/or keep edges.
|
|
TopTools_MapOfShape anAvoidFaces;
|
|
TopTools_ListIteratorOfListOfShape it(aKeepEdges);
|
|
for (; it.More(); it.Next()) {
|
|
const TopoDS_Shape& aE = it.Value();
|
|
const TopTools_ListOfShape& aLF = aMapEF.FindFromKey(aE);
|
|
anAvoidFaces.Add(aLF.First());
|
|
anAvoidFaces.Add(aLF.Last());
|
|
}
|
|
for (i = 1; i <= faces.Length(); i++) {
|
|
if (anAvoidFaces.Contains(faces(i))) {
|
|
// update the boundaries of merged area, for that
|
|
// remove from 'edges' the edges of this face and add to 'edges'
|
|
// the edges of this face that were not present in 'edges' before
|
|
Standard_Boolean hasConnectAnotherFaces = Standard_False;
|
|
TopExp_Explorer ex(faces(i), TopAbs_EDGE);
|
|
for (; ex.More() && !hasConnectAnotherFaces; ex.Next()) {
|
|
TopoDS_Shape aE = ex.Current();
|
|
const TopTools_ListOfShape& aLF = aMapEF.FindFromKey(aE);
|
|
if (aLF.Extent() > 1) {
|
|
for (it.Init(aLF); it.More() && !hasConnectAnotherFaces; it.Next()) {
|
|
if (!anAvoidFaces.Contains(it.Value()))
|
|
hasConnectAnotherFaces = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
if (!hasConnectAnotherFaces) {
|
|
AddOrdinaryEdges(edges, faces(i), dummy);
|
|
faces.Remove(i);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
// check if the faces with keep edges contained in
|
|
// already updated the boundaries of merged area
|
|
if (!faces.IsEmpty()) {
|
|
TopTools_MapOfShape aMapFaces;
|
|
for (i = 1; i <= faces.Length(); i++) {
|
|
aMapFaces.Add(faces(i));
|
|
}
|
|
for (it.Init(aKeepEdges); it.More(); it.Next()) {
|
|
const TopoDS_Shape& aE = it.Value();
|
|
const TopTools_ListOfShape& aLF = aMapEF.FindFromKey(aE);
|
|
if (aLF.Extent() < 2)
|
|
continue;
|
|
if (aMapFaces.Contains(aLF.First()) &&
|
|
aMapFaces.Contains(aLF.Last())) {
|
|
for (i = 1; i <= faces.Length(); i++) {
|
|
if (faces(i).IsEqual(aLF.First()) ||
|
|
faces(i).IsEqual(aLF.Last())) {
|
|
AddOrdinaryEdges(edges, faces(i), dummy);
|
|
faces.Remove(i);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// add multi-connected and keep edges as internal in new face
|
|
TopTools_ListIteratorOfListOfShape it(aKeepEdges);
|
|
for (; it.More(); it.Next()) {
|
|
const TopoDS_Shape& aE = it.Value();
|
|
edges.Append(aE.Oriented(TopAbs_INTERNAL));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// all faces collected in the sequence. Perform union of faces
|
|
if (faces.Length() > 1) {
|
|
TopoDS_Face aResult;
|
|
BRep_Builder B;
|
|
B.MakeFace(aResult,aBaseSurface,aBaseLocation,0);
|
|
Standard_Integer nbWires = 0;
|
|
|
|
TopoDS_Face tmpF = TopoDS::Face(faces(1).Oriented(TopAbs_FORWARD));
|
|
|
|
// connecting wires
|
|
while (edges.Length()>0) {
|
|
|
|
Standard_Boolean isEdge3d = Standard_False;
|
|
nbWires++;
|
|
TopTools_MapOfShape aVertices;
|
|
TopoDS_Wire aWire;
|
|
B.MakeWire(aWire);
|
|
|
|
TopoDS_Edge anEdge = TopoDS::Edge(edges(1));
|
|
edges.Remove(1);
|
|
// collect internal edges in separate wires
|
|
Standard_Boolean isInternal = (anEdge.Orientation() == TopAbs_INTERNAL);
|
|
|
|
isEdge3d |= !BRep_Tool::Degenerated(anEdge);
|
|
B.Add(aWire,anEdge);
|
|
TopoDS_Vertex V1,V2;
|
|
TopExp::Vertices(anEdge,V1,V2);
|
|
aVertices.Add(V1);
|
|
aVertices.Add(V2);
|
|
|
|
Standard_Boolean isNewFound = Standard_False;
|
|
do {
|
|
isNewFound = Standard_False;
|
|
for(Standard_Integer j = 1; j <= edges.Length(); j++) {
|
|
anEdge = TopoDS::Edge(edges(j));
|
|
// check if the current edge orientation corresponds to the first one
|
|
Standard_Boolean isCurrInternal = (anEdge.Orientation() == TopAbs_INTERNAL);
|
|
if (isCurrInternal != isInternal)
|
|
continue;
|
|
TopExp::Vertices(anEdge,V1,V2);
|
|
if(aVertices.Contains(V1) || aVertices.Contains(V2)) {
|
|
isEdge3d |= !BRep_Tool::Degenerated(anEdge);
|
|
aVertices.Add(V1);
|
|
aVertices.Add(V2);
|
|
B.Add(aWire,anEdge);
|
|
edges.Remove(j);
|
|
j--;
|
|
isNewFound = Standard_True;
|
|
}
|
|
}
|
|
} while (isNewFound);
|
|
|
|
// sorting any type of edges
|
|
aWire.Closed (BRep_Tool::IsClosed (aWire));
|
|
|
|
Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(aWire,tmpF,Precision::Confusion());
|
|
if (mySafeInputMode)
|
|
sfw->SetContext(myContext);
|
|
sfw->FixReorder();
|
|
Standard_Boolean isDegRemoved = Standard_False;
|
|
if(!sfw->StatusReorder ( ShapeExtend_FAIL )) {
|
|
// clear degenerated edges if at least one with 3d curve exist
|
|
if(isEdge3d) {
|
|
Handle(ShapeExtend_WireData) sewd = sfw->WireData();
|
|
for(Standard_Integer j = 1; j<=sewd->NbEdges();j++) {
|
|
TopoDS_Edge E = sewd->Edge(j);
|
|
if(BRep_Tool::Degenerated(E)) {
|
|
sewd->Remove(j);
|
|
isDegRemoved = Standard_True;
|
|
j--;
|
|
}
|
|
}
|
|
}
|
|
sfw->FixShifted();
|
|
if(isDegRemoved)
|
|
sfw->FixDegenerated();
|
|
}
|
|
aWire = sfw->Wire();
|
|
|
|
// add resulting wire
|
|
if(isEdge3d) {
|
|
B.Add(aResult,aWire);
|
|
}
|
|
else {
|
|
// sorting edges
|
|
Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
|
|
Standard_Integer nbEdges = sbwd->NbEdges();
|
|
// sort degenerated edges and create one edge instead of several ones
|
|
ShapeAnalysis_WireOrder sawo(Standard_False, 0);
|
|
ShapeAnalysis_Edge sae;
|
|
Standard_Integer aLastEdge = nbEdges;
|
|
for(Standard_Integer j = 1; j <= nbEdges; j++) {
|
|
Standard_Real f,l;
|
|
//smh protection on NULL pcurve
|
|
Handle(Geom2d_Curve) c2d;
|
|
if(!sae.PCurve(sbwd->Edge(j),tmpF,c2d,f,l)) {
|
|
aLastEdge--;
|
|
continue;
|
|
}
|
|
sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
|
|
}
|
|
if (sawo.NbEdges() == 0)
|
|
continue;
|
|
sawo.Perform();
|
|
|
|
// constructind one degenerative edge
|
|
gp_XY aStart, anEnd, tmp;
|
|
Standard_Integer nbFirst = sawo.Ordered(1);
|
|
TopoDS_Edge anOrigE = TopoDS::Edge(sbwd->Edge(nbFirst).Oriented(TopAbs_FORWARD));
|
|
ShapeBuild_Edge sbe;
|
|
TopoDS_Vertex aDummyV;
|
|
TopoDS_Edge E = sbe.CopyReplaceVertices(anOrigE,aDummyV,aDummyV);
|
|
sawo.XY(nbFirst,aStart,tmp);
|
|
sawo.XY(sawo.Ordered(aLastEdge),tmp,anEnd);
|
|
|
|
gp_XY aVec = anEnd-aStart;
|
|
Handle(Geom2d_Line) aLine = new Geom2d_Line(aStart,gp_Dir2d(anEnd-aStart));
|
|
|
|
B.UpdateEdge(E,aLine,tmpF,0.);
|
|
B.Range(E,tmpF,0.,aVec.Modulus());
|
|
Handle(Geom_Curve) C3d;
|
|
B.UpdateEdge(E,C3d,0.);
|
|
B.Degenerated(E,Standard_True);
|
|
TopoDS_Wire aW;
|
|
B.MakeWire(aW);
|
|
B.Add(aW,E);
|
|
aW.Closed (Standard_True);
|
|
B.Add(aResult,aW);
|
|
}
|
|
}
|
|
|
|
ShapeFix_Face sff (aResult);
|
|
//Initializing by tolerances
|
|
sff.SetPrecision(Precision::Confusion());
|
|
sff.SetMinTolerance(Precision::Confusion());
|
|
sff.SetMaxTolerance(1.);
|
|
//Setting modes
|
|
SetFixWireModes(sff);
|
|
if (mySafeInputMode)
|
|
sff.SetContext(myContext);
|
|
// Applying the fixes
|
|
sff.Perform();
|
|
if(!sff.Status(ShapeExtend_FAIL))
|
|
{
|
|
// perform substitution of faces
|
|
aResult = sff.Face();
|
|
myContext->Merge(faces, aResult);
|
|
}
|
|
}
|
|
} // end processing each face
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : UnifyEdges
|
|
//purpose :
|
|
//=======================================================================
|
|
void ShapeUpgrade_UnifySameDomain::UnifyEdges()
|
|
{
|
|
TopoDS_Shape aRes = myContext->Apply(myShape);
|
|
// creating map of edge faces
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
|
|
TopExp::MapShapesAndAncestors(aRes, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
|
|
// creating map of vertex edges
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapEdgesVertex;
|
|
TopExp::MapShapesAndUniqueAncestors(aRes, TopAbs_VERTEX, TopAbs_EDGE, aMapEdgesVertex);
|
|
|
|
if (mySafeInputMode)
|
|
UpdateMapOfShapes(myKeepShapes, myContext);
|
|
|
|
// Sequence of the edges of the shape
|
|
TopTools_SequenceOfShape aSeqEdges;
|
|
const Standard_Integer aNbE = aMapEdgeFaces.Extent();
|
|
for (Standard_Integer i = 1; i <= aNbE; ++i)
|
|
aSeqEdges.Append(aMapEdgeFaces.FindKey(i));
|
|
|
|
// Prepare map of shared vertices (with the number of connected edges greater then 2)
|
|
TopTools_MapOfShape aSharedVert;
|
|
CheckSharedVertices(aSeqEdges, aMapEdgesVertex, myKeepShapes, aSharedVert);
|
|
// Merge the edges avoiding removal of the shared vertices
|
|
Standard_Boolean isMerged = MergeSeq(aSeqEdges, myAngTol, myLinTol, myConcatBSplines,
|
|
mySafeInputMode, myContext, aSharedVert);
|
|
// Collect faces to rebuild
|
|
TopTools_IndexedMapOfShape aChangedFaces;
|
|
if (isMerged)
|
|
{
|
|
for (Standard_Integer i = 1; i <= aNbE; ++i)
|
|
{
|
|
const TopoDS_Shape& aE = aMapEdgeFaces.FindKey(i);
|
|
if (myContext->IsRecorded(aE))
|
|
{
|
|
TopTools_ListIteratorOfListOfShape it(aMapEdgeFaces(i));
|
|
for (; it.More(); it.Next())
|
|
aChangedFaces.Add(it.Value());
|
|
}
|
|
}
|
|
}
|
|
|
|
// fix changed faces and replace them in the local context
|
|
Standard_Real aPrec = Precision::Confusion();
|
|
for (Standard_Integer i = 1; i <= aChangedFaces.Extent(); i++) {
|
|
TopoDS_Face aFace = TopoDS::Face(myContext->Apply(aChangedFaces.FindKey(i)));
|
|
if (aFace.IsNull())
|
|
continue;
|
|
|
|
// for a planar face create and store pcurve of edge on face
|
|
// to speed up all operations; but this is allowed only when non-safe mode in force
|
|
if (!mySafeInputMode)
|
|
{
|
|
TopLoc_Location aLoc;
|
|
Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace, aLoc);
|
|
aSurface = ClearRts(aSurface);
|
|
if (aSurface->IsKind(STANDARD_TYPE(Geom_Plane)))
|
|
{
|
|
TopTools_ListOfShape aLE;
|
|
for (TopExp_Explorer anEx(aFace, TopAbs_EDGE); anEx.More(); anEx.Next())
|
|
aLE.Append(anEx.Current());
|
|
BRepLib::BuildPCurveForEdgesOnPlane(aLE, aFace);
|
|
}
|
|
}
|
|
|
|
ShapeFix_Face sff(aFace);
|
|
if (mySafeInputMode)
|
|
sff.SetContext(myContext);
|
|
sff.SetPrecision(aPrec);
|
|
sff.SetMinTolerance(aPrec);
|
|
sff.SetMaxTolerance(Max(1., aPrec*1000.));
|
|
sff.FixOrientationMode() = 0;
|
|
sff.FixAddNaturalBoundMode() = 0;
|
|
sff.FixIntersectingWiresMode() = 0;
|
|
sff.FixLoopWiresMode() = 0;
|
|
sff.FixSplitFaceMode() = 0;
|
|
sff.FixPeriodicDegeneratedMode() = 0;
|
|
SetFixWireModes(sff);
|
|
sff.Perform();
|
|
TopoDS_Shape aNewFace = sff.Face();
|
|
myContext->Replace(aFace,aNewFace);
|
|
}
|
|
|
|
if (aChangedFaces.Extent() > 0) {
|
|
// fix changed shell and replace it in the local context
|
|
TopoDS_Shape aRes1 = myContext->Apply(aRes);
|
|
Standard_Boolean isChanged = Standard_False;
|
|
TopExp_Explorer expsh;
|
|
for (expsh.Init(aRes1, TopAbs_SHELL); expsh.More(); expsh.Next()) {
|
|
TopoDS_Shell aShell = TopoDS::Shell(expsh.Current());
|
|
Handle(ShapeFix_Shell) sfsh = new ShapeFix_Shell;
|
|
sfsh->FixFaceOrientation(aShell);
|
|
TopoDS_Shape aNewShell = sfsh->Shell();
|
|
if (!aNewShell.IsSame(aShell)) {
|
|
myContext->Replace(aShell, aNewShell);
|
|
isChanged = Standard_True;
|
|
}
|
|
}
|
|
if (isChanged)
|
|
aRes1 = myContext->Apply(aRes1);
|
|
myContext->Replace(myShape, aRes1);
|
|
}
|
|
|
|
myShape = myContext->Apply(myShape);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Build
|
|
//purpose : builds the resulting shape
|
|
//=======================================================================
|
|
void ShapeUpgrade_UnifySameDomain::Build()
|
|
{
|
|
if (myUnifyFaces)
|
|
UnifyFaces();
|
|
if (myUnifyEdges)
|
|
UnifyEdges();
|
|
|
|
// Fill the history of modifications during the operation
|
|
FillHistory();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : FillHistory
|
|
//purpose : Fill the history of modifications during the operation
|
|
//=======================================================================
|
|
void ShapeUpgrade_UnifySameDomain::FillHistory()
|
|
{
|
|
if (myHistory.IsNull())
|
|
// History is not requested
|
|
return;
|
|
|
|
// Only Vertices, Edges and Faces can be modified during unification.
|
|
// Thus, only these kind of shapes should be checked.
|
|
|
|
// Get history from the context.
|
|
// It contains all modifications of the operation. Some of these
|
|
// modifications become not relevant and should be filtered.
|
|
Handle(BRepTools_History) aCtxHistory = myContext->History();
|
|
|
|
// Explore the history of the context and fill
|
|
// the history of UnifySameDomain algorithm
|
|
Handle(BRepTools_History) aUSDHistory = new BRepTools_History();
|
|
|
|
// Map all Vertices, Edges, Faces and Solids in the input shape
|
|
TopTools_IndexedMapOfShape aMapInputShape;
|
|
TopExp::MapShapes(myInitShape, TopAbs_VERTEX, aMapInputShape);
|
|
TopExp::MapShapes(myInitShape, TopAbs_EDGE , aMapInputShape);
|
|
TopExp::MapShapes(myInitShape, TopAbs_FACE , aMapInputShape);
|
|
TopExp::MapShapes(myInitShape, TopAbs_SOLID , aMapInputShape);
|
|
|
|
// Map all Vertices, Edges, Faces and Solids in the result shape
|
|
TopTools_IndexedMapOfShape aMapResultShapes;
|
|
TopExp::MapShapes(myShape, TopAbs_VERTEX, aMapResultShapes);
|
|
TopExp::MapShapes(myShape, TopAbs_EDGE , aMapResultShapes);
|
|
TopExp::MapShapes(myShape, TopAbs_FACE , aMapResultShapes);
|
|
TopExp::MapShapes(myShape, TopAbs_SOLID , aMapResultShapes);
|
|
|
|
// Iterate on all input shapes and get their modifications
|
|
Standard_Integer i, aNb = aMapInputShape.Extent();
|
|
for (i = 1; i <= aNb; ++i)
|
|
{
|
|
const TopoDS_Shape& aS = aMapInputShape(i);
|
|
|
|
// Check the shape itself to be present in the result
|
|
if (aMapResultShapes.Contains(aS))
|
|
{
|
|
// The shape is present in the result as is, thus has not been modified
|
|
continue;
|
|
}
|
|
|
|
// Check if the shape has been modified during the operation
|
|
const TopTools_ListOfShape& aLSImages = aCtxHistory->Modified(aS);
|
|
if (aLSImages.IsEmpty())
|
|
{
|
|
// The shape has not been modified and not present in the result,
|
|
// thus it has been removed
|
|
aUSDHistory->Remove(aS);
|
|
continue;
|
|
}
|
|
|
|
// Check the images of the shape to be present in the result
|
|
Standard_Boolean bRemoved = Standard_True;
|
|
TopTools_ListIteratorOfListOfShape aItLSIm(aLSImages);
|
|
for (; aItLSIm.More(); aItLSIm.Next())
|
|
{
|
|
const TopoDS_Shape& aSIm = aItLSIm.Value();
|
|
if (aMapResultShapes.Contains(aSIm))
|
|
{
|
|
if (!aSIm.IsSame(aS))
|
|
// Image is found in the result, thus the shape has been modified
|
|
aUSDHistory->AddModified(aS, aSIm);
|
|
bRemoved = Standard_False;
|
|
}
|
|
}
|
|
|
|
if (bRemoved)
|
|
{
|
|
// No images are found in the result, thus the shape has been removed
|
|
aUSDHistory->Remove(aS);
|
|
}
|
|
}
|
|
|
|
// Merge the history of the operation into global history
|
|
myHistory->Merge(aUSDHistory);
|
|
}
|