0025624: Visualization - selection is incorrect in perspective mode in a specific...
[occt.git] / src / Select3D / Select3D_Projector.cxx
1 // Created on: 1992-03-13
2 // Created by: Christophe MARION
3 // Copyright (c) 1992-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 <Select3D_Projector.ixx>
18 #include <Precision.hxx>
19 #include <gp_Ax3.hxx>
20 #include <gp_Vec.hxx>
21 #include <gp_Vec2d.hxx>
22 #include <gp_Mat.hxx>
23 #include <Graphic3d_Vec4.hxx>
24
25 namespace
26 {
27   //=======================================================================
28   //function : TrsfType
29   //purpose  :
30   //=======================================================================
31   static Standard_Integer TrsfType(const gp_GTrsf& theTrsf)
32   {
33     const gp_Mat& aMat = theTrsf.VectorialPart();
34     if ((Abs (aMat.Value (1, 1) - 1.0) < 1e-15)
35      && (Abs (aMat.Value (2, 2) - 1.0) < 1e-15)
36      && (Abs (aMat.Value (3, 3) - 1.0) < 1e-15))
37     {
38       return 1; // top
39     }
40     else if ((Abs (aMat.Value (1, 1) - 0.7071067811865476) < 1e-15)
41           && (Abs (aMat.Value (1, 2) + 0.5) < 1e-15)
42           && (Abs (aMat.Value (1, 3) - 0.5) < 1e-15)
43           && (Abs (aMat.Value (2, 1) - 0.7071067811865476) < 1e-15)
44           && (Abs (aMat.Value (2, 2) - 0.5) < 1e-15)
45           && (Abs (aMat.Value (2, 3) + 0.5) < 1e-15)
46           && (Abs (aMat.Value (3, 1)) < 1e-15)
47           && (Abs (aMat.Value (3, 2) - 0.7071067811865476) < 1e-15)
48           && (Abs (aMat.Value (3, 3) - 0.7071067811865476) < 1e-15))
49     {
50       return 0; // inverse axo
51     }
52     else if ((Abs (aMat.Value (1, 1) - 1.0) < 1e-15)
53           && (Abs (aMat.Value (2, 3) - 1.0) < 1e-15)
54           && (Abs (aMat.Value (3, 2) + 1.0) < 1e-15))
55     {
56       return 2; // front
57     }
58     else if ((Abs (aMat.Value (1, 1) - 0.7071067811865476) < 1e-15)
59           && (Abs (aMat.Value (1, 2) - 0.7071067811865476) < 1e-15)
60           && (Abs (aMat.Value (1, 3)) < 1e-15)
61           && (Abs (aMat.Value (2, 1) + 0.5) < 1e-15)
62           && (Abs (aMat.Value (2, 2) - 0.5) < 1e-15)
63           && (Abs (aMat.Value (2, 3) - 0.7071067811865476) < 1e-15)
64           && (Abs (aMat.Value (3, 1) - 0.5) < 1e-15)
65           && (Abs (aMat.Value (3, 2) + 0.5) < 1e-15)
66           && (Abs (aMat.Value (3, 3) - 0.7071067811865476) < 1e-15))
67     {
68       return 3; // axo
69     }
70
71     return -1;
72   }
73
74    //====== TYPE 0 (inverse axonometric)
75    // (0.7071067811865476, -0.5               ,  0.4999999999999999)
76    // (0.7071067811865475,  0.5000000000000001, -0.5              )
77    // (0.0,                 0.7071067811865475,  0.7071067811865476)
78
79    // ====== TYPE 1 (top)
80    // (1.0, 0.0, 0.0)
81    // (0.0, 1.0, 0.0)
82    // (0.0, 0.0, 1.0)
83
84    // ======= TYPE 2 (front)
85    // (1.0,  0.0                   , 0.0)
86    // (0.0,  1.110223024625157e-16 , 1.0)
87    // (0.0, -1.0                   , 1.110223024625157e-16)
88
89    // ======= TYPE 3 (axonometric)
90    // ( 0.7071067811865476, 0.7071067811865475, 0.0)
91    // (-0.5               , 0.5000000000000001, 0.7071067811865475)
92    // ( 0.4999999999999999, -0.5              , 0.7071067811865476)
93 }
94
95 // formula for derivating a perspective, from Mathematica
96
97 //        X'[t]      X[t] Z'[t]
98 // D1 =  -------- + -------------
99 //           Z[t]          Z[t] 2
100 //       1 - ----   f (1 - ----)
101 //            f             f
102
103 //=======================================================================
104 //function : Select3D_Projector
105 //purpose  :
106 //=======================================================================
107 Select3D_Projector::Select3D_Projector (const Handle(V3d_View)& theView)
108 : myPersp (Standard_False),
109   myFocus (0.0),
110   myZNear (0.0),
111   myZFar (10.0),
112   myType (-1)
113 {
114   SetView (theView);
115 }
116
117 //=======================================================================
118 //function : Select3D_Projector
119 //purpose  :
120 //=======================================================================
121 Select3D_Projector::Select3D_Projector()
122 : myPersp (Standard_False),
123   myFocus (0.0),
124   myZNear (0.0),
125   myZFar (10.0),
126   myType (-1)
127 {
128   Scaled();
129 }
130
131 //=======================================================================
132 //function : Select3D_Projector
133 //purpose  :
134 //=======================================================================
135 Select3D_Projector::Select3D_Projector (const gp_Ax2& theCS)
136 : myPersp (Standard_False),
137   myFocus (0.0),
138   myZNear (0.0),
139   myZFar (10.0),
140   myType (-1)
141 {
142   myScaledTrsf.SetTransformation (theCS);
143   myGTrsf.SetTrsf (myScaledTrsf);
144   Scaled();
145 }
146
147 //=======================================================================
148 //function : Select3D_Projector
149 //purpose  :
150 //=======================================================================
151 Select3D_Projector::Select3D_Projector (const gp_Ax2& theCS, const Standard_Real theFocus)
152 : myPersp (Standard_True),
153   myFocus (theFocus),
154   myZNear (0.0),
155   myZFar (10.0),
156   myType (-1)
157 {
158   myScaledTrsf.SetTransformation (theCS);
159   myGTrsf.SetTrsf (myScaledTrsf);
160   Scaled();
161 }
162
163 //=======================================================================
164 //function : Select3D_Projector
165 //purpose  :
166 //=======================================================================
167 Select3D_Projector::Select3D_Projector (const gp_Trsf& theViewTrsf,
168                                         const Standard_Boolean theIsPersp,
169                                         const Standard_Real theFocus)
170 : myPersp (theIsPersp),
171   myFocus (theFocus),
172   myGTrsf (theViewTrsf),
173   myScaledTrsf (theViewTrsf),
174   myZNear (0.0),
175   myZFar (10.0),
176   myType (-1)
177 {
178   Scaled();
179 }
180
181 //=======================================================================
182 //function : Select3D_Projector
183 //purpose  :
184 //=======================================================================
185 Select3D_Projector::Select3D_Projector (const gp_GTrsf& theViewTrsf,
186                                         const Standard_Boolean theIsPersp,
187                                         const Standard_Real theFocus)
188 : myPersp (theIsPersp),
189   myFocus (theFocus),
190   myGTrsf (theViewTrsf),
191   myScaledTrsf (theViewTrsf.Trsf()),
192   myZNear (0.0),
193   myZFar (10.0),
194   myType (-1)
195 {
196   Scaled();
197 }
198
199 //=======================================================================
200 //function : Select3D_Projector
201 //purpose  :
202 //=======================================================================
203 Select3D_Projector::Select3D_Projector (const Graphic3d_Mat4d& theViewTrsf,
204                                         const Graphic3d_Mat4d& theProjTrsf,
205                                         const Standard_Real theZNear,
206                                         const Standard_Real theZFar)
207 : myPersp (Standard_False),
208   myFocus (0.0),
209   myType (-1)
210 {
211   Set (theViewTrsf, theProjTrsf, theZNear, theZFar);
212 }
213
214 //=======================================================================
215 //function : Set
216 //purpose  :
217 //=======================================================================
218 void Select3D_Projector::Set (const gp_Trsf& theViewTrsf,
219                               const Standard_Boolean theIsPersp,
220                               const Standard_Real theFocus)
221 {
222   myPersp      = theIsPersp;
223   myFocus      = theFocus;
224   myScaledTrsf = theViewTrsf;
225   myProjTrsf.InitIdentity();
226   Scaled();
227 }
228
229 //=======================================================================
230 //function : Set
231 //purpose  :
232 //=======================================================================
233 void Select3D_Projector::Set (const Graphic3d_Mat4d& theViewTrsf,
234                               const Graphic3d_Mat4d& theProjTrsf,
235                               const Standard_Real theZNear,
236                               const Standard_Real theZFar)
237 {
238   // Copy elements corresponding to common view-transformation
239   for (Standard_Integer aRowIt = 0; aRowIt < 3; ++aRowIt)
240   {
241     for (Standard_Integer aColIt = 0; aColIt < 4; ++aColIt)
242     {
243       myGTrsf.SetValue (aRowIt + 1, aColIt + 1, theViewTrsf.GetValue (aRowIt, aColIt));
244     }
245   }
246
247   // Adapt scaled transformation for compatibilty
248   gp_Dir aViewY (theViewTrsf.GetValue (0, 1), theViewTrsf.GetValue (1, 1), theViewTrsf.GetValue (2, 1));
249   gp_Dir aViewZ (theViewTrsf.GetValue (0, 2), theViewTrsf.GetValue (1, 2), theViewTrsf.GetValue (2, 2));
250   gp_XYZ aViewT (theViewTrsf.GetValue (0, 3), theViewTrsf.GetValue (1, 3), theViewTrsf.GetValue (2, 3));
251   gp_Dir aViewX = aViewY ^ aViewZ;
252   gp_Ax3 aViewAx3 (gp_Pnt (aViewT), aViewZ, aViewX);
253   myScaledTrsf.SetTransformation (aViewAx3);
254
255   myPersp    = Standard_False;
256   myFocus    = 0.0;
257   myProjTrsf = theProjTrsf;
258   myZNear    = theZNear;
259   myZFar     = theZFar;
260   Scaled();
261 }
262
263 //=======================================================================
264 //function : SetView
265 //purpose  :
266 //=======================================================================
267 void Select3D_Projector::SetView (const Handle(V3d_View)& theView)
268 {
269   const Graphic3d_Mat4d& aViewTrsf = theView->Camera()->OrientationMatrix();
270   const Graphic3d_Mat4d& aProjTrsf = theView->Camera()->ProjectionMatrix();
271
272   gp_XYZ aFrameScale = theView->Camera()->ViewDimensions();
273   Graphic3d_Mat4d aScale;
274   aScale.ChangeValue (0, 0) = aFrameScale.X();
275   aScale.ChangeValue (1, 1) = aFrameScale.Y();
276   aScale.ChangeValue (2, 2) = aFrameScale.Z();
277   Graphic3d_Mat4d aScaledProjTrsf = aScale * aProjTrsf;
278
279   Set (aViewTrsf,
280        aScaledProjTrsf,
281        theView->Camera()->ZNear(),
282        theView->Camera()->ZFar());
283 }
284
285 //=======================================================================
286 //function : Scaled
287 //purpose  :
288 //=======================================================================
289 void Select3D_Projector::Scaled (const Standard_Boolean theToCheckOptimized)
290 {
291   myType = -1;
292
293   if (!theToCheckOptimized && !myPersp && myProjTrsf.IsIdentity())
294   {
295     myType = TrsfType (myGTrsf);
296   }
297
298   myInvTrsf = myGTrsf.Inverted();
299 }
300
301 //=======================================================================
302 //function : Project
303 //purpose  :
304 //=======================================================================
305 void Select3D_Projector::Project (const gp_Pnt& theP, gp_Pnt2d& thePout) const
306 {
307   Standard_Real aXout = 0.0;
308   Standard_Real aYout = 0.0;
309   Standard_Real aZout = 0.0;
310   Project (theP, aXout, aYout, aZout);
311   thePout.SetCoord (aXout, aYout);
312 }
313
314 //=======================================================================
315 //function : Project
316 //purpose  :
317 //=======================================================================
318 void Select3D_Projector::Project (const gp_Pnt& theP,
319                                   Standard_Real& theX,
320                                   Standard_Real& theY,
321                                   Standard_Real& theZ) const
322 {
323   Graphic3d_Vec4d aTransformed (0.0, 0.0, 0.0, 1.0);
324
325   // view transformation
326   switch (myType)
327   {
328     case 0 : // inverse axo
329     {
330       Standard_Real aX07 = theP.X() * 0.7071067811865475;
331       Standard_Real aY05 = theP.Y() * 0.5;
332       Standard_Real aZ05 = theP.Z() * 0.5;
333       aTransformed.x() = aX07 - aY05 + aZ05;
334       aTransformed.y() = aX07 + aY05 - aZ05;
335       aTransformed.z() = 0.7071067811865475 * (theP.Y() + theP.Z());
336       break;
337     }
338
339     case 1 : // top
340     {
341       aTransformed.x() = theP.X();
342       aTransformed.y() = theP.Y();
343       aTransformed.z() = theP.Z();
344       break;
345     }
346
347     case 2 : // front
348     {
349       aTransformed.x() =  theP.X();
350       aTransformed.y() =  theP.Z();
351       aTransformed.z() = -theP.Y();
352       break;
353     }
354
355     case 3 : // axo
356     {
357       Standard_Real aXmy05 = (theP.X() - theP.Y()) * 0.5;
358       Standard_Real aZ07 = theP.Z() * 0.7071067811865476;
359       aTransformed.x() = 0.7071067811865476 * (theP.X() + theP.Y());
360       aTransformed.y() = -aXmy05 + aZ07;
361       aTransformed.z() =  aXmy05 + aZ07;
362       break;
363     }
364
365     default :
366     {
367       gp_Pnt aTransformPnt = theP;
368       Transform (aTransformPnt);
369       aTransformed.x() = aTransformPnt.X();
370       aTransformed.y() = aTransformPnt.Y();
371       aTransformed.z() = aTransformPnt.Z();
372     }
373   }
374
375   // projection transformation
376   if (myPersp)
377   {
378     // simplified perspective
379     Standard_Real aDistortion = 1.0 - aTransformed.z() / myFocus;
380     theX = aTransformed.x() / aDistortion;
381     theY = aTransformed.y() / aDistortion;
382     theZ = aTransformed.z();
383     return;
384   }
385
386   if (myProjTrsf.IsIdentity())
387   {
388     // no projection transformation
389     theX = aTransformed.x();
390     theY = aTransformed.y();
391     theZ = aTransformed.z();
392     return;
393   }
394
395   Graphic3d_Vec4d aProjected = myProjTrsf * aTransformed;
396
397   theX = aProjected.x() / aProjected.w();
398   theY = aProjected.y() / aProjected.w();
399   theZ = aProjected.z() / aProjected.w();
400 }
401
402 //=======================================================================
403 //function : Project
404 //purpose  :
405 //=======================================================================
406 void Select3D_Projector::Project (const gp_Pnt& theP,
407                                   const gp_Vec& theD1,
408                                   gp_Pnt2d& thePout,
409                                   gp_Vec2d& theD1out) const
410 {
411   // view transformation
412   gp_Pnt aTP = theP;
413   Transform (aTP);
414
415   gp_Vec aTD1 = theD1;
416   Transform (aTD1);
417
418   // projection transformation
419   if (myPersp)
420   {
421     // simplified perspective
422     Standard_Real aDist = 1.0 - aTP.Z() / myFocus;
423     thePout.SetCoord (aTP.X() / aDist, aTP.Y() / aDist);
424     theD1out.SetCoord (aTD1.X() / aDist + aTP.X() * aTD1.Z() / (myFocus * aDist * aDist),
425                        aTD1.Y() / aDist + aTP.Y() * aTD1.Z() / (myFocus * aDist * aDist));
426     return;
427   }
428
429   if (myProjTrsf.IsIdentity())
430   {
431     // no projection transformation
432     thePout.SetCoord (aTP.X(), aTP.Y());
433     theD1out.SetCoord (aTD1.X(), aTD1.Y());
434   }
435
436   Graphic3d_Vec4d aTransformedPnt1 (aTP.X(), aTP.Y(), aTP.Z(), 1.0);
437   Graphic3d_Vec4d aTransformedPnt2 (aTP.X() + aTD1.X(), aTP.Y() + aTD1.Y(), aTP.Z() + aTD1.Z(), 1.0);
438
439   Graphic3d_Vec4d aProjectedPnt1 = myProjTrsf * aTransformedPnt1;
440   Graphic3d_Vec4d aProjectedPnt2 = myProjTrsf * aTransformedPnt2;
441
442   aProjectedPnt1 /= aProjectedPnt1.w();
443   aProjectedPnt2 /= aProjectedPnt2.w();
444
445   Graphic3d_Vec4d aProjectedD1 = aProjectedPnt2 - aProjectedPnt1;
446
447   thePout.SetCoord (aProjectedPnt1.x(), aProjectedPnt1.y());
448   theD1out.SetCoord (aProjectedD1.x(), aProjectedD1.y());
449 }
450
451 //=======================================================================
452 //function : Shoot
453 //purpose  :
454 //=======================================================================
455 gp_Lin Select3D_Projector::Shoot (const Standard_Real theX, const Standard_Real theY) const
456 {
457   gp_Lin aViewLin;
458
459   if (myPersp)
460   {
461     // simplified perspective
462     aViewLin = gp_Lin (gp_Pnt (0.0, 0.0, myFocus), gp_Dir (theX, theY, -myFocus));
463   }
464   else if (myProjTrsf.IsIdentity())
465   {
466     // no projection transformation
467     aViewLin = gp_Lin (gp_Pnt (theX, theY, 0.0), gp_Dir (0.0, 0.0, -1.0));
468   }
469   else
470   {
471     // get direction of projection over the point in view space
472     Graphic3d_Mat4d aProjInv;
473     if (!myProjTrsf.Inverted (aProjInv))
474     {
475       return gp_Lin();
476     }
477
478     Graphic3d_Vec4d aVPnt1 = aProjInv * Graphic3d_Vec4d (theX, theY, myZNear, 1.0);
479     Graphic3d_Vec4d aVPnt2 = aProjInv * Graphic3d_Vec4d (theX, theY, myZFar, 1.0);
480     aVPnt1 /= aVPnt1.w();
481     aVPnt2 /= aVPnt2.w();
482
483     gp_Vec aViewDir (aVPnt2.x() - aVPnt1.x(), aVPnt2.y() - aVPnt1.y(), aVPnt2.z() - aVPnt1.z());
484
485     aViewLin = gp_Lin (gp_Pnt (aVPnt1.x(), aVPnt1.y(), aVPnt1.z()), gp_Dir (aViewDir));
486   }
487
488   // view transformation
489   Transform (aViewLin, myInvTrsf);
490
491   return aViewLin;
492 }