// 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. //: q0 abv 12.03.99: mat-a.stp: protection against no pcurves in SwapSeam() // abv 28.04.99 S4137: added method Add(WireData), method SetLast fixed // abv 05.05.99 S4174: protection against INTERNAL/EXTERNAL edges #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPLEMENT_STANDARD_RTTIEXT(ShapeExtend_WireData, Standard_Transient) //================================================================================================= ShapeExtend_WireData::ShapeExtend_WireData() { Clear(); } //================================================================================================= ShapeExtend_WireData::ShapeExtend_WireData(const TopoDS_Wire& wire, const Standard_Boolean chained, const Standard_Boolean theManifold) { Init(wire, chained, theManifold); } //================================================================================================= void ShapeExtend_WireData::Init(const Handle(ShapeExtend_WireData)& other) { Clear(); Standard_Integer i, nb = other->NbEdges(); for (i = 1; i <= nb; i++) Add(other->Edge(i)); nb = other->NbNonManifoldEdges(); for (i = 1; i <= nb; i++) Add(other->NonmanifoldEdge(i)); myManifoldMode = other->ManifoldMode(); } //================================================================================================= Standard_Boolean ShapeExtend_WireData::Init(const TopoDS_Wire& wire, const Standard_Boolean chained, const Standard_Boolean theManifold) { Clear(); myManifoldMode = theManifold; Standard_Boolean OK = Standard_True; TopoDS_Vertex Vlast; for (TopoDS_Iterator it(wire); it.More(); it.Next()) { TopoDS_Edge E = TopoDS::Edge(it.Value()); // protect against INTERNAL/EXTERNAL edges if ((E.Orientation() != TopAbs_REVERSED && E.Orientation() != TopAbs_FORWARD)) { myNonmanifoldEdges->Append(E); continue; } TopoDS_Vertex V1, V2; for (TopoDS_Iterator itv(E); itv.More(); itv.Next()) { TopoDS_Vertex V = TopoDS::Vertex(itv.Value()); if (V.Orientation() == TopAbs_FORWARD) V1 = V; else if (V.Orientation() == TopAbs_REVERSED) V2 = V; } // chainage? Si pas bon et chained False on repart sur WireExplorer if (!Vlast.IsNull() && !Vlast.IsSame(V1) && theManifold) { OK = Standard_False; if (!chained) break; } Vlast = V2; if (wire.Orientation() == TopAbs_REVERSED) myEdges->Prepend(E); else myEdges->Append(E); } if (!myManifoldMode) { Standard_Integer nb = myNonmanifoldEdges->Length(); Standard_Integer i = 1; for (; i <= nb; i++) myEdges->Append(myNonmanifoldEdges->Value(i)); myNonmanifoldEdges->Clear(); } // refaire chainage ? Par WireExplorer if (OK || chained) return OK; Clear(); for (BRepTools_WireExplorer we(wire); we.More(); we.Next()) myEdges->Append(TopoDS::Edge(we.Current())); return OK; } //================================================================================================= void ShapeExtend_WireData::Clear() { myEdges = new TopTools_HSequenceOfShape(); myNonmanifoldEdges = new TopTools_HSequenceOfShape; mySeamF = mySeamR = -1; mySeams.Nullify(); myManifoldMode = Standard_True; } //================================================================================================= void ShapeExtend_WireData::ComputeSeams(const Standard_Boolean enforce) { if (mySeamF >= 0 && !enforce) return; mySeams = new TColStd_HSequenceOfInteger(); mySeamF = mySeamR = 0; TopoDS_Shape S; Standard_Integer i, nb = NbEdges(); TopTools_IndexedMapOfShape ME; Standard_Integer* SE = new Standard_Integer[nb + 1]; // deux passes : d abord on mappe les Edges REVERSED // Pour chacune, on note aussi son RANG dans la liste for (i = 1; i <= nb; i++) { S = Edge(i); if (S.Orientation() == TopAbs_REVERSED) { Standard_Integer num = ME.Add(S); SE[num] = i; } } // ensuite on voit les Edges FORWARD qui y seraient deja -> on note leur n0 // c-a-d le n0 de la directe ET de la reverse for (i = 1; i <= nb; i++) { S = Edge(i); if (S.Orientation() == TopAbs_REVERSED) continue; Standard_Integer num = ME.FindIndex(S); if (num <= 0) continue; if (mySeamF == 0) { mySeamF = i; mySeamR = SE[num]; } else { mySeams->Append(i); mySeams->Append(SE[num]); } } delete[] SE; // ne pas oublier !! } //================================================================================================= void ShapeExtend_WireData::SetLast(const Standard_Integer num) { if (num == 0) return; Standard_Integer i, nb = NbEdges(); for (i = nb; i > num; i--) { TopoDS_Edge edge = TopoDS::Edge(myEdges->Value(nb)); myEdges->Remove(nb); myEdges->InsertBefore(1, edge); } mySeamF = -1; } //================================================================================================= void ShapeExtend_WireData::SetDegeneratedLast() { Standard_Integer i, nb = NbEdges(); for (i = 1; i <= nb; i++) { if (BRep_Tool::Degenerated(Edge(i))) { SetLast(i); return; } } } //================================================================================================= void ShapeExtend_WireData::Add(const TopoDS_Edge& edge, const Standard_Integer atnum) { if (edge.Orientation() != TopAbs_REVERSED && edge.Orientation() != TopAbs_FORWARD && myManifoldMode) { myNonmanifoldEdges->Append(edge); return; } if (edge.IsNull()) return; if (atnum == 0) { myEdges->Append(edge); } else { myEdges->InsertBefore(atnum, edge); } mySeamF = -1; } //================================================================================================= void ShapeExtend_WireData::Add(const TopoDS_Wire& wire, const Standard_Integer atnum) { if (wire.IsNull()) return; Standard_Integer n = atnum; TopTools_SequenceOfShape aNMEdges; for (TopoDS_Iterator it(wire); it.More(); it.Next()) { TopoDS_Edge edge = TopoDS::Edge(it.Value()); if (edge.Orientation() != TopAbs_REVERSED && edge.Orientation() != TopAbs_FORWARD) { if (myManifoldMode) myNonmanifoldEdges->Append(edge); else aNMEdges.Append(edge); continue; } if (n == 0) { myEdges->Append(edge); } else { myEdges->InsertBefore(n, edge); n++; } } Standard_Integer i = 1, nb = aNMEdges.Length(); for (; i <= nb; i++) myEdges->Append(aNMEdges.Value(i)); mySeamF = -1; } //================================================================================================= void ShapeExtend_WireData::Add(const Handle(ShapeExtend_WireData)& wire, const Standard_Integer atnum) { if (wire.IsNull()) return; TopTools_SequenceOfShape aNMEdges; Standard_Integer n = atnum; Standard_Integer i = 1; for (; i <= wire->NbEdges(); i++) { TopoDS_Edge aE = wire->Edge(i); if (aE.Orientation() == TopAbs_INTERNAL || aE.Orientation() == TopAbs_EXTERNAL) { aNMEdges.Append(aE); continue; } if (n == 0) { myEdges->Append(wire->Edge(i)); } else { myEdges->InsertBefore(n, wire->Edge(i)); n++; } } // non-manifold edges for non-manifold wire should be added at end for (i = 1; i <= aNMEdges.Length(); i++) myEdges->Append(aNMEdges.Value(i)); for (i = 1; i <= wire->NbNonManifoldEdges(); i++) { if (myManifoldMode) myNonmanifoldEdges->Append(wire->NonmanifoldEdge(i)); else { if (n == 0) myEdges->Append(wire->Edge(i)); else { myEdges->InsertBefore(n, wire->Edge(i)); n++; } } } mySeamF = -1; } //================================================================================================= void ShapeExtend_WireData::Add(const TopoDS_Shape& shape, const Standard_Integer atnum) { if (shape.ShapeType() == TopAbs_EDGE) Add(TopoDS::Edge(shape), atnum); else if (shape.ShapeType() == TopAbs_WIRE) Add(TopoDS::Wire(shape), atnum); } //================================================================================================= void ShapeExtend_WireData::AddOriented(const TopoDS_Edge& edge, const Standard_Integer mode) { if (edge.IsNull() || mode < 0) return; TopoDS_Edge E = edge; if (mode == 1 || mode == 3) E.Reverse(); Add(E, mode / 2); // mode = 0,1 -> 0 mode = 2,3 -> 1 } //================================================================================================= void ShapeExtend_WireData::AddOriented(const TopoDS_Wire& wire, const Standard_Integer mode) { if (wire.IsNull() || mode < 0) return; TopoDS_Wire W = wire; if (mode == 1 || mode == 3) W.Reverse(); Add(W, mode / 2); // mode = 0,1 -> 0 mode = 2,3 -> 1 } void ShapeExtend_WireData::AddOriented(const TopoDS_Shape& shape, const Standard_Integer mode) { if (shape.ShapeType() == TopAbs_EDGE) AddOriented(TopoDS::Edge(shape), mode); else if (shape.ShapeType() == TopAbs_WIRE) AddOriented(TopoDS::Wire(shape), mode); } //================================================================================================= void ShapeExtend_WireData::Remove(const Standard_Integer num) { myEdges->Remove(num > 0 ? num : NbEdges()); mySeamF = -1; } //================================================================================================= void ShapeExtend_WireData::Set(const TopoDS_Edge& edge, const Standard_Integer num) { if (edge.Orientation() != TopAbs_REVERSED && edge.Orientation() != TopAbs_FORWARD && myManifoldMode) { if (num <= myNonmanifoldEdges->Length()) myNonmanifoldEdges->SetValue(num, edge); else myNonmanifoldEdges->Append(edge); } else myEdges->SetValue((num > 0 ? num : NbEdges()), edge); mySeamF = -1; } //======================================================================= // function : Reverse // purpose : reverse order of edges in the wire //======================================================================= void ShapeExtend_WireData::Reverse() { Standard_Integer i, nb = NbEdges(); // inverser les edges + les permuter pour inverser le wire for (i = 1; i <= nb / 2; i++) { TopoDS_Shape S1 = myEdges->Value(i); S1.Reverse(); TopoDS_Shape S2 = myEdges->Value(nb + 1 - i); S2.Reverse(); myEdges->SetValue(i, S2); myEdges->SetValue(nb + 1 - i, S1); } // nb d edges impair : inverser aussi l edge du milieu (rang inchange) if (nb % 2) { // test impair i = (nb + 1) / 2; TopoDS_Shape SI = myEdges->Value(i); SI.Reverse(); myEdges->SetValue(i, SI); } mySeamF = -1; } //================================================================================================= // Fonction auxiliaire SwapSeam pour inverser static void SwapSeam(const TopoDS_Shape& S, const TopoDS_Face& F) { TopoDS_Edge E = TopoDS::Edge(S); if (E.IsNull() || F.IsNull()) return; if (E.Orientation() == TopAbs_REVERSED) return; // ne le faire qu une fois ! TopoDS_Face theface = F; theface.Orientation(TopAbs_FORWARD); //: S4136 Standard_Real Tol = BRep_Tool::Tolerance(theface); Handle(Geom2d_Curve) c2df, c2dr; Standard_Real uff, ulf, ufr, ulr; // d abord FWD puis REV c2df = BRep_Tool::CurveOnSurface(E, theface, uff, ulf); E.Orientation(TopAbs_REVERSED); c2dr = BRep_Tool::CurveOnSurface(E, theface, ufr, ulr); if (c2df.IsNull() || c2dr.IsNull()) return; //: q0 // On permute E.Orientation(TopAbs_FORWARD); BRep_Builder B; B.UpdateEdge(E, c2dr, c2df, theface, 0.); //: S4136: Tol B.Range(E, theface, uff, ulf); } void ShapeExtend_WireData::Reverse(const TopoDS_Face& face) { Reverse(); if (face.IsNull()) return; // ATTENTION aux coutures // Une edge de couture est presente deux fois, FWD et REV // Les inverser revient a permuter leur role ... donc ne rien faire // Il faut donc aussi permuter leurs pcurves ComputeSeams(Standard_True); if (mySeamF > 0) SwapSeam(myEdges->Value(mySeamF), face); if (mySeamR > 0) SwapSeam(myEdges->Value(mySeamR), face); Standard_Integer nb = (mySeams.IsNull() ? 0 : mySeams->Length()); for (Standard_Integer i = 1; i <= nb; i++) { SwapSeam(myEdges->Value(mySeams->Value(i)), face); } mySeamF = -1; } //================================================================================================= Standard_Integer ShapeExtend_WireData::NbEdges() const { return myEdges->Length(); } //================================================================================================= TopoDS_Edge ShapeExtend_WireData::Edge(const Standard_Integer num) const { if (num < 0) { TopoDS_Edge E = Edge(-num); E.Reverse(); return E; } return TopoDS::Edge(myEdges->Value(num)); } //================================================================================================= Standard_Integer ShapeExtend_WireData::NbNonManifoldEdges() const { return myNonmanifoldEdges->Length(); } //================================================================================================= TopoDS_Edge ShapeExtend_WireData::NonmanifoldEdge(const Standard_Integer num) const { TopoDS_Edge E; if (num < 0) return E; return TopoDS::Edge(myNonmanifoldEdges->Value(num)); } //================================================================================================= Standard_Integer ShapeExtend_WireData::Index(const TopoDS_Edge& edge) { for (Standard_Integer i = 1; i <= NbEdges(); i++) if (Edge(i).IsSame(edge) && (Edge(i).Orientation() == edge.Orientation() || !IsSeam(i))) return i; return 0; } //================================================================================================= Standard_Boolean ShapeExtend_WireData::IsSeam(const Standard_Integer num) { if (mySeamF < 0) ComputeSeams(); if (mySeamF == 0) return Standard_False; if (num == mySeamF || num == mySeamR) return Standard_True; // Pas suffisant : on regarde dans la liste Standard_Integer i, nb = mySeams->Length(); for (i = 1; i <= nb; i++) { if (num == mySeams->Value(i)) return Standard_True; } return Standard_False; } //================================================================================================= TopoDS_Wire ShapeExtend_WireData::Wire() const { TopoDS_Wire W; BRep_Builder B; B.MakeWire(W); Standard_Integer i, nb = NbEdges(); Standard_Boolean ismanifold = Standard_True; for (i = 1; i <= nb; i++) { TopoDS_Edge aE = Edge(i); if (aE.Orientation() != TopAbs_FORWARD && aE.Orientation() != TopAbs_REVERSED) ismanifold = Standard_False; B.Add(W, aE); } if (ismanifold) { TopoDS_Vertex vf, vl; TopExp::Vertices(W, vf, vl); if (!vf.IsNull() && !vl.IsNull() && vf.IsSame(vl)) W.Closed(Standard_True); } if (myManifoldMode) { nb = NbNonManifoldEdges(); for (i = 1; i <= nb; i++) B.Add(W, NonmanifoldEdge(i)); } return W; } //================================================================================================= TopoDS_Wire ShapeExtend_WireData::WireAPIMake() const { TopoDS_Wire W; BRepBuilderAPI_MakeWire MW; Standard_Integer i, nb = NbEdges(); for (i = 1; i <= nb; i++) MW.Add(Edge(i)); if (myManifoldMode) { nb = NbNonManifoldEdges(); for (i = 1; i <= nb; i++) MW.Add(NonmanifoldEdge(i)); } if (MW.IsDone()) W = MW.Wire(); return W; } //================================================================================================= Handle(TopTools_HSequenceOfShape) ShapeExtend_WireData::NonmanifoldEdges() const { return myNonmanifoldEdges; } //================================================================================================= Standard_Boolean& ShapeExtend_WireData::ManifoldMode() { return myManifoldMode; }