2
$\begingroup$

I'm trying to implement a complicated Manipulate[] interface. I'm not really interested in working code, but for those interested, I would like the program to

  • allow you to drag around a variable number of locators,
  • and have it output the motion of an object traveling from one locator to the next in straight line segments at constant velocity (just the function of time; no actual animation needed), and graph of the motion (i.e. connect the locators on the screen via ParametricPlot[]).
  • One last thing: the times at which the object passes each of the locators are needed to specify a unique solution. But rather than manipulating the times themselves, I'd like to have input fields for the average velocity in each segment, and have the program infer the times.

Here is a schematic that describes how I've tried to accomplish this:

enter image description here

However, I have been stumped as to how to implement this. Manipulate[] doesn't seem to have enough flexibility, and Dynamic[] seems to come with its own issues. All I'd like to know is if this is a dead end, or if not, some rough outline of how I could complete this implementation. Here is how far I've gotten, with the help of a few answered stack exchange questions:

GLOBAL PARAMETERS:

Row[{SetterBar[Dynamic@\[CapitalNu], Range[1, 10, 1]],"     Sets Length of X,Y,V"}]

INTERFACE VARIABLES -> INTERNAL VARIABLES:

Internalize[{V_, {X_, Y_}}, N_] := Module[{T},
  T = Table[0, {i, 1, N + 2}];
  For[i = 2, i <= N + 2, i++,
   T[[i]] = 
     T[[i - 1]] + Norm[{X[[i - 1]], Y[[i - 1]]} - {X[[i]], Y[[i]]}]/
      V[[i]];];
  T
  ]
X := Table[
   ToExpression["x" <> ToString@i], {i, 0, \[CapitalNu] + 1}];
Y := Table[
   ToExpression["y" <> ToString@i], {i, 0, \[CapitalNu] + 1}];
V := Table[
   ToExpression["v" <> ToString@i], {i, 1, \[CapitalNu] + 1}];
T := Internalize[{V, {X, Y}}, \[CapitalNu]];

MANIPULATE INTERFACE

Procedure[T_,{X_,Y_}]:= Piecewise@
 position=Table[{{X[[i]]-(t-T[[i]])/(T[[i+1]]-T[[i]]))(X[[i]]-X[[i-1]]),Y[[i]]-(t-T[[i]])/(T[[i+1]]-T[[i]]))(Y[[i]]-Y[[i-1]])},  
   T[[i]] <= t <= T[[i + 1]]}, {i, 1, \[CapitalNu]}]

(*The rest would look like this: 
Manipulate[ParametricPlot[Procedure[Dynamic@T,{Dynamic@X,Dynamic@Y}][t],  {t,T[[1]],T[[-1]]}],
Table[{X[[i]],Y[[i]]},Locators],Table[Silders[V[[i]]]]],] *)

Does anyone know if Mathematica is capable of something like this? (I must emphasize, the Manipulate interface has to adjust automatically to changes in N; no retyping code permitted).

The key issue I haven't been able to figure out is how to apply Manipulate[] controls, including locators, to the elements of variable length lists.

While this question may seem unnecessarily long, context really helps.

$\endgroup$
  • $\begingroup$ I appreciate your effort in making the diagram, but I'd also appreciate it if you could tell us what you're trying to achieve (it seems like you're trying to change a plot dynamically) as opposed to just how you'd achieve it. You could start by describing the desired outcome of your code e.g. the plot would behave this way if the manipulate is changed. Also, does your Locator refer to this. There's only one mention of locator in your code but it was Locators, which I think is a typo. If so, what do you want these locators to do? $\endgroup$ – seismatica Aug 25 '14 at 1:18
  • $\begingroup$ fixed the issue. Thanks for your input! $\endgroup$ – David Roberts Aug 25 '14 at 1:28
  • $\begingroup$ Really appreciate it. time-wise parametrized piece-wise sounds very intimidating to me. Perhaps you might want to explain a little broader what you're trying to do. Are you tracking an object? If so, what information are you given about this object (position, speed, etc.)? Just dumb it down a little i.e. use less jargon, so that the readers can understand what you're trying to do. $\endgroup$ – seismatica Aug 25 '14 at 1:31
  • $\begingroup$ It just means connect the locators with line segments and assume the object goes at constant velocity v_i at the ith segment. I've written the code in the function Procedure[]. $\endgroup$ – David Roberts Aug 25 '14 at 1:33
  • 1
    $\begingroup$ You may steal some ideas from here mathematica.stackexchange.com/a/14149/193 $\endgroup$ – Dr. belisarius Aug 25 '14 at 2:00
2
$\begingroup$

Here's my attempt at achieving what you describes.

1) I define a display function that takes n as the number of randomly generated locators (initLoc). It also takes a list of speeds v between those locators. The rest of the function is figuring out at what time a particle will reach a particular locator (locatorTimes) given its average speed and the locator position; I think this is what you meant by "inferring the times" in your question.

Then, the points primitives to draw the red line are generated (linePrimitive) by selecting only the points that the particle had passed, along with its current position (the current position is a little tricky to determine since we're only given the time of the particle, not its position). The final result is a Manipulate of a position's path as a function of time.

Clear[display]
display[n_Integer, v_List] /; Length[v] == n - 1 := 
 DynamicModule[{initLoc, locatorTimes, linePrimitive},

  initLoc = RandomReal[{-10, 10}, {n, 2}];

  locatorTimes[pt : {{_, _} ..}, velocity_?VectorQ] := 
   Module[{ptDiff, tInterval, ptPassed, timeAtLocator},
    ptDiff = Norm[#2 - #1] & @@@ Partition[pt, 2, 1];
    tInterval = ptDiff/velocity;
    Prepend[Accumulate[tInterval], 0.]
    ];

  linePrimitive[pt : {{_, _} ..}, velocity_?VectorQ, t_] /; 
    t <= Last@locatorTimes[pt, velocity] := 
   Module[{times, lastPoint, vx, vy},
    times = locatorTimes[pt, velocity];
    lastPoint = Length@Select[times, # <= t &];
    {vx, vy} = (pt[[lastPoint + 1]] - 
        pt[[lastPoint]])/(times[[lastPoint + 1]] - times[[lastPoint]]);
    Append[pt[[1 ;; lastPoint]], 
      pt[[lastPoint]] + {vx, vy} (t - times[[lastPoint]])]~Prepend~
     velocity[[lastPoint]]
    ];

  Manipulate[
   Graphics[
    {Red, PointSize@0.02, Point[pt[[1]]], Thick, 
     Line@Rest@linePrimitive[pt, v, t]},
    PlotRange -> {{-10, 10}, {-10, 10}},
    PlotLabel -> 
     TableForm[
      Append[Flatten /@ Flatten[{pt, v}, {{2}, {1}}], 
       Flatten@linePrimitive[pt, v, t][[{-1, 1}]]],
      TableHeadings -> {("Locator " <> ToString@# & /@ 
           Range@Length@pt)~Append~"Current Position", {"x", "y", 
         "v"}}]
    ],
   {{pt, initLoc}, Locator}, {t, 0., 
    Floor[Last@locatorTimes[pt, v], 0.0001]}
   ]
  ]

display[6, {1, 2, 3, 2, 1}]

Mathematica graphics


2) I then nest this display function within larger Manipulate's. The outermost Manipulate determines the number of locators needed. It then pass that number down to the next inner Manipulate for it to generate n - 1 velocity input fields.

The values that the user inputs in these input fields will be passed down, along with the number of locators, to display for it to generate a position vs time interactive slider that you saw above. The user can also change the velocities at once by changing constv in the outermost Manipulate.

Manipulate[
 DynamicModule[{v},
  v = Symbol["v" <> StringJoin[ToString /@ {#1, #2}]] & @@@ 
    Partition[Range@n, 2, 1];
  Manipulate[Evaluate@display[n, v], 
   Evaluate[Sequence @@ ({#, constv} & /@ v)]]
  ]
 , {n, Range[2, 5], SetterBar}, {constv, 1}]

Mathematica graphics


If you have any questions please feel free to ask. School starts tomorrow for me so I had to code this in a hurry so I can go to bed soon. I will fix this code tomorrow if there's any issue. One of the issues is the slow dragging of my locators. Hence, if anyone has suggestions for code refactoring, I'd really appreciate it.

$\endgroup$
  • $\begingroup$ This is beautiful. I'm currently parsing your code to try to understand it. You've simplified a lot of my functions. One question: what does the "/;" symbol do when defining functions? $\endgroup$ – David Roberts Aug 25 '14 at 15:07
  • $\begingroup$ Again, really nice, and a proof of principle. $\endgroup$ – David Roberts Aug 25 '14 at 18:03
  • $\begingroup$ You've really saved my butt - I've been doing this stuff for a school project, and I was unable to learn the nuances of Dynamic[] in time. Can I credit you? How should I credit you? $\endgroup$ – David Roberts Aug 25 '14 at 22:29
  • 1
    $\begingroup$ Your accepting my answer is more than enough :) The /;--aka Condition--is needed to ensure that the function only takes appropriate arguments, otherwise it is not evaluated (this is a good thing, because passing bad arguments into a function will return incorrect results). For example, /; Length[v] == n - 1 for your display function means that if the function takes n points (let's say 5), and it must also take only n - 1 (which means 4) velocities. $\endgroup$ – seismatica Aug 25 '14 at 23:49

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.