0024573: Wrong result of 2d-offset algorithm on customer's shape
[occt.git] / src / Bisector / Bisector_Inter.cxx
1 // Created on: 1994-06-24
2 // Created by: Yves FRICAUD
3 // Copyright (c) 1994-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
9 // under the terms of the GNU Lesser General Public 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 //  Modified by skv - Mon May  5 15:06:39 2003 OCC616
18
19 #include <Bisector_Inter.ixx>
20 #include <IntRes2d_Intersection.hxx>
21 #include <Bisector_Curve.hxx>
22 #include <Bisector_BisecAna.hxx>
23 #include <Bisector_BisecCC.hxx>
24 #include <Bisector_BisecPC.hxx>
25 #include <Bisector_FunctionInter.hxx>
26 #include <Geom2dInt_GInter.hxx>
27 #include <Geom2d_TrimmedCurve.hxx>
28 #include <Geom2dAdaptor_Curve.hxx>
29 #include <Geom2d_Curve.hxx>
30 #include <Geom2d_Line.hxx>
31 #include <IntRes2d_Transition.hxx>
32 #include <IntRes2d_IntersectionPoint.hxx>
33 #include <Precision.hxx>
34 #include <math_BissecNewton.hxx>
35 #include <ElCLib.hxx>
36
37 #ifdef DRAW
38 #include <Draw_Appli.hxx>
39 #include <DrawTrSurf_Curve2d.hxx>
40 #include <Draw_Marker2D.hxx>
41 #endif
42 #ifdef DEB
43 static Standard_Boolean Affich = Standard_False;
44 #endif
45
46 //===================================================================================
47 // function :
48 // putpose  :
49 //===================================================================================
50 Bisector_Inter::Bisector_Inter() 
51 {
52 }
53
54 //===================================================================================
55 // function :
56 // putpose  :
57 //===================================================================================
58 Bisector_Inter::Bisector_Inter(const Bisector_Bisec&  C1, 
59                                const IntRes2d_Domain& D1, 
60                                const Bisector_Bisec&  C2, 
61                                const IntRes2d_Domain& D2, 
62                                const Standard_Real    TolConf, 
63                                const Standard_Real    Tol,
64                                const Standard_Boolean ComunElement) 
65 {
66   Perform (C1,D1,C2,D2,TolConf,Tol,ComunElement);
67 }
68
69 //===================================================================================
70 // function : ConstructSegment
71 // putpose  :
72 //===================================================================================
73 static Handle(Geom2d_Line) ConstructSegment(const gp_Pnt2d&     PMin,
74                                             const gp_Pnt2d&     PMax,
75                                             const Standard_Real UMin,
76 //                                          const Standard_Real UMax)
77                                             const Standard_Real )
78 {
79   gp_Dir2d Dir(PMax.X() - PMin.X(),PMax.Y() - PMin.Y());
80   Handle(Geom2d_Line) L = new Geom2d_Line (gp_Pnt2d(PMin.X() - UMin*Dir.X(),
81                                                     PMin.Y() - UMin*Dir.Y()),Dir);
82   return L;
83 }
84
85 //===================================================================================
86 // function : Perform
87 // putpose  :
88 //===================================================================================
89 void Bisector_Inter::Perform(const Bisector_Bisec&  C1,
90                              const IntRes2d_Domain& D1, 
91                              const Bisector_Bisec&  C2,
92                              const IntRes2d_Domain& D2,
93                              const Standard_Real    TolConf,
94                              const Standard_Real    Tol,
95                              const Standard_Boolean ComunElement) 
96 {
97   Handle(Bisector_Curve)    Bis1  = Handle(Bisector_Curve)::DownCast( C1.Value()->BasisCurve()); 
98   Handle(Bisector_Curve)    Bis2  = Handle(Bisector_Curve)::DownCast( C2.Value()->BasisCurve());
99
100   Handle(Geom2d_Curve)*  SBis1 = new Handle(Geom2d_Curve) [Bis1->NbIntervals()+1];
101   Handle(Geom2d_Curve)*  SBis2 = new Handle(Geom2d_Curve) [Bis2->NbIntervals()+1];
102   IntRes2d_Domain*       SD1   = new IntRes2d_Domain [Bis1->NbIntervals()+1];
103   IntRes2d_Domain*       SD2   = new IntRes2d_Domain [Bis2->NbIntervals()+1];
104
105   Standard_Integer NB1 = 0; Standard_Integer NB2 = 0;
106   Standard_Real    MinDomain,MaxDomain;
107   Standard_Real    UMin,UMax;
108   gp_Pnt2d         PMin,PMax;
109
110   //------------------------------------------------------
111   // Return Min Max domain1.
112   //------------------------------------------------------
113   if (D1.HasFirstPoint()) {MinDomain = D1.FirstParameter();}
114   else                    {MinDomain = RealFirst();        }
115
116   if (D1.HasLastPoint())  {MaxDomain = D1.LastParameter();}
117   else                    {MaxDomain = RealLast();        }
118
119   //----------------------------------------------------------
120   // Cutting the first curve by the intervals of
121   // continuity taking account of D1
122   //----------------------------------------------------------
123 //for (Standard_Integer IB1 = 1; IB1 <= Bis1->NbIntervals(); IB1++) {
124   Standard_Integer IB1;
125   for ( IB1 = 1; IB1 <= Bis1->NbIntervals(); IB1++) {
126     UMin = Bis1->IntervalFirst(IB1);
127     UMax = Bis1->IntervalLast (IB1);
128     if (UMax > MinDomain && UMin < MaxDomain) {
129       UMin = Max (UMin,MinDomain);
130       UMax = Min (UMax,MaxDomain);
131       PMin = Bis1->Value(UMin);
132       PMax = Bis1->Value(UMax);
133       SD1 [IB1].SetValues(PMin,UMin,D1.FirstTolerance(),
134                           PMax,UMax,D1.LastTolerance());
135
136       if ((IB1 == 1                   && Bis1->IsExtendAtStart()) || 
137           (IB1 == Bis1->NbIntervals() && Bis1->IsExtendAtEnd())    ){
138         //--------------------------------------------------------
139         // Part corresponding to an extension is a segment.     
140         //--------------------------------------------------------
141         SBis1 [IB1] = ConstructSegment (PMin,PMax,UMin,UMax);
142       }
143       else {
144         SBis1 [IB1] = Bis1;
145       }
146       NB1++;
147     }
148   }
149
150   //------------------------------------------------------
151   // Return Min Max domain2.
152   //------------------------------------------------------
153   if (D2.HasFirstPoint()) {MinDomain = D2.FirstParameter();}
154   else                    {MinDomain = RealFirst();        }
155
156   if (D2.HasLastPoint())  {MaxDomain = D2.LastParameter();}
157   else                    {MaxDomain = RealLast();        }
158
159   //----------------------------------------------------------
160   // Cut the second curve following the intervals of
161   // continuity taking account of D2
162   //----------------------------------------------------------
163 //for (Standard_Integer IB2 = 1; IB2 <= Bis2->NbIntervals(); IB2++) {
164   Standard_Integer IB2;
165   for ( IB2 = 1; IB2 <= Bis2->NbIntervals(); IB2++) {
166     UMin = Bis2->IntervalFirst(IB2);
167     UMax = Bis2->IntervalLast  (IB2);
168     if (UMax > MinDomain && UMin < MaxDomain) {
169       UMin = Max (UMin,MinDomain);
170       UMax = Min (UMax,MaxDomain);
171       PMin = Bis2->Value(UMin);
172       PMax = Bis2->Value(UMax);
173       SD2 [IB2].SetValues(PMin,UMin,D2.FirstTolerance(),
174                           PMax,UMax,D2.LastTolerance());
175
176       if ((IB2 == 1                   && Bis2->IsExtendAtStart()) || 
177           (IB2 == Bis1->NbIntervals() && Bis2->IsExtendAtEnd())    ){
178         //--------------------------------------------------------
179         // Part corresponding to an extension is a segment.     
180         //--------------------------------------------------------
181         SBis2 [IB2] = ConstructSegment (PMin,PMax,UMin,UMax);
182       }
183       else {
184         SBis2 [IB2] = Bis2;
185       }
186       NB2++;
187     }
188   }
189
190   //--------------------------------------------------------------
191   // Loop on the intersections of parts of each curve.
192   //--------------------------------------------------------------
193   for ( IB1 = 1; IB1 <= NB1; IB1++) {
194     for ( IB2 = 1; IB2 <= NB2; IB2++) {
195       SinglePerform(SBis1[IB1],SD1[IB1],
196                     SBis2[IB2],SD2[IB2],TolConf,Tol,ComunElement);
197     }
198   }
199   delete [] SBis1;
200   delete [] SBis2;
201   delete [] SD1;
202   delete [] SD2;
203 }
204
205 //===================================================================================
206 // function : SinglePerform
207 // putpose  :
208 //===================================================================================
209 void Bisector_Inter::SinglePerform(const Handle(Geom2d_Curve)&    CBis1,
210                                    const IntRes2d_Domain&         D1, 
211                                    const Handle(Geom2d_Curve)&    CBis2,
212                                    const IntRes2d_Domain&         D2,
213                                    const Standard_Real            TolConf,
214                                    const Standard_Real            Tol,
215                                    const Standard_Boolean         ComunElement) 
216 {
217   Handle(Geom2d_Curve)   Bis1 = CBis1;
218   Handle(Geom2d_Curve)   Bis2 = CBis2;
219
220   Handle(Standard_Type)  Type1 = Bis1->DynamicType();
221   Handle(Standard_Type)  Type2 = Bis2->DynamicType();
222
223   if (Type1 == STANDARD_TYPE(Bisector_BisecAna) || Type2 ==  STANDARD_TYPE(Bisector_BisecAna)) {      
224     Handle(Geom2d_Curve) C2Bis1,C2Bis2;
225     if (Type1 == STANDARD_TYPE(Bisector_BisecAna)) {
226       C2Bis1 = Handle(Bisector_BisecAna)::DownCast(Bis1)->Geom2dCurve();
227     }
228     else {
229       C2Bis1 = Bis1;
230     }
231     if (Type2 == STANDARD_TYPE(Bisector_BisecAna)) {
232       C2Bis2 = Handle(Bisector_BisecAna)::DownCast(Bis2)->Geom2dCurve();
233     }   
234     else {
235       C2Bis2 = Bis2;
236     }
237     Type1 = C2Bis1->DynamicType();
238     Type2 = C2Bis2->DynamicType();
239     if (Type1 == STANDARD_TYPE(Geom2d_Line) && Type2 != STANDARD_TYPE(Geom2d_Line)) {
240       TestBound(Handle(Geom2d_Line)::DownCast(C2Bis1),
241                 D1,C2Bis2,D2,TolConf,Standard_False);
242     }
243     else if (Type2 == STANDARD_TYPE(Geom2d_Line)&& Type1 != STANDARD_TYPE(Geom2d_Line)) {
244       TestBound(Handle(Geom2d_Line)::DownCast(C2Bis2),
245                 D2,C2Bis1,D1,TolConf,Standard_True);
246     }
247     Geom2dInt_GInter Intersect;
248     Geom2dAdaptor_Curve AC2Bis1(C2Bis1);
249     Geom2dAdaptor_Curve AC2Bis2(C2Bis2);
250     Intersect.Perform(AC2Bis1,D1,AC2Bis2,D2,TolConf,Tol);
251     Append (Intersect,D1.FirstParameter(),D1.LastParameter(),
252                       D2.FirstParameter(),D2.LastParameter());
253   }
254   else if (Type1 == STANDARD_TYPE(Bisector_BisecPC) || Type2 == STANDARD_TYPE(Bisector_BisecPC)) {
255     Geom2dInt_GInter Intersect;
256     Geom2dAdaptor_Curve ABis1(Bis1);
257     Geom2dAdaptor_Curve ABis2(Bis2);
258     Intersect.Perform(ABis1,D1,ABis2,D2,TolConf,Tol);
259     Append (Intersect,D1.FirstParameter(),D1.LastParameter(),
260                       D2.FirstParameter(),D2.LastParameter());
261   }
262   else if (ComunElement &&
263            Type1 == STANDARD_TYPE(Bisector_BisecCC) &&  Type2 == STANDARD_TYPE(Bisector_BisecCC)) {
264     NeighbourPerform(Handle(Bisector_BisecCC)::DownCast(Bis1),D1,
265                      Handle(Bisector_BisecCC)::DownCast(Bis2),D2,Tol);
266   }
267   else {
268     // If we are here one of two bissectrices is a segment.
269     // If one of bissectrices is not a segment, it is tested if 
270     // its extremities are on the straight line.
271
272     if (Type1 == STANDARD_TYPE(Geom2d_Line) && Type2 != STANDARD_TYPE(Geom2d_Line)) {
273       TestBound(Handle(Geom2d_Line)::DownCast(Bis1),
274                 D1,Bis2,D2,TolConf,Standard_False);
275     }
276     else if (Type2 == STANDARD_TYPE(Geom2d_Line)&& Type1 != STANDARD_TYPE(Geom2d_Line)) {
277       TestBound(Handle(Geom2d_Line)::DownCast(Bis2),
278                 D2,Bis1,D1,TolConf,Standard_True);
279     }
280     Geom2dInt_GInter Intersect;
281     Geom2dAdaptor_Curve ABis1(Bis1);
282     Geom2dAdaptor_Curve ABis2(Bis2);
283     Intersect.Perform(ABis1,D1,ABis2,D2,TolConf,Tol);
284     Append (Intersect,D1.FirstParameter(),D1.LastParameter(),
285                       D2.FirstParameter(),D2.LastParameter());
286   }
287
288 #ifdef DRAW
289   if (Affich) {
290     Handle(DrawTrSurf_Curve2d) dr;
291     Draw_Color                 Couleur = Draw_bleu;
292     
293     dr = new DrawTrSurf_Curve2d(Bis1,Couleur,100);
294     dout << dr;
295     dr = new DrawTrSurf_Curve2d(Bis2,Couleur,100);
296     dout << dr;
297     if (IsDone() && !IsEmpty()) {
298       for (Standard_Integer k = 1; k <= NbPoints(); k++) {
299         gp_Pnt2d P =  Point(k).Value();
300         Handle(Draw_Marker2D) drp  = new Draw_Marker2D(P,Draw_Plus,Draw_vert); 
301         dout << drp;
302       }
303     }
304     dout.Flush();
305   }
306 #endif  
307 }
308
309 //===================================================================================
310 // function : NeighbourPerform
311 // putpose  : Find the intersection of 2 neighbor bissectrices curve/curve
312 //            (ie Bis1 separates A and B and Bis2 separates B and C).
313 //            Bis1 is parameterized by B and Bis2 by C.
314 //
315 //            Method : Bis2 is parameterized by B 
316 //            2 bissectrices are thus parameterized by the same curve.
317 //            Let D1(u) = d(Bis1(u),B(u)) and D2(U) = d(Bis2(u),B(U))
318 //            Parameter U0 for which D1(U0)-D2(U0) = 0 is found.
319 //===================================================================================
320 void Bisector_Inter::NeighbourPerform(const Handle(Bisector_BisecCC)&  Bis1,
321                                       const IntRes2d_Domain&           D1, 
322                                       const Handle(Bisector_BisecCC)&  Bis2,
323                                       const IntRes2d_Domain&           D2,
324                                       const Standard_Real              Tol)
325 {
326   Standard_Real USol,U1,U2,Dist;
327   Standard_Real UMin =0.,UMax =0.;  
328   Standard_Real Eps = Precision::PConfusion();
329   gp_Pnt2d PSol;
330   
331   Handle(Geom2d_Curve)     Guide;
332   Handle(Bisector_BisecCC) BisTemp;
333
334   // Change guiedline on Bis2.
335   BisTemp      = Bis2->ChangeGuide();
336   Guide        = Bis2->Curve(2);
337 #ifdef DEB
338   gp_Pnt2d P2S = Bis2->ValueAndDist(D2.FirstParameter(),U1,UMax,Dist);
339   gp_Pnt2d P2E = Bis2->ValueAndDist(D2.LastParameter() ,U1,UMin,Dist);
340 #else
341   Bis2->ValueAndDist(D2.FirstParameter(),U1,UMax,Dist);
342   Bis2->ValueAndDist(D2.LastParameter() ,U1,UMin,Dist);
343 #endif
344   // Calculate the domain of intersection on the guideline.
345   UMin = Max (D1.FirstParameter(),UMin);
346   UMax = Min (D1.LastParameter() ,UMax);
347
348   done = Standard_True;
349
350   if (UMin - Eps > UMax + Eps) {return;}
351
352   // Solution F = 0 to find the common point.
353   Bisector_FunctionInter Fint (Guide,Bis1,BisTemp);
354   math_BissecNewton      Sol (Fint,UMin,UMax,Tol,20);
355   if (Sol.IsDone()) {
356     USol   = Sol.Root();
357   }
358   else { return; }
359
360   PSol    = BisTemp ->ValueAndDist(USol,U1,U2,Dist);
361   
362   IntRes2d_Transition        Trans1,Trans2;
363   IntRes2d_IntersectionPoint PointInterSol(PSol,USol,U2,
364                                            Trans1,Trans2,Standard_False);
365   Append (PointInterSol);
366 }
367
368
369
370 //=====================================================================================
371 // function : TestBound
372 // putpose  : Test if the extremities of Bis2 are on the segment cooresponding to Bis1.
373 //=====================================================================================
374 void Bisector_Inter::TestBound (const Handle(Geom2d_Line)&   Bis1,
375                                 const IntRes2d_Domain&       D1,
376                                 const Handle(Geom2d_Curve)&  Bis2,
377                                 const IntRes2d_Domain&       D2,
378                                 const Standard_Real          TolConf,
379                                 const Standard_Boolean       Reverse)
380 {
381   IntRes2d_Transition Trans1,Trans2;
382   IntRes2d_IntersectionPoint PointInterSol;
383
384   gp_Lin2d L1       = Bis1->Lin2d();
385   gp_Pnt2d PF       = Bis2->Value(D2.FirstParameter());
386   gp_Pnt2d PL       = Bis2->Value(D2.LastParameter());
387 //  Modified by skv - Mon May  5 14:43:28 2003 OCC616 Begin
388 //   Standard_Real Tol = Min(TolConf,Precision::Confusion());
389 //   Tol = 10*Tol;
390   Standard_Real Tol = TolConf;
391 //  Modified by skv - Mon May  5 14:43:30 2003 OCC616 End
392
393   Standard_Boolean BisecAlgo = Standard_False;
394   if (Bis2->DynamicType() == STANDARD_TYPE(Bisector_BisecCC))
395     {
396       BisecAlgo = Standard_True;
397 //  Modified by skv - Mon May  5 14:43:45 2003 OCC616 Begin
398 //       Tol = 1.e-5;
399 //  Modified by skv - Mon May  5 14:43:46 2003 OCC616 End
400     }
401
402   if (L1.Distance(PF) < Tol) {
403     Standard_Real U1 = ElCLib::Parameter(L1,PF);
404 //  Modified by skv - Mon May  5 14:48:12 2003 OCC616 Begin
405 //     if ( D1.FirstParameter() - Tol <= U1 &&
406 //       D1.LastParameter () + Tol >= U1   ) {
407     if ( D1.FirstParameter() - D1.FirstTolerance() < U1 &&
408          D1.LastParameter () + D1.LastTolerance()  > U1   ) {
409 //  Modified by skv - Mon May  5 14:48:14 2003 OCC616 End
410       // PF est sur L1
411       if (BisecAlgo)
412         PF = ElCLib::Value( U1 , L1 );
413       PointInterSol.SetValues (PF, U1, D2.FirstParameter(), 
414                                Trans1, Trans2, Reverse);
415       Append (PointInterSol);
416     }
417   }  
418
419   if (L1.Distance(PL) < Tol) {
420     Standard_Real U1 = ElCLib::Parameter(L1,PL);
421 //  Modified by skv - Mon May  5 15:05:48 2003 OCC616 Begin
422 //     if ( D1.FirstParameter() - Tol <= U1 &&
423 //       D1.LastParameter () + Tol >= U1   ) {
424     if ( D1.FirstParameter() - D1.FirstTolerance() < U1 &&
425          D1.LastParameter () + D1.LastTolerance()  > U1   ) {
426 //  Modified by skv - Mon May  5 15:05:49 2003 OCC616 End
427       if (BisecAlgo)
428         PL = ElCLib::Value( U1 , L1 );
429       PointInterSol.SetValues (PL, U1, D2.LastParameter(), 
430                                Trans1, Trans2, Reverse);
431       Append (PointInterSol);
432     }
433   }     
434 }