0030349: Coding - add usage of Standard_EXPORT for some not inline methods in Select3D
[occt.git] / src / Graphic3d / Graphic3d_Camera.cxx
CommitLineData
b5ac8292 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//
d5f74e42 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
b5ac8292 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
b5ac8292 16#include <Graphic3d_Camera.hxx>
1beb58d7 17
18#include <gp_Pln.hxx>
19#include <gp_QuaternionNLerp.hxx>
20#include <gp_QuaternionSLerp.hxx>
825aa485 21#include <Graphic3d_Vec4.hxx>
22#include <Graphic3d_WorldViewProjState.hxx>
1beb58d7 23#include <NCollection_Sequence.hxx>
24#include <Standard_ShortReal.hxx>
b5ac8292 25#include <Standard_Atomic.hxx>
197ac94e 26#include <Standard_Assert.hxx>
b5ac8292 27
92efcf78 28IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera,Standard_Transient)
29
b5ac8292 30namespace
31{
32 // (degrees -> radians) * 0.5
197ac94e 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;
b5ac8292 38
39 // atomic state counter
40 static volatile Standard_Integer THE_STATE_COUNTER = 0;
3c648527 41
42 // minimum camera distance
43 static const Standard_Real MIN_DISTANCE = Pow (0.1, ShortRealDigits() - 2);
ea764884 44
45 // z-range tolerance compatible with for floating point.
46 static Standard_Real zEpsilon()
47 {
48 return FLT_EPSILON;
49 }
50
51 // relative z-range tolerance compatible with for floating point.
52 static Standard_Real zEpsilon (const Standard_Real theValue)
53 {
5c8908e0 54 Standard_Real anAbsValue = Abs (theValue);
55 if (anAbsValue <= (double)FLT_MIN)
825aa485 56 {
5c8908e0 57 return FLT_MIN;
825aa485 58 }
5c8908e0 59 Standard_Real aLogRadix = Log10 (anAbsValue) / Log10 (FLT_RADIX);
ea764884 60 Standard_Real aExp = Floor (aLogRadix);
61 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
a3f6f591 62 }
1beb58d7 63
64 //! Convert camera definition to Ax3
65 gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
66 {
67 const gp_Dir aBackDir(gp_Vec(theCamera.Center(), theCamera.Eye()));
68 const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
69 const gp_Dir anYAxis (aBackDir .Crossed (anXAxis));
70 const gp_Dir aZAxis (anXAxis .Crossed (anYAxis));
71 return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
72 }
a3f6f591 73}
b5ac8292 74
75// =======================================================================
76// function : Graphic3d_Camera
77// purpose :
78// =======================================================================
79Graphic3d_Camera::Graphic3d_Camera()
80: myUp (0.0, 1.0, 0.0),
81 myEye (0.0, 0.0, -1500.0),
82 myCenter (0.0, 0.0, 0.0),
b5ac8292 83 myAxialScale (1.0, 1.0, 1.0),
84 myProjType (Projection_Orthographic),
85 myFOVy (45.0),
778cd667 86 myFOVyTan (Tan (DTR_HALF * 45.0)),
197ac94e 87 myZNear (DEFAULT_ZNEAR),
88 myZFar (DEFAULT_ZFAR),
b5ac8292 89 myAspect (1.0),
90 myScale (1000.0),
91 myZFocus (1.0),
92 myZFocusType (FocusType_Relative),
93 myIOD (0.05),
197ac94e 94 myIODType (IODType_Relative)
b5ac8292 95{
825aa485 96 myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
97 (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
98 this);
b5ac8292 99}
100
101// =======================================================================
102// function : Graphic3d_Camera
103// purpose :
104// =======================================================================
105Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
b5ac8292 106{
825aa485 107 myWorldViewProjState.Initialize (this);
108
b5ac8292 109 Copy (theOther);
110}
111
112// =======================================================================
113// function : CopyMappingData
114// purpose :
115// =======================================================================
116void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
117{
bf02aa7d 118 SetFOVy (theOtherCamera->FOVy());
119 SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
120 SetAspect (theOtherCamera->Aspect());
121 SetScale (theOtherCamera->Scale());
122 SetZFocus (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
123 SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
124 SetProjectionType (theOtherCamera->ProjectionType());
3bffef55 125 SetTile (theOtherCamera->myTile);
b5ac8292 126}
127
128// =======================================================================
129// function : CopyOrientationData
130// purpose :
131// =======================================================================
132void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
133{
bf02aa7d 134 SetUp (theOtherCamera->Up());
135 SetEye (theOtherCamera->Eye());
136 SetCenter (theOtherCamera->Center());
137 SetAxialScale (theOtherCamera->AxialScale());
b5ac8292 138}
139
140// =======================================================================
141// function : Copy
142// purpose :
143// =======================================================================
144void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
145{
b5ac8292 146 CopyMappingData (theOther);
147 CopyOrientationData (theOther);
b5ac8292 148}
149
150// =======================================================================
151// function : SetEye
152// purpose :
153// =======================================================================
154void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
155{
bf02aa7d 156 if (Eye().IsEqual (theEye, 0.0))
157 {
158 return;
159 }
160
b5ac8292 161 myEye = theEye;
197ac94e 162 InvalidateOrientation();
b5ac8292 163}
164
165// =======================================================================
166// function : SetCenter
167// purpose :
168// =======================================================================
169void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
170{
bf02aa7d 171 if (Center().IsEqual (theCenter, 0.0))
172 {
173 return;
174 }
175
b5ac8292 176 myCenter = theCenter;
197ac94e 177 InvalidateOrientation();
b5ac8292 178}
179
180// =======================================================================
181// function : SetUp
182// purpose :
183// =======================================================================
184void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
185{
bf02aa7d 186 if (Up().IsEqual (theUp, 0.0))
187 {
188 return;
189 }
190
b5ac8292 191 myUp = theUp;
197ac94e 192 InvalidateOrientation();
b5ac8292 193}
194
195// =======================================================================
196// function : SetAxialScale
197// purpose :
198// =======================================================================
197ac94e 199void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
b5ac8292 200{
bf02aa7d 201 if (AxialScale().IsEqual (theAxialScale, 0.0))
202 {
203 return;
204 }
205
b5ac8292 206 myAxialScale = theAxialScale;
197ac94e 207 InvalidateOrientation();
b5ac8292 208}
209
210// =======================================================================
211// function : SetDistance
212// purpose :
213// =======================================================================
214void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
215{
bf02aa7d 216 if (Distance() == theDistance)
217 {
218 return;
219 }
220
b5ac8292 221 gp_Vec aCenter2Eye (Direction());
222 aCenter2Eye.Reverse();
3c648527 223
224 // Camera should have non-zero distance.
225 aCenter2Eye.Scale (Max (theDistance, MIN_DISTANCE));
b5ac8292 226 SetEye (Center().Translated (aCenter2Eye));
227}
228
229// =======================================================================
230// function : Distance
231// purpose :
232// =======================================================================
233Standard_Real Graphic3d_Camera::Distance() const
234{
235 return myEye.Distance (myCenter);
236}
237
238// =======================================================================
239// function : SetDirection
240// purpose :
241// =======================================================================
242void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
243{
bf02aa7d 244 if (Direction().IsEqual (theDir, 0.0))
245 {
246 return;
247 }
248
b5ac8292 249 gp_Vec aScaledDir (theDir);
250 aScaledDir.Scale (Distance());
251 aScaledDir.Reverse();
252 SetEye (Center().Translated (aScaledDir));
253}
254
255// =======================================================================
256// function : Direction
257// purpose :
258// =======================================================================
259gp_Dir Graphic3d_Camera::Direction() const
260{
261 return gp_Dir (gp_Vec (myEye, myCenter));
262}
263
264// =======================================================================
265// function : SetScale
266// purpose :
267// =======================================================================
268void Graphic3d_Camera::SetScale (const Standard_Real theScale)
269{
c357e426 270 if (Scale() == theScale)
271 {
272 return;
273 }
274
b5ac8292 275 myScale = theScale;
276
277 switch (myProjType)
278 {
279 case Projection_Perspective :
280 case Projection_Stereo :
281 case Projection_MonoLeftEye :
282 case Projection_MonoRightEye :
283 {
778cd667 284 Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
b5ac8292 285 SetDistance (aDistance);
286 }
287
288 default :
289 break;
290 }
291
197ac94e 292 InvalidateProjection();
b5ac8292 293}
294
295// =======================================================================
296// function : Scale
297// purpose :
298// =======================================================================
299Standard_Real Graphic3d_Camera::Scale() const
300{
301 switch (myProjType)
302 {
303 case Projection_Orthographic :
304 return myScale;
305
306 // case Projection_Perspective :
307 // case Projection_Stereo :
308 // case Projection_MonoLeftEye :
309 // case Projection_MonoRightEye :
310 default :
778cd667 311 return Distance() * 2.0 * myFOVyTan;
b5ac8292 312 }
313}
314
315// =======================================================================
316// function : SetProjectionType
317// purpose :
318// =======================================================================
319void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
320{
c357e426 321 Projection anOldType = ProjectionType();
b5ac8292 322
323 if (anOldType == theProjectionType)
324 {
325 return;
326 }
327
197ac94e 328 if (anOldType == Projection_Orthographic)
b5ac8292 329 {
197ac94e 330 if (myZNear <= RealEpsilon())
331 {
332 myZNear = DEFAULT_ZNEAR;
333 }
334 if (myZFar <= RealEpsilon())
335 {
336 myZFar = DEFAULT_ZFAR;
337 }
b5ac8292 338 }
339
197ac94e 340 myProjType = theProjectionType;
341
342 InvalidateProjection();
b5ac8292 343}
344
345// =======================================================================
346// function : SetFOVy
347// purpose :
348// =======================================================================
349void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
350{
c357e426 351 if (FOVy() == theFOVy)
352 {
353 return;
354 }
355
b5ac8292 356 myFOVy = theFOVy;
778cd667 357 myFOVyTan = Tan(DTR_HALF * myFOVy);
c357e426 358
197ac94e 359 InvalidateProjection();
b5ac8292 360}
361
362// =======================================================================
197ac94e 363// function : SetZRange
b5ac8292 364// purpose :
365// =======================================================================
197ac94e 366void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
367 const Standard_Real theZFar)
b5ac8292 368{
197ac94e 369 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
370 if (!IsOrthographic())
b5ac8292 371 {
197ac94e 372 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
373 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
b5ac8292 374 }
375
c357e426 376 if (ZNear() == theZNear
377 && ZFar () == theZFar)
378 {
379 return;
380 }
381
197ac94e 382 myZNear = theZNear;
383 myZFar = theZFar;
b5ac8292 384
197ac94e 385 InvalidateProjection();
b5ac8292 386}
387
388// =======================================================================
389// function : SetAspect
390// purpose :
391// =======================================================================
392void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
393{
c357e426 394 if (Aspect() == theAspect)
395 {
396 return;
397 }
398
b5ac8292 399 myAspect = theAspect;
c357e426 400
197ac94e 401 InvalidateProjection();
b5ac8292 402}
403
404// =======================================================================
405// function : SetZFocus
406// purpose :
407// =======================================================================
408void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
409{
c357e426 410 if (ZFocusType() == theType
411 && ZFocus () == theZFocus)
412 {
413 return;
414 }
415
b5ac8292 416 myZFocusType = theType;
c357e426 417 myZFocus = theZFocus;
418
197ac94e 419 InvalidateProjection();
b5ac8292 420}
421
422// =======================================================================
423// function : SetIOD
424// purpose :
425// =======================================================================
426void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
427{
bf02aa7d 428 if (GetIODType() == theType
429 && IOD () == theIOD)
c357e426 430 {
431 return;
432 }
433
b5ac8292 434 myIODType = theType;
c357e426 435 myIOD = theIOD;
436
197ac94e 437 InvalidateProjection();
b5ac8292 438}
439
440// =======================================================================
3bffef55 441// function : SetTile
442// purpose :
443// =======================================================================
444void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
445{
446 if (myTile == theTile)
447 {
448 return;
449 }
450
451 myTile = theTile;
452 InvalidateProjection();
453}
454
455// =======================================================================
b5ac8292 456// function : OrthogonalizeUp
457// purpose :
458// =======================================================================
459void Graphic3d_Camera::OrthogonalizeUp()
460{
197ac94e 461 SetUp (OrthogonalizedUp());
b5ac8292 462}
463
464// =======================================================================
197ac94e 465// function : OrthogonalizedUp
b5ac8292 466// purpose :
467// =======================================================================
197ac94e 468gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
b5ac8292 469{
197ac94e 470 gp_Dir aDir = Direction();
471 gp_Dir aLeft = aDir.Crossed (Up());
b5ac8292 472
197ac94e 473 // recompute up as: up = left x direction
474 return aLeft.Crossed (aDir);
b5ac8292 475}
476
477// =======================================================================
478// function : Transform
479// purpose :
480// =======================================================================
481void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
482{
bf02aa7d 483 if (theTrsf.Form() == gp_Identity)
484 {
485 return;
486 }
487
488 SetUp (myUp.Transformed (theTrsf));
489 SetEye (myEye.Transformed (theTrsf));
490 SetCenter (myCenter.Transformed (theTrsf));
b5ac8292 491}
492
493// =======================================================================
494// function : safePointCast
495// purpose :
496// =======================================================================
197ac94e 497static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
b5ac8292 498{
499 Standard_Real aLim = 1e15f;
197ac94e 500
b5ac8292 501 // have to deal with values greater then max float
502 gp_Pnt aSafePoint = thePnt;
503 const Standard_Real aBigFloat = aLim * 0.1f;
504 if (Abs (aSafePoint.X()) > aLim)
505 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
506 if (Abs (aSafePoint.Y()) > aLim)
507 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
508 if (Abs (aSafePoint.Z()) > aLim)
509 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
510
511 // convert point
197ac94e 512 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
b5ac8292 513
514 return aPnt;
515}
516
517// =======================================================================
518// function : Project
519// purpose :
520// =======================================================================
521gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
522{
197ac94e 523 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
524 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 525
526 // use compatible type of point
197ac94e 527 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 528
529 aPnt = aViewMx * aPnt; // convert to view coordinate space
530 aPnt = aProjMx * aPnt; // convert to projection coordinate space
531
532 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
533
534 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
535}
536
537// =======================================================================
538// function : UnProject
539// purpose :
540// =======================================================================
541gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
542{
197ac94e 543 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
544 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 545
197ac94e 546 Graphic3d_Mat4d aInvView;
547 Graphic3d_Mat4d aInvProj;
b5ac8292 548
549 // this case should never happen
550 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
551 {
552 return gp_Pnt (0.0, 0.0, 0.0);
553 }
554
555 // use compatible type of point
197ac94e 556 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 557
558 aPnt = aInvProj * aPnt; // convert to view coordinate space
559 aPnt = aInvView * aPnt; // convert to world coordinate space
560
561 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
562
563 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
564}
565
566// =======================================================================
567// function : ConvertView2Proj
568// purpose :
569// =======================================================================
570gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
571{
197ac94e 572 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 573
574 // use compatible type of point
197ac94e 575 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 576
577 aPnt = aProjMx * aPnt; // convert to projection coordinate space
578
579 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
580
581 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
582}
583
584// =======================================================================
585// function : ConvertProj2View
586// purpose :
587// =======================================================================
588gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
589{
197ac94e 590 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 591
197ac94e 592 Graphic3d_Mat4d aInvProj;
b5ac8292 593
594 // this case should never happen, but...
595 if (!aProjMx.Inverted (aInvProj))
596 {
197ac94e 597 return gp_Pnt (0, 0, 0);
b5ac8292 598 }
599
600 // use compatible type of point
197ac94e 601 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 602
603 aPnt = aInvProj * aPnt; // convert to view coordinate space
604
605 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
606
607 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
608}
609
610// =======================================================================
611// function : ConvertWorld2View
612// purpose :
613// =======================================================================
614gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
615{
197ac94e 616 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 617
618 // use compatible type of point
197ac94e 619 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 620
621 aPnt = aViewMx * aPnt; // convert to view coordinate space
622
623 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
624
625 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
626}
627
628// =======================================================================
629// function : ConvertView2World
630// purpose :
631// =======================================================================
632gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
633{
197ac94e 634 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 635
197ac94e 636 Graphic3d_Mat4d aInvView;
b5ac8292 637
638 if (!aViewMx.Inverted (aInvView))
639 {
640 return gp_Pnt(0, 0, 0);
641 }
642
643 // use compatible type of point
197ac94e 644 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 645
646 aPnt = aInvView * aPnt; // convert to world coordinate space
647
648 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
649
650 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
651}
652
653// =======================================================================
654// function : ViewDimensions
655// purpose :
656// =======================================================================
3fe9ce0e 657gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
b5ac8292 658{
659 // view plane dimensions
778cd667 660 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
539d3a1b 661 Standard_Real aSizeX, aSizeY;
662 if (myAspect > 1.0)
663 {
664 aSizeX = aSize * myAspect;
665 aSizeY = aSize;
666 }
667 else
668 {
669 aSizeX = aSize;
670 aSizeY = aSize / myAspect;
671 }
b5ac8292 672
673 // and frustum depth
197ac94e 674 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
b5ac8292 675}
676
677// =======================================================================
197ac94e 678// function : Frustum
b5ac8292 679// purpose :
680// =======================================================================
197ac94e 681void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
682 gp_Pln& theRight,
683 gp_Pln& theBottom,
684 gp_Pln& theTop,
685 gp_Pln& theNear,
686 gp_Pln& theFar) const
b5ac8292 687{
197ac94e 688 gp_Vec aProjection = gp_Vec (Direction());
689 gp_Vec anUp = OrthogonalizedUp();
690 gp_Vec aSide = aProjection ^ anUp;
691
692 Standard_ASSERT_RAISE (
693 !aProjection.IsParallel (anUp, Precision::Angular()),
694 "Can not derive SIDE = PROJ x UP - directions are parallel");
695
696 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
697 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
698
699 Standard_Real aHScaleHor = Scale() * 0.5 * Aspect();
700 Standard_Real aHScaleVer = Scale() * 0.5;
701
702 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
703 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
704 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
705 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
706
707 gp_Vec aDirLeft = aSide;
708 gp_Vec aDirRight = -aSide;
709 gp_Vec aDirBottom = anUp;
710 gp_Vec aDirTop = -anUp;
711 if (!IsOrthographic())
712 {
713 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
714 Standard_Real aHFOVVer = DTR_HALF * FOVy();
715 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
716 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
717 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
718 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
719 }
720
721 theLeft = gp_Pln (aPntLeft, aDirLeft);
722 theRight = gp_Pln (aPntRight, aDirRight);
723 theBottom = gp_Pln (aPntBottom, aDirBottom);
724 theTop = gp_Pln (aPntTop, aDirTop);
725}
726
727// =======================================================================
728// function : OrientationMatrix
729// purpose :
730// =======================================================================
731const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
732{
778cd667 733 return UpdateOrientation (myMatricesD).Orientation;
197ac94e 734}
735
736// =======================================================================
737// function : OrientationMatrixF
738// purpose :
739// =======================================================================
740const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
741{
778cd667 742 return UpdateOrientation (myMatricesF).Orientation;
197ac94e 743}
744
745// =======================================================================
746// function : ProjectionMatrix
747// purpose :
748// =======================================================================
749const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
750{
778cd667 751 return UpdateProjection (myMatricesD).MProjection;
197ac94e 752}
753
754// =======================================================================
755// function : ProjectionMatrixF
756// purpose :
757// =======================================================================
758const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
759{
778cd667 760 return UpdateProjection (myMatricesF).MProjection;
197ac94e 761}
762
763// =======================================================================
764// function : ProjectionStereoLeft
765// purpose :
766// =======================================================================
767const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
768{
778cd667 769 return UpdateProjection (myMatricesD).LProjection;
197ac94e 770}
771
772// =======================================================================
773// function : ProjectionStereoLeftF
774// purpose :
775// =======================================================================
776const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
777{
778cd667 778 return UpdateProjection (myMatricesF).LProjection;
197ac94e 779}
780
781// =======================================================================
782// function : ProjectionStereoRight
783// purpose :
784// =======================================================================
785const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
786{
778cd667 787 return UpdateProjection (myMatricesD).RProjection;
197ac94e 788}
789
790// =======================================================================
791// function : ProjectionStereoRightF
792// purpose :
793// =======================================================================
794const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
795{
778cd667 796 return UpdateProjection (myMatricesF).RProjection;
b5ac8292 797}
798
799// =======================================================================
800// function : UpdateProjection
801// purpose :
802// =======================================================================
197ac94e 803template <typename Elem_t>
804Graphic3d_Camera::TransformMatrices<Elem_t>&
805 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 806{
197ac94e 807 if (theMatrices.IsProjectionValid())
b5ac8292 808 {
197ac94e 809 return theMatrices; // for inline accessors
b5ac8292 810 }
811
197ac94e 812 theMatrices.InitProjection();
b5ac8292 813
814 // sets top of frustum based on FOVy and near clipping plane
197ac94e 815 Elem_t aScale = static_cast<Elem_t> (myScale);
816 Elem_t aZNear = static_cast<Elem_t> (myZNear);
817 Elem_t aZFar = static_cast<Elem_t> (myZFar);
818 Elem_t anAspect = static_cast<Elem_t> (myAspect);
ab1c121b 819 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
b5ac8292 820 if (IsOrthographic())
821 {
ab1c121b 822 aDXHalf = aScale * Elem_t (0.5);
197ac94e 823 aDYHalf = aScale * Elem_t (0.5);
b5ac8292 824 }
825 else
826 {
778cd667 827 aDXHalf = aZNear * Elem_t (myFOVyTan);
828 aDYHalf = aZNear * Elem_t (myFOVyTan);
b5ac8292 829 }
830
ab1c121b 831 if (anAspect > 1.0)
832 {
833 aDXHalf *= anAspect;
834 }
835 else
836 {
837 aDYHalf /= anAspect;
838 }
839
b5ac8292 840 // sets right of frustum based on aspect ratio
197ac94e 841 Elem_t aLeft = -aDXHalf;
842 Elem_t aRight = aDXHalf;
843 Elem_t aBot = -aDYHalf;
844 Elem_t aTop = aDYHalf;
b5ac8292 845
197ac94e 846 Elem_t aIOD = myIODType == IODType_Relative
847 ? static_cast<Elem_t> (myIOD * Distance())
848 : static_cast<Elem_t> (myIOD);
b5ac8292 849
197ac94e 850 Elem_t aFocus = myZFocusType == FocusType_Relative
851 ? static_cast<Elem_t> (myZFocus * Distance())
852 : static_cast<Elem_t> (myZFocus);
b5ac8292 853
3bffef55 854 if (myTile.IsValid())
855 {
856 const Elem_t aDXFull = Elem_t(2) * aDXHalf;
857 const Elem_t aDYFull = Elem_t(2) * aDYHalf;
858 const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
859 aLeft = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
860 aRight = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
861 aBot = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
862 aTop = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
863 }
864
b5ac8292 865 switch (myProjType)
866 {
867 case Projection_Orthographic :
778cd667 868 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
b5ac8292 869 break;
870
871 case Projection_Perspective :
778cd667 872 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
b5ac8292 873 break;
874
875 case Projection_MonoLeftEye :
876 {
197ac94e 877 StereoEyeProj (aLeft, aRight, aBot, aTop,
878 aZNear, aZFar, aIOD, aFocus,
778cd667 879 Standard_True, theMatrices.MProjection);
880 theMatrices.LProjection = theMatrices.MProjection;
b5ac8292 881 break;
882 }
883
884 case Projection_MonoRightEye :
885 {
197ac94e 886 StereoEyeProj (aLeft, aRight, aBot, aTop,
887 aZNear, aZFar, aIOD, aFocus,
778cd667 888 Standard_False, theMatrices.MProjection);
889 theMatrices.RProjection = theMatrices.MProjection;
b5ac8292 890 break;
891 }
892
893 case Projection_Stereo :
894 {
778cd667 895 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, theMatrices.MProjection);
b5ac8292 896
197ac94e 897 StereoEyeProj (aLeft, aRight, aBot, aTop,
898 aZNear, aZFar, aIOD, aFocus,
899 Standard_True,
778cd667 900 theMatrices.LProjection);
b5ac8292 901
197ac94e 902 StereoEyeProj (aLeft, aRight, aBot, aTop,
903 aZNear, aZFar, aIOD, aFocus,
904 Standard_False,
778cd667 905 theMatrices.RProjection);
b5ac8292 906 break;
907 }
908 }
197ac94e 909
910 return theMatrices; // for inline accessors
b5ac8292 911}
912
913// =======================================================================
914// function : UpdateOrientation
915// purpose :
916// =======================================================================
197ac94e 917template <typename Elem_t>
918Graphic3d_Camera::TransformMatrices<Elem_t>&
919 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 920{
197ac94e 921 if (theMatrices.IsOrientationValid())
b5ac8292 922 {
197ac94e 923 return theMatrices; // for inline accessors
b5ac8292 924 }
925
197ac94e 926 theMatrices.InitOrientation();
927
928 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
929 static_cast<Elem_t> (myEye.Y()),
930 static_cast<Elem_t> (myEye.Z()));
931
932 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
933 static_cast<Elem_t> (myCenter.Y()),
934 static_cast<Elem_t> (myCenter.Z()));
b5ac8292 935
197ac94e 936 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
937 static_cast<Elem_t> (myUp.Y()),
938 static_cast<Elem_t> (myUp.Z()));
b5ac8292 939
197ac94e 940 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
941 static_cast<Elem_t> (myAxialScale.Y()),
942 static_cast<Elem_t> (myAxialScale.Z()));
b5ac8292 943
778cd667 944 LookOrientation (anEye, aCenter, anUp, anAxialScale, theMatrices.Orientation);
b5ac8292 945
197ac94e 946 return theMatrices; // for inline accessors
947}
b5ac8292 948
197ac94e 949// =======================================================================
950// function : InvalidateProjection
951// purpose :
952// =======================================================================
953void Graphic3d_Camera::InvalidateProjection()
954{
955 myMatricesD.ResetProjection();
956 myMatricesF.ResetProjection();
825aa485 957 myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
197ac94e 958}
b5ac8292 959
197ac94e 960// =======================================================================
961// function : InvalidateOrientation
962// purpose :
963// =======================================================================
964void Graphic3d_Camera::InvalidateOrientation()
965{
966 myMatricesD.ResetOrientation();
967 myMatricesF.ResetOrientation();
825aa485 968 myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 969}
970
971// =======================================================================
972// function : OrthoProj
973// purpose :
974// =======================================================================
197ac94e 975template <typename Elem_t>
976void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
977 const Elem_t theRight,
978 const Elem_t theBottom,
979 const Elem_t theTop,
980 const Elem_t theNear,
981 const Elem_t theFar,
982 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 983{
984 // row 0
197ac94e 985 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
986 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
987 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
b5ac8292 988 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
989
990 // row 1
197ac94e 991 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
992 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
993 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
b5ac8292 994 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
995
996 // row 2
197ac94e 997 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
998 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
999 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
b5ac8292 1000 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1001
1002 // row 3
197ac94e 1003 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1004 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1005 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1006 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
b5ac8292 1007}
1008
1009// =======================================================================
1010// function : PerspectiveProj
1011// purpose :
1012// =======================================================================
197ac94e 1013template <typename Elem_t>
1014void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
1015 const Elem_t theRight,
1016 const Elem_t theBottom,
1017 const Elem_t theTop,
1018 const Elem_t theNear,
1019 const Elem_t theFar,
1020 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 1021{
1022 // column 0
197ac94e 1023 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
1024 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1025 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1026 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
b5ac8292 1027
1028 // column 1
197ac94e 1029 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1030 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
1031 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1032 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
b5ac8292 1033
1034 // column 2
1035 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
1036 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
1037 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
197ac94e 1038 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
b5ac8292 1039
1040 // column 3
197ac94e 1041 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1042 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
1043 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1044 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
b5ac8292 1045}
1046
1047// =======================================================================
1048// function : StereoEyeProj
1049// purpose :
1050// =======================================================================
197ac94e 1051template <typename Elem_t>
1052void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
1053 const Elem_t theRight,
1054 const Elem_t theBottom,
1055 const Elem_t theTop,
1056 const Elem_t theNear,
1057 const Elem_t theFar,
1058 const Elem_t theIOD,
1059 const Elem_t theZFocus,
1060 const Standard_Boolean theIsLeft,
1061 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 1062{
197ac94e 1063 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
1064 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
b5ac8292 1065
1066 // construct eye projection matrix
1067 PerspectiveProj (theLeft + aDXStereoShift,
1068 theRight + aDXStereoShift,
1069 theBottom, theTop, theNear, theFar,
b5ac8292 1070 theOutMx);
1071
197ac94e 1072 if (theIOD != Elem_t (0.0))
b5ac8292 1073 {
1074 // X translation to cancel parallax
197ac94e 1075 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
b5ac8292 1076 }
1077}
1078
1079// =======================================================================
1080// function : LookOrientation
1081// purpose :
1082// =======================================================================
197ac94e 1083template <typename Elem_t>
1084void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
1085 const NCollection_Vec3<Elem_t>& theLookAt,
1086 const NCollection_Vec3<Elem_t>& theUpDir,
1087 const NCollection_Vec3<Elem_t>& theAxialScale,
1088 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 1089{
197ac94e 1090 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
b5ac8292 1091 aForward.Normalize();
1092
1093 // side = forward x up
197ac94e 1094 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
b5ac8292 1095 aSide.Normalize();
1096
1097 // recompute up as: up = side x forward
197ac94e 1098 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
b5ac8292 1099
197ac94e 1100 NCollection_Mat4<Elem_t> aLookMx;
b5ac8292 1101 aLookMx.SetRow (0, aSide);
1102 aLookMx.SetRow (1, anUp);
1103 aLookMx.SetRow (2, -aForward);
1104
197ac94e 1105 theOutMx.InitIdentity();
1106 theOutMx.Multiply (aLookMx);
b5ac8292 1107 theOutMx.Translate (-theEye);
1108
197ac94e 1109 NCollection_Mat4<Elem_t> anAxialScaleMx;
b5ac8292 1110 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1111 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1112 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1113
1114 theOutMx.Multiply (anAxialScaleMx);
1115}
6bc6a6fc 1116
1117//=============================================================================
1118//function : ZFitAll
1119//purpose :
1120//=============================================================================
10dbdf34 1121bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1122 const Bnd_Box& theMinMax,
1123 const Bnd_Box& theGraphicBB,
1124 Standard_Real& theZNear,
1125 Standard_Real& theZFar) const
6bc6a6fc 1126{
1127 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1128
ea764884 1129 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1130 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1131 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1132 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
ed063270 1133 if (theGraphicBB.IsVoid())
6bc6a6fc 1134 {
10dbdf34 1135 theZNear = DEFAULT_ZNEAR;
1136 theZFar = DEFAULT_ZFAR;
1137 return false;
6bc6a6fc 1138 }
1139
ea764884 1140 // Measure depth of boundary points from camera eye.
ed063270 1141 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1142
ea764884 1143 Standard_Real aGraphicBB[6];
ed063270 1144 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1145
1146 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1147 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1148 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1149 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1150 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1151 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1152 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1153 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1154
5a19c303 1155 Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1156
1157 if (isFiniteMinMax)
6bc6a6fc 1158 {
ea764884 1159 Standard_Real aMinMax[6];
ed063270 1160 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1161
1162 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1163 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1164 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1165 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1166 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1167 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1168 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1169 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1170 }
6bc6a6fc 1171
ea764884 1172 // Camera eye plane.
6bc6a6fc 1173 gp_Dir aCamDir = Direction();
1174 gp_Pnt aCamEye = myEye;
1175 gp_Pln aCamPln (aCamEye, aCamDir);
1176
5a19c303 1177 Standard_Real aModelMinDist = RealLast();
1178 Standard_Real aModelMaxDist = RealFirst();
1179 Standard_Real aGraphMinDist = RealLast();
1180 Standard_Real aGraphMaxDist = RealFirst();
6bc6a6fc 1181
1182 const gp_XYZ& anAxialScale = myAxialScale;
1183
ea764884 1184 // Get minimum and maximum distances to the eye plane.
ed063270 1185 Standard_Integer aCounter = 0;
1186 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1187 for (; aPntIt.More(); aPntIt.Next())
6bc6a6fc 1188 {
ed063270 1189 gp_Pnt aMeasurePnt = aPntIt.Value();
6bc6a6fc 1190
1191 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
ed063270 1192 aMeasurePnt.Y() * anAxialScale.Y(),
1193 aMeasurePnt.Z() * anAxialScale.Z());
6bc6a6fc 1194
1195 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1196
ea764884 1197 // Check if the camera is intruded into the scene.
6bc6a6fc 1198 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1199 {
1200 aDistance *= -1;
1201 }
1202
ea764884 1203 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
5a19c303 1204 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1205 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
6bc6a6fc 1206 aChangeMinDist = Min (aDistance, aChangeMinDist);
1207 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
ed063270 1208 aCounter++;
6bc6a6fc 1209 }
1210
ea764884 1211 // Compute depth of bounding box center.
5a19c303 1212 Standard_Real aMidDepth = (aGraphMinDist + aGraphMaxDist) * 0.5;
1213 Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
6bc6a6fc 1214
ea764884 1215 // Compute enlarged or shrank near and far z ranges.
35c4a17c 1216 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1217 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
6bc6a6fc 1218
1219 if (!IsOrthographic())
1220 {
ea764884 1221 // Everything is behind the perspective camera.
1222 if (aZFar < zEpsilon())
6bc6a6fc 1223 {
10dbdf34 1224 theZNear = DEFAULT_ZNEAR;
1225 theZFar = DEFAULT_ZFAR;
1226 return false;
6bc6a6fc 1227 }
6bc6a6fc 1228 }
1229
ea764884 1230 //
1231 // Consider clipping errors due to double to single precision floating-point conversion.
1232 //
1233
1234 // Model to view transformation performs translation of points against eye position
1235 // in three dimensions. Both point coordinate and eye position values are converted from
1236 // double to single precision floating point numbers producing conversion errors.
1237 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1238 // translation assuming that the:
1239 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1240 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1241
1242 // Model to view transformation performs rotation of points according to view direction.
1243 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1244 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1245 // values are converted from double to single precision floating point numbers producing
1246 // conversion errors.
1247 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1248 // of point coordinates by direction vector.
1249 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1250 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1251
1252 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1253 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1254
1255 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1256 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1257 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1258
1259 if (!IsOrthographic())
6bc6a6fc 1260 {
5a19c303 1261 // For perspective projection, the value of z in normalized device coordinates is non-linear
1262 // function of eye z coordinate. For fixed-point depth representation resolution of z in
1263 // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1264 // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1265 // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1266 // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1267 // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1268 // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1269 // the zNear will be placed similarly giving lower resolution.
1270 // Approximation of the formula for respectively large z range is:
1271 // zNear = [z * (1 + k) / (k * c)],
1272 // where:
1273 // z - distance to center of model boundaries;
1274 // k - chosen ratio, c - capacity of depth buffer;
1275 // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1276 //
1277 // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1278 // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1279 // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1280 // small applicative objects measured with "theMinMax" values.
1281 Standard_Real aZRange = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1282 Standard_Real aZMin = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1283 Standard_Real aZ = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1284 Standard_Real aZNearMin = aZ * 5.97E-4;
1285 if (aZNear < aZNearMin)
1286 {
1287 // Clip zNear according to the minimum value matching the quality.
1288 aZNear = aZNearMin;
1289 }
1290 else
1291 {
1292 // Compensate zNear conversion errors for perspective projection.
1293 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1294 }
1295
1296 // Compensate zFar conversion errors for perspective projection.
1297 aZFar += zEpsilon (aZFar);
ea764884 1298
1299 // Ensure that after all the zNear is not a negative value.
1300 if (aZNear < zEpsilon())
1301 {
1302 aZNear = zEpsilon();
1303 }
6bc6a6fc 1304 }
1305
10dbdf34 1306 theZNear = aZNear;
1307 theZFar = aZFar;
1308 return true;
6bc6a6fc 1309}
1beb58d7 1310
1311//=============================================================================
1312//function : Interpolate
1313//purpose :
1314//=============================================================================
1315template<>
1316Standard_EXPORT void NCollection_Lerp<Handle(Graphic3d_Camera)>::Interpolate (const double theT,
1317 Handle(Graphic3d_Camera)& theCamera) const
1318{
1319 if (Abs (theT - 1.0) < Precision::Confusion())
1320 {
1321 // just copy end-point transformation
1322 theCamera->Copy (myEnd);
1323 return;
1324 }
1325
1326 theCamera->Copy (myStart);
1327 if (Abs (theT - 0.0) < Precision::Confusion())
1328 {
1329 return;
1330 }
1331
1332 // apply rotation
1333 {
1334 gp_Ax3 aCamStart = cameraToAx3 (*myStart);
1335 gp_Ax3 aCamEnd = cameraToAx3 (*myEnd);
1336 gp_Trsf aTrsfStart, aTrsfEnd;
1337 aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1338 aTrsfEnd .SetTransformation (aCamEnd, gp::XOY());
1339
1340 gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1341 gp_Quaternion aRotEnd = aTrsfEnd .GetRotation();
1342 gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1343 gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1344 gp_Trsf aTrsfRot;
1345 aTrsfRot.SetRotation (aRot);
1346 theCamera->Transform (aTrsfRot);
1347 }
1348
1349 // apply translation
1350 {
1351 gp_XYZ aCenter = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myEnd->Center().XYZ(), theT);
1352 gp_XYZ anEye = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Eye().XYZ(), myEnd->Eye().XYZ(), theT);
1353 gp_XYZ anAnchor = aCenter;
1354 Standard_Real aKc = 0.0;
1355
1356 const Standard_Real aDeltaCenter = myStart->Center().Distance (myEnd->Center());
1357 const Standard_Real aDeltaEye = myStart->Eye() .Distance (myEnd->Eye());
1358 if (aDeltaEye <= gp::Resolution())
1359 {
1360 anAnchor = anEye;
1361 aKc = 1.0;
1362 }
1363 else if (aDeltaCenter > gp::Resolution())
1364 {
1365 aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1366
1367 const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myStart->Eye().XYZ(), aKc);
1368 const gp_XYZ anAnchorEnd = NCollection_Lerp<gp_XYZ>::Interpolate (myEnd ->Center().XYZ(), myEnd ->Eye().XYZ(), aKc);
1369 anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1370 }
1371
1372 const gp_Vec aDirEyeToCenter = theCamera->Direction();
1373 const Standard_Real aDistEyeCenterStart = myStart->Eye().Distance (myStart->Center());
1374 const Standard_Real aDistEyeCenterEnd = myEnd ->Eye().Distance (myEnd ->Center());
1375 const Standard_Real aDistEyeCenter = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1376 aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1377 anEye = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1378
1379 theCamera->SetCenter (aCenter);
1380 theCamera->SetEye (anEye);
1381 }
1382
1383 // apply scaling
1384 if (Abs(myStart->Scale() - myEnd->Scale()) > Precision::Confusion()
1385 && myStart->IsOrthographic())
1386 {
1387 const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (myStart->Scale(), myEnd->Scale(), theT);
1388 theCamera->SetScale (aScale);
1389 }
1390}