1 // Created on: 1995-05-30
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
18 #include <Bnd_Box.hxx>
19 #include <BRep_Builder.hxx>
20 #include <BRep_Tool.hxx>
21 #include <BRepBndLib.hxx>
22 #include <BRepFeat_MakeCylindricalHole.hxx>
23 #include <BRepPrim_Cylinder.hxx>
24 #include <BRepTools.hxx>
26 #include <Geom_Curve.hxx>
28 #include <LocOpe_CurveShapeIntersector.hxx>
29 #include <LocOpe_PntFace.hxx>
30 #include <Precision.hxx>
31 #include <Standard_ConstructionError.hxx>
32 #include <StdFail_NotDone.hxx>
33 #include <TopExp_Explorer.hxx>
34 #include <TopLoc_Location.hxx>
36 #include <TopoDS_Shape.hxx>
37 #include <TopoDS_Solid.hxx>
38 #include <TopTools_ListIteratorOfListOfShape.hxx>
39 #include <TopTools_ListOfShape.hxx>
40 #include <BRepAdaptor_Surface.hxx>
43 static void Baryc(const TopoDS_Shape&,
46 static void BoxParameters(const TopoDS_Shape&,
51 static Standard_Boolean GetOffset(const LocOpe_PntFace& PntInfo,
52 const Standard_Real Radius,
54 Standard_Real& outOff );
56 static void CreateCyl(const LocOpe_PntFace& PntInfoFirst, const LocOpe_PntFace& PntInfoLast, const Standard_Real Radius,
57 const gp_Ax1& Axis, TopoDS_Shell& Cyl, TopoDS_Face& CylTopF, TopoDS_Face& CylBottF );
60 //=======================================================================
63 //=======================================================================
65 void BRepFeat_MakeCylindricalHole::Perform(const Standard_Real Radius)
67 const TopoDS_Shape& aObject=myArguments.First();
68 if (aObject.IsNull() || !myAxDef) {
69 Standard_ConstructionError::Raise();
72 myIsBlind = Standard_False;
73 myStatus = BRepFeat_NoError;
75 LocOpe_CurveShapeIntersector theASI(myAxis,aObject);
76 if (!theASI.IsDone() || theASI.NbPoints() <= 0) {
77 myStatus = BRepFeat_InvalidPlacement;
81 // It is not possible to use infinite cylinder for topological operations.
82 Standard_Real PMin,PMax;
83 BoxParameters(aObject,myAxis,PMin,PMax);
84 Standard_Real Heigth = 2.*(PMax-PMin);
85 gp_XYZ theOrig = myAxis.Location().XYZ();
86 theOrig += ((3.*PMin-PMax)/2.) * myAxis.Direction().XYZ();
87 gp_Pnt p1_ao1(theOrig); gp_Ax2 a1_ao1(p1_ao1,myAxis.Direction());
88 BRepPrim_Cylinder theCylinder(a1_ao1,
92 // Probably it is better to make cut directly
97 B.Add(theTool,theCylinder.Shell());
99 myTopFace = theCylinder.TopFace();
100 myBotFace = theCylinder.BottomFace();
101 myValidate = Standard_False;
103 // BRepTools::Dump(theTool,cout);
104 Standard_Boolean Fuse = Standard_False;
108 BOPAlgo_BOP::Perform();
112 //=======================================================================
113 //function : PerformThruNext
115 //=======================================================================
117 void BRepFeat_MakeCylindricalHole::PerformThruNext(const Standard_Real Radius,
118 const Standard_Boolean Cont)
121 const TopoDS_Shape& aObject=myArguments.First();
122 if (aObject.IsNull() || !myAxDef) {
123 Standard_ConstructionError::Raise();
126 myIsBlind = Standard_False;
128 myStatus = BRepFeat_NoError;
130 LocOpe_CurveShapeIntersector theASI(myAxis,aObject);
131 if (!theASI.IsDone()) {
132 myStatus = BRepFeat_InvalidPlacement;
136 Standard_Integer IndFrom,IndTo;
137 TopAbs_Orientation theOr;
138 LocOpe_PntFace PntInfoFirst, PntInfoLast;
139 Standard_Boolean ok = theASI.LocalizeAfter(0.,theOr,IndFrom,IndTo);
141 if (theOr == TopAbs_FORWARD) {
142 PntInfoFirst = theASI.Point(IndFrom);
143 ok = theASI.LocalizeAfter(IndTo,theOr,IndFrom,IndTo);
145 if (theOr != TopAbs_REVERSED) {
149 PntInfoLast = theASI.Point(IndTo);
154 else { // TopAbs_REVERSED
155 PntInfoLast = theASI.Point(IndTo);
156 ok = theASI.LocalizeBefore(IndFrom,theOr,IndFrom,IndTo);
158 if (theOr != TopAbs_FORWARD) {
162 PntInfoFirst = theASI.Point(IndFrom);
168 myStatus = BRepFeat_InvalidPlacement;
173 CreateCyl(PntInfoFirst, PntInfoLast, Radius, myAxis, Cyl, myTopFace, myBotFace);
176 TopoDS_Solid theTool;
177 B.MakeSolid(theTool);
180 Standard_Boolean Fuse = Standard_False;
183 BOPAlgo_BOP::Perform();
184 TopTools_ListOfShape parts;
187 Standard_Integer nbparts = 0;
188 TopTools_ListIteratorOfListOfShape its(parts);
189 for (; its.More(); its.Next()) {
193 myStatus = BRepFeat_InvalidPlacement;
197 if (nbparts >= 2) { // preserve the smallest as parameter
200 Standard_Real First=PntInfoFirst.Parameter();
201 Standard_Real Last=PntInfoLast.Parameter();
203 Standard_Real parbar,parmin = Last;
205 for (its.Initialize(parts); its.More(); its.Next()) {
206 Baryc(its.Value(),Barycentre);
207 parbar = ElCLib::LineParameter(myAxis,Barycentre);
208 if (parbar >= First && parbar <= Last && parbar <= parmin) {
210 tokeep = its.Value();
214 if (tokeep.IsNull()) { // preserve the closest interval
216 Standard_Real dmin = RealLast();
217 for (its.Initialize(parts); its.More(); its.Next()) {
218 Baryc(its.Value(),Barycentre);
219 parbar = ElCLib::LineParameter(myAxis,Barycentre);
220 if (parbar < First) {
221 if (First - parbar < dmin ) {
223 tokeep = its.Value();
225 else { // parbar > Last
226 if (parbar - Last < dmin) {
228 tokeep = its.Value();
234 for (its.Initialize(parts); its.More(); its.Next()) {
235 if (tokeep.IsSame(its.Value())) {
236 KeepPart(its.Value());
243 //=======================================================================
244 //function : PerformUntilEnd
246 //=======================================================================
248 void BRepFeat_MakeCylindricalHole::PerformUntilEnd(const Standard_Real Radius,
249 const Standard_Boolean Cont)
252 const TopoDS_Shape& aObject=myArguments.First();
253 if (aObject.IsNull() || !myAxDef) {
254 Standard_ConstructionError::Raise();
257 myIsBlind = Standard_False;
259 myStatus = BRepFeat_NoError;
261 LocOpe_CurveShapeIntersector theASI(myAxis,aObject);
262 if (!theASI.IsDone()) {
263 myStatus = BRepFeat_InvalidPlacement;
267 Standard_Integer IndFrom,IndTo;
268 TopAbs_Orientation theOr;
269 Standard_Boolean ok = theASI.LocalizeAfter(0.,theOr,IndFrom,IndTo);
270 LocOpe_PntFace PntInfoFirst, PntInfoLast;
273 if (theOr == TopAbs_REVERSED) {
274 ok = theASI.LocalizeBefore(IndFrom,theOr,IndFrom,IndTo); // on reset
275 // It is possible to search for the next.
277 if ( ok && theOr == TopAbs_FORWARD) {
278 PntInfoFirst = theASI.Point(IndFrom);
279 ok = theASI.LocalizeBefore(theASI.NbPoints()+1,theOr,IndFrom,IndTo);
281 if (theOr != TopAbs_REVERSED) {
285 PntInfoLast = theASI.Point(IndTo);
291 myStatus = BRepFeat_InvalidPlacement;
296 CreateCyl(PntInfoFirst, PntInfoLast, Radius, myAxis, Cyl, myTopFace, myBotFace);
299 TopoDS_Solid theTool;
300 B.MakeSolid(theTool);
303 Standard_Boolean Fuse = Standard_False;
306 BOPAlgo_BOP::Perform();
307 TopTools_ListOfShape parts;
310 Standard_Integer nbparts = 0;
311 TopTools_ListIteratorOfListOfShape its(parts);
312 for (; its.More(); its.Next()) {
316 myStatus = BRepFeat_InvalidPlacement;
320 if (nbparts >= 2) { // preserve everything above the First
321 Standard_Real parbar;
323 for (its.Initialize(parts); its.More(); its.Next()) {
324 Baryc(its.Value(),Barycentre);
325 parbar = ElCLib::LineParameter(myAxis,Barycentre);
326 if (parbar > PntInfoFirst.Parameter()) {
327 KeepPart(its.Value());
334 //=======================================================================
337 //=======================================================================
339 void BRepFeat_MakeCylindricalHole::Perform(const Standard_Real Radius,
340 const Standard_Real PFrom,
341 const Standard_Real PTo,
342 const Standard_Boolean Cont)
345 const TopoDS_Shape& aObject=myArguments.First();
346 if (aObject.IsNull() || !myAxDef) {
347 Standard_ConstructionError::Raise();
350 myIsBlind = Standard_False;
352 myStatus = BRepFeat_NoError;
354 LocOpe_CurveShapeIntersector theASI(myAxis,aObject);
355 if (!theASI.IsDone()) {
356 myStatus = BRepFeat_InvalidPlacement;
360 Standard_Real thePFrom,thePTo;
370 //Standard_Real First=0,Last=0,prm;
371 LocOpe_PntFace PntInfoFirst, PntInfoLast;
372 Standard_Integer IndFrom,IndTo;
373 TopAbs_Orientation theOr;
374 Standard_Boolean ok = theASI.LocalizeAfter(thePFrom,theOr,IndFrom,IndTo);
376 if (theOr == TopAbs_REVERSED) {
377 ok = theASI.LocalizeBefore(IndFrom,theOr,IndFrom,IndTo); // reset
378 // It is possible to find the next.
380 if ( ok && theOr == TopAbs_FORWARD) {
381 PntInfoFirst = theASI.Point(IndFrom);
382 ok = theASI.LocalizeBefore(thePTo,theOr,IndFrom,IndTo);
384 if (theOr == TopAbs_FORWARD) {
385 ok = theASI.LocalizeAfter(IndTo,theOr,IndFrom,IndTo);
387 if (ok && theOr == TopAbs_REVERSED) {
388 PntInfoLast = theASI.Point(IndTo);
395 myStatus = BRepFeat_InvalidPlacement;
400 CreateCyl(PntInfoFirst, PntInfoLast, Radius, myAxis, Cyl, myTopFace, myBotFace);
403 TopoDS_Solid theTool;
404 B.MakeSolid(theTool);
407 Standard_Boolean Fuse = Standard_False;
410 BOPAlgo_BOP::Perform();
411 TopTools_ListOfShape parts;
414 Standard_Integer nbparts = 0;
415 TopTools_ListIteratorOfListOfShape its(parts);
416 for (; its.More(); its.Next()) {
420 myStatus = BRepFeat_InvalidPlacement;
424 if (nbparts >= 2) { // preserve parts between First and Last
427 Standard_Real parbar;
429 for (its.Initialize(parts); its.More(); its.Next()) {
430 Baryc(its.Value(),Barycentre);
431 parbar = ElCLib::LineParameter(myAxis,Barycentre);
432 if (!(parbar < PntInfoFirst.Parameter() || parbar > PntInfoLast.Parameter())) {
433 KeepPart(its.Value());
440 //=======================================================================
441 //function : PerformBlind
443 //=======================================================================
445 void BRepFeat_MakeCylindricalHole::PerformBlind(const Standard_Real Radius,
446 const Standard_Real Length,
447 const Standard_Boolean Cont)
450 const TopoDS_Shape& aObject=myArguments.First();
451 if (aObject.IsNull() || !myAxDef || Length <= 0.) {
452 Standard_ConstructionError::Raise();
455 myIsBlind = Standard_True;
457 myStatus = BRepFeat_NoError;
459 LocOpe_CurveShapeIntersector theASI(myAxis,aObject);
460 if (!theASI.IsDone()) {
461 myStatus = BRepFeat_InvalidPlacement;
466 Standard_Integer IndFrom,IndTo;
467 TopAbs_Orientation theOr;
468 Standard_Boolean ok = theASI.LocalizeAfter(0.,theOr,IndFrom,IndTo);
471 if (theOr == TopAbs_REVERSED) {
472 ok = theASI.LocalizeBefore(IndFrom,theOr,IndFrom,IndTo); // reset
473 // it is possible to find the next
475 ok = ok && theOr == TopAbs_FORWARD;
478 myStatus = BRepFeat_InvalidPlacement;
482 // check a priori the length of the hole
483 Standard_Integer IFNext,ITNext;
484 ok = theASI.LocalizeAfter(IndTo,theOr,IFNext,ITNext);
486 myStatus = BRepFeat_InvalidPlacement;
489 if (theASI.Point(IFNext).Parameter() <= Length) {
490 myStatus = BRepFeat_HoleTooLong;
494 TopTools_ListOfShape theList;
496 // version for advanced control
497 for (Standard_Integer i=IndFrom; i<= ITNext; i++) {
498 theList.Append(theASI.Point(i).Face());
501 First = theASI.Point(IndFrom).Parameter();
503 //// It is not possible to use infinite cylinder for topological operations.
504 Standard_Real PMin,PMax;
505 BoxParameters(aObject,myAxis,PMin,PMax);
507 myStatus = BRepFeat_InvalidPlacement;
511 Standard_Real Heigth = 3.*(Length-PMin)/2.;
512 gp_XYZ theOrig = myAxis.Location().XYZ();
513 theOrig += ((3.*PMin-Length)/2.) * myAxis.Direction().XYZ();
514 gp_Pnt p5_ao1(theOrig); gp_Ax2 a5_ao1(p5_ao1,myAxis.Direction());
515 BRepPrim_Cylinder theCylinder(a5_ao1,
520 TopoDS_Solid theTool;
521 B.MakeSolid(theTool);
522 B.Add(theTool,theCylinder.Shell());
524 myTopFace = theCylinder.TopFace();
527 // BRepTools::Dump(theTool,cout);
528 Standard_Boolean Fuse = Standard_False;
529 //myBuilder.Perform(theTool,theList,Fuse);
530 //myBuilder.BuildPartsOfTool();
533 BOPAlgo_BOP::Perform();
534 TopTools_ListOfShape parts;
537 Standard_Integer nbparts = 0;
538 TopTools_ListIteratorOfListOfShape its(parts);
539 for (; its.More(); its.Next()) {
543 myStatus = BRepFeat_InvalidPlacement;
547 if (nbparts >= 2) { // preserve the smallest as parameter along the axis
549 Standard_Real parbar,parmin = RealLast();
551 for (its.Initialize(parts); its.More(); its.Next()) {
552 Baryc(its.Value(),Barycentre);
553 parbar = ElCLib::LineParameter(myAxis,Barycentre);
554 if (parbar >= First && parbar <= parmin) {
556 tokeep = its.Value();
560 if (tokeep.IsNull()) { // preserve the closest interval
562 Standard_Real dmin = RealLast();
563 for (its.Initialize(parts); its.More(); its.Next()) {
564 Baryc(its.Value(),Barycentre);
565 parbar = ElCLib::LineParameter(myAxis,Barycentre);
566 if (Abs(First - parbar) < dmin ) {
567 dmin = Abs(First-parbar);
568 tokeep = its.Value();
572 for (its.Initialize(parts); its.More(); its.Next()) {
573 if (tokeep.IsSame(its.Value())) {
574 KeepPart(its.Value());
581 //=======================================================================
584 //=======================================================================
586 void BRepFeat_MakeCylindricalHole::Build ()
588 if (myStatus == BRepFeat_NoError) {
590 if (!ErrorStatus()) {
591 myStatus = (myValidate) ? Validate() : BRepFeat_NoError;
592 if (myStatus == BRepFeat_NoError) {
597 myStatus = BRepFeat_InvalidPlacement; // why not
603 //=======================================================================
604 //function : Validate
606 //=======================================================================
608 BRepFeat_Status BRepFeat_MakeCylindricalHole::Validate ()
610 BRepFeat_Status thestat = BRepFeat_NoError;
611 TopExp_Explorer ex(Shape(),TopAbs_FACE);
612 if (myIsBlind) { // limit of the hole
613 for (; ex.More(); ex.Next()) {
614 if (ex.Current().IsSame(myTopFace) ) {
619 thestat = BRepFeat_HoleTooLong;
623 for (; ex.More(); ex.Next()) {
624 if (ex.Current().IsSame(myTopFace) ) {
625 return BRepFeat_InvalidPlacement;
628 for (ex.ReInit(); ex.More(); ex.Next()) {
629 if (ex.Current().IsSame(myBotFace) ) {
630 return BRepFeat_InvalidPlacement;
639 void Baryc(const TopoDS_Shape& S, gp_Pnt& B)
641 TopExp_Explorer exp(S,TopAbs_EDGE);
642 gp_XYZ Bar(0.,0.,0.);
644 Handle(Geom_Curve) C;
645 Standard_Real prm,First,Last;
647 Standard_Integer i, nbp= 0;
648 for (; exp.More(); exp.Next()) {
649 // Calculate points by non-degenerated edges
650 const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
651 if (!BRep_Tool::Degenerated(E)) {
652 C = BRep_Tool::Curve(E,L,First,Last);
653 C = Handle(Geom_Curve)::DownCast(C->Transformed(L.Transformation()));
654 for (i=1;i<=11; i++) {
655 prm = ((11-i)*First + (i-1)*Last)/10.;
656 Bar += C->Value(prm).XYZ();
661 Bar.Divide((Standard_Real)nbp);
666 void BoxParameters(const TopoDS_Shape& S,
668 Standard_Real& parmin,
669 Standard_Real& parmax)
672 // calculate the parameters of a bounding box in the direction of the axis of the hole
674 BRepBndLib::Add(S,B);
676 B.Get(c[0],c[2],c[4],c[1],c[3],c[5]);
678 Standard_Integer i,j,k;
680 parmax = RealFirst();
682 for (i=0; i<=1; i++) {
684 for (j=2; j<=3; j++) {
686 for (k=4; k<=5; k++) {
688 param = ElCLib::LineParameter(Axis,P);
689 parmin = Min(param,parmin);
690 parmax = Max(param,parmax);
696 Standard_Boolean GetOffset(const LocOpe_PntFace& PntInfo, const Standard_Real Radius, const gp_Ax1& Axis, Standard_Real& outOff )
698 const TopoDS_Face& FF = PntInfo.Face();
699 BRepAdaptor_Surface FFA(FF);
701 Standard_Real Up = PntInfo.UParameter();
702 Standard_Real Vp = PntInfo.VParameter();
705 FFA.D1(Up, Vp, PP, D1U, D1V);
707 CSLib_NormalStatus stat;
708 CSLib::Normal(D1U, D1V, Precision::Angular(), stat, NormF);
709 if (stat != CSLib_Defined)
710 return Standard_False;
711 Standard_Real angle = Axis.Direction().Angle(NormF);
712 if (Abs(M_PI/2. - angle) < Precision::Angular())
713 return Standard_False;
714 outOff = Radius * Abs (tan(angle));
715 return Standard_True;
718 void CreateCyl(const LocOpe_PntFace& PntInfoFirst, const LocOpe_PntFace& PntInfoLast, const Standard_Real Radius,
719 const gp_Ax1& Axis, TopoDS_Shell& Cyl, TopoDS_Face& CylTopF, TopoDS_Face& CylBottF )
721 Standard_Real First=0, Last=0;
722 double offF = 0., offL = 0.;
723 Last = PntInfoLast.Parameter();
724 First = PntInfoFirst.Parameter();
725 Standard_Real Heigth = Last - First;
727 if ( !GetOffset(PntInfoFirst, Radius, Axis, offF))
729 if ( !GetOffset(PntInfoLast, Radius, Axis, offL))
732 //create cylinder along the axis (myAxis);
733 //from 'First - offF' to 'Last + offL' params
734 gp_XYZ theOrig = PntInfoFirst.Pnt().XYZ() - offF * Axis.Direction().XYZ();
735 gp_Pnt p2_ao1(theOrig);
736 gp_Ax2 a2_ao1(p2_ao1, Axis.Direction());
737 BRepPrim_Cylinder theCylinder(a2_ao1, Radius, Heigth + offF + offL);
738 Cyl = theCylinder.Shell();
739 CylTopF = theCylinder.TopFace();
740 CylBottF = theCylinder.BottomFace();