0028486: Fuse of several solids fails due to presence of common zones between faces
[occt.git] / src / ProjLib / ProjLib_Sphere.cxx
1 // Created on: 1993-08-24
2 // Created by: Bruno DUMORTIER
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 //  Modified by skv - Tue Aug  1 16:29:59 2006 OCC13116
18
19 #include <ElCLib.hxx>
20 #include <gp.hxx>
21 #include <gp_Circ.hxx>
22 #include <gp_Elips.hxx>
23 #include <gp_Hypr.hxx>
24 #include <gp_Lin.hxx>
25 #include <gp_Parab.hxx>
26 #include <gp_Sphere.hxx>
27 #include <gp_Trsf2d.hxx>
28 #include <gp_Vec.hxx>
29 #include <gp_Vec2d.hxx>
30 #include <Precision.hxx>
31 #include <ProjLib_Sphere.hxx>
32 #include <Standard_NoSuchObject.hxx>
33 #include <Standard_NotImplemented.hxx>
34 #include <StdFail_NotDone.hxx>
35
36 //=======================================================================
37 //function : ProjLib_Sphere
38 //purpose  : 
39 //=======================================================================
40 ProjLib_Sphere::ProjLib_Sphere()
41 {
42 }
43
44
45 //=======================================================================
46 //function : ProjLib_Sphere
47 //purpose  : 
48 //=======================================================================
49
50 ProjLib_Sphere::ProjLib_Sphere(const gp_Sphere& Sp)
51 {
52   Init(Sp);
53 }
54
55
56 //=======================================================================
57 //function : ProjLib_Sphere
58 //purpose  : 
59 //=======================================================================
60
61 ProjLib_Sphere::ProjLib_Sphere(const gp_Sphere& Sp, const gp_Circ& C)
62 {
63   Init(Sp);
64   Project(C);
65 }
66
67
68 //=======================================================================
69 //function : Init
70 //purpose  : 
71 //=======================================================================
72
73 void  ProjLib_Sphere::Init(const gp_Sphere& Sp)
74 {
75   myType = GeomAbs_OtherCurve;
76   mySphere = Sp;
77   myIsPeriodic = Standard_False;
78   isDone = Standard_False;
79 }
80
81
82 //=======================================================================
83 //function : EvalPnt2d / EvalDir2d
84 //purpose  : returns the Projected Pnt / Dir in the parametrization range
85 //           of mySphere.
86 //           P is a point on a sphere with the same Position as Sp,
87 //           but with a radius equal to 1. ( in order to avoid to divide
88 //           by Radius)
89 //                / X = cosV cosU        U = Atan(Y/X)
90 //            P = | Y = cosV sinU   ==>
91 //                \ Z = sinV             V = ASin( Z)
92 //=======================================================================
93
94 static gp_Pnt2d EvalPnt2d( const gp_Vec P, const gp_Sphere& Sp)
95 {
96   Standard_Real X = P.Dot(gp_Vec(Sp.Position().XDirection()));
97   Standard_Real Y = P.Dot(gp_Vec(Sp.Position().YDirection()));
98   Standard_Real Z = P.Dot(gp_Vec(Sp.Position().Direction()));
99   Standard_Real U,V;
100
101   if ( Abs(X) > Precision::PConfusion() ||
102        Abs(Y) > Precision::PConfusion() ) {
103     Standard_Real UU = ATan2(Y,X);
104     U = ElCLib::InPeriod(UU, 0., 2*M_PI);
105   }
106   else {
107     U = 0.;
108   }
109
110   if ( Z > 1.) 
111     Z = 1.;
112   else if ( Z < -1.) 
113     Z = -1.;
114   V = ASin ( Z);
115
116   return gp_Pnt2d( U, V);
117 }
118
119
120 //=======================================================================
121 //function : Project
122 //purpose  : 
123 //=======================================================================
124
125 void  ProjLib_Sphere::Project(const gp_Circ& C)
126 {
127   gp_Pnt O;           // O Location of Sp;
128   gp_Dir Xc, Yc, Zc;  // X Y Z Direction of C; 
129   gp_Dir Xs, Ys, Zs;  // X Y Z Direction of Sp;
130   
131   //Check the validity :
132   //                     Xc & Yc must be perpendicular to Zs ->IsoV;
133   //                     O,Zs is in the Plane O,Xc,Yc;       ->IsoU;
134   
135   O  = mySphere.Location();
136   Xc = C.Position().XDirection();
137   Yc = C.Position().YDirection();
138   Zc = Xc ^ Yc;
139   Xs = mySphere.Position().XDirection();
140   Ys = mySphere.Position().YDirection();
141   Zs = mySphere.Position().Direction();
142   
143   Standard_Boolean isIsoU, isIsoV;
144   Standard_Real Tol = Precision::Confusion();
145
146   isIsoU = Zc.IsNormal(Zs,Tol) && O.IsEqual(C.Location(),Tol);
147   isIsoV = Xc.IsNormal(Zs,Tol) && Yc.IsNormal(Zs,Tol); 
148   
149   gp_Pnt2d P2d1, P2d2;
150   gp_Dir2d D2d;
151
152   if ( isIsoU) {  
153     myType = GeomAbs_Line;
154     
155     P2d1 = EvalPnt2d(gp_Vec(Xc),mySphere);
156     P2d2 = EvalPnt2d(gp_Vec(Yc),mySphere);
157     
158     if (isIsoU && (Abs(P2d1.Y()-M_PI/2.) < Precision::PConfusion() ||
159                    Abs(P2d1.Y()+M_PI/2.) < Precision::PConfusion()   )) {
160       // then P1 is on the apex of the sphere and U is undefined
161       // The value of U is given by P2d2.Y() .
162       P2d1.SetX(P2d2.X());
163     }
164     else if ( Abs( Abs(P2d1.X()-P2d2.X()) - M_PI) < Precision::PConfusion()) {
165       // then we have U2 = U1 + PI; V2;
166       // we have to assume that U1 = U2 
167       //   so V2 = PI - V2;
168       P2d2.SetX( P2d1.X());
169       if (P2d2.Y() < 0.) 
170         P2d2.SetY( -M_PI - P2d2.Y());
171       else
172         P2d2.SetY(  M_PI - P2d2.Y());
173     }
174     else {
175       P2d2.SetX( P2d1.X());
176     }
177     
178     D2d = gp_Dir2d(gp_Vec2d(P2d1,P2d2));
179     isDone = Standard_True;
180   }
181   else if ( isIsoV) {
182     myType = GeomAbs_Line;
183     
184     //P2d(U,V) :first point of the PCurve.
185     Standard_Real U = Xs.AngleWithRef(Xc, Xs^Ys);
186     if (U<0) 
187       U += 2*M_PI;
188     Standard_Real Z = gp_Vec(O,C.Location()).Dot(Zs);
189     Standard_Real V = ASin(Z/mySphere.Radius());
190     P2d1 = gp_Pnt2d(U,V);
191     D2d = gp_Dir2d((Xc^Yc).Dot(Xs^Ys) ,0.);
192     isDone = Standard_True;
193   }
194   myLin = gp_Lin2d(P2d1, D2d);
195 }
196
197
198 void  ProjLib_Sphere::Project(const gp_Lin& L)
199 {
200  ProjLib_Projector::Project(L);
201 }
202
203 void  ProjLib_Sphere::Project(const gp_Elips& E)
204 {
205  ProjLib_Projector::Project(E);
206 }
207
208 void  ProjLib_Sphere::Project(const gp_Parab& P)
209 {
210  ProjLib_Projector::Project(P);
211 }
212
213 void  ProjLib_Sphere::Project(const gp_Hypr& H)
214 {
215  ProjLib_Projector::Project(H);
216 }
217
218
219 //=======================================================================
220 //function : SetInBounds
221 //purpose  : 
222 //=======================================================================
223
224 void ProjLib_Sphere::SetInBounds(const Standard_Real U) 
225 {
226   StdFail_NotDone_Raise_if( !isDone, "ProjLib_Sphere:SetInBounds");
227   
228   // first set the y of the first point in -pi/2 pi/2
229   Standard_Real newY, Y = ElCLib::Value(U,myLin).Y();
230   newY = ElCLib::InPeriod( Y, -M_PI, M_PI);
231   
232   myLin.Translate(gp_Vec2d(0.,newY-Y));
233
234   gp_Pnt2d P = ElCLib::Value(U,myLin);
235   gp_Trsf2d Trsf;
236   gp_Ax2d   Axis;
237   Standard_Real Tol = 1.e-7;
238   gp_Dir2d D2d = myLin.Direction();
239 //  Modified by skv - Tue Aug  1 16:29:59 2006 OCC13116 Begin
240 //   if ((P.Y() > M_PI/2) || 
241   if ((P.Y() - M_PI/2 > Tol) || 
242 //  Modified by skv - Tue Aug  1 16:29:59 2006 OCC13116 End
243       (Abs(P.Y()-M_PI/2)<Tol && D2d.IsEqual(gp::DY2d(),Tol))) {
244     Axis = gp_Ax2d( gp_Pnt2d( 0., M_PI/2.), gp::DX2d());
245   }
246 //  Modified by skv - Tue Aug  1 16:29:59 2006 OCC13116 Begin
247 //   else if ((P.Y() < -M_PI/2) || 
248   else if ((P.Y() + M_PI/2 < -Tol) || 
249 //  Modified by skv - Tue Aug  1 16:29:59 2006 OCC13116 End
250            (Abs(P.Y()+M_PI/2)<Tol && D2d.IsOpposite(gp::DY2d(),Tol))) {
251     Axis = gp_Ax2d( gp_Pnt2d( 0., -M_PI/2.), gp::DX2d());
252   }
253   else 
254     return;
255
256   Trsf.SetMirror(Axis);
257   myLin.Transform(Trsf);
258
259   myLin.Translate(gp_Vec2d(M_PI,0.));
260
261   // il faut maintenant recadrer en U
262   Standard_Real newX, X = ElCLib::Value(U,myLin).X();
263   newX = ElCLib::InPeriod( X, 0., 2.*M_PI);
264   myLin.Translate(gp_Vec2d(newX-X,0.));
265 }