mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-14 13:30:48 +03:00
Initial implementation of the new offset algorithm.
Initial implementation of the solid creation mode for the new offset creation algorithm.
This commit is contained in:
587
src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx
Normal file
587
src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx
Normal file
@@ -0,0 +1,587 @@
|
||||
// Created on: 2016-10-13
|
||||
// Created by: Alexander MALYSHEV
|
||||
// Copyright (c) 1995-1999 Matra Datavision
|
||||
// Copyright (c) 1999-2016 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 self.
|
||||
#include <BRepOffset_MakeSimpleOffset.hxx>
|
||||
|
||||
#include <Adaptor3d_CurveOnSurface.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepLib.hxx>
|
||||
#include <BRepLib_MakeEdge.hxx>
|
||||
#include <BRepLib_MakeFace.hxx>
|
||||
#include <BRepTools_Quilt.hxx>
|
||||
#include <BRepAdaptor_HCurve2d.hxx>
|
||||
#include <BRepAdaptor_HSurface.hxx>
|
||||
#include <BRepAdaptor_Surface.hxx>
|
||||
#include <BRepOffset_SimpleOffset.hxx>
|
||||
#include <BRepTools_Modifier.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
#include <Geom2d_Line.hxx>
|
||||
#include <GeomFill_Generator.hxx>
|
||||
#include <Extrema_LocateExtPC.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <ShapeAnalysis_FreeBounds.hxx>
|
||||
#include <ShapeFix_Edge.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//function : BRepOffset_MakeSimpleOffset
|
||||
//purpose : Constructor
|
||||
//=============================================================================
|
||||
BRepOffset_MakeSimpleOffset::BRepOffset_MakeSimpleOffset(const TopoDS_Shape& theInputShape,
|
||||
const Standard_Real theOffsetValue)
|
||||
: myInputShape(theInputShape),
|
||||
myOffsetValue(theOffsetValue),
|
||||
myIsBuildSolid(Standard_False),
|
||||
myMaxAngle(0.0),
|
||||
myError(BRepOffsetSimple_OK),
|
||||
myIsDone(Standard_False)
|
||||
{
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : GetErrorMessage
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
TCollection_AsciiString BRepOffset_MakeSimpleOffset::GetErrorMessage() const
|
||||
{
|
||||
TCollection_AsciiString anError = "";
|
||||
|
||||
if (myError == BRepOffsetSimple_NullInputShape)
|
||||
{
|
||||
anError = "Null input shape";
|
||||
return anError;
|
||||
}
|
||||
else if (myError == BRepOffsetSimple_ErrorOffsetComputation)
|
||||
{
|
||||
anError = "Error during offset construction";
|
||||
return anError;
|
||||
}
|
||||
else if (myError == BRepOffsetSimple_ErrorWallFaceComputation)
|
||||
{
|
||||
anError = "Error during building wall face";
|
||||
return anError;
|
||||
}
|
||||
else if (myError == BRepOffsetSimple_ErrorInvalidNbShells)
|
||||
{
|
||||
anError = "Result contains two or more shells";
|
||||
return anError;
|
||||
}
|
||||
else if (myError == BRepOffsetSimple_ErrorNonClosedShell)
|
||||
{
|
||||
anError = "Result shell is not closed";
|
||||
return anError;
|
||||
}
|
||||
|
||||
return anError;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : Clear
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
void BRepOffset_MakeSimpleOffset::Clear()
|
||||
{
|
||||
myIsDone = Standard_False;
|
||||
myError = BRepOffsetSimple_OK;
|
||||
myMaxAngle = 0.0;
|
||||
myMapVE.Clear();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : GetSafeOffset
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
Standard_Real BRepOffset_MakeSimpleOffset::GetSafeOffset(const Standard_Real theExpectedToler)
|
||||
{
|
||||
// Compute max angle in faces junctions.
|
||||
if (myMaxAngle == 0.0) // Non-initialized.
|
||||
ComputeMaxAngle();
|
||||
|
||||
const Standard_Real anExpOffset = theExpectedToler / (2.0 * myMaxAngle);
|
||||
return anExpOffset;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : Perform
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
void BRepOffset_MakeSimpleOffset::Perform()
|
||||
{
|
||||
// Clear result of previous computations.
|
||||
Clear();
|
||||
|
||||
// Check shape existence.
|
||||
if (myInputShape.IsNull())
|
||||
{
|
||||
myError = BRepOffsetSimple_NullInputShape;
|
||||
return;
|
||||
}
|
||||
|
||||
if (myMaxAngle == 0.0) // Non-initialized.
|
||||
ComputeMaxAngle();
|
||||
|
||||
Handle(BRepOffset_SimpleOffset) aBuilder = new BRepOffset_SimpleOffset(myInputShape, myOffsetValue);
|
||||
BRepTools_Modifier aModifier(myInputShape, aBuilder);
|
||||
|
||||
if (!aModifier.IsDone())
|
||||
{
|
||||
myError = BRepOffsetSimple_ErrorOffsetComputation;
|
||||
return;
|
||||
}
|
||||
|
||||
myResShape = aModifier.ModifiedShape(myInputShape);
|
||||
|
||||
// Fix degeneracy. Degenerated edge should be mapped to the degenerated.
|
||||
BRep_Builder aBB;
|
||||
TopExp_Explorer anExpSE(myInputShape, TopAbs_EDGE);
|
||||
for(; anExpSE.More(); anExpSE.Next())
|
||||
{
|
||||
const TopoDS_Edge & aCurrEdge = TopoDS::Edge(anExpSE.Current());
|
||||
|
||||
if (!BRep_Tool::Degenerated(aCurrEdge))
|
||||
continue;
|
||||
|
||||
const TopoDS_Edge & anEdge = TopoDS::Edge(aModifier.ModifiedShape(aCurrEdge));
|
||||
aBB.Degenerated(anEdge, Standard_True);
|
||||
}
|
||||
|
||||
// Restore walls for solid.
|
||||
if (myIsBuildSolid && !BuildMissingWalls(aModifier))
|
||||
return;
|
||||
|
||||
myIsDone = Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : tgtfaces
|
||||
//purpose : check the angle at the border between two squares.
|
||||
// Two shares should have a shared front edge.
|
||||
//=============================================================================
|
||||
static void tgtfaces(const TopoDS_Edge& Ed,
|
||||
const TopoDS_Face& F1,
|
||||
const TopoDS_Face& F2,
|
||||
const Standard_Boolean couture,
|
||||
Standard_Real& theResAngle)
|
||||
{
|
||||
// Check that pcurves exist on both faces of edge.
|
||||
Standard_Real aFirst,aLast;
|
||||
Handle(Geom2d_Curve) aCurve;
|
||||
aCurve = BRep_Tool::CurveOnSurface(Ed,F1,aFirst,aLast);
|
||||
if(aCurve.IsNull())
|
||||
return;
|
||||
aCurve = BRep_Tool::CurveOnSurface(Ed,F2,aFirst,aLast);
|
||||
if(aCurve.IsNull())
|
||||
return;
|
||||
|
||||
Standard_Real u;
|
||||
TopoDS_Edge E = Ed;
|
||||
BRepAdaptor_Surface aBAS1(F1,Standard_False);
|
||||
BRepAdaptor_Surface aBAS2(F2,Standard_False);
|
||||
|
||||
Handle(BRepAdaptor_HSurface) HS1 = new BRepAdaptor_HSurface (aBAS1);
|
||||
Handle(BRepAdaptor_HSurface) HS2;
|
||||
if(couture) HS2 = HS1;
|
||||
else HS2 = new BRepAdaptor_HSurface(aBAS2);
|
||||
//case when edge lies on the one face
|
||||
|
||||
E.Orientation(TopAbs_FORWARD);
|
||||
Handle(BRepAdaptor_HCurve2d) HC2d1 = new BRepAdaptor_HCurve2d();
|
||||
HC2d1->ChangeCurve2d().Initialize(E,F1);
|
||||
if(couture) E.Orientation(TopAbs_REVERSED);
|
||||
Handle(BRepAdaptor_HCurve2d) HC2d2 = new BRepAdaptor_HCurve2d();
|
||||
HC2d2->ChangeCurve2d().Initialize(E,F2);
|
||||
|
||||
Standard_Boolean rev1 = (F1.Orientation() == TopAbs_REVERSED);
|
||||
Standard_Boolean rev2 = (F2.Orientation() == TopAbs_REVERSED);
|
||||
Standard_Real f,l,eps;
|
||||
BRep_Tool::Range(E,f,l);
|
||||
Extrema_LocateExtPC ext;
|
||||
|
||||
eps = (l - f) / 100.0;
|
||||
f += eps; // to avoid calculations on
|
||||
l -= eps; // points of pointed squares.
|
||||
gp_Pnt2d p;
|
||||
gp_Pnt pp1,pp2;//,PP;
|
||||
gp_Vec du1, dv1;
|
||||
gp_Vec du2, dv2;
|
||||
gp_Vec d1,d2;
|
||||
Standard_Real norm;
|
||||
|
||||
const Standard_Integer NBPNT = 23;
|
||||
for(Standard_Integer i = 0; i <= NBPNT; i++)
|
||||
{
|
||||
// First suppose that this is sameParameter
|
||||
u = f + (l - f) * i / NBPNT;
|
||||
|
||||
// take derivatives of surfaces at the same u, and compute normals
|
||||
HC2d1->D0(u,p);
|
||||
HS1->D1 (p.X(), p.Y(), pp1, du1, dv1);
|
||||
d1 = (du1.Crossed(dv1));
|
||||
norm = d1.Magnitude();
|
||||
if (norm > 1.e-12) d1 /= norm;
|
||||
else continue; // skip degenerated point
|
||||
if(rev1) d1.Reverse();
|
||||
|
||||
HC2d2->D0(u,p);
|
||||
HS2->D1 (p.X(), p.Y(), pp2, du2, dv2);
|
||||
d2 = (du2.Crossed(dv2));
|
||||
norm = d2.Magnitude();
|
||||
if (norm > 1.e-12) d2 /= norm;
|
||||
else continue; // skip degenerated point
|
||||
if(rev2) d2.Reverse();
|
||||
|
||||
// Compute angle.
|
||||
Standard_Real aCurrentAng = d1.Angle(d2);
|
||||
|
||||
theResAngle = Max(theResAngle, aCurrentAng);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// function : ComputeMaxAngleOnShape
|
||||
// purpose : Code the regularities on all edges of the shape, boundary of
|
||||
// two faces that do not have it.
|
||||
//=============================================================================
|
||||
static void ComputeMaxAngleOnShape(const TopoDS_Shape& S,
|
||||
Standard_Real& theResAngle)
|
||||
{
|
||||
TopTools_IndexedDataMapOfShapeListOfShape M;
|
||||
TopExp::MapShapesAndAncestors(S,TopAbs_EDGE,TopAbs_FACE,M);
|
||||
TopTools_ListIteratorOfListOfShape It;
|
||||
TopExp_Explorer Ex;
|
||||
TopoDS_Face F1,F2;
|
||||
Standard_Boolean found, couture;
|
||||
for(Standard_Integer i = 1; i <= M.Extent(); i++)
|
||||
{
|
||||
TopoDS_Edge E = TopoDS::Edge(M.FindKey(i));
|
||||
found = Standard_False; couture = Standard_False;
|
||||
F1.Nullify();
|
||||
for(It.Initialize(M.FindFromIndex(i));It.More() && !found;It.Next())
|
||||
{
|
||||
if(F1.IsNull()) { F1 = TopoDS::Face(It.Value()); }
|
||||
else
|
||||
{
|
||||
if(!F1.IsSame(TopoDS::Face(It.Value())))
|
||||
{
|
||||
found = Standard_True;
|
||||
F2 = TopoDS::Face(It.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found && !F1.IsNull()){//is it a sewing edge?
|
||||
TopAbs_Orientation orE = E.Orientation();
|
||||
TopoDS_Edge curE;
|
||||
for(Ex.Init(F1,TopAbs_EDGE);Ex.More() && !found;Ex.Next()){
|
||||
curE= TopoDS::Edge(Ex.Current());
|
||||
if(E.IsSame(curE) && orE != curE.Orientation())
|
||||
{
|
||||
found = Standard_True;
|
||||
couture = Standard_True;
|
||||
F2 = F1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(found)
|
||||
{
|
||||
if(BRep_Tool::Continuity(E,F1,F2)<=GeomAbs_C0)
|
||||
{
|
||||
try
|
||||
{
|
||||
tgtfaces(E, F1, F2, couture, theResAngle);
|
||||
}
|
||||
catch(Standard_Failure)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : ComputeMaxAngle
|
||||
//purpose : Computes max angle in faces junction
|
||||
//=============================================================================
|
||||
void BRepOffset_MakeSimpleOffset::ComputeMaxAngle()
|
||||
{
|
||||
ComputeMaxAngleOnShape(myInputShape, myMaxAngle);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : BuildMissingWalls
|
||||
//purpose : Builds walls to the result solid.
|
||||
//=============================================================================
|
||||
Standard_Boolean BRepOffset_MakeSimpleOffset::BuildMissingWalls(const BRepTools_Modifier& theModifier)
|
||||
{
|
||||
// Internal list of new faces.
|
||||
NCollection_List<TopoDS_Face> aListOfNewFaces;
|
||||
BRep_Builder aBB;
|
||||
|
||||
// Compute outer bounds of original shape.
|
||||
ShapeAnalysis_FreeBounds aFB(myInputShape);
|
||||
const TopoDS_Compound& aFreeWires = aFB.GetClosedWires();
|
||||
|
||||
// Build linear faces on each edge and its image.
|
||||
TopExp_Explorer anExpCW(aFreeWires,TopAbs_WIRE);
|
||||
for(; anExpCW.More() ; anExpCW.Next())
|
||||
{
|
||||
const TopoDS_Wire& aCurWire = TopoDS::Wire(anExpCW.Current());
|
||||
|
||||
// Iterate over outer edges in outer wires.
|
||||
TopExp_Explorer anExpWE(aCurWire, TopAbs_EDGE);
|
||||
for(; anExpWE.More() ; anExpWE.Next())
|
||||
{
|
||||
const TopoDS_Edge& aCurEdge = TopoDS::Edge(anExpWE.Current());
|
||||
|
||||
TopoDS_Face aNewFace = BuildWallFace(theModifier, aCurEdge);
|
||||
|
||||
if (aNewFace.IsNull())
|
||||
{
|
||||
myError = BRepOffsetSimple_ErrorWallFaceComputation;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
aListOfNewFaces.Append(aNewFace);
|
||||
}
|
||||
}
|
||||
|
||||
// Update result to be compound.
|
||||
TopoDS_Compound aResCompound;
|
||||
aBB.MakeCompound(aResCompound);
|
||||
|
||||
// Add old faces.
|
||||
TopExp_Explorer anExpSF(myInputShape, TopAbs_FACE);
|
||||
for ( ; anExpSF.More() ; anExpSF.Next())
|
||||
aBB.Add(aResCompound, anExpSF.Current());
|
||||
|
||||
// Add new faces.
|
||||
anExpSF.Init(myResShape, TopAbs_FACE);
|
||||
for ( ; anExpSF.More() ; anExpSF.Next())
|
||||
aBB.Add(aResCompound, anExpSF.Current());
|
||||
|
||||
// Add wall faces.
|
||||
NCollection_List<TopoDS_Face>::Iterator anIterF(aListOfNewFaces);
|
||||
for ( ; anIterF.More() ; anIterF.Next())
|
||||
{
|
||||
const TopoDS_Face& aF = anIterF.Value();
|
||||
aBB.Add(aResCompound, aF);
|
||||
}
|
||||
|
||||
// Create result shell.
|
||||
BRepTools_Quilt aQuilt;
|
||||
aQuilt.Add(aResCompound);
|
||||
TopoDS_Shape aShells = aQuilt.Shells();
|
||||
|
||||
TopExp_Explorer anExpSSh(aShells, TopAbs_SHELL);
|
||||
TopoDS_Shell aResShell;
|
||||
for ( ; anExpSSh.More() ; anExpSSh.Next() )
|
||||
{
|
||||
if (!aResShell.IsNull())
|
||||
{
|
||||
// Shell is not null -> explorer contains two or more shells.
|
||||
myError = BRepOffsetSimple_ErrorInvalidNbShells;
|
||||
return Standard_False;
|
||||
}
|
||||
aResShell = TopoDS::Shell(anExpSSh.Current());
|
||||
}
|
||||
|
||||
if (!BRep_Tool::IsClosed(aResShell))
|
||||
{
|
||||
myError = BRepOffsetSimple_ErrorNonClosedShell;
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
// Create result solid.
|
||||
TopoDS_Solid aResSolid;
|
||||
aBB.MakeSolid(aResSolid);
|
||||
aBB.Add(aResSolid, aResShell);
|
||||
myResShape = aResSolid;
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : BuildWallFace
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
TopoDS_Face BRepOffset_MakeSimpleOffset::BuildWallFace(const BRepTools_Modifier& theModifier,
|
||||
const TopoDS_Edge& theOrigEdge)
|
||||
{
|
||||
TopoDS_Face aResFace;
|
||||
|
||||
// Get offset edge. offset edge is revered to create correct wire.
|
||||
TopoDS_Edge aNewEdge = TopoDS::Edge(theModifier.ModifiedShape(theOrigEdge));
|
||||
aNewEdge.Orientation(TopAbs_REVERSED);
|
||||
|
||||
TopoDS_Vertex aNewV1, aNewV2;
|
||||
TopExp::Vertices(aNewEdge, aNewV1, aNewV2);
|
||||
|
||||
// Wire contour is:
|
||||
// theOrigEdge (forcible forward) -> wall1 -> aNewEdge (forcible reversed) -> wall2
|
||||
// Firstly it is necessary to create copy of original shape with forward direction.
|
||||
// This simplifies walls creation.
|
||||
TopoDS_Edge anOrigCopy = theOrigEdge;
|
||||
anOrigCopy.Orientation(TopAbs_FORWARD);
|
||||
TopoDS_Vertex aV1, aV2;
|
||||
TopExp::Vertices(anOrigCopy, aV1, aV2);
|
||||
|
||||
// To simplify work with map.
|
||||
TopoDS_Vertex aForwardV1 = TopoDS::Vertex(aV1.Oriented(TopAbs_FORWARD));
|
||||
TopoDS_Vertex aForwardV2 = TopoDS::Vertex(aV2.Oriented(TopAbs_FORWARD));
|
||||
|
||||
// Check existence of edges in stored map: Edge1
|
||||
TopoDS_Edge aWall1;
|
||||
if (myMapVE.IsBound(aForwardV2))
|
||||
{
|
||||
// Edge exists - get it from map.
|
||||
aWall1 = myMapVE(aForwardV2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Edge does not exist - create it and add to the map.
|
||||
BRepLib_MakeEdge aME1(TopoDS::Vertex(aV2.Oriented(TopAbs_FORWARD)),
|
||||
TopoDS::Vertex(aNewV2.Oriented(TopAbs_REVERSED)));
|
||||
if (!aME1.IsDone())
|
||||
return aResFace;
|
||||
aWall1 = aME1.Edge();
|
||||
|
||||
myMapVE.Bind(aForwardV2, aWall1);
|
||||
}
|
||||
|
||||
// Check existence of edges in stored map: Edge2
|
||||
TopoDS_Edge aWall2;
|
||||
if (myMapVE.IsBound(aForwardV1))
|
||||
{
|
||||
// Edge exists - get it from map.
|
||||
aWall2 = TopoDS::Edge(myMapVE(aForwardV1).Oriented(TopAbs_REVERSED));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Edge does not exist - create it and add to the map.
|
||||
BRepLib_MakeEdge aME2(TopoDS::Vertex(aV1.Oriented(TopAbs_FORWARD)),
|
||||
TopoDS::Vertex(aNewV1.Oriented(TopAbs_REVERSED)));
|
||||
if (!aME2.IsDone())
|
||||
return aResFace;
|
||||
aWall2 = aME2.Edge();
|
||||
|
||||
myMapVE.Bind(aForwardV1, aWall2);
|
||||
|
||||
// Orient it in reversed direction.
|
||||
aWall2.Orientation(TopAbs_REVERSED);
|
||||
}
|
||||
|
||||
BRep_Builder aBB;
|
||||
|
||||
TopoDS_Wire aWire;
|
||||
aBB.MakeWire(aWire);
|
||||
aBB.Add(aWire, anOrigCopy);
|
||||
aBB.Add(aWire, aWall1);
|
||||
aBB.Add(aWire, aNewEdge);
|
||||
aBB.Add(aWire, aWall2);
|
||||
|
||||
// Build 3d curves on wire
|
||||
BRepLib::BuildCurves3d( aWire );
|
||||
|
||||
// Try to build using simple planar approach.
|
||||
TopoDS_Face aF;
|
||||
try
|
||||
{
|
||||
// Call of face maker is wrapped by try/catch since it generates exceptions sometimes.
|
||||
BRepLib_MakeFace aFM(aWire, Standard_True);
|
||||
if (aFM.IsDone())
|
||||
aF = aFM.Face();
|
||||
}
|
||||
catch(Standard_Failure)
|
||||
{
|
||||
}
|
||||
|
||||
if (aF.IsNull()) // Exception in face maker or result is not computed.
|
||||
{
|
||||
// Build using thrusections.
|
||||
Standard_Boolean ToReverse = Standard_False;
|
||||
Standard_Real fpar, lpar, fparOE, lparOE;
|
||||
Handle(Geom_Curve) EdgeCurve = BRep_Tool::Curve(theOrigEdge, fpar, lpar);
|
||||
Handle(Geom_TrimmedCurve) TrEdgeCurve = new Geom_TrimmedCurve( EdgeCurve, fpar, lpar );
|
||||
Handle(Geom_Curve) OffsetCurve = BRep_Tool::Curve(aNewEdge, fparOE, lparOE);
|
||||
Handle(Geom_TrimmedCurve) TrOffsetCurve = new Geom_TrimmedCurve( OffsetCurve, fparOE, lparOE );
|
||||
|
||||
GeomFill_Generator ThrusecGenerator;
|
||||
ThrusecGenerator.AddCurve( TrEdgeCurve );
|
||||
ThrusecGenerator.AddCurve( TrOffsetCurve );
|
||||
ThrusecGenerator.Perform( Precision::PConfusion() );
|
||||
Handle(Geom_Surface) theSurf = ThrusecGenerator.Surface();
|
||||
//theSurf = new Geom_SurfaceOfLinearExtrusion( TrOffsetCurve, OffsetDir );
|
||||
Standard_Real Uf, Ul, Vf, Vl;
|
||||
theSurf->Bounds(Uf, Ul, Vf, Vl);
|
||||
TopLoc_Location Loc;
|
||||
Handle(Geom2d_Line) EdgeLine2d, OELine2d, aLine2d, aLine2d2;
|
||||
EdgeLine2d = new Geom2d_Line(gp_Pnt2d(0., Vf), gp_Dir2d(1., 0.));
|
||||
aBB.UpdateEdge(theOrigEdge, EdgeLine2d, theSurf, Loc, Precision::Confusion());
|
||||
OELine2d = new Geom2d_Line(gp_Pnt2d(0., Vl), gp_Dir2d(1., 0.));
|
||||
aBB.UpdateEdge(aNewEdge, OELine2d, theSurf, Loc, Precision::Confusion());
|
||||
Standard_Real UonV1 = (ToReverse)? Ul : Uf;
|
||||
Standard_Real UonV2 = (ToReverse)? Uf : Ul;
|
||||
aLine2d = new Geom2d_Line(gp_Pnt2d(UonV2, 0.), gp_Dir2d(0., 1.));
|
||||
aLine2d2 = new Geom2d_Line(gp_Pnt2d(UonV1, 0.), gp_Dir2d(0., 1.));
|
||||
if (aWall1.IsSame(aWall2))
|
||||
{
|
||||
aBB.UpdateEdge(aWall1, aLine2d, aLine2d2, theSurf, Loc, Precision::Confusion());
|
||||
Handle(Geom_Curve) BSplC34 = theSurf->UIso( Uf );
|
||||
aBB.UpdateEdge(aWall1, BSplC34, Precision::Confusion());
|
||||
aBB.Range(aWall1, Vf, Vl);
|
||||
}
|
||||
else
|
||||
{
|
||||
aBB.SameParameter(aWall1, Standard_False);
|
||||
aBB.SameRange(aWall1, Standard_False);
|
||||
aBB.SameParameter(aWall2, Standard_False);
|
||||
aBB.SameRange(aWall2, Standard_False);
|
||||
aBB.UpdateEdge(aWall1, aLine2d, theSurf, Loc, Precision::Confusion());
|
||||
aBB.Range(aWall1, theSurf, Loc, Vf, Vl);
|
||||
aBB.UpdateEdge(aWall2, aLine2d2, theSurf, Loc, Precision::Confusion());
|
||||
aBB.Range(aWall2, theSurf, Loc, Vf, Vl);
|
||||
Handle(Geom_Curve) BSplC3 = theSurf->UIso( UonV2 );
|
||||
aBB.UpdateEdge(aWall1, BSplC3, Precision::Confusion());
|
||||
aBB.Range(aWall1, Vf, Vl, Standard_True); //only for 3d curve
|
||||
Handle(Geom_Curve) BSplC4 = theSurf->UIso( UonV1 );
|
||||
aBB.UpdateEdge(aWall2, BSplC4, Precision::Confusion());
|
||||
aBB.Range(aWall2, Vf, Vl, Standard_True); //only for 3d curve
|
||||
}
|
||||
|
||||
aF = BRepLib_MakeFace(theSurf, aWire);
|
||||
|
||||
}
|
||||
|
||||
// Fix same parameter and same range flags.
|
||||
ShapeFix_Edge aSFE;
|
||||
TopExp_Explorer anExpFE(aF, TopAbs_EDGE);
|
||||
for ( ; anExpFE.More() ; anExpFE.Next())
|
||||
{
|
||||
const TopoDS_Edge& aCurrEdge = TopoDS::Edge(anExpFE.Current());
|
||||
aSFE.FixSameParameter(aCurrEdge);
|
||||
//aSFE.FixSameParameter(aCurrEdge, aF);
|
||||
}
|
||||
|
||||
return aF;
|
||||
}
|
143
src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx
Normal file
143
src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx
Normal file
@@ -0,0 +1,143 @@
|
||||
// Created on: 2016-10-13
|
||||
// Created by: Alexander MALYSHEV
|
||||
// Copyright (c) 1999-2016 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.
|
||||
|
||||
#ifndef _BRepOffset_MakeSimpleOffset_HeaderFile
|
||||
#define _BRepOffset_MakeSimpleOffset_HeaderFile
|
||||
|
||||
#include <NCollection_DataMap.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <Standard_Real.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
class BRepTools_Modifier;
|
||||
|
||||
|
||||
enum BRepOffsetSimple_Status
|
||||
{
|
||||
BRepOffsetSimple_OK,
|
||||
BRepOffsetSimple_NullInputShape,
|
||||
BRepOffsetSimple_ErrorOffsetComputation,
|
||||
BRepOffsetSimple_ErrorWallFaceComputation,
|
||||
BRepOffsetSimple_ErrorInvalidNbShells,
|
||||
BRepOffsetSimple_ErrorNonClosedShell
|
||||
};
|
||||
|
||||
//! This class represents simple offset algorithm itself. It builds simple offset without intersection.
|
||||
//! Solid can be created using SetBuildSolidFlag method (set flag to true). By default shell will be constructed.
|
||||
//!
|
||||
//! Algorithm:
|
||||
//! 1. Build source-image maps for vertices, edges and faces.BRepTools_Modification class will be used
|
||||
//! to store this information. An image of a shared edge can be constructed from the corresponding edge
|
||||
//! of the first iterated face.
|
||||
//! 2. Run BRepTools_Modifier to obtain offset shape.
|
||||
// 3. Ensure topological integrity of the output shape.
|
||||
//!
|
||||
//! Limitations:
|
||||
//! According to the algorithm nature result depends on the smoothness of input data. Smooth (G1-continuity) input shape
|
||||
//! will lead to the good result.
|
||||
class BRepOffset_MakeSimpleOffset
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor.
|
||||
Standard_EXPORT BRepOffset_MakeSimpleOffset(const TopoDS_Shape& theInputShape,
|
||||
const Standard_Real theOffsetValue);
|
||||
|
||||
//! Computes offset shape.
|
||||
Standard_EXPORT void Perform();
|
||||
|
||||
//! Gets error message.
|
||||
Standard_EXPORT TCollection_AsciiString GetErrorMessage() const;
|
||||
|
||||
//! Gets error code.
|
||||
const BRepOffsetSimple_Status GetError() const { return myError; }
|
||||
|
||||
// Inline methods.
|
||||
//! Gets solid building flag.
|
||||
const Standard_Boolean GetBuildSolidFlag() const { return myIsBuildSolid; }
|
||||
|
||||
//! Sets solid building flag.
|
||||
void SetBuildSolidFlag(const Standard_Boolean theBuildFlag) { myIsBuildSolid = theBuildFlag; }
|
||||
|
||||
//! Gets offset value.
|
||||
const Standard_Real GetOffsetValue() const { return myOffsetValue; }
|
||||
|
||||
//! Sets offset value.
|
||||
void SetOffsetValue(const Standard_Real theOffsetValue) { myOffsetValue = theOffsetValue; }
|
||||
|
||||
//! Gets done state.
|
||||
const Standard_Boolean IsDone() const { return myIsDone; }
|
||||
|
||||
//! Returns result shape.
|
||||
const TopoDS_Shape& GetResultShape() const { return myResShape; }
|
||||
|
||||
//! Computes max safe offset value for the given tolerance.
|
||||
Standard_Real GetSafeOffset(const Standard_Real theExpectedToler);
|
||||
|
||||
protected:
|
||||
|
||||
//! Computes max angle in faces junction.
|
||||
void ComputeMaxAngle();
|
||||
|
||||
//! Clears previous result.
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
|
||||
//! Builds face on specified wall.
|
||||
TopoDS_Face BuildWallFace(const BRepTools_Modifier& theModifier,
|
||||
const TopoDS_Edge& theOrigEdge);
|
||||
|
||||
//! Builds missing walls.
|
||||
Standard_Boolean BuildMissingWalls(const BRepTools_Modifier& theModifier);
|
||||
|
||||
// Input data.
|
||||
|
||||
//! Input shape.
|
||||
TopoDS_Shape myInputShape;
|
||||
|
||||
//! Offset value.
|
||||
Standard_Real myOffsetValue;
|
||||
|
||||
//! Solid building flag. True means solid construction.
|
||||
Standard_Boolean myIsBuildSolid;
|
||||
|
||||
// Internal data.
|
||||
|
||||
//! Maximal angle in faces junction. This value helps to estimate result tolerance.
|
||||
Standard_Real myMaxAngle;
|
||||
|
||||
//! Error message.
|
||||
BRepOffsetSimple_Status myError;
|
||||
|
||||
//! Done state.
|
||||
Standard_Boolean myIsDone;
|
||||
|
||||
//! Map of vertex - wall edge.
|
||||
//! Used to build shared edge between adjacent wall faces.
|
||||
NCollection_DataMap<TopoDS_Vertex, TopoDS_Edge> myMapVE;
|
||||
|
||||
// Output data.
|
||||
|
||||
//! Result shape.
|
||||
TopoDS_Shape myResShape;
|
||||
|
||||
};
|
||||
|
||||
#endif // _BRepOffset_MakeSimpleOffset_HeaderFile
|
438
src/BRepOffset/BRepOffset_SimpleOffset.cxx
Normal file
438
src/BRepOffset/BRepOffset_SimpleOffset.cxx
Normal file
@@ -0,0 +1,438 @@
|
||||
// Created on: 2016-10-14
|
||||
// Created by: Alexander MALYSHEV
|
||||
// Copyright (c) 1995-1999 Matra Datavision
|
||||
// Copyright (c) 1999-2016 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 self.
|
||||
#include <BRepOffset_SimpleOffset.hxx>
|
||||
|
||||
#include <Adaptor3d_CurveOnSurface.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepLib.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <Geom_OffsetSurface.hxx>
|
||||
#include <GeomAdaptor_Curve.hxx>
|
||||
#include <Geom2dAdaptor_HCurve.hxx>
|
||||
#include <GeomAdaptor_HSurface.hxx>
|
||||
#include <NCollection_Vector.hxx>
|
||||
#include <ShapeAnalysis_Edge.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
|
||||
|
||||
static const Standard_Integer NCONTROL=22;
|
||||
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(BRepOffset_SimpleOffset, BRepTools_Modification)
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//function : BRepOffset_SimpleOffset
|
||||
//purpose : Constructor
|
||||
//=============================================================================
|
||||
BRepOffset_SimpleOffset::BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
|
||||
const Standard_Real theOffsetValue)
|
||||
: myOffsetValue(theOffsetValue)
|
||||
{
|
||||
FillOffsetData(theInputShape);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : NewSurface
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
Standard_Boolean BRepOffset_SimpleOffset::NewSurface(const TopoDS_Face& F,
|
||||
Handle(Geom_Surface)& S,
|
||||
TopLoc_Location& L,
|
||||
Standard_Real& Tol,
|
||||
Standard_Boolean& RevWires,
|
||||
Standard_Boolean& RevFace)
|
||||
{
|
||||
if (!myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_FORWARD))) &&
|
||||
!myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_REVERSED))))
|
||||
return Standard_False;
|
||||
|
||||
NewFaceData aNFD;
|
||||
if (myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_FORWARD))))
|
||||
aNFD = myFaceInfo.Find(TopoDS::Face(F.Oriented(TopAbs_FORWARD)));
|
||||
if (myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_REVERSED))))
|
||||
aNFD = myFaceInfo.Find(TopoDS::Face(F.Oriented(TopAbs_REVERSED)));
|
||||
|
||||
S = aNFD.myOffsetS;
|
||||
L = aNFD.myL;
|
||||
Tol = aNFD.myTol;
|
||||
RevWires = aNFD.myRevWires;
|
||||
RevFace = aNFD.myRevFace;
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : NewCurve
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
Standard_Boolean BRepOffset_SimpleOffset::NewCurve(const TopoDS_Edge& E,
|
||||
Handle(Geom_Curve)& C,
|
||||
TopLoc_Location& L,
|
||||
Standard_Real& Tol)
|
||||
{
|
||||
if (!myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_FORWARD))) &&
|
||||
!myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_REVERSED))))
|
||||
return Standard_False;
|
||||
|
||||
NewEdgeData aNED;
|
||||
if (myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_FORWARD))))
|
||||
aNED = myEdgeInfo.Find(TopoDS::Edge(E.Oriented(TopAbs_FORWARD)));
|
||||
if (myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_REVERSED))))
|
||||
aNED = myEdgeInfo.Find(TopoDS::Edge(E.Oriented(TopAbs_REVERSED)));
|
||||
|
||||
C = aNED.myOffsetC;
|
||||
L = aNED.myL;
|
||||
Tol = aNED.myTol;
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : NewPoint
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
Standard_Boolean BRepOffset_SimpleOffset::NewPoint (const TopoDS_Vertex& V,
|
||||
gp_Pnt& P,
|
||||
Standard_Real& Tol)
|
||||
{
|
||||
if (!myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_FORWARD))) &&
|
||||
!myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_REVERSED))))
|
||||
return Standard_False;
|
||||
|
||||
NewVertexData aNVD;
|
||||
if (myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_FORWARD))))
|
||||
aNVD = myVertexInfo.Find(TopoDS::Vertex(V.Oriented(TopAbs_FORWARD)));
|
||||
if (myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_REVERSED))))
|
||||
aNVD = myVertexInfo.Find(TopoDS::Vertex(V.Oriented(TopAbs_REVERSED)));
|
||||
|
||||
P = aNVD.myP;
|
||||
Tol = aNVD.myTol;
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : NewCurve2d
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
Standard_Boolean BRepOffset_SimpleOffset::NewCurve2d (const TopoDS_Edge& E,
|
||||
const TopoDS_Face& F,
|
||||
const TopoDS_Edge& /*NewE*/,
|
||||
const TopoDS_Face& /*NewF*/,
|
||||
Handle(Geom2d_Curve)& C,
|
||||
Standard_Real& Tol)
|
||||
{
|
||||
// Use original pcurve.
|
||||
Standard_Real aF, aL;
|
||||
C = BRep_Tool::CurveOnSurface(E, F, aF, aL);
|
||||
Tol = BRep_Tool::Tolerance(E);
|
||||
|
||||
if (myEdgeInfo.IsBound(E))
|
||||
Tol = myEdgeInfo.Find(E).myTol;
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : NewParameter
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
Standard_Boolean BRepOffset_SimpleOffset::NewParameter (const TopoDS_Vertex& V,
|
||||
const TopoDS_Edge& E,
|
||||
Standard_Real& P,
|
||||
Standard_Real& Tol)
|
||||
{
|
||||
// Use original parameter.
|
||||
P = BRep_Tool::Parameter(V, E);
|
||||
Tol = BRep_Tool::Tolerance(V);
|
||||
|
||||
if (myVertexInfo.IsBound(V))
|
||||
Tol = myVertexInfo.Find(V).myTol;
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : NewParameter
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
GeomAbs_Shape BRepOffset_SimpleOffset::Continuity (const TopoDS_Edge& E,
|
||||
const TopoDS_Face& F1,
|
||||
const TopoDS_Face& F2,
|
||||
const TopoDS_Edge& /*NewE*/,
|
||||
const TopoDS_Face& /*NewF1*/,
|
||||
const TopoDS_Face& /*NewF2*/)
|
||||
{
|
||||
// Compute result using original continuity.
|
||||
return BRep_Tool::Continuity(E, F1, F2);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : FillOffsetData
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
void BRepOffset_SimpleOffset::FillOffsetData(const TopoDS_Shape& theShape)
|
||||
{
|
||||
// Clears old data.
|
||||
myFaceInfo.Clear();
|
||||
myEdgeInfo.Clear();
|
||||
myVertexInfo.Clear();
|
||||
|
||||
// Faces loop. Compute offset surface for each face.
|
||||
TopExp_Explorer anExpSF(theShape, TopAbs_FACE);
|
||||
for(; anExpSF.More(); anExpSF.Next())
|
||||
{
|
||||
const TopoDS_Face& aCurrFace = TopoDS::Face(anExpSF.Current());
|
||||
FillFaceData(aCurrFace);
|
||||
}
|
||||
|
||||
// Iterate over edges to compute 3d curve.
|
||||
TopTools_IndexedDataMapOfShapeListOfShape aEdgeFaceMap;
|
||||
TopExp::MapShapesAndAncestors(theShape, TopAbs_EDGE, TopAbs_FACE, aEdgeFaceMap);
|
||||
for (Standard_Integer anIdx = 1; anIdx <= aEdgeFaceMap.Extent(); ++anIdx)
|
||||
{
|
||||
const TopoDS_Edge& aCurrEdge = TopoDS::Edge(aEdgeFaceMap.FindKey(anIdx));
|
||||
FillEdgeData(aCurrEdge, aEdgeFaceMap, anIdx);
|
||||
}
|
||||
|
||||
// Iterate over vertices to compute new vertex.
|
||||
TopTools_IndexedDataMapOfShapeListOfShape aVertexEdgeMap;
|
||||
TopExp::MapShapesAndAncestors(theShape, TopAbs_VERTEX, TopAbs_EDGE, aVertexEdgeMap);
|
||||
for (Standard_Integer anIdx = 1; anIdx <= aVertexEdgeMap.Extent(); ++anIdx)
|
||||
{
|
||||
const TopoDS_Vertex & aCurrVertex = TopoDS::Vertex(aVertexEdgeMap.FindKey(anIdx));
|
||||
FillVertexData(aCurrVertex, aVertexEdgeMap, anIdx);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : FillFaceData
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
void BRepOffset_SimpleOffset::FillFaceData(const TopoDS_Face& theFace)
|
||||
{
|
||||
NewFaceData aNFD;
|
||||
aNFD.myRevWires = Standard_False;
|
||||
aNFD.myTol = BRep_Tool::Tolerance(theFace);
|
||||
|
||||
// Create offset surface.
|
||||
|
||||
// Any existing transformation is applied to the surface.
|
||||
// New face will have null transformation.
|
||||
Handle(Geom_Surface) aS = BRep_Tool::Surface(theFace);
|
||||
|
||||
// Take into account face orientation.
|
||||
Standard_Real aMult = 1.0;
|
||||
aNFD.myRevFace = Standard_False;
|
||||
if (theFace.Orientation() == TopAbs_REVERSED)
|
||||
{
|
||||
aNFD.myRevFace = Standard_True;
|
||||
aMult = -1.0;
|
||||
}
|
||||
aNFD.myOffsetS = new Geom_OffsetSurface(aS, aMult * myOffsetValue, Standard_True);
|
||||
aNFD.myL = TopLoc_Location(); // Null transformation.
|
||||
|
||||
// Save offset surface in map.
|
||||
myFaceInfo.Bind(theFace, aNFD);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : FillEdgeData
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
void BRepOffset_SimpleOffset::FillEdgeData(const TopoDS_Edge& theEdge,
|
||||
const TopTools_IndexedDataMapOfShapeListOfShape& theEdgeFaceMap,
|
||||
const Standard_Integer theIdx)
|
||||
{
|
||||
const TopTools_ListOfShape& aFacesList = theEdgeFaceMap(theIdx);
|
||||
|
||||
if (aFacesList.Extent() == 0)
|
||||
return; // Free edges are skipped.
|
||||
|
||||
// Get offset surface.
|
||||
const TopoDS_Face& aCurrFace = TopoDS::Face(aFacesList.First());
|
||||
|
||||
if (!myFaceInfo.IsBound(aCurrFace))
|
||||
return;
|
||||
|
||||
// No need to deal with transformation - it is applied in fill faces data method.
|
||||
const NewFaceData & aNFD = myFaceInfo.Find(aCurrFace);
|
||||
Handle(Geom_Surface) anOffsetSurf = aNFD.myOffsetS;
|
||||
|
||||
// Compute offset 3d curve.
|
||||
Standard_Real aF, aL;
|
||||
Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theEdge, aCurrFace, aF, aL);
|
||||
|
||||
BRepBuilderAPI_MakeEdge anEdgeMaker(aC2d, anOffsetSurf, aF, aL);
|
||||
TopoDS_Edge aNewEdge = anEdgeMaker.Edge();
|
||||
|
||||
// Compute max tolerance. Vertex tolerance usage is taken from existing offset computation algorithm.
|
||||
// This piece of code significantly influences resulting performance.
|
||||
TopoDS_Vertex aV1, aV2;
|
||||
TopExp::Vertices(theEdge, aV1, aV2);
|
||||
Standard_Real aTol = Max(BRep_Tool::Tolerance(aV1),
|
||||
BRep_Tool::Tolerance(aV2));
|
||||
BRepLib::BuildCurves3d(aNewEdge, aTol);
|
||||
|
||||
NewEdgeData aNED;
|
||||
aNED.myOffsetC = BRep_Tool::Curve(aNewEdge, aNED.myL, aF, aL);
|
||||
|
||||
// Iterate over adjacent faces for the current edge and compute max deviation.
|
||||
Standard_Real anEdgeTol = 0.0;
|
||||
TopTools_ListIteratorOfListOfShape anIter(aFacesList);
|
||||
for ( ; !aNED.myOffsetC.IsNull() && anIter.More() ; anIter.Next())
|
||||
{
|
||||
const TopoDS_Face& aCurFace = TopoDS::Face(anIter.Value());
|
||||
|
||||
if (!myFaceInfo.IsBound(aCurFace))
|
||||
continue;
|
||||
|
||||
// Create offset curve on surface.
|
||||
Standard_Real aF, aL;
|
||||
const Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theEdge, aCurFace, aF, aL);
|
||||
const Handle(Adaptor2d_HCurve2d) aHCurve2d = new Geom2dAdaptor_HCurve(aC2d, aF, aL);
|
||||
const Handle(Adaptor3d_HSurface) aHSurface = new GeomAdaptor_HSurface(myFaceInfo.Find(aCurFace).myOffsetS);
|
||||
Adaptor3d_CurveOnSurface aCurveOnSurf(aHCurve2d, aHSurface);
|
||||
|
||||
// Extract 3d-curve (it is not null).
|
||||
const GeomAdaptor_Curve aCurve3d(aNED.myOffsetC, aF, aL);
|
||||
|
||||
// It is necessary to compute maximal deviation (tolerance).
|
||||
Standard_Real aMaxTol = 0.0;
|
||||
ShapeAnalysis_Edge::ComputeDeviation(aCurve3d, aCurveOnSurf, Standard_True, aMaxTol, NCONTROL);
|
||||
anEdgeTol = Max(anEdgeTol, aMaxTol);
|
||||
|
||||
}
|
||||
aNED.myTol = Max(BRep_Tool::Tolerance(aNewEdge), anEdgeTol);
|
||||
|
||||
// Save computed 3d curve in map.
|
||||
myEdgeInfo.Bind(theEdge, aNED);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : FillVertexData
|
||||
//purpose :
|
||||
//=============================================================================
|
||||
void BRepOffset_SimpleOffset::FillVertexData(const TopoDS_Vertex& theVertex,
|
||||
const TopTools_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
|
||||
const Standard_Integer theIdx)
|
||||
{
|
||||
// Algorithm:
|
||||
// Find adjacent edges for the given vertex.
|
||||
// Find corresponding end on the each adjacent edge.
|
||||
// Get offset points for founded end.
|
||||
// Set result vertex position as barycenter of founded points.
|
||||
|
||||
gp_Pnt aCurrPnt = BRep_Tool::Pnt(theVertex);
|
||||
|
||||
const TopTools_ListOfShape& aEdgesList = theVertexEdgeMap(theIdx);
|
||||
|
||||
if (aEdgesList.Extent() == 0)
|
||||
return; // Free vertices are skipped.
|
||||
|
||||
// Array to store offset points.
|
||||
NCollection_Vector<gp_Pnt> anOffsetPointVec;
|
||||
|
||||
Standard_Real aMaxEdgeTol = 0.0;
|
||||
|
||||
// Iterate over adjacent edges.
|
||||
TopTools_ListIteratorOfListOfShape anIterEdges(aEdgesList);
|
||||
for (; anIterEdges.More() ; anIterEdges.Next() )
|
||||
{
|
||||
const TopoDS_Edge& aCurrEdge = TopoDS::Edge(anIterEdges.Value());
|
||||
|
||||
if (!myEdgeInfo.IsBound(aCurrEdge))
|
||||
continue; // Skip shared edges with wrong orientation.
|
||||
|
||||
// Find the closest bound.
|
||||
Standard_Real aF, aL;
|
||||
Handle(Geom_Curve) aC3d = BRep_Tool::Curve(aCurrEdge, aF, aL);
|
||||
// Protection from degenerated edges.
|
||||
if (aC3d.IsNull())
|
||||
continue;
|
||||
|
||||
const gp_Pnt aPntF = aC3d->Value(aF);
|
||||
const gp_Pnt aPntL = aC3d->Value(aL);
|
||||
|
||||
const Standard_Real aSqDistF = aPntF.SquareDistance(aCurrPnt);
|
||||
const Standard_Real aSqDistL = aPntL.SquareDistance(aCurrPnt);
|
||||
|
||||
Standard_Real aMinParam = aF, aMaxParam = aL;
|
||||
if (aSqDistL < aSqDistF)
|
||||
{
|
||||
// Square distance to last point is closer.
|
||||
aMinParam = aL; aMaxParam = aF;
|
||||
}
|
||||
|
||||
// Compute point on offset edge.
|
||||
const NewEdgeData& aNED = myEdgeInfo.Find(aCurrEdge);
|
||||
const Handle(Geom_Curve) &anOffsetCurve = aNED.myOffsetC;
|
||||
const gp_Pnt anOffsetPoint = anOffsetCurve->Value(aMinParam);
|
||||
anOffsetPointVec.Append(anOffsetPoint);
|
||||
|
||||
// Handle situation when edge is closed.
|
||||
TopoDS_Vertex aV1, aV2;
|
||||
TopExp::Vertices(aCurrEdge, aV1, aV2);
|
||||
if (aV1.IsSame(aV2))
|
||||
{
|
||||
const gp_Pnt anOffsetPoint = anOffsetCurve->Value(aMaxParam);
|
||||
anOffsetPointVec.Append(anOffsetPoint);
|
||||
}
|
||||
|
||||
aMaxEdgeTol = Max(aMaxEdgeTol, aNED.myTol);
|
||||
}
|
||||
|
||||
// NCollection_Vector starts from 0 by default.
|
||||
// It's better to use lower() and upper() in this case instead of direct indexes range.
|
||||
gp_Pnt aCenter(0.0, 0.0, 0.0);
|
||||
for(Standard_Integer i = anOffsetPointVec.Lower();
|
||||
i <= anOffsetPointVec.Upper();
|
||||
++i)
|
||||
{
|
||||
aCenter.SetXYZ(aCenter.XYZ() + anOffsetPointVec.Value(i).XYZ());
|
||||
}
|
||||
aCenter.SetXYZ(aCenter.XYZ() / anOffsetPointVec.Size());
|
||||
|
||||
// Compute max distance.
|
||||
Standard_Real aSqMaxDist = 0.0;
|
||||
for(Standard_Integer i = anOffsetPointVec.Lower();
|
||||
i <= anOffsetPointVec.Upper();
|
||||
++i)
|
||||
{
|
||||
const Standard_Real aSqDist = aCenter.SquareDistance(anOffsetPointVec.Value(i));
|
||||
if (aSqDist > aSqMaxDist)
|
||||
aSqMaxDist = aSqDist;
|
||||
}
|
||||
|
||||
const Standard_Real aResTol = Max(aMaxEdgeTol, Sqrt(aSqMaxDist));
|
||||
|
||||
const Standard_Real aMultCoeff = 1.001; // Avoid tolerance problems.
|
||||
NewVertexData aNVD;
|
||||
aNVD.myP = aCenter;
|
||||
aNVD.myTol = aResTol * aMultCoeff;
|
||||
|
||||
// Save computed vertex info.
|
||||
myVertexInfo.Bind(theVertex, aNVD);
|
||||
}
|
177
src/BRepOffset/BRepOffset_SimpleOffset.hxx
Normal file
177
src/BRepOffset/BRepOffset_SimpleOffset.hxx
Normal file
@@ -0,0 +1,177 @@
|
||||
// Created on: 2016-10-14
|
||||
// Created by: Alexander MALYSHEV
|
||||
// Copyright (c) 1999-2016 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.
|
||||
|
||||
#ifndef _BRepOffset_SimpleOffset_HeaderFile
|
||||
#define _BRepOffset_SimpleOffset_HeaderFile
|
||||
|
||||
#include <BRepTools_Modification.hxx>
|
||||
#include <GeomAbs_Shape.hxx>
|
||||
#include <Geom2d_Curve.hxx>
|
||||
#include <Standard_Real.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <Standard_Type.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
#include <NCollection_DataMap.hxx>
|
||||
|
||||
|
||||
class BRepOffset_SimpleOffset;
|
||||
DEFINE_STANDARD_HANDLE(BRepOffset_SimpleOffset, BRepTools_Modification)
|
||||
|
||||
//! This class represents mechanism of simple offset algorithm i. e.
|
||||
//! topology-preserve offset without intersection.
|
||||
class BRepOffset_SimpleOffset : public BRepTools_Modification
|
||||
{
|
||||
public:
|
||||
|
||||
DEFINE_STANDARD_RTTI(BRepOffset_SimpleOffset)
|
||||
|
||||
//! Constructor.
|
||||
Standard_EXPORT BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
|
||||
const Standard_Real theOffsetValue);
|
||||
|
||||
//! Returns Standard_True if the face <F> has been
|
||||
//! modified. In this case, <S> is the new geometric
|
||||
//! support of the face, <L> the new location,<Tol>
|
||||
//! the new tolerance.<RevWires> has to be set to
|
||||
//! Standard_True when the modification reverses the
|
||||
//! normal of the surface.(the wires have to be
|
||||
//! reversed). <RevFace> has to be set to
|
||||
//! Standard_True if the orientation of the modified
|
||||
//! face changes in the shells which contain it. --
|
||||
//! Here, <RevFace> will return Standard_True if the
|
||||
//! -- gp_Trsf is negative.
|
||||
Standard_EXPORT Standard_Boolean NewSurface (const TopoDS_Face& F,
|
||||
Handle(Geom_Surface)& S,
|
||||
TopLoc_Location& L,
|
||||
Standard_Real& Tol,
|
||||
Standard_Boolean& RevWires,
|
||||
Standard_Boolean& RevFace) Standard_OVERRIDE;
|
||||
|
||||
//! Returns Standard_True if the edge <E> has been
|
||||
//! modified. In this case, <C> is the new geometric
|
||||
//! support of the edge, <L> the new location, <Tol>
|
||||
//! the new tolerance. Otherwise, returns
|
||||
//! Standard_False, and <C>, <L>, <Tol> are not
|
||||
//! significant.
|
||||
Standard_EXPORT Standard_Boolean NewCurve (const TopoDS_Edge& E,
|
||||
Handle(Geom_Curve)& C,
|
||||
TopLoc_Location& L,
|
||||
Standard_Real& Tol) Standard_OVERRIDE;
|
||||
|
||||
//! Returns Standard_True if the vertex <V> has been
|
||||
//! modified. In this case, <P> is the new geometric
|
||||
//! support of the vertex, <Tol> the new tolerance.
|
||||
//! Otherwise, returns Standard_False, and <P>, <Tol>
|
||||
//! are not significant.
|
||||
Standard_EXPORT Standard_Boolean NewPoint (const TopoDS_Vertex& V,
|
||||
gp_Pnt& P,
|
||||
Standard_Real& Tol) Standard_OVERRIDE;
|
||||
|
||||
//! Returns Standard_True if the edge <E> has a new
|
||||
//! curve on surface on the face <F>.In this case, <C>
|
||||
//! is the new geometric support of the edge, <L> the
|
||||
//! new location, <Tol> the new tolerance.
|
||||
//! Otherwise, returns Standard_False, and <C>, <L>,
|
||||
//! <Tol> are not significant.
|
||||
Standard_EXPORT Standard_Boolean NewCurve2d (const TopoDS_Edge& E,
|
||||
const TopoDS_Face& F,
|
||||
const TopoDS_Edge& NewE,
|
||||
const TopoDS_Face& NewF,
|
||||
Handle(Geom2d_Curve)& C,
|
||||
Standard_Real& Tol) Standard_OVERRIDE;
|
||||
|
||||
//! Returns Standard_True if the Vertex <V> has a new
|
||||
//! parameter on the edge <E>. In this case, <P> is
|
||||
//! the parameter, <Tol> the new tolerance.
|
||||
//! Otherwise, returns Standard_False, and <P>, <Tol>
|
||||
//! are not significant.
|
||||
Standard_EXPORT Standard_Boolean NewParameter (const TopoDS_Vertex& V,
|
||||
const TopoDS_Edge& E,
|
||||
Standard_Real& P,
|
||||
Standard_Real& Tol) Standard_OVERRIDE;
|
||||
|
||||
//! Returns the continuity of <NewE> between <NewF1>
|
||||
//! and <NewF2>.
|
||||
//!
|
||||
//! <NewE> is the new edge created from <E>. <NewF1>
|
||||
//! (resp. <NewF2>) is the new face created from <F1>
|
||||
//! (resp. <F2>).
|
||||
Standard_EXPORT GeomAbs_Shape Continuity (const TopoDS_Edge& E,
|
||||
const TopoDS_Face& F1,
|
||||
const TopoDS_Face& F2,
|
||||
const TopoDS_Edge& NewE,
|
||||
const TopoDS_Face& NewF1,
|
||||
const TopoDS_Face& NewF2) Standard_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
//! Method to fill new face data for single face.
|
||||
void FillFaceData(const TopoDS_Face& theFace);
|
||||
|
||||
//! Method to fill new edge data for single edge.
|
||||
void FillEdgeData(const TopoDS_Edge& theEdge,
|
||||
const TopTools_IndexedDataMapOfShapeListOfShape& theEdgeFaceMap,
|
||||
const Standard_Integer theIdx);
|
||||
|
||||
//! Method to fill new vertex data for single vertex.
|
||||
void FillVertexData(const TopoDS_Vertex& theVertex,
|
||||
const TopTools_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
|
||||
const Standard_Integer theIdx);
|
||||
|
||||
struct NewFaceData
|
||||
{
|
||||
Handle(Geom_Surface) myOffsetS;
|
||||
TopLoc_Location myL;
|
||||
Standard_Real myTol;
|
||||
Standard_Boolean myRevWires;
|
||||
Standard_Boolean myRevFace;
|
||||
};
|
||||
|
||||
struct NewEdgeData
|
||||
{
|
||||
Handle(Geom_Curve) myOffsetC; // Resulting curve.
|
||||
TopLoc_Location myL;
|
||||
Standard_Real myTol;
|
||||
};
|
||||
|
||||
struct NewVertexData
|
||||
{
|
||||
gp_Pnt myP;
|
||||
Standard_Real myTol;
|
||||
};
|
||||
|
||||
//! Fills offset data.
|
||||
void FillOffsetData(const TopoDS_Shape& theInputShape);
|
||||
|
||||
//! Copy-assignment contsructor and copy constructor are not allowed.
|
||||
void operator=(const BRepOffset_SimpleOffset&);
|
||||
BRepOffset_SimpleOffset(const BRepOffset_SimpleOffset&);
|
||||
|
||||
//! Map of faces to new faces information.
|
||||
NCollection_DataMap<TopoDS_Face, NewFaceData> myFaceInfo;
|
||||
|
||||
//! Map of edges to new edges information.
|
||||
NCollection_DataMap<TopoDS_Edge, NewEdgeData> myEdgeInfo;
|
||||
|
||||
//! Map of vertices to new vertices information.
|
||||
NCollection_DataMap<TopoDS_Vertex, NewVertexData> myVertexInfo;
|
||||
|
||||
|
||||
//! Ofsset value.
|
||||
Standard_Real myOffsetValue;
|
||||
};
|
||||
|
||||
#endif // _BRepOffset_SimpleOffset_HeaderFile
|
4
src/BRepOffset/FILES
Normal file
4
src/BRepOffset/FILES
Normal file
@@ -0,0 +1,4 @@
|
||||
BRepOffset_MakeSimpleOffset.cxx
|
||||
BRepOffset_MakeSimpleOffset.hxx
|
||||
BRepOffset_SimpleOffset.cxx
|
||||
BRepOffset_SimpleOffset.hxx
|
@@ -54,6 +54,7 @@
|
||||
#include <LocOpe_FindEdges.hxx>
|
||||
#include <LocOpe_FindEdgesInFace.hxx>
|
||||
|
||||
#include <BRepOffset_MakeSimpleOffset.hxx>
|
||||
#include <BRepOffsetAPI_MakeOffsetShape.hxx>
|
||||
#include <BRepOffsetAPI_MakeThickSolid.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
@@ -2241,6 +2242,52 @@ static Standard_Integer BOSS(Draw_Interpretor& theCommands,
|
||||
return 1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//function : ComputeSimpleOffset
|
||||
//purpose : Computes simple offset.
|
||||
//=============================================================================
|
||||
static Standard_Integer ComputeSimpleOffset(Draw_Interpretor& theCommands,
|
||||
Standard_Integer narg,
|
||||
const char** a)
|
||||
{
|
||||
if (narg != 4)
|
||||
{
|
||||
theCommands << "offsetshapesimple result shape offsetvalue \n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Input data.
|
||||
TopoDS_Shape aShape = DBRep::Get(a[2]);
|
||||
if (aShape.IsNull())
|
||||
{
|
||||
theCommands << "Input shape is null";
|
||||
return 0;
|
||||
}
|
||||
const Standard_Real anOffsetValue = Draw::Atof(a[3]);
|
||||
if (Abs(anOffsetValue) < gp::Resolution())
|
||||
{
|
||||
theCommands << "Null offset value";
|
||||
return 0;
|
||||
}
|
||||
|
||||
BRepOffset_MakeSimpleOffset aMaker(aShape, anOffsetValue);
|
||||
if (narg == 5 && !strcasecmp(a[4],"solid") )
|
||||
{
|
||||
aMaker.SetBuildSolidFlag(Standard_True);
|
||||
}
|
||||
|
||||
aMaker.Perform();
|
||||
|
||||
if (!aMaker.IsDone())
|
||||
{
|
||||
theCommands << "ERROR:" << aMaker.GetErrorMessage() << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBRep::Set(a[1], aMaker.GetResultShape());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : FeatureCommands
|
||||
@@ -2393,4 +2440,7 @@ void BRepTest::FeatureCommands (Draw_Interpretor& theCommands)
|
||||
" Perform fillet on top and bottom edges of dprism :bossage dprism result radtop radbottom First/LastShape (1/2)",
|
||||
__FILE__,BOSS);
|
||||
|
||||
theCommands.Add("offsetshapesimple",
|
||||
"offsetshapesimple result shape offsetvalue [solid]",
|
||||
__FILE__, ComputeSimpleOffset);
|
||||
}
|
||||
|
Reference in New Issue
Block a user