1 // Created on: 1999-06-17
2 // Created by: data exchange team
3 // Copyright (c) 1999-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
23 #include <ShapeConstruct.ixx>
24 #include <Standard_Failure.hxx>
25 #include <Standard_ErrorHandler.hxx>
26 #include <Geom_Conic.hxx>
27 #include <Geom_TrimmedCurve.hxx>
28 #include <GeomConvert_ApproxCurve.hxx>
29 #include <GeomConvert.hxx>
30 #include <Geom2d_Conic.hxx>
31 #include <Geom2d_TrimmedCurve.hxx>
32 #include <Geom2dConvert_ApproxCurve.hxx>
33 #include <Geom2dConvert.hxx>
34 #include <Geom_RectangularTrimmedSurface.hxx>
35 #include <Geom_SurfaceOfLinearExtrusion.hxx>
36 #include <TColgp_Array1OfPnt.hxx>
37 #include <TColStd_Array1OfReal.hxx>
38 #include <TColStd_Array1OfInteger.hxx>
39 #include <TColgp_Array2OfPnt.hxx>
40 #include <TColStd_Array2OfReal.hxx>
41 #include <GeomConvert_ApproxSurface.hxx>
42 #include <Geom_SurfaceOfRevolution.hxx>
43 #include <Geom_OffsetCurve.hxx>
44 #include <ShapeConstruct_Curve.hxx>
45 #include <Precision.hxx>
46 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
49 #include <GeomAPI.hxx>
50 #include <TopTools_HSequenceOfShape.hxx>
51 #include <ShapeAnalysis_Edge.hxx>
52 #include <BRep_Builder.hxx>
53 #include <BRep_Tool.hxx>
54 #include <Geom_Plane.hxx>
55 #include <TopAbs_Orientation.hxx>
58 //=======================================================================
59 //function : ConvertCurveToBSpline
61 //=======================================================================
63 Handle(Geom_BSplineCurve) ShapeConstruct::ConvertCurveToBSpline(const Handle(Geom_Curve)& C3D,
64 const Standard_Real First,
65 const Standard_Real Last,
66 const Standard_Real Tol3d,
67 const GeomAbs_Shape Continuity,
68 const Standard_Integer MaxSegments,
69 const Standard_Integer MaxDegree)
71 Standard_Integer MaxDeg = MaxDegree;
72 Handle(Geom_BSplineCurve) aBSpline;
73 if(C3D->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
74 aBSpline = Handle(Geom_BSplineCurve)::DownCast(C3D);
76 if(C3D->IsKind(STANDARD_TYPE(Geom_Conic)))
77 MaxDeg = Min(MaxDeg,6);
79 Handle(Geom_TrimmedCurve) tcurve = new Geom_TrimmedCurve(C3D,First,Last); //protection agains parabols ets
82 GeomConvert_ApproxCurve approx (tcurve, Tol3d, Continuity, MaxSegments, MaxDeg);
83 if ( approx.HasResult() )
84 aBSpline = Handle(Geom_BSplineCurve)::DownCast(approx.Curve());
86 aBSpline = GeomConvert::CurveToBSplineCurve(C3D,Convert_QuasiAngular);
88 catch (Standard_Failure) {
90 cout << "Warning: GeomConvert_ApproxSurface Exception: ";
91 Standard_Failure::Caught()->Print(cout); cout << endl;
93 aBSpline = GeomConvert::CurveToBSplineCurve(C3D,Convert_QuasiAngular);
99 //=======================================================================
100 //function : ConvertCurveToBSpline
102 //=======================================================================
104 Handle(Geom2d_BSplineCurve) ShapeConstruct::ConvertCurveToBSpline(const Handle(Geom2d_Curve)& C2D,
105 const Standard_Real First,
106 const Standard_Real Last,
107 const Standard_Real Tol2d,
108 const GeomAbs_Shape Continuity,
109 const Standard_Integer MaxSegments,
110 const Standard_Integer MaxDegree)
112 Handle(Geom2d_BSplineCurve) aBSpline2d;
113 if(C2D->IsKind(STANDARD_TYPE(Geom2d_Conic))) {
114 Handle(Geom2d_TrimmedCurve) tcurve = new Geom2d_TrimmedCurve(C2D,First,Last); //protection agains parabols ets
115 Geom2dConvert_ApproxCurve approx (tcurve, Tol2d, Continuity, MaxSegments, MaxDegree);
116 if ( approx.HasResult() )
117 aBSpline2d = Handle(Geom2d_BSplineCurve)::DownCast(approx.Curve());
119 aBSpline2d = Geom2dConvert::CurveToBSplineCurve(tcurve,Convert_QuasiAngular);
121 else if(!C2D->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
122 aBSpline2d = Geom2dConvert::CurveToBSplineCurve(C2D,Convert_QuasiAngular);
125 aBSpline2d = Handle(Geom2d_BSplineCurve)::DownCast(C2D);
130 //=======================================================================
131 //function : ConvertSurfaceToBSpline
133 //=======================================================================
135 // Note: this method has the same purpose as GeomConvert::SurfaceToBSplineSurface(),
136 // but treats more correctly offset surfaces and takes parameters such as UV limits
137 // and degree as arguments instead of deducing them from the surface.
138 // Eventually it may be merged back to GeomConvert.
140 Handle(Geom_BSplineSurface) ShapeConstruct::ConvertSurfaceToBSpline(const Handle(Geom_Surface)& surf,
141 const Standard_Real UF,
142 const Standard_Real UL,
143 const Standard_Real VF,
144 const Standard_Real VL,
145 const Standard_Real Tol3d,
146 const GeomAbs_Shape Continuity,
147 const Standard_Integer MaxSegments,
148 const Standard_Integer MaxDegree)
150 Handle(Geom_BSplineSurface) res;
152 Handle(Geom_Surface) S = surf;
153 if(surf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
154 Handle(Geom_RectangularTrimmedSurface) RTS =
155 Handle(Geom_RectangularTrimmedSurface)::DownCast(surf);
156 S = RTS->BasisSurface();
159 // use GeomConvert for direct conversion of analytic surfaces
160 if (S->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
162 Handle(Geom_RectangularTrimmedSurface) aRTS =
163 new Geom_RectangularTrimmedSurface(S,UF,UL,VF,VL);
164 return GeomConvert::SurfaceToBSplineSurface(aRTS);
167 if(S->IsKind(STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion))) {
168 Handle(Geom_SurfaceOfLinearExtrusion) extr = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(S);
169 Handle(Geom_Curve) basis = extr->BasisCurve();
170 //gp_Dir direction = extr->Direction(); // direction not used (skl)
172 GeomAbs_Shape cnt = (Continuity > GeomAbs_C2 ? GeomAbs_C2: Continuity);
173 Handle(Geom_BSplineCurve) bspl = ConvertCurveToBSpline(basis, UF, UL, Tol3d, cnt, MaxSegments, MaxDegree);
175 gp_Trsf shiftF,shiftL;
176 shiftF.SetTranslation(extr->Value(UF,0),extr->Value(UF,VF));
177 shiftL.SetTranslation(extr->Value(UF,0),extr->Value(UF,VL));
179 Standard_Integer nbPoles = bspl->NbPoles();
180 TColgp_Array1OfPnt poles(1,nbPoles);
181 TColStd_Array1OfReal weights(1,nbPoles);
182 Standard_Integer nbKnots = bspl->NbKnots();
183 TColStd_Array1OfReal knots(1,nbKnots);
184 TColStd_Array1OfInteger mults(1,nbKnots);
188 bspl->Multiplicities(mults);
189 bspl->Weights(weights);
191 TColgp_Array2OfPnt resPoles(1,nbPoles,1,2);
192 TColStd_Array2OfReal resWeigth(1,nbPoles,1,2);
193 for(Standard_Integer j = 1; j <= nbPoles; j++) {
194 resPoles(j,1) = poles(j).Transformed(shiftF);
195 resPoles(j,2) = poles(j).Transformed(shiftL);
196 resWeigth(j,1)= weights(j);
197 resWeigth(j,2)= weights(j);
200 TColStd_Array1OfReal vknots(1,2);
201 TColStd_Array1OfInteger vmults(1,2);
204 vmults(1) = vmults(2) = 2;
206 Handle(Geom_BSplineSurface) bspline = new Geom_BSplineSurface(resPoles, resWeigth, knots, vknots, mults, vmults,
207 bspl->Degree(),1,bspl->IsPeriodic(),Standard_False);
211 if(S->IsKind(STANDARD_TYPE(Geom_SurfaceOfRevolution))) {
212 Handle(Geom_SurfaceOfRevolution) revol = Handle(Geom_SurfaceOfRevolution)::DownCast(S);
213 Handle(Geom_Curve) basis = revol->BasisCurve();
214 if(basis->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
215 GeomAbs_Shape cnt = basis->Continuity();
216 cnt = (cnt > GeomAbs_C2 ? GeomAbs_C2: cnt);
217 Handle(Geom_BSplineCurve) bspl = ConvertCurveToBSpline(basis, VF, VL, Tol3d, cnt, MaxSegments, MaxDegree);
218 gp_Ax1 axis = revol->Axis();
219 Handle(Geom_SurfaceOfRevolution) newRevol = new Geom_SurfaceOfRevolution(bspl,axis);
221 cout <<" Revolution on offset converted" << endl;
227 Handle(Geom_RectangularTrimmedSurface) aSurface = new Geom_RectangularTrimmedSurface(S,UF,UL,VF,VL);
228 Handle(Geom_BSplineSurface) errSpl;
229 for(Standard_Integer cnt = (Continuity > GeomAbs_C3 ? GeomAbs_C3: Continuity); cnt >= 0 ; ) {
232 GeomAbs_Shape aCont = (GeomAbs_Shape) cnt;
233 GeomConvert_ApproxSurface anApprox(aSurface,Tol3d/2,aCont,aCont,MaxDegree,MaxDegree,MaxSegments,0);
234 Standard_Boolean Done = anApprox.IsDone();
235 if (anApprox.MaxError() <= Tol3d && Done) {
238 Standard_Integer nbOfSpan = (anApprox.Surface()->NbUKnots()-1)*(anApprox.Surface()->NbVKnots()-1);
239 cout << "\terror = " << anApprox.MaxError() << "\tspans = " << nbOfSpan << endl;
240 cout << " Surface is aproximated with continuity " << (GeomAbs_Shape)cnt <<endl;
242 S = anApprox.Surface();
243 Handle(Geom_BSplineSurface) Bsc = Handle(Geom_BSplineSurface)::DownCast(S);
247 if(anApprox.HasResult())
248 errSpl = Handle(Geom_BSplineSurface)::DownCast(anApprox.Surface());
250 cout << "\terror = " << anApprox.MaxError() <<endl;
256 catch (Standard_Failure) {
258 cout << "Warning: GeomConvert_ApproxSurface Exception: try to decrease continuity ";
259 Standard_Failure::Caught()->Print(cout); cout << endl;
268 //=======================================================================
269 //function : JoinPCurves
271 //=======================================================================
273 Standard_Boolean ShapeConstruct::JoinPCurves(const Handle(TopTools_HSequenceOfShape)& edges,
274 const TopoDS_Face& theFace,
275 TopoDS_Edge& theEdge)
277 ShapeAnalysis_Edge sae;
282 // check if current face is plane.
283 Handle(Geom_Surface) aGeomSurf = BRep_Tool::Surface(theFace);
284 while (aGeomSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
287 aGeomSurf = Handle(Geom_RectangularTrimmedSurface)::DownCast(aGeomSurf)->BasisSurface();
289 if (aGeomSurf->IsKind(STANDARD_TYPE(Geom_Plane)))
290 return Standard_True;
293 Standard_Boolean IsEdgeSeam = Standard_False;
294 Handle(Geom2d_Curve) aCrvRes1, aCrvRes2;
295 TopAbs_Orientation resOrient;
296 Standard_Real newf,newl;
298 Standard_Integer i = 1;
299 for(; i <= edges->Length(); i++) {
300 TopoDS_Edge Edge = TopoDS::Edge(edges->Value(i));
302 IsEdgeSeam = sae.IsSeam(Edge,theFace);
303 else if (IsEdgeSeam && (!sae.IsSeam(Edge,theFace)))
304 break; // different cases
305 else if (!IsEdgeSeam && (sae.IsSeam(Edge,theFace)))
306 break; // different cases
308 resOrient = TopAbs_FORWARD;
309 Handle(Geom2d_Curve) c2d,c2d2;
310 Standard_Real first, last,first2, last2;
311 if(!sae.PCurve ( Edge, theFace, c2d, first, last, Standard_False ))
315 TopoDS_Edge tmpE1 =TopoDS::Edge(Edge.Reversed());
316 sae.PCurve ( tmpE1, theFace, c2d2, first2, last2, Standard_False );
326 resOrient = Edge.Orientation();
329 Handle(Geom2d_Curve) newCrv;
330 Standard_Boolean isRev1,isRev2;
331 if(!JoinCurves(aCrvRes1,c2d,resOrient,Edge.Orientation(),newf,newl,first, last,newCrv,isRev1,isRev2))
335 Handle(Geom2d_Curve) newCrv2;
336 Standard_Real newf2 = newf,newl2 = newl;
338 if(!JoinCurves(aCrvRes2,c2d2,resOrient,Edge.Orientation(),newf2,newl2,first2, last2,newCrv2,isRev1,isRev2))
343 Standard_Real fp2d = newCrv->FirstParameter();
344 Standard_Real lp2d = newCrv->LastParameter();
345 newl += (last - first);
346 if(fp2d > newf) newf = fp2d;
347 if(lp2d < newl) newl = lp2d;
352 B.UpdateEdge(theEdge,aCrvRes1,aCrvRes2,theFace,0);
354 B.UpdateEdge(theEdge,aCrvRes1,theFace,0);
355 B.Range(theEdge,theFace,newf,newl);
356 B.SameRange(theEdge,Standard_False);
357 B.SameParameter(theEdge,Standard_False);
358 return (i <= edges->Length());
360 catch ( Standard_Failure ) {
362 cout<<"Error: ShapeConstruct::JoinPCurves Exception in GeomConvert_CompCurveToBSplineCurve: ";
363 Standard_Failure::Caught()->Print(cout); cout<<endl;
366 return Standard_False;
369 //=======================================================================
370 //function : JoinCurves
372 //=======================================================================
374 template<class HCurve>
375 static inline HCurve GetCurveCopy(const HCurve& curve,
376 Standard_Real& first, Standard_Real& last,
377 const TopAbs_Orientation &orient)
379 if ( orient == TopAbs_REVERSED ) {
380 Standard_Real cf = first;
381 first = curve->ReversedParameter ( last );
382 last = curve->ReversedParameter ( cf );
383 return curve->Reversed();
385 return HCurve::DownCast(curve->Copy());
388 template<class HCurve>
389 static inline void SegmentCurve (HCurve& curve,
390 const Standard_Real first,
391 const Standard_Real last)
393 if(curve->FirstParameter() < first - Precision::PConfusion() ||
394 curve->LastParameter() > last + Precision::PConfusion()) {
395 if(curve->IsPeriodic())
396 curve->Segment(first,last);
397 else curve->Segment(Max(curve->FirstParameter(),first),
398 Min(curve->LastParameter(),last));
402 template<class HPoint>
403 static inline void GetReversedParameters(const HPoint& p11,
407 Standard_Boolean& isRev1,
408 Standard_Boolean& isRev2)
410 isRev1 = Standard_False;
411 isRev2 = Standard_False;
412 //gka protection against crossing seem on second face
414 Standard_Real d11 = p11.Distance(p21);
415 Standard_Real d21 =p12.Distance(p21);
417 Standard_Real d12 = p11.Distance(p22);
418 Standard_Real d22 = p22.Distance(p12);
419 Standard_Real Dmin1 = Min(d11,d21);
420 Standard_Real Dmin2 = Min(d12,d22);
421 if(fabs(Dmin1 - Dmin2) <= Precision::Confusion() || Dmin2 > Dmin1) {
422 isRev1 = (d11 < d21 ? Standard_True : Standard_False);
424 else if(Dmin2 < Dmin1) {
425 isRev1 = (d12 < d22 ? Standard_True : Standard_False);
426 isRev2 = Standard_True;
431 //=======================================================================
432 //function : JoinCurves
434 //=======================================================================
436 Standard_Boolean ShapeConstruct::JoinCurves(const Handle(Geom_Curve)& ac3d1,
437 const Handle(Geom_Curve)& ac3d2,
438 const TopAbs_Orientation Orient1,
439 const TopAbs_Orientation Orient2,
440 Standard_Real& first1,
441 Standard_Real& last1,
442 Standard_Real& first2,
443 Standard_Real& last2,
444 Handle(Geom_Curve)& c3dOut,
445 Standard_Boolean& isRev1,
446 Standard_Boolean& isRev2)
449 Handle(Geom_Curve) c3d1,c3d2;
451 c3d1 = GetCurveCopy ( ac3d1, first1, last1, Orient1 );
452 c3d2 = GetCurveCopy ( ac3d2, first2, last2, Orient2 );
453 ShapeConstruct_Curve scc;
454 Standard_Boolean After = Standard_True;
455 Handle(Geom_BSplineCurve) bsplc1 = scc.ConvertToBSpline(c3d1,first1, last1,Precision::Confusion());
456 Handle(Geom_BSplineCurve) bsplc2 = scc.ConvertToBSpline(c3d2,first2, last2,Precision::Confusion());
458 // newl = last1 + last2 - first2;
460 if(bsplc1.IsNull() || bsplc2.IsNull()) return Standard_False;
462 SegmentCurve(bsplc1,first1, last1);
463 SegmentCurve(bsplc2,first2, last2);
465 //regression on file 866026_M-f276-f311.brep bug OCC482
466 gp_Pnt pp11 = bsplc1->Pole(1);
467 gp_Pnt pp12 = bsplc1->Pole(bsplc1->NbPoles());
469 gp_Pnt pp21 = bsplc2->Pole(1);
470 gp_Pnt pp22 = bsplc2->Pole(bsplc2->NbPoles());
472 GetReversedParameters(pp11,pp12,pp21,pp22,isRev1,isRev2);
480 gp_Pnt pmid = 0.5 * ( bsplc1->Pole(bsplc1->NbPoles()).XYZ() + bsplc2->Pole(1).XYZ() );
481 bsplc1->SetPole(bsplc1->NbPoles(), pmid);
482 bsplc2->SetPole(1, pmid);
483 GeomConvert_CompCurveToBSplineCurve connect3d(bsplc1);
484 if(!connect3d.Add(bsplc2,Precision::Confusion(), After, Standard_False)) return Standard_False;
485 c3dOut = connect3d.BSplineCurve();
486 return Standard_True;
489 //=======================================================================
490 //function : JoinCurves2d
492 //=======================================================================
494 Standard_Boolean ShapeConstruct::JoinCurves(const Handle(Geom2d_Curve)& aC2d1,
495 const Handle(Geom2d_Curve)& aC2d2,
496 const TopAbs_Orientation Orient1,
497 const TopAbs_Orientation Orient2,
498 Standard_Real& first1,
499 Standard_Real& last1,
500 Standard_Real& first2,
501 Standard_Real& last2,
502 Handle(Geom2d_Curve)& C2dOut,
503 Standard_Boolean& isRev1,
504 Standard_Boolean& isRev2,
505 const Standard_Boolean isError)
507 Handle(Geom2d_Curve) c2d1,c2d2;
508 c2d1 = GetCurveCopy ( aC2d1, first1, last1, Orient1 );
509 c2d2 = GetCurveCopy ( aC2d2, first2, last2, Orient2 );
510 ShapeConstruct_Curve scc;
511 Standard_Boolean After = Standard_True;
513 Handle(Geom2d_BSplineCurve) bsplc12d = scc.ConvertToBSpline(c2d1,first1,last1,Precision::Confusion());
514 Handle(Geom2d_BSplineCurve) bsplc22d = scc.ConvertToBSpline(c2d2,first2,last2,Precision::Confusion());
516 if(bsplc12d.IsNull() || bsplc22d.IsNull()) return Standard_False;
518 SegmentCurve(bsplc12d,first1,last1);
519 SegmentCurve(bsplc22d,first2,last2);
520 //gka protection against crossing seem on second face
521 gp_Pnt2d pp112d = bsplc12d->Pole(1).XY();
522 gp_Pnt2d pp122d = bsplc12d->Pole(bsplc12d->NbPoles()).XY();
524 gp_Pnt2d pp212d = bsplc22d->Pole(1).XY();
525 gp_Pnt2d pp222d = bsplc22d->Pole(bsplc22d->NbPoles()).XY();
527 GetReversedParameters(pp112d,pp122d,pp212d,pp222d,isRev1,isRev2);
529 //regression on file 866026_M-f276-f311.brep bug OCC482
530 //if(isRev1 || isRev2)
539 //---------------------------------------------------------
540 //protection against invalid topology Housing(sam1296.brep(face 707) - bugmergeedges4.brep)
542 gp_Pnt2d pp1 = bsplc12d->Value(bsplc12d->FirstParameter());
543 gp_Pnt2d pp2 = bsplc12d->Value(bsplc12d->LastParameter());
544 gp_Pnt2d pp3 = bsplc12d->Value((bsplc12d->FirstParameter() + bsplc12d->LastParameter())*0.5);
546 Standard_Real leng = pp1.Distance(pp2);
547 Standard_Boolean isCircle = (leng < pp1.Distance(pp3) + Precision::PConfusion());
548 if((pp1.Distance(bsplc22d->Pole(1)) < leng) && !isCircle) return Standard_False;
550 //-------------------------------------------------------
551 gp_Pnt2d pmid1 = 0.5 * ( bsplc12d->Pole(bsplc12d->NbPoles()).XY() + bsplc22d->Pole(1).XY() );
552 bsplc12d->SetPole(bsplc12d->NbPoles(), pmid1);
553 bsplc22d->SetPole(1, pmid1);
555 // abv 01 Sep 99: Geom2dConvert ALWAYS performs reparametrisation of the
556 // second curve before merging; this is quite not suitable
557 // Use 3d tool instead
558 // Geom2dConvert_CompCurveToBSplineCurve connect2d(bsplc12d);
561 gp_Pln vPln ( vPnt, vDir );
562 Handle(Geom_BSplineCurve) bspl1 =
563 Handle(Geom_BSplineCurve)::DownCast ( GeomAPI::To3d ( bsplc12d, vPln ) );
564 Handle(Geom_BSplineCurve) bspl2 =
565 Handle(Geom_BSplineCurve)::DownCast ( GeomAPI::To3d ( bsplc22d, vPln ) );
566 GeomConvert_CompCurveToBSplineCurve connect2d(bspl1);
567 if(!connect2d.Add(bspl2,Precision::PConfusion(), After, Standard_False)) return Standard_False;
568 C2dOut = GeomAPI::To2d ( connect2d.BSplineCurve(), vPln );
570 return Standard_True;