0024947: Redesign OCCT legacy type system -- automatic
[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
16#include <gp_Pln.hxx>
17#include <Standard_ShortReal.hxx>
18
19#include <Graphic3d_Vec4.hxx>
20#include <Graphic3d_Camera.hxx>
21
22#include <Standard_Atomic.hxx>
197ac94e 23#include <Standard_Assert.hxx>
b5ac8292 24
ed063270 25#include <NCollection_Sequence.hxx>
26
b5ac8292 27
28namespace
29{
30 // (degrees -> radians) * 0.5
197ac94e 31 static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
32
33 // default property values
34 static const Standard_Real DEFAULT_ZNEAR = 0.001;
35 static const Standard_Real DEFAULT_ZFAR = 3000.0;
b5ac8292 36
37 // atomic state counter
38 static volatile Standard_Integer THE_STATE_COUNTER = 0;
3c648527 39
40 // minimum camera distance
41 static const Standard_Real MIN_DISTANCE = Pow (0.1, ShortRealDigits() - 2);
ea764884 42
43 // z-range tolerance compatible with for floating point.
44 static Standard_Real zEpsilon()
45 {
46 return FLT_EPSILON;
47 }
48
49 // relative z-range tolerance compatible with for floating point.
50 static Standard_Real zEpsilon (const Standard_Real theValue)
51 {
52 Standard_Real aLogRadix = Log10 (Abs (theValue)) / Log10 (FLT_RADIX);
53 Standard_Real aExp = Floor (aLogRadix);
54 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
55 };
b5ac8292 56};
57
58// =======================================================================
59// function : Graphic3d_Camera
60// purpose :
61// =======================================================================
62Graphic3d_Camera::Graphic3d_Camera()
63: myUp (0.0, 1.0, 0.0),
64 myEye (0.0, 0.0, -1500.0),
65 myCenter (0.0, 0.0, 0.0),
b5ac8292 66 myAxialScale (1.0, 1.0, 1.0),
67 myProjType (Projection_Orthographic),
68 myFOVy (45.0),
197ac94e 69 myZNear (DEFAULT_ZNEAR),
70 myZFar (DEFAULT_ZFAR),
b5ac8292 71 myAspect (1.0),
72 myScale (1000.0),
73 myZFocus (1.0),
74 myZFocusType (FocusType_Relative),
75 myIOD (0.05),
197ac94e 76 myIODType (IODType_Relative)
b5ac8292 77{
78 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
79 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 80}
81
82// =======================================================================
83// function : Graphic3d_Camera
84// purpose :
85// =======================================================================
86Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
b5ac8292 87{
88 Copy (theOther);
89}
90
91// =======================================================================
92// function : CopyMappingData
93// purpose :
94// =======================================================================
95void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
96{
197ac94e 97 myFOVy = theOtherCamera->myFOVy;
98 myZNear = theOtherCamera->myZNear;
99 myZFar = theOtherCamera->myZFar;
100 myAspect = theOtherCamera->myAspect;
101 myScale = theOtherCamera->myScale;
102 myZFocus = theOtherCamera->myZFocus;
103 myZFocusType = theOtherCamera->myZFocusType;
104 myIOD = theOtherCamera->myIOD;
105 myIODType = theOtherCamera->myIODType;
106 myProjType = theOtherCamera->myProjType;
107 myProjectionState = theOtherCamera->myProjectionState;
b5ac8292 108
197ac94e 109 InvalidateProjection();
b5ac8292 110}
111
112// =======================================================================
113// function : CopyOrientationData
114// purpose :
115// =======================================================================
116void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
117{
197ac94e 118 myUp = theOtherCamera->myUp;
119 myEye = theOtherCamera->myEye;
120 myCenter = theOtherCamera->myCenter;
121 myAxialScale = theOtherCamera->myAxialScale;
b5ac8292 122 myOrientationState = theOtherCamera->myOrientationState;
123
197ac94e 124 InvalidateOrientation();
b5ac8292 125}
126
127// =======================================================================
128// function : Copy
129// purpose :
130// =======================================================================
131void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
132{
b5ac8292 133 CopyMappingData (theOther);
134 CopyOrientationData (theOther);
b5ac8292 135}
136
137// =======================================================================
138// function : SetEye
139// purpose :
140// =======================================================================
141void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
142{
143 myEye = theEye;
197ac94e 144 InvalidateOrientation();
b5ac8292 145}
146
147// =======================================================================
148// function : SetCenter
149// purpose :
150// =======================================================================
151void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
152{
153 myCenter = theCenter;
197ac94e 154 InvalidateOrientation();
b5ac8292 155}
156
157// =======================================================================
158// function : SetUp
159// purpose :
160// =======================================================================
161void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
162{
163 myUp = theUp;
197ac94e 164 InvalidateOrientation();
b5ac8292 165}
166
167// =======================================================================
168// function : SetAxialScale
169// purpose :
170// =======================================================================
197ac94e 171void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
b5ac8292 172{
173 myAxialScale = theAxialScale;
197ac94e 174 InvalidateOrientation();
b5ac8292 175}
176
177// =======================================================================
178// function : SetDistance
179// purpose :
180// =======================================================================
181void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
182{
183 gp_Vec aCenter2Eye (Direction());
184 aCenter2Eye.Reverse();
3c648527 185
186 // Camera should have non-zero distance.
187 aCenter2Eye.Scale (Max (theDistance, MIN_DISTANCE));
b5ac8292 188 SetEye (Center().Translated (aCenter2Eye));
189}
190
191// =======================================================================
192// function : Distance
193// purpose :
194// =======================================================================
195Standard_Real Graphic3d_Camera::Distance() const
196{
197 return myEye.Distance (myCenter);
198}
199
200// =======================================================================
201// function : SetDirection
202// purpose :
203// =======================================================================
204void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
205{
206 gp_Vec aScaledDir (theDir);
207 aScaledDir.Scale (Distance());
208 aScaledDir.Reverse();
209 SetEye (Center().Translated (aScaledDir));
210}
211
212// =======================================================================
213// function : Direction
214// purpose :
215// =======================================================================
216gp_Dir Graphic3d_Camera::Direction() const
217{
218 return gp_Dir (gp_Vec (myEye, myCenter));
219}
220
221// =======================================================================
222// function : SetScale
223// purpose :
224// =======================================================================
225void Graphic3d_Camera::SetScale (const Standard_Real theScale)
226{
227 myScale = theScale;
228
229 switch (myProjType)
230 {
231 case Projection_Perspective :
232 case Projection_Stereo :
233 case Projection_MonoLeftEye :
234 case Projection_MonoRightEye :
235 {
236 Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0);
237 SetDistance (aDistance);
238 }
239
240 default :
241 break;
242 }
243
197ac94e 244 InvalidateProjection();
b5ac8292 245}
246
247// =======================================================================
248// function : Scale
249// purpose :
250// =======================================================================
251Standard_Real Graphic3d_Camera::Scale() const
252{
253 switch (myProjType)
254 {
255 case Projection_Orthographic :
256 return myScale;
257
258 // case Projection_Perspective :
259 // case Projection_Stereo :
260 // case Projection_MonoLeftEye :
261 // case Projection_MonoRightEye :
262 default :
197ac94e 263 return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0);
b5ac8292 264 }
265}
266
267// =======================================================================
268// function : SetProjectionType
269// purpose :
270// =======================================================================
271void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
272{
273 Projection anOldType = myProjType;
274
275 if (anOldType == theProjectionType)
276 {
277 return;
278 }
279
197ac94e 280 if (anOldType == Projection_Orthographic)
b5ac8292 281 {
197ac94e 282 if (myZNear <= RealEpsilon())
283 {
284 myZNear = DEFAULT_ZNEAR;
285 }
286 if (myZFar <= RealEpsilon())
287 {
288 myZFar = DEFAULT_ZFAR;
289 }
b5ac8292 290 }
291
197ac94e 292 myProjType = theProjectionType;
293
294 InvalidateProjection();
b5ac8292 295}
296
297// =======================================================================
298// function : SetFOVy
299// purpose :
300// =======================================================================
301void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
302{
303 myFOVy = theFOVy;
197ac94e 304 InvalidateProjection();
b5ac8292 305}
306
307// =======================================================================
197ac94e 308// function : SetZRange
b5ac8292 309// purpose :
310// =======================================================================
197ac94e 311void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
312 const Standard_Real theZFar)
b5ac8292 313{
197ac94e 314 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
315 if (!IsOrthographic())
b5ac8292 316 {
197ac94e 317 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
318 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
b5ac8292 319 }
320
197ac94e 321 myZNear = theZNear;
322 myZFar = theZFar;
b5ac8292 323
197ac94e 324 InvalidateProjection();
b5ac8292 325}
326
327// =======================================================================
328// function : SetAspect
329// purpose :
330// =======================================================================
331void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
332{
333 myAspect = theAspect;
197ac94e 334 InvalidateProjection();
b5ac8292 335}
336
337// =======================================================================
338// function : SetZFocus
339// purpose :
340// =======================================================================
341void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
342{
343 myZFocusType = theType;
344 myZFocus = theZFocus;
197ac94e 345 InvalidateProjection();
b5ac8292 346}
347
348// =======================================================================
349// function : SetIOD
350// purpose :
351// =======================================================================
352void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
353{
354 myIODType = theType;
355 myIOD = theIOD;
197ac94e 356 InvalidateProjection();
b5ac8292 357}
358
359// =======================================================================
360// function : OrthogonalizeUp
361// purpose :
362// =======================================================================
363void Graphic3d_Camera::OrthogonalizeUp()
364{
197ac94e 365 SetUp (OrthogonalizedUp());
b5ac8292 366}
367
368// =======================================================================
197ac94e 369// function : OrthogonalizedUp
b5ac8292 370// purpose :
371// =======================================================================
197ac94e 372gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
b5ac8292 373{
197ac94e 374 gp_Dir aDir = Direction();
375 gp_Dir aLeft = aDir.Crossed (Up());
b5ac8292 376
197ac94e 377 // recompute up as: up = left x direction
378 return aLeft.Crossed (aDir);
b5ac8292 379}
380
381// =======================================================================
382// function : Transform
383// purpose :
384// =======================================================================
385void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
386{
387 myUp.Transform (theTrsf);
388 myEye.Transform (theTrsf);
389 myCenter.Transform (theTrsf);
197ac94e 390 InvalidateOrientation();
b5ac8292 391}
392
393// =======================================================================
394// function : safePointCast
395// purpose :
396// =======================================================================
197ac94e 397static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
b5ac8292 398{
399 Standard_Real aLim = 1e15f;
197ac94e 400
b5ac8292 401 // have to deal with values greater then max float
402 gp_Pnt aSafePoint = thePnt;
403 const Standard_Real aBigFloat = aLim * 0.1f;
404 if (Abs (aSafePoint.X()) > aLim)
405 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
406 if (Abs (aSafePoint.Y()) > aLim)
407 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
408 if (Abs (aSafePoint.Z()) > aLim)
409 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
410
411 // convert point
197ac94e 412 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
b5ac8292 413
414 return aPnt;
415}
416
417// =======================================================================
418// function : Project
419// purpose :
420// =======================================================================
421gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
422{
197ac94e 423 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
424 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 425
426 // use compatible type of point
197ac94e 427 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 428
429 aPnt = aViewMx * aPnt; // convert to view coordinate space
430 aPnt = aProjMx * aPnt; // convert to projection coordinate space
431
432 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
433
434 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
435}
436
437// =======================================================================
438// function : UnProject
439// purpose :
440// =======================================================================
441gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
442{
197ac94e 443 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
444 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 445
197ac94e 446 Graphic3d_Mat4d aInvView;
447 Graphic3d_Mat4d aInvProj;
b5ac8292 448
449 // this case should never happen
450 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
451 {
452 return gp_Pnt (0.0, 0.0, 0.0);
453 }
454
455 // use compatible type of point
197ac94e 456 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 457
458 aPnt = aInvProj * aPnt; // convert to view coordinate space
459 aPnt = aInvView * aPnt; // convert to world coordinate space
460
461 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
462
463 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
464}
465
466// =======================================================================
467// function : ConvertView2Proj
468// purpose :
469// =======================================================================
470gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
471{
197ac94e 472 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 473
474 // use compatible type of point
197ac94e 475 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 476
477 aPnt = aProjMx * aPnt; // convert to projection coordinate space
478
479 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
480
481 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
482}
483
484// =======================================================================
485// function : ConvertProj2View
486// purpose :
487// =======================================================================
488gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
489{
197ac94e 490 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 491
197ac94e 492 Graphic3d_Mat4d aInvProj;
b5ac8292 493
494 // this case should never happen, but...
495 if (!aProjMx.Inverted (aInvProj))
496 {
197ac94e 497 return gp_Pnt (0, 0, 0);
b5ac8292 498 }
499
500 // use compatible type of point
197ac94e 501 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 502
503 aPnt = aInvProj * aPnt; // convert to view coordinate space
504
505 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
506
507 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
508}
509
510// =======================================================================
511// function : ConvertWorld2View
512// purpose :
513// =======================================================================
514gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
515{
197ac94e 516 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 517
518 // use compatible type of point
197ac94e 519 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 520
521 aPnt = aViewMx * aPnt; // convert to view coordinate space
522
523 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
524
525 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
526}
527
528// =======================================================================
529// function : ConvertView2World
530// purpose :
531// =======================================================================
532gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
533{
197ac94e 534 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 535
197ac94e 536 Graphic3d_Mat4d aInvView;
b5ac8292 537
538 if (!aViewMx.Inverted (aInvView))
539 {
540 return gp_Pnt(0, 0, 0);
541 }
542
543 // use compatible type of point
197ac94e 544 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 545
546 aPnt = aInvView * aPnt; // convert to world coordinate space
547
548 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
549
550 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
551}
552
553// =======================================================================
554// function : ViewDimensions
555// purpose :
556// =======================================================================
197ac94e 557gp_XYZ Graphic3d_Camera::ViewDimensions() const
b5ac8292 558{
559 // view plane dimensions
539d3a1b 560 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy));
561 Standard_Real aSizeX, aSizeY;
562 if (myAspect > 1.0)
563 {
564 aSizeX = aSize * myAspect;
565 aSizeY = aSize;
566 }
567 else
568 {
569 aSizeX = aSize;
570 aSizeY = aSize / myAspect;
571 }
b5ac8292 572
573 // and frustum depth
197ac94e 574 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
b5ac8292 575}
576
577// =======================================================================
197ac94e 578// function : Frustum
b5ac8292 579// purpose :
580// =======================================================================
197ac94e 581void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
582 gp_Pln& theRight,
583 gp_Pln& theBottom,
584 gp_Pln& theTop,
585 gp_Pln& theNear,
586 gp_Pln& theFar) const
b5ac8292 587{
197ac94e 588 gp_Vec aProjection = gp_Vec (Direction());
589 gp_Vec anUp = OrthogonalizedUp();
590 gp_Vec aSide = aProjection ^ anUp;
591
592 Standard_ASSERT_RAISE (
593 !aProjection.IsParallel (anUp, Precision::Angular()),
594 "Can not derive SIDE = PROJ x UP - directions are parallel");
595
596 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
597 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
598
599 Standard_Real aHScaleHor = Scale() * 0.5 * Aspect();
600 Standard_Real aHScaleVer = Scale() * 0.5;
601
602 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
603 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
604 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
605 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
606
607 gp_Vec aDirLeft = aSide;
608 gp_Vec aDirRight = -aSide;
609 gp_Vec aDirBottom = anUp;
610 gp_Vec aDirTop = -anUp;
611 if (!IsOrthographic())
612 {
613 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
614 Standard_Real aHFOVVer = DTR_HALF * FOVy();
615 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
616 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
617 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
618 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
619 }
620
621 theLeft = gp_Pln (aPntLeft, aDirLeft);
622 theRight = gp_Pln (aPntRight, aDirRight);
623 theBottom = gp_Pln (aPntBottom, aDirBottom);
624 theTop = gp_Pln (aPntTop, aDirTop);
625}
626
627// =======================================================================
628// function : OrientationMatrix
629// purpose :
630// =======================================================================
631const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
632{
633 return *UpdateOrientation (myMatricesD).Orientation;
634}
635
636// =======================================================================
637// function : OrientationMatrixF
638// purpose :
639// =======================================================================
640const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
641{
642 return *UpdateOrientation (myMatricesF).Orientation;
643}
644
645// =======================================================================
646// function : ProjectionMatrix
647// purpose :
648// =======================================================================
649const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
650{
651 return *UpdateProjection (myMatricesD).MProjection;
652}
653
654// =======================================================================
655// function : ProjectionMatrixF
656// purpose :
657// =======================================================================
658const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
659{
660 return *UpdateProjection (myMatricesF).MProjection;
661}
662
663// =======================================================================
664// function : ProjectionStereoLeft
665// purpose :
666// =======================================================================
667const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
668{
669 return *UpdateProjection (myMatricesD).LProjection;
670}
671
672// =======================================================================
673// function : ProjectionStereoLeftF
674// purpose :
675// =======================================================================
676const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
677{
678 return *UpdateProjection (myMatricesF).LProjection;
679}
680
681// =======================================================================
682// function : ProjectionStereoRight
683// purpose :
684// =======================================================================
685const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
686{
687 return *UpdateProjection (myMatricesD).RProjection;
688}
689
690// =======================================================================
691// function : ProjectionStereoRightF
692// purpose :
693// =======================================================================
694const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
695{
696 return *UpdateProjection (myMatricesF).RProjection;
b5ac8292 697}
698
699// =======================================================================
700// function : UpdateProjection
701// purpose :
702// =======================================================================
197ac94e 703template <typename Elem_t>
704Graphic3d_Camera::TransformMatrices<Elem_t>&
705 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 706{
197ac94e 707 if (theMatrices.IsProjectionValid())
b5ac8292 708 {
197ac94e 709 return theMatrices; // for inline accessors
b5ac8292 710 }
711
197ac94e 712 theMatrices.InitProjection();
b5ac8292 713
714 // sets top of frustum based on FOVy and near clipping plane
197ac94e 715 Elem_t aScale = static_cast<Elem_t> (myScale);
716 Elem_t aZNear = static_cast<Elem_t> (myZNear);
717 Elem_t aZFar = static_cast<Elem_t> (myZFar);
718 Elem_t anAspect = static_cast<Elem_t> (myAspect);
ab1c121b 719 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
b5ac8292 720 if (IsOrthographic())
721 {
ab1c121b 722 aDXHalf = aScale * Elem_t (0.5);
197ac94e 723 aDYHalf = aScale * Elem_t (0.5);
b5ac8292 724 }
725 else
726 {
ab1c121b 727 aDXHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
197ac94e 728 aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
b5ac8292 729 }
730
ab1c121b 731 if (anAspect > 1.0)
732 {
733 aDXHalf *= anAspect;
734 }
735 else
736 {
737 aDYHalf /= anAspect;
738 }
739
b5ac8292 740 // sets right of frustum based on aspect ratio
197ac94e 741 Elem_t aLeft = -aDXHalf;
742 Elem_t aRight = aDXHalf;
743 Elem_t aBot = -aDYHalf;
744 Elem_t aTop = aDYHalf;
b5ac8292 745
197ac94e 746 Elem_t aIOD = myIODType == IODType_Relative
747 ? static_cast<Elem_t> (myIOD * Distance())
748 : static_cast<Elem_t> (myIOD);
b5ac8292 749
197ac94e 750 Elem_t aFocus = myZFocusType == FocusType_Relative
751 ? static_cast<Elem_t> (myZFocus * Distance())
752 : static_cast<Elem_t> (myZFocus);
b5ac8292 753
754 switch (myProjType)
755 {
756 case Projection_Orthographic :
197ac94e 757 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 758 break;
759
760 case Projection_Perspective :
197ac94e 761 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 762 break;
763
764 case Projection_MonoLeftEye :
765 {
197ac94e 766 StereoEyeProj (aLeft, aRight, aBot, aTop,
767 aZNear, aZFar, aIOD, aFocus,
768 Standard_True, *theMatrices.MProjection);
38a0206f 769 *theMatrices.LProjection = *theMatrices.MProjection;
b5ac8292 770 break;
771 }
772
773 case Projection_MonoRightEye :
774 {
197ac94e 775 StereoEyeProj (aLeft, aRight, aBot, aTop,
776 aZNear, aZFar, aIOD, aFocus,
777 Standard_False, *theMatrices.MProjection);
38a0206f 778 *theMatrices.RProjection = *theMatrices.MProjection;
b5ac8292 779 break;
780 }
781
782 case Projection_Stereo :
783 {
197ac94e 784 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 785
197ac94e 786 StereoEyeProj (aLeft, aRight, aBot, aTop,
787 aZNear, aZFar, aIOD, aFocus,
788 Standard_True,
789 *theMatrices.LProjection);
b5ac8292 790
197ac94e 791 StereoEyeProj (aLeft, aRight, aBot, aTop,
792 aZNear, aZFar, aIOD, aFocus,
793 Standard_False,
794 *theMatrices.RProjection);
b5ac8292 795 break;
796 }
797 }
197ac94e 798
799 return theMatrices; // for inline accessors
b5ac8292 800}
801
802// =======================================================================
803// function : UpdateOrientation
804// purpose :
805// =======================================================================
197ac94e 806template <typename Elem_t>
807Graphic3d_Camera::TransformMatrices<Elem_t>&
808 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 809{
197ac94e 810 if (theMatrices.IsOrientationValid())
b5ac8292 811 {
197ac94e 812 return theMatrices; // for inline accessors
b5ac8292 813 }
814
197ac94e 815 theMatrices.InitOrientation();
816
817 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
818 static_cast<Elem_t> (myEye.Y()),
819 static_cast<Elem_t> (myEye.Z()));
820
821 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
822 static_cast<Elem_t> (myCenter.Y()),
823 static_cast<Elem_t> (myCenter.Z()));
b5ac8292 824
197ac94e 825 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
826 static_cast<Elem_t> (myUp.Y()),
827 static_cast<Elem_t> (myUp.Z()));
b5ac8292 828
197ac94e 829 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
830 static_cast<Elem_t> (myAxialScale.Y()),
831 static_cast<Elem_t> (myAxialScale.Z()));
b5ac8292 832
197ac94e 833 LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
b5ac8292 834
197ac94e 835 return theMatrices; // for inline accessors
836}
b5ac8292 837
197ac94e 838// =======================================================================
839// function : InvalidateProjection
840// purpose :
841// =======================================================================
842void Graphic3d_Camera::InvalidateProjection()
843{
844 myMatricesD.ResetProjection();
845 myMatricesF.ResetProjection();
846 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
847}
b5ac8292 848
197ac94e 849// =======================================================================
850// function : InvalidateOrientation
851// purpose :
852// =======================================================================
853void Graphic3d_Camera::InvalidateOrientation()
854{
855 myMatricesD.ResetOrientation();
856 myMatricesF.ResetOrientation();
857 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 858}
859
860// =======================================================================
861// function : OrthoProj
862// purpose :
863// =======================================================================
197ac94e 864template <typename Elem_t>
865void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
866 const Elem_t theRight,
867 const Elem_t theBottom,
868 const Elem_t theTop,
869 const Elem_t theNear,
870 const Elem_t theFar,
871 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 872{
873 // row 0
197ac94e 874 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
875 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
876 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
b5ac8292 877 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
878
879 // row 1
197ac94e 880 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
881 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
882 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
b5ac8292 883 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
884
885 // row 2
197ac94e 886 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
887 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
888 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
b5ac8292 889 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
890
891 // row 3
197ac94e 892 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
893 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
894 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
895 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
b5ac8292 896}
897
898// =======================================================================
899// function : PerspectiveProj
900// purpose :
901// =======================================================================
197ac94e 902template <typename Elem_t>
903void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
904 const Elem_t theRight,
905 const Elem_t theBottom,
906 const Elem_t theTop,
907 const Elem_t theNear,
908 const Elem_t theFar,
909 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 910{
911 // column 0
197ac94e 912 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
913 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
914 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
915 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
b5ac8292 916
917 // column 1
197ac94e 918 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
919 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
920 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
921 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
b5ac8292 922
923 // column 2
924 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
925 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
926 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
197ac94e 927 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
b5ac8292 928
929 // column 3
197ac94e 930 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
931 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
932 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
933 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
b5ac8292 934}
935
936// =======================================================================
937// function : StereoEyeProj
938// purpose :
939// =======================================================================
197ac94e 940template <typename Elem_t>
941void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
942 const Elem_t theRight,
943 const Elem_t theBottom,
944 const Elem_t theTop,
945 const Elem_t theNear,
946 const Elem_t theFar,
947 const Elem_t theIOD,
948 const Elem_t theZFocus,
949 const Standard_Boolean theIsLeft,
950 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 951{
197ac94e 952 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
953 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
b5ac8292 954
955 // construct eye projection matrix
956 PerspectiveProj (theLeft + aDXStereoShift,
957 theRight + aDXStereoShift,
958 theBottom, theTop, theNear, theFar,
b5ac8292 959 theOutMx);
960
197ac94e 961 if (theIOD != Elem_t (0.0))
b5ac8292 962 {
963 // X translation to cancel parallax
197ac94e 964 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
b5ac8292 965 }
966}
967
968// =======================================================================
969// function : LookOrientation
970// purpose :
971// =======================================================================
197ac94e 972template <typename Elem_t>
973void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
974 const NCollection_Vec3<Elem_t>& theLookAt,
975 const NCollection_Vec3<Elem_t>& theUpDir,
976 const NCollection_Vec3<Elem_t>& theAxialScale,
977 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 978{
197ac94e 979 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
b5ac8292 980 aForward.Normalize();
981
982 // side = forward x up
197ac94e 983 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
b5ac8292 984 aSide.Normalize();
985
986 // recompute up as: up = side x forward
197ac94e 987 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
b5ac8292 988
197ac94e 989 NCollection_Mat4<Elem_t> aLookMx;
b5ac8292 990 aLookMx.SetRow (0, aSide);
991 aLookMx.SetRow (1, anUp);
992 aLookMx.SetRow (2, -aForward);
993
197ac94e 994 theOutMx.InitIdentity();
995 theOutMx.Multiply (aLookMx);
b5ac8292 996 theOutMx.Translate (-theEye);
997
197ac94e 998 NCollection_Mat4<Elem_t> anAxialScaleMx;
b5ac8292 999 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1000 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1001 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1002
1003 theOutMx.Multiply (anAxialScaleMx);
1004}
6bc6a6fc 1005
1006//=============================================================================
1007//function : ZFitAll
1008//purpose :
1009//=============================================================================
1010void Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor, const Bnd_Box& theMinMax, const Bnd_Box& theGraphicBB)
1011{
1012 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1013
ea764884 1014 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1015 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1016 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1017 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
ed063270 1018 if (theGraphicBB.IsVoid())
6bc6a6fc 1019 {
ea764884 1020 SetZRange (DEFAULT_ZNEAR, DEFAULT_ZFAR);
6bc6a6fc 1021 return;
1022 }
1023
ea764884 1024 // Measure depth of boundary points from camera eye.
ed063270 1025 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1026
ea764884 1027 Standard_Real aGraphicBB[6];
ed063270 1028 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1029
1030 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1031 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1032 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1033 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1034 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1035 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1036 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1037 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1038
1039 if (!theMinMax.IsVoid() && !theMinMax.IsWhole())
6bc6a6fc 1040 {
ea764884 1041 Standard_Real aMinMax[6];
ed063270 1042 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1043
1044 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1045 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1046 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1047 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1048 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1049 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1050 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1051 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1052 }
6bc6a6fc 1053
ea764884 1054 // Camera eye plane.
6bc6a6fc 1055 gp_Dir aCamDir = Direction();
1056 gp_Pnt aCamEye = myEye;
1057 gp_Pln aCamPln (aCamEye, aCamDir);
1058
1059 Standard_Real aModelMinDist = RealLast();
1060 Standard_Real aModelMaxDist = RealFirst();
1061 Standard_Real aGraphicMinDist = RealLast();
1062 Standard_Real aGraphicMaxDist = RealFirst();
1063
1064 const gp_XYZ& anAxialScale = myAxialScale;
1065
ea764884 1066 // Get minimum and maximum distances to the eye plane.
ed063270 1067 Standard_Integer aCounter = 0;
1068 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1069 for (; aPntIt.More(); aPntIt.Next())
6bc6a6fc 1070 {
ed063270 1071 gp_Pnt aMeasurePnt = aPntIt.Value();
6bc6a6fc 1072
1073 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
ed063270 1074 aMeasurePnt.Y() * anAxialScale.Y(),
1075 aMeasurePnt.Z() * anAxialScale.Z());
6bc6a6fc 1076
1077 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1078
ea764884 1079 // Check if the camera is intruded into the scene.
6bc6a6fc 1080 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1081 {
1082 aDistance *= -1;
1083 }
1084
ea764884 1085 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
ed063270 1086 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphicMinDist;
1087 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphicMaxDist;
6bc6a6fc 1088 aChangeMinDist = Min (aDistance, aChangeMinDist);
1089 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
ed063270 1090 aCounter++;
6bc6a6fc 1091 }
1092
ea764884 1093 // Compute depth of bounding box center.
6bc6a6fc 1094 Standard_Real aMidDepth = (aGraphicMinDist + aGraphicMaxDist) * 0.5;
1095 Standard_Real aHalfDepth = (aGraphicMaxDist - aGraphicMinDist) * 0.5;
1096
ea764884 1097 // Compute enlarged or shrank near and far z ranges.
35c4a17c 1098 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1099 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
6bc6a6fc 1100
1101 if (!IsOrthographic())
1102 {
ea764884 1103 // Everything is behind the perspective camera.
1104 if (aZFar < zEpsilon())
6bc6a6fc 1105 {
ea764884 1106 SetZRange (DEFAULT_ZNEAR, DEFAULT_ZFAR);
1107 return;
6bc6a6fc 1108 }
ea764884 1109
1110 // For better perspective the zNear value should not be less than zEpsilon (zFar).
1111 // If zNear computed by graphical boundaries do not meet the rule (e.g. it is negative
1112 // when computing it for grid) it could be increased up to minimum depth computed by
1113 // application min max values. This means that z-fit can sacrifice presentation of
1114 // non primary application graphical objects in favor of better perspective projection;
1115 if (aZNear < zEpsilon (aZFar))
6bc6a6fc 1116 {
ea764884 1117 // Otherwise it should be increased up to zEpsilon (1.0) to avoid clipping of primary
1118 // graphical objects.
1119 if (aModelMinDist < zEpsilon (aZFar))
1120 {
1121 aMidDepth = (aModelMinDist + aModelMaxDist) * 0.5;
1122 aHalfDepth = (aModelMinDist - aModelMaxDist) * 0.5;
1123 aZNear = Max (zEpsilon(), aMidDepth - aHalfDepth * theScaleFactor);
1124 }
1125 else
1126 {
1127 aZNear = zEpsilon (aZFar);
1128 }
6bc6a6fc 1129 }
1130 }
1131
ea764884 1132 //
1133 // Consider clipping errors due to double to single precision floating-point conversion.
1134 //
1135
1136 // Model to view transformation performs translation of points against eye position
1137 // in three dimensions. Both point coordinate and eye position values are converted from
1138 // double to single precision floating point numbers producing conversion errors.
1139 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1140 // translation assuming that the:
1141 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1142 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1143
1144 // Model to view transformation performs rotation of points according to view direction.
1145 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1146 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1147 // values are converted from double to single precision floating point numbers producing
1148 // conversion errors.
1149 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1150 // of point coordinates by direction vector.
1151 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1152 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1153
1154 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1155 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1156
1157 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1158 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1159 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1160
1161 if (!IsOrthographic())
6bc6a6fc 1162 {
ea764884 1163 // Compensate zNear, zFar conversion errors for perspective projection.
1164 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1165 aZFar += zEpsilon (aZFar);
1166
1167 // Ensure that after all the zNear is not a negative value.
1168 if (aZNear < zEpsilon())
1169 {
1170 aZNear = zEpsilon();
1171 }
6bc6a6fc 1172 }
1173
1174 SetZRange (aZNear, aZFar);
1175}