# Enable parallel projection without resetting the camera

**URL:** <https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289>\
**Category:** Development\
**Created:** [March 1, 2021, 8:54pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289 "2021-03-01T20:54:04Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![rodrigomologni](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/r/54ee81/32.png) [@rodrigomologni](https://discourse.vtk.org/u/rodrigomologni)\
**Post date:** [March 1, 2021, 8:54pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/1 "2021-03-01T20:54:04Z")

</div>

Hi, Support!

When I press P to enable parallel projection, the camera is “restarted”. Is this a bug? Must I reimplement the transformations to overcome this problem or is there a simpler solution?

Thanks for any help!

> **parallel\_projection\_bug.py**
>
> ```python
> import vtk
> 
> def keyboard_callback(object, event):
> if object.GetKeyCode() == 'p':
> camera = renderer.GetActiveCamera()
> flag = camera.GetParallelProjection()
> camera.SetParallelProjection(not flag)
> 
> source = vtk.vtkSphereSource()
> 
> mapper = vtk.vtkPolyDataMapper()
> mapper.SetInputConnection(source.GetOutputPort())
> 
> actor = vtk.vtkActor()
> actor.SetMapper(mapper)
> actor.GetProperty().EdgeVisibilityOn()
> 
> renderer = vtk.vtkRenderer()
> renderer.AddActor(actor)
> renderer.SetBackground(.3, .3, .3)
> 
> window = vtk.vtkRenderWindow()
> window.AddRenderer(renderer)
> window.SetSize(800, 600)
> 
> interactor = vtk.vtkRenderWindowInteractor()
> interactor.AddObserver('KeyPressEvent', keyboard_callback)
> interactor.SetRenderWindow(window)
> interactor.SetInteractorStyle(vtk.vtkInteractorStyleRubberBandPick())
> interactor.Start()
> 
> ```

 ![parallel_projection_bug](https://discourse.vtk.org/uploads/default/original/2X/3/3f4e2dfe0bff8e230f0947187f791d7269994024.gif)

---

<div class="post-metadata">

**Author:** ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)\
**Post date:** [March 1, 2021, 9:12pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/2 "2021-03-01T21:12:35Z")

</div>

Probably it is not a bug. These two projections are completely different, so you cannot keep camera parameters when switching. If for your application you don’t find VTK’s behavior optimal then you can compute the new camera parameters before switching and set them in the camera after switching projection mode.

---

<div class="post-metadata">

**Author:** ![rodrigomologni](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/r/54ee81/32.png) [@rodrigomologni](https://discourse.vtk.org/u/rodrigomologni)\
**Post date:** [March 1, 2021, 9:19pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/3 "2021-03-01T21:19:14Z")

</div>

@lassoan Thank you for answering me. I will check these parameters.

---

<div class="post-metadata">

**Author:** ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)\
**Post date:** [March 1, 2021, 10:24pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/4 "2021-03-01T22:24:22Z")

</div>

The parallel vs. perspective projection are different but not completely different. There are lots of parameters that they have in common:

- Camera Position
- Camera FocalPoint
- ClippingRange

The big difference is that parallel projection uses “ParallelScale”, but perspective uses “ViewAngle”. But even these parameters are closely related, because they are just two different ways of describing the height of the view (ParallelScale describes the height as a length, while ViewAngle describes the height as an angle).

And, of course, lengths and angles are related to each other through trigonometry, so ParallelScale and ViewAngle are in fact mathematically related:

```python
ParallelScale = 2*(Distance*tan(0.5*ViewAngle))

```

In this equation the “Distance” is the distance from the camera to the focal point (which is usually the same as the distance from the camera to the object of interest).

So, given a perspective view it’s generally possible to compute a good parallel view and vice-versa. But VTK does not do this.

---

<div class="post-metadata">

**Author:** ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)\
**Post date:** [March 1, 2021, 11:41pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/5 "2021-03-01T23:41:52Z")

</div>

What I meant is that parallel and perspective projections are fundamentally different, so it is not possible to compute parameters that results in generally equivalent views.

> [@dgobbi](#):
>
> So, given a perspective view it’s generally possible to compute a good parallel view and vice-versa. But VTK does not do this.

I think VTK’s behavior is reasonable. I would not expect vtkCamera to change any other of its parameters when I call SetParallelProjectionOn/Off. Instead, when the application switches between projection modes then it can compute the parameters that are equivalent for the particular use case (or call generic conversion methods available in [vtkRenderer](https://vtk.org/doc/nightly/html/classvtkRenderer.html): `ResetCamera(bounds)`, `ResetCameraScreenSpace(bounds)`).

---

<div class="post-metadata">

**Author:** ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)\
**Post date:** [March 2, 2021, 12:20am UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/6 "2021-03-02T00:20:14Z")

</div>

However, the original poster specifically asked for methods that do not involve resetting the camera. My reading of the question was, is there a way to switch between perspective and parallel projection that keeps an (approximately) spherical object the same size within the view?

---

<div class="post-metadata">

**Author:** ![rodrigomologni](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/r/54ee81/32.png) [@rodrigomologni](https://discourse.vtk.org/u/rodrigomologni)\
**Post date:** [March 2, 2021, 1:24am UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/7 "2021-03-02T01:24:55Z")

</div>

> My reading of the question was, is there a way to switch between perspective and parallel projection that keeps an (approximately) spherical object the same size within the view?

@dgobbi Yes, I would like to do exactly that, as shown below (fake image).  
@lassoan Sorry for not being clear on my question.

![parallel_projection](https://discourse.vtk.org/uploads/default/original/2X/7/73c4b4c3f51b016f2188a442a2853eb3529f8be5.gif)

@lassoan and @dgobbi Thank you both very much for the explanations and suggestions. They will help me to try to overcome this problem.

---

<div class="post-metadata">

**Author:** ![rodrigomologni](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/r/54ee81/32.png) [@rodrigomologni](https://discourse.vtk.org/u/rodrigomologni)\
**Post date:** [March 6, 2021, 12:29pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/8 "2021-03-06T12:29:38Z")

</div>

### To: @dgobbi

Dear Gobbi,

> [@dgobbi](#):
>
> ```auto
> ParallelScale = 2*(Distance*tan(0.5*ViewAngle))
> 
> ```

The equation you provided is producing different results than VTK. I found another equation in the VTK code that solved the problem:

```auto
ParallelScale = Distance * sin(0.5*ViewAngle)

```

Thank you very much for your help!

### To: @lassoan

Dear Lasso,

> [@lassoan](#):
>
> These two projections are completely different, so you cannot keep camera parameters when switching.

I solved the problem by setting the position and the parallel projection scale of the active camera.

> [@lassoan](#):
>
> What I meant is that parallel and perspective projections are fundamentally different, so it is not possible to compute parameters that results in generally equivalent views.

@dgobbi is right! There is a geometric relationship between parallel and perspective projections. I used this relationship to enable/disable the parallel projection of a same camera without producing the “reset camera” effect.

> [@lassoan](#):
>
> Probably it is not a bug.

You’re right! It’s not a bug. However, I see this problem as an unwanted effect that could be solved within the VTK.

Thank you for your help!

### Solution

> **parallel\_projection\_bug\_solved.py**
>
> ```python
> import vtk
> import math
> 
> def keyboard_callback(caller, event):
> if caller.GetKeyCode() == 'p':
> camera = renderer.GetActiveCamera()
> angle = camera.GetViewAngle()
> angle = math.radians(angle)
> if camera.GetParallelProjection():
> point = camera.GetFocalPoint()
> direction = camera.GetDirectionOfProjection()
> scale = camera.GetParallelScale()
> distance = scale / math.sin(.5 * angle)
> x = point[0] - distance * direction[0]
> y = point[1] - distance * direction[1]
> z = point[2] - distance * direction[2]
> camera.SetPosition(x, y, z)
> camera.ParallelProjectionOff()
> renderer.ResetCameraClippingRange()
> else:
> distance = camera.GetDistance()
> scale = distance * math.sin(.5 * angle)
> camera.SetParallelScale(scale)
> camera.ParallelProjectionOn()
> window.Render()
> 
> source = vtk.vtkSphereSource()
> 
> mapper = vtk.vtkPolyDataMapper()
> mapper.SetInputConnection(source.GetOutputPort())
> 
> actor = vtk.vtkActor()
> actor.SetMapper(mapper)
> actor.GetProperty().EdgeVisibilityOn()
> 
> renderer = vtk.vtkRenderer()
> renderer.AddActor(actor)
> renderer.SetBackground(.3, .3, .3)
> renderer.GetActiveCamera().ParallelProjectionOn()
> renderer.ResetCamera()
> 
> window = vtk.vtkRenderWindow()
> window.AddRenderer(renderer)
> window.SetSize(800, 600)
> 
> interactor = vtk.vtkRenderWindowInteractor()
> interactor.AddObserver('KeyPressEvent', keyboard_callback)
> interactor.SetRenderWindow(window)
> interactor.SetInteractorStyle(vtk.vtkInteractorStyleRubberBandPick())
> interactor.Start()
> 
> ```

![Untitled](https://discourse.vtk.org/uploads/default/original/2X/7/71ee8575be4dc2b10ed03b5c28ba4eb620603056.gif)

![Untitled](https://discourse.vtk.org/uploads/default/original/2X/3/3d5a1cbbcbddcee3e72038cf3b777c06d4a05133.gif)

---

<div class="post-metadata">

**Author:** ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)\
**Post date:** [March 6, 2021, 4:09pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/9 "2021-03-06T16:09:44Z")

</div>

Hi Rodrigo,

I might have been mistaken about the factor of two, but not about using “tan()”. If sin() seems to work, that’s only because sin() and tan() give similar results for small angles.

Using sin() would only be correct if “Distance” was measured along the hypotenuse. But it’s not. This can be shown with a very simple diagram.  
 ![hypotenuse](https://discourse.vtk.org/uploads/default/original/2X/4/436a9112d8a82c9bc480e3148dbd6ca2ecab7dfe.png)

---

<div class="post-metadata">

**Author:** ![rodrigomologni](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/r/54ee81/32.png) [@rodrigomologni](https://discourse.vtk.org/u/rodrigomologni)\
**Post date:** [March 6, 2021, 4:51pm UTC](https://discourse.vtk.org/t/enable-parallel-projection-without-resetting-the-camera/5289/10 "2021-03-06T16:51:20Z")

</div>

Hi @dgobbi,

You’re right again! I didn’t try to understand, but VTK uses `sin` instead of `tan`. I had to use `sin` to produce the same result as VTK. Thank you for your attention!

Source: [vtkRenderer.cxx](https://gitlab.kitware.com/rodrigomologni/vtk/-/blob/master/Rendering/Core/vtkRenderer.cxx) (line 1162)
