1 // Created on: 1998-08-20
2 // Created by: Philippe MANGIN
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16 
17 #include <BRepAdaptor_CompCurve.hxx>
18 
19 #include <BRep_Tool.hxx>
20 #include <BRepTools_WireExplorer.hxx>
21 #include <ElCLib.hxx>
22 #include <GCPnts_AbscissaPoint.hxx>
23 #include <Geom_BezierCurve.hxx>
24 #include <Geom_BSplineCurve.hxx>
25 #include <gp_Circ.hxx>
26 #include <gp_Elips.hxx>
27 #include <gp_Hypr.hxx>
28 #include <gp_Lin.hxx>
29 #include <gp_Parab.hxx>
30 #include <gp_Pnt.hxx>
31 #include <gp_Vec.hxx>
32 #include <Standard_DomainError.hxx>
33 #include <Standard_NoSuchObject.hxx>
34 #include <Standard_NullObject.hxx>
35 #include <Standard_OutOfRange.hxx>
36 #include <TopAbs_Orientation.hxx>
37 #include <TopExp.hxx>
38 #include <TopoDS_Edge.hxx>
39 #include <TopoDS_Wire.hxx>
40 
IMPLEMENT_STANDARD_RTTIEXT(BRepAdaptor_CompCurve,Adaptor3d_Curve)41 IMPLEMENT_STANDARD_RTTIEXT(BRepAdaptor_CompCurve, Adaptor3d_Curve)
42 
43 BRepAdaptor_CompCurve::BRepAdaptor_CompCurve()
44 : TFirst  (0.0),
45   TLast   (0.0),
46   PTol    (0.0),
47   CurIndex(-1),
48   Forward (Standard_False),
49   IsbyAC  (Standard_False)
50 {
51 }
52 
BRepAdaptor_CompCurve(const TopoDS_Wire & theWire,const Standard_Boolean theIsAC)53 BRepAdaptor_CompCurve::BRepAdaptor_CompCurve(const TopoDS_Wire&     theWire,
54                                              const Standard_Boolean theIsAC)
55 : myWire  (theWire),
56   TFirst  (0.0),
57   TLast   (0.0),
58   PTol    (0.0),
59   CurIndex(-1),
60   Forward (Standard_False),
61   IsbyAC  (theIsAC)
62 {
63   Initialize(theWire, theIsAC);
64 }
65 
BRepAdaptor_CompCurve(const TopoDS_Wire & theWire,const Standard_Boolean theIsAC,const Standard_Real theFirst,const Standard_Real theLast,const Standard_Real theTolerance)66 BRepAdaptor_CompCurve::BRepAdaptor_CompCurve(const TopoDS_Wire& theWire,
67                                              const Standard_Boolean theIsAC,
68                                              const Standard_Real theFirst,
69                                              const Standard_Real theLast,
70                                              const Standard_Real theTolerance)
71 : myWire  (theWire),
72   TFirst  (theFirst),
73   TLast   (theLast),
74   PTol    (theTolerance),
75   CurIndex(-1),
76   Forward (Standard_False),
77   IsbyAC  (theIsAC)
78 {
79   Initialize(theWire, theIsAC, theFirst, theLast, theTolerance);
80 }
81 
82 //=======================================================================
83 //function : ShallowCopy
84 //purpose  :
85 //=======================================================================
86 
Handle(Adaptor3d_Curve)87 Handle(Adaptor3d_Curve) BRepAdaptor_CompCurve::ShallowCopy() const
88 {
89   Handle(BRepAdaptor_CompCurve) aCopy = new BRepAdaptor_CompCurve();
90 
91   aCopy->myWire   = myWire;
92   aCopy->TFirst   = TFirst;
93   aCopy->TLast    = TLast;
94   aCopy->PTol     = PTol;
95   aCopy->myCurves = new (BRepAdaptor_HArray1OfCurve) (1, myCurves->Size());
96   for (Standard_Integer anI = 1; anI <= myCurves->Size(); ++anI)
97   {
98     const Handle(Adaptor3d_Curve) aCurve = myCurves->Value(anI).ShallowCopy();
99     const BRepAdaptor_Curve& aBrepCurve = *(Handle(BRepAdaptor_Curve)::DownCast(aCurve));
100     aCopy->myCurves->SetValue(anI, aBrepCurve);
101   }
102   aCopy->myKnots  = myKnots;
103   aCopy->CurIndex = CurIndex;
104   aCopy->Forward  = Forward;
105   aCopy->IsbyAC   = IsbyAC;
106 
107   return aCopy;
108 }
109 
Initialize(const TopoDS_Wire & W,const Standard_Boolean AC)110  void BRepAdaptor_CompCurve::Initialize(const TopoDS_Wire& W,
111 					const Standard_Boolean AC)
112 {
113   Standard_Integer ii, NbEdge;
114   BRepTools_WireExplorer wexp;
115   TopoDS_Edge E;
116 
117   myWire = W;
118   PTol = 0.0;
119   IsbyAC = AC;
120 
121   for (NbEdge=0, wexp.Init(myWire);
122        wexp.More(); wexp.Next())
123     if (! BRep_Tool::Degenerated(wexp.Current())) NbEdge++;
124 
125   if (NbEdge == 0) return;
126 
127   CurIndex = (NbEdge+1)/2;
128   myCurves = new (BRepAdaptor_HArray1OfCurve) (1,NbEdge);
129   myKnots = new (TColStd_HArray1OfReal) (1,NbEdge+1);
130   myKnots->SetValue(1, 0.);
131 
132   for (ii=0, wexp.Init(myWire);
133        wexp.More(); wexp.Next()) {
134     E = wexp.Current();
135     if (! BRep_Tool::Degenerated(E)) {
136       ii++;
137       myCurves->ChangeValue(ii).Initialize(E);
138       if (AC) {
139 	myKnots->SetValue(ii+1,  myKnots->Value(ii));
140 	myKnots->ChangeValue(ii+1) +=
141 	  GCPnts_AbscissaPoint::Length(myCurves->ChangeValue(ii));
142       }
143       else  myKnots->SetValue(ii+1, (Standard_Real)ii);
144     }
145   }
146 
147   Forward = Standard_True; // Default ; The Reverse Edges are parsed.
148   if((NbEdge > 2) || ((NbEdge==2) && (!myWire.Closed())) ) {
149     TopAbs_Orientation Or = myCurves->Value(1).Edge().Orientation();
150     TopoDS_Vertex VI, VL;
151     TopExp::CommonVertex(myCurves->Value(1).Edge(),
152 			     myCurves->Value(2).Edge(),
153 			     VI);
154     VL = TopExp::LastVertex(myCurves->Value(1).Edge());
155     if (VI.IsSame(VL)) { // The direction of parsing is always preserved
156       if (Or == TopAbs_REVERSED)
157 	 Forward = Standard_False;
158     }
159     else {// The direction of parsing is always reversed
160      if (Or != TopAbs_REVERSED)
161 	 Forward = Standard_False;
162     }
163   }
164 
165   TFirst = 0;
166   TLast = myKnots->Value(myKnots->Length());
167 }
168 
Initialize(const TopoDS_Wire & W,const Standard_Boolean AC,const Standard_Real First,const Standard_Real Last,const Standard_Real Tol)169  void BRepAdaptor_CompCurve::Initialize(const TopoDS_Wire& W,
170 					const Standard_Boolean AC,
171 					const Standard_Real First,
172 					const Standard_Real Last,
173 					const Standard_Real Tol)
174 {
175   Initialize(W, AC);
176   TFirst = First;
177   TLast = Last;
178   PTol = Tol;
179 
180   // Trim the extremal curves.
181   Handle (BRepAdaptor_Curve) HC;
182   Standard_Integer i1, i2;
183   Standard_Real f=TFirst, l=TLast, d;
184   i1 = i2 = CurIndex;
185   Prepare(f, d, i1);
186   Prepare(l, d, i2);
187   CurIndex = (i1+i2)/2; // Small optimization
188   if (i1==i2) {
189     if (l > f)
190       HC = Handle(BRepAdaptor_Curve)::DownCast(myCurves->Value(i1).Trim(f, l, PTol));
191     else
192       HC = Handle(BRepAdaptor_Curve)::DownCast(myCurves->Value(i1).Trim(l, f, PTol));
193     myCurves->SetValue(i1, *HC);
194   }
195   else {
196     const BRepAdaptor_Curve& c1 = myCurves->Value(i1);
197     const BRepAdaptor_Curve& c2 = myCurves->Value(i2);
198     Standard_Real k;
199 
200     k = c1.LastParameter();
201     if (k>f)
202       HC = Handle(BRepAdaptor_Curve)::DownCast(c1.Trim(f, k, PTol));
203     else
204       HC = Handle(BRepAdaptor_Curve)::DownCast(c1.Trim(k, f, PTol));
205     myCurves->SetValue(i1, *HC);
206 
207     k = c2.FirstParameter();
208     if (k<=l)
209       HC = Handle(BRepAdaptor_Curve)::DownCast(c2.Trim(k, l, PTol));
210     else
211       HC = Handle(BRepAdaptor_Curve)::DownCast(c2.Trim(l, k, PTol));
212     myCurves->SetValue(i2, *HC);
213   }
214 }
215 
Wire() const216 const TopoDS_Wire& BRepAdaptor_CompCurve::Wire() const
217 {
218   return myWire;
219 }
220 
Edge(const Standard_Real U,TopoDS_Edge & E,Standard_Real & UonE) const221  void BRepAdaptor_CompCurve::Edge(const Standard_Real U,
222 				  TopoDS_Edge& E,
223 				  Standard_Real& UonE) const
224 {
225   Standard_Real d;
226   Standard_Integer index = CurIndex;
227   UonE = U;
228   Prepare(UonE, d, index);
229   E = myCurves->Value(index).Edge();
230 }
231 
FirstParameter() const232  Standard_Real BRepAdaptor_CompCurve::FirstParameter() const
233 {
234   return TFirst;
235 }
236 
LastParameter() const237  Standard_Real BRepAdaptor_CompCurve::LastParameter() const
238 {
239   return TLast;
240 }
241 
Continuity() const242  GeomAbs_Shape BRepAdaptor_CompCurve::Continuity() const
243 {
244   if ( myCurves->Length() > 1) return GeomAbs_C0;
245   return myCurves->Value(1).Continuity();
246 }
247 
NbIntervals(const GeomAbs_Shape S) const248  Standard_Integer BRepAdaptor_CompCurve::NbIntervals(const GeomAbs_Shape S) const
249 {
250   Standard_Integer NbInt, ii;
251   for (ii=1, NbInt=0; ii<=myCurves->Length(); ii++)
252     NbInt += myCurves->ChangeValue(ii).NbIntervals(S);
253 
254   return NbInt;
255 }
256 
Intervals(TColStd_Array1OfReal & T,const GeomAbs_Shape S) const257  void BRepAdaptor_CompCurve::Intervals(TColStd_Array1OfReal& T,
258                                        const GeomAbs_Shape S) const
259 {
260   Standard_Integer ii, jj, kk, n;
261   Standard_Real f, F, delta;
262 
263   // First curve (direction of parsing of the edge)
264   n = myCurves->ChangeValue(1).NbIntervals(S);
265   Handle(TColStd_HArray1OfReal) Ti = new (TColStd_HArray1OfReal) (1, n+1);
266   myCurves->ChangeValue(1).Intervals(Ti->ChangeArray1(), S);
267   InvPrepare(1, f, delta);
268   F = myKnots->Value(1);
269   if (delta < 0) {
270     // invert the direction of parsing
271     for (kk=1,jj=Ti->Length(); jj>0; kk++, jj--)
272       T(kk) = F + (Ti->Value(jj)-f)*delta;
273   }
274   else {
275     for (kk=1; kk<=Ti->Length(); kk++)
276       T(kk) = F + (Ti->Value(kk)-f)*delta;
277   }
278 
279   // and the next
280   for (ii=2; ii<=myCurves->Length(); ii++) {
281     n = myCurves->ChangeValue(ii).NbIntervals(S);
282     if (n != Ti->Length()-1) Ti = new (TColStd_HArray1OfReal) (1, n+1);
283     myCurves->ChangeValue(ii).Intervals(Ti->ChangeArray1(), S);
284     InvPrepare(ii, f, delta);
285     F = myKnots->Value(ii);
286     if (delta < 0) {
287       // invert the direction of parcing
288       for (jj=Ti->Length()-1; jj>0; kk++, jj--)
289 	T(kk) = F + (Ti->Value(jj)-f)*delta;
290     }
291     else {
292       for (jj=2; jj<=Ti->Length(); kk++, jj++)
293 	T(kk) = F + (Ti->Value(jj)-f)*delta;
294     }
295   }
296 }
297 
Handle(Adaptor3d_Curve)298  Handle(Adaptor3d_Curve) BRepAdaptor_CompCurve::Trim(const Standard_Real First,
299 						    const Standard_Real Last,
300 						    const Standard_Real Tol) const
301 {
302   BRepAdaptor_CompCurve C(myWire, IsbyAC, First, Last, Tol);
303   Handle(BRepAdaptor_CompCurve) HC =
304     new (BRepAdaptor_CompCurve) (C);
305   return HC;
306 }
307 
IsClosed() const308  Standard_Boolean BRepAdaptor_CompCurve::IsClosed() const
309 {
310   return myWire.Closed();
311 }
312 
IsPeriodic() const313  Standard_Boolean BRepAdaptor_CompCurve::IsPeriodic() const
314 {
315   return Standard_False;
316 
317 }
318 
Period() const319  Standard_Real BRepAdaptor_CompCurve::Period() const
320 {
321   return (TLast - TFirst);
322 }
323 
Value(const Standard_Real U) const324  gp_Pnt BRepAdaptor_CompCurve::Value(const Standard_Real U) const
325 {
326   Standard_Real u = U, d;
327   Standard_Integer index = CurIndex;
328   Prepare(u, d, index);
329   return myCurves->Value(index).Value(u);
330 }
331 
D0(const Standard_Real U,gp_Pnt & P) const332  void BRepAdaptor_CompCurve::D0(const Standard_Real U,
333 				gp_Pnt& P) const
334 {
335   Standard_Real u = U, d;
336   Standard_Integer index = CurIndex;
337   Prepare(u, d, index);
338   myCurves->Value(index).D0(u, P);
339 }
340 
D1(const Standard_Real U,gp_Pnt & P,gp_Vec & V) const341  void BRepAdaptor_CompCurve::D1(const Standard_Real U,
342 				gp_Pnt& P,
343 				gp_Vec& V) const
344 {
345   Standard_Real u = U, d;
346   Standard_Integer index = CurIndex;
347   Prepare(u, d, index);
348   myCurves->Value(index).D1(u, P, V);
349   V*=d;
350 }
351 
D2(const Standard_Real U,gp_Pnt & P,gp_Vec & V1,gp_Vec & V2) const352  void BRepAdaptor_CompCurve::D2(const Standard_Real U,
353 				gp_Pnt& P,
354 				gp_Vec& V1,
355 				gp_Vec& V2) const
356 {
357   Standard_Real u = U, d;
358   Standard_Integer index = CurIndex;
359   Prepare(u, d, index);
360   myCurves->Value(index).D2(u, P, V1, V2);
361   V1*=d;
362   V2 *= d*d;
363 }
364 
D3(const Standard_Real U,gp_Pnt & P,gp_Vec & V1,gp_Vec & V2,gp_Vec & V3) const365  void BRepAdaptor_CompCurve::D3(const Standard_Real U,
366 				gp_Pnt& P,gp_Vec& V1,
367 				gp_Vec& V2,
368 				gp_Vec& V3) const
369 {
370   Standard_Real u = U, d;
371   Standard_Integer index = CurIndex;
372   Prepare(u, d, index);
373   myCurves->Value(index).D3(u, P, V1, V2, V3);
374   V1*=d;
375   V2 *= d*d;
376   V3 *= d*d*d;
377 }
378 
DN(const Standard_Real U,const Standard_Integer N) const379  gp_Vec BRepAdaptor_CompCurve::DN(const Standard_Real U,
380 				  const Standard_Integer N) const
381 {
382   Standard_Real u = U, d;
383   Standard_Integer index = CurIndex;
384   Prepare(u, d, index);
385 
386   return (myCurves->Value(index).DN(u, N) * Pow(d, N));
387 }
388 
Resolution(const Standard_Real R3d) const389  Standard_Real BRepAdaptor_CompCurve::Resolution(const Standard_Real R3d) const
390 {
391   Standard_Real Res = 1.e200, r;
392   Standard_Integer ii, L = myCurves->Length();
393   for (ii=1; ii<=L; ii++) {
394     r = myCurves->Value(ii).Resolution(R3d);
395     if (r < Res) Res = r;
396   }
397   return Res;
398 }
399 
GetType() const400  GeomAbs_CurveType BRepAdaptor_CompCurve::GetType() const
401 {
402   return GeomAbs_OtherCurve; //temporary
403 //  if ( myCurves->Length() > 1) return GeomAbs_OtherCurve;
404 //  return myCurves->Value(1).GetType();
405 }
406 
Line() const407  gp_Lin BRepAdaptor_CompCurve::Line() const
408 {
409   return myCurves->Value(1).Line();
410 }
411 
Circle() const412  gp_Circ BRepAdaptor_CompCurve::Circle() const
413 {
414   return myCurves->Value(1).Circle();
415 }
416 
Ellipse() const417  gp_Elips BRepAdaptor_CompCurve::Ellipse() const
418 {
419   return myCurves->Value(1).Ellipse();
420 }
421 
Hyperbola() const422  gp_Hypr BRepAdaptor_CompCurve::Hyperbola() const
423 {
424   return myCurves->Value(1).Hyperbola();
425 }
426 
Parabola() const427  gp_Parab BRepAdaptor_CompCurve::Parabola() const
428 {
429   return myCurves->Value(1).Parabola();
430 }
431 
Degree() const432  Standard_Integer BRepAdaptor_CompCurve::Degree() const
433 {
434   return myCurves->Value(1).Degree();
435 }
436 
IsRational() const437  Standard_Boolean BRepAdaptor_CompCurve::IsRational() const
438 {
439   return myCurves->Value(1).IsRational();
440 }
441 
NbPoles() const442  Standard_Integer BRepAdaptor_CompCurve::NbPoles() const
443 {
444   return myCurves->Value(1).NbPoles();
445 }
446 
NbKnots() const447  Standard_Integer BRepAdaptor_CompCurve::NbKnots() const
448 {
449   return myCurves->Value(1).NbKnots();
450 }
451 
Handle(Geom_BezierCurve)452  Handle(Geom_BezierCurve) BRepAdaptor_CompCurve::Bezier() const
453 {
454   return myCurves->Value(1).Bezier();
455 }
456 
Handle(Geom_BSplineCurve)457  Handle(Geom_BSplineCurve) BRepAdaptor_CompCurve::BSpline() const
458 {
459   return myCurves->Value(1).BSpline();
460 }
461 
462 //=======================================================================
463 //function : Prepare
464 //purpose  :
465 // When the parameter is close to "node" the rule is determined
466 // depending on the sign of tol:
467 //   - negative -> Rule preceding to the node.
468 //   - positive -> Rule following after the node.
469 //=======================================================================
470 
Prepare(Standard_Real & W,Standard_Real & Delta,Standard_Integer & theCurIndex) const471  void BRepAdaptor_CompCurve::Prepare(Standard_Real& W,
472 				     Standard_Real& Delta,
473 				     Standard_Integer& theCurIndex) const
474 {
475   Standard_Real f,l, Wtest, Eps;
476   Standard_Integer ii;
477   if (W-TFirst < TLast-W) { Eps = PTol; }
478   else                    { Eps = -PTol;}
479 
480 
481   Wtest = W+Eps; //Offset to discriminate the nodes
482 
483   // Find the index
484   Standard_Boolean Trouve = Standard_False;
485   if (myKnots->Value(theCurIndex) > Wtest) {
486     for (ii=theCurIndex-1; ii>0 && !Trouve; ii--)
487       if (myKnots->Value(ii)<= Wtest) {
488 	theCurIndex = ii;
489 	Trouve = Standard_True;
490       }
491     if (!Trouve) theCurIndex = 1; // Out of limits...
492   }
493 
494   else if (myKnots->Value(theCurIndex+1) <= Wtest) {
495     for (ii=theCurIndex+1; ii<=myCurves->Length() && !Trouve; ii++)
496       if (myKnots->Value(ii+1)> Wtest) {
497 	theCurIndex = ii;
498 	Trouve = Standard_True;
499       }
500     if (!Trouve) theCurIndex = myCurves->Length(); // Out of limits...
501   }
502 
503   // Invert ?
504   const TopoDS_Edge& E = myCurves->Value(theCurIndex).Edge();
505   TopAbs_Orientation Or = E.Orientation();
506   Standard_Boolean Reverse;
507   Reverse = (Forward && (Or == TopAbs_REVERSED)) ||
508             (!Forward && (Or != TopAbs_REVERSED));
509 
510   // Calculate the local parameter
511   BRep_Tool::Range(E, f, l);
512   Delta = myKnots->Value(theCurIndex+1) - myKnots->Value(theCurIndex);
513   if (Delta > PTol*1.e-9) Delta = (l-f)/Delta;
514 
515   if (Reverse) {
516     Delta *= -1;
517     W = l + (W-myKnots->Value(theCurIndex)) * Delta;
518   }
519   else {
520     W = f + (W-myKnots->Value(theCurIndex)) * Delta;
521   }
522 }
523 
InvPrepare(const Standard_Integer index,Standard_Real & First,Standard_Real & Delta) const524 void  BRepAdaptor_CompCurve::InvPrepare(const Standard_Integer index,
525 					Standard_Real& First,
526 					Standard_Real& Delta) const
527 {
528   // Invert?
529   const TopoDS_Edge& E = myCurves->Value(index).Edge();
530   TopAbs_Orientation Or = E.Orientation();
531   Standard_Boolean Reverse;
532   Reverse = (Forward && (Or == TopAbs_REVERSED)) ||
533             (!Forward && (Or != TopAbs_REVERSED));
534 
535   // Calculate the parameters of reparametrisation
536   // such as : T = Ti + (t-First)*Delta
537   Standard_Real f, l;
538   BRep_Tool::Range(E, f, l);
539   Delta = myKnots->Value(index+1) - myKnots->Value(index);
540   if (l-f > PTol*1.e-9) Delta /= (l-f);
541 
542   if (Reverse) {
543     Delta *= -1;
544     First = l;
545   }
546   else {
547     First = f;
548   }
549 }
550