Circumnavigating a curve or going through it to show different behavior
One way to detect crossings is to form a straight line between the previous position of the locator and the new position, and then check if there is an intersection between that straight line and $x^3$. I wrote this function to count the number of line intersection of a straight line with endpoints p1
and p2
. The function which in this case is $x^3$ can be any function, and the interval which in this case is $0<x<1$ can be any interval.
SetAttributes[countIntersections, HoldFirst]
countIntersections[{f_, {xmin_, xmax_}}, p1_, p2_] := Module[{delta = p2 - p1, sol},
If[p1 == p2, Return[0]];
sol = Solve[{
{x, f} == p1 + Normalize[delta] k,
# < x < #2 & @@ Sort[{First[p1], First[p1 + delta]}],
xmin < x < xmax,
0 < k < Norm[delta]
}, {x, k}];
Length@sol
]
Just to emphasize how this work I built a little demo.
DynamicModule[{p1 = {0.5, 0.5}, p2 = {0.6, 0.5}},
LocatorPane[
Dynamic[{p1, p2}],
Dynamic@Show[
Plot[x^3, {x, 0, 1}],
Graphics[{
If[
countIntersections[{x^3, {0, 1}}, p1, p2] == 0,
Black,
Red
],
Line[{p1, p2}]
}]
]
]
]
But of course for the real thing we don't have two locators. The second position is simply the previous position of the locator. Here's how that can be written:
DynamicModule[{p1 = {0.5, 0.5}, p2, plot, diskColor = Black},
p2 = p1;
LocatorPane[
Dynamic[p1],
Dynamic[
If[
countIntersections[{x^3, {0, 1}}, p1, p2] != 0,
diskColor = diskColor /. {Red -> Black, Black -> Red}
]
plot = Show[
Plot[x^3, {x, 0, 1}],
Graphics[{
diskColor,
Disk[{0.2, 1}, 0.08]
}], AspectRatio -> 0.75, PlotRange -> {{0, 2}, {0, 1.5}}
];
p2 = p1;
plot
]
]
]
I don't know how to handle parallel Events
but if there is single Locator
you can try this:
DynamicModule[{col = Blue, acc = 0, p = {1, 1}},
EventHandler[
Show[
Graphics[{Dynamic@Disk[p, [email protected]]}],
Plot[x^3, {x, 0, 1}] /. l_Line :> EventHandler[ l, {"MouseEntered" :>
If[acc === 1, (col = col /. {Red -> Blue, Blue -> Red})]}]
, Frame -> True, PlotRange -> {{0, 1.5}, {0, 1.5}},
Epilog -> Inset[Graphics[Dynamic@{col, Disk[]}, ImageSize -> 30], {0.2, 1}]
],
{"MouseDown" :> (acc = 1; p = MousePosition["Graphics"]),
"MouseDragged" :> (p = MousePosition["Graphics"]),
"MouseUp" :> (acc = 0;)}, PassEventsDown -> True]
]
Do not move cursor too quickly :P
The order of things in Show
is important. Our custom locator has to be under the border line.
Partial answer: this does not handle the going-around-the-curve bit.
g1 = Graphics[{Blue, Table[Circle[{0, 0}, i], {i, 3}]}, ImageSize -> 20];
g2 = Graphics[{Red, Table[Circle[{0, 0}, i], {i, 3}]}, ImageSize -> 20];
DynamicModule[{pt = {0.1, 1}},
Plot[x^3, {x, 0, 1}, PlotRange -> {{0, 1.5}, {0, 1.5}},
Filling -> Bottom, Frame -> True, ImageSize -> 600,
Epilog -> Dynamic@{
If[Last[pt] < First[pt]^3, Blue, Red], PointSize[.05], Point[{.1, 1}],
Locator[Dynamic[pt], If[Last[pt] < First[pt]^3, g1, g2]]}]]