Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular/Angular slider

A recent SO question reminded me of some code I tried to write a while back. The aim is to make a CircularSlider[] object that can be used for angle-like variables in dynamic objects.

The framework for my solution (below) comes from the ValueThumbSlider[] defined in the Advanced Manipulate Functionality tutorial. The main difference is that in ValueThumbSlider[] the value of the slider and the position of the LocatorPlane[] are the same thing, whilst in my CircularSlider[] they are not - and this leads to problems.

The first problem is that moving the Locator will not change the slider value. This is fixed by using the 2nd argument in the Dynamic: (x = #/Abs[Complex @@ #]) &.

This in turn leads to the problem that if you externally set the value of the slider (t) from outside, it will immediately revert to its previous value. This is fixed by keeping the old value (t0) and comparing to t. If they don't match then it's assumed that t has changed and so the Locator position x is updated to its new position.

CircularSlider[t_] := CircularSlider[t, {0, 1}];
CircularSlider[Dynamic[t_], {min_, max_}] /; max > min := 
 With[{d = (max - min)/(2. Pi)},
  DynamicModule[{td = t/d, x, t0}, x = {Cos[td], Sin[td]};
   LocatorPane[
    Dynamic[If[!NumberQ[t], t = min; x = {Cos[td], Sin[td]}];
     If[t != t0, t0 = t; x = {Cos[td], Sin[td]}];
     t = Mod[Arg[Complex @@ x] d, max, min]; t0 = t;
     x, (x = #/Abs[Complex @@ #]) &],
    Graphics[{AbsoluteThickness[1.5], Circle[], 
      Dynamic[{Text[NumberForm[t, {3, 2}], {0, 0}]}]}],
    ImageSize -> Small]]]

alt text


So my question is: can someone make this work with out the above kludges?

like image 988
Simon Avatar asked Dec 12 '10 09:12

Simon


1 Answers

As for problem#1, I wouldn't consider the use of the second argument to Dynamic as a kludge -- that is what the second argument is for. Therefore, I don't have an alternative solution for that one.

Problem #2 can be avoided if you refrain from assigning t in the first argument to Dynamic.

With this in mind, here is another implementation:

CircularSlider2[Dynamic[t_], r:{min_, max_}:{0, 1}] :=
  DynamicModule[{scale, toXY, fromXY},
      scale = (max - min) / (2. Pi);
      toXY[a_?NumberQ] := Through@{Cos, Sin}[a / scale];
      toXY[a_] := {1, 0};
      fromXY[{x_, y_}] := Mod[Arg[x + I y] scale, max, min];
      LocatorPane[
        Dynamic[toXY[t], (t = fromXY[#])&],
        Graphics[{
            AbsoluteThickness[1.5], Circle[],
            Dynamic[{Text[NumberForm[t, {3,2}], {0, 0}]}]
          }],
        ImageSize -> Small
      ]
  ]

The only material difference between this version and the original version is that the first argument to Dynamic is an expresssion that is free of side-effects.


Edit

I just stumbled across this undocumented experimental feature in Mathematica 8:

DynamicModule[{x = RandomReal[{0, 50}]},
  {Experimental`AngularSlider[Dynamic@x], Dynamic@x}
]

angular slider

like image 167
WReach Avatar answered Oct 13 '22 02:10

WReach