1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File: BlockFix_UnionFaces.cxx
23 // Created: Tue Dec 7 17:15:42 2004
24 // Author: Pavel DURANDIN
27 #include <BlockFix_UnionFaces.ixx>
29 #include <ShapeAnalysis_WireOrder.hxx>
30 #include <ShapeAnalysis_Edge.hxx>
32 #include <ShapeBuild_Edge.hxx>
33 #include <ShapeBuild_ReShape.hxx>
35 #include <ShapeExtend_WireData.hxx>
36 #include <ShapeExtend_CompositeSurface.hxx>
38 #include <ShapeFix_Face.hxx>
39 #include <ShapeFix_ComposeShell.hxx>
40 #include <ShapeFix_SequenceOfWireSegment.hxx>
41 #include <ShapeFix_WireSegment.hxx>
42 #include <ShapeFix_Wire.hxx>
43 #include <ShapeFix_Edge.hxx>
45 #include <BRep_Tool.hxx>
46 #include <BRep_Builder.hxx>
47 #include <BRepTools.hxx>
50 #include <TopExp_Explorer.hxx>
52 #include <TopTools_SequenceOfShape.hxx>
53 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
54 #include <TopTools_ListOfShape.hxx>
55 #include <TopTools_ListIteratorOfListOfShape.hxx>
56 #include <TopTools_MapOfShape.hxx>
57 #include <TopTools_MapIteratorOfMapOfShape.hxx>
60 #include <TopoDS_Edge.hxx>
61 #include <TopoDS_Wire.hxx>
62 #include <TopoDS_Face.hxx>
63 #include <TopoDS_Solid.hxx>
64 #include <TopoDS_Vertex.hxx>
65 #include <TopoDS_Shell.hxx>
66 #include <TopoDS_Iterator.hxx>
68 #include <TColGeom_HArray2OfSurface.hxx>
70 #include <Geom_Plane.hxx>
71 #include <Geom_OffsetSurface.hxx>
72 #include <Geom_CylindricalSurface.hxx>
73 #include <Geom_SphericalSurface.hxx>
74 #include <Geom_Surface.hxx>
75 #include <Geom_Curve.hxx>
76 #include <Geom_RectangularTrimmedSurface.hxx>
78 #include <Geom2d_Line.hxx>
81 #include <gp_Pnt2d.hxx>
83 //=======================================================================
84 //function : BlockFix_UnionFaces
86 //=======================================================================
88 BlockFix_UnionFaces::BlockFix_UnionFaces()
89 : myTolerance(Precision::Confusion())
94 //=======================================================================
95 //function : GetTolearnce
97 //=======================================================================
99 Standard_Real& BlockFix_UnionFaces::GetTolerance()
105 //=======================================================================
106 //function : AddOrdinaryEdges
108 //=======================================================================
109 // adds edges from the shape to the sequence
110 // seams and equal edges are dropped
111 // Returns true if one of original edges dropped
112 static Standard_Boolean AddOrdinaryEdges(TopTools_SequenceOfShape& edges,
113 const TopoDS_Shape aShape,
114 Standard_Integer& anIndex)
117 TopTools_MapOfShape aNewEdges;
118 //add edges without seams
119 for(TopExp_Explorer exp(aShape,TopAbs_EDGE); exp.More(); exp.Next()) {
120 TopoDS_Shape edge = exp.Current();
121 if(aNewEdges.Contains(edge))
122 aNewEdges.Remove(edge);
127 Standard_Boolean isDropped = Standard_False;
128 //merge edges and drop seams
129 for(Standard_Integer i = 1; i <= edges.Length(); i++) {
130 TopoDS_Shape current = edges(i);
131 if(aNewEdges.Contains(current)) {
133 aNewEdges.Remove(current);
138 isDropped = Standard_True;
144 //add edges to the sequemce
145 for(TopTools_MapIteratorOfMapOfShape anIter(aNewEdges); anIter.More(); anIter.Next())
146 edges.Append(anIter.Key());
152 //=======================================================================
153 //function : ClearRts
155 //=======================================================================
156 static Handle(Geom_Surface) ClearRts(const Handle(Geom_Surface)& aSurface)
158 if(aSurface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
159 Handle(Geom_RectangularTrimmedSurface) rts =
160 Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
161 return rts->BasisSurface();
167 //=======================================================================
170 //=======================================================================
172 TopoDS_Shape BlockFix_UnionFaces::Perform(const TopoDS_Shape& Shape)
174 Handle(ShapeBuild_ReShape) myContext = new ShapeBuild_ReShape;
175 TopoDS_Shape aResShape = myContext->Apply(Shape);
177 // processing each solid
178 TopExp_Explorer exps;
179 for(exps.Init(Shape, TopAbs_SOLID); exps.More(); exps.Next()) {
180 TopoDS_Solid aSolid = TopoDS::Solid(exps.Current());
182 // creating map of edge faces
183 TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
184 TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
186 // map of processed shapes
187 TopTools_MapOfShape aProcessed;
189 Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape;
191 Standard_Integer NbModif=0;
192 Standard_Boolean hasFailed = Standard_False;
193 Standard_Real tol = Min(Max(Precision::Confusion(), myTolerance/10.),0.1);
194 // processing each face
196 //for( exp.Init(Shape, TopAbs_FACE); exp.More(); exp.Next()) {
197 for( exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
198 TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
200 if(aProcessed.Contains(aFace))
203 Standard_Integer dummy;
204 TopTools_SequenceOfShape edges;
205 AddOrdinaryEdges(edges,aFace,dummy);
207 TopTools_SequenceOfShape faces;
210 //surface and location to construct result
211 TopLoc_Location aBaseLocation;
212 Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(aFace,aBaseLocation);
213 aBaseSurface = ClearRts(aBaseSurface);
215 // find adjacent faces to union
217 for( i = 1; i <= edges.Length(); i++) {
218 TopoDS_Edge edge = TopoDS::Edge(edges(i));
219 if(BRep_Tool::Degenerated(edge))
222 const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
223 TopTools_ListIteratorOfListOfShape anIter(aList);
224 for( ; anIter.More(); anIter.Next()) {
225 TopoDS_Face anCheckedFace = TopoDS::Face(anIter.Value().Oriented(TopAbs_FORWARD));
226 if(anCheckedFace.IsSame(aFace))
229 if(aProcessed.Contains(anCheckedFace))
232 if(IsSameDomain(aFace,anCheckedFace)) {
234 if(aList.Extent() != 2) {
235 // non mainfold case is not processed
240 TopoDS_Face aMockUpFace;
242 B.MakeFace(aMockUpFace,aBaseSurface,aBaseLocation,0.);
243 MovePCurves(aMockUpFace,anCheckedFace);
245 if(AddOrdinaryEdges(edges,aMockUpFace,dummy)) {
246 // sequence edges is modified
250 faces.Append(anCheckedFace);
251 aProcessed.Add(anCheckedFace);
257 // all faces collected in the sequence. Perform union of faces
258 if(faces.Length() > 1) {
262 B.MakeFace(aResult,aBaseSurface,aBaseLocation,0);
263 Standard_Integer nbWires = 0;
266 while(edges.Length()>0) {
268 Standard_Boolean isEdge3d = Standard_False;
270 TopTools_MapOfShape aVertices;
274 TopoDS_Edge anEdge = TopoDS::Edge(edges(1));
277 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
280 TopExp::Vertices(anEdge,V1,V2);
284 Standard_Boolean isNewFound = Standard_False;
286 isNewFound = Standard_False;
287 for(Standard_Integer j = 1; j <= edges.Length(); j++) {
288 anEdge = TopoDS::Edge(edges(j));
289 TopExp::Vertices(anEdge,V1,V2);
290 if(aVertices.Contains(V1) || aVertices.Contains(V2)) {
291 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
297 isNewFound = Standard_True;
300 } while (isNewFound);
302 // sorting any type of edges
303 aWire = TopoDS::Wire(aContext->Apply(aWire));
305 TopoDS_Face tmpF = TopoDS::Face(aContext->Apply(faces(1).Oriented(TopAbs_FORWARD)));
306 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(aWire,tmpF,Precision::Confusion());
308 Standard_Boolean isDegRemoved = Standard_False;
309 if(!sfw->StatusReorder ( ShapeExtend_FAIL )) {
310 // clear degenerated edges if at least one with 3d curve exist
312 Handle(ShapeExtend_WireData) sewd = sfw->WireData();
313 for(Standard_Integer j = 1; j<=sewd->NbEdges();j++) {
314 TopoDS_Edge E = sewd->Edge(j);
315 if(BRep_Tool::Degenerated(E)) {
317 isDegRemoved = Standard_True;
324 sfw->FixDegenerated();
326 TopoDS_Wire aWireFixed = sfw->Wire();
327 aContext->Replace(aWire,aWireFixed);
328 // add resulting wire
330 B.Add(aResult,aWireFixed);
334 Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
335 Standard_Integer nbEdges = sbwd->NbEdges();
336 // sort degenerated edges and create one edge instead of several ones
337 ShapeAnalysis_WireOrder sawo(Standard_False, 0);
338 ShapeAnalysis_Edge sae;
339 Standard_Integer aLastEdge = nbEdges;
340 for(Standard_Integer j = 1; j <= nbEdges; j++) {
342 //smh protection on NULL pcurve
343 Handle(Geom2d_Curve) c2d;
344 if(!sae.PCurve(sbwd->Edge(j),tmpF,c2d,f,l)) {
348 sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
352 // constructind one degenerative edge
353 gp_XY aStart, anEnd, tmp;
354 Standard_Integer nbFirst = sawo.Ordered(1);
355 TopoDS_Edge anOrigE = TopoDS::Edge(sbwd->Edge(nbFirst).Oriented(TopAbs_FORWARD));
357 TopoDS_Vertex aDummyV;
358 TopoDS_Edge E = sbe.CopyReplaceVertices(anOrigE,aDummyV,aDummyV);
359 sawo.XY(nbFirst,aStart,tmp);
360 sawo.XY(sawo.Ordered(aLastEdge),tmp,anEnd);
362 gp_XY aVec = anEnd-aStart;
363 Handle(Geom2d_Line) aLine = new Geom2d_Line(aStart,gp_Dir2d(anEnd-aStart));
365 B.UpdateEdge(E,aLine,tmpF,0.);
366 B.Range(E,tmpF,0.,aVec.Modulus());
367 Handle(Geom_Curve) C3d;
368 B.UpdateEdge(E,C3d,0.);
369 B.Degenerated(E,Standard_True);
378 // perform substitution of face
379 aContext->Replace(aContext->Apply(aFace),aResult);
382 ShapeFix_Face sff (aResult);
383 //Intializing by tolerances
384 sff.SetPrecision(myTolerance);
385 sff.SetMinTolerance(tol);
386 sff.SetMaxTolerance(Max(1.,myTolerance*1000.));
388 sff.FixOrientationMode() = 0;
389 //sff.FixWireMode() = 0;
390 sff.SetContext(aContext);
391 // Applying the fixes
393 if(sff.Status(ShapeExtend_FAIL))
394 hasFailed = Standard_True;
396 // breaking down to several faces
397 TopoDS_Shape theResult = aContext->Apply(aResult);
398 for(TopExp_Explorer aFaceExp(theResult,TopAbs_FACE);aFaceExp.More();aFaceExp.Next()) {
399 TopoDS_Face aCurrent = TopoDS::Face(aFaceExp.Current().Oriented(TopAbs_FORWARD));
400 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
401 grid->SetValue ( 1, 1, aBaseSurface );
402 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
403 ShapeFix_ComposeShell CompShell;
404 CompShell.Init ( G, aBaseLocation, aCurrent, ::Precision::Confusion() );//myPrecision
405 CompShell.SetContext( aContext );
407 TopTools_SequenceOfShape parts;
408 ShapeFix_SequenceOfWireSegment wires;
409 for(TopExp_Explorer W_Exp(aCurrent,TopAbs_WIRE);W_Exp.More();W_Exp.Next()) {
410 Handle(ShapeExtend_WireData) sbwd =
411 new ShapeExtend_WireData ( TopoDS::Wire(W_Exp.Current() ));
412 ShapeFix_WireSegment seg ( sbwd, TopAbs_REVERSED );
416 CompShell.DispatchWires ( parts,wires );
417 for (Standard_Integer j=1; j <= parts.Length(); j++ ) {
418 ShapeFix_Face aFixOrient(TopoDS::Face(parts(j)));
419 aFixOrient.SetContext(aContext);
420 aFixOrient.FixOrientation();
423 TopoDS_Shape CompRes;
424 if ( faces.Length() !=1 ) {
427 for ( i=1; i <= parts.Length(); i++ )
428 B.Add ( S, parts(i) );
431 else CompRes = parts(1);
433 aContext->Replace(aCurrent,CompRes);
436 // remove the remaining faces
437 for(i = 2; i <= faces.Length(); i++)
438 aContext->Remove(faces(i));
442 //TopoDS_Shape aResult = Shape;
444 TopoDS_Shape aResult = aSolid;
446 aResult = aContext->Apply(aSolid);
449 for(exp.Init(aResult,TopAbs_EDGE); exp.More(); exp.Next()) {
450 TopoDS_Edge E = TopoDS::Edge(exp.Current());
451 sfe.FixVertexTolerance (E);
452 // ptv add fix same parameter
453 sfe.FixSameParameter(E, myTolerance);
456 myContext->Replace(aSolid,aResult);
460 for( exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
461 TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
462 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
463 sfw->SetContext(myContext);
464 sfw->SetPrecision(myTolerance);
465 sfw->SetMinTolerance(myTolerance);
466 sfw->SetMaxTolerance(Max(1.,myTolerance*1000.));
468 for ( TopoDS_Iterator iter(aFace,Standard_False); iter.More(); iter.Next()) {
469 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
477 } // end processing each solid
479 aResShape = myContext->Apply(Shape);
484 //=======================================================================
485 //function : IsSameDomain
487 //=======================================================================
489 Standard_Boolean BlockFix_UnionFaces::IsSameDomain(const TopoDS_Face& aFace,
490 const TopoDS_Face& aCheckedFace) const
492 //checking the same handless
493 TopLoc_Location L1, L2;
494 Handle(Geom_Surface) S1, S2;
496 S1 = BRep_Tool::Surface(aFace,L1);
497 S2 = BRep_Tool::Surface(aCheckedFace,L2);
499 if (S1 == S2 && L1 == L2)
502 // begin: planar case (improvement 20052)
503 S1 = BRep_Tool::Surface(aFace);
504 S2 = BRep_Tool::Surface(aCheckedFace);
506 Handle(Geom_Plane) aGP1, aGP2;
507 Handle(Geom_RectangularTrimmedSurface) aGRTS1, aGRTS2;
508 Handle(Geom_OffsetSurface) aGOFS1, aGOFS2;
510 aGRTS1 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S1);
511 aGRTS2 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S2);
513 aGOFS1 = Handle(Geom_OffsetSurface)::DownCast(S1);
514 aGOFS2 = Handle(Geom_OffsetSurface)::DownCast(S2);
516 if (!aGOFS1.IsNull()) {
517 aGP1 = Handle(Geom_Plane)::DownCast(aGOFS1->BasisSurface());
519 else if (!aGRTS1.IsNull()) {
520 aGP1 = Handle(Geom_Plane)::DownCast(aGRTS1->BasisSurface());
523 aGP1 = Handle(Geom_Plane)::DownCast(S1);
526 if (!aGOFS2.IsNull()) {
527 aGP2 = Handle(Geom_Plane)::DownCast(aGOFS2->BasisSurface());
529 else if (!aGRTS2.IsNull()) {
530 aGP2 = Handle(Geom_Plane)::DownCast(aGRTS2->BasisSurface());
533 aGP2 = Handle(Geom_Plane)::DownCast(S2);
536 if (!aGP1.IsNull() && !aGP2.IsNull()) {
537 // both surfaces are planar, check equality
538 Standard_Real A1, B1, C1, D1;
539 Standard_Real A2, B2, C2, D2;
540 aGP1->Coefficients(A1, B1, C1, D1);
541 aGP2->Coefficients(A2, B2, C2, D2);
543 if (fabs(A1) > Precision::Confusion()) {
549 else if (fabs(B1) > Precision::Confusion()) {
559 if (fabs(A2) > Precision::Confusion()) {
565 else if (fabs(B2) > Precision::Confusion()) {
575 if (fabs(A1 - A2) < Precision::Confusion() &&
576 fabs(B1 - B2) < Precision::Confusion() &&
577 fabs(C1 - C2) < Precision::Confusion() &&
578 fabs(D1 - D2) < Precision::Confusion())
581 // end: planar case (improvement 20052)
587 //=======================================================================
588 //function : MovePCurves
590 //=======================================================================
592 void BlockFix_UnionFaces::MovePCurves(TopoDS_Face& aTarget,
593 const TopoDS_Face& aSource) const
596 for(TopExp_Explorer wexp(aSource,TopAbs_WIRE);wexp.More();wexp.Next()) {
597 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(TopoDS::Wire(wexp.Current()),
598 aTarget, Precision::Confusion());
600 Standard_Boolean isReoredFailed = sfw->StatusReorder ( ShapeExtend_FAIL );
601 sfw->FixEdgeCurves();
606 sfw->FixDegenerated();
608 // remove degenerated edges from not degenerated points
609 ShapeAnalysis_Edge sae;
610 Handle(ShapeExtend_WireData) sewd = sfw->WireData();
611 for(Standard_Integer i = 1; i<=sewd->NbEdges();i++) {
612 TopoDS_Edge E = sewd->Edge(i);
613 if(BRep_Tool::Degenerated(E)&&!sae.HasPCurve(E,aTarget)) {
619 TopoDS_Wire ResWire = sfw->Wire();
620 B.Add(aTarget,ResWire);