0392b3ec0c233520567eb7ecc5f5c746d4ac1ebf
[occt.git] / src / Graphic3d / Graphic3d_Camera.cxx
1 // Created on: 2013-05-29
2 // Created by: Anton POLETAEV
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Graphic3d_Camera.hxx>
17
18 #include <gp_Pln.hxx>
19 #include <gp_QuaternionNLerp.hxx>
20 #include <gp_QuaternionSLerp.hxx>
21 #include <Graphic3d_Vec4.hxx>
22 #include <Graphic3d_WorldViewProjState.hxx>
23 #include <NCollection_Sequence.hxx>
24 #include <Standard_ShortReal.hxx>
25 #include <Standard_Atomic.hxx>
26 #include <Standard_Assert.hxx>
27
28 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera,Standard_Transient)
29
30 namespace
31 {
32   // (degrees -> radians) * 0.5
33   static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
34
35   // default property values
36   static const Standard_Real DEFAULT_ZNEAR = 0.001;
37   static const Standard_Real DEFAULT_ZFAR  = 3000.0;
38
39   // atomic state counter
40   static volatile Standard_Integer THE_STATE_COUNTER = 0;
41
42   // z-range tolerance compatible with for floating point.
43   static Standard_Real zEpsilon()
44   {
45     return FLT_EPSILON;
46   }
47
48   // relative z-range tolerance compatible with for floating point.
49   static Standard_Real zEpsilon (const Standard_Real theValue)
50   {
51     Standard_Real anAbsValue = Abs (theValue);
52     if (anAbsValue <= (double)FLT_MIN)
53     {
54       return FLT_MIN;
55     }
56     Standard_Real aLogRadix = Log10 (anAbsValue) / Log10 (FLT_RADIX);
57     Standard_Real aExp = Floor (aLogRadix);
58     return FLT_EPSILON * Pow (FLT_RADIX, aExp);
59   }
60
61   //! Convert camera definition to Ax3
62   gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
63   {
64     const gp_Dir aBackDir = -theCamera.Direction();
65     const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
66     const gp_Dir anYAxis (aBackDir      .Crossed (anXAxis));
67     const gp_Dir aZAxis  (anXAxis       .Crossed (anYAxis));
68     return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
69   }
70 }
71
72 // =======================================================================
73 // function : Graphic3d_Camera
74 // purpose  :
75 // =======================================================================
76 Graphic3d_Camera::Graphic3d_Camera()
77 : myUp (0.0, 1.0, 0.0),
78   myDirection (0.0, 0.0, 1.0),
79   myEye (0.0, 0.0, -1500.0),
80   myDistance (1500.0),
81   myAxialScale (1.0, 1.0, 1.0),
82   myProjType (Projection_Orthographic),
83   myFOVy (45.0),
84   myFOVx (45.0),
85   myFOV2d (180.0),
86   myFOVyTan (Tan (DTR_HALF * 45.0)),
87   myZNear (DEFAULT_ZNEAR),
88   myZFar (DEFAULT_ZFAR),
89   myAspect (1.0),
90   myScale (1000.0),
91   myZFocus (1.0),
92   myZFocusType (FocusType_Relative),
93   myIOD (0.05),
94   myIODType (IODType_Relative),
95   myIsCustomProjMatM (false),
96   myIsCustomProjMatLR(false),
97   myIsCustomFrustomLR(false)
98 {
99   myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
100                                    (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
101                                    this);
102 }
103
104 // =======================================================================
105 // function : Graphic3d_Camera
106 // purpose  :
107 // =======================================================================
108 Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
109 : myUp (0.0, 1.0, 0.0),
110   myDirection (0.0, 0.0, 1.0),
111   myEye (0.0, 0.0, -1500.0),
112   myDistance (1500.0),
113   myAxialScale (1.0, 1.0, 1.0),
114   myProjType (Projection_Orthographic),
115   myFOVy (45.0),
116   myFOVx (45.0),
117   myFOV2d (180.0),
118   myFOVyTan (Tan (DTR_HALF * 45.0)),
119   myZNear (DEFAULT_ZNEAR),
120   myZFar (DEFAULT_ZFAR),
121   myAspect (1.0),
122   myScale (1000.0),
123   myZFocus (1.0),
124   myZFocusType (FocusType_Relative),
125   myIOD (0.05),
126   myIODType (IODType_Relative),
127   myIsCustomProjMatM (false),
128   myIsCustomProjMatLR(false),
129   myIsCustomFrustomLR(false)
130 {
131   myWorldViewProjState.Initialize (this);
132
133   Copy (theOther);
134 }
135
136 // =======================================================================
137 // function : CopyMappingData
138 // purpose  :
139 // =======================================================================
140 void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
141 {
142   SetProjectionType (theOtherCamera->ProjectionType());
143   SetFOVy           (theOtherCamera->FOVy());
144   SetFOV2d          (theOtherCamera->FOV2d());
145   SetZRange         (theOtherCamera->ZNear(), theOtherCamera->ZFar());
146   SetAspect         (theOtherCamera->Aspect());
147   SetScale          (theOtherCamera->Scale());
148   SetZFocus         (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
149   SetIOD            (theOtherCamera->GetIODType(), theOtherCamera->IOD());
150   SetTile           (theOtherCamera->myTile);
151
152   ResetCustomProjection();
153   if (theOtherCamera->IsCustomStereoProjection())
154   {
155     SetCustomStereoProjection (theOtherCamera->myCustomProjMatL,
156                                theOtherCamera->myCustomHeadToEyeMatL,
157                                theOtherCamera->myCustomProjMatR,
158                                theOtherCamera->myCustomHeadToEyeMatR);
159   }
160   else if (theOtherCamera->IsCustomStereoFrustum())
161   {
162     SetCustomStereoFrustums (theOtherCamera->myCustomFrustumL, theOtherCamera->myCustomFrustumR);
163   }
164   if (theOtherCamera->IsCustomMonoProjection())
165   {
166     SetCustomMonoProjection (theOtherCamera->myCustomProjMatM);
167   }
168 }
169
170 // =======================================================================
171 // function : CopyOrientationData
172 // purpose  :
173 // =======================================================================
174 void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
175 {
176   if (!myEye.IsEqual (theOtherCamera->Eye(), 0.0)
177    || !myUp.IsEqual (theOtherCamera->Up(), 0.0)
178    || !myDirection.IsEqual (theOtherCamera->Direction(), 0.0)
179    ||  myDistance != theOtherCamera->Distance())
180   {
181     myEye = theOtherCamera->Eye();
182     myUp  = theOtherCamera->Up();
183     myDirection = theOtherCamera->Direction();
184     myDistance = theOtherCamera->Distance();
185     InvalidateOrientation();
186   }
187   SetAxialScale (theOtherCamera->AxialScale());
188 }
189
190 // =======================================================================
191 // function : Copy
192 // purpose  :
193 // =======================================================================
194 void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
195 {
196   CopyMappingData (theOther);
197   CopyOrientationData (theOther);
198 }
199
200 // =======================================================================
201 // function : MoveEyeTo
202 // purpose  :
203 // =======================================================================
204 void Graphic3d_Camera::MoveEyeTo (const gp_Pnt& theEye)
205 {
206   if (myEye.IsEqual (theEye, 0.0))
207   {
208     return;
209   }
210
211   myEye = theEye;
212   InvalidateOrientation();
213 }
214
215 // =======================================================================
216 // function : SetEyeAndCenter
217 // purpose  :
218 // =======================================================================
219 void Graphic3d_Camera::SetEyeAndCenter (const gp_Pnt& theEye,
220                                         const gp_Pnt& theCenter)
221 {
222   if (Eye()   .IsEqual (theEye,    0.0)
223    && Center().IsEqual (theCenter, 0.0))
224   {
225     return;
226   }
227
228   myEye = theEye;
229   myDistance = theEye.Distance (theCenter);
230   if (myDistance > gp::Resolution())
231   {
232     myDirection = gp_Dir (theCenter.XYZ() - theEye.XYZ());
233   }
234   InvalidateOrientation();
235 }
236
237 // =======================================================================
238 // function : SetEye
239 // purpose  :
240 // =======================================================================
241 void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
242 {
243   if (Eye().IsEqual (theEye, 0.0))
244   {
245     return;
246   }
247
248   const gp_Pnt aCenter = Center();
249   myEye = theEye;
250   myDistance = myEye.Distance (aCenter);
251   if (myDistance > gp::Resolution())
252   {
253     myDirection = gp_Dir (aCenter.XYZ() - myEye.XYZ());
254   }
255   InvalidateOrientation();
256 }
257
258 // =======================================================================
259 // function : SetCenter
260 // purpose  :
261 // =======================================================================
262 void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
263 {
264   const Standard_Real aDistance = myEye.Distance (theCenter);
265   if (myDistance == aDistance)
266   {
267     return;
268   }
269
270   myDistance = aDistance;
271   if (myDistance > gp::Resolution())
272   {
273     myDirection = gp_Dir (theCenter.XYZ() - myEye.XYZ());
274   }
275   InvalidateOrientation();
276 }
277
278 // =======================================================================
279 // function : SetUp
280 // purpose  :
281 // =======================================================================
282 void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
283 {
284   if (Up().IsEqual (theUp, 0.0))
285   {
286     return;
287   }
288
289   myUp = theUp;
290   InvalidateOrientation();
291 }
292
293 // =======================================================================
294 // function : SetAxialScale
295 // purpose  :
296 // =======================================================================
297 void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
298 {
299   if (AxialScale().IsEqual (theAxialScale, 0.0))
300   {
301     return;
302   }
303
304   myAxialScale = theAxialScale;
305   InvalidateOrientation();
306 }
307
308 // =======================================================================
309 // function : SetDistance
310 // purpose  :
311 // =======================================================================
312 void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
313 {
314   if (myDistance == theDistance)
315   {
316     return;
317   }
318
319   const gp_Pnt aCenter = Center();
320   myDistance = theDistance;
321   myEye = aCenter.XYZ() - myDirection.XYZ() * myDistance;
322   InvalidateOrientation();
323 }
324
325 // =======================================================================
326 // function : SetDirectionFromEye
327 // purpose  :
328 // =======================================================================
329 void Graphic3d_Camera::SetDirectionFromEye (const gp_Dir& theDir)
330 {
331   if (myDirection.IsEqual (theDir, 0.0))
332   {
333     return;
334   }
335
336   myDirection = theDir;
337   InvalidateOrientation();
338 }
339
340 // =======================================================================
341 // function : SetDirection
342 // purpose  :
343 // =======================================================================
344 void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
345 {
346   if (myDirection.IsEqual (theDir, 0.0))
347   {
348     return;
349   }
350
351   const gp_Pnt aCenter = Center();
352   myDirection = theDir;
353   myEye = aCenter.XYZ() - theDir.XYZ() * myDistance;
354   InvalidateOrientation();
355 }
356
357 // =======================================================================
358 // function : SetScale
359 // purpose  :
360 // =======================================================================
361 void Graphic3d_Camera::SetScale (const Standard_Real theScale)
362 {
363   if (Scale() == theScale)
364   {
365     return;
366   }
367
368   myScale = theScale;
369
370   switch (myProjType)
371   {
372     case Projection_Perspective  :
373     case Projection_Stereo       :
374     case Projection_MonoLeftEye  :
375     case Projection_MonoRightEye :
376     {
377       Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
378       SetDistance (aDistance);
379     }
380
381     default :
382       break;
383   }
384
385   InvalidateProjection();
386 }
387
388 // =======================================================================
389 // function : Scale
390 // purpose  :
391 // =======================================================================
392 Standard_Real Graphic3d_Camera::Scale() const
393 {
394   switch (myProjType)
395   {
396     case Projection_Orthographic :
397       return myScale;
398
399     // case Projection_Perspective  :
400     // case Projection_Stereo       :
401     // case Projection_MonoLeftEye  :
402     // case Projection_MonoRightEye :
403     default :
404       return Distance() * 2.0 * myFOVyTan;
405   }
406 }
407
408 // =======================================================================
409 // function : SetProjectionType
410 // purpose  :
411 // =======================================================================
412 void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
413 {
414   Projection anOldType = ProjectionType();
415
416   if (anOldType == theProjectionType)
417   {
418     return;
419   }
420
421   if (anOldType == Projection_Orthographic)
422   {
423     if (myZNear <= RealEpsilon())
424     {
425       myZNear = DEFAULT_ZNEAR;
426     }
427     if (myZFar <= RealEpsilon())
428     {
429       myZFar = DEFAULT_ZFAR;
430     }
431   }
432
433   myProjType = theProjectionType;
434
435   InvalidateProjection();
436 }
437
438 // =======================================================================
439 // function : SetFOVy
440 // purpose  :
441 // =======================================================================
442 void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
443 {
444   if (FOVy() == theFOVy)
445   {
446     return;
447   }
448
449   myFOVy = theFOVy;
450   myFOVx = theFOVy * myAspect;
451   myFOVyTan = Tan(DTR_HALF * myFOVy);
452
453   InvalidateProjection();
454 }
455
456 // =======================================================================
457 // function : SetFOV2d
458 // purpose  :
459 // =======================================================================
460 void Graphic3d_Camera::SetFOV2d (const Standard_Real theFOV)
461 {
462   if (FOV2d() == theFOV)
463   {
464     return;
465   }
466
467   myFOV2d = theFOV;
468   InvalidateProjection();
469 }
470
471 // =======================================================================
472 // function : SetZRange
473 // purpose  :
474 // =======================================================================
475 void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
476                                   const Standard_Real theZFar)
477 {
478   Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
479   if (!IsOrthographic())
480   {
481     Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
482     Standard_ASSERT_RAISE (theZFar  > 0.0, "Only positive Z-Far is allowed for perspective camera");
483   }
484
485   if (ZNear() == theZNear
486    && ZFar () == theZFar)
487   {
488     return;
489   }
490
491   myZNear = theZNear;
492   myZFar  = theZFar;
493
494   InvalidateProjection();
495 }
496
497 // =======================================================================
498 // function : SetAspect
499 // purpose  :
500 // =======================================================================
501 void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
502 {
503   if (Aspect() == theAspect)
504   {
505     return;
506   }
507
508   myAspect = theAspect;
509   myFOVx = myFOVy * theAspect;
510
511   InvalidateProjection();
512 }
513
514 // =======================================================================
515 // function : SetZFocus
516 // purpose  :
517 // =======================================================================
518 void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
519 {
520   if (ZFocusType() == theType
521    && ZFocus    () == theZFocus)
522   {
523     return;
524   }
525
526   myZFocusType = theType;
527   myZFocus     = theZFocus;
528
529   InvalidateProjection();
530 }
531
532 // =======================================================================
533 // function : SetIOD
534 // purpose  :
535 // =======================================================================
536 void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
537 {
538   if (GetIODType() == theType
539    && IOD       () == theIOD)
540   {
541     return;
542   }
543
544   myIODType = theType;
545   myIOD     = theIOD;
546
547   InvalidateProjection();
548 }
549
550 // =======================================================================
551 // function : SetTile
552 // purpose  :
553 // =======================================================================
554 void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
555 {
556   if (myTile == theTile)
557   {
558     return;
559   }
560
561   myTile = theTile;
562   InvalidateProjection();
563 }
564
565 // =======================================================================
566 // function : OrthogonalizeUp
567 // purpose  :
568 // =======================================================================
569 void Graphic3d_Camera::OrthogonalizeUp()
570 {
571   SetUp (OrthogonalizedUp());
572 }
573
574 // =======================================================================
575 // function : OrthogonalizedUp
576 // purpose  :
577 // =======================================================================
578 gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
579 {
580   gp_Dir aDir  = Direction();
581   gp_Dir aLeft = aDir.Crossed (Up());
582
583   // recompute up as: up = left x direction
584   return aLeft.Crossed (aDir);
585 }
586
587 // =======================================================================
588 // function : Transform
589 // purpose  :
590 // =======================================================================
591 void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
592 {
593   if (theTrsf.Form() == gp_Identity)
594   {
595     return;
596   }
597
598   myUp .Transform (theTrsf);
599   myDirection.Transform (theTrsf);
600   myEye.Transform (theTrsf);
601   InvalidateOrientation();
602 }
603
604 // =======================================================================
605 // function : safePointCast
606 // purpose  :
607 // =======================================================================
608 static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
609 {
610   Standard_Real aLim = 1e15f;
611
612   // have to deal with values greater then max float
613   gp_Pnt aSafePoint = thePnt;
614   const Standard_Real aBigFloat = aLim * 0.1f;
615   if (Abs (aSafePoint.X()) > aLim)
616     aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
617   if (Abs (aSafePoint.Y()) > aLim)
618     aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
619   if (Abs (aSafePoint.Z()) > aLim)
620     aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
621
622   // convert point
623   Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
624
625   return aPnt;
626 }
627
628 // =======================================================================
629 // function : Project
630 // purpose  :
631 // =======================================================================
632 gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
633 {
634   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
635   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
636
637   // use compatible type of point
638   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
639
640   aPnt = aViewMx * aPnt; // convert to view coordinate space
641   aPnt = aProjMx * aPnt; // convert to projection coordinate space
642
643   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
644
645   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
646 }
647
648 // =======================================================================
649 // function : UnProject
650 // purpose  :
651 // =======================================================================
652 gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
653 {
654   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
655   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
656
657   Graphic3d_Mat4d aInvView;
658   Graphic3d_Mat4d aInvProj;
659
660   // this case should never happen
661   if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
662   {
663     return gp_Pnt (0.0, 0.0, 0.0);
664   }
665
666   // use compatible type of point
667   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
668
669   aPnt = aInvProj * aPnt; // convert to view coordinate space
670   aPnt = aInvView * aPnt; // convert to world coordinate space
671
672   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
673
674   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
675 }
676
677 // =======================================================================
678 // function : ConvertView2Proj
679 // purpose  :
680 // =======================================================================
681 gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
682 {
683   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
684
685   // use compatible type of point
686   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
687
688   aPnt = aProjMx * aPnt; // convert to projection coordinate space
689
690   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
691
692   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
693 }
694
695 // =======================================================================
696 // function : ConvertProj2View
697 // purpose  :
698 // =======================================================================
699 gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
700 {
701   const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
702
703   Graphic3d_Mat4d aInvProj;
704
705   // this case should never happen, but...
706   if (!aProjMx.Inverted (aInvProj))
707   {
708     return gp_Pnt (0, 0, 0);
709   }
710
711   // use compatible type of point
712   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
713
714   aPnt = aInvProj * aPnt; // convert to view coordinate space
715
716   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
717
718   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
719 }
720
721 // =======================================================================
722 // function : ConvertWorld2View
723 // purpose  :
724 // =======================================================================
725 gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
726 {
727   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
728
729   // use compatible type of point
730   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
731
732   aPnt = aViewMx * aPnt; // convert to view coordinate space
733
734   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
735
736   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
737 }
738
739 // =======================================================================
740 // function : ConvertView2World
741 // purpose  :
742 // =======================================================================
743 gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
744 {
745   const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
746
747   Graphic3d_Mat4d aInvView;
748
749   if (!aViewMx.Inverted (aInvView))
750   {
751     return gp_Pnt(0, 0, 0);
752   }
753
754   // use compatible type of point
755   Graphic3d_Vec4d aPnt = safePointCast (thePnt);
756
757   aPnt = aInvView * aPnt; // convert to world coordinate space
758
759   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
760
761   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
762 }
763
764 // =======================================================================
765 // function : ViewDimensions
766 // purpose  :
767 // =======================================================================
768 gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
769 {
770   // view plane dimensions
771   Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
772   Standard_Real aSizeX, aSizeY;
773   if (myAspect > 1.0)
774   {
775     aSizeX = aSize * myAspect;
776     aSizeY = aSize;
777   }
778   else
779   {
780     aSizeX = aSize;
781     aSizeY = aSize / myAspect;
782   }
783
784   // and frustum depth
785   return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
786 }
787
788 // =======================================================================
789 // function : Frustum
790 // purpose  :
791 // =======================================================================
792 void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
793                                 gp_Pln& theRight,
794                                 gp_Pln& theBottom,
795                                 gp_Pln& theTop,
796                                 gp_Pln& theNear,
797                                 gp_Pln& theFar) const
798 {
799   gp_Vec aProjection = gp_Vec (Direction());
800   gp_Vec anUp        = OrthogonalizedUp();
801   gp_Vec aSide       = aProjection ^ anUp;
802
803   Standard_ASSERT_RAISE (
804     !aProjection.IsParallel (anUp, Precision::Angular()),
805      "Can not derive SIDE = PROJ x UP - directions are parallel");
806
807   theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
808   theFar  = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
809
810   Standard_Real aHScaleHor = 0.0, aHScaleVer = 0.0;
811   if (Aspect() >= 1.0)
812   {
813     aHScaleHor = Scale() * 0.5 * Aspect();
814     aHScaleVer = Scale() * 0.5;
815   }
816   else
817   {
818     aHScaleHor = Scale() * 0.5;
819     aHScaleVer = Scale() * 0.5 / Aspect();
820   }
821
822   gp_Pnt aPntLeft   = Center().Translated (aHScaleHor * -aSide);
823   gp_Pnt aPntRight  = Center().Translated (aHScaleHor *  aSide);
824   gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
825   gp_Pnt aPntTop    = Center().Translated (aHScaleVer *  anUp);
826
827   gp_Vec aDirLeft   =  aSide;
828   gp_Vec aDirRight  = -aSide;
829   gp_Vec aDirBottom =  anUp;
830   gp_Vec aDirTop    = -anUp;
831   if (!IsOrthographic())
832   {
833     Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
834     Standard_Real aHFOVVer = DTR_HALF * FOVy();
835     aDirLeft.Rotate   (gp_Ax1 (gp::Origin(), anUp),   aHFOVHor);
836     aDirRight.Rotate  (gp_Ax1 (gp::Origin(), anUp),  -aHFOVHor);
837     aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
838     aDirTop.Rotate    (gp_Ax1 (gp::Origin(), aSide),  aHFOVVer);
839   }
840
841   theLeft   = gp_Pln (aPntLeft,   aDirLeft);
842   theRight  = gp_Pln (aPntRight,  aDirRight);
843   theBottom = gp_Pln (aPntBottom, aDirBottom);
844   theTop    = gp_Pln (aPntTop,    aDirTop);
845 }
846
847 // =======================================================================
848 // function : OrientationMatrix
849 // purpose  :
850 // =======================================================================
851 const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
852 {
853   return UpdateOrientation (myMatricesD).Orientation;
854 }
855
856 // =======================================================================
857 // function : OrientationMatrixF
858 // purpose  :
859 // =======================================================================
860 const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
861 {
862   return UpdateOrientation (myMatricesF).Orientation;
863 }
864
865 // =======================================================================
866 // function : ProjectionMatrix
867 // purpose  :
868 // =======================================================================
869 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
870 {
871   return UpdateProjection (myMatricesD).MProjection;
872 }
873
874 // =======================================================================
875 // function : ProjectionMatrixF
876 // purpose  :
877 // =======================================================================
878 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
879 {
880   return UpdateProjection (myMatricesF).MProjection;
881 }
882
883 // =======================================================================
884 // function : ProjectionStereoLeft
885 // purpose  :
886 // =======================================================================
887 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
888 {
889   return UpdateProjection (myMatricesD).LProjection;
890 }
891
892 // =======================================================================
893 // function : ProjectionStereoLeftF
894 // purpose  :
895 // =======================================================================
896 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
897 {
898   return UpdateProjection (myMatricesF).LProjection;
899 }
900
901 // =======================================================================
902 // function : ProjectionStereoRight
903 // purpose  :
904 // =======================================================================
905 const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
906 {
907   return UpdateProjection (myMatricesD).RProjection;
908 }
909
910 // =======================================================================
911 // function : ProjectionStereoRightF
912 // purpose  :
913 // =======================================================================
914 const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
915 {
916   return UpdateProjection (myMatricesF).RProjection;
917 }
918
919 // =======================================================================
920 // function : ResetCustomProjection
921 // purpose  :
922 // =======================================================================
923 void Graphic3d_Camera::ResetCustomProjection()
924 {
925   if (myIsCustomFrustomLR
926    || myIsCustomProjMatLR
927    || myIsCustomProjMatM)
928   {
929     myIsCustomFrustomLR = false;
930     myIsCustomProjMatLR = false;
931     myIsCustomProjMatM  = false;
932     InvalidateProjection();
933   }
934 }
935
936 // =======================================================================
937 // function : StereoProjection
938 // purpose  :
939 // =======================================================================
940 void Graphic3d_Camera::StereoProjection (Graphic3d_Mat4d& theProjL,
941                                          Graphic3d_Mat4d& theHeadToEyeL,
942                                          Graphic3d_Mat4d& theProjR,
943                                          Graphic3d_Mat4d& theHeadToEyeR) const
944 {
945   stereoProjection (theProjL, theHeadToEyeL, theProjR, theHeadToEyeR);
946 }
947
948 // =======================================================================
949 // function : StereoProjectionF
950 // purpose  :
951 // =======================================================================
952 void Graphic3d_Camera::StereoProjectionF (Graphic3d_Mat4& theProjL,
953                                           Graphic3d_Mat4& theHeadToEyeL,
954                                           Graphic3d_Mat4& theProjR,
955                                           Graphic3d_Mat4& theHeadToEyeR) const
956 {
957   stereoProjection (theProjL, theHeadToEyeL, theProjR, theHeadToEyeR);
958 }
959
960 // =======================================================================
961 // function : stereoProjection
962 // purpose  :
963 // =======================================================================
964 template <typename Elem_t>
965 void Graphic3d_Camera::stereoProjection (NCollection_Mat4<Elem_t>& theProjL,
966                                          NCollection_Mat4<Elem_t>& theHeadToEyeL,
967                                          NCollection_Mat4<Elem_t>& theProjR,
968                                          NCollection_Mat4<Elem_t>& theHeadToEyeR) const
969 {
970   if (myIsCustomProjMatLR)
971   {
972     theProjL     .ConvertFrom (myCustomProjMatL);
973     theHeadToEyeL.ConvertFrom (myCustomHeadToEyeMatL);
974     theProjR     .ConvertFrom (myCustomProjMatR);
975     theHeadToEyeR.ConvertFrom (myCustomHeadToEyeMatR);
976     return;
977   }
978
979   NCollection_Mat4<Elem_t> aDummy;
980   computeProjection (aDummy, theProjL, theProjR, false);
981
982   const Standard_Real aIOD = myIODType == IODType_Relative
983                            ? myIOD * Distance()
984                            : myIOD;
985   if (aIOD != 0.0)
986   {
987     // X translation to cancel parallax
988     theHeadToEyeL.InitIdentity();
989     theHeadToEyeL.SetColumn (3, NCollection_Vec3<Elem_t> (Elem_t ( 0.5 * aIOD), Elem_t (0.0), Elem_t (0.0)));
990     theHeadToEyeR.InitIdentity();
991     theHeadToEyeR.SetColumn (3, NCollection_Vec3<Elem_t> (Elem_t (-0.5 * aIOD), Elem_t (0.0), Elem_t (0.0)));
992   }
993 }
994
995 // =======================================================================
996 // function : SetCustomStereoFrustums
997 // purpose  :
998 // =======================================================================
999 void Graphic3d_Camera::SetCustomStereoFrustums (const Aspect_FrustumLRBT<Standard_Real>& theFrustumL,
1000                                                 const Aspect_FrustumLRBT<Standard_Real>& theFrustumR)
1001 {
1002   myCustomFrustumL = theFrustumL;
1003   myCustomFrustumR = theFrustumR;
1004   myIsCustomFrustomLR = true;
1005   myIsCustomProjMatLR = false;
1006   InvalidateProjection();
1007 }
1008
1009 // =======================================================================
1010 // function : SetCustomStereoProjection
1011 // purpose  :
1012 // =======================================================================
1013 void Graphic3d_Camera::SetCustomStereoProjection (const Graphic3d_Mat4d& theProjL,
1014                                                   const Graphic3d_Mat4d& theHeadToEyeL,
1015                                                   const Graphic3d_Mat4d& theProjR,
1016                                                   const Graphic3d_Mat4d& theHeadToEyeR)
1017 {
1018   myCustomProjMatL = theProjL;
1019   myCustomProjMatR = theProjR;
1020   myCustomHeadToEyeMatL = theHeadToEyeL;
1021   myCustomHeadToEyeMatR = theHeadToEyeR;
1022   myIsCustomProjMatLR = true;
1023   myIsCustomFrustomLR = false;
1024   InvalidateProjection();
1025 }
1026
1027 // =======================================================================
1028 // function : SetCustomMonoProjection
1029 // purpose  :
1030 // =======================================================================
1031 void Graphic3d_Camera::SetCustomMonoProjection (const Graphic3d_Mat4d& theProj)
1032 {
1033   myCustomProjMatM = theProj;
1034   myIsCustomProjMatM = true;
1035   InvalidateProjection();
1036 }
1037
1038 // =======================================================================
1039 // function : computeProjection
1040 // purpose  :
1041 // =======================================================================
1042 template <typename Elem_t>
1043 void Graphic3d_Camera::computeProjection (NCollection_Mat4<Elem_t>& theProjM,
1044                                           NCollection_Mat4<Elem_t>& theProjL,
1045                                           NCollection_Mat4<Elem_t>& theProjR,
1046                                           bool theToAddHeadToEye) const
1047 {
1048   theProjM.InitIdentity();
1049   theProjL.InitIdentity();
1050   theProjR.InitIdentity();
1051
1052   // sets top of frustum based on FOVy and near clipping plane
1053   Elem_t aScale   = static_cast<Elem_t> (myScale);
1054   Elem_t aZNear   = static_cast<Elem_t> (myZNear);
1055   Elem_t aZFar    = static_cast<Elem_t> (myZFar);
1056   Elem_t anAspect = static_cast<Elem_t> (myAspect);
1057   Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
1058   if (IsOrthographic())
1059   {
1060     aDXHalf = aDYHalf = aScale * Elem_t (0.5);
1061   }
1062   else
1063   {
1064     aDXHalf = aDYHalf = aZNear * Elem_t (myFOVyTan);
1065   }
1066
1067   if (anAspect > 1.0)
1068   {
1069     aDXHalf *= anAspect;
1070   }
1071   else
1072   {
1073     aDYHalf /= anAspect;
1074   }
1075
1076   // sets right of frustum based on aspect ratio
1077   Aspect_FrustumLRBT<Elem_t> anLRBT;
1078   anLRBT.Left   = -aDXHalf;
1079   anLRBT.Right  =  aDXHalf;
1080   anLRBT.Bottom = -aDYHalf;
1081   anLRBT.Top    =  aDYHalf;
1082
1083   Elem_t aIOD  = myIODType == IODType_Relative 
1084     ? static_cast<Elem_t> (myIOD * Distance())
1085     : static_cast<Elem_t> (myIOD);
1086
1087   Elem_t aFocus = myZFocusType == FocusType_Relative 
1088     ? static_cast<Elem_t> (myZFocus * Distance())
1089     : static_cast<Elem_t> (myZFocus);
1090
1091   if (myTile.IsValid())
1092   {
1093     const Elem_t aDXFull = Elem_t(2) * aDXHalf;
1094     const Elem_t aDYFull = Elem_t(2) * aDYHalf;
1095     const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
1096     anLRBT.Left   = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x())                       / static_cast<Elem_t> (myTile.TotalSize.x());
1097     anLRBT.Right  = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1098     anLRBT.Bottom = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y())                       / static_cast<Elem_t> (myTile.TotalSize.y());
1099     anLRBT.Top    = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
1100   }
1101
1102   if (myIsCustomProjMatM)
1103   {
1104     theProjM.ConvertFrom (myCustomProjMatM);
1105   }
1106   switch (myProjType)
1107   {
1108     case Projection_Orthographic:
1109     {
1110       if (!myIsCustomProjMatM)
1111       {
1112         orthoProj (theProjM, anLRBT, aZNear, aZFar);
1113       }
1114       break;
1115     }
1116     case Projection_Perspective:
1117     {
1118       if (!myIsCustomProjMatM)
1119       {
1120         perspectiveProj (theProjM, anLRBT, aZNear, aZFar);
1121       }
1122       break;
1123     }
1124     case Projection_MonoLeftEye:
1125     case Projection_MonoRightEye:
1126     case Projection_Stereo:
1127     {
1128       if (!myIsCustomProjMatM)
1129       {
1130         perspectiveProj (theProjM, anLRBT, aZNear, aZFar);
1131       }
1132       if (myIsCustomProjMatLR)
1133       {
1134         if (theToAddHeadToEye)
1135         {
1136           theProjL.ConvertFrom (myCustomProjMatL * myCustomHeadToEyeMatL);
1137           theProjR.ConvertFrom (myCustomProjMatR * myCustomHeadToEyeMatR);
1138         }
1139         else
1140         {
1141           theProjL.ConvertFrom (myCustomProjMatL);
1142           theProjR.ConvertFrom (myCustomProjMatR);
1143         }
1144       }
1145       else if (myIsCustomFrustomLR)
1146       {
1147         anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumL).Multiplied (aZNear);
1148         perspectiveProj (theProjL, anLRBT, aZNear, aZFar);
1149
1150         anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumR).Multiplied (aZNear);
1151         perspectiveProj (theProjR, anLRBT, aZNear, aZFar);
1152       }
1153       else
1154       {
1155         stereoEyeProj (theProjL,
1156                        anLRBT, aZNear, aZFar, aIOD, aFocus,
1157                        Aspect_Eye_Left);
1158         stereoEyeProj (theProjR,
1159                        anLRBT, aZNear, aZFar, aIOD, aFocus,
1160                        Aspect_Eye_Right);
1161       }
1162
1163       if (theToAddHeadToEye
1164       && !myIsCustomProjMatLR
1165       &&  aIOD != Elem_t (0.0))
1166       {
1167         // X translation to cancel parallax
1168         theProjL.Translate (NCollection_Vec3<Elem_t> (Elem_t ( 0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1169         theProjR.Translate (NCollection_Vec3<Elem_t> (Elem_t (-0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1170       }
1171       break;
1172     }
1173   }
1174   if (myProjType == Projection_MonoLeftEye)
1175   {
1176     theProjM = theProjL;
1177   }
1178   else if (myProjType == Projection_MonoRightEye)
1179   {
1180     theProjM = theProjR;
1181   }
1182 }
1183
1184 // =======================================================================
1185 // function : UpdateOrientation
1186 // purpose  :
1187 // =======================================================================
1188 template <typename Elem_t>
1189 Graphic3d_Camera::TransformMatrices<Elem_t>&
1190   Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
1191 {
1192   if (theMatrices.IsOrientationValid())
1193   {
1194     return theMatrices; // for inline accessors
1195   }
1196
1197   theMatrices.InitOrientation();
1198
1199   NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
1200                                   static_cast<Elem_t> (myEye.Y()),
1201                                   static_cast<Elem_t> (myEye.Z()));
1202
1203   NCollection_Vec3<Elem_t> aViewDir (static_cast<Elem_t> (myDirection.X()),
1204                                      static_cast<Elem_t> (myDirection.Y()),
1205                                      static_cast<Elem_t> (myDirection.Z()));
1206
1207   NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
1208                                  static_cast<Elem_t> (myUp.Y()),
1209                                  static_cast<Elem_t> (myUp.Z()));
1210
1211   NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
1212                                          static_cast<Elem_t> (myAxialScale.Y()),
1213                                          static_cast<Elem_t> (myAxialScale.Z()));
1214
1215   LookOrientation (anEye, aViewDir, anUp, anAxialScale, theMatrices.Orientation);
1216
1217   return theMatrices; // for inline accessors
1218 }
1219
1220 // =======================================================================
1221 // function : InvalidateProjection
1222 // purpose  :
1223 // =======================================================================
1224 void Graphic3d_Camera::InvalidateProjection()
1225 {
1226   myMatricesD.ResetProjection();
1227   myMatricesF.ResetProjection();
1228   myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1229 }
1230
1231 // =======================================================================
1232 // function : InvalidateOrientation
1233 // purpose  :
1234 // =======================================================================
1235 void Graphic3d_Camera::InvalidateOrientation()
1236 {
1237   myMatricesD.ResetOrientation();
1238   myMatricesF.ResetOrientation();
1239   myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
1240 }
1241
1242 // =======================================================================
1243 // function : orthoProj
1244 // purpose  :
1245 // =======================================================================
1246 template <typename Elem_t>
1247 void Graphic3d_Camera::orthoProj (NCollection_Mat4<Elem_t>& theOutMx,
1248                                   const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1249                                   const Elem_t theNear,
1250                                   const Elem_t theFar)
1251 {
1252   // row 0
1253   theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theLRBT.Right - theLRBT.Left);
1254   theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1255   theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
1256   theOutMx.ChangeValue (0, 3) = - (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1257
1258   // row 1
1259   theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1260   theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theLRBT.Top - theLRBT.Bottom);
1261   theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
1262   theOutMx.ChangeValue (1, 3) = - (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
1263
1264   // row 2
1265   theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1266   theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1267   theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
1268   theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1269
1270   // row 3
1271   theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1272   theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1273   theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1274   theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
1275 }
1276
1277 // =======================================================================
1278 // function : PerspectiveProj
1279 // purpose  :
1280 // =======================================================================
1281 template <typename Elem_t>
1282 void Graphic3d_Camera::perspectiveProj (NCollection_Mat4<Elem_t>& theOutMx,
1283                                         const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1284                                         const Elem_t theNear,
1285                                         const Elem_t theFar)
1286 {
1287   // column 0
1288   theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theLRBT.Right - theLRBT.Left);
1289   theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1290   theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1291   theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1292
1293   // column 1
1294   theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1295   theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theLRBT.Top - theLRBT.Bottom);
1296   theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1297   theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1298
1299   // column 2
1300   theOutMx.ChangeValue (0, 2) = (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1301   theOutMx.ChangeValue (1, 2) = (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
1302   theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
1303   theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
1304
1305   // column 3
1306   theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1307   theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
1308   theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1309   theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
1310 }
1311
1312 // =======================================================================
1313 // function : StereoEyeProj
1314 // purpose  :
1315 // =======================================================================
1316 template <typename Elem_t>
1317 void Graphic3d_Camera::stereoEyeProj (NCollection_Mat4<Elem_t>& theOutMx,
1318                                       const Aspect_FrustumLRBT<Elem_t>& theLRBT,
1319                                       const Elem_t theNear,
1320                                       const Elem_t theFar,
1321                                       const Elem_t theIOD,
1322                                       const Elem_t theZFocus,
1323                                       const Aspect_Eye theEyeIndex)
1324 {
1325   Elem_t aDx = theEyeIndex == Aspect_Eye_Left ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
1326   Elem_t aDXStereoShift = aDx * theNear / theZFocus;
1327
1328   // construct eye projection matrix
1329   Aspect_FrustumLRBT<Elem_t> aLRBT = theLRBT;
1330   aLRBT.Left  = theLRBT.Left  + aDXStereoShift;
1331   aLRBT.Right = theLRBT.Right + aDXStereoShift;
1332   perspectiveProj (theOutMx, aLRBT, theNear, theFar);
1333 }
1334
1335 // =======================================================================
1336 // function : LookOrientation
1337 // purpose  :
1338 // =======================================================================
1339 template <typename Elem_t>
1340 void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
1341                                         const NCollection_Vec3<Elem_t>& theFwdDir,
1342                                         const NCollection_Vec3<Elem_t>& theUpDir,
1343                                         const NCollection_Vec3<Elem_t>& theAxialScale,
1344                                         NCollection_Mat4<Elem_t>& theOutMx)
1345 {
1346   NCollection_Vec3<Elem_t> aForward = theFwdDir;
1347   aForward.Normalize();
1348
1349   // side = forward x up
1350   NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
1351   aSide.Normalize();
1352
1353   // recompute up as: up = side x forward
1354   NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
1355
1356   NCollection_Mat4<Elem_t> aLookMx;
1357   aLookMx.SetRow (0, aSide);
1358   aLookMx.SetRow (1, anUp);
1359   aLookMx.SetRow (2, -aForward);
1360
1361   theOutMx.InitIdentity();
1362   theOutMx.Multiply (aLookMx);
1363   theOutMx.Translate (-theEye);
1364
1365   NCollection_Mat4<Elem_t> anAxialScaleMx;
1366   anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1367   anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1368   anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1369
1370   theOutMx.Multiply (anAxialScaleMx);
1371 }
1372
1373 //=============================================================================
1374 //function : ZFitAll
1375 //purpose  :
1376 //=============================================================================
1377 bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1378                                 const Bnd_Box&      theMinMax,
1379                                 const Bnd_Box&      theGraphicBB,
1380                                 Standard_Real&      theZNear,
1381                                 Standard_Real&      theZFar) const
1382 {
1383   Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1384
1385   // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1386   // by their graphical boundaries. It precisely fits min max boundaries of primary application
1387   // objects (second argument), while it can sacrifice the real graphical boundaries of the
1388   // scene with infinite or helper objects (third argument) for the sake of perspective projection.
1389   if (theGraphicBB.IsVoid())
1390   {
1391     theZNear = DEFAULT_ZNEAR;
1392     theZFar  = DEFAULT_ZFAR;
1393     return false;
1394   }
1395
1396   // Measure depth of boundary points from camera eye.
1397   NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1398
1399   Standard_Real aGraphicBB[6];
1400   theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1401
1402   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1403   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1404   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1405   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1406   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1407   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1408   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1409   aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1410
1411   Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1412
1413   if (isFiniteMinMax)
1414   {
1415     Standard_Real aMinMax[6];
1416     theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1417
1418     aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1419     aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1420     aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1421     aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1422     aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1423     aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1424     aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1425     aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1426   }
1427
1428   // Camera eye plane.
1429   gp_Dir aCamDir = Direction();
1430   gp_Pnt aCamEye = myEye;
1431   gp_Pln aCamPln (aCamEye, aCamDir);
1432
1433   Standard_Real aModelMinDist = RealLast();
1434   Standard_Real aModelMaxDist = RealFirst();
1435   Standard_Real aGraphMinDist = RealLast();
1436   Standard_Real aGraphMaxDist = RealFirst();
1437
1438   const gp_XYZ& anAxialScale = myAxialScale;
1439
1440   // Get minimum and maximum distances to the eye plane.
1441   Standard_Integer aCounter = 0;
1442   NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1443   for (; aPntIt.More(); aPntIt.Next())
1444   {
1445     gp_Pnt aMeasurePnt = aPntIt.Value();
1446
1447     aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
1448                           aMeasurePnt.Y() * anAxialScale.Y(),
1449                           aMeasurePnt.Z() * anAxialScale.Z());
1450
1451     Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1452
1453     // Check if the camera is intruded into the scene.
1454     gp_Vec aVecToMeasurePnt (aCamEye, aMeasurePnt);
1455     if (aVecToMeasurePnt.Magnitude() > gp::Resolution()
1456      && aCamDir.IsOpposite (aVecToMeasurePnt, M_PI * 0.5))
1457     {
1458       aDistance *= -1;
1459     }
1460
1461     // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
1462     Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1463     Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
1464     aChangeMinDist = Min (aDistance, aChangeMinDist);
1465     aChangeMaxDist = Max (aDistance, aChangeMaxDist);
1466     aCounter++;
1467   }
1468
1469   // Compute depth of bounding box center.
1470   Standard_Real aMidDepth  = (aGraphMinDist + aGraphMaxDist) * 0.5;
1471   Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
1472
1473   // Compute enlarged or shrank near and far z ranges.
1474   Standard_Real aZNear  = aMidDepth - aHalfDepth * theScaleFactor;
1475   Standard_Real aZFar   = aMidDepth + aHalfDepth * theScaleFactor;
1476
1477   if (!IsOrthographic())
1478   {
1479     // Everything is behind the perspective camera.
1480     if (aZFar < zEpsilon())
1481     {
1482       theZNear = DEFAULT_ZNEAR;
1483       theZFar  = DEFAULT_ZFAR;
1484       return false;
1485     }
1486   }
1487
1488   //
1489   // Consider clipping errors due to double to single precision floating-point conversion.
1490   //
1491
1492   // Model to view transformation performs translation of points against eye position
1493   // in three dimensions. Both point coordinate and eye position values are converted from
1494   // double to single precision floating point numbers producing conversion errors. 
1495   // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1496   // translation assuming that the:
1497   // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1498   Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1499
1500   // Model to view transformation performs rotation of points according to view direction.
1501   // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1502   // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1503   // values are converted from double to single precision floating point numbers producing
1504   // conversion errors.
1505   // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1506   // of point coordinates by direction vector.
1507   gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1508   gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1509
1510   Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1511                              6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1512
1513   // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1514   aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1515   aZFar  += zEpsilon (aZFar)  + aEyeConf + aModelConf;
1516
1517   if (!IsOrthographic())
1518   {
1519     // For perspective projection, the value of z in normalized device coordinates is non-linear
1520     // function of eye z coordinate. For fixed-point depth representation resolution of z in
1521     // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1522     // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1523     // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1524     // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1525     // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1526     // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1527     // the zNear will be placed similarly giving lower resolution.
1528     // Approximation of the formula for respectively large z range is:
1529     // zNear = [z * (1 + k) / (k * c)],
1530     // where:
1531     // z - distance to center of model boundaries;
1532     // k - chosen ratio, c - capacity of depth buffer;
1533     // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1534     //
1535     // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1536     // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1537     // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1538     // small applicative objects measured with "theMinMax" values.
1539     Standard_Real aZRange   = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1540     Standard_Real aZMin     = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1541     Standard_Real aZ        = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1542     Standard_Real aZNearMin = aZ * 5.97E-4;
1543     if (aZNear < aZNearMin)
1544     {
1545       // Clip zNear according to the minimum value matching the quality.
1546       aZNear = aZNearMin;
1547       if (aZFar < aZNear)
1548       {
1549         aZFar = aZNear;
1550       }
1551     }
1552     else
1553     {
1554       // Compensate zNear conversion errors for perspective projection.
1555       aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1556     }
1557
1558     // Compensate zFar conversion errors for perspective projection.
1559     aZFar += zEpsilon (aZFar);
1560
1561     // Ensure that after all the zNear is not a negative value.
1562     if (aZNear < zEpsilon())
1563     {
1564       aZNear = zEpsilon();
1565     }
1566     Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1567   }
1568
1569   theZNear = aZNear;
1570   theZFar  = aZFar;
1571   Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
1572   return true;
1573 }
1574
1575 //=============================================================================
1576 //function : Interpolate
1577 //purpose  :
1578 //=============================================================================
1579 void Graphic3d_Camera::Interpolate (const Handle(Graphic3d_Camera)& theStart,
1580                                     const Handle(Graphic3d_Camera)& theEnd,
1581                                     const double theT,
1582                                     Handle(Graphic3d_Camera)& theCamera)
1583 {
1584   if (Abs (theT - 1.0) < Precision::Confusion())
1585   {
1586     // just copy end-point transformation
1587     theCamera->Copy (theEnd);
1588     return;
1589   }
1590
1591   theCamera->Copy (theStart);
1592   if (Abs (theT - 0.0) < Precision::Confusion())
1593   {
1594     return;
1595   }
1596
1597   // apply rotation
1598   {
1599     gp_Ax3 aCamStart = cameraToAx3 (*theStart);
1600     gp_Ax3 aCamEnd   = cameraToAx3 (*theEnd);
1601     gp_Trsf aTrsfStart, aTrsfEnd;
1602     aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1603     aTrsfEnd  .SetTransformation (aCamEnd,   gp::XOY());
1604
1605     gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1606     gp_Quaternion aRotEnd   = aTrsfEnd  .GetRotation();
1607     gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1608     gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1609     gp_Trsf aTrsfRot;
1610     aTrsfRot.SetRotation (aRot);
1611     theCamera->Transform (aTrsfRot);
1612   }
1613
1614   // apply translation
1615   {
1616     gp_XYZ aCenter  = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Center().XYZ(), theEnd->Center().XYZ(), theT);
1617     gp_XYZ anEye    = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Eye().XYZ(),    theEnd->Eye().XYZ(),    theT);
1618     gp_XYZ anAnchor = aCenter;
1619     Standard_Real aKc = 0.0;
1620
1621     const Standard_Real aDeltaCenter = theStart->Center().Distance (theEnd->Center());
1622     const Standard_Real aDeltaEye    = theStart->Eye()   .Distance (theEnd->Eye());
1623     if (aDeltaEye <= gp::Resolution())
1624     {
1625       anAnchor = anEye;
1626       aKc = 1.0;
1627     }
1628     else if (aDeltaCenter > gp::Resolution())
1629     {
1630       aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1631
1632       const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Center().XYZ(), theStart->Eye().XYZ(), aKc);
1633       const gp_XYZ anAnchorEnd   = NCollection_Lerp<gp_XYZ>::Interpolate (theEnd  ->Center().XYZ(), theEnd  ->Eye().XYZ(), aKc);
1634       anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1635     }
1636
1637     const gp_Vec        aDirEyeToCenter     = theCamera->Direction();
1638     const Standard_Real aDistEyeCenterStart = theStart->Eye().Distance (theStart->Center());
1639     const Standard_Real aDistEyeCenterEnd   = theEnd  ->Eye().Distance (theEnd  ->Center());
1640     const Standard_Real aDistEyeCenter      = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1641     aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1642     anEye   = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1643
1644     theCamera->SetEyeAndCenter (anEye, aCenter);
1645   }
1646
1647   // apply scaling
1648   if (Abs(theStart->Scale() - theEnd->Scale()) > Precision::Confusion()
1649    && theStart->IsOrthographic())
1650   {
1651     const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (theStart->Scale(), theEnd->Scale(), theT);
1652     theCamera->SetScale (aScale);
1653   }
1654 }
1655
1656 //=======================================================================
1657 //function : FrustumPoints
1658 //purpose  :
1659 //=======================================================================
1660 void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePoints,
1661                                       const Graphic3d_Mat4d& theModelWorld) const
1662 {
1663   if (thePoints.Length() != FrustumVerticesNB)
1664   {
1665     thePoints.Resize (0, FrustumVerticesNB, Standard_False);
1666   }
1667
1668   const Graphic3d_Mat4d& aProjectionMat = ProjectionMatrix();
1669   const Graphic3d_Mat4d aWorldViewMat = OrientationMatrix() * theModelWorld;
1670
1671   Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
1672   Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
1673   Standard_Real aNear = 0.0, aFar = 0.0;
1674   if (!IsOrthographic())
1675   {
1676     // handle perspective projection
1677     aNear = aProjectionMat.GetValue (2, 3) / (-1.0 + aProjectionMat.GetValue (2, 2));
1678     aFar  = aProjectionMat.GetValue (2, 3) / ( 1.0 + aProjectionMat.GetValue (2, 2));
1679     // Near plane
1680     nLeft   = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1681     nRight  = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1682     nTop    = aNear * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1683     nBottom = aNear * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1684     // Far plane
1685     fLeft   = aFar  * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1686     fRight  = aFar  * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1687     fTop    = aFar  * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1688     fBottom = aFar  * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1689   }
1690   else
1691   {
1692     // handle orthographic projection
1693     aNear = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) + 1.0);
1694     aFar  = (1.0 / aProjectionMat.GetValue (2, 2)) * (aProjectionMat.GetValue (2, 3) - 1.0);
1695     // Near plane
1696     nLeft   = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
1697     fLeft   = nLeft;
1698     nRight  = ( 1.0 - aProjectionMat.GetValue (0, 3)) /   aProjectionMat.GetValue (0, 0);
1699     fRight  = nRight;
1700     nTop    = ( 1.0 - aProjectionMat.GetValue (1, 3)) /   aProjectionMat.GetValue (1, 1);
1701     fTop    = nTop;
1702     nBottom = (-1.0 - aProjectionMat.GetValue (1, 3)) /   aProjectionMat.GetValue (1, 1);
1703     fBottom = nBottom;
1704   }
1705
1706   Graphic3d_Vec4d aLeftTopNear     (nLeft,  nTop,    -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
1707   Graphic3d_Vec4d aLeftBottomNear  (nLeft,  nBottom, -aNear, 1.0), aRightTopFar    (fRight, fTop,    -aFar, 1.0);
1708   Graphic3d_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar     (fLeft,  fTop,    -aFar, 1.0);
1709   Graphic3d_Vec4d aRightTopNear    (nRight, nTop,    -aNear, 1.0), aLeftBottomFar  (fLeft,  fBottom, -aFar, 1.0);
1710
1711   Graphic3d_Mat4d anInvWorldView;
1712   aWorldViewMat.Inverted (anInvWorldView);
1713
1714   Graphic3d_Vec4d aTmpPnt;
1715   aTmpPnt = anInvWorldView * aLeftTopNear;
1716   thePoints.SetValue (FrustumVert_LeftTopNear,     aTmpPnt.xyz() / aTmpPnt.w());
1717   aTmpPnt = anInvWorldView * aRightBottomFar;
1718   thePoints.SetValue (FrustumVert_RightBottomFar,  aTmpPnt.xyz() / aTmpPnt.w());
1719   aTmpPnt = anInvWorldView * aLeftBottomNear;
1720   thePoints.SetValue (FrustumVert_LeftBottomNear,  aTmpPnt.xyz() / aTmpPnt.w());
1721   aTmpPnt = anInvWorldView * aRightTopFar;
1722   thePoints.SetValue (FrustumVert_RightTopFar,     aTmpPnt.xyz() / aTmpPnt.w());
1723   aTmpPnt = anInvWorldView * aRightBottomNear;
1724   thePoints.SetValue (FrustumVert_RightBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1725   aTmpPnt = anInvWorldView * aLeftTopFar;
1726   thePoints.SetValue (FrustumVert_LeftTopFar,      aTmpPnt.xyz() / aTmpPnt.w());
1727   aTmpPnt = anInvWorldView * aRightTopNear;
1728   thePoints.SetValue (FrustumVert_RightTopNear,    aTmpPnt.xyz() / aTmpPnt.w());
1729   aTmpPnt = anInvWorldView * aLeftBottomFar;
1730   thePoints.SetValue (FrustumVert_LeftBottomFar,   aTmpPnt.xyz() / aTmpPnt.w());
1731 }
1732
1733 //=======================================================================
1734 //function : DumpJson
1735 //purpose  : 
1736 //=======================================================================
1737 void Graphic3d_Camera::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1738 {
1739   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1740
1741   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myUp)
1742   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myDirection)
1743   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myEye)
1744
1745   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDistance)
1746
1747   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myAxialScale)
1748   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myProjType)
1749   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myFOVy)
1750   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZNear)
1751   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFar)
1752   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAspect)
1753
1754   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myScale)
1755   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFocus)
1756   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFocusType)
1757   
1758   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIOD)
1759   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIODType)
1760   
1761   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myTile)
1762   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myMatricesD)
1763   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myMatricesF)
1764   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myWorldViewProjState)
1765 }