0027664: Incomplete intersection curve from the attached shapes
[occt.git] / src / IntPatch / IntPatch_PolyArc.cxx
1 // Created on: 1993-01-27
2 // Created by: Isabelle GRIGNON
3 // Copyright (c) 1993-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
18 #include <Adaptor2d_HCurve2d.hxx>
19 #include <Bnd_Box2d.hxx>
20 #include <gp_Pnt2d.hxx>
21 #include <IntPatch_PolyArc.hxx>
22 #include <Standard_ConstructionError.hxx>
23
24 inline void MinMax (const Standard_Real a1, const Standard_Real a2,
25                     Standard_Real& amin, Standard_Real& amax)
26 {
27   if (a1 < a2) {
28     amin = a1; amax = a2;
29   }
30   else {
31     amin = a2; amax = a1;
32   }
33 }
34
35 IntPatch_PolyArc::IntPatch_PolyArc(const Handle(Adaptor2d_HCurve2d)& Line ,
36                                    const Standard_Integer NbSample,
37                                    const Standard_Real aPdeb,
38                                    const Standard_Real aPfin,
39                                    const Bnd_Box2d& BoxOtherPolygon):
40                                    brise(1,Max(1,NbSample)),
41                                    param(1,Max(1,NbSample)),
42                                    offsetx(0.0),
43                                    offsety(0.0)
44 {
45   Standard_Real Pdeb = aPdeb;
46   Standard_Real Pfin = aPfin;
47   gp_Pnt2d p2d;
48   
49   if (Pdeb == RealFirst() || Pfin == RealLast() || NbSample <= 1) {
50     Standard_ConstructionError::Raise();
51   }
52   //----------------------------------------------------------------------
53   //-- On veut eviter les cas ou  le present polygone est beaucoup plus 
54   //-- grand que l objet en second.
55   //-- 
56   //-- Par exemple lorsque l objet en second est une ligne de cheminement
57   //-- qui contient de nombreux segments (>>100), une fleche nulle 
58   //-- et ce polygone quelques segments et une fleche qui contient
59   //-- toute la ligne de cheminement. 
60   //--
61   //-- Dans ce cas (tout un polygone compris dans la zone d influence)
62   //-- les calculs deviennent tres longs (N2)
63   //----------------------------------------------------------------------
64   Standard_Integer IndexInf = NbSample+1;
65   Standard_Integer IndexSup = 0;
66   
67   Standard_Real bx0,by0,bxmin,bxmax,bymin,bymax,r,r2;
68   
69   BoxOtherPolygon.Get(bxmin,bymin,bxmax,bymax);
70   r=(bxmax-bxmin)+(bymax-bymin);
71   bx0=(bxmax+bxmin)*0.5;
72   by0=(bymax+bymin)*0.5;
73   
74   Standard_Real Pas;
75   Standard_Real X,Y,Xs,Ys,Xm,Ym,XXs,YYs;
76   
77   r*=0.8;
78   r2 = r*r*49.;
79   Standard_Integer nbloop=0;
80   
81   do { 
82     nbloop++;
83     Pas = (Pfin-Pdeb)/(NbSample-1);
84     param(1) = Pdeb;
85     Line->D0(Pdeb,p2d);
86     Xs = p2d.X(); Ys = p2d.Y();
87     brise(1).SetCoord(Xs,Ys);
88     
89     myBox.SetVoid();
90     
91     myBox.Add(brise(1));
92     myError =0.;
93     
94     for (Standard_Integer i =2; i<=NbSample;i++) {
95       param(i) = Pdeb + (i-1)*Pas;
96       Line->D0(param(i),p2d);
97       X = p2d.X(); Y = p2d.Y();
98       brise(i).SetCoord(X,Y);
99       XXs = 0.5*(Xs+X);
100       YYs = 0.5*(Ys+Y);
101       //------------------------------------------------------------
102       //-- On recherche le debut et la fin de la zone significative
103       //------------------------------------------------------------
104       // MSV: (see cda 002 H2) if segment is too large (>>r) we have
105       //      a risk to jump through BoxOtherPolygon, therefore we should
106       //      check this condition if the first one is failure.
107       Standard_Boolean isMidPtInBox = (Abs(bx0-XXs) + Abs(by0-YYs)) < r;
108       Standard_Boolean isSegOut = Standard_True;
109       if(!isMidPtInBox) {
110         Standard_Real d = (X-Xs)*(X-Xs)+(Y-Ys)*(Y-Ys);
111         if (d > r2) {
112           Standard_Real xmin,xmax,ymin,ymax;
113           MinMax (Xs,X, xmin,xmax);
114           MinMax (Ys,Y, ymin,ymax);
115           isSegOut = (xmax < bxmin || xmin > bxmax ||
116                       ymax < bymin || ymin > bymax);
117         }
118       }
119       if(isMidPtInBox || !isSegOut) { 
120         // MSV: take the previous and the next segments too, because of
121         //      we check only the middle point (see BUC60946)
122         //if(IndexInf>i) IndexInf=i-1;
123         //if(IndexSup<i) IndexSup=i;
124         if(IndexInf>i) IndexInf=Max(i-2,1);
125         if(IndexSup<i) IndexSup=Min(i+1,NbSample);
126       }
127       
128       myBox.Add(brise(i));
129       Line->D0(param(i)-Pas*0.5,p2d);
130       Xm = p2d.X() - XXs;
131       Ym = p2d.Y() - YYs;
132       Xm = Sqrt(Xm*Xm+Ym*Ym);
133       myError =Max (myError , Xm);
134       Xs = X;
135       Ys = Y;
136     }
137     if(IndexInf > IndexSup) { 
138       r+=r; 
139       r2 = r*r*49.;
140       //-- cout<<" Le rayon : "<<r<<" est insuffisant "<<endl;
141     }
142     else {
143       //----------------------------------------------
144       //-- Si le nombre de points significatifs est
145       //-- insuffisant, on reechantillonne une fois
146       //-- encore
147       //----------------------------------------------
148       if((IndexSup-IndexInf)<(NbSample/2)) { 
149         //-- cout<<" --- On remet ca entre les index "<<IndexInf<<" et "<<IndexSup<<endl;
150         nbloop = 10;
151         //if(IndexInf>1) IndexInf--;
152         //if(IndexSup<NbSample) IndexSup++;
153         Pdeb = param(IndexInf); 
154         Pfin = param(IndexSup);
155         //IndexInf = IndexSup+1;
156         IndexInf = NbSample+1;
157         IndexSup = 0;
158       }
159     }
160   }
161   while((IndexInf > IndexSup) && nbloop<=10); 
162   myError*=1.2;
163   if(myError<0.00000001) 
164     myError = 0.00000001;
165   myBox.Enlarge(myError);
166
167   ferme = (Line->Value(aPdeb).Distance(Line->Value(aPfin)) <= 1e-7);
168 }
169
170 Standard_Boolean IntPatch_PolyArc::Closed() const { return ferme;}
171
172 Standard_Integer IntPatch_PolyArc::NbPoints() const {return brise.Length();}
173
174 gp_Pnt2d IntPatch_PolyArc::Point(const Standard_Integer Index ) const 
175
176   if(offsetx == 0.0 && offsety==0.0) 
177     return(brise(Index));
178   
179   const gp_Pnt2d& P = brise(Index);
180   return (gp_Pnt2d(P.X()+offsetx,P.Y()+offsety));
181 }
182
183 Standard_Real IntPatch_PolyArc::Parameter(const Standard_Integer Index ) const
184 { return param(Index);}
185
186
187 void IntPatch_PolyArc::SetOffset(const Standard_Real ox,const Standard_Real oy) { 
188   Standard_Real xmin,ymin,xmax,ymax,g;
189   myBox.Get(xmin,ymin,xmax,ymax);
190   g = myBox.GetGap();
191   
192   myBox.SetVoid();
193   
194   myBox.Update(xmin-offsetx,ymin-offsety,
195                xmax-offsetx,ymax-offsety);
196   offsetx = ox;
197   offsety = oy;
198   myBox.Update(xmin+offsetx,ymin+offsety,
199                xmax+offsetx,ymax+offsety);
200   myBox.SetGap(g);
201 }