5
$\begingroup$

Here is an example how to use Dynamic inside Manipulate for smooth rotation. But it does not work for the following code.

Manipulate[
 Show[Graphics3D[Cube[]], 
  ViewPoint -> 
   RotationMatrix[Dynamic@fi, 
     RotationMatrix[Dynamic@fi, {0, 1, 1}] . {0, 0, 
       1}] . {1.3`, -2.4`, 2.`}], {fi, 0, 2 Pi}]

It can be solved by wrapping whole view point expression by Dynamic instead of using Dynamic@fi.

Manipulate[
 Show[Graphics3D[Cube[]], 
  ViewPoint -> 
   Dynamic[RotationMatrix[fi, 
      RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}] . {1.3`, -2.4`, 
      2.`}]], {fi, 0, 2 Pi}]

But then if you accidently click and drag the graphics by mouse an error message is thrown.

How to prevent this?

$\endgroup$
3
  • $\begingroup$ You can get much better control by setting up a DynamicModule that sets the values of ViewAngle, ViewVertical, etc. There is a whole world of even smoother control via tuning the exact way values are being fed to/read by the FE, which has been extensively documented on the site $\endgroup$ Commented 17 hours ago
  • $\begingroup$ @b3m2a1 It is like those answers generated by AI - lots of words without any concrete results/examples. Try xzczd's answer where he is using DynamicModule - it is slow as hell. $\endgroup$ Commented 12 hours ago
  • $\begingroup$ What are you talking about...? $\endgroup$ Commented 6 hours ago

4 Answers 4

5
$\begingroup$

As mentioned in the document of Dynamic:

Dynamic[expr] is equivalent to Dynamic[expr, (expr=#)&].

So the easiest fix should be introducing a variable to store the expression that cannot be Set:

Manipulate[
 v = RotationMatrix[fi, 
    RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}] . {1.3`, -2.4`, 2.`}; 
 Show[Graphics3D[Cube[]], ViewPoint -> Dynamic[v]], {fi, 0, 2 Pi}]

Put the var in a DynamicModule should be safer:

DynamicModule[{var}, 
 Manipulate[
  var = RotationMatrix[fi, 
     RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}] . {1.3`, -2.4`, 2.`}; 
  Show[Graphics3D[Cube[]], ViewPoint -> Dynamic[var]], {fi, 0, 2 Pi}]]
$\endgroup$
4
  • $\begingroup$ First version of your code works well but your second version of code is slow as hell it is same as if no Dynamic and DynamicModule were used. Try it with pl in the link in OP instead of simple graphic Graphics3D[Cube[]]. $\endgroup$ Commented 12 hours ago
  • $\begingroup$ pl = Plot3D[{Sin[x] + Cos[y]}, {x, 0, 2 Pi}, {y, 0, 2 Pi}, PlotPoints -> 300, SphericalRegion -> True] $\endgroup$ Commented 12 hours ago
  • $\begingroup$ @azerbajdzan Oh… Seems that the DynamicModule should be outside of Manipulate. See my edit. Thx for pointing out. $\endgroup$ Commented 10 hours ago
  • 1
    $\begingroup$ Instead of DynamicModule[], one could add {var, ControlType -> None} to the controls. The Manipulate[] variables are instantiated in a DynamicModule[] by default. $\endgroup$ Commented 4 hours ago
4
$\begingroup$

Adding Deploy in Deploy@Show... worked.

Manipulate[
 Deploy@Show[Graphics3D[Cube[]], 
   ViewPoint -> 
    Dynamic[RotationMatrix[fi, 
       RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}] . {1.3`, -2.4`, 
       2.`}]], {fi, 0, 2 Pi}]

But it has disadvantage that I can not change graphics size by mouse afterwards. So I am still waiting for a better answer.

$\endgroup$
3
$\begingroup$

Just for the fun of it, here's a version of this that allows you to also change the base ViewPoint dynamically

DynamicModule[{baseViewPoint = {1.3`, -2.4`, 2.`}, activeViewPoint, tfMat},
 Manipulate[
  tfMat = RotationMatrix[fi, RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}];
  Show[
   Graphics3D[Cube[]],
   ViewPoint -> Dynamic[
     tfMat . baseViewPoint,
     Function[baseViewPoint = Transpose[tfMat] . #]
     ]
   ],
  {fi, 0, 2 Pi}
  ]
 ]

and here's a version that allows you to customize the layout and drop the Manipulate

DynamicModule[{baseViewPoint = {1.3`, -2.4`, 2.`}, activeViewPoint, tfMat, fi},
 Panel@
  Column@{
    Panel[
     Show[
      Graphics3D[Cube[]],
      ViewPoint -> Dynamic[
        tfMat . baseViewPoint,
        Function[baseViewPoint = Transpose[tfMat] . #]
        ]
      ],
     Background -> White
     ],
    Slider[
     Dynamic[fi, 
      Function[
       fi = #;
       tfMat = RotationMatrix[fi, RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}]
       ],
      {fi, 0, 2 Pi}
      ]
     ]
    },
 Initialization :> {
   tfMat = IdentityMatrix[3],
   fi = 0
   }
 ]

You can get different, potentially better behaved rotations by adjusting parameters other than the ViewPoint like the ViewVertical, but those options are comprehensively discussed in other answers on this site

$\endgroup$
2
$\begingroup$

Another way...

The Front End will update some option settings of the form key -> Dynamic[value] when the mouse interacts with graphics, in a way similar to interacting with a slider. For instance, the various view options; maybe others. (The water hose example here shows how to make the rotation of the graphics respect gravity.) The update has effect value = <new_value>. If value cannot be Set[], you'll get a Set::write error.

A straightforward way to fix this is to supply an appropriate tracking function, Dynamic[value, func] (or use the 3-function version). If you don't want mouse dragging to change fi or to try to set a value for Dot[], you could use # & or Null & for the tracking function:

Manipulate[
 Show[Graphics3D[Cube[]],
  ViewPoint -> Dynamic[
    RotationMatrix[fi, 
      RotationMatrix[fi, {0, 1, 1}] . {0, 0, 1}] . {1.3`, -2.4`, 2.`},
    # &
    ]
  ], {fi, 0, 2 Pi}]
$\endgroup$

Your Answer

By clicking β€œPost Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.