6
$\begingroup$

How do I get the InputField to coordinate with the LocatorPane so that a change in each control changes the other to be in agreement? It would be nice if the function was self-contained and was dynamically linked to a second similar control where the variable is radians. The angle control is based on this (see Applications). Related links do not address or solve this particular issue; links such as this this, and this

 fDeg[Dynamic[angleDeg_]] :=   
   DynamicModule[{p, angleRad, angleCalc, dtr = Degree},  

    angleCalc[newp_,   
      oldp_] := (angleRad =   
       angleRad + ArcCos[newp.oldp] Sign[Cross[newp].(newp - oldp)];   
      If[0 < angleRad, angleRad = Mod[angleRad, +2*Pi]];  
      If[0 > angleRad, angleRad = Mod[angleRad, -2*Pi]];  
      angleDeg = angleRad/dtr;  
      f[angleDeg];  
      p = {Cos[angleRad], Sin[angleRad]});  

    angleRad = angleDeg*dtr;  
    p = {Cos[angleRad], Sin[angleRad]};  

    LocatorPane[Dynamic[p, (angleCalc @@ Normalize /@ {#, p}) &],   
     Dynamic@Show[  
       Graphics[{Circle[], Arrowheads[0.15],   
         Arrow[Dynamic[{{0, 0}, p}]]}, ImageSize -> Tiny],  
       Graphics[{Dynamic[{Text[  
            NumberForm[angleDeg, {3, 2}], {0, 0}]}]}]],   
     Appearance -> None]];  

 aDeg = 45;  

 Column[{  
   "Degrees:",  
   fDeg[Dynamic[aDeg]],  
   "aDeg: ",   
   InputField[Dynamic[aDeg],   
    FieldSize -> 6]  
   }, Alignment -> Center]  
$\endgroup$
5
$\begingroup$

Consider the following refactoring of your code

First, the locator pane is used to set a point location constrained on a circle with unit radius (this part borrowed heavily from an example in the documentation for LocatorPane). A degree value is then calculated from the coordinates of tha tpoint.

Secondly, the input field is used to read in a degree value, which is then used to update the position of the dynamic point pt using the second argument of Dynamic.

DynamicModule[
  {pt = {0, 1.}},
  Column[{
    "Degrees:", Dynamic[(ArcTan @@ pt)/Degree],
    LocatorPane[
      Dynamic[pt],
      Graphics[{
        Circle[],
        PointSize[Large],
        Dynamic[Arrow[{{0, 0}, pt/Norm[pt]}]]
      }],
      Appearance -> None
    ],
    InputField[
      Dynamic[(ArcTan @@ pt)/Degree, (pt = N@{Cos[#1 Degree], Sin[#1 Degree]}) &],
      FieldSize -> Tiny
    ]
    }, Alignment -> Center
  ]
]

This keeps both fields in sync with each other:

animation shows the locator and input field working together

$\endgroup$
  • $\begingroup$ MarcoB. This is nice. But I was hoping for a self-contained function where only aDeg is passed. One reason for this is to allow aDeg to be altered elsewhere by some process such as a simulation of an automated flight control system. The controls (LocatorPane and InputField) would change accordingly. But the simulation could be interrupted by the user by means of the controls, and a new value input by the field or the dial. Any thoughts? $\endgroup$ – kmutiny Mar 11 at 2:25
3
$\begingroup$

An alternative way to use Experimental`AngularSlider is to use a single dynamic variable and limit the angles to the range 0 to 360 using {0,360} as the second argument of AngularSlider:

DynamicModule[{z = 120}, 
 Column[{Experimental`AngularSlider[Dynamic[z], {0, 360}, 
   Experimental`BoundaryAction -> "Clip"], 
   InputField[Dynamic[z], ImageSize -> {100, 24}, BaseStyle -> 16]}, 
  Alignment -> Center]]

enter image description here

To display angles in radians and degrees and allow the slider to move around the clock:

DynamicModule[{z = 120}, 
 Panel @ Column[{Style["Degree", 16], 
    Overlay[{Experimental`AngularSlider[Dynamic[z,(z = Round[#, 1]) &], {0, 360}, 
       Experimental`BoundaryAction -> "Wrap", ImageSize -> 200], 
      Graphics[{Text[Framed[Style[Dynamic[Round[z,1]] °, 16], FrameStyle -> None], 
         Scaled @ {3/4, 4/10}, {-1, 1}], 
       Text[Framed[Style[Dynamic[Round[z Degree, Pi/2^7] ], 16], FrameStyle -> None],
        Scaled @ {3/4, 4/10}, {-1, -1}]}]}, All, 1], 
    InputField[Dynamic[z, (z = Round[#, 1]) &], ImageSize -> {100, 24}, BaseStyle -> 16]},
   Alignment -> Center]]

enter image description here

If you want to play with various options of Experimental`AngularSlider you can use

NotebookTools`AngularSliderTest[]

enter image description here

$\endgroup$
2
$\begingroup$

Here is a simplified demo linking an InputField[] with Experimental`AngularSlider[]:

DynamicModule[{x = 0., u = 0.}, 
              Column[{Experimental`AngularSlider[Dynamic[x, (x = #; u = x/Degree) &]], 
                      InputField[Dynamic[u, (u = #; x = u Degree) &], Number]}]]

linking AngularSlider and InputField

Clicking on the AngularSlider[] updates the value in the InputField[], and entering a (degree) value in the InputField[] moves the slider to the specified angle.

$\endgroup$
0
$\begingroup$

I think the following code solves the issue, though I’m not sure exactly why it works but the other didn't. Note that the function is self-contained, and that the InputField should be placeable in a separate part of an application. Also note the added features. The next step would be to make a function for radians and link the 2 controls.

 DynamicModule[{gSquare, dtr, rtd, AngularControlDegFnc01,   
   AngularControlRadFnc01, aDeg, aRad, ShowDeg},  

  AngularControlDegFnc01[Dynamic[aDegArg_]] := DynamicModule[  
    {  
     aRadH,  
     dtrH = Pi/180., rtdH = 180./Pi,  
     Pi2H = 2*Pi, icrH = .25, thH = 0.01, athH = 0.017,  
     c1H = RGBColor[.8, .5, .5], c2H = RGBColor[.5, .5, .8],  
     pH, pCalcH, aCalcH, cCalcH, mCalcH, wCalcH, rCalcH  
     },  

    rCalcH[] := aRadH = aDegArg*dtrH;  
    wCalcH[] := {icrH*pCalcH[], pCalcH[]};  
    pCalcH[] := pH = {Cos[aRadH], Sin[aRadH]};  
    cCalcH[] := If[Sign[aRadH] == -1, Return[c1H], Return[c2H]];  
    mCalcH[] := Block[{},  
      If[0 < aRadH, aRadH = Mod[aRadH, +Pi2H]];  
      If[0 > aRadH, aRadH = Mod[aRadH, -Pi2H]];];  
    aCalcH[newpArg_, oldpArg_] := Block[{},  
      aRadH =   
       aRadH + ArcCos[newpArg.oldpArg]*  
         Sign[Cross[newpArg].(newpArg - oldpArg)];  
      aDegArg = aRadH*rtdH;  
      mCalcH[];  
      pCalcH[]];  

    rCalcH[];  
    pCalcH[];  

    LocatorPane[Dynamic[pH, (aCalcH @@ Normalize /@ {#, pH}) &],  
     Dynamic[ShowDeg = Show[{  
         Graphics[{cCalcH[], Disk[{0, 0}, 1, {0, rCalcH[]}]}],  
         Graphics[{Black, Thickness[thH], Line[{{0, 0}, {1, 0}}]}],  
         Graphics[{GrayLevel[.8], Disk[{0, 0}, icrH]}],  
         Graphics[{Thickness[thH], Circle[{0, 0}, icrH]}],  
         Graphics[{Black, Thickness[1.5*thH], Circle[]}],  
         Graphics[{Black, Thickness[athH], Arrowheads[5*athH],   
           Arrow[wCalcH[]]}],  
         Graphics[{Dynamic[{Text[  
              NumberForm[Round[aDegArg, 0.01], {3, 1}], {0, 0}]}]}]},   
        ImageSize -> 150]  

      ], Appearance -> None]  
    ];  

  gSquare =   
   Graphics[{Gray, Thick,   
     Line[1.4*{{-1, -1}, {-1, +1}, {+1, +1}, {+1, -1}, {-1, -1}}]}];  
  dtr = Pi/180.;  
  rtd = 180./Pi;  
  aDeg = 45;  
  aRad = aDeg*dtr;  

  Manipulate[  
   Dynamic@Show[{ShowDeg, gSquare}, ImageSize -> 150],  
   Row[{  
     Column[{  
       AngularControlDegFnc01[Dynamic[aDeg]],  
       Row[{"aDeg: ", InputField[Dynamic[aDeg], FieldSize -> 6]}]  
       }]  
     }],  
   ControlPlacement -> Left  
   ]  
  ]  
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.