1 // Created on: 1997-10-13
2 // Created by: Roman BORISOV
3 // Copyright (c) 1997-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 <Adaptor3d_Curve.hxx>
19 #include <Approx_CurveOnSurface.hxx>
20 #include <BRep_Builder.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAdaptor_HCurve.hxx>
23 #include <BRepAdaptor_HSurface.hxx>
24 #include <BRepAdaptor_Surface.hxx>
25 #include <BRepAlgo_NormalProjection.hxx>
26 #include <BRepAlgoAPI_Section.hxx>
27 #include <BRepLib_MakeEdge.hxx>
28 #include <BRepLib_MakeVertex.hxx>
29 #include <BRepLib_MakeWire.hxx>
30 #include <BRepTools.hxx>
31 #include <BRepTopAdaptor_FClass2d.hxx>
32 #include <Geom2d_BSplineCurve.hxx>
33 #include <Geom2d_Curve.hxx>
34 #include <Geom2d_TrimmedCurve.hxx>
35 #include <Geom2dAdaptor_HCurve.hxx>
36 #include <Geom_BSplineCurve.hxx>
37 #include <GeomAdaptor.hxx>
38 #include <Precision.hxx>
39 #include <ProjLib_CompProjectedCurve.hxx>
40 #include <ProjLib_HCompProjectedCurve.hxx>
41 #include <Standard_ConstructionError.hxx>
42 #include <Standard_NoSuchObject.hxx>
43 #include <StdFail_NotDone.hxx>
44 #include <TColgp_Array1OfPnt2d.hxx>
45 #include <TColStd_Array1OfInteger.hxx>
46 #include <TColStd_Array1OfReal.hxx>
49 #include <TopExp_Explorer.hxx>
51 #include <TopoDS_Edge.hxx>
52 #include <TopoDS_Shape.hxx>
53 #include <TopTools_HSequenceOfShape.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
56 #ifdef OCCT_DEBUG_CHRONO
57 #include <OSD_Timer.hxx>
59 OSD_Chronometer chr_total, chr_init, chr_approx, chr_booltool;
61 Standard_Real t_total, t_init, t_approx, t_booltool;
62 Standard_IMPORT Standard_Real t_init_point, t_dicho_bound;
63 Standard_IMPORT Standard_Integer init_point_count, dicho_bound_count;
65 void InitChron(OSD_Chronometer& ch)
71 void ResultChron( OSD_Chronometer & ch, Standard_Real & time)
80 //=======================================================================
81 //function : BRepAlgo_NormalProjection
83 //=======================================================================
85 BRepAlgo_NormalProjection::BRepAlgo_NormalProjection()
86 : myIsDone(Standard_False), myMaxDist(-1.),
87 myWith3d(Standard_True), myFaceBounds(Standard_True)
90 BB.MakeCompound(TopoDS::Compound(myToProj));
94 //=======================================================================
95 //function : BRepAlgo_NormalProjection
97 //=======================================================================
99 BRepAlgo_NormalProjection::BRepAlgo_NormalProjection(const TopoDS_Shape& S)
100 : myIsDone(Standard_False), myMaxDist(-1.),
101 myWith3d(Standard_True), myFaceBounds(Standard_True)
104 BB.MakeCompound(TopoDS::Compound(myToProj));
109 //=======================================================================
112 //=======================================================================
114 void BRepAlgo_NormalProjection::Init(const TopoDS_Shape& S)
119 //=======================================================================
122 //=======================================================================
124 void BRepAlgo_NormalProjection::Add(const TopoDS_Shape& ToProj)
127 BB.Add(myToProj, ToProj);
130 //=======================================================================
131 //function : SetParams
133 //=======================================================================
135 void BRepAlgo_NormalProjection::SetParams(const Standard_Real Tol3D,
136 const Standard_Real Tol2D,
137 const GeomAbs_Shape InternalContinuity,
138 const Standard_Integer MaxDegree,
139 const Standard_Integer MaxSeg)
143 myContinuity = InternalContinuity;
144 myMaxDegree = MaxDegree;
148 //=======================================================================
149 //function : SetDefaultParams
151 //=======================================================================
153 void BRepAlgo_NormalProjection::SetDefaultParams()
156 myTol2d = Pow(myTol3d, 2./3);
157 myContinuity = GeomAbs_C2;
162 //=======================================================================
163 //function : SetLimits
165 //=======================================================================
167 void BRepAlgo_NormalProjection::SetLimit(const Standard_Boolean FaceBounds)
169 myFaceBounds = FaceBounds;
172 //=======================================================================
173 //function : SetMaxDistance
175 //=======================================================================
177 void BRepAlgo_NormalProjection::SetMaxDistance(const Standard_Real MaxDist)
182 //=======================================================================
183 //function : Compute3d
185 //=======================================================================
187 void BRepAlgo_NormalProjection::Compute3d(const Standard_Boolean With3d)
192 //=======================================================================
195 //=======================================================================
197 void BRepAlgo_NormalProjection::Build()
199 #ifdef OCCT_DEBUG_CHRONO
200 Standard_Integer init_count = 0, approx_count = 0, booltool_count = 0;
207 init_point_count = 0;
210 dicho_bound_count = 0;
212 InitChron(chr_total);
214 myIsDone = Standard_False;
215 ProjLib_CompProjectedCurve Projector;
216 Handle(TopTools_HSequenceOfShape) Edges = new TopTools_HSequenceOfShape();
217 Handle(TopTools_HSequenceOfShape) Faces = new TopTools_HSequenceOfShape();
218 TopTools_ListOfShape DescenList;
219 Standard_Integer NbEdges = 0, NbFaces = 0, i, j, k;
220 TopExp_Explorer ExpOfWire, ExpOfShape;
221 Standard_Real Udeb, Ufin;
222 TopoDS_Shape VertexRes;
223 Standard_Boolean Only3d, Only2d, Elementary;
225 // for isoparametric cases
226 TColgp_Array1OfPnt2d Poles(1, 2);
227 TColStd_Array1OfReal Knots(1, 2);
228 TColStd_Array1OfInteger Mults(1,2);
229 Standard_Integer Deg;
235 for(ExpOfWire.Init(myToProj, TopAbs_EDGE);
237 ExpOfWire.Next(), NbEdges++) {
238 Edges->Append(ExpOfWire.Current());
241 for(ExpOfShape.Init(myShape, TopAbs_FACE);
243 ExpOfShape.Next(), NbFaces++) {
244 Faces->Append(ExpOfShape.Current());
248 BB.MakeCompound(TopoDS::Compound(myRes));
249 BB.MakeCompound(TopoDS::Compound(VertexRes));
250 Standard_Boolean YaVertexRes = Standard_False;
252 for(i = 1; i <= NbEdges; i++){
254 BRepAdaptor_Curve cur(TopoDS::Edge(Edges->Value(i)));
255 Handle(BRepAdaptor_HCurve) hcur = new BRepAdaptor_HCurve();
257 Elementary = IsElementary(cur);
258 for(j = 1; j <= NbFaces; j++){
259 BRepAdaptor_Surface sur(TopoDS::Face(Faces->Value(j)));
260 Handle(BRepAdaptor_HSurface) hsur = new BRepAdaptor_HSurface();
263 // computation of TolU and TolV
265 Standard_Real TolU, TolV;
267 TolU = hsur->UResolution(myTol3d)/20;
268 TolV = hsur->VResolution(myTol3d)/20;
270 #ifdef OCCT_DEBUG_CHRONO
274 ProjLib_CompProjectedCurve(hsur, hcur, TolU, TolV, myMaxDist);
275 #ifdef OCCT_DEBUG_CHRONO
276 ResultChron(chr_init,t_init);
280 Handle(ProjLib_HCompProjectedCurve) HProjector =
281 new ProjLib_HCompProjectedCurve();
282 HProjector->Set(Projector);
284 Standard_Boolean Degenerated = Standard_False;
285 gp_Pnt2d P2d, Pdeb, Pfin;
287 Standard_Real UIso, VIso;
289 Handle(Adaptor2d_HCurve2d) HPCur;
290 Handle(Geom2d_Curve) PCur2d; // Only for isoparametric projection
292 for(k = 1; k <= Projector.NbCurves(); k++){
293 if(Projector.IsSinglePnt(k, P2d)){
295 cout << "Projection of edge "<<i<<" on face "<<j;
296 cout << " is punctual"<<endl<<endl;
298 Projector.GetSurface()->D0(P2d.X(), P2d.Y(), P);
299 prj = BRepLib_MakeVertex(P).Shape();
300 DescenList.Append(prj);
301 BB.Add(VertexRes, prj);
302 YaVertexRes = Standard_True;
304 myAncestorMap.Bind(prj, Edges->Value(i));
307 Only2d = Only3d = Standard_False;
308 Projector.Bounds(k, Udeb, Ufin);
310 /**************************************************************/
311 if (Projector.IsUIso(k, UIso)) {
313 cout << "Projection of edge "<<i<<" on face "<<j;
314 cout << " is U-isoparametric"<<endl<<endl;
316 Projector.D0(Udeb, Pdeb);
317 Projector.D0(Ufin, Pfin);
322 Handle(Geom2d_BSplineCurve) BS2d =
323 new Geom2d_BSplineCurve(Poles, Knots, Mults, Deg);
324 PCur2d = new Geom2d_TrimmedCurve( BS2d, Udeb, Ufin);
325 HPCur = new Geom2dAdaptor_HCurve(PCur2d);
326 Only3d = Standard_True;
328 else if (Projector.IsVIso(k, VIso)) {
330 cout << "Projection of edge "<<i<<" on face "<<j;
331 cout << " is V-isoparametric"<<endl<<endl;
333 Projector.D0(Udeb, Pdeb);
334 Projector.D0(Ufin, Pfin);
339 Handle(Geom2d_BSplineCurve) BS2d =
340 new Geom2d_BSplineCurve(Poles, Knots, Mults, Deg);
341 PCur2d = new Geom2d_TrimmedCurve(BS2d, Udeb, Ufin);
342 HPCur = new Geom2dAdaptor_HCurve(PCur2d);
343 Only3d = Standard_True;
345 else HPCur = HProjector;
347 if((myWith3d == Standard_False || Elementary) &&
348 (Projector.MaxDistance(k) <= myTol3d) )
349 Only2d = Standard_True;
351 if(Only2d && Only3d) {
352 BRepLib_MakeEdge MKed(GeomAdaptor::MakeCurve(hcur->Curve()),
355 BB.UpdateEdge(TopoDS::Edge(prj),
357 TopoDS::Face(Faces->Value(j)),
359 BB.UpdateVertex(TopExp::FirstVertex(TopoDS::Edge(prj)),myTol3d);
360 BB.UpdateVertex(TopExp::LastVertex(TopoDS::Edge(prj)),myTol3d);
363 #ifdef OCCT_DEBUG_CHRONO
364 InitChron(chr_approx);
366 Approx_CurveOnSurface appr(HPCur, hsur, Udeb, Ufin, myTol3d,
367 myContinuity, myMaxDegree, myMaxSeg,
369 #ifdef OCCT_DEBUG_CHRONO
370 ResultChron(chr_approx,t_approx);
373 cout<<"Approximation.IsDone = "<<appr.IsDone()<<endl;
375 cout<<"MaxError3d = "<<appr.MaxError3d()<<endl<<endl;
377 cout<<"MaxError2dU = "<<appr.MaxError2dU()<<endl;
378 cout<<"MaxError2dV = "<<appr.MaxError2dV()<<endl<<endl;
383 if(!Only3d) PCur2d = appr.Curve2d();
385 BRepLib_MakeEdge MKed(GeomAdaptor::MakeCurve(hcur->Curve()),
390 // It is tested if the solution is not degenerated to set the
391 // flag on edge, one takes several points, checks if the cloud of
392 // points has less diameter than the tolerance 3D
393 Degenerated = Standard_True;
395 Handle(Geom_BSplineCurve) BS3d = appr.Curve3d();
396 gp_Pnt P1(0.,0.,0.),PP; // skl : I change "P" to "PP"
397 Standard_Integer NbPoint,ii ; // skl : I change "i" to "ii"
398 Standard_Real Par,DPar;
399 // start from 3 points to reject non degenerated edges
402 DPar = (BS3d->LastParameter()-BS3d->FirstParameter())/(NbPoint-1);
403 for (ii=0;ii<NbPoint;ii++)
405 Par=BS3d->FirstParameter()+ii*DPar;
407 P1.SetXYZ(P1.XYZ() + PP.XYZ()/NbPoint);
409 for (ii=0;ii<NbPoint && Degenerated ;ii++)
411 Par=BS3d->FirstParameter()+ii*DPar;
413 Dist=P1.Distance(PP);
415 Degenerated = Standard_False;
419 // if the test passes a more exact test with 10 points
421 P1.SetCoord(0.,0.,0.);
423 DPar = (BS3d->LastParameter()-BS3d->FirstParameter())/(NbPoint-1);
424 for (ii=0;ii<NbPoint;ii++)
426 Par=BS3d->FirstParameter()+ii*DPar;
428 P1.SetXYZ(P1.XYZ() + PP.XYZ()/NbPoint);
430 for (ii=0;ii<NbPoint && Degenerated ;ii++)
432 Par=BS3d->FirstParameter()+ii*DPar;
434 Dist=P1.Distance(PP);
436 Degenerated = Standard_False;
443 cout << "Projection of edge "<<i<<" on face "<<j;
444 cout << " is degenerated "<<endl<<endl;
448 BB.UpdateVertex(VV,P1,myTol3d);
449 BB.MakeEdge(TopoDS::Edge(prj));
450 BB.Add(TopoDS::Edge(prj),VV.Oriented(TopAbs_FORWARD));
451 BB.Add(TopoDS::Edge(prj),VV.Oriented(TopAbs_REVERSED));
452 BB.Degenerated(TopoDS::Edge(prj), Standard_True);
455 prj = BRepLib_MakeEdge(BS3d).Edge();
459 BB.UpdateEdge(TopoDS::Edge(prj),
461 TopoDS::Face(Faces->Value(j)),
463 BB.UpdateVertex(TopExp::FirstVertex(TopoDS::Edge(prj)),appr.MaxError3d());
464 BB.UpdateVertex(TopExp::LastVertex(TopoDS::Edge(prj)),appr.MaxError3d());
466 BB.Range(TopoDS::Edge(prj),
467 TopoDS::Face(Faces->Value(j)),
473 // Trimming edges by face bounds
474 // if the solution is degenerated, use of BoolTool is avoided
475 #ifdef OCCT_DEBUG_CHRONO
476 InitChron(chr_booltool);
479 // Perform Boolean COMMON operation to get parts of projected edge
481 BRepAlgoAPI_Section aSection(Faces->Value(j), prj);
482 if (aSection.IsDone()) {
483 const TopoDS_Shape& aRC = aSection.Shape();
485 TopExp_Explorer aExpE(aRC, TopAbs_EDGE);
486 for (; aExpE.More(); aExpE.Next()) {
487 const TopoDS_Shape& aE = aExpE.Current();
489 myAncestorMap.Bind(aE, Edges->Value(i));
490 myCorresp.Bind(aE, Faces->Value(j));
494 // if the common operation has failed, try to classify the part
495 BRepTopAdaptor_FClass2d classifier(TopoDS::Face(Faces->Value(j)),
496 Precision::Confusion());
498 Standard_Real f = PCur2d->FirstParameter();
499 Standard_Real l = PCur2d->LastParameter();
500 Standard_Real pmil = (f + l )/2;
501 PCur2d->D0(pmil, Puv);
503 state = classifier.Perform(Puv);
504 if(state == TopAbs_IN || state == TopAbs_ON) {
506 DescenList.Append(prj);
507 myAncestorMap.Bind(prj, Edges->Value(i));
508 myCorresp.Bind(prj, Faces->Value(j));
514 cout << " BooleanOperations : no solution " << endl;
517 BRepTopAdaptor_FClass2d classifier(TopoDS::Face(Faces->Value(j)),
518 Precision::Confusion());
520 Standard_Real f = PCur2d->FirstParameter();
521 Standard_Real l = PCur2d->LastParameter();
522 Standard_Real pmil = (f + l )/2;
523 PCur2d->D0(pmil, Puv);
525 state = classifier.Perform(Puv);
526 if(state == TopAbs_IN || state == TopAbs_ON) {
528 DescenList.Append(prj);
529 myAncestorMap.Bind(prj, Edges->Value(i));
530 myCorresp.Bind(prj, Faces->Value(j));
532 #ifdef OCCT_DEBUG_CHRONO
533 ResultChron(chr_booltool,t_booltool);
540 DescenList.Append(prj);
541 myAncestorMap.Bind(prj, Edges->Value(i));
542 myCorresp.Bind(prj, Faces->Value(j));
547 myDescendants.Bind(Edges->Value(i), DescenList);
549 // JPI : eventual wire creation is reported in a specific method
550 // BuilWire that can be called by the user. Otherwise, the
551 // relations of map myAncestorMap, myCorresp will be lost.
553 if(YaVertexRes) BB.Add(myRes, VertexRes);
555 myIsDone = Standard_True;
557 #ifdef OCCT_DEBUG_CHRONO
558 ResultChron(chr_total,t_total);
560 cout<<"Build - Total time : "<<t_total<<" includes:" <<endl;
561 cout<<"- Projection : "<<t_init<<endl;
562 cout<<" -- Initial point search : "<<t_init_point<<endl;
563 cout<<" -- DichoBound search : "<<t_dicho_bound<<endl;
564 cout<<"- Approximation : "<<t_approx<<endl;
565 cout<<"- Boolean operation : "<<t_booltool<<endl;
566 cout<<"- Rest of time : "<<t_total-(t_init + t_approx + t_booltool )<<endl<<endl;
568 t_init /= init_count;
569 if (init_point_count != 0)
570 t_init_point /= init_point_count;
571 if (dicho_bound_count != 0)
572 t_dicho_bound /= dicho_bound_count;
573 if (approx_count != 0)
574 t_approx /= approx_count;
575 if (booltool_count != 0)
576 t_booltool /= booltool_count;
578 cout<<"Unitary average time : "<<endl;
579 cout<<"- Projection : "<<t_init<<endl;
580 cout<<" -- Initial point search: "<<t_init_point<<endl;
581 cout<<" -- DichoBound search : "<<t_dicho_bound<<endl;
582 cout<<"- Approximation : "<<t_approx<<endl;
583 cout<<"- Boolean operation :"<<t_booltool<<endl;
584 cout<<endl<<"Number of initial point computations is "<<init_point_count<<endl<<endl;
588 //=======================================================================
591 //=======================================================================
593 Standard_Boolean BRepAlgo_NormalProjection::IsDone() const
598 //=======================================================================
599 //function : Projection
601 //=======================================================================
603 const TopoDS_Shape& BRepAlgo_NormalProjection::Projection() const
608 //=======================================================================
609 //function : Ancestor
611 //=======================================================================
613 const TopoDS_Shape& BRepAlgo_NormalProjection::Ancestor(const TopoDS_Edge& E) const
615 return myAncestorMap.Find(E);
618 //=======================================================================
621 //=======================================================================
623 const TopoDS_Shape& BRepAlgo_NormalProjection::Couple(const TopoDS_Edge& E) const
625 return myCorresp.Find(E);
628 //=======================================================================
629 //function : Generated
631 //=======================================================================
633 const TopTools_ListOfShape& BRepAlgo_NormalProjection::Generated(const TopoDS_Shape& S)
635 return myDescendants.Find(S);
638 //=======================================================================
639 //function : IsElementary
641 //=======================================================================
643 Standard_Boolean BRepAlgo_NormalProjection::IsElementary(const Adaptor3d_Curve& C) const
645 GeomAbs_CurveType type;
650 case GeomAbs_Ellipse:
651 case GeomAbs_Hyperbola:
652 case GeomAbs_Parabola: return Standard_True;
653 default: return Standard_False;
656 //=======================================================================
657 //function : BuildWire
659 //=======================================================================
661 Standard_Boolean BRepAlgo_NormalProjection::BuildWire(TopTools_ListOfShape& ListOfWire) const
663 TopExp_Explorer ExpOfWire, ExpOfShape;
664 Standard_Boolean IsWire=Standard_False;
665 ExpOfShape.Init(myRes, TopAbs_EDGE);
666 if(ExpOfShape.More())
668 TopTools_ListOfShape List;
670 for ( ; ExpOfShape.More(); ExpOfShape.Next())
672 const TopoDS_Shape& CurE = ExpOfShape.Current();
679 const TopoDS_Shape& Wire = MW.Shape();
680 // If the resulting wire contains the same edge as at the beginning OK
681 // otherwise the result really consists of several wires.
682 TopExp_Explorer exp2(Wire,TopAbs_EDGE);
683 Standard_Integer NbEdges = 0;
684 for (;exp2.More(); exp2.Next()) NbEdges++;
685 if ( NbEdges == List.Extent())
687 ListOfWire.Append(Wire);
688 IsWire = Standard_True;