mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-05-22 04:37:23 +08:00
Majority of functions now simply call same functions from std namespace. Functions that duplicate std namespace functionality are declared deprecated. Calls of deprecated functions are replaced with std functions calls.
4296 lines
154 KiB
C++
4296 lines
154 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 <ShapeUpgrade_UnifySameDomain.hxx>
|
|
|
|
#include <BRep_Builder.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
#include <BRepLib.hxx>
|
|
#include <BRepTopAdaptor_TopolTool.hxx>
|
|
#include <GC_MakeCircle.hxx>
|
|
#include <Geom2d_Circle.hxx>
|
|
#include <GCE2d_MakeLine.hxx>
|
|
#include <Geom2d_TrimmedCurve.hxx>
|
|
#include <Geom2dConvert.hxx>
|
|
#include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
|
|
#include <Geom_BezierCurve.hxx>
|
|
#include <Geom_BSplineCurve.hxx>
|
|
#include <Geom_BSplineSurface.hxx>
|
|
#include <Geom_Circle.hxx>
|
|
#include <Geom_Ellipse.hxx>
|
|
#include <Geom_CylindricalSurface.hxx>
|
|
#include <Geom_ElementarySurface.hxx>
|
|
#include <Geom_Line.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 <GeomConvert.hxx>
|
|
#include <GeomConvert_ApproxSurface.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 <ShapeAnalysis_Surface.hxx>
|
|
#include <ShapeBuild_ReShape.hxx>
|
|
#include <ShapeConstruct_ProjectCurveOnSurface.hxx>
|
|
#include <ShapeFix_Face.hxx>
|
|
#include <ShapeFix_Shell.hxx>
|
|
#include <ShapeFix_Wire.hxx>
|
|
#include <Standard_NullValue.hxx>
|
|
#include <Standard_Type.hxx>
|
|
#include <TColGeom2d_Array1OfBSplineCurve.hxx>
|
|
#include <TColGeom2d_HArray1OfBSplineCurve.hxx>
|
|
#include <TColGeom2d_SequenceOfBoundedCurve.hxx>
|
|
#include <TColGeom2d_SequenceOfCurve.hxx>
|
|
#include <TColGeom_Array1OfBSplineCurve.hxx>
|
|
#include <TColGeom_HArray1OfBSplineCurve.hxx>
|
|
#include <TColGeom_SequenceOfSurface.hxx>
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
#include <TColStd_MapOfInteger.hxx>
|
|
#include <TColStd_SequenceOfBoolean.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_MapOfShape.hxx>
|
|
#include <TopTools_SequenceOfShape.hxx>
|
|
#include <gp_Circ.hxx>
|
|
#include <BRepAdaptor_Curve.hxx>
|
|
#include <BRepAdaptor_Curve2d.hxx>
|
|
#include <BRepAdaptor_Surface.hxx>
|
|
#include <gp_Vec2d.hxx>
|
|
#include <Extrema_ExtPS.hxx>
|
|
#include <BRepTools.hxx>
|
|
#include <BRepTopAdaptor_FClass2d.hxx>
|
|
#include <ElCLib.hxx>
|
|
#include <BRepBuilderAPI_MakeEdge.hxx>
|
|
#include <ElSLib.hxx>
|
|
#include <GeomProjLib.hxx>
|
|
|
|
IMPLEMENT_STANDARD_RTTIEXT(ShapeUpgrade_UnifySameDomain, Standard_Transient)
|
|
|
|
static Standard_Boolean IsOnSingularity(const TopTools_ListOfShape& theEdgeList)
|
|
{
|
|
TopTools_ListIteratorOfListOfShape anItl(theEdgeList);
|
|
for (; anItl.More(); anItl.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(anItl.Value());
|
|
if (BRep_Tool::Degenerated(anEdge))
|
|
return Standard_True;
|
|
}
|
|
|
|
return Standard_False;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : IsUiso
|
|
// purpose : only for seam edges assumed to be U- or V- isolines
|
|
//=======================================================================
|
|
static Standard_Boolean IsUiso(const TopoDS_Edge& theEdge, const TopoDS_Face& theFace)
|
|
{
|
|
BRepAdaptor_Curve2d aBAcurve2d(theEdge, theFace);
|
|
gp_Pnt2d aP2d;
|
|
gp_Vec2d aVec;
|
|
aBAcurve2d.D1(aBAcurve2d.FirstParameter(), aP2d, aVec);
|
|
return (std::abs(aVec.Y()) > std::abs(aVec.X()));
|
|
}
|
|
|
|
static Standard_Boolean IsLinear(const BRepAdaptor_Curve& theBAcurve, gp_Dir& theDir)
|
|
{
|
|
GeomAbs_CurveType aType = theBAcurve.GetType();
|
|
|
|
if (aType == GeomAbs_Line)
|
|
{
|
|
theDir = theBAcurve.Line().Position().Direction();
|
|
return Standard_True;
|
|
}
|
|
|
|
if ((aType == GeomAbs_BezierCurve || aType == GeomAbs_BSplineCurve) && theBAcurve.NbPoles() == 2)
|
|
{
|
|
gp_Pnt aFirstPnt = theBAcurve.Value(theBAcurve.FirstParameter());
|
|
gp_Pnt aLastPnt = theBAcurve.Value(theBAcurve.LastParameter());
|
|
theDir = gp_Vec(aFirstPnt, aLastPnt);
|
|
return Standard_True;
|
|
}
|
|
|
|
return Standard_False;
|
|
}
|
|
|
|
static void SplitWire(const TopoDS_Wire& theWire,
|
|
const TopoDS_Face& theFace,
|
|
const TopTools_IndexedMapOfShape& theVmap,
|
|
TopTools_SequenceOfShape& theWireSeq);
|
|
|
|
static Standard_Real TrueValueOfOffset(const Standard_Real theValue, const Standard_Real thePeriod)
|
|
{
|
|
if (theValue > 0.)
|
|
return thePeriod;
|
|
|
|
return (-thePeriod);
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : GetFaceFromSeq
|
|
// purpose : gets a face from the sequence that has a common boundary
|
|
// with already got <theUsedFaces>. If it is possible,
|
|
// gets a face that has a common boundary in 2D space too
|
|
// (excludes seam edges).
|
|
// <theIndFace> returns the Index of the face in the sequence.
|
|
//=======================================================================
|
|
static TopoDS_Face GetFaceFromSeq(const TopTools_SequenceOfShape& theFaces,
|
|
const TopoDS_Face& theRefFace,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theMapEF,
|
|
TopTools_IndexedMapOfShape& theUsedFaces,
|
|
Standard_Integer& theIndFace)
|
|
{
|
|
if (theUsedFaces.IsEmpty())
|
|
{
|
|
theIndFace = 1;
|
|
theUsedFaces.Add(theFaces(1));
|
|
return TopoDS::Face(theFaces(1));
|
|
}
|
|
|
|
TopoDS_Edge aSeamEdge;
|
|
TopoDS_Face aTargetFace;
|
|
for (Standard_Integer ii = 1; ii <= theUsedFaces.Extent(); ii++)
|
|
{
|
|
const TopoDS_Face& aUsedFace = TopoDS::Face(theUsedFaces(ii));
|
|
TopExp_Explorer anExplo(aUsedFace, TopAbs_EDGE);
|
|
for (; anExplo.More(); anExplo.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(anExplo.Current());
|
|
const TopTools_ListOfShape& aFaceList = theMapEF.FindFromKey(anEdge);
|
|
if (aFaceList.Extent() < 2)
|
|
continue;
|
|
|
|
const TopoDS_Face& aFace = (aFaceList.First().IsSame(aUsedFace))
|
|
? TopoDS::Face(aFaceList.Last())
|
|
: TopoDS::Face(aFaceList.First());
|
|
|
|
if (theUsedFaces.Contains(aFace))
|
|
continue;
|
|
|
|
if (BRep_Tool::IsClosed(anEdge, theRefFace))
|
|
{
|
|
aSeamEdge = anEdge;
|
|
continue;
|
|
}
|
|
|
|
aTargetFace = aFace;
|
|
break;
|
|
}
|
|
if (aTargetFace.IsNull() && !aSeamEdge.IsNull())
|
|
{
|
|
const TopTools_ListOfShape& aFaceList = theMapEF.FindFromKey(aSeamEdge);
|
|
aTargetFace = (aFaceList.First().IsSame(aUsedFace)) ? TopoDS::Face(aFaceList.Last())
|
|
: TopoDS::Face(aFaceList.First());
|
|
}
|
|
if (!aTargetFace.IsNull())
|
|
break;
|
|
}
|
|
|
|
theUsedFaces.Add(aTargetFace);
|
|
for (Standard_Integer ii = 2; ii <= theFaces.Length(); ii++)
|
|
if (theFaces(ii).IsSame(aTargetFace))
|
|
{
|
|
theIndFace = ii;
|
|
break;
|
|
}
|
|
|
|
return aTargetFace;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static void UpdateBoundaries(const Handle(Geom2d_Curve)& thePCurve,
|
|
const Standard_Real theFirst,
|
|
const Standard_Real theLast,
|
|
const Standard_Integer theIndCoord,
|
|
Standard_Real& theMinCoord,
|
|
Standard_Real& theMaxCoord)
|
|
{
|
|
const Standard_Integer NbSamples = 4;
|
|
Standard_Real Delta = (theLast - theFirst) / NbSamples;
|
|
|
|
for (Standard_Integer i = 0; i <= NbSamples; i++)
|
|
{
|
|
Standard_Real aParam = theFirst + i * Delta;
|
|
gp_Pnt2d aPoint = thePCurve->Value(aParam);
|
|
|
|
if (aPoint.Coord(theIndCoord) < theMinCoord)
|
|
theMinCoord = aPoint.Coord(theIndCoord);
|
|
|
|
if (aPoint.Coord(theIndCoord) > theMaxCoord)
|
|
theMaxCoord = aPoint.Coord(theIndCoord);
|
|
}
|
|
}
|
|
|
|
static Standard_Boolean TryMakeLine(const Handle(Geom2d_Curve)& thePCurve,
|
|
const Standard_Real theFirst,
|
|
const Standard_Real theLast,
|
|
Handle(Geom2d_Line)& theLine)
|
|
{
|
|
gp_Pnt2d aFirstPnt = thePCurve->Value(theFirst);
|
|
gp_Pnt2d aLastPnt = thePCurve->Value(theLast);
|
|
gp_Vec2d aVec(aFirstPnt, aLastPnt);
|
|
Standard_Real aSqLen = aVec.SquareMagnitude();
|
|
Standard_Real aSqParamLen = (theLast - theFirst) * (theLast - theFirst);
|
|
if (std::abs(aSqLen - aSqParamLen) > Precision::Confusion())
|
|
return Standard_False;
|
|
|
|
gp_Dir2d aDir = aVec;
|
|
gp_Vec2d anOffset = -aDir;
|
|
anOffset *= theFirst;
|
|
gp_Pnt2d anOrigin = aFirstPnt.Translated(anOffset);
|
|
gp_Lin2d aLin(anOrigin, aDir);
|
|
|
|
const Standard_Integer NbSamples = 10;
|
|
Standard_Real aDelta = (theLast - theFirst) / NbSamples;
|
|
for (Standard_Integer i = 1; i < NbSamples; i++)
|
|
{
|
|
Standard_Real aParam = theFirst + i * aDelta;
|
|
gp_Pnt2d aPnt = thePCurve->Value(aParam);
|
|
Standard_Real aDist = aLin.Distance(aPnt);
|
|
if (aDist > Precision::Confusion())
|
|
return Standard_False;
|
|
}
|
|
|
|
theLine = new Geom2d_Line(aLin);
|
|
return Standard_True;
|
|
}
|
|
|
|
// Removes the specified edge from the vertex to edge map.
|
|
// @param theEdge The edge to remove.
|
|
// @param theVertexToEdges The map of vertices to edges.
|
|
// @return True if the edge was removed, false otherwise.
|
|
static bool RemoveEdgeFromMap(const TopoDS_Edge& theEdge,
|
|
TopTools_IndexedDataMapOfShapeListOfShape& theVertexToEdges)
|
|
{
|
|
bool anIsRemoved = false;
|
|
TopoDS_Vertex aFirstVertex;
|
|
TopoDS_Vertex aLastVertex;
|
|
TopExp::Vertices(theEdge, aFirstVertex, aLastVertex);
|
|
for (const auto& aVertex : {aFirstVertex, aLastVertex})
|
|
{
|
|
if (!theVertexToEdges.Contains(aVertex))
|
|
{
|
|
continue;
|
|
}
|
|
TopTools_ListOfShape& aVertexEdges = theVertexToEdges.ChangeFromKey(aVertex);
|
|
TopTools_ListIteratorOfListOfShape anEdgesIter(aVertexEdges);
|
|
while (anEdgesIter.More())
|
|
{
|
|
const TopoDS_Shape& anEdge = anEdgesIter.Value();
|
|
if (anEdge.IsSame(theEdge))
|
|
{
|
|
anIsRemoved = true;
|
|
aVertexEdges.Remove(anEdgesIter);
|
|
}
|
|
else
|
|
{
|
|
anEdgesIter.Next();
|
|
}
|
|
}
|
|
}
|
|
return anIsRemoved;
|
|
}
|
|
|
|
static Standard_Real ComputeMinEdgeSize(const TopTools_SequenceOfShape& theEdges,
|
|
const TopoDS_Face& theRefFace,
|
|
TopTools_MapOfShape& theEdgesMap)
|
|
{
|
|
Standard_Real MinSize = RealLast();
|
|
|
|
for (Standard_Integer ind = 1; ind <= theEdges.Length(); ind++)
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(theEdges(ind));
|
|
theEdgesMap.Add(anEdge);
|
|
TopoDS_Vertex V1, V2;
|
|
TopExp::Vertices(anEdge, V1, V2);
|
|
BRepAdaptor_Curve2d BAcurve2d(anEdge, theRefFace);
|
|
gp_Pnt2d FirstP2d = BAcurve2d.Value(BAcurve2d.FirstParameter());
|
|
gp_Pnt2d LastP2d = BAcurve2d.Value(BAcurve2d.LastParameter());
|
|
Standard_Real aSqDist;
|
|
if (V1.IsSame(V2) && !BRep_Tool::Degenerated(anEdge))
|
|
{
|
|
gp_Pnt2d MidP2d =
|
|
BAcurve2d.Value((BAcurve2d.FirstParameter() + BAcurve2d.LastParameter()) / 2);
|
|
aSqDist = FirstP2d.SquareDistance(MidP2d);
|
|
}
|
|
else
|
|
aSqDist = FirstP2d.SquareDistance(LastP2d);
|
|
if (aSqDist < MinSize)
|
|
MinSize = aSqDist;
|
|
}
|
|
MinSize = std::sqrt(MinSize);
|
|
return MinSize;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : FindCoordBounds
|
|
// purpose : Searching for origin of U in 2d space
|
|
// Returns Standard_False if could not find curve on surface
|
|
// Returns Standard_True if succeed
|
|
//=======================================================================
|
|
static Standard_Boolean FindCoordBounds(const TopTools_SequenceOfShape& theFaces,
|
|
const TopoDS_Face& theRefFace,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theMapEF,
|
|
const TopTools_MapOfShape& theEdgesMap,
|
|
const Standard_Integer theIndCoord,
|
|
const Standard_Real thePeriod,
|
|
Standard_Real& theMinCoord,
|
|
Standard_Real& theMaxCoord,
|
|
Standard_Integer& theNumberOfIntervals,
|
|
Standard_Integer& theIndFaceMax)
|
|
{
|
|
NCollection_Sequence<std::pair<Standard_Real, Standard_Real>> aPairSeq;
|
|
|
|
Standard_Real aSimpleMax = RealFirst();
|
|
theIndFaceMax = 0;
|
|
|
|
TopTools_IndexedMapOfShape aUsedFaces;
|
|
TopoDS_Face aLastFace;
|
|
for (Standard_Integer ii = 1; ii <= theFaces.Length(); ii++)
|
|
{
|
|
Standard_Integer anIndFace = 0;
|
|
// Get a face bordering with previous ones
|
|
TopoDS_Face aFace = GetFaceFromSeq(theFaces, theRefFace, theMapEF, aUsedFaces, anIndFace);
|
|
Standard_Real aMinCoord = RealLast(), aMaxCoord = RealFirst();
|
|
TopExp_Explorer Explo(aFace, TopAbs_EDGE);
|
|
for (; Explo.More(); Explo.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(Explo.Current());
|
|
if (!theEdgesMap.Contains(anEdge))
|
|
continue;
|
|
Standard_Real fpar, lpar;
|
|
Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(anEdge, theRefFace, fpar, lpar);
|
|
if (aPCurve.IsNull())
|
|
{
|
|
return Standard_False;
|
|
}
|
|
UpdateBoundaries(aPCurve, fpar, lpar, theIndCoord, aMinCoord, aMaxCoord);
|
|
}
|
|
|
|
if (Precision::IsInfinite(aMinCoord) || Precision::IsInfinite(aMaxCoord))
|
|
continue;
|
|
|
|
if (aMaxCoord > aSimpleMax)
|
|
{
|
|
aSimpleMax = aMaxCoord;
|
|
theIndFaceMax = anIndFace;
|
|
}
|
|
|
|
// Insert new interval (aMinCoord, aMaxCoord) into sequence of intervals
|
|
Standard_Boolean anIsInInterval = Standard_False;
|
|
for (Standard_Integer jj = 1; jj <= aPairSeq.Length(); jj++)
|
|
{
|
|
Standard_Real aLocalMin = aPairSeq(jj).first;
|
|
Standard_Real aLocalMax = aPairSeq(jj).second;
|
|
if (aMinCoord >= aLocalMin && aMinCoord <= aLocalMax && aMaxCoord >= aLocalMin
|
|
&& aMaxCoord <= aLocalMax)
|
|
{
|
|
anIsInInterval = Standard_True;
|
|
break;
|
|
}
|
|
|
|
if (aMinCoord < aLocalMin && (aMaxCoord >= aLocalMin && aMaxCoord <= aLocalMax))
|
|
{
|
|
aPairSeq(jj).first = aMinCoord;
|
|
anIsInInterval = Standard_True;
|
|
break;
|
|
}
|
|
else if (aMinCoord < aLocalMin && aMaxCoord > aLocalMax)
|
|
{
|
|
aPairSeq(jj).first = aMinCoord;
|
|
aPairSeq(jj).second = aMaxCoord;
|
|
anIsInInterval = Standard_True;
|
|
break;
|
|
}
|
|
else if ((aMinCoord >= aLocalMin && aMinCoord <= aLocalMax) && aMaxCoord > aLocalMax)
|
|
{
|
|
aPairSeq(jj).second = aMaxCoord;
|
|
anIsInInterval = Standard_True;
|
|
break;
|
|
}
|
|
}
|
|
if (!anIsInInterval)
|
|
{
|
|
std::pair<Standard_Real, Standard_Real> anInterval(aMinCoord, aMaxCoord);
|
|
if (!aPairSeq.IsEmpty() && aMaxCoord < aPairSeq(1).first)
|
|
aPairSeq.Prepend(anInterval);
|
|
else
|
|
aPairSeq.Append(anInterval);
|
|
}
|
|
}
|
|
|
|
theNumberOfIntervals = aPairSeq.Length();
|
|
|
|
if (aPairSeq.Length() == 2)
|
|
{
|
|
theMinCoord = aPairSeq(2).first - thePeriod;
|
|
}
|
|
else if (aPairSeq.Length() > 0)
|
|
{
|
|
theMinCoord = aPairSeq(1).first;
|
|
}
|
|
else
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
theMaxCoord = aPairSeq(1).second;
|
|
return Standard_True;
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
// Returns the start and end points of the edge in parametric space of the face.
|
|
// The orientation of the edge is taken into account, so the start and end points
|
|
// will be swapped if the edge has a reversed orientation.
|
|
// @param theEdge The edge to get the points from.
|
|
// @param theRefFace The reference face to get the parametric points.
|
|
// @return A pair of points representing the start and end points of the edge in parametric space.
|
|
static std::pair<gp_Pnt2d, gp_Pnt2d> getCurveParams(const TopoDS_Edge& theEdge,
|
|
const TopoDS_Face& theRefFace)
|
|
{
|
|
BRepAdaptor_Curve2d aCurveAdaptor(theEdge, theRefFace);
|
|
Standard_Real aFirstParam = aCurveAdaptor.FirstParameter();
|
|
Standard_Real aLastParam = aCurveAdaptor.LastParameter();
|
|
if (theEdge.Orientation() != TopAbs_FORWARD)
|
|
{
|
|
std::swap(aFirstParam, aLastParam);
|
|
}
|
|
|
|
const gp_Pnt2d aFirstPoint = aCurveAdaptor.Value(aFirstParam);
|
|
const gp_Pnt2d aLastPoint = aCurveAdaptor.Value(aLastParam);
|
|
return {aFirstPoint, aLastPoint};
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
static void RelocatePCurvesToNewUorigin(
|
|
const TopTools_SequenceOfShape& theEdges,
|
|
const TopoDS_Shape& theFirstFace,
|
|
const TopoDS_Face& theRefFace,
|
|
const Standard_Real theCoordTol,
|
|
const Standard_Integer theIndCoord,
|
|
const Standard_Real thePeriod,
|
|
TopTools_IndexedDataMapOfShapeListOfShape& theVEmap,
|
|
NCollection_DataMap<TopoDS_Shape, Handle(Geom2d_Curve)>& theEdgeNewPCurve,
|
|
TopTools_MapOfShape& theUsedEdges)
|
|
{
|
|
TopTools_MapOfShape anEdgesOfFirstFace;
|
|
TopExp::MapShapes(theFirstFace, anEdgesOfFirstFace);
|
|
|
|
for (;;) // walk by contours
|
|
{
|
|
// try to find the start edge that:
|
|
// 1. belongs to outer edges of first face;
|
|
// 2. has minimum U-coord of its start point
|
|
TopoDS_Edge aStartEdge;
|
|
TopAbs_Orientation anOrientation = TopAbs_FORWARD;
|
|
Standard_Real aCoordMin = RealLast();
|
|
for (Standard_Integer anEdgeIndex = 1; anEdgeIndex <= theEdges.Length(); ++anEdgeIndex)
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(theEdges(anEdgeIndex));
|
|
if (theUsedEdges.Contains(anEdge))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!anEdgesOfFirstFace.Contains(anEdge))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (aStartEdge.IsNull())
|
|
{
|
|
aStartEdge = anEdge;
|
|
const auto&& [aFirstPoint, aLastPoint] = getCurveParams(anEdge, theRefFace);
|
|
if (aFirstPoint.Coord(theIndCoord) < aLastPoint.Coord(theIndCoord))
|
|
{
|
|
aCoordMin = aFirstPoint.Coord(theIndCoord);
|
|
anOrientation = TopAbs_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
aCoordMin = aLastPoint.Coord(theIndCoord);
|
|
anOrientation = TopAbs_REVERSED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const auto&& [aFirstPoint, aLastPoint] = getCurveParams(anEdge, theRefFace);
|
|
if (aFirstPoint.Coord(theIndCoord) < aCoordMin)
|
|
{
|
|
aStartEdge = anEdge;
|
|
aCoordMin = aFirstPoint.Coord(theIndCoord);
|
|
anOrientation = TopAbs_FORWARD;
|
|
}
|
|
if (aLastPoint.Coord(theIndCoord) < aCoordMin)
|
|
{
|
|
aStartEdge = anEdge;
|
|
aCoordMin = aLastPoint.Coord(theIndCoord);
|
|
anOrientation = TopAbs_REVERSED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aStartEdge.IsNull()) // all contours are passed
|
|
{
|
|
break;
|
|
}
|
|
|
|
TopoDS_Edge aCurrentEdge = aStartEdge;
|
|
Standard_Real anEdgeStartParam, anEdgeEndParam;
|
|
Handle(Geom2d_Curve) CurPCurve =
|
|
BRep_Tool::CurveOnSurface(aCurrentEdge, theRefFace, anEdgeStartParam, anEdgeEndParam);
|
|
CurPCurve = new Geom2d_TrimmedCurve(CurPCurve, anEdgeStartParam, anEdgeEndParam);
|
|
theEdgeNewPCurve.Bind(aCurrentEdge, CurPCurve);
|
|
if (aCurrentEdge.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
std::swap(anEdgeStartParam, anEdgeEndParam);
|
|
}
|
|
Standard_Real CurParam = (anOrientation == TopAbs_FORWARD) ? anEdgeEndParam : anEdgeStartParam;
|
|
gp_Pnt2d CurPoint = CurPCurve->Value(CurParam);
|
|
|
|
for (;;) // collect pcurves of a contour
|
|
{
|
|
if (!RemoveEdgeFromMap(aCurrentEdge, theVEmap))
|
|
{
|
|
break; // end of contour in 2d
|
|
}
|
|
theUsedEdges.Add(aCurrentEdge);
|
|
TopoDS_Vertex CurVertex = (anOrientation == TopAbs_FORWARD)
|
|
? TopExp::LastVertex(aCurrentEdge, Standard_True)
|
|
: TopExp::FirstVertex(aCurrentEdge, Standard_True);
|
|
|
|
const TopTools_ListOfShape& Elist = theVEmap.FindFromKey(CurVertex);
|
|
if (Elist.IsEmpty())
|
|
{
|
|
break; // end of contour in 3d
|
|
}
|
|
|
|
for (TopTools_ListIteratorOfListOfShape itl(Elist); itl.More(); itl.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
|
|
if (anEdge.IsSame(aCurrentEdge))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TopoDS_Vertex aFirstVertex = (anOrientation == TopAbs_FORWARD)
|
|
? TopExp::FirstVertex(anEdge, Standard_True)
|
|
: TopExp::LastVertex(anEdge, Standard_True);
|
|
if (!aFirstVertex.IsSame(CurVertex)) // may be if CurVertex is deg.vertex
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, theRefFace, anEdgeStartParam, anEdgeEndParam);
|
|
aPCurve = new Geom2d_TrimmedCurve(aPCurve, anEdgeStartParam, anEdgeEndParam);
|
|
if (anEdge.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
std::swap(anEdgeStartParam, anEdgeEndParam);
|
|
}
|
|
Standard_Real aParam =
|
|
(anOrientation == TopAbs_FORWARD) ? anEdgeStartParam : anEdgeEndParam;
|
|
gp_Pnt2d aPoint = aPCurve->Value(aParam);
|
|
Standard_Real anOffset = CurPoint.Coord(theIndCoord) - aPoint.Coord(theIndCoord);
|
|
if (!(std::abs(anOffset) < theCoordTol
|
|
|| std::abs(std::abs(anOffset) - thePeriod) < theCoordTol))
|
|
{
|
|
continue; // may be if CurVertex is deg.vertex
|
|
}
|
|
|
|
if (std::abs(anOffset) > thePeriod / 2)
|
|
{
|
|
anOffset = TrueValueOfOffset(anOffset, thePeriod);
|
|
gp_Vec2d aVec;
|
|
if (theIndCoord == 1)
|
|
aVec.SetCoord(anOffset, 0.);
|
|
else
|
|
aVec.SetCoord(0., anOffset);
|
|
Handle(Geom2d_Curve) aNewPCurve = Handle(Geom2d_Curve)::DownCast(aPCurve->Copy());
|
|
aNewPCurve->Translate(aVec);
|
|
aPCurve = aNewPCurve;
|
|
}
|
|
theEdgeNewPCurve.Bind(anEdge, aPCurve);
|
|
aCurrentEdge = anEdge;
|
|
TopAbs_Orientation CurOr = TopAbs::Compose(anOrientation, aCurrentEdge.Orientation());
|
|
CurParam = (CurOr == TopAbs_FORWARD) ? aPCurve->LastParameter() : aPCurve->FirstParameter();
|
|
CurPoint = aPCurve->Value(CurParam);
|
|
break;
|
|
}
|
|
} // for (;;) (collect pcurves of a contour)
|
|
} // for (;;) (walk by contours)
|
|
}
|
|
|
|
static void InsertWiresIntoFaces(const TopTools_SequenceOfShape& theWires,
|
|
const TopTools_SequenceOfShape& theFaces,
|
|
const TopoDS_Face& theRefFace)
|
|
{
|
|
BRep_Builder BB;
|
|
for (Standard_Integer ii = 1; ii <= theWires.Length(); ii++)
|
|
{
|
|
const TopoDS_Wire& aWire = TopoDS::Wire(theWires(ii));
|
|
TopoDS_Iterator iter(aWire);
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(iter.Value());
|
|
BRepAdaptor_Curve2d BAcurve2d(anEdge, theRefFace);
|
|
gp_Pnt2d aPnt2d =
|
|
BAcurve2d.Value((BAcurve2d.FirstParameter() + BAcurve2d.LastParameter()) / 2.);
|
|
TopoDS_Shape RequiredFace;
|
|
for (Standard_Integer jj = 1; jj <= theFaces.Length(); jj++)
|
|
{
|
|
const TopoDS_Face& aFace = TopoDS::Face(theFaces(jj));
|
|
BRepTopAdaptor_FClass2d Classifier(aFace, Precision::Confusion());
|
|
TopAbs_State aStatus = Classifier.Perform(aPnt2d);
|
|
if (aStatus == TopAbs_IN)
|
|
{
|
|
RequiredFace = aFace.Oriented(TopAbs_FORWARD);
|
|
break;
|
|
}
|
|
}
|
|
if (!RequiredFace.IsNull())
|
|
{
|
|
BB.Add(RequiredFace, aWire);
|
|
}
|
|
else
|
|
{
|
|
Standard_ASSERT_INVOKE("ShapeUpgrade_UnifySameDomain: wire remains unclassified");
|
|
}
|
|
}
|
|
}
|
|
|
|
static TopoDS_Face FindCommonFace(const TopoDS_Edge& theEdge1,
|
|
const TopoDS_Edge& theEdge2,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap,
|
|
TopAbs_Orientation& theOrOfE1OnFace,
|
|
TopAbs_Orientation& theOrOfE2OnFace)
|
|
{
|
|
TopoDS_Vertex aVertex;
|
|
TopExp::CommonVertex(theEdge1, theEdge2, aVertex);
|
|
const TopTools_ListOfShape& Flist = theVFmap.FindFromKey(aVertex);
|
|
TopTools_ListIteratorOfListOfShape itl(Flist);
|
|
for (; itl.More(); itl.Next())
|
|
{
|
|
TopoDS_Face aFace = TopoDS::Face(itl.Value());
|
|
aFace.Orientation(TopAbs_FORWARD);
|
|
Standard_Boolean e1found = Standard_False, e2found = Standard_False;
|
|
TopExp_Explorer Explo(aFace, TopAbs_EDGE);
|
|
for (; Explo.More(); Explo.Next())
|
|
{
|
|
const TopoDS_Shape& anEdge = Explo.Current();
|
|
if (anEdge.IsSame(theEdge1))
|
|
{
|
|
e1found = Standard_True;
|
|
theOrOfE1OnFace = anEdge.Orientation();
|
|
}
|
|
if (anEdge.IsSame(theEdge2))
|
|
{
|
|
e2found = Standard_True;
|
|
theOrOfE2OnFace = anEdge.Orientation();
|
|
}
|
|
if (e1found && e2found)
|
|
return aFace;
|
|
}
|
|
}
|
|
|
|
TopoDS_Face NullFace;
|
|
return NullFace;
|
|
}
|
|
|
|
static Standard_Boolean FindClosestPoints(const TopoDS_Edge& theEdge1,
|
|
const TopoDS_Edge& theEdge2,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap,
|
|
TopoDS_Face& theCommonFace,
|
|
Standard_Real& theMinSqDist,
|
|
TopAbs_Orientation& OrOfE1OnFace,
|
|
TopAbs_Orientation& OrOfE2OnFace,
|
|
Standard_Integer& theIndOnE1,
|
|
Standard_Integer& theIndOnE2,
|
|
gp_Pnt2d* PointsOnEdge1,
|
|
gp_Pnt2d* PointsOnEdge2)
|
|
|
|
{
|
|
theCommonFace = FindCommonFace(theEdge1, theEdge2, theVFmap, OrOfE1OnFace, OrOfE2OnFace);
|
|
if (theCommonFace.IsNull())
|
|
return Standard_False;
|
|
|
|
Standard_Real fpar1, lpar1, fpar2, lpar2;
|
|
Handle(Geom2d_Curve) PCurve1 = BRep_Tool::CurveOnSurface(theEdge1, theCommonFace, fpar1, lpar1);
|
|
Handle(Geom2d_Curve) PCurve2 = BRep_Tool::CurveOnSurface(theEdge2, theCommonFace, fpar2, lpar2);
|
|
PointsOnEdge1[0] = PCurve1->Value(fpar1);
|
|
PointsOnEdge1[1] = PCurve1->Value(lpar1);
|
|
PointsOnEdge2[0] = PCurve2->Value(fpar2);
|
|
PointsOnEdge2[1] = PCurve2->Value(lpar2);
|
|
theMinSqDist = RealLast();
|
|
theIndOnE1 = -1;
|
|
theIndOnE2 = -1;
|
|
for (Standard_Integer ind1 = 0; ind1 < 2; ind1++)
|
|
for (Standard_Integer ind2 = 0; ind2 < 2; ind2++)
|
|
{
|
|
Standard_Real aSqDist = PointsOnEdge1[ind1].SquareDistance(PointsOnEdge2[ind2]);
|
|
if (aSqDist < theMinSqDist)
|
|
{
|
|
theMinSqDist = aSqDist;
|
|
theIndOnE1 = ind1;
|
|
theIndOnE2 = ind2;
|
|
}
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static void ReconstructMissedSeam(const TopTools_SequenceOfShape& theRemovedEdges,
|
|
const TopoDS_Face& theFrefFace,
|
|
const TopoDS_Edge& theCurEdge,
|
|
const TopoDS_Vertex& theCurVertex,
|
|
const gp_Pnt2d& theCurPoint,
|
|
const Standard_Real theUperiod,
|
|
const Standard_Real theVperiod,
|
|
TopoDS_Edge& theSeamEdge,
|
|
gp_Pnt2d& theNextPoint)
|
|
{
|
|
Handle(Geom_Surface) RefSurf = BRep_Tool::Surface(theFrefFace);
|
|
|
|
// Find seam edge between removed edges
|
|
theSeamEdge.Nullify();
|
|
for (Standard_Integer i = 1; i <= theRemovedEdges.Length(); i++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(theRemovedEdges(i));
|
|
if (anEdge.IsSame(theCurEdge))
|
|
continue;
|
|
Standard_Real Param1, Param2;
|
|
Handle(Geom2d_Curve) aPC = BRep_Tool::CurveOnSurface(anEdge, theFrefFace, Param1, Param2);
|
|
if (aPC.IsNull())
|
|
continue;
|
|
|
|
TopoDS_Vertex aFirstVertex, aLastVertex;
|
|
TopExp::Vertices(anEdge, aFirstVertex, aLastVertex, Standard_True);
|
|
|
|
if ((aFirstVertex.IsSame(theCurVertex) || aLastVertex.IsSame(theCurVertex))
|
|
&& BRep_Tool::IsClosed(anEdge, theFrefFace))
|
|
{
|
|
Standard_Real aParam = (anEdge.Orientation() == TopAbs_FORWARD) ? Param1 : Param2;
|
|
gp_Pnt2d aPoint = aPC->Value(aParam);
|
|
Standard_Real aUdiff = std::abs(aPoint.X() - theCurPoint.X());
|
|
Standard_Real aVdiff = std::abs(aPoint.Y() - theCurPoint.Y());
|
|
if ((theUperiod != 0. && aUdiff > theUperiod / 2)
|
|
|| (theVperiod != 0. && aVdiff > theVperiod / 2))
|
|
{
|
|
if (aLastVertex.IsSame(theCurVertex) || (theUperiod != 0. && theVperiod != 0.))
|
|
{
|
|
anEdge.Reverse();
|
|
}
|
|
else
|
|
{
|
|
TopAbs_Orientation anOri = anEdge.Orientation();
|
|
anEdge.Orientation(TopAbs_FORWARD);
|
|
Handle(Geom2d_Curve) aPC1 =
|
|
BRep_Tool::CurveOnSurface(anEdge, theFrefFace, Param1, Param2);
|
|
anEdge.Reverse();
|
|
Handle(Geom2d_Curve) aPC2 =
|
|
BRep_Tool::CurveOnSurface(anEdge, theFrefFace, Param1, Param2);
|
|
anEdge.Reverse(); // again FORWARD
|
|
TopLoc_Location aLoc;
|
|
BRep_Builder aBB;
|
|
Standard_Real aTol = BRep_Tool::Tolerance(anEdge);
|
|
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFrefFace, aLoc);
|
|
aBB.UpdateEdge(anEdge, aPC2, aPC1, aSurf, aLoc, aTol);
|
|
anEdge.Orientation(anOri);
|
|
}
|
|
aPC = BRep_Tool::CurveOnSurface(anEdge, theFrefFace, Param1, Param2);
|
|
aParam = (anEdge.Orientation() == TopAbs_FORWARD) ? Param1 : Param2;
|
|
aPoint = aPC->Value(aParam);
|
|
aUdiff = std::abs(aPoint.X() - theCurPoint.X());
|
|
aVdiff = std::abs(aPoint.Y() - theCurPoint.Y());
|
|
}
|
|
if ((theUperiod == 0. || aUdiff < theUperiod / 2)
|
|
&& (theVperiod == 0. || aVdiff < theVperiod / 2))
|
|
{
|
|
aFirstVertex = TopExp::FirstVertex(anEdge, Standard_True);
|
|
if (aFirstVertex.IsSame(theCurVertex))
|
|
{
|
|
theSeamEdge = anEdge;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!theSeamEdge.IsNull())
|
|
{
|
|
Standard_Real Param1, Param2;
|
|
Handle(Geom2d_Curve) aPC = BRep_Tool::CurveOnSurface(theSeamEdge, theFrefFace, Param1, Param2);
|
|
Standard_Real aParam = (theSeamEdge.Orientation() == TopAbs_FORWARD) ? Param2 : Param1;
|
|
theNextPoint = aPC->Value(aParam);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static Standard_Boolean SameSurf(const Handle(Geom_Surface)& theS1,
|
|
const Handle(Geom_Surface)& theS2)
|
|
{
|
|
static Standard_Real aCoefs[2] = {0.3399811, 0.7745966};
|
|
|
|
Standard_Real uf1, ul1, vf1, vl1, uf2, ul2, vf2, vl2;
|
|
theS1->Bounds(uf1, ul1, vf1, vl1);
|
|
theS2->Bounds(uf2, ul2, vf2, vl2);
|
|
constexpr Standard_Real aPTol = Precision::PConfusion();
|
|
if (Precision::IsNegativeInfinite(uf1))
|
|
{
|
|
if (!Precision::IsNegativeInfinite(uf2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
uf1 = std::min(-1., (ul1 - 1.));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Precision::IsNegativeInfinite(uf2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
if (std::abs(uf1 - uf2) > aPTol)
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (Precision::IsNegativeInfinite(vf1))
|
|
{
|
|
if (!Precision::IsNegativeInfinite(vf2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
vf1 = std::min(-1., (vl1 - 1.));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Precision::IsNegativeInfinite(vf2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
if (std::abs(vf1 - vf2) > aPTol)
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (Precision::IsPositiveInfinite(ul1))
|
|
{
|
|
if (!Precision::IsPositiveInfinite(ul2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
ul1 = std::max(1., (uf1 + 1.));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Precision::IsPositiveInfinite(ul2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
if (std::abs(ul1 - ul2) > aPTol)
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
if (Precision::IsPositiveInfinite(vl1))
|
|
{
|
|
if (!Precision::IsPositiveInfinite(vl2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
vl1 = std::max(1., (vf1 + 1.));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Precision::IsPositiveInfinite(vl2))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
else
|
|
{
|
|
if (std::abs(vl1 - vl2) > aPTol)
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
|
|
Standard_Real u, v, du = (ul1 - uf1), dv = (vl1 - vf1);
|
|
Standard_Integer i, j;
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
u = uf1 + aCoefs[i] * du;
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
v = vf1 + aCoefs[j] * dv;
|
|
gp_Pnt aP1 = theS1->Value(u, v);
|
|
gp_Pnt aP2 = theS2->Value(u, v);
|
|
if (!aP1.IsEqual(aP2, aPTol))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Standard_True;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static void TransformPCurves(const TopoDS_Face& theRefFace,
|
|
const TopoDS_Face& theFace,
|
|
TopTools_MapOfShape& theMapEdgesWithTemporaryPCurves)
|
|
{
|
|
Handle(Geom_Surface) RefSurf = BRep_Tool::Surface(theRefFace);
|
|
if (RefSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
|
|
RefSurf = (Handle(Geom_RectangularTrimmedSurface)::DownCast(RefSurf))->BasisSurface();
|
|
|
|
Handle(Geom_Surface) SurfFace = BRep_Tool::Surface(theFace);
|
|
if (SurfFace->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
|
|
SurfFace = (Handle(Geom_RectangularTrimmedSurface)::DownCast(SurfFace))->BasisSurface();
|
|
|
|
Standard_Boolean ToModify = Standard_False, ToTranslate = Standard_False,
|
|
ToRotate = Standard_False, X_Reverse = Standard_False,
|
|
Y_Reverse = Standard_False, ToProject = Standard_False;
|
|
|
|
Standard_Real aTranslation = 0., anAngle = 0.;
|
|
|
|
// Get axes of surface of face and of surface of RefFace
|
|
Handle(Geom_ElementarySurface) ElemSurfFace = Handle(Geom_ElementarySurface)::DownCast(SurfFace);
|
|
Handle(Geom_ElementarySurface) ElemRefSurf = Handle(Geom_ElementarySurface)::DownCast(RefSurf);
|
|
|
|
if (!ElemSurfFace.IsNull() && !ElemRefSurf.IsNull())
|
|
{
|
|
gp_Ax3 AxisOfSurfFace = ElemSurfFace->Position();
|
|
gp_Ax3 AxisOfRefSurf = ElemRefSurf->Position();
|
|
|
|
gp_Pnt OriginRefSurf = AxisOfRefSurf.Location();
|
|
|
|
Standard_Real aParam = ElCLib::LineParameter(AxisOfSurfFace.Axis(), OriginRefSurf);
|
|
|
|
if (std::abs(aParam) > Precision::PConfusion())
|
|
aTranslation = -aParam;
|
|
|
|
gp_Dir VdirSurfFace = AxisOfSurfFace.Direction();
|
|
gp_Dir VdirRefSurf = AxisOfRefSurf.Direction();
|
|
gp_Dir XdirSurfFace = AxisOfSurfFace.XDirection();
|
|
gp_Dir XdirRefSurf = AxisOfRefSurf.XDirection();
|
|
|
|
gp_Dir CrossProd1 = AxisOfRefSurf.XDirection() ^ AxisOfRefSurf.YDirection();
|
|
gp_Dir CrossProd2 = AxisOfSurfFace.XDirection() ^ AxisOfSurfFace.YDirection();
|
|
if (CrossProd1 * CrossProd2 < 0.)
|
|
X_Reverse = Standard_True;
|
|
|
|
Standard_Real ScalProd = VdirSurfFace * VdirRefSurf;
|
|
if (ScalProd < 0.)
|
|
Y_Reverse = Standard_True;
|
|
|
|
if (!X_Reverse && !Y_Reverse)
|
|
{
|
|
gp_Dir DirRef = VdirRefSurf;
|
|
if (!AxisOfRefSurf.Direct())
|
|
DirRef.Reverse();
|
|
anAngle = XdirRefSurf.AngleWithRef(XdirSurfFace, DirRef);
|
|
}
|
|
else
|
|
anAngle = XdirRefSurf.Angle(XdirSurfFace);
|
|
|
|
ToRotate = (std::abs(anAngle) > Precision::PConfusion());
|
|
|
|
ToTranslate = (std::abs(aTranslation) > Precision::PConfusion());
|
|
|
|
ToModify = ToTranslate || ToRotate || X_Reverse || Y_Reverse;
|
|
}
|
|
else
|
|
{
|
|
if (!SameSurf(RefSurf, SurfFace))
|
|
{
|
|
ToProject = Standard_True;
|
|
}
|
|
}
|
|
|
|
BRep_Builder BB;
|
|
TopExp_Explorer Explo(theFace, TopAbs_EDGE);
|
|
TopTools_MapOfShape aEmap;
|
|
for (; Explo.More(); Explo.Next())
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(Explo.Current());
|
|
if (BRep_Tool::Degenerated(anEdge) && ToModify)
|
|
continue;
|
|
|
|
if (ToProject && BRep_Tool::IsClosed(anEdge, theFace))
|
|
continue;
|
|
|
|
if (!aEmap.Add(anEdge))
|
|
continue;
|
|
|
|
TopAbs_Orientation anOr = anEdge.Orientation();
|
|
|
|
Standard_Real fpar, lpar;
|
|
Handle(Geom2d_Curve) PCurveOnRef = BRep_Tool::CurveOnSurface(anEdge, theRefFace, fpar, lpar);
|
|
Handle(Geom2d_Curve) PCurve2;
|
|
if (!PCurveOnRef.IsNull() /* && !(ToModify || ToProject)*/)
|
|
{
|
|
anEdge.Reverse();
|
|
PCurve2 = BRep_Tool::CurveOnSurface(anEdge, theRefFace, fpar, lpar);
|
|
if (PCurve2 != PCurveOnRef) // two pcurves
|
|
continue;
|
|
}
|
|
|
|
Handle(Geom2d_Curve) PCurves[2], NewPCurves[2];
|
|
anEdge.Orientation(TopAbs_FORWARD);
|
|
PCurves[0] = BRep_Tool::CurveOnSurface(anEdge, theFace, fpar, lpar);
|
|
anEdge.Reverse();
|
|
PCurves[1] = BRep_Tool::CurveOnSurface(anEdge, theFace, fpar, lpar);
|
|
|
|
Standard_Integer NbPcurves = (PCurves[0] == PCurves[1]) ? 1 : 2;
|
|
|
|
for (Standard_Integer ii = 0; ii < NbPcurves; ii++)
|
|
{
|
|
if (ToProject)
|
|
{
|
|
Handle(Geom_Curve) aC3d = BRep_Tool::Curve(anEdge, fpar, lpar);
|
|
aC3d = new Geom_TrimmedCurve(aC3d, fpar, lpar);
|
|
Standard_Real tol = BRep_Tool::Tolerance(anEdge);
|
|
tol = std::min(tol, Precision::Approximation());
|
|
NewPCurves[ii] = GeomProjLib::Curve2d(aC3d, RefSurf);
|
|
}
|
|
else
|
|
{
|
|
NewPCurves[ii] = Handle(Geom2d_Curve)::DownCast(PCurves[ii]->Copy());
|
|
}
|
|
if (ToTranslate)
|
|
NewPCurves[ii]->Translate(gp_Vec2d(0., aTranslation));
|
|
if (Y_Reverse)
|
|
NewPCurves[ii]->Mirror(gp::OX2d());
|
|
if (X_Reverse)
|
|
{
|
|
NewPCurves[ii]->Mirror(gp::OY2d());
|
|
NewPCurves[ii]->Translate(gp_Vec2d(2 * M_PI, 0.));
|
|
}
|
|
if (ToRotate)
|
|
NewPCurves[ii]->Translate(gp_Vec2d(anAngle, 0.));
|
|
}
|
|
|
|
anEdge.Orientation(TopAbs_FORWARD);
|
|
|
|
if (NbPcurves == 1)
|
|
{
|
|
if (PCurve2.IsNull() || (!RefSurf->IsUClosed() && !RefSurf->IsVClosed()))
|
|
{
|
|
BB.UpdateEdge(anEdge, NewPCurves[0], theRefFace, 0.);
|
|
theMapEdgesWithTemporaryPCurves.Add(anEdge);
|
|
}
|
|
else
|
|
{
|
|
// check: may be it is the same pcurve
|
|
Standard_Real aUmin, aUmax, aVmin, aVmax;
|
|
RefSurf->Bounds(aUmin, aUmax, aVmin, aVmax);
|
|
Standard_Real aUperiod = (RefSurf->IsUClosed()) ? (aUmax - aUmin) : 0.;
|
|
Standard_Real aVperiod = (RefSurf->IsVClosed()) ? (aVmax - aVmin) : 0.;
|
|
gp_Pnt2d aP2dOnPCurve1 = PCurveOnRef->Value(fpar);
|
|
gp_Pnt2d aP2dOnPCurve2 = NewPCurves[0]->Value(fpar);
|
|
if ((aUperiod != 0. && std::abs(aP2dOnPCurve1.X() - aP2dOnPCurve2.X()) > aUperiod / 2)
|
|
|| (aVperiod != 0. && std::abs(aP2dOnPCurve1.Y() - aP2dOnPCurve2.Y()) > aVperiod / 2))
|
|
{
|
|
Handle(Geom2d_Curve) NullPCurve;
|
|
BB.UpdateEdge(anEdge, NullPCurve, theRefFace, 0.);
|
|
if (anOr == TopAbs_FORWARD)
|
|
BB.UpdateEdge(anEdge, NewPCurves[0], PCurveOnRef, theRefFace, 0.);
|
|
else
|
|
BB.UpdateEdge(anEdge, PCurveOnRef, NewPCurves[0], theRefFace, 0.);
|
|
|
|
theMapEdgesWithTemporaryPCurves.Add(anEdge);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BB.UpdateEdge(anEdge, NewPCurves[0], NewPCurves[1], theRefFace, 0.);
|
|
theMapEdgesWithTemporaryPCurves.Add(anEdge);
|
|
}
|
|
|
|
BB.Range(anEdge, fpar, lpar);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static void AddPCurves(const TopTools_SequenceOfShape& theFaces,
|
|
const TopoDS_Face& theRefFace,
|
|
TopTools_MapOfShape& theMapEdgesWithTemporaryPCurves)
|
|
{
|
|
BRepAdaptor_Surface RefBAsurf(theRefFace, Standard_False);
|
|
|
|
GeomAbs_SurfaceType aType = RefBAsurf.GetType();
|
|
if (aType == GeomAbs_Plane)
|
|
return;
|
|
|
|
for (Standard_Integer i = 1; i <= theFaces.Length(); i++)
|
|
{
|
|
TopoDS_Face aFace = TopoDS::Face(theFaces(i));
|
|
aFace.Orientation(TopAbs_FORWARD);
|
|
if (aFace.IsSame(theRefFace))
|
|
continue;
|
|
|
|
TransformPCurves(theRefFace, aFace, theMapEdgesWithTemporaryPCurves);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
// 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,
|
|
TopTools_SequenceOfShape& theRemovedEdges)
|
|
{
|
|
// map of edges
|
|
TopTools_IndexedMapOfShape aNewEdges;
|
|
// add edges without seams
|
|
for (TopExp_Explorer exp(aShape, TopAbs_EDGE); exp.More(); exp.Next())
|
|
{
|
|
const TopoDS_Shape& edge = exp.Current();
|
|
if (aNewEdges.Contains(edge))
|
|
{
|
|
aNewEdges.RemoveKey(edge);
|
|
theRemovedEdges.Append(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);
|
|
theRemovedEdges.Append(current);
|
|
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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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();
|
|
|
|
while (aBasis->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
Handle(Geom_TrimmedCurve) aTc = Handle(Geom_TrimmedCurve)::DownCast(aBasis);
|
|
aBasis = aTc->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();
|
|
|
|
while (aBasis->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
Handle(Geom_TrimmedCurve) aTc = Handle(Geom_TrimmedCurve)::DownCast(aBasis);
|
|
aBasis = aTc->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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static Handle(Geom_Surface) ClearRts(const Handle(Geom_Surface)& aSurface)
|
|
{
|
|
const Handle(Geom_RectangularTrimmedSurface) aRTS =
|
|
Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
|
|
return aRTS.IsNull() ? aSurface : aRTS->BasisSurface();
|
|
}
|
|
|
|
//=======================================================================
|
|
// 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
|
|
Handle(Geom2d_Curve) aC2d;
|
|
if (BRep_Tool::IsClosed(theEdge, theFace))
|
|
{
|
|
// Find the edge in the face: it will have correct orientation
|
|
TopoDS_Edge anEdgeInFace;
|
|
TopoDS_Face aFace = theFace;
|
|
aFace.Orientation(TopAbs_FORWARD);
|
|
TopExp_Explorer anExplo(aFace, TopAbs_EDGE);
|
|
for (; anExplo.More(); anExplo.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(anExplo.Current());
|
|
if (anEdge.IsSame(theEdge))
|
|
{
|
|
anEdgeInFace = anEdge;
|
|
break;
|
|
}
|
|
}
|
|
if (anEdgeInFace.IsNull())
|
|
return Standard_False;
|
|
|
|
aC2d = BRep_Tool::CurveOnSurface(anEdgeInFace, aFace, f, l);
|
|
}
|
|
else
|
|
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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static Standard_Boolean IsSameDomain(
|
|
const TopoDS_Face& aFace,
|
|
const TopoDS_Face& aCheckedFace,
|
|
const Standard_Real theLinTol,
|
|
const Standard_Real theAngTol,
|
|
ShapeUpgrade_UnifySameDomain::DataMapOfFacePlane& theFacePlaneMap)
|
|
{
|
|
// 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)
|
|
{
|
|
Handle(Geom_Plane) aPlaneOfFaces;
|
|
if (theFacePlaneMap.IsBound(aFace))
|
|
aPlaneOfFaces = theFacePlaneMap(aFace);
|
|
else if (theFacePlaneMap.IsBound(aCheckedFace))
|
|
aPlaneOfFaces = theFacePlaneMap(aCheckedFace);
|
|
else
|
|
aPlaneOfFaces = new Geom_Plane(aPln1);
|
|
|
|
theFacePlaneMap.Bind(aFace, aPlaneOfFaces);
|
|
theFacePlaneMap.Bind(aCheckedFace, aPlaneOfFaces);
|
|
|
|
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_Surface) aGA1 = new GeomAdaptor_Surface(S1);
|
|
Handle(GeomAdaptor_Surface) aGA2 = new GeomAdaptor_Surface(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 const&)
|
|
{
|
|
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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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 remaining Vertex
|
|
Standard_Boolean closed_flag = Standard_False;
|
|
GeomConvert::ConcatC1(tab_c3d,
|
|
tabtolvertex,
|
|
ArrayOfIndices,
|
|
concatcurve,
|
|
closed_flag,
|
|
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 remaining Vertex
|
|
closed_flag = Standard_False;
|
|
Geom2dConvert::ConcatC1(tab_c2d,
|
|
tabtolvertex,
|
|
ArrayOfInd2d,
|
|
concatc2d,
|
|
closed_flag,
|
|
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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::UnionPCurves(const TopTools_SequenceOfShape& theChain,
|
|
TopoDS_Edge& theEdge)
|
|
{
|
|
Standard_Real aFirst3d, aLast3d;
|
|
Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst3d, aLast3d);
|
|
Standard_Real aTolEdge = BRep_Tool::Tolerance(theEdge);
|
|
Standard_Real aMaxTol = aTolEdge;
|
|
|
|
TopTools_SequenceOfShape aFaceSeq;
|
|
|
|
const TopoDS_Edge& aFirstEdge = TopoDS::Edge(theChain.Value(1));
|
|
const TopTools_ListOfShape& aFaceList = myEFmap.FindFromKey(aFirstEdge);
|
|
TopTools_ListIteratorOfListOfShape anItl(aFaceList);
|
|
for (; anItl.More(); anItl.Next())
|
|
{
|
|
TopoDS_Face aFace = TopoDS::Face(anItl.Value());
|
|
if (myFacePlaneMap.IsBound(aFace))
|
|
continue;
|
|
|
|
if (myFaceNewFace.IsBound(aFace))
|
|
aFace = TopoDS::Face(myFaceNewFace(aFace));
|
|
|
|
aFace.Orientation(TopAbs_FORWARD); // to get proper pcurves of seam edges
|
|
|
|
BRepAdaptor_Surface aBAsurf(aFace, Standard_False);
|
|
if (aBAsurf.GetType() == GeomAbs_Plane)
|
|
continue;
|
|
|
|
TopLoc_Location aLoc;
|
|
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace, aLoc);
|
|
Standard_Boolean isFound = Standard_False;
|
|
for (Standard_Integer ii = 1; ii <= aFaceSeq.Length(); ii++)
|
|
{
|
|
TopLoc_Location aPrevLoc;
|
|
Handle(Geom_Surface) aPrevSurf = BRep_Tool::Surface(TopoDS::Face(aFaceSeq(ii)), aPrevLoc);
|
|
if (aPrevSurf == aSurf && aPrevLoc == aLoc)
|
|
{
|
|
isFound = Standard_True;
|
|
break;
|
|
}
|
|
}
|
|
if (isFound)
|
|
continue;
|
|
|
|
aFaceSeq.Append(aFace);
|
|
}
|
|
|
|
TColGeom2d_SequenceOfCurve ResPCurves;
|
|
TColStd_SequenceOfReal ResFirsts;
|
|
TColStd_SequenceOfReal ResLasts;
|
|
TColStd_SequenceOfReal aTolVerSeq;
|
|
TopoDS_Edge aPrevEdge;
|
|
Standard_Boolean anIsSeam = Standard_False;
|
|
|
|
for (Standard_Integer j = 1; j <= aFaceSeq.Length(); j++)
|
|
{
|
|
TColGeom2d_SequenceOfCurve aPCurveSeq;
|
|
TColStd_SequenceOfReal aFirstsSeq;
|
|
TColStd_SequenceOfReal aLastsSeq;
|
|
TColStd_SequenceOfBoolean aForwardsSeq;
|
|
GeomAbs_CurveType aCurrentType = GeomAbs_OtherCurve;
|
|
|
|
Standard_Real aFirst, aLast;
|
|
for (Standard_Integer i = 1; i <= theChain.Length(); i++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(theChain.Value(i));
|
|
Standard_Boolean isForward = (anEdge.Orientation() != TopAbs_REVERSED);
|
|
|
|
if (anIsSeam && j == 2) // second pass
|
|
anEdge.Reverse();
|
|
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, TopoDS::Face(aFaceSeq(j)), aFirst, aLast);
|
|
if (aPCurve.IsNull())
|
|
continue;
|
|
|
|
if (aFaceSeq.Length() == 1)
|
|
{
|
|
TopoDS_Edge aReversedEdge = anEdge;
|
|
aReversedEdge.Reverse();
|
|
Handle(Geom2d_Curve) aPCurve2 =
|
|
BRep_Tool::CurveOnSurface(aReversedEdge, TopoDS::Face(aFaceSeq(j)), aFirst, aLast);
|
|
if (aPCurve != aPCurve2)
|
|
{
|
|
anIsSeam = Standard_True;
|
|
aFaceSeq.Append(aFaceSeq(j));
|
|
}
|
|
}
|
|
|
|
Geom2dAdaptor_Curve anAdaptor(aPCurve);
|
|
GeomAbs_CurveType aType = anAdaptor.GetType();
|
|
|
|
Handle(Geom2d_Line) aLine;
|
|
if (aType == GeomAbs_BSplineCurve || aType == GeomAbs_BezierCurve)
|
|
TryMakeLine(aPCurve, aFirst, aLast, aLine);
|
|
if (!aLine.IsNull())
|
|
{
|
|
aPCurve = aLine;
|
|
anAdaptor.Load(aPCurve);
|
|
aType = GeomAbs_Line;
|
|
}
|
|
|
|
if (aPCurveSeq.IsEmpty())
|
|
{
|
|
Handle(Geom2d_Curve) aCopyPCurve = Handle(Geom2d_Curve)::DownCast(aPCurve->Copy());
|
|
if (aCopyPCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
|
|
aCopyPCurve = (Handle(Geom2d_TrimmedCurve)::DownCast(aCopyPCurve))->BasisCurve();
|
|
|
|
aPCurveSeq.Append(aCopyPCurve);
|
|
aFirstsSeq.Append(aFirst);
|
|
aLastsSeq.Append(aLast);
|
|
aForwardsSeq.Append(isForward);
|
|
aCurrentType = aType;
|
|
aPrevEdge = anEdge;
|
|
continue;
|
|
}
|
|
|
|
Standard_Boolean isSameCurve = Standard_False;
|
|
Standard_Real aNewF = aFirst;
|
|
Standard_Real aNewL = aLast;
|
|
if (aPCurve == aPCurveSeq.Last())
|
|
{
|
|
isSameCurve = Standard_True;
|
|
}
|
|
else if (aType == aCurrentType)
|
|
{
|
|
Geom2dAdaptor_Curve aPrevAdaptor(aPCurveSeq.Last());
|
|
switch (aType)
|
|
{
|
|
case GeomAbs_Line: {
|
|
gp_Lin2d aPrevLin = aPrevAdaptor.Line();
|
|
gp_Pnt2d aFirstP2d = aPCurve->Value(aFirst);
|
|
gp_Pnt2d aLastP2d = aPCurve->Value(aLast);
|
|
if (aPrevLin.Contains(aFirstP2d, Precision::Confusion())
|
|
&& aPrevLin.Contains(aLastP2d, Precision::Confusion()))
|
|
{
|
|
isSameCurve = Standard_True;
|
|
gp_Pnt2d p1 = anAdaptor.Value(aFirst);
|
|
gp_Pnt2d p2 = anAdaptor.Value(aLast);
|
|
aNewF = ElCLib::Parameter(aPrevLin, p1);
|
|
aNewL = ElCLib::Parameter(aPrevLin, p2);
|
|
if (aNewF > aNewL)
|
|
{
|
|
Standard_Real aTmp = aNewF;
|
|
aNewF = aNewL;
|
|
aNewL = aTmp;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case GeomAbs_Circle: {
|
|
gp_Circ2d aCirc = anAdaptor.Circle();
|
|
gp_Circ2d aPrevCirc = aPrevAdaptor.Circle();
|
|
if (aCirc.Location().Distance(aPrevCirc.Location()) <= Precision::Confusion()
|
|
&& std::abs(aCirc.Radius() - aPrevCirc.Radius()) <= Precision::Confusion())
|
|
{
|
|
isSameCurve = Standard_True;
|
|
gp_Pnt2d p1 = anAdaptor.Value(aFirst);
|
|
gp_Pnt2d p2 = anAdaptor.Value(aLast);
|
|
aNewF = ElCLib::Parameter(aPrevCirc, p1);
|
|
aNewL = ElCLib::Parameter(aPrevCirc, p2);
|
|
if (aNewF > aNewL)
|
|
{
|
|
Standard_Real aTmp = aNewF;
|
|
aNewF = aNewL;
|
|
aNewL = aTmp;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (isSameCurve)
|
|
{
|
|
if (aForwardsSeq.Last() == Standard_True)
|
|
aLastsSeq.ChangeLast() = aNewL;
|
|
else
|
|
aFirstsSeq.ChangeLast() = aNewF;
|
|
}
|
|
else
|
|
{
|
|
Handle(Geom2d_Curve) aCopyPCurve = Handle(Geom2d_Curve)::DownCast(aPCurve->Copy());
|
|
if (aCopyPCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
|
|
aCopyPCurve = (Handle(Geom2d_TrimmedCurve)::DownCast(aCopyPCurve))->BasisCurve();
|
|
|
|
aPCurveSeq.Append(aCopyPCurve);
|
|
aFirstsSeq.Append(aFirst);
|
|
aLastsSeq.Append(aLast);
|
|
aForwardsSeq.Append(isForward);
|
|
aCurrentType = aType;
|
|
TopoDS_Vertex aV;
|
|
TopExp::CommonVertex(aPrevEdge, anEdge, aV);
|
|
Standard_Real aTol = BRep_Tool::Tolerance(aV);
|
|
aTolVerSeq.Append(aTol);
|
|
}
|
|
aPrevEdge = anEdge;
|
|
}
|
|
|
|
Handle(Geom2d_Curve) aResPCurve;
|
|
Standard_Real aResFirst, aResLast;
|
|
if (aPCurveSeq.Length() == 1)
|
|
{
|
|
aResPCurve = aPCurveSeq.Last();
|
|
aResFirst = aFirstsSeq.Last();
|
|
aResLast = aLastsSeq.Last();
|
|
if (aForwardsSeq.Last() == Standard_False)
|
|
{
|
|
Standard_Real aNewLast = aResPCurve->ReversedParameter(aResFirst);
|
|
Standard_Real aNewFirst = aResPCurve->ReversedParameter(aResLast);
|
|
aResPCurve->Reverse();
|
|
aResFirst = aNewFirst;
|
|
aResLast = aNewLast;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// C1 concatenation for PCurveSeq
|
|
TColGeom2d_Array1OfBSplineCurve tab_c2d(0, aPCurveSeq.Length() - 1);
|
|
for (Standard_Integer i = 1; i <= aPCurveSeq.Length(); i++)
|
|
{
|
|
Handle(Geom2d_TrimmedCurve) aTrPCurve =
|
|
new Geom2d_TrimmedCurve(aPCurveSeq(i), aFirstsSeq(i), aLastsSeq(i));
|
|
if (aForwardsSeq(i) == Standard_False)
|
|
{
|
|
aTrPCurve->Reverse();
|
|
}
|
|
tab_c2d(i - 1) = Geom2dConvert::CurveToBSplineCurve(aTrPCurve);
|
|
Geom2dConvert::C0BSplineToC1BSplineCurve(tab_c2d(i - 1), Precision::Confusion());
|
|
}
|
|
|
|
TColStd_Array1OfReal tabtolvertex(0, aTolVerSeq.Length() - 1);
|
|
for (Standard_Integer i = 1; i <= aTolVerSeq.Length(); i++)
|
|
{
|
|
Standard_Real aTol = aTolVerSeq(i);
|
|
tabtolvertex(i - 1) = aTol;
|
|
if (aTol > aMaxTol)
|
|
aMaxTol = aTol;
|
|
}
|
|
|
|
Handle(TColGeom2d_HArray1OfBSplineCurve) concatc2d; // array of the concatenated curves
|
|
Handle(TColStd_HArray1OfInteger) ArrayOfInd2d; // array of the remaining Vertex
|
|
Standard_Boolean aClosedFlag = Standard_False;
|
|
Geom2dConvert::ConcatC1(tab_c2d,
|
|
tabtolvertex,
|
|
ArrayOfInd2d,
|
|
concatc2d,
|
|
aClosedFlag,
|
|
Precision::Confusion()); // C1 concatenation
|
|
|
|
if (concatc2d->Length() > 1)
|
|
{
|
|
Geom2dConvert_CompCurveToBSplineCurve Concat2d(concatc2d->Value(concatc2d->Lower()));
|
|
|
|
for (Standard_Integer i = concatc2d->Lower() + 1; i <= concatc2d->Upper(); i++)
|
|
Concat2d.Add(concatc2d->Value(i), aMaxTol, Standard_True);
|
|
|
|
concatc2d->SetValue(concatc2d->Lower(), Concat2d.BSplineCurve());
|
|
}
|
|
Handle(Geom2d_BSplineCurve) aBSplineCurve = concatc2d->Value(concatc2d->Lower());
|
|
aResPCurve = aBSplineCurve;
|
|
aResFirst = aBSplineCurve->FirstParameter();
|
|
aResLast = aBSplineCurve->LastParameter();
|
|
}
|
|
ResPCurves.Append(aResPCurve);
|
|
ResFirsts.Append(aResFirst);
|
|
ResLasts.Append(aResLast);
|
|
}
|
|
|
|
BRep_Builder aBuilder;
|
|
|
|
// Check the results for consistency
|
|
Standard_Boolean IsBadRange = Standard_False;
|
|
Standard_Real aRange3d = aLast3d - aFirst3d;
|
|
for (Standard_Integer ii = 1; ii <= ResPCurves.Length(); ii++)
|
|
{
|
|
Standard_Real aRange = ResLasts(ii) - ResFirsts(ii);
|
|
if (std::abs(aRange3d - aRange) > aMaxTol)
|
|
IsBadRange = Standard_True;
|
|
}
|
|
|
|
if (IsBadRange)
|
|
{
|
|
for (Standard_Integer ii = 1; ii <= ResPCurves.Length(); ii++)
|
|
{
|
|
const TopoDS_Face& aFace = TopoDS::Face(aFaceSeq(ii));
|
|
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
|
|
Handle(ShapeAnalysis_Surface) aSAS = new ShapeAnalysis_Surface(aSurf);
|
|
ShapeConstruct_ProjectCurveOnSurface aToolProj;
|
|
aToolProj.Init(aSAS, Precision::Confusion());
|
|
Handle(Geom2d_Curve) aNewPCurve;
|
|
if (aToolProj.Perform(aCurve, aFirst3d, aLast3d, aNewPCurve))
|
|
ResPCurves(ii) = aNewPCurve;
|
|
else
|
|
{
|
|
// Reparametrize pcurve
|
|
Handle(Geom2d_TrimmedCurve) aTrPCurve =
|
|
new Geom2d_TrimmedCurve(ResPCurves(ii), ResFirsts(ii), ResLasts(ii));
|
|
Handle(Geom2d_BSplineCurve) aBSplinePCurve = Geom2dConvert::CurveToBSplineCurve(aTrPCurve);
|
|
TColStd_Array1OfReal aKnots(1, aBSplinePCurve->NbKnots());
|
|
aBSplinePCurve->Knots(aKnots);
|
|
BSplCLib::Reparametrize(aFirst3d, aLast3d, aKnots);
|
|
aBSplinePCurve->SetKnots(aKnots);
|
|
ResPCurves(ii) = aBSplinePCurve;
|
|
}
|
|
ResFirsts(ii) = aFirst3d;
|
|
ResLasts(ii) = aLast3d;
|
|
}
|
|
}
|
|
|
|
// Reparametrize pcurves if needed
|
|
if (!ResPCurves.IsEmpty())
|
|
{
|
|
for (Standard_Integer ii = 1; ii <= ResPCurves.Length(); ii++)
|
|
{
|
|
if (std::abs(aFirst3d - ResFirsts(ii)) > aMaxTol
|
|
|| std::abs(aLast3d - ResLasts(ii)) > aMaxTol)
|
|
{
|
|
Geom2dAdaptor_Curve aGAcurve(ResPCurves(ii));
|
|
GeomAbs_CurveType aType = aGAcurve.GetType();
|
|
if (aType == GeomAbs_Line)
|
|
{
|
|
gp_Lin2d aLin2d = aGAcurve.Line();
|
|
gp_Dir2d aDir2d = aLin2d.Direction();
|
|
gp_Pnt2d aPnt2d = aGAcurve.Value(ResFirsts(ii));
|
|
gp_Vec2d anOffset = -aDir2d;
|
|
anOffset *= aFirst3d;
|
|
aPnt2d.Translate(anOffset);
|
|
Handle(Geom2d_Line) aNewLine2d = new Geom2d_Line(aPnt2d, aDir2d);
|
|
ResPCurves(ii) = aNewLine2d;
|
|
}
|
|
else if (aType == GeomAbs_Circle)
|
|
{
|
|
gp_Circ2d aCirc2d = aGAcurve.Circle();
|
|
Standard_Real aRadius = aCirc2d.Radius();
|
|
gp_Ax22d aPosition = aCirc2d.Position();
|
|
gp_Pnt2d aLocation = aCirc2d.Location();
|
|
Standard_Real anOffset = ResFirsts(ii) - aFirst3d;
|
|
aPosition.Rotate(aLocation, anOffset);
|
|
Handle(Geom2d_Circle) aNewCircle2d = new Geom2d_Circle(aPosition, aRadius);
|
|
ResPCurves(ii) = aNewCircle2d;
|
|
}
|
|
else // general case
|
|
{
|
|
Handle(Geom2d_TrimmedCurve) aTrPCurve =
|
|
new Geom2d_TrimmedCurve(ResPCurves(ii), ResFirsts(ii), ResLasts(ii));
|
|
Handle(Geom2d_BSplineCurve) aBSplinePCurve =
|
|
Geom2dConvert::CurveToBSplineCurve(aTrPCurve);
|
|
TColStd_Array1OfReal aKnots(1, aBSplinePCurve->NbKnots());
|
|
aBSplinePCurve->Knots(aKnots);
|
|
BSplCLib::Reparametrize(aFirst3d, aLast3d, aKnots);
|
|
aBSplinePCurve->SetKnots(aKnots);
|
|
ResPCurves(ii) = aBSplinePCurve;
|
|
}
|
|
ResFirsts(ii) = aFirst3d;
|
|
ResLasts(ii) = aLast3d;
|
|
} // if ranges > aMaxTol
|
|
} // for (Standard_Integer ii = 1; ii <= ResPCurves.Length(); ii++)
|
|
}
|
|
|
|
if (anIsSeam)
|
|
{
|
|
aBuilder.UpdateEdge(theEdge, ResPCurves(1), ResPCurves(2), TopoDS::Face(aFaceSeq(1)), aTolEdge);
|
|
}
|
|
else
|
|
for (Standard_Integer j = 1; j <= ResPCurves.Length(); j++)
|
|
{
|
|
aBuilder.UpdateEdge(theEdge, ResPCurves(j), TopoDS::Face(aFaceSeq(j)), aTolEdge);
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : MergeSubSeq
|
|
// purpose : Merges a sequence of edges into one edge if possible
|
|
//=======================================================================
|
|
|
|
Standard_Boolean ShapeUpgrade_UnifySameDomain::MergeSubSeq(
|
|
const TopTools_SequenceOfShape& theChain,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap,
|
|
TopoDS_Edge& OutEdge)
|
|
{
|
|
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 < theChain.Length(); j++)
|
|
{
|
|
TopoDS_Edge edge1 = TopoDS::Edge(theChain.Value(j));
|
|
TopoDS_Edge edge2 = TopoDS::Edge(theChain.Value(j + 1));
|
|
|
|
if (BRep_Tool::Degenerated(edge1) && BRep_Tool::Degenerated(edge2))
|
|
{
|
|
// Find the closest points in 2d
|
|
TopoDS_Edge edgeFirst = TopoDS::Edge(theChain.First());
|
|
TopoDS_Edge edgeLast = TopoDS::Edge(theChain.Last());
|
|
TopoDS_Face CommonFace;
|
|
Standard_Real MinSqDist;
|
|
TopAbs_Orientation OrOfE1OnFace, OrOfE2OnFace;
|
|
Standard_Integer IndOnE1, IndOnE2;
|
|
gp_Pnt2d PointsOnEdge1[2], PointsOnEdge2[2];
|
|
if (!FindClosestPoints(edgeFirst,
|
|
edgeLast,
|
|
theVFmap,
|
|
CommonFace,
|
|
MinSqDist,
|
|
OrOfE1OnFace,
|
|
OrOfE2OnFace,
|
|
IndOnE1,
|
|
IndOnE2,
|
|
PointsOnEdge1,
|
|
PointsOnEdge2))
|
|
return Standard_False;
|
|
|
|
// Define indices corresponding to extremities of future edge
|
|
IndOnE1 = 1 - IndOnE1;
|
|
IndOnE2 = 1 - IndOnE2;
|
|
|
|
// Construct new degenerated edge
|
|
gp_Pnt2d StartPoint = PointsOnEdge1[IndOnE1];
|
|
gp_Pnt2d EndPoint = PointsOnEdge2[IndOnE2];
|
|
if ((OrOfE1OnFace == TopAbs_FORWARD && IndOnE1 == 1)
|
|
|| (OrOfE1OnFace == TopAbs_REVERSED && IndOnE1 == 0))
|
|
{
|
|
gp_Pnt2d Tmp = StartPoint;
|
|
StartPoint = EndPoint;
|
|
EndPoint = Tmp;
|
|
}
|
|
|
|
Handle(Geom2d_Line) aLine = GCE2d_MakeLine(StartPoint, EndPoint);
|
|
|
|
TopoDS_Vertex aVertex = TopExp::FirstVertex(edgeFirst);
|
|
TopoDS_Vertex StartVertex = aVertex, EndVertex = aVertex;
|
|
StartVertex.Orientation(TopAbs_FORWARD);
|
|
EndVertex.Orientation(TopAbs_REVERSED);
|
|
|
|
TopoDS_Edge NewEdge;
|
|
B.MakeEdge(NewEdge);
|
|
B.UpdateEdge(NewEdge, aLine, CommonFace, Precision::Confusion());
|
|
B.Range(NewEdge, 0., StartPoint.Distance(EndPoint));
|
|
B.Add(NewEdge, StartVertex);
|
|
B.Add(NewEdge, EndVertex);
|
|
B.Degenerated(NewEdge, Standard_True);
|
|
OutEdge = NewEdge;
|
|
return Standard_True;
|
|
}
|
|
|
|
c3d1 = BRep_Tool::Curve(edge1, fp1, lp1);
|
|
c3d2 = BRep_Tool::Curve(edge2, fp2, lp2);
|
|
|
|
BRepAdaptor_Curve aBAcurve1(edge1);
|
|
BRepAdaptor_Curve aBAcurve2(edge2);
|
|
gp_Dir aDir1, aDir2;
|
|
|
|
if (c3d1.IsNull() || c3d2.IsNull())
|
|
return Standard_False;
|
|
|
|
if (c3d1->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(c3d1);
|
|
c3d1 = tc->BasisCurve();
|
|
}
|
|
if (c3d2->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
|
|
{
|
|
Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(c3d2);
|
|
c3d2 = tc->BasisCurve();
|
|
}
|
|
if (IsLinear(aBAcurve1, aDir1) && IsLinear(aBAcurve2, aDir2))
|
|
{
|
|
Handle(Geom_Line) L1 = Handle(Geom_Line)::DownCast(c3d1);
|
|
Handle(Geom_Line) L2 = Handle(Geom_Line)::DownCast(c3d2);
|
|
if (!aDir1.IsParallel(aDir2, myAngTol))
|
|
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(theChain.First()));
|
|
gp_Pnt PV1 = BRep_Tool::Pnt(V[0]);
|
|
V[1] = sae.LastVertex(TopoDS::Edge(theChain.Last()));
|
|
gp_Pnt PV2 = BRep_Tool::Pnt(V[1]);
|
|
gp_Vec Vec(PV1, PV2);
|
|
if (mySafeInputMode)
|
|
{
|
|
for (int k = 0; k < 2; k++)
|
|
{
|
|
if (!myContext->IsRecorded(V[k]))
|
|
{
|
|
TopoDS_Vertex Vcopy = TopoDS::Vertex(V[k].EmptyCopied());
|
|
myContext->Replace(V[k], Vcopy);
|
|
V[k] = Vcopy;
|
|
}
|
|
else
|
|
V[k] = TopoDS::Vertex(myContext->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.);
|
|
UnionPCurves(theChain, E);
|
|
OutEdge = E;
|
|
return Standard_True;
|
|
}
|
|
|
|
if (IsUnionOfCirclesPossible)
|
|
{
|
|
double f, l;
|
|
TopoDS_Edge FE = TopoDS::Edge(theChain.First());
|
|
Handle(Geom_Curve) c3d = BRep_Tool::Curve(FE, f, l);
|
|
|
|
if (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(theChain.Last()));
|
|
Standard_Boolean isClosed = V[0].IsSame(V[1]);
|
|
if (!isClosed)
|
|
{
|
|
// additionally check the points for equality to make a final decision about closedness of the
|
|
// result curve
|
|
gp_Pnt aP0 = BRep_Tool::Pnt(V[0]);
|
|
gp_Pnt aP1 = BRep_Tool::Pnt(V[1]);
|
|
Standard_Real aTol = std::max(BRep_Tool::Tolerance(V[0]), BRep_Tool::Tolerance(V[1]));
|
|
if (aP0.SquareDistance(aP1) < aTol * aTol)
|
|
{
|
|
isClosed = Standard_True;
|
|
V[1] = V[0];
|
|
V[1].Reverse();
|
|
}
|
|
}
|
|
TopoDS_Edge E;
|
|
if (isClosed)
|
|
{
|
|
// 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 (std::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 // open chain
|
|
{
|
|
Standard_Real ParamFirst = BRep_Tool::Parameter(V[0], FE);
|
|
TopoDS_Vertex VertexLastOnFE = sae.LastVertex(FE);
|
|
Standard_Real ParamLast = BRep_Tool::Parameter(VertexLastOnFE, FE);
|
|
|
|
if (mySafeInputMode)
|
|
{
|
|
for (int k = 0; k < 2; k++)
|
|
{
|
|
if (!myContext->IsRecorded(V[k]))
|
|
{
|
|
TopoDS_Vertex Vcopy = TopoDS::Vertex(V[k].EmptyCopied());
|
|
myContext->Replace(V[k], Vcopy);
|
|
V[k] = Vcopy;
|
|
}
|
|
else
|
|
V[k] = TopoDS::Vertex(myContext->Apply(V[k]));
|
|
}
|
|
}
|
|
|
|
gp_Pnt PointFirst = BRep_Tool::Pnt(V[0]);
|
|
while (std::abs(ParamLast - ParamFirst) > 7 * M_PI / 8)
|
|
ParamLast = (ParamFirst + ParamLast) / 2;
|
|
BRepAdaptor_Curve BAcurveFE(FE);
|
|
gp_Pnt PointLast = BAcurveFE.Value(ParamLast);
|
|
gp_Pnt Origin = Cir->Circ().Location();
|
|
gp_Dir Dir1 = gp_Vec(Origin, PointFirst);
|
|
gp_Dir Dir2 = gp_Vec(Origin, PointLast);
|
|
gp_Dir Vdir = Dir1 ^ Dir2;
|
|
gp_Ax2 anAx2(Origin, Vdir, Dir1);
|
|
Handle(Geom_Circle) aNewCircle = new Geom_Circle(anAx2, Cir->Radius());
|
|
gp_Pnt PointLastInChain = BRep_Tool::Pnt(V[1]);
|
|
gp_Dir DirLastInChain = gp_Vec(Origin, PointLastInChain);
|
|
Standard_Real lpar = Dir1.AngleWithRef(DirLastInChain, Vdir);
|
|
if (lpar < 0.)
|
|
lpar += 2 * M_PI;
|
|
|
|
Handle(Geom_TrimmedCurve) tc = new Geom_TrimmedCurve(aNewCircle, 0., lpar);
|
|
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], lpar, E, 0.);
|
|
}
|
|
UnionPCurves(theChain, E);
|
|
OutEdge = E;
|
|
return Standard_True;
|
|
}
|
|
if (theChain.Length() > 1 && myConcatBSplines)
|
|
{
|
|
// 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(theChain.First()));
|
|
TopoDS_Vertex VL = sae.LastVertex(TopoDS::Edge(theChain.Last()));
|
|
Standard_Boolean NeedUnion = Standard_True;
|
|
for (j = 1; j <= theChain.Length(); j++)
|
|
{
|
|
TopoDS_Edge edge = TopoDS::Edge(theChain.Value(j));
|
|
TopLoc_Location Loc;
|
|
Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, Loc, fp1, lp1);
|
|
if (c3d.IsNull())
|
|
continue;
|
|
if (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
|
|
std::cout << "can not make analytical union => make approximation" << std::endl;
|
|
#endif
|
|
TopoDS_Edge E = GlueEdgesWithPCurves(theChain, VF, VL);
|
|
OutEdge = E;
|
|
return Standard_True;
|
|
}
|
|
else
|
|
{
|
|
#ifdef OCCT_DEBUG
|
|
std::cout << "can not make approximation for such types of curves" << std::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,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap)
|
|
{
|
|
Standard_Boolean IsDegE1 = BRep_Tool::Degenerated(edge1);
|
|
Standard_Boolean IsDegE2 = BRep_Tool::Degenerated(edge2);
|
|
|
|
if (IsDegE1 && IsDegE2)
|
|
{
|
|
// Find connstion point in 2d
|
|
TopoDS_Face CommonFace;
|
|
Standard_Real MinSqDist;
|
|
TopAbs_Orientation OrOfE1OnFace, OrOfE2OnFace;
|
|
Standard_Integer IndOnE1, IndOnE2;
|
|
gp_Pnt2d PointsOnEdge1[2], PointsOnEdge2[2];
|
|
if (!FindClosestPoints(edge1,
|
|
edge2,
|
|
theVFmap,
|
|
CommonFace,
|
|
MinSqDist,
|
|
OrOfE1OnFace,
|
|
OrOfE2OnFace,
|
|
IndOnE1,
|
|
IndOnE2,
|
|
PointsOnEdge1,
|
|
PointsOnEdge2))
|
|
return Standard_False;
|
|
|
|
if (MinSqDist <= Precision::SquareConfusion())
|
|
return Standard_True;
|
|
|
|
return Standard_False;
|
|
}
|
|
else if (IsDegE1 || IsDegE2)
|
|
return Standard_False;
|
|
|
|
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;
|
|
}
|
|
|
|
gp_Dir aDir1, aDir2;
|
|
if (!(IsLinear(ade1, aDir1) && IsLinear(ade2, aDir2))
|
|
&& ((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)
|
|
{
|
|
// Check that the accumulated deflection does not exceed the linear tolerance
|
|
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;
|
|
|
|
// Check that the accumulated angle does not exceed the angular tolerance.
|
|
// For symmetry, check the angle between vectors of:
|
|
// - first edge and resulting curve, and
|
|
// - the last edge and resulting curve.
|
|
if (theDirectionVec.Angle(aCurV) > theAngTol || Diff2.Angle(aCurV) > theAngTol)
|
|
return Standard_False;
|
|
}
|
|
|
|
return Standard_True;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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;
|
|
}
|
|
|
|
struct ShapeUpgrade_UnifySameDomain::SubSequenceOfEdges
|
|
{
|
|
TopTools_SequenceOfShape SeqsEdges;
|
|
TopoDS_Edge UnionEdges;
|
|
};
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::generateSubSeq(
|
|
const TopTools_SequenceOfShape& anInpEdgeSeq,
|
|
NCollection_Sequence<SubSequenceOfEdges>& SeqOfSubSeqOfEdges,
|
|
Standard_Boolean IsClosed,
|
|
double theAngTol,
|
|
double theLinTol,
|
|
const TopTools_MapOfShape& AvoidEdgeVrt,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap)
|
|
{
|
|
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,
|
|
theVFmap);
|
|
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,
|
|
theVFmap))
|
|
{
|
|
SeqOfSubSeqOfEdges.ChangeLast().SeqsEdges.Append(SeqOfSubSeqOfEdges.ChangeFirst().SeqsEdges);
|
|
SeqOfSubSeqOfEdges.Remove(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
Standard_Boolean ShapeUpgrade_UnifySameDomain::MergeEdges(
|
|
TopTools_SequenceOfShape& SeqEdges,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap,
|
|
NCollection_Sequence<SubSequenceOfEdges>& SeqOfSubSeqOfEdges,
|
|
const TopTools_MapOfShape& NonMergVrt)
|
|
{
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapVE;
|
|
Standard_Integer j;
|
|
TopTools_MapOfShape VerticesToAvoid;
|
|
const Standard_Integer aNbE = SeqEdges.Length();
|
|
for (j = 1; j <= aNbE; j++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(SeqEdges(j));
|
|
// fill in the map V-E
|
|
for (TopoDS_Iterator it(anEdge.Oriented(TopAbs_FORWARD)); it.More(); it.Next())
|
|
{
|
|
const 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);
|
|
}
|
|
}
|
|
}
|
|
NCollection_MapAlgo::Unite(VerticesToAvoid, NonMergVrt);
|
|
|
|
// do loop while there are unused edges
|
|
TopTools_MapOfShape aUsedEdges;
|
|
|
|
for (Standard_Integer iE = 1; iE <= aNbE; ++iE)
|
|
{
|
|
TopoDS_Edge edge = TopoDS::Edge(SeqEdges(iE));
|
|
if (!aUsedEdges.Add(edge))
|
|
continue;
|
|
|
|
// make chain for unite
|
|
TopTools_SequenceOfShape aChain;
|
|
aChain.Append(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, myAngTol, myLinTol, VerticesToAvoid, theVFmap);
|
|
|
|
// 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, theVFmap, UE))
|
|
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
|
|
//=======================================================================
|
|
Standard_Boolean ShapeUpgrade_UnifySameDomain::MergeSeq(
|
|
TopTools_SequenceOfShape& SeqEdges,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theVFmap,
|
|
const TopTools_MapOfShape& nonMergVert)
|
|
{
|
|
NCollection_Sequence<SubSequenceOfEdges> SeqOfSubsSeqOfEdges;
|
|
if (MergeEdges(SeqEdges, theVFmap, SeqOfSubsSeqOfEdges, nonMergVert))
|
|
{
|
|
for (Standard_Integer i = 1; i <= SeqOfSubsSeqOfEdges.Length(); i++)
|
|
{
|
|
if (SeqOfSubsSeqOfEdges(i).UnionEdges.IsNull())
|
|
continue;
|
|
|
|
myContext->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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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();
|
|
myFacePlaneMap.Clear();
|
|
myEFmap.Clear();
|
|
myFaceNewFace.Clear();
|
|
myHistory->Clear();
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::AllowInternalEdges(const Standard_Boolean theValue)
|
|
{
|
|
myAllowInternal = theValue;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::SetSafeInputMode(Standard_Boolean theValue)
|
|
{
|
|
mySafeInputMode = theValue;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::KeepShape(const TopoDS_Shape& theShape)
|
|
{
|
|
if (theShape.ShapeType() == TopAbs_EDGE || theShape.ShapeType() == TopAbs_VERTEX)
|
|
myKeepShapes.Add(theShape);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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());
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::UnifyFaces()
|
|
{
|
|
// creating map of edge faces for the whole shape
|
|
TopTools_IndexedDataMapOfShapeListOfShape aGMapEdgeFaces;
|
|
|
|
TopTools_IndexedMapOfShape aFaceMap;
|
|
TopExp::MapShapes(myShape, TopAbs_FACE, aFaceMap);
|
|
for (Standard_Integer i = 1; i <= aFaceMap.Extent(); i++)
|
|
TopExp::MapShapesAndAncestors(aFaceMap(i), TopAbs_EDGE, TopAbs_FACE, aGMapEdgeFaces);
|
|
|
|
// creating map of face shells for the whole shape to avoid
|
|
// unification of faces belonging to the different shells
|
|
DataMapOfShapeMapOfShape aGMapFaceShells;
|
|
for (TopExp_Explorer anExp(myShape, TopAbs_SHELL); anExp.More(); anExp.Next())
|
|
{
|
|
const TopoDS_Shape& aShell = anExp.Current();
|
|
for (TopoDS_Iterator anItF(aShell); anItF.More(); anItF.Next())
|
|
{
|
|
const TopoDS_Shape& aF = anItF.Value();
|
|
if (TopTools_MapOfShape* pShells = aGMapFaceShells.ChangeSeek(aF))
|
|
{
|
|
pShells->Add(aShell);
|
|
}
|
|
else
|
|
{
|
|
(aGMapFaceShells.Bound(aF, TopTools_MapOfShape()))->Add(aShell);
|
|
}
|
|
}
|
|
}
|
|
|
|
// creating map of free boundaries
|
|
TopTools_MapOfShape aFreeBoundMap;
|
|
// look at only shells not belonging to solids
|
|
TopExp_Explorer anExplo(myShape, TopAbs_SHELL, TopAbs_SOLID);
|
|
for (; anExplo.More(); anExplo.Next())
|
|
{
|
|
const TopoDS_Shape& aShell = anExplo.Current();
|
|
TopTools_IndexedDataMapOfShapeListOfShape aEFmap;
|
|
TopExp::MapShapesAndAncestors(aShell, TopAbs_EDGE, TopAbs_FACE, aEFmap);
|
|
for (Standard_Integer ii = 1; ii <= aEFmap.Extent(); ii++)
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(aEFmap.FindKey(ii));
|
|
const TopTools_ListOfShape& aFaceList = aEFmap(ii);
|
|
if (!BRep_Tool::Degenerated(anEdge) && aFaceList.Extent() == 1)
|
|
aFreeBoundMap.Add(anEdge);
|
|
}
|
|
}
|
|
|
|
// unify faces in each shell separately
|
|
TopExp_Explorer exps;
|
|
for (exps.Init(myShape, TopAbs_SHELL); exps.More(); exps.Next())
|
|
IntUnifyFaces(exps.Current(), aGMapEdgeFaces, aGMapFaceShells, aFreeBoundMap);
|
|
|
|
// 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)
|
|
{
|
|
// No connection to shells, thus no need to pass the face-shell map
|
|
IntUnifyFaces(aCmp, aGMapEdgeFaces, DataMapOfShapeMapOfShape(), aFreeBoundMap);
|
|
}
|
|
|
|
myShape = myContext->Apply(myShape);
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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 : isSameSets
|
|
// purpose : Compares two sets of shapes. Returns true if they are the same,
|
|
// false otherwise.
|
|
//=======================================================================
|
|
|
|
template <class Container>
|
|
static Standard_Boolean isSameSets(const Container* theFShells1, const Container* theFShells2)
|
|
{
|
|
// If both are null - no problem
|
|
if (theFShells1 == nullptr && theFShells2 == nullptr)
|
|
{
|
|
return Standard_True;
|
|
}
|
|
// If only one is null - not the same
|
|
if (theFShells1 == nullptr || theFShells2 == nullptr)
|
|
{
|
|
return Standard_False;
|
|
}
|
|
// Both not null
|
|
if (theFShells1->Extent() != theFShells2->Extent())
|
|
{
|
|
return Standard_False;
|
|
}
|
|
// number of shells in each set should be very small in normal cases - max 2.
|
|
// thus just check if all objects of one are contained in the other and vice versa.
|
|
for (typename Container::Iterator it1(*theFShells1), it2(*theFShells2); it1.More() && it2.More();
|
|
it1.Next(), it2.Next())
|
|
{
|
|
if (!theFShells1->Contains(it2.Value()) || !theFShells2->Contains(it1.Value()))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void ShapeUpgrade_UnifySameDomain::IntUnifyFaces(
|
|
const TopoDS_Shape& theInpShape,
|
|
const TopTools_IndexedDataMapOfShapeListOfShape& theGMapEdgeFaces,
|
|
const DataMapOfShapeMapOfShape& theGMapFaceShells,
|
|
const TopTools_MapOfShape& theFreeBoundMap)
|
|
{
|
|
// 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 aFace = TopoDS::Face(exp.Current());
|
|
if (aProcessed.Contains(aFace))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const Handle(Geom_Surface) aBaseSurface = ClearRts(BRep_Tool::Surface(aFace));
|
|
// Bug 33894: Prevent crash when face has no surface
|
|
if (aBaseSurface.IsNull())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Boundary edges for the new face
|
|
TopTools_SequenceOfShape edges;
|
|
TopTools_SequenceOfShape RemovedEdges;
|
|
|
|
Standard_Integer dummy;
|
|
AddOrdinaryEdges(edges, aFace, dummy, RemovedEdges);
|
|
|
|
// 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;
|
|
TopAbs_Orientation RefFaceOrientation = aFace.Orientation();
|
|
|
|
// Take original surface
|
|
TopoDS_Face RefFace;
|
|
BRep_Builder BB;
|
|
BB.MakeFace(RefFace, aBaseSurface, aBaseLocation, 0.);
|
|
RefFace.Orientation(RefFaceOrientation);
|
|
TopTools_MapOfShape MapEdgesWithTemporaryPCurves; // map of edges not lying on RefFace
|
|
// these edges may be updated by temporary pcurves
|
|
|
|
Standard_Real Uperiod = (aBaseSurface->IsUPeriodic()) ? aBaseSurface->UPeriod() : 0.;
|
|
Standard_Real Vperiod = (aBaseSurface->IsVPeriodic()) ? aBaseSurface->VPeriod() : 0.;
|
|
|
|
// Get shells connected to the face (in normal cases should not be more than 2)
|
|
const TopTools_MapOfShape* pFShells1 = theGMapFaceShells.Seek(aFace);
|
|
|
|
// 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)
|
|
|| theFreeBoundMap.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(aFace, edge, aTMid, aDN1);
|
|
//
|
|
// Process the faces
|
|
TopTools_ListIteratorOfListOfShape anIter(aList);
|
|
for (; anIter.More(); anIter.Next())
|
|
{
|
|
|
|
TopoDS_Face aCheckedFace = TopoDS::Face(anIter.Value());
|
|
if (aCheckedFace.IsSame(aFace))
|
|
continue;
|
|
|
|
if (aProcessed.Contains(aCheckedFace))
|
|
continue;
|
|
|
|
// Get shells connected to the checked face
|
|
const TopTools_MapOfShape* pFShells2 = theGMapFaceShells.Seek(aCheckedFace);
|
|
// Faces can be unified only if the shells of faces connected to
|
|
// these faces are the same. Otherwise, topology would be broken.
|
|
if (!isSameSets(pFShells1, pFShells2))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (bCheckNormals)
|
|
{
|
|
// get normal of checked face using the same parameter on edge
|
|
gp_Dir aDN2;
|
|
if (GetNormalToSurface(aCheckedFace, 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, aCheckedFace, myLinTol, myAngTol, myFacePlaneMap))
|
|
{
|
|
|
|
if (AddOrdinaryEdges(edges, aCheckedFace, dummy, RemovedEdges))
|
|
{
|
|
// sequence edges is modified
|
|
i = dummy;
|
|
}
|
|
|
|
faces.Append(aCheckedFace);
|
|
aProcessed.Add(aCheckedFace);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (faces.Length() > 1)
|
|
{
|
|
if (myFacePlaneMap.IsBound(faces(1)))
|
|
{
|
|
const Handle(Geom_Plane)& aPlane = myFacePlaneMap(faces(1));
|
|
TopLoc_Location aLoc;
|
|
BB.UpdateFace(RefFace, aPlane, aLoc, Precision::Confusion());
|
|
}
|
|
// Add correct pcurves for the reference surface to the edges of other faces
|
|
TopoDS_Face F_RefFace = RefFace;
|
|
F_RefFace.Orientation(TopAbs_FORWARD);
|
|
AddPCurves(faces, F_RefFace, MapEdgesWithTemporaryPCurves);
|
|
|
|
// 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) || theFreeBoundMap.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())
|
|
{
|
|
const 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, RemovedEdges);
|
|
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, RemovedEdges);
|
|
faces.Remove(i);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // if (!myAllowInternal)
|
|
else
|
|
{ // internal edges are allowed
|
|
// 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));
|
|
}
|
|
}
|
|
} // if (!aKeepEdges.IsEmpty())
|
|
} // if (faces.Length() > 1)
|
|
|
|
TopTools_IndexedDataMapOfShapeListOfShape aMapEF;
|
|
for (i = 1; i <= faces.Length(); i++)
|
|
TopExp::MapShapesAndUniqueAncestors(faces(i), TopAbs_EDGE, TopAbs_FACE, aMapEF);
|
|
|
|
// Correct orientation of edges
|
|
for (Standard_Integer ii = 1; ii <= edges.Length(); ii++)
|
|
{
|
|
const TopoDS_Shape& anEdge = edges(ii);
|
|
Standard_Integer indE = aMapEF.FindIndex(anEdge);
|
|
const TopTools_ListOfShape& aLF = aMapEF(indE);
|
|
if (myAllowInternal && myKeepShapes.Contains(anEdge) && aLF.Extent() == 2)
|
|
edges(ii).Orientation(TopAbs_INTERNAL);
|
|
|
|
if (anEdge.Orientation() != TopAbs_INTERNAL)
|
|
edges(ii) = aMapEF.FindKey(indE);
|
|
}
|
|
|
|
// Exclude internal edges
|
|
TopTools_IndexedMapOfShape InternalEdges;
|
|
Standard_Integer ind_e = 1;
|
|
while (ind_e <= edges.Length())
|
|
{
|
|
const TopoDS_Shape& anEdge = edges(ind_e);
|
|
if (anEdge.Orientation() == TopAbs_INTERNAL)
|
|
{
|
|
InternalEdges.Add(anEdge);
|
|
edges.Remove(ind_e);
|
|
}
|
|
else
|
|
ind_e++;
|
|
}
|
|
|
|
if (RefFaceOrientation == TopAbs_REVERSED)
|
|
for (Standard_Integer ii = 1; ii <= edges.Length(); ii++)
|
|
edges(ii).Reverse();
|
|
TopoDS_Face F_RefFace = RefFace;
|
|
F_RefFace.Orientation(TopAbs_FORWARD);
|
|
|
|
// all faces collected in the sequence. Perform union of faces
|
|
if (faces.Length() > 1)
|
|
{
|
|
Standard_Real CoordTol = Precision::Confusion();
|
|
TopTools_MapOfShape edgesMap;
|
|
CoordTol = ComputeMinEdgeSize(edges, F_RefFace, edgesMap);
|
|
CoordTol /= 10.;
|
|
CoordTol = std::max(CoordTol, Precision::Confusion());
|
|
|
|
TopTools_IndexedDataMapOfShapeListOfShape VEmap;
|
|
for (Standard_Integer ind = 1; ind <= edges.Length(); ind++)
|
|
TopExp::MapShapesAndUniqueAncestors(edges(ind), TopAbs_VERTEX, TopAbs_EDGE, VEmap);
|
|
|
|
// Try to find seam edge and an edge that is not seam but has 2 pcurves on the surface
|
|
Standard_Boolean SeamFound = Standard_False, UseamFound = Standard_False,
|
|
VseamFound = Standard_False;
|
|
TopoDS_Edge EdgeWith2pcurves;
|
|
for (Standard_Integer ii = 1; ii <= faces.Length(); ii++)
|
|
{
|
|
const TopoDS_Face& face_ii = TopoDS::Face(faces(ii));
|
|
TopoDS_Wire anOuterWire = BRepTools::OuterWire(face_ii);
|
|
TopoDS_Iterator itw(anOuterWire);
|
|
for (; itw.More(); itw.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value());
|
|
if (BRep_Tool::IsClosed(anEdge, face_ii))
|
|
{
|
|
if (BRepTools::IsReallyClosed(anEdge, face_ii))
|
|
{
|
|
if (IsUiso(anEdge, face_ii))
|
|
UseamFound = Standard_True;
|
|
else
|
|
VseamFound = Standard_True;
|
|
}
|
|
else
|
|
EdgeWith2pcurves = anEdge;
|
|
}
|
|
}
|
|
}
|
|
SeamFound = UseamFound || VseamFound;
|
|
|
|
Standard_Boolean aIsEdgeWith2pcurvesSmooth = Standard_False;
|
|
if (myConcatBSplines && !EdgeWith2pcurves.IsNull() && !SeamFound)
|
|
{
|
|
const TopTools_ListOfShape& aFaceList = theGMapEdgeFaces.FindFromKey(EdgeWith2pcurves);
|
|
const TopoDS_Face& aFace1 = TopoDS::Face(aFaceList.First());
|
|
const TopoDS_Face& aFace2 = TopoDS::Face(aFaceList.Last());
|
|
GeomAbs_Shape anOrderOfCont =
|
|
BRepLib::ContinuityOfFaces(EdgeWith2pcurves, aFace1, aFace2, myAngTol);
|
|
aIsEdgeWith2pcurvesSmooth = (anOrderOfCont >= GeomAbs_G1);
|
|
}
|
|
|
|
if (aIsEdgeWith2pcurvesSmooth)
|
|
{
|
|
Handle(Geom2d_Curve) aPC1, aPC2;
|
|
Standard_Real aFirst, aLast;
|
|
aPC1 = BRep_Tool::CurveOnSurface(EdgeWith2pcurves, F_RefFace, aFirst, aLast);
|
|
EdgeWith2pcurves.Reverse();
|
|
aPC2 = BRep_Tool::CurveOnSurface(EdgeWith2pcurves, F_RefFace, aFirst, aLast);
|
|
gp_Pnt2d aPnt1 = aPC1->Value(aFirst);
|
|
gp_Pnt2d aPnt2 = aPC2->Value(aFirst);
|
|
Standard_Boolean anIsUclosed =
|
|
(std::abs(aPnt1.X() - aPnt2.X()) > std::abs(aPnt1.Y() - aPnt2.Y()));
|
|
Standard_Boolean aToMakeUPeriodic = Standard_False, aToMakeVPeriodic = Standard_False;
|
|
if (anIsUclosed && Uperiod == 0.)
|
|
aToMakeUPeriodic = Standard_True;
|
|
if (!anIsUclosed && Vperiod == 0.)
|
|
aToMakeVPeriodic = Standard_True;
|
|
|
|
if (aToMakeUPeriodic || aToMakeVPeriodic)
|
|
{
|
|
Handle(Geom_BSplineSurface) aBSplineSurface =
|
|
Handle(Geom_BSplineSurface)::DownCast(aBaseSurface);
|
|
if (aBSplineSurface.IsNull())
|
|
{
|
|
Standard_Real aTol = 1.e-4;
|
|
GeomAbs_Shape aUCont = GeomAbs_C1, aVCont = GeomAbs_C1;
|
|
Standard_Integer degU = 14, degV = 14;
|
|
Standard_Integer nmax = 16;
|
|
Standard_Integer aPrec = 1;
|
|
GeomConvert_ApproxSurface
|
|
Approximator(aBaseSurface, aTol, aUCont, aVCont, degU, degV, nmax, aPrec);
|
|
aBSplineSurface = Approximator.Surface();
|
|
}
|
|
|
|
if (aToMakeUPeriodic)
|
|
{
|
|
aBSplineSurface->SetUPeriodic();
|
|
Uperiod = aBSplineSurface->UPeriod();
|
|
}
|
|
if (aToMakeVPeriodic)
|
|
{
|
|
aBSplineSurface->SetVPeriodic();
|
|
Vperiod = aBSplineSurface->VPeriod();
|
|
}
|
|
|
|
// Update ref face and pcurves if the surface changed
|
|
if (aBSplineSurface != aBaseSurface)
|
|
{
|
|
TopoDS_Face OldRefFace = RefFace;
|
|
Handle(Geom2d_Curve) NullPCurve;
|
|
RefFace.Nullify();
|
|
BB.MakeFace(RefFace, aBSplineSurface, aBaseLocation, 0.);
|
|
for (Standard_Integer ii = 1; ii <= edges.Length(); ii++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(edges(ii));
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, OldRefFace, aFirst, aLast);
|
|
if (MapEdgesWithTemporaryPCurves.Contains(anEdge))
|
|
BB.UpdateEdge(anEdge, NullPCurve, OldRefFace, 0.);
|
|
BB.UpdateEdge(anEdge, aPCurve, RefFace, 0.);
|
|
}
|
|
F_RefFace = RefFace;
|
|
F_RefFace.Orientation(TopAbs_FORWARD);
|
|
}
|
|
}
|
|
} // if (myConcatBSplines && !EdgeWith2pcurves.IsNull() && !SeamFound)
|
|
|
|
// Perform relocating to new U-origin
|
|
// Define boundaries in 2d space of RefFace
|
|
Standard_Real aPeriods[2] = {Uperiod, Vperiod};
|
|
Standard_Boolean anIsSeamFound[2] = {UseamFound, VseamFound};
|
|
Standard_Real aSurfMin[2], aSurfMax[2];
|
|
aBaseSurface->Bounds(aSurfMin[0], aSurfMax[0], aSurfMin[1], aSurfMax[1]);
|
|
|
|
for (Standard_Integer ii = 0; ii < 2; ii++)
|
|
if (aPeriods[ii] != 0.)
|
|
{
|
|
// if seam edge exists, do nothing
|
|
if (!anIsSeamFound[ii])
|
|
{
|
|
// try to find the origin of U in 2d space
|
|
// so that all the faces are in [origin, origin + Uperiod]
|
|
Standard_Real aMinCoord, aMaxCoord; // Umin, Umax;
|
|
Standard_Integer aNumberOfIntervals, i_face_max;
|
|
if (!FindCoordBounds(faces,
|
|
F_RefFace,
|
|
aMapEF,
|
|
edgesMap,
|
|
ii + 1,
|
|
aPeriods[ii],
|
|
aMinCoord,
|
|
aMaxCoord,
|
|
aNumberOfIntervals,
|
|
i_face_max))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (aMaxCoord - aMinCoord > aPeriods[ii] - 1.e-5)
|
|
anIsSeamFound[ii] = Standard_True;
|
|
else if (aNumberOfIntervals == 2)
|
|
{
|
|
TopTools_MapOfShape UsedEdges;
|
|
NCollection_DataMap<TopoDS_Shape, Handle(Geom2d_Curve)> EdgeNewPCurve;
|
|
|
|
// Relocate pcurves to new U-origin
|
|
RelocatePCurvesToNewUorigin(edges,
|
|
faces(i_face_max),
|
|
F_RefFace,
|
|
CoordTol,
|
|
ii + 1,
|
|
aPeriods[ii],
|
|
VEmap,
|
|
EdgeNewPCurve,
|
|
UsedEdges);
|
|
|
|
// PCurves from unused edges (may be degenerated edges)
|
|
for (Standard_Integer ind = 1; ind <= edges.Length(); ind++)
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(edges(ind));
|
|
if (!UsedEdges.Contains(anEdge))
|
|
{
|
|
Standard_Real fpar, lpar;
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, F_RefFace, fpar, lpar);
|
|
aPCurve = new Geom2d_TrimmedCurve(aPCurve, fpar, lpar);
|
|
EdgeNewPCurve.Bind(anEdge, aPCurve);
|
|
}
|
|
}
|
|
|
|
// Restore VEmap
|
|
VEmap.Clear();
|
|
for (Standard_Integer ind = 1; ind <= edges.Length(); ind++)
|
|
TopExp::MapShapesAndUniqueAncestors(edges(ind), TopAbs_VERTEX, TopAbs_EDGE, VEmap);
|
|
|
|
// Find NewUmin and NewUmax
|
|
Standard_Real NewCoordMin = RealLast(), NewCoordMax = RealFirst();
|
|
for (Standard_Integer jj = 1; jj <= edges.Length(); jj++)
|
|
{
|
|
const Handle(Geom2d_Curve)& aPCurve = EdgeNewPCurve(edges(jj));
|
|
UpdateBoundaries(aPCurve,
|
|
aPCurve->FirstParameter(),
|
|
aPCurve->LastParameter(),
|
|
ii + 1,
|
|
NewCoordMin,
|
|
NewCoordMax);
|
|
}
|
|
|
|
if (NewCoordMax - NewCoordMin < aPeriods[ii] - CoordTol
|
|
&& !(-Precision::Confusion() < NewCoordMin
|
|
&& NewCoordMin < aPeriods[ii] + Precision::Confusion()
|
|
&& -Precision::Confusion() < NewCoordMax
|
|
&& NewCoordMax < aPeriods[ii] + Precision::Confusion()))
|
|
{
|
|
// we can build a face without seam edge:
|
|
// update the edges with earlier computed relocated pcurves
|
|
// fitting into (NewUorigin, NewUorigin + Uperiod)
|
|
Standard_Real RestSpaceInCoord = aPeriods[ii] - (NewCoordMax - NewCoordMin);
|
|
Standard_Real NewCoordOrigin = NewCoordMin - RestSpaceInCoord / 2;
|
|
if (NewCoordOrigin < aSurfMin[ii])
|
|
NewCoordOrigin = aSurfMin[ii];
|
|
Handle(Geom_Surface) NewSurf;
|
|
Standard_Boolean anIsInU = (ii == 0);
|
|
if (NewCoordOrigin == aSurfMin[ii])
|
|
NewSurf = aBaseSurface;
|
|
else
|
|
NewSurf = new Geom_RectangularTrimmedSurface(aBaseSurface,
|
|
NewCoordOrigin,
|
|
NewCoordOrigin + aPeriods[ii],
|
|
anIsInU); // trim in U or V
|
|
TopoDS_Face OldRefFace = RefFace;
|
|
Handle(Geom2d_Curve) NullPCurve;
|
|
RefFace.Nullify();
|
|
BB.MakeFace(RefFace, NewSurf, aBaseLocation, 0.);
|
|
for (Standard_Integer jj = 1; jj <= edges.Length(); jj++)
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(edges(jj));
|
|
if (MapEdgesWithTemporaryPCurves.Contains(anEdge))
|
|
BB.UpdateEdge(anEdge, NullPCurve, OldRefFace, 0.);
|
|
const Handle(Geom2d_Curve)& aPCurve = EdgeNewPCurve(anEdge);
|
|
BB.UpdateEdge(anEdge, aPCurve, RefFace, 0.);
|
|
}
|
|
}
|
|
} // else (Umax - Umin < Uperiod - 1.e-5, no Useam)
|
|
} // if (!UseamFound)
|
|
} // if (Uperiod != 0.)
|
|
UseamFound = anIsSeamFound[0];
|
|
VseamFound = anIsSeamFound[1];
|
|
////////////////////////////////////
|
|
F_RefFace = RefFace;
|
|
F_RefFace.Orientation(TopAbs_FORWARD);
|
|
|
|
TopTools_SequenceOfShape NewFaces, NewWires;
|
|
|
|
if (Uperiod == 0 || Vperiod == 0)
|
|
{
|
|
// Set the "periods" for closed non-periodic surface
|
|
TopLoc_Location aLoc;
|
|
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(RefFace, aLoc);
|
|
if (aSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
|
|
aSurf = (Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurf))->BasisSurface();
|
|
Standard_Real Ufirst, Ulast, Vfirst, Vlast;
|
|
aSurf->Bounds(Ufirst, Ulast, Vfirst, Vlast);
|
|
if (Uperiod == 0 && aSurf->IsUClosed())
|
|
Uperiod = Ulast - Ufirst;
|
|
if (Vperiod == 0 && aSurf->IsVClosed())
|
|
Vperiod = Vlast - Vfirst;
|
|
}
|
|
|
|
TopTools_MapOfShape UsedEdges;
|
|
|
|
Standard_Real FaceUmin = RealLast();
|
|
Standard_Real FaceVmin = RealLast();
|
|
for (Standard_Integer ii = 1; ii <= edges.Length(); ii++)
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(edges(ii));
|
|
BRepAdaptor_Curve2d aBAcurve(anEdge, F_RefFace);
|
|
gp_Pnt2d aFirstPoint = aBAcurve.Value(aBAcurve.FirstParameter());
|
|
gp_Pnt2d aLastPoint = aBAcurve.Value(aBAcurve.LastParameter());
|
|
|
|
if (aFirstPoint.X() < FaceUmin)
|
|
FaceUmin = aFirstPoint.X();
|
|
if (aLastPoint.X() < FaceUmin)
|
|
FaceUmin = aLastPoint.X();
|
|
|
|
if (aFirstPoint.Y() < FaceVmin)
|
|
FaceVmin = aFirstPoint.Y();
|
|
if (aLastPoint.Y() < FaceVmin)
|
|
FaceVmin = aLastPoint.Y();
|
|
}
|
|
|
|
// Building new wires from <edges>
|
|
// and build faces
|
|
while (!edges.IsEmpty())
|
|
{
|
|
// try to find non-degenerated edge
|
|
TopoDS_Edge StartEdge = TopoDS::Edge(edges(1));
|
|
Standard_Integer istart = 1;
|
|
while (BRep_Tool::Degenerated(StartEdge) && istart < edges.Length())
|
|
{
|
|
istart++;
|
|
StartEdge = TopoDS::Edge(edges(istart));
|
|
}
|
|
|
|
TopoDS_Wire aNewWire;
|
|
BB.MakeWire(aNewWire);
|
|
BB.Add(aNewWire, StartEdge);
|
|
RemoveEdgeFromMap(StartEdge, VEmap);
|
|
TopTools_IndexedMapOfShape SplittingVertices;
|
|
|
|
Standard_Real fpar, lpar;
|
|
Handle(Geom2d_Curve) StartPCurve =
|
|
BRep_Tool::CurveOnSurface(StartEdge, F_RefFace, fpar, lpar);
|
|
TopoDS_Vertex StartVertex, CurVertex;
|
|
TopExp::Vertices(StartEdge, StartVertex, CurVertex, Standard_True); // with orientation
|
|
Standard_Real StartParam, CurParam;
|
|
if (StartEdge.Orientation() == TopAbs_FORWARD)
|
|
{
|
|
StartParam = fpar;
|
|
CurParam = lpar;
|
|
}
|
|
else
|
|
{
|
|
StartParam = lpar;
|
|
CurParam = fpar;
|
|
}
|
|
gp_Pnt2d StartPoint = StartPCurve->Value(StartParam);
|
|
gp_Pnt2d CurPoint = StartPCurve->Value(CurParam);
|
|
|
|
TopoDS_Edge CurEdge = StartEdge;
|
|
for (;;) // loop till the end of current new wire
|
|
{
|
|
TopoDS_Edge NextEdge;
|
|
gp_Pnt2d NextPoint;
|
|
|
|
TopTools_ListOfShape Elist;
|
|
// const TopTools_ListOfShape& Elist = VEmap.FindFromKey(CurVertex);
|
|
if (VEmap.Contains(CurVertex))
|
|
Elist = VEmap.FindFromKey(CurVertex);
|
|
TopTools_ListIteratorOfListOfShape itl(Elist);
|
|
if (Elist.IsEmpty())
|
|
{
|
|
if (CurVertex.IsSame(StartVertex))
|
|
{
|
|
// Points of two vertices coincide in 3d but may be not in 2d
|
|
if ((Uperiod != 0. && std::abs(StartPoint.X() - CurPoint.X()) > Uperiod / 2)
|
|
|| (Vperiod != 0.
|
|
&& std::abs(StartPoint.Y() - CurPoint.Y())
|
|
> Vperiod / 2)) // end of parametric space
|
|
{
|
|
//<edges> do not contain seams => we must reconstruct the seam up to <NextEdge>
|
|
ReconstructMissedSeam(RemovedEdges,
|
|
F_RefFace,
|
|
CurEdge,
|
|
CurVertex,
|
|
CurPoint,
|
|
Uperiod,
|
|
Vperiod,
|
|
NextEdge,
|
|
NextPoint);
|
|
}
|
|
else
|
|
{
|
|
break; // end of wire
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NextEdge.IsNull())
|
|
{
|
|
Standard_Boolean EndOfWire = Standard_False;
|
|
|
|
Standard_Boolean anIsOnSingularity = IsOnSingularity(Elist);
|
|
if (!anIsOnSingularity && Elist.Extent() > 1)
|
|
SplittingVertices.Add(CurVertex);
|
|
|
|
TopTools_ListOfShape TmpElist, TrueElist;
|
|
//<TrueElist> will be the list of candidates to become <NextEdge>
|
|
for (itl.Initialize(Elist); itl.More(); itl.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
|
|
if (UsedEdges.Contains(anEdge))
|
|
continue;
|
|
TopoDS_Vertex aFirstVertex = TopExp::FirstVertex(anEdge, Standard_True);
|
|
if (!aFirstVertex.IsSame(CurVertex))
|
|
continue;
|
|
TmpElist.Append(anEdge);
|
|
}
|
|
if (TmpElist.Extent() <= 1 || (Uperiod != 0. || Vperiod != 0))
|
|
TrueElist.Assign(TmpElist);
|
|
else
|
|
{
|
|
// we must choose the closest direction - the biggest angle
|
|
Standard_Real MaxAngle = RealFirst();
|
|
TopoDS_Edge TrueEdge;
|
|
Handle(Geom2d_Curve) CurPCurve =
|
|
BRep_Tool::CurveOnSurface(CurEdge, F_RefFace, fpar, lpar);
|
|
CurParam = (CurEdge.Orientation() == TopAbs_FORWARD) ? lpar : fpar;
|
|
gp_Vec2d CurDir;
|
|
CurPCurve->D1(CurParam, CurPoint, CurDir);
|
|
CurDir.Normalize();
|
|
if (CurEdge.Orientation() == TopAbs_REVERSED)
|
|
CurDir.Reverse();
|
|
for (itl.Initialize(TmpElist); itl.More(); itl.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, F_RefFace, fpar, lpar);
|
|
Standard_Real aParam = (anEdge.Orientation() == TopAbs_FORWARD) ? fpar : lpar;
|
|
gp_Pnt2d aPoint;
|
|
gp_Vec2d aDir;
|
|
aPCurve->D1(aParam, aPoint, aDir);
|
|
aDir.Normalize();
|
|
if (anEdge.Orientation() == TopAbs_REVERSED)
|
|
aDir.Reverse();
|
|
Standard_Real anAngle = CurDir.Angle(aDir);
|
|
if (anAngle > MaxAngle)
|
|
{
|
|
MaxAngle = anAngle;
|
|
TrueEdge = anEdge;
|
|
}
|
|
}
|
|
TrueElist.Append(TrueEdge);
|
|
}
|
|
|
|
// Find next edge in TrueElist
|
|
for (itl.Initialize(TrueElist); itl.More(); itl.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
|
|
|
|
Handle(Geom2d_Curve) aPCurve =
|
|
BRep_Tool::CurveOnSurface(anEdge, F_RefFace, fpar, lpar);
|
|
Standard_Real aParam = (anEdge.Orientation() == TopAbs_FORWARD) ? fpar : lpar;
|
|
gp_Pnt2d aPoint = aPCurve->Value(aParam);
|
|
Standard_Real DiffU = std::abs(aPoint.X() - CurPoint.X());
|
|
Standard_Real DiffV = std::abs(aPoint.Y() - CurPoint.Y());
|
|
if (Uperiod != 0. && DiffU > CoordTol
|
|
&& std::abs(DiffU - Uperiod) > CoordTol) // may be it is a deg.vertex
|
|
continue;
|
|
if (Vperiod != 0. && DiffV > CoordTol
|
|
&& std::abs(DiffV - Vperiod) > CoordTol) // may be it is a deg.vertex
|
|
continue;
|
|
|
|
// Check: may be <CurPoint> and <aPoint> are on Period from each other
|
|
if ((Uperiod != 0. && DiffU > Uperiod / 2)
|
|
|| (Vperiod != 0. && DiffV > Vperiod / 2)) // end of parametric space
|
|
{
|
|
//<edges> do not contain seams => we must reconstruct the seam up to <NextEdge>
|
|
gp_Pnt2d StartOfNextEdge;
|
|
TopoDS_Vertex LastVertexOfSeam;
|
|
ReconstructMissedSeam(RemovedEdges,
|
|
F_RefFace,
|
|
CurEdge,
|
|
CurVertex,
|
|
CurPoint,
|
|
Uperiod,
|
|
Vperiod,
|
|
NextEdge,
|
|
NextPoint);
|
|
|
|
// Check: may be it is the end
|
|
if (LastVertexOfSeam.IsSame(StartVertex)
|
|
&& std::abs(StartPoint.X() - StartOfNextEdge.X()) < Uperiod / 2)
|
|
EndOfWire = Standard_True;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
NextEdge = anEdge;
|
|
Standard_Real LastParam = (NextEdge.Orientation() == TopAbs_FORWARD) ? lpar : fpar;
|
|
NextPoint = aPCurve->Value(LastParam);
|
|
break;
|
|
}
|
|
} // for (itl.Initialize(TrueElist); itl.More(); itl.Next())
|
|
|
|
if (EndOfWire)
|
|
break;
|
|
}
|
|
|
|
if (NextEdge.IsNull())
|
|
{
|
|
if (Uperiod != 0. || Vperiod != 0.)
|
|
{
|
|
if (CurVertex.IsSame(StartVertex)
|
|
&& (Uperiod == 0. || std::abs(StartPoint.X() - CurPoint.X()) < Uperiod / 2)
|
|
&& (Vperiod == 0. || std::abs(StartPoint.Y() - CurPoint.Y()) < Vperiod / 2))
|
|
break; // end of wire
|
|
|
|
ReconstructMissedSeam(RemovedEdges,
|
|
F_RefFace,
|
|
CurEdge,
|
|
CurVertex,
|
|
CurPoint,
|
|
Uperiod,
|
|
Vperiod,
|
|
NextEdge,
|
|
NextPoint);
|
|
if (NextEdge.IsNull())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
CurPoint = NextPoint;
|
|
CurEdge = NextEdge;
|
|
CurVertex = TopExp::LastVertex(CurEdge, Standard_True); // with orientation
|
|
BB.Add(aNewWire, CurEdge);
|
|
UsedEdges.Add(CurEdge);
|
|
RemoveEdgeFromMap(CurEdge, VEmap);
|
|
} // for (;;)
|
|
|
|
aNewWire.Closed(Standard_True);
|
|
UsedEdges.Add(StartEdge);
|
|
|
|
// Remove used edges from sequence
|
|
Standard_Integer ind = 1;
|
|
while (ind <= edges.Length())
|
|
{
|
|
if (UsedEdges.Contains(edges(ind)))
|
|
edges.Remove(ind);
|
|
else
|
|
ind++;
|
|
}
|
|
|
|
// add just built wire to current face or save it in the sequence of wires
|
|
Standard_Boolean EdgeOnBoundOfSurfFound = Standard_False;
|
|
TopoDS_Iterator itw(aNewWire);
|
|
for (; itw.More(); itw.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value());
|
|
if (BRep_Tool::IsClosed(anEdge, RefFace))
|
|
{
|
|
EdgeOnBoundOfSurfFound = Standard_True;
|
|
break;
|
|
}
|
|
}
|
|
if (EdgeOnBoundOfSurfFound) // this wire can not be a hole
|
|
{
|
|
TopLoc_Location aLoc;
|
|
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(RefFace, aLoc);
|
|
TopoDS_Face aResult;
|
|
BB.MakeFace(aResult, aSurf, aLoc, 0);
|
|
BB.Add(aResult, aNewWire);
|
|
aResult.Orientation(RefFaceOrientation);
|
|
NewFaces.Append(aResult);
|
|
}
|
|
else // may be this wire is a hole
|
|
{
|
|
// split this wire if needed
|
|
if (!SplittingVertices.IsEmpty())
|
|
SplitWire(aNewWire, F_RefFace, SplittingVertices, NewWires);
|
|
else
|
|
NewWires.Append(aNewWire);
|
|
}
|
|
} // while (!edges.IsEmpty())
|
|
|
|
// Build wires from internal edges
|
|
TopTools_IndexedDataMapOfShapeListOfShape IntVEmap;
|
|
for (Standard_Integer ii = 1; ii <= InternalEdges.Extent(); ii++)
|
|
TopExp::MapShapesAndAncestors(InternalEdges(ii), TopAbs_VERTEX, TopAbs_EDGE, IntVEmap);
|
|
TopTools_SequenceOfShape InternalWires;
|
|
while (!InternalEdges.IsEmpty())
|
|
{
|
|
TopoDS_Edge aFirstEdge = TopoDS::Edge(InternalEdges(1));
|
|
InternalEdges.RemoveFromIndex(1);
|
|
TopoDS_Wire anInternalWire;
|
|
BB.MakeWire(anInternalWire);
|
|
BB.Add(anInternalWire, aFirstEdge);
|
|
TopoDS_Edge EndEdges[2];
|
|
EndEdges[0] = EndEdges[1] = aFirstEdge;
|
|
TopoDS_Vertex VV[2];
|
|
TopExp::Vertices(aFirstEdge, VV[0], VV[1]);
|
|
for (;;)
|
|
{
|
|
if (VV[0].IsSame(VV[1])) // closed wire
|
|
break;
|
|
Standard_Boolean found = Standard_False;
|
|
for (Standard_Integer ii = 0; ii < 2; ii++)
|
|
{
|
|
const TopTools_ListOfShape& Elist = IntVEmap.FindFromKey(VV[ii]);
|
|
TopTools_ListIteratorOfListOfShape itl(Elist);
|
|
for (; itl.More(); itl.Next())
|
|
{
|
|
TopoDS_Edge anEdge = TopoDS::Edge(itl.Value());
|
|
if (anEdge.IsSame(EndEdges[ii]))
|
|
continue;
|
|
found = Standard_True;
|
|
InternalEdges.RemoveKey(anEdge);
|
|
BB.Add(anInternalWire, anEdge);
|
|
TopoDS_Vertex V1, V2;
|
|
TopExp::Vertices(anEdge, V1, V2);
|
|
VV[ii] = (V1.IsSame(VV[ii])) ? V2 : V1;
|
|
EndEdges[ii] = anEdge;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) // end of open wire
|
|
break;
|
|
}
|
|
InternalWires.Append(anInternalWire);
|
|
}
|
|
|
|
// Insert new faces instead of old ones
|
|
if (NewFaces.IsEmpty())
|
|
{
|
|
// one face without seam
|
|
TopLoc_Location aLoc;
|
|
Handle(Geom_Surface) aSurf = BRep_Tool::Surface(RefFace, aLoc);
|
|
TopoDS_Face aResult;
|
|
BB.MakeFace(aResult, aSurf, aLoc, 0.);
|
|
for (Standard_Integer ii = 1; ii <= NewWires.Length(); ii++)
|
|
BB.Add(aResult, NewWires(ii));
|
|
for (Standard_Integer ii = 1; ii <= InternalWires.Length(); ii++)
|
|
BB.Add(aResult, InternalWires(ii));
|
|
aResult.Orientation(RefFaceOrientation);
|
|
myContext->Merge(faces, aResult);
|
|
// Update the map Face-NewFace
|
|
for (Standard_Integer jj = 1; jj <= faces.Length(); jj++)
|
|
myFaceNewFace.Bind(faces(jj), aResult);
|
|
}
|
|
else if (NewFaces.Length() == 1)
|
|
{
|
|
TopoDS_Shape aNewFace = NewFaces(1).Oriented(TopAbs_FORWARD);
|
|
for (Standard_Integer ii = 1; ii <= NewWires.Length(); ii++)
|
|
BB.Add(aNewFace, NewWires(ii));
|
|
for (Standard_Integer ii = 1; ii <= InternalWires.Length(); ii++)
|
|
BB.Add(aNewFace, InternalWires(ii));
|
|
myContext->Merge(faces, NewFaces(1));
|
|
// Update the map Face-NewFace
|
|
for (Standard_Integer jj = 1; jj <= faces.Length(); jj++)
|
|
myFaceNewFace.Bind(faces(jj), NewFaces(1));
|
|
}
|
|
else
|
|
{
|
|
// Insert new wires and internal wires into correspondent faces
|
|
InsertWiresIntoFaces(NewWires, NewFaces, RefFace);
|
|
InsertWiresIntoFaces(InternalWires, NewFaces, RefFace);
|
|
|
|
NCollection_Sequence<TopTools_MapOfShape> Emaps;
|
|
for (Standard_Integer ii = 1; ii <= faces.Length(); ii++)
|
|
{
|
|
TopTools_MapOfShape aEmap;
|
|
TopExp::MapShapes(faces(ii), aEmap);
|
|
Emaps.Append(aEmap);
|
|
}
|
|
for (Standard_Integer ii = 1; ii <= NewFaces.Length(); ii++)
|
|
{
|
|
TopTools_SequenceOfShape facesForThisFace;
|
|
TopTools_MapOfShape UsedFaces;
|
|
TopExp_Explorer Explo(NewFaces(ii), TopAbs_EDGE);
|
|
for (; Explo.More(); Explo.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(Explo.Current());
|
|
if (BRep_Tool::Degenerated(anEdge) || BRep_Tool::IsClosed(anEdge, RefFace))
|
|
continue;
|
|
Standard_Integer jj;
|
|
for (jj = 1; jj <= Emaps.Length(); jj++)
|
|
if (Emaps(jj).Contains(anEdge))
|
|
break;
|
|
if (UsedFaces.Add(faces(jj)))
|
|
facesForThisFace.Append(faces(jj));
|
|
}
|
|
myContext->Merge(facesForThisFace, NewFaces(ii));
|
|
// Update the map Face-NewFace
|
|
for (Standard_Integer jj = 1; jj <= facesForThisFace.Length(); jj++)
|
|
myFaceNewFace.Bind(facesForThisFace(jj), NewFaces(ii));
|
|
}
|
|
}
|
|
} // if (faces.Length() > 1)
|
|
} // end processing each face
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
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);
|
|
// creating map of vertex faces
|
|
TopTools_IndexedDataMapOfShapeListOfShape aVFmap;
|
|
TopExp::MapShapesAndUniqueAncestors(aRes, TopAbs_VERTEX, TopAbs_FACE, aVFmap);
|
|
|
|
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, aVFmap, 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
|
|
constexpr 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(std::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()
|
|
{
|
|
TopExp::MapShapesAndAncestors(myInitShape, TopAbs_EDGE, TopAbs_FACE, myEFmap);
|
|
|
|
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);
|
|
}
|
|
|
|
void SplitWire(const TopoDS_Wire& theWire,
|
|
const TopoDS_Face& theFace,
|
|
const TopTools_IndexedMapOfShape& theVmap,
|
|
TopTools_SequenceOfShape& theWireSeq)
|
|
{
|
|
TopTools_DataMapOfShapeListOfShape aVEmap;
|
|
|
|
TopTools_MapOfShape aEmap;
|
|
TopoDS_Iterator itw(theWire);
|
|
for (; itw.More(); itw.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value());
|
|
if (!aEmap.Add(anEdge))
|
|
continue;
|
|
if (anEdge.Orientation() != TopAbs_FORWARD && anEdge.Orientation() != TopAbs_REVERSED)
|
|
continue;
|
|
|
|
const TopoDS_Vertex& aVertex = TopExp::FirstVertex(anEdge, Standard_True); // with orientation
|
|
if (aVEmap.IsBound(aVertex))
|
|
aVEmap(aVertex).Append(anEdge);
|
|
else
|
|
{
|
|
TopTools_ListOfShape aElist;
|
|
aElist.Append(anEdge);
|
|
aVEmap.Bind(aVertex, aElist);
|
|
}
|
|
}
|
|
|
|
BRep_Builder aBB;
|
|
for (Standard_Integer ii = 1; ii <= theVmap.Extent(); ii++)
|
|
{
|
|
const TopoDS_Vertex& anOrigin = TopoDS::Vertex(theVmap(ii));
|
|
TopTools_ListOfShape& aBranches = aVEmap(anOrigin);
|
|
TopTools_ListIteratorOfListOfShape anItl(aBranches);
|
|
while (anItl.More())
|
|
{
|
|
TopoDS_Edge CurEdge = TopoDS::Edge(anItl.Value());
|
|
aBranches.Remove(anItl);
|
|
|
|
TopoDS_Wire aNewWire;
|
|
aBB.MakeWire(aNewWire);
|
|
for (;;)
|
|
{
|
|
aBB.Add(aNewWire, CurEdge);
|
|
|
|
// clang-format off
|
|
const TopoDS_Vertex& aVertex = TopExp::LastVertex (CurEdge, Standard_True); //with orientation
|
|
// clang-format on
|
|
if (aVertex.IsSame(anOrigin))
|
|
break;
|
|
|
|
if (!aVEmap.IsBound(aVertex))
|
|
break;
|
|
|
|
TopTools_ListOfShape& aElist = aVEmap(aVertex);
|
|
if (aElist.Extent() == 0)
|
|
break;
|
|
|
|
if (aElist.Extent() == 1)
|
|
{
|
|
CurEdge = TopoDS::Edge(aElist.First());
|
|
aElist.Clear();
|
|
}
|
|
else
|
|
{
|
|
Standard_Real fpar, lpar;
|
|
Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(CurEdge, theFace, fpar, lpar);
|
|
Standard_Real aParam = (CurEdge.Orientation() == TopAbs_FORWARD) ? lpar : fpar;
|
|
gp_Pnt2d aPoint;
|
|
gp_Vec2d CurDir;
|
|
aPCurve->D1(aParam, aPoint, CurDir);
|
|
CurDir.Normalize();
|
|
if (CurEdge.Orientation() == TopAbs_REVERSED)
|
|
CurDir.Reverse();
|
|
// choose the rightest direction - the smallest angle
|
|
Standard_Real MinAngle = RealLast();
|
|
TopoDS_Edge NextEdge;
|
|
TopTools_ListIteratorOfListOfShape aLocalIter(aElist);
|
|
for (; aLocalIter.More(); aLocalIter.Next())
|
|
{
|
|
const TopoDS_Edge& anEdge = TopoDS::Edge(aLocalIter.Value());
|
|
aPCurve = BRep_Tool::CurveOnSurface(anEdge, theFace, fpar, lpar);
|
|
aParam = (anEdge.Orientation() == TopAbs_FORWARD) ? fpar : lpar;
|
|
gp_Vec2d aDir;
|
|
aPCurve->D1(aParam, aPoint, aDir);
|
|
aDir.Normalize();
|
|
if (anEdge.Orientation() == TopAbs_REVERSED)
|
|
aDir.Reverse();
|
|
Standard_Real anAngle = CurDir.Angle(aDir);
|
|
if (anAngle < MinAngle)
|
|
{
|
|
MinAngle = anAngle;
|
|
NextEdge = anEdge;
|
|
}
|
|
}
|
|
CurEdge = NextEdge;
|
|
// Remove <CurEdge> from list
|
|
for (aLocalIter.Initialize(aElist); aLocalIter.More(); aLocalIter.Next())
|
|
if (CurEdge.IsSame(aLocalIter.Value()))
|
|
{
|
|
aElist.Remove(aLocalIter);
|
|
break;
|
|
}
|
|
} // else (more than one edge)
|
|
} // for (;;)
|
|
theWireSeq.Append(aNewWire);
|
|
} // while (anItl.More())
|
|
}
|
|
}
|