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