1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-06 18:26:22 +03:00
occt/src/BRepOffset/BRepOffset_Analyse.cxx
aml 03383c97c3 0026473: Offset API fails to create offset shape
Tolerance of map building changed.
Added possibility to work 0.0 offset value.

Added test cases bugs/modalg_6/bug26473_1 bug26473_2
2015-07-29 15:34:24 +03:00

609 lines
17 KiB
C++

// Created on: 1995-10-20
// Created by: Yves FRICAUD
// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Adaptor3d_Surface.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepOffset_Analyse.hxx>
#include <BRepOffset_Interval.hxx>
#include <BRepOffset_ListIteratorOfListOfInterval.hxx>
#include <BRepOffset_Tool.hxx>
#include <BRepTools.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <gp.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec.hxx>
#include <Precision.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
//
static void Correct2dPoint(const Adaptor3d_Surface& theS, gp_Pnt2d& theP2d);
//
static BRepOffset_Type DefineConnectType(const TopoDS_Edge& E,
const TopoDS_Face& F1,
const TopoDS_Face& F2,
const Standard_Real SinTol,
const Standard_Boolean CorrectPoint);
//
static void CorrectOrientationOfTangent(gp_Vec& TangVec,
const TopoDS_Vertex& aVertex,
const TopoDS_Edge& anEdge)
{
TopoDS_Vertex Vlast = TopExp::LastVertex(anEdge);
if (aVertex.IsSame(Vlast))
TangVec.Reverse();
}
//=======================================================================
//function : BRepOffset_Analyse
//purpose :
//=======================================================================
BRepOffset_Analyse::BRepOffset_Analyse()
:myDone(Standard_False)
{
}
//=======================================================================
//function : BRepOffset_Analyse
//purpose :
//=======================================================================
BRepOffset_Analyse::BRepOffset_Analyse(const TopoDS_Shape& S,
const Standard_Real Angle)
:myDone(Standard_False)
{
Perform( S, Angle);
}
//=======================================================================
//function : EdgeAnlyse
//purpose :
//=======================================================================
static void EdgeAnalyse(const TopoDS_Edge& E,
const TopoDS_Face& F1,
const TopoDS_Face& F2,
const Standard_Real SinTol,
BRepOffset_ListOfInterval& LI)
{
Standard_Real f,l;
BRep_Tool::Range(E, F1, f, l);
BRepOffset_Interval I;
I.First(f); I.Last(l);
//
// Tangent if the regularity is at least G1.
if (BRep_Tool::HasContinuity(E,F1,F2)) {
if (BRep_Tool::Continuity(E,F1,F2) > GeomAbs_C0) {
I.Type(BRepOffset_Tangent);
LI.Append(I);
return;
}
}
//
BRepOffset_Type aType = DefineConnectType(E, F1, F2, SinTol, Standard_False);
if(aType != BRepOffset_Tangent)
{
aType = DefineConnectType(E, F1, F2, SinTol, Standard_True);
}
I.Type(aType);
LI.Append(I);
}
//=======================================================================
//function : BuildAncestors
//purpose :
//=======================================================================
static void BuildAncestors (const TopoDS_Shape& S,
TopTools_IndexedDataMapOfShapeListOfShape& MA)
{
MA.Clear();
TopExp::MapShapesAndAncestors(S,TopAbs_VERTEX,TopAbs_EDGE,MA);
TopExp::MapShapesAndAncestors(S,TopAbs_EDGE ,TopAbs_FACE,MA);
// Purge ancestors.
TopTools_MapOfShape Map;
for (Standard_Integer i = 1; i <= MA.Extent(); i++) {
Map.Clear();
TopTools_ListOfShape& L = MA(i);
TopTools_ListIteratorOfListOfShape it(L);
while (it.More()) {
if (!Map.Add(it.Value())) {
L.Remove(it);
}
else {
it.Next();
}
}
}
}
//=======================================================================
//function : IsDone
//purpose :
//=======================================================================
Standard_Boolean BRepOffset_Analyse::IsDone() const
{
return myDone;
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void BRepOffset_Analyse::Perform (const TopoDS_Shape& S,
const Standard_Real Angle)
{
myShape = S;
angle = Angle;
Standard_Real SinTol = Sin(Angle);
// Build ancestors.
BuildAncestors (S,ancestors);
TopExp_Explorer Exp(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
for ( ; Exp.More(); Exp.Next()) {
const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
if (!mapEdgeType.IsBound(E)) {
BRepOffset_ListOfInterval LI;
mapEdgeType.Bind(E,LI);
const TopTools_ListOfShape& L = Ancestors(E);
if ( L.IsEmpty())
continue;
if (L.Extent() == 2) {
const TopoDS_Face& F1 = TopoDS::Face(L.First());
const TopoDS_Face& F2 = TopoDS::Face(L.Last ());
EdgeAnalyse(E,F1,F2,SinTol,mapEdgeType(E));
}
else if (L.Extent() == 1) {
Standard_Real U1,U2;
const TopoDS_Face& F = TopoDS::Face(L.First());
BRep_Tool::Range(E,F,U1,U2);
BRepOffset_Interval Inter(U1,U2,BRepOffset_Other);
if (! BRepTools::IsReallyClosed(E,F)) {
Inter.Type(BRepOffset_FreeBoundary);
}
mapEdgeType(E).Append(Inter);
}
else {
#ifdef OCCT_DEBUG
cout <<"edge shared by more than two faces"<<endl;
#endif
}
}
}
myDone = Standard_True;
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void BRepOffset_Analyse::Clear()
{
myDone = Standard_False;
myShape .Nullify();
mapEdgeType.Clear();
ancestors .Clear();
}
//=======================================================================
//function : BRepOffset_ListOfInterval&
//purpose :
//=======================================================================
const BRepOffset_ListOfInterval& BRepOffset_Analyse::Type(const TopoDS_Edge& E)
const
{
return mapEdgeType (E);
}
//=======================================================================
//function : Edges
//purpose :
//=======================================================================
void BRepOffset_Analyse::Edges(const TopoDS_Vertex& V,
const BRepOffset_Type T,
TopTools_ListOfShape& LE)
const
{
LE.Clear();
const TopTools_ListOfShape& L = Ancestors (V);
TopTools_ListIteratorOfListOfShape it(L);
for ( ;it.More(); it.Next()) {
const TopoDS_Edge& E = TopoDS::Edge(it.Value());
TopoDS_Vertex V1,V2;
BRepOffset_Tool::EdgeVertices (E,V1,V2);
if (V1.IsSame(V)) {
if (mapEdgeType(E).Last().Type() == T)
LE.Append(E);
}
if (V2.IsSame(V)) {
if (mapEdgeType(E).First().Type() == T)
LE.Append(E);
}
}
}
//=======================================================================
//function : Edges
//purpose :
//=======================================================================
void BRepOffset_Analyse::Edges(const TopoDS_Face& F,
const BRepOffset_Type T,
TopTools_ListOfShape& LE)
const
{
LE.Clear();
TopExp_Explorer exp(F, TopAbs_EDGE);
for ( ;exp.More(); exp.Next()) {
const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
const BRepOffset_ListOfInterval& Lint = Type(E);
BRepOffset_ListIteratorOfListOfInterval it(Lint);
for ( ;it.More(); it.Next()) {
if (it.Value().Type() == T) LE.Append(E);
}
}
}
//=======================================================================
//function : TangentEdges
//purpose :
//=======================================================================
void BRepOffset_Analyse::TangentEdges(const TopoDS_Edge& Edge ,
const TopoDS_Vertex& Vertex,
TopTools_ListOfShape& Edges ) const
{
gp_Vec V,VRef;
Standard_Real U,URef;
BRepAdaptor_Curve C3d, C3dRef;
URef = BRep_Tool::Parameter(Vertex,Edge);
C3dRef = BRepAdaptor_Curve(Edge);
VRef = C3dRef.DN(URef,1);
CorrectOrientationOfTangent(VRef, Vertex, Edge);
if (VRef.SquareMagnitude() < gp::Resolution()) return;
Edges.Clear();
const TopTools_ListOfShape& Anc = Ancestors(Vertex);
TopTools_ListIteratorOfListOfShape it(Anc);
for ( ; it.More(); it.Next()) {
const TopoDS_Edge& CurE = TopoDS::Edge(it.Value());
if ( CurE.IsSame(Edge)) continue;
U = BRep_Tool::Parameter(Vertex,CurE);
C3d = BRepAdaptor_Curve(CurE);
V = C3d.DN(U,1);
CorrectOrientationOfTangent(V, Vertex, CurE);
if (V.SquareMagnitude() < gp::Resolution()) continue;
if (V.IsOpposite(VRef,angle)) {
Edges.Append(CurE);
}
}
}
//=======================================================================
//function : HasAncestor
//purpose :
//=======================================================================
Standard_Boolean BRepOffset_Analyse::HasAncestor (const TopoDS_Shape& S) const
{
return ancestors.Contains(S);
}
//=======================================================================
//function : Ancestors
//purpose :
//=======================================================================
const TopTools_ListOfShape& BRepOffset_Analyse::Ancestors
(const TopoDS_Shape& S) const
{
return ancestors.FindFromKey(S);
}
//=======================================================================
//function : Explode
//purpose :
//=======================================================================
void BRepOffset_Analyse::Explode( TopTools_ListOfShape& List,
const BRepOffset_Type T ) const
{
List.Clear();
BRep_Builder B;
TopTools_MapOfShape Map;
TopExp_Explorer Fexp;
for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
if ( Map.Add(Fexp.Current())) {
TopoDS_Face Face = TopoDS::Face(Fexp.Current());
TopoDS_Compound Co;
B.MakeCompound(Co);
B.Add(Co,Face);
// add to Co all faces from the cloud of faces
// G1 created from <Face>
AddFaces(Face,Co,Map,T);
List.Append(Co);
}
}
}
//=======================================================================
//function : Explode
//purpose :
//=======================================================================
void BRepOffset_Analyse::Explode( TopTools_ListOfShape& List,
const BRepOffset_Type T1,
const BRepOffset_Type T2) const
{
List.Clear();
BRep_Builder B;
TopTools_MapOfShape Map;
TopExp_Explorer Fexp;
for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
if ( Map.Add(Fexp.Current())) {
TopoDS_Face Face = TopoDS::Face(Fexp.Current());
TopoDS_Compound Co;
B.MakeCompound(Co);
B.Add(Co,Face);
// add to Co all faces from the cloud of faces
// G1 created from <Face>
AddFaces(Face,Co,Map,T1,T2);
List.Append(Co);
}
}
}
//=======================================================================
//function : AddFaces
//purpose :
//=======================================================================
void BRepOffset_Analyse::AddFaces (const TopoDS_Face& Face,
TopoDS_Compound& Co,
TopTools_MapOfShape& Map,
const BRepOffset_Type T) const
{
BRep_Builder B;
TopExp_Explorer exp(Face,TopAbs_EDGE);
for ( ; exp.More(); exp.Next()) {
const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
const BRepOffset_ListOfInterval& LI = Type(E);
if (!LI.IsEmpty() && LI.First().Type() == T) {
// so <NewFace> is attached to G1 by <Face>
const TopTools_ListOfShape& L = Ancestors(E);
if (L.Extent() == 2) {
TopoDS_Face F1 = TopoDS::Face(L.First());
if ( F1.IsSame(Face))
F1 = TopoDS::Face(L.Last ());
if ( Map.Add(F1)) {
B.Add(Co,F1);
AddFaces(F1,Co,Map,T);
}
}
}
}
}
//=======================================================================
//function : AddFaces
//purpose :
//=======================================================================
void BRepOffset_Analyse::AddFaces (const TopoDS_Face& Face,
TopoDS_Compound& Co,
TopTools_MapOfShape& Map,
const BRepOffset_Type T1,
const BRepOffset_Type T2) const
{
BRep_Builder B;
TopExp_Explorer exp(Face,TopAbs_EDGE);
for ( ; exp.More(); exp.Next()) {
const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
const BRepOffset_ListOfInterval& LI = Type(E);
if (!LI.IsEmpty() &&
(LI.First().Type() == T1 || LI.First().Type() == T2)) {
// so <NewFace> is attached to G1 by <Face>
const TopTools_ListOfShape& L = Ancestors(E);
if (L.Extent() == 2) {
TopoDS_Face F1 = TopoDS::Face(L.First());
if ( F1.IsSame(Face))
F1 = TopoDS::Face(L.Last ());
if ( Map.Add(F1)) {
B.Add(Co,F1);
AddFaces(F1,Co,Map,T1,T2);
}
}
}
}
}
//=======================================================================
//function : Correct2dPoint
//purpose :
//=======================================================================
void Correct2dPoint(const Adaptor3d_Surface& theS, gp_Pnt2d& theP2d)
{
const Standard_Real coeff = 0.01;
Standard_Real eps;
Standard_Real u1, u2, v1, v2;
if(theS.GetType() >= GeomAbs_BezierSurface)
{
u1 = theS.FirstUParameter();
u2 = theS.LastUParameter();
v1 = theS.FirstVParameter();
v2 = theS.LastVParameter();
if(!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
{
eps = Max(coeff*(u2-u1), Precision::PConfusion());
if(Abs(theP2d.X()-u1) < eps)
{
theP2d.SetX(u1 + eps);
}
if(Abs(theP2d.X()-u2) < eps)
{
theP2d.SetX(u2 - eps);
}
}
if(!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
{
eps = Max(coeff*(v2-v1), Precision::PConfusion());
if(Abs(theP2d.Y()-v1) < eps)
{
theP2d.SetY(v1 + eps);
}
if(Abs(theP2d.Y()-v2) < eps)
{
theP2d.SetY(v2 - eps);
}
}
}
}
//=======================================================================
//function : DefineConnectType
//purpose :
//=======================================================================
BRepOffset_Type DefineConnectType(const TopoDS_Edge& E,
const TopoDS_Face& F1,
const TopoDS_Face& F2,
const Standard_Real SinTol,
const Standard_Boolean CorrectPoint)
{
TopLoc_Location L;
Standard_Real f,l;
BRepAdaptor_Surface S1(F1), S2(F2);
Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E,F2,f,l);
BRepAdaptor_Curve C(E);
f = C.FirstParameter();
l = C.LastParameter();
//
Standard_Real ParOnC = 0.5*(f+l);
gp_Vec T1 = C.DN(ParOnC,1).Transformed(L.Transformation());
if (T1.SquareMagnitude() > gp::Resolution()) {
T1.Normalize();
}
if (BRepOffset_Tool::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
T1.Reverse();
}
if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
gp_Pnt2d P = C1->Value(ParOnC);
gp_Pnt P3;
gp_Vec D1U,D1V;
if(CorrectPoint)
Correct2dPoint(S1, P);
//
S1.D1(P.X(),P.Y(),P3,D1U,D1V);
gp_Vec DN1(D1U^D1V);
if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
P = C2->Value(ParOnC);
if(CorrectPoint)
Correct2dPoint(S2, P);
S2.D1(P.X(),P.Y(),P3,D1U,D1V);
gp_Vec DN2(D1U^D1V);
if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
DN1.Normalize();
DN2.Normalize();
gp_Vec ProVec = DN1^DN2;
Standard_Real NormProVec = ProVec.Magnitude();
if (Abs(NormProVec) < SinTol) {
// plane
if (DN1.Dot(DN2) > 0) {
//Tangent
return BRepOffset_Tangent;
}
else {
//Mixed not finished!
#ifdef OCCT_DEBUG
cout <<" faces locally mixed"<<endl;
#endif
return BRepOffset_Convex;
}
}
else {
if (NormProVec > gp::Resolution())
ProVec.Normalize();
Standard_Real Prod = T1.Dot(DN1^DN2);
if (Prod > 0.) {
//
return BRepOffset_Convex;
}
else {
//reenters
return BRepOffset_Concave;
}
}
}