0022683: Incorrect result of Select3D_Projector::Project() in the case of perspective...
[occt.git] / src / Select3D / Select3D_Projector.cxx
1 // File:        Select3D_Projector.cxx
2 // Created:     Fri Mar 13 11:08:32 1992
3 // Author:      Christophe MARION
4 //              <cma@sdsun2>
5
6 #define IMP240100       //GG
7 //                      Change RefToPix()/Convert() to Project() method.
8
9 #include <Select3D_Projector.ixx>
10 #include <Precision.hxx>
11 #include <gp_Ax3.hxx>
12 #include <gp_Vec.hxx>
13 #include <gp_Vec2d.hxx>
14
15 // formula for derivating a perspective, from Mathematica
16
17 //        X'[t]      X[t] Z'[t]
18 // D1 =  -------- + -------------
19 //           Z[t]          Z[t] 2
20 //       1 - ----   f (1 - ----)
21 //            f             f
22
23 //=======================================================================
24 //function : Select3D_Projector
25 //purpose  :
26 //=======================================================================
27
28 Select3D_Projector::Select3D_Projector(const Handle(V3d_View)& aViou)
29 : myPersp(aViou->Type()==V3d_PERSPECTIVE),
30   myFocus(aViou->Focale()),
31   myView(aViou),
32   myDepthMin(-Precision::Infinite()),
33   myDepthMax( Precision::Infinite())
34 {
35   Standard_Real Xat,Yat,Zat,XUp,YUp,ZUp,DX,DY,DZ;
36   //Standard_Boolean Pers=Standard_False;
37
38   aViou->At(Xat,Yat,Zat);
39   aViou->Up(XUp,YUp,ZUp);
40   aViou->Proj(DX,DY,DZ);
41   gp_Pnt At (Xat,Yat,Zat);
42   gp_Dir Zpers (DX,DY,DZ);
43   gp_Dir Ypers (XUp,YUp,ZUp);
44   gp_Dir Xpers = Ypers.Crossed(Zpers);
45   gp_Ax3 Axe (At, Zpers, Xpers);
46   myScaledTrsf.SetTransformation(Axe);
47   myGTrsf.SetTrsf(myScaledTrsf);
48   Scaled();
49
50 }
51
52 //=======================================================================
53 //function : Select3D_Projector
54 //purpose  :
55 //=======================================================================
56
57 Select3D_Projector::Select3D_Projector()
58 : myPersp(Standard_False),
59   myFocus(0),
60   myDepthMin(-Precision::Infinite()),
61   myDepthMax( Precision::Infinite())
62 {
63   Scaled();
64 }
65
66 //=======================================================================
67 //function : Select3D_Projector
68 //purpose  :
69 //=======================================================================
70
71 Select3D_Projector::Select3D_Projector (const gp_Ax2& CS)
72 : myPersp(Standard_False),
73   myFocus(0),
74   myDepthMin(-Precision::Infinite()),
75   myDepthMax( Precision::Infinite())
76 {
77   myScaledTrsf.SetTransformation(CS);
78   myGTrsf.SetTrsf(myScaledTrsf);
79   Scaled();
80 }
81
82 //=======================================================================
83 //function : Select3D_Projector
84 //purpose  :
85 //=======================================================================
86
87 Select3D_Projector::Select3D_Projector (const gp_Ax2& CS,
88                                         const Standard_Real Focus)
89 : myPersp(Standard_True),
90   myFocus(Focus),
91   myDepthMin(-Precision::Infinite()),
92   myDepthMax( Precision::Infinite())
93 {
94   myScaledTrsf.SetTransformation(CS);
95   myGTrsf.SetTrsf(myScaledTrsf);
96   Scaled();
97 }
98
99 //=======================================================================
100 //function : Select3D_Projector
101 //purpose  :
102 //=======================================================================
103
104 Select3D_Projector::Select3D_Projector (const gp_Trsf& T,
105                                         const Standard_Boolean Persp,
106                                         const Standard_Real Focus)
107 : myPersp(Persp),
108   myFocus(Focus),
109   myScaledTrsf(T),
110   myDepthMin(-Precision::Infinite()),
111   myDepthMax( Precision::Infinite())
112 {
113   myGTrsf.SetTrsf(myScaledTrsf);
114   Scaled();
115 }
116
117 //=======================================================================
118 //function : Select3D_Projector
119 //purpose  :
120 //=======================================================================
121
122 Select3D_Projector::Select3D_Projector (const gp_GTrsf& GT,
123                                         const Standard_Boolean Persp,
124                                         const Standard_Real Focus)
125 : myPersp(Persp),
126   myFocus(Focus),
127   myGTrsf(GT),
128   myDepthMin(-Precision::Infinite()),
129   myDepthMax( Precision::Infinite())
130 {
131   Scaled();
132 }
133
134 //=======================================================================
135 //function : Set
136 //purpose  :
137 //=======================================================================
138
139 void Select3D_Projector::Set
140   (const gp_Trsf& T,
141    const Standard_Boolean Persp,
142    const Standard_Real Focus)
143 {
144   myPersp      = Persp;
145   myFocus      = Focus;
146   myScaledTrsf = T;
147   Scaled();
148 }
149
150 //=======================================================================
151 //function : Scaled
152 //purpose  :
153 //=======================================================================
154
155 #include <gp_Mat.hxx>
156
157 static Standard_Integer TrsfType(const gp_GTrsf& Trsf) {
158   const gp_Mat& Mat = Trsf.VectorialPart();
159   if(   (Abs(Mat.Value(1,1)-1.0) < 1e-15)
160      && (Abs(Mat.Value(2,2)-1.0) < 1e-15)
161      && (Abs(Mat.Value(3,3)-1.0) < 1e-15)) {
162     return(1); //-- top
163   }
164   else if(   (Abs(Mat.Value(1,1)-0.7071067811865476) < 1e-15)
165           && (Abs(Mat.Value(1,2)+0.5) < 1e-15)
166           && (Abs(Mat.Value(1,3)-0.5) < 1e-15)
167
168           && (Abs(Mat.Value(2,1)-0.7071067811865476) < 1e-15)
169           && (Abs(Mat.Value(2,2)-0.5) < 1e-15)
170           && (Abs(Mat.Value(2,3)+0.5) < 1e-15)
171
172           && (Abs(Mat.Value(3,1)) < 1e-15)
173           && (Abs(Mat.Value(3,2)-0.7071067811865476) < 1e-15)
174           && (Abs(Mat.Value(3,3)-0.7071067811865476) < 1e-15)) {
175     return(0); //--
176   }
177   else if(   (Abs(Mat.Value(1,1)-1.0) < 1e-15)
178           && (Abs(Mat.Value(2,3)-1.0) < 1e-15)
179           && (Abs(Mat.Value(3,2)+1.0) < 1e-15)) {
180     return(2); //-- front
181   }
182   else if(   (Abs(Mat.Value(1,1)-0.7071067811865476) < 1e-15)
183           && (Abs(Mat.Value(1,2)-0.7071067811865476) < 1e-15)
184           && (Abs(Mat.Value(1,3)) < 1e-15)
185
186           && (Abs(Mat.Value(2,1)+0.5) < 1e-15)
187           && (Abs(Mat.Value(2,2)-0.5) < 1e-15)
188           && (Abs(Mat.Value(2,3)-0.7071067811865476) < 1e-15)
189
190           && (Abs(Mat.Value(3,1)-0.5) < 1e-15)
191           && (Abs(Mat.Value(3,2)+0.5) < 1e-15)
192           && (Abs(Mat.Value(3,3)-0.7071067811865476) < 1e-15)) {
193     return(3); //-- axo
194   }
195   return(-1);
196 }
197
198 void Select3D_Projector::Scaled (const Standard_Boolean On)
199 {
200   myType=-1;
201   if (!On) {
202     if (!myPersp) {
203       //myGTrsf.SetTranslationPart(gp_XYZ(0.,0.,0.));
204       myType=TrsfType(myGTrsf);
205     }
206   }
207   myInvTrsf = myGTrsf;
208   myInvTrsf.Invert();
209 }
210
211 //=======================================================================
212 //function : Project
213 //purpose  :
214 //=======================================================================
215
216 void Select3D_Projector::Project (const gp_Pnt& P, gp_Pnt2d& Pout) const
217 {
218
219   if(!myView.IsNull()){
220     Standard_Real Xout,Yout;
221 //    V3d_View
222 #ifdef IMP240100
223     myView->Project(P.X(),P.Y(),P.Z(),Xout,Yout);
224 #else
225     Standard_Integer Xp,Yp;
226     myView->RefToPix(P.X(),P.Y(),P.Z(),Xp,Yp);
227     myView->Convert(Xp,Yp,Xout,Yout);
228 #endif
229     Pout.SetCoord(Xout,Yout);
230   }
231   else{
232     if(myType!=-1) {
233       Standard_Real X,Y;
234       switch (myType) {
235       case 0: {  //-- axono standard
236         Standard_Real x07 = P.X()*0.7071067811865475;
237         Standard_Real y05 = P.Y()*0.5;
238         Standard_Real z05 = P.Z()*0.5;
239         X=x07-y05+z05;
240         Y=x07+y05-z05;
241         //-- Z=0.7071067811865475*(P.Y()+P.Z());
242         break;
243       }
244       case 1: { //-- top
245         X=P.X(); Y=P.Y(); //-- Z=P.Z();
246         Pout.SetCoord(X,Y);
247         break;
248       }
249       case 2: {
250         X=P.X(); Y=P.Z(); //-- Z=-P.Y();
251         Pout.SetCoord(X,Y);
252         break;
253       }
254       case 3: {
255         Standard_Real xmy05 = (P.X()-P.Y())*0.5;
256         Standard_Real z07 = P.Z()*0.7071067811865476;
257         X=0.7071067811865476*(P.X()+P.Y());
258         Y=-xmy05+z07;
259         Pout.SetCoord(X,Y);
260         //-- Z= xmy05+z07;
261         break;
262       }
263       default: {
264         gp_Pnt P2 = P;
265         Transform(P2);
266         if (myPersp) {
267           Standard_Real R = 1.-P2.Z()/myFocus;
268           Pout.SetCoord(P2.X()/R,P2.Y()/R);
269         }
270         else
271           Pout.SetCoord(P2.X(),P2.Y());
272         break;
273       }
274       }
275     }
276     else {
277       gp_Pnt P2 = P;
278       Transform(P2);
279       if (myPersp) {
280         Standard_Real R = 1.-P2.Z()/myFocus;
281         Pout.SetCoord(P2.X()/R,P2.Y()/R);
282       }
283       else
284         Pout.SetCoord(P2.X(),P2.Y());
285     }
286   }
287
288
289 }
290
291 //=======================================================================
292 //function : Project
293 //purpose  :
294 //=======================================================================
295 /*  ====== TYPE 0  (??)
296    (0.7071067811865476, -0.5               ,  0.4999999999999999)
297    (0.7071067811865475,  0.5000000000000001, -0.5              )
298    (0.0,                 0.7071067811865475,  0.7071067811865476)
299
300   ====== TYPE 1 (top)
301 (1.0, 0.0, 0.0)
302 (0.0, 1.0, 0.0)
303 (0.0, 0.0, 1.0)
304
305  ======= TYPE 2 (front)
306 (1.0,  0.0                   , 0.0)
307 (0.0,  1.110223024625157e-16 , 1.0)
308 (0.0, -1.0                   , 1.110223024625157e-16)
309
310  ======= TYPE 3
311 ( 0.7071067811865476, 0.7071067811865475, 0.0)
312 (-0.5               , 0.5000000000000001, 0.7071067811865475)
313 ( 0.4999999999999999, -0.5              , 0.7071067811865476)
314 */
315 void Select3D_Projector::Project (const gp_Pnt& P,
316                                  Standard_Real& X,
317                                  Standard_Real& Y,
318                                  Standard_Real& Z) const
319 {
320   if(!myView.IsNull()){
321 //    Standard_Real Xout,Yout;
322 //    V3d_View
323 #ifdef IMP240100
324     myView->Project(P.X(),P.Y(),P.Z(),X,Y);
325 #else
326     Standard_Integer Xp,Yp;
327     myView->RefToPix(P.X(),P.Y(),P.Z(),Xp,Yp);
328     myView->Convert(Xp,Yp,X,Y);
329 #endif
330   }
331   else{
332     if(myType!=-1) {
333       switch (myType) {
334       case 0: {  //-- axono standard
335         Standard_Real x07 = P.X()*0.7071067811865475;
336         Standard_Real y05 = P.Y()*0.5;
337         Standard_Real z05 = P.Z()*0.5;
338         X=x07-y05+z05;
339         Y=x07+y05-z05;
340         Z=0.7071067811865475*(P.Y()+P.Z());
341         break;
342       }
343       case 1: { //-- top
344         X=P.X(); Y=P.Y(); Z=P.Z();
345         break;
346       }
347       case 2: {
348         X=P.X(); Y=P.Z(); Z=-P.Y();
349         break;
350       }
351       case 3: {
352         Standard_Real xmy05 = (P.X()-P.Y())*0.5;
353         Standard_Real z07 = P.Z()*0.7071067811865476;
354         X=0.7071067811865476*(P.X()+P.Y());
355         Y=-xmy05+z07;
356         Z= xmy05+z07;
357         break;
358       }
359       default: {
360         gp_Pnt P2 = P;
361         Transform(P2);
362         P2.Coord(X,Y,Z);
363         break;
364       }
365       }
366     }
367     else {
368       gp_Pnt P2 = P;
369       Transform(P2);
370       P2.Coord(X,Y,Z);
371       if (myPersp) {
372         Standard_Real R = 1 - Z / myFocus;
373         X = X / R;
374         Y = Y / R;
375       }
376     }
377   }
378 }
379 //=======================================================================
380 //function : Project
381 //purpose  :
382 //=======================================================================
383
384 void Select3D_Projector::Project (const gp_Pnt& P,
385                                  const gp_Vec& D1,
386                                  gp_Pnt2d& Pout,
387                                  gp_Vec2d& D1out) const
388 {
389   gp_Pnt PP = P;
390   Transform(PP);
391   gp_Vec DD1 = D1;
392   Transform(DD1);
393   if (myPersp) {
394     Standard_Real R = 1. - PP.Z() / myFocus;
395     Pout .SetCoord(PP .X()/R , PP.Y()/R);
396     D1out.SetCoord(DD1.X()/R + PP.X()*DD1.Z()/(myFocus * R*R),
397                    DD1.Y()/R + PP.Y()*DD1.Z()/(myFocus * R*R));
398   }
399   else {
400     Pout .SetCoord(PP .X(),PP .Y());
401     D1out.SetCoord(DD1.X(),DD1.Y());
402   }
403 }
404
405
406 //=======================================================================
407 //function : Shoot
408 //purpose  :
409 //=======================================================================
410
411 gp_Lin Select3D_Projector::Shoot
412   (const Standard_Real X,
413    const Standard_Real Y) const
414 {
415   gp_Lin L;
416
417   if (myPersp) {
418     L = gp_Lin(gp_Pnt(0,0, myFocus),
419                gp_Dir(X,Y,-myFocus));
420   }
421   else {
422     L = gp_Lin(gp_Pnt(X,Y,0),
423                gp_Dir(0,0,-1));
424   }
425   Transform(L, myInvTrsf);
426   return L;
427 }
428
429
430 void Select3D_Projector::SetView(const Handle(V3d_View)& aViou)
431 {
432   myView = aViou;
433   myPersp = aViou->Type()==V3d_PERSPECTIVE;
434   myFocus= aViou->Focale();
435   Standard_Real Xat,Yat,Zat,XUp,YUp,ZUp,DX,DY,DZ;
436   //Standard_Boolean Pers=Standard_False;
437
438   aViou->At(Xat,Yat,Zat);
439   aViou->Up(XUp,YUp,ZUp);
440   aViou->Proj(DX,DY,DZ);
441   gp_Pnt At (Xat,Yat,Zat);
442   gp_Dir Zpers (DX,DY,DZ);
443   gp_Dir Ypers (XUp,YUp,ZUp);
444   gp_Dir Xpers = Ypers.Crossed(Zpers);
445   gp_Ax3 Axe (At, Zpers, Xpers);
446   myScaledTrsf.SetTransformation(Axe);
447   Scaled();
448
449 }
450
451 void Select3D_Projector::DepthMinMax (const Standard_Real theDepthMin,
452                                       const Standard_Real theDepthMax)
453 {
454   myDepthMin = theDepthMin;
455   myDepthMax = theDepthMax;
456 }