50cc4a9028d103586cdb39a232bac99cbf6ba134
[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   myType (-1)
111 {
112   SetView (theView);
113 }
114
115 //=======================================================================
116 //function : Select3D_Projector
117 //purpose  :
118 //=======================================================================
119 Select3D_Projector::Select3D_Projector()
120 : myPersp (Standard_False),
121   myFocus (0.0),
122   myType (-1)
123 {
124   Scaled();
125 }
126
127 //=======================================================================
128 //function : Select3D_Projector
129 //purpose  :
130 //=======================================================================
131 Select3D_Projector::Select3D_Projector (const gp_Ax2& theCS)
132 : myPersp (Standard_False),
133   myFocus (0.0),
134   myType (-1)
135 {
136   myScaledTrsf.SetTransformation (theCS);
137   myGTrsf.SetTrsf (myScaledTrsf);
138   Scaled();
139 }
140
141 //=======================================================================
142 //function : Select3D_Projector
143 //purpose  :
144 //=======================================================================
145 Select3D_Projector::Select3D_Projector (const gp_Ax2& theCS, const Standard_Real theFocus)
146 : myPersp (Standard_True),
147   myFocus (theFocus),
148   myType (-1)
149 {
150   myScaledTrsf.SetTransformation (theCS);
151   myGTrsf.SetTrsf (myScaledTrsf);
152   Scaled();
153 }
154
155 //=======================================================================
156 //function : Select3D_Projector
157 //purpose  :
158 //=======================================================================
159 Select3D_Projector::Select3D_Projector (const gp_Trsf& theViewTrsf,
160                                         const Standard_Boolean theIsPersp,
161                                         const Standard_Real theFocus)
162 : myPersp (theIsPersp),
163   myFocus (theFocus),
164   myGTrsf (theViewTrsf),
165   myScaledTrsf (theViewTrsf),
166   myType (-1)
167 {
168   Scaled();
169 }
170
171 //=======================================================================
172 //function : Select3D_Projector
173 //purpose  :
174 //=======================================================================
175 Select3D_Projector::Select3D_Projector (const gp_GTrsf& theViewTrsf,
176                                         const Standard_Boolean theIsPersp,
177                                         const Standard_Real theFocus)
178 : myPersp (theIsPersp),
179   myFocus (theFocus),
180   myGTrsf (theViewTrsf),
181   myScaledTrsf (theViewTrsf.Trsf()),
182   myType (-1)
183 {
184   Scaled();
185 }
186
187 //=======================================================================
188 //function : Select3D_Projector
189 //purpose  :
190 //=======================================================================
191 Select3D_Projector::Select3D_Projector (const Graphic3d_Mat4d& theViewTrsf,
192                                         const Graphic3d_Mat4d& theProjTrsf)
193 : myPersp (Standard_False),
194   myFocus (0.0),
195   myType (-1)
196 {
197   Set (theViewTrsf, theProjTrsf);
198 }
199
200 //=======================================================================
201 //function : Set
202 //purpose  :
203 //=======================================================================
204 void Select3D_Projector::Set (const gp_Trsf& theViewTrsf,
205                               const Standard_Boolean theIsPersp,
206                               const Standard_Real theFocus)
207 {
208   myPersp      = theIsPersp;
209   myFocus      = theFocus;
210   myScaledTrsf = theViewTrsf;
211   myProjTrsf.InitIdentity();
212   Scaled();
213 }
214
215 //=======================================================================
216 //function : Set
217 //purpose  :
218 //=======================================================================
219 void Select3D_Projector::Set (const Graphic3d_Mat4d& theViewTrsf,
220                               const Graphic3d_Mat4d& theProjTrsf)
221 {
222   // Copy elements corresponding to common view-transformation
223   for (Standard_Integer aRowIt = 0; aRowIt < 3; ++aRowIt)
224   {
225     for (Standard_Integer aColIt = 0; aColIt < 4; ++aColIt)
226     {
227       myGTrsf.SetValue (aRowIt + 1, aColIt + 1, theViewTrsf.GetValue (aRowIt, aColIt));
228     }
229   }
230
231   // Adapt scaled transformation for compatibilty
232   gp_Dir aViewY (theViewTrsf.GetValue (0, 1), theViewTrsf.GetValue (1, 1), theViewTrsf.GetValue (2, 1));
233   gp_Dir aViewZ (theViewTrsf.GetValue (0, 2), theViewTrsf.GetValue (1, 2), theViewTrsf.GetValue (2, 2));
234   gp_XYZ aViewT (theViewTrsf.GetValue (0, 3), theViewTrsf.GetValue (1, 3), theViewTrsf.GetValue (2, 3));
235   gp_Dir aViewX = aViewY ^ aViewZ;
236   gp_Ax3 aViewAx3 (gp_Pnt (aViewT), aViewZ, aViewX);
237   myScaledTrsf.SetTransformation (aViewAx3);
238
239   myPersp    = Standard_False;
240   myFocus    = 0.0;
241   myProjTrsf = theProjTrsf;
242   Scaled();
243 }
244
245 //=======================================================================
246 //function : SetView
247 //purpose  :
248 //=======================================================================
249 void Select3D_Projector::SetView (const Handle(V3d_View)& theView)
250 {
251   const Graphic3d_Mat4d& aViewTrsf = theView->Camera()->OrientationMatrix();
252   const Graphic3d_Mat4d& aProjTrsf = theView->Camera()->ProjectionMatrix();
253
254   gp_XYZ aFrameScale = theView->Camera()->ViewDimensions();
255   Graphic3d_Mat4d aScale;
256   aScale.ChangeValue (0, 0) = aFrameScale.X();
257   aScale.ChangeValue (1, 1) = aFrameScale.Y();
258   aScale.ChangeValue (2, 2) = aFrameScale.Z();
259   Graphic3d_Mat4d aScaledProjTrsf = aScale * aProjTrsf;
260
261   Set (aViewTrsf, aScaledProjTrsf);
262 }
263
264 //=======================================================================
265 //function : Scaled
266 //purpose  :
267 //=======================================================================
268 void Select3D_Projector::Scaled (const Standard_Boolean theToCheckOptimized)
269 {
270   myType = -1;
271
272   if (!theToCheckOptimized && !myPersp && myProjTrsf.IsIdentity())
273   {
274     myType = TrsfType (myGTrsf);
275   }
276
277   myInvTrsf = myGTrsf.Inverted();
278 }
279
280 //=======================================================================
281 //function : Project
282 //purpose  :
283 //=======================================================================
284 void Select3D_Projector::Project (const gp_Pnt& theP, gp_Pnt2d& thePout) const
285 {
286   Standard_Real aXout = 0.0;
287   Standard_Real aYout = 0.0;
288   Standard_Real aZout = 0.0;
289   Project (theP, aXout, aYout, aZout);
290   thePout.SetCoord (aXout, aYout);
291 }
292
293 //=======================================================================
294 //function : Project
295 //purpose  :
296 //=======================================================================
297 void Select3D_Projector::Project (const gp_Pnt& theP,
298                                   Standard_Real& theX,
299                                   Standard_Real& theY,
300                                   Standard_Real& theZ) const
301 {
302   Graphic3d_Vec4d aTransformed (0.0, 0.0, 0.0, 1.0);
303
304   // view transformation
305   switch (myType)
306   {
307     case 0 : // inverse axo
308     {
309       Standard_Real aX07 = theP.X() * 0.7071067811865475;
310       Standard_Real aY05 = theP.Y() * 0.5;
311       Standard_Real aZ05 = theP.Z() * 0.5;
312       aTransformed.x() = aX07 - aY05 + aZ05;
313       aTransformed.y() = aX07 + aY05 - aZ05;
314       aTransformed.z() = 0.7071067811865475 * (theP.Y() + theP.Z());
315       break;
316     }
317
318     case 1 : // top
319     {
320       aTransformed.x() = theP.X();
321       aTransformed.y() = theP.Y();
322       aTransformed.z() = theP.Z();
323       break;
324     }
325
326     case 2 : // front
327     {
328       aTransformed.x() =  theP.X();
329       aTransformed.y() =  theP.Z();
330       aTransformed.z() = -theP.Y();
331       break;
332     }
333
334     case 3 : // axo
335     {
336       Standard_Real aXmy05 = (theP.X() - theP.Y()) * 0.5;
337       Standard_Real aZ07 = theP.Z() * 0.7071067811865476;
338       aTransformed.x() = 0.7071067811865476 * (theP.X() + theP.Y());
339       aTransformed.y() = -aXmy05 + aZ07;
340       aTransformed.z() =  aXmy05 + aZ07;
341       break;
342     }
343
344     default :
345     {
346       gp_Pnt aTransformPnt = theP;
347       Transform (aTransformPnt);
348       aTransformed.x() = aTransformPnt.X();
349       aTransformed.y() = aTransformPnt.Y();
350       aTransformed.z() = aTransformPnt.Z();
351     }
352   }
353
354   // projection transformation
355   if (myPersp)
356   {
357     // simplified perspective
358     Standard_Real aDistortion = 1.0 - aTransformed.z() / myFocus;
359     theX = aTransformed.x() / aDistortion;
360     theY = aTransformed.y() / aDistortion;
361     theZ = aTransformed.z();
362     return;
363   }
364
365   if (myProjTrsf.IsIdentity())
366   {
367     // no projection transformation
368     theX = aTransformed.x();
369     theY = aTransformed.y();
370     theZ = aTransformed.z();
371     return;
372   }
373
374   Graphic3d_Vec4d aProjected = myProjTrsf * aTransformed;
375
376   theX = aProjected.x() / aProjected.w();
377   theY = aProjected.y() / aProjected.w();
378   theZ = aProjected.z() / aProjected.w();
379 }
380
381 //=======================================================================
382 //function : Project
383 //purpose  :
384 //=======================================================================
385 void Select3D_Projector::Project (const gp_Pnt& theP,
386                                   const gp_Vec& theD1,
387                                   gp_Pnt2d& thePout,
388                                   gp_Vec2d& theD1out) const
389 {
390   // view transformation
391   gp_Pnt aTP = theP;
392   Transform (aTP);
393
394   gp_Vec aTD1 = theD1;
395   Transform (aTD1);
396
397   // projection transformation
398   if (myPersp)
399   {
400     // simplified perspective
401     Standard_Real aDist = 1.0 - aTP.Z() / myFocus;
402     thePout.SetCoord (aTP.X() / aDist, aTP.Y() / aDist);
403     theD1out.SetCoord (aTD1.X() / aDist + aTP.X() * aTD1.Z() / (myFocus * aDist * aDist),
404                        aTD1.Y() / aDist + aTP.Y() * aTD1.Z() / (myFocus * aDist * aDist));
405     return;
406   }
407
408   if (myProjTrsf.IsIdentity())
409   {
410     // no projection transformation
411     thePout.SetCoord (aTP.X(), aTP.Y());
412     theD1out.SetCoord (aTD1.X(), aTD1.Y());
413   }
414
415   Graphic3d_Vec4d aTransformedPnt1 (aTP.X(), aTP.Y(), aTP.Z(), 1.0);
416   Graphic3d_Vec4d aTransformedPnt2 (aTP.X() + aTD1.X(), aTP.Y() + aTD1.Y(), aTP.Z() + aTD1.Z(), 1.0);
417
418   Graphic3d_Vec4d aProjectedPnt1 = myProjTrsf * aTransformedPnt1;
419   Graphic3d_Vec4d aProjectedPnt2 = myProjTrsf * aTransformedPnt2;
420
421   aProjectedPnt1 /= aProjectedPnt1.w();
422   aProjectedPnt2 /= aProjectedPnt2.w();
423
424   Graphic3d_Vec4d aProjectedD1 = aProjectedPnt2 - aProjectedPnt1;
425
426   thePout.SetCoord (aProjectedPnt1.x(), aProjectedPnt1.y());
427   theD1out.SetCoord (aProjectedD1.x(), aProjectedD1.y());
428 }
429
430 //=======================================================================
431 //function : Shoot
432 //purpose  :
433 //=======================================================================
434 gp_Lin Select3D_Projector::Shoot (const Standard_Real theX, const Standard_Real theY) const
435 {
436   gp_Lin aViewLin;
437
438   if (myPersp)
439   {
440     // simplified perspective
441     aViewLin = gp_Lin (gp_Pnt (0.0, 0.0, myFocus), gp_Dir (theX, theY, -myFocus));
442   }
443   else if (myProjTrsf.IsIdentity())
444   {
445     // no projection transformation
446     aViewLin = gp_Lin (gp_Pnt (theX, theY, 0.0), gp_Dir (0.0, 0.0, -1.0));
447   }
448   else
449   {
450     // get direction of projection over the point in view space
451     Graphic3d_Mat4d aProjInv;
452     if (!myProjTrsf.Inverted (aProjInv))
453     {
454       return gp_Lin();
455     }
456
457     Graphic3d_Vec4d aVPnt1 = aProjInv * Graphic3d_Vec4d (theX, theY,  0.0, 1.0);
458     Graphic3d_Vec4d aVPnt2 = aProjInv * Graphic3d_Vec4d (theX, theY, 10.0, 1.0);
459     aVPnt1 /= aVPnt1.w();
460     aVPnt2 /= aVPnt2.w();
461
462     gp_Vec aViewDir (aVPnt2.x() - aVPnt1.x(), aVPnt2.y() - aVPnt1.y(), aVPnt2.z() - aVPnt1.z());
463
464     aViewLin = gp_Lin (gp_Pnt (aVPnt1.x(), aVPnt1.y(), aVPnt1.z()), gp_Dir (aViewDir));
465   }
466
467   // view transformation
468   Transform (aViewLin, myInvTrsf);
469
470   return aViewLin;
471 }