Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Why doesn't Locator behave correctly in the following code?

BezierPoint[t_, cps_] := Block[{tt},
   tt = {(1 - t)^3, 3 t (1 - t)^2, 3 t^2 (1 - t), t^3};
   Sum[cps[[i]]*tt[[i]], {i, 1, 4}]
   ];

DiskBezierRadius[t_, ri_] := Block[{tt},
   tt = {(1 - t)^3, 3 t (1 - t)^2, 3 t^2 (1 - t), t^3};
   Sum[ri[[i]] tt[[i]], {i, 1, 4}]
   ];

ControlPoints = {{100, 100}, {100, 300}, {300, 200}, {300, 
    100}};
ControlRadii = {50, 50, 20, 20};
Dynamic[Show[
  ParametricPlot[BezierPoint[t, ControlPoints], {t, 0, 1}],
  Graphics[
   Table[p = BezierPoint[t, ControlPoints]; {Text[t, p], 
     Circle[p, 5]}, {t, 0, 1, 0.1}]],
  Graphics[
   {
    Line[ControlPoints[[1 ;; 2]]],
    Line[ControlPoints[[3 ;; 4]]],
    Blue,
    Locator[Dynamic[ControlPoints[[1]]]],
    Locator[Dynamic[ControlPoints[[2]]]],
    Locator[ControlPoints[[3]]],
    Locator[ControlPoints[[4]]]
    }
   ],
  Axes -> None, AspectRatio -> Automatic,
  PlotRange -> {{0, 400}, {0, 400}}
  ]]
Dynamic[ControlPoints[[1]]]

enter image description here

If I wrap into Dynamic two locators (as in code above) then I have both locators dragged by mouse. I mean if I drag one locator, then both locator move. I can't drag only one locator.

If I wrap only one (second) locator, then it can be dragged alone.

share|improve this question
add comment

3 Answers

If you can use a Manipulate, it would avoid some of the Dynamic complexity:

Manipulate[
 Show[
  ParametricPlot[BezierPoint[t, pts], {t, 0, 1}, 
   PlotRange -> {{0, 400}, {0, 400}}],
  Graphics[
   {
    Red, Thick,
    BezierCurve[pts],
    Gray,
    Line[{pts[[1]], pts[[2]]}],
    Line[{pts[[-1]], pts[[-2]]}],
    Table[
     {
      Gray, Disk[BezierPoint[t, pts], 10],
      White, Text[t, BezierPoint[t, pts]]
      }, {t, 0, 1, 0.1}]
    }],
  Axes -> None, AspectRatio -> Automatic
  ],
 {pts, Locator},
 Initialization :> {pts = ControlPoints}]

animation

There's a problem with the locators obscuring the text at the start and end. I don't know how to fix that...

share|improve this answer
    
I believe setting the locator appearance to none will suppress it but still allow interactivity that will allow the desired functionality with the desired presentation,e.g. I used it in my answer –  ubpdqn Oct 27 '13 at 10:46
add comment

I apologise for not directly answering your question but provide an alternative. LocatorPane is useful when dealing with multiple locators. Does produce the desired behaviour (assuming your functions are iniitialized and I have omitted display of control point 1):

DynamicModule[{
  ControlPoints = {{100, 100}, {100, 300}, {300, 200}, {300, 100}},
  ControlRadii = {{50, 50, 20, 20}}},
 LocatorPane[Dynamic[ControlPoints],
  Dynamic@
   Show[ParametricPlot[BezierPoint[t, ControlPoints], {t, 0, 1}], 
    Graphics[
     Table[p = BezierPoint[t, ControlPoints]; {Text[t, p], 
       Circle[p, 10]}, {t, 0, 1, 0.1}]], 
    Graphics[{Line[ControlPoints[[1 ;; 2]]], 
      Line[ControlPoints[[3 ;; 4]]], Point[Dynamic@ControlPoints]}], 
    Axes -> None, AspectRatio -> Automatic, 
    PlotRange -> {{0, 400}, {0, 400}}], Appearance->None
  ]
 ]
share|improve this answer
add comment

Introduction

It appears to me that this might be a bug. I certainly cannot think of any other explanation, but I would be glad if there is one.

The issue is with ParametricPlot, but I cannot explain why there should be a problem. Each Locator is basically an EventHandler that, when activated, tracks changes in position of the mouse and updates the coordinates of the Locator accordingly. What seems to happen is that a mousedown in one Locator activates all Locators when the graphics includes a ParametricPlot that depends on the Locator points. This somehow causes all dynamic locators to be updated whenever one dynamic locator is dragged.

It does not appear to be a localization issue or a kernel vs. front end variable issue -- that is, putting variables in Module or DynamicModule did not help.

As shown in other answers, the issue does not occur with LocatorPane, which creates a single event handler for the locators.


There is another issue in the OP's code. Since p is not localized and is set (several times) inside a Dynamic, there is continual updating.


One fix

Here is a fix of the OP's code that preserves the behavior of Locators, in case that is preferred over the behavior of LocatorPane.

Dynamic[With[{param = BezierPoint[t, ControlPoints]},
  Show[
   (* replace ParametricPlot *)
   Graphics[Line[Table[param, {t, 0, 1, 1/100}]]],
   (* localize p *)
   Graphics[Table[With[{p = param}, {Text[t, p], Circle[p, 5]}], {t, 0, 1, 0.1}]],
   Graphics[{
     Line[ControlPoints[[1 ;; 2]]], Line[ControlPoints[[3 ;; 4]]],
     Blue,
     Locator[Dynamic[ControlPoints[[1]]]],
     Locator[Dynamic[ControlPoints[[2]]]],
     Locator[(*Dynamic@*)ControlPoints[[3]]],
     Locator[(*Dynamic@*)ControlPoints[[4]]]}],
   Axes -> None, AspectRatio -> Automatic, 
   PlotRange -> {{0, 400}, {0, 400}}]
  ]]

Another example and some evidence

Here is further evidence that the issue lies with ParametricPlot. This example from the Locator reference page works fine:

DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}}, 
 Dynamic @ Graphics[{Circle[], Red, 
    GeometricTransformation[Circle[], Transpose[{v1, v2}]], Green, 
    Line[{{0, 0}, v1}], Line[{{0, 0}, v2}], Locator[Dynamic[v1]], 
    Locator[Dynamic[v2]]}, PlotRange -> 3]]

But if we replace the circles with a ParametricPlot, we get an example similar to the OP's, and the locators are linked as in the OP's.

DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
 Dynamic @ Show[
   ParametricPlot[{{Cos[t], Sin[t]}, v1 Cos[t] + v2 Sin[t]}, {t, 0, 2 Pi}],
   Graphics[{(*Circle[],Red,GeometricTransformation[Circle[],
     Transpose[{v1,v2}]],*)
     Green, Line[{{0, 0}, v1}], Line[{{0, 0}, v2}],
     Locator[Dynamic[v1]], Locator[Dynamic[v2]]}],
   Axes -> False, PlotRange -> 3
   ]]

The locators are still linked if we move the symbols outside ParametricPlot and insert an evaluated parametrization:

DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
 Dynamic @ With[{param = v1 Cos[t] + v2 Sin[t]},
   Show[
    ParametricPlot[{{Cos[t], Sin[t]}, param}, {t, 0, 2 Pi}],
    Graphics[{
      Green, Line[{{0, 0}, v1}], Line[{{0, 0}, v2}],
      Locator[Dynamic[v1]], Locator[Dynamic[v2]]}],
    Axes -> False, PlotRange -> 3
    ]]]

Even if extract the Lines from the ParametricPlot, the locators are still linked.

DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
 Dynamic @ With[{plot =
    ParametricPlot[{{Cos[t], Sin[t]}, v1 Cos[t] + v2 Sin[t]}, {t, 0, 2 Pi}]},
   Graphics[{
     Cases[plot, _Line, Infinity],
     Green, Line[{{0, 0}, v1}], Line[{{0, 0}, v2}],
     Locator[Dynamic[v1]], Locator[Dynamic[v2]]},
    PlotRange -> 3
    ]]]

It happens with Plot, too.


However, the locators work independently if I define the function,

SetAttributes[myParamPlot, HoldAll];
myParamPlot[param_, dom_] := Graphics[Line[Table[param, dom]]]

and replace ParametricPlot[..] with myParamPlot[param, {t, 0, 1, 1/100}] in the OP's example or with two calls to myParamPlot, one for the circle and one for the transformed circle, in the modified doc. ctr. example.


The OP's approach seems reasonable to me, if Locator is preferred to LocatorPane. If LocatorPane is acceptable, then the Manipulate/DynamicModule approaches of other answers do not have the unexpected pitfall that the OP encountered.

share|improve this answer
    
Useful answer. I can see that years of study gradually lead to enlightenment about dynamic.... I thought there was something about the p that caused the flickering but I just removed it instead of trying to work out what was going wrong. –  cormullion Oct 27 '13 at 19:37
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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