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
26 #include <BlockFix_UnionFaces.ixx>
28 #include <ShapeAnalysis_WireOrder.hxx>
29 #include <ShapeAnalysis_Edge.hxx>
31 #include <ShapeBuild_Edge.hxx>
32 #include <ShapeBuild_ReShape.hxx>
34 #include <ShapeExtend_WireData.hxx>
35 #include <ShapeExtend_CompositeSurface.hxx>
37 #include <ShapeFix_Face.hxx>
38 #include <ShapeFix_ComposeShell.hxx>
39 #include <ShapeFix_SequenceOfWireSegment.hxx>
40 #include <ShapeFix_WireSegment.hxx>
41 #include <ShapeFix_Wire.hxx>
42 #include <ShapeFix_Edge.hxx>
44 #include <BRep_Tool.hxx>
45 #include <BRep_Builder.hxx>
46 #include <BRepTools.hxx>
49 #include <TopExp_Explorer.hxx>
51 #include <TopTools_SequenceOfShape.hxx>
52 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
53 #include <TopTools_ListOfShape.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
55 #include <TopTools_MapOfShape.hxx>
56 #include <TopTools_MapIteratorOfMapOfShape.hxx>
59 #include <TopoDS_Edge.hxx>
60 #include <TopoDS_Wire.hxx>
61 #include <TopoDS_Face.hxx>
62 #include <TopoDS_Solid.hxx>
63 #include <TopoDS_Vertex.hxx>
64 #include <TopoDS_Shell.hxx>
65 #include <TopoDS_Iterator.hxx>
67 #include <TColGeom_HArray2OfSurface.hxx>
69 #include <Geom_Plane.hxx>
70 #include <Geom_OffsetSurface.hxx>
71 #include <Geom_CylindricalSurface.hxx>
72 #include <Geom_SphericalSurface.hxx>
73 #include <Geom_Surface.hxx>
74 #include <Geom_Curve.hxx>
75 #include <Geom_RectangularTrimmedSurface.hxx>
77 #include <Geom2d_Line.hxx>
80 #include <gp_Pnt2d.hxx>
82 //=======================================================================
83 //function : BlockFix_UnionFaces
85 //=======================================================================
87 BlockFix_UnionFaces::BlockFix_UnionFaces()
88 : myTolerance(Precision::Confusion()),
94 //=======================================================================
95 //function : GetTolerance
97 //=======================================================================
99 Standard_Real& BlockFix_UnionFaces::GetTolerance()
105 //=======================================================================
106 //function : GetOptimumNbFaces
108 //=======================================================================
110 Standard_Integer& BlockFix_UnionFaces::GetOptimumNbFaces()
112 return myOptimumNbFaces;
116 //=======================================================================
117 //function : AddOrdinaryEdges
119 //=======================================================================
120 // adds edges from the shape to the sequence
121 // seams and equal edges are dropped
122 // Returns true if one of original edges dropped
123 static Standard_Boolean AddOrdinaryEdges(TopTools_SequenceOfShape& edges,
124 const TopoDS_Shape aShape,
125 Standard_Integer& anIndex)
128 TopTools_MapOfShape aNewEdges;
129 //add edges without seams
130 for(TopExp_Explorer exp(aShape,TopAbs_EDGE); exp.More(); exp.Next()) {
131 TopoDS_Shape edge = exp.Current();
132 if(aNewEdges.Contains(edge))
133 aNewEdges.Remove(edge);
138 Standard_Boolean isDropped = Standard_False;
139 //merge edges and drop seams
140 for(Standard_Integer i = 1; i <= edges.Length(); i++) {
141 TopoDS_Shape current = edges(i);
142 if(aNewEdges.Contains(current)) {
144 aNewEdges.Remove(current);
149 isDropped = Standard_True;
155 //add edges to the sequemce
156 for(TopTools_MapIteratorOfMapOfShape anIter(aNewEdges); anIter.More(); anIter.Next())
157 edges.Append(anIter.Key());
163 //=======================================================================
164 //function : ClearRts
166 //=======================================================================
167 static Handle(Geom_Surface) ClearRts(const Handle(Geom_Surface)& aSurface)
169 if(aSurface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
170 Handle(Geom_RectangularTrimmedSurface) rts =
171 Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
172 return rts->BasisSurface();
178 //=======================================================================
181 //=======================================================================
183 TopoDS_Shape BlockFix_UnionFaces::Perform(const TopoDS_Shape& Shape)
185 Handle(ShapeBuild_ReShape) myContext = new ShapeBuild_ReShape;
186 TopoDS_Shape aResShape = myContext->Apply(Shape);
188 // processing each solid
189 TopExp_Explorer exps;
190 for (exps.Init(Shape, TopAbs_SOLID); exps.More(); exps.Next()) {
191 TopoDS_Solid aSolid = TopoDS::Solid(exps.Current());
193 // creating map of edge faces
194 TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
195 TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
197 // map of processed shapes
198 TopTools_MapOfShape aProcessed;
200 Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape;
202 Standard_Integer NbModif = 0;
203 Standard_Boolean hasFailed = Standard_False;
204 Standard_Real tol = Min(Max(Precision::Confusion(), myTolerance/10.), 0.1);
209 TopTools_MapOfShape mapF;
210 for (exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
211 if (mapF.Add(exp.Current()))
215 bool doUnion = ((myOptimumNbFaces == 0) ||
216 ((myOptimumNbFaces > 0) && (nbf > myOptimumNbFaces)));
218 // processing each face
220 for (exp.Init(aSolid, TopAbs_FACE); exp.More() && doUnion; exp.Next()) {
221 TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
223 if (aProcessed.Contains(aFace))
226 Standard_Integer dummy;
227 TopTools_SequenceOfShape edges;
228 AddOrdinaryEdges(edges,aFace,dummy);
230 TopTools_SequenceOfShape faces;
233 //surface and location to construct result
234 TopLoc_Location aBaseLocation;
235 Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(aFace,aBaseLocation);
236 aBaseSurface = ClearRts(aBaseSurface);
238 // find adjacent faces to union
240 for (i = 1; i <= edges.Length(); i++) {
241 TopoDS_Edge edge = TopoDS::Edge(edges(i));
242 if (BRep_Tool::Degenerated(edge))
245 const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
246 TopTools_ListIteratorOfListOfShape anIter(aList);
247 for (; anIter.More(); anIter.Next()) {
248 TopoDS_Face anCheckedFace = TopoDS::Face(anIter.Value().Oriented(TopAbs_FORWARD));
249 if (anCheckedFace.IsSame(aFace))
252 if (aProcessed.Contains(anCheckedFace))
255 if (IsSameDomain(aFace,anCheckedFace)) {
257 if (aList.Extent() != 2) {
258 // non mainfold case is not processed
263 TopoDS_Face aMockUpFace;
265 B.MakeFace(aMockUpFace,aBaseSurface,aBaseLocation,0.);
266 MovePCurves(aMockUpFace,anCheckedFace);
268 if (AddOrdinaryEdges(edges,aMockUpFace,dummy)) {
269 // sequence edges is modified
273 faces.Append(anCheckedFace);
274 aProcessed.Add(anCheckedFace);
280 // all faces collected in the sequence. Perform union of faces
281 if (faces.Length() > 1) {
285 B.MakeFace(aResult,aBaseSurface,aBaseLocation,0);
286 Standard_Integer nbWires = 0;
289 while (edges.Length()>0) {
291 Standard_Boolean isEdge3d = Standard_False;
293 TopTools_MapOfShape aVertices;
297 TopoDS_Edge anEdge = TopoDS::Edge(edges(1));
300 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
303 TopExp::Vertices(anEdge,V1,V2);
307 Standard_Boolean isNewFound = Standard_False;
309 isNewFound = Standard_False;
310 for(Standard_Integer j = 1; j <= edges.Length(); j++) {
311 anEdge = TopoDS::Edge(edges(j));
312 TopExp::Vertices(anEdge,V1,V2);
313 if(aVertices.Contains(V1) || aVertices.Contains(V2)) {
314 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
320 isNewFound = Standard_True;
323 } while (isNewFound);
325 // sorting any type of edges
326 aWire = TopoDS::Wire(aContext->Apply(aWire));
328 TopoDS_Face tmpF = TopoDS::Face(aContext->Apply(faces(1).Oriented(TopAbs_FORWARD)));
329 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(aWire,tmpF,Precision::Confusion());
331 Standard_Boolean isDegRemoved = Standard_False;
332 if(!sfw->StatusReorder ( ShapeExtend_FAIL )) {
333 // clear degenerated edges if at least one with 3d curve exist
335 Handle(ShapeExtend_WireData) sewd = sfw->WireData();
336 for(Standard_Integer j = 1; j<=sewd->NbEdges();j++) {
337 TopoDS_Edge E = sewd->Edge(j);
338 if(BRep_Tool::Degenerated(E)) {
340 isDegRemoved = Standard_True;
347 sfw->FixDegenerated();
349 TopoDS_Wire aWireFixed = sfw->Wire();
350 aContext->Replace(aWire,aWireFixed);
351 // add resulting wire
353 B.Add(aResult,aWireFixed);
357 Handle(ShapeExtend_WireData) sbwd = sfw->WireData();
358 Standard_Integer nbEdges = sbwd->NbEdges();
359 // sort degenerated edges and create one edge instead of several ones
360 ShapeAnalysis_WireOrder sawo(Standard_False, 0);
361 ShapeAnalysis_Edge sae;
362 Standard_Integer aLastEdge = nbEdges;
363 for(Standard_Integer j = 1; j <= nbEdges; j++) {
365 //smh protection on NULL pcurve
366 Handle(Geom2d_Curve) c2d;
367 if(!sae.PCurve(sbwd->Edge(j),tmpF,c2d,f,l)) {
371 sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
375 // constructind one degenerative edge
376 gp_XY aStart, anEnd, tmp;
377 Standard_Integer nbFirst = sawo.Ordered(1);
378 TopoDS_Edge anOrigE = TopoDS::Edge(sbwd->Edge(nbFirst).Oriented(TopAbs_FORWARD));
380 TopoDS_Vertex aDummyV;
381 TopoDS_Edge E = sbe.CopyReplaceVertices(anOrigE,aDummyV,aDummyV);
382 sawo.XY(nbFirst,aStart,tmp);
383 sawo.XY(sawo.Ordered(aLastEdge),tmp,anEnd);
385 gp_XY aVec = anEnd-aStart;
386 Handle(Geom2d_Line) aLine = new Geom2d_Line(aStart,gp_Dir2d(anEnd-aStart));
388 B.UpdateEdge(E,aLine,tmpF,0.);
389 B.Range(E,tmpF,0.,aVec.Modulus());
390 Handle(Geom_Curve) C3d;
391 B.UpdateEdge(E,C3d,0.);
392 B.Degenerated(E,Standard_True);
400 // perform substitution of face
401 aContext->Replace(aContext->Apply(aFace),aResult);
403 ShapeFix_Face sff (aResult);
404 //Intializing by tolerances
405 sff.SetPrecision(myTolerance);
406 sff.SetMinTolerance(tol);
407 sff.SetMaxTolerance(Max(1.,myTolerance*1000.));
409 sff.FixOrientationMode() = 0;
410 //sff.FixWireMode() = 0;
411 sff.SetContext(aContext);
412 // Applying the fixes
414 if(sff.Status(ShapeExtend_FAIL))
415 hasFailed = Standard_True;
417 // breaking down to several faces
418 TopoDS_Shape theResult = aContext->Apply(aResult);
419 for (TopExp_Explorer aFaceExp (theResult,TopAbs_FACE); aFaceExp.More(); aFaceExp.Next()) {
420 TopoDS_Face aCurrent = TopoDS::Face(aFaceExp.Current().Oriented(TopAbs_FORWARD));
421 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
422 grid->SetValue ( 1, 1, aBaseSurface );
423 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
424 ShapeFix_ComposeShell CompShell;
425 CompShell.Init ( G, aBaseLocation, aCurrent, ::Precision::Confusion() );//myPrecision
426 CompShell.SetContext( aContext );
428 TopTools_SequenceOfShape parts;
429 ShapeFix_SequenceOfWireSegment wires;
430 for(TopExp_Explorer W_Exp(aCurrent,TopAbs_WIRE);W_Exp.More();W_Exp.Next()) {
431 Handle(ShapeExtend_WireData) sbwd =
432 new ShapeExtend_WireData ( TopoDS::Wire(W_Exp.Current() ));
433 ShapeFix_WireSegment seg ( sbwd, TopAbs_REVERSED );
437 CompShell.DispatchWires ( parts,wires );
438 for (Standard_Integer j=1; j <= parts.Length(); j++ ) {
439 ShapeFix_Face aFixOrient(TopoDS::Face(parts(j)));
440 aFixOrient.SetContext(aContext);
441 aFixOrient.FixOrientation();
444 TopoDS_Shape CompRes;
445 if ( faces.Length() !=1 ) {
448 for ( i=1; i <= parts.Length(); i++ )
449 B.Add ( S, parts(i) );
452 else CompRes = parts(1);
454 aContext->Replace(aCurrent,CompRes);
457 // remove the remaining faces
458 for(i = 2; i <= faces.Length(); i++)
459 aContext->Remove(faces(i));
461 } // end processing each face
463 //TopoDS_Shape aResult = Shape;
464 if (NbModif > 0 && !hasFailed) {
465 TopoDS_Shape aResult = aContext->Apply(aSolid);
468 for (exp.Init(aResult,TopAbs_EDGE); exp.More(); exp.Next()) {
469 TopoDS_Edge E = TopoDS::Edge(exp.Current());
470 sfe.FixVertexTolerance (E);
471 // ptv add fix same parameter
472 sfe.FixSameParameter(E, myTolerance);
475 myContext->Replace(aSolid, aResult);
479 for (exp.Init(aSolid, TopAbs_FACE); exp.More(); exp.Next()) {
480 TopoDS_Face aFace = TopoDS::Face(exp.Current().Oriented(TopAbs_FORWARD));
481 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
482 sfw->SetContext(myContext);
483 sfw->SetPrecision(myTolerance);
484 sfw->SetMinTolerance(myTolerance);
485 sfw->SetMaxTolerance(Max(1.,myTolerance*1000.));
487 for (TopoDS_Iterator iter (aFace,Standard_False); iter.More(); iter.Next()) {
488 TopoDS_Wire wire = TopoDS::Wire(iter.Value());
495 } // end processing each solid
497 aResShape = myContext->Apply(Shape);
502 //=======================================================================
503 //function : IsSameDomain
505 //=======================================================================
507 Standard_Boolean BlockFix_UnionFaces::IsSameDomain(const TopoDS_Face& aFace,
508 const TopoDS_Face& aCheckedFace) const
510 //checking the same handless
511 TopLoc_Location L1, L2;
512 Handle(Geom_Surface) S1, S2;
514 S1 = BRep_Tool::Surface(aFace,L1);
515 S2 = BRep_Tool::Surface(aCheckedFace,L2);
517 if (S1 == S2 && L1 == L2)
520 // begin: planar case (improvement 20052)
521 S1 = BRep_Tool::Surface(aFace);
522 S2 = BRep_Tool::Surface(aCheckedFace);
524 Handle(Geom_Plane) aGP1, aGP2;
525 Handle(Geom_RectangularTrimmedSurface) aGRTS1, aGRTS2;
526 Handle(Geom_OffsetSurface) aGOFS1, aGOFS2;
528 aGRTS1 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S1);
529 aGRTS2 = Handle(Geom_RectangularTrimmedSurface)::DownCast(S2);
531 aGOFS1 = Handle(Geom_OffsetSurface)::DownCast(S1);
532 aGOFS2 = Handle(Geom_OffsetSurface)::DownCast(S2);
534 if (!aGOFS1.IsNull()) {
535 aGP1 = Handle(Geom_Plane)::DownCast(aGOFS1->BasisSurface());
537 else if (!aGRTS1.IsNull()) {
538 aGP1 = Handle(Geom_Plane)::DownCast(aGRTS1->BasisSurface());
541 aGP1 = Handle(Geom_Plane)::DownCast(S1);
544 if (!aGOFS2.IsNull()) {
545 aGP2 = Handle(Geom_Plane)::DownCast(aGOFS2->BasisSurface());
547 else if (!aGRTS2.IsNull()) {
548 aGP2 = Handle(Geom_Plane)::DownCast(aGRTS2->BasisSurface());
551 aGP2 = Handle(Geom_Plane)::DownCast(S2);
554 if (!aGP1.IsNull() && !aGP2.IsNull()) {
555 // both surfaces are planar, check equality
556 Standard_Real A1, B1, C1, D1;
557 Standard_Real A2, B2, C2, D2;
558 aGP1->Coefficients(A1, B1, C1, D1);
559 aGP2->Coefficients(A2, B2, C2, D2);
561 if (fabs(A1) > Precision::Confusion()) {
567 else if (fabs(B1) > Precision::Confusion()) {
577 if (fabs(A2) > Precision::Confusion()) {
583 else if (fabs(B2) > Precision::Confusion()) {
593 if (fabs(A1 - A2) < Precision::Confusion() &&
594 fabs(B1 - B2) < Precision::Confusion() &&
595 fabs(C1 - C2) < Precision::Confusion() &&
596 fabs(D1 - D2) < Precision::Confusion())
599 // end: planar case (improvement 20052)
605 //=======================================================================
606 //function : MovePCurves
608 //=======================================================================
610 void BlockFix_UnionFaces::MovePCurves(TopoDS_Face& aTarget,
611 const TopoDS_Face& aSource) const
614 for(TopExp_Explorer wexp(aSource,TopAbs_WIRE);wexp.More();wexp.Next()) {
615 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(TopoDS::Wire(wexp.Current()),
616 aTarget, Precision::Confusion());
618 Standard_Boolean isReoredFailed = sfw->StatusReorder ( ShapeExtend_FAIL );
619 sfw->FixEdgeCurves();
624 sfw->FixDegenerated();
626 // remove degenerated edges from not degenerated points
627 ShapeAnalysis_Edge sae;
628 Handle(ShapeExtend_WireData) sewd = sfw->WireData();
629 for(Standard_Integer i = 1; i<=sewd->NbEdges();i++) {
630 TopoDS_Edge E = sewd->Edge(i);
631 if(BRep_Tool::Degenerated(E)&&!sae.HasPCurve(E,aTarget)) {
637 TopoDS_Wire ResWire = sfw->Wire();
638 B.Add(aTarget,ResWire);