# How can I speed up the evaluation of a Dynamic Locator acting on a Region?

I write this code

region = ParametricRegion[{Sin[u],
Sin[2*u]}, {{u, 0, 2*Pi}}]; DynamicModule[{p = {0, 0}},
Show[ParametricPlot[{Sin[u], Sin[2*u]}, {u, 0, 2*Pi},
PlotLabel -> Dynamic[p]],
Graphics[Locator[
Dynamic[p,
If[RegionDistance[region, #1] < 0.2,
p = RegionNearest[region, #1]] &]]]]]


But the efficiency is very poor.

• Could you not use TrackingFunction to achieve better performance? – e.doroskevic Jan 19 '16 at 9:25

## With RegionNearest

RegionNearest is a function that basically processes the region and returns a function of type RegionNearestFunction which is optimized for finding the nearest point in the region quickly. You should use the returned function to find the closest point in the region. As it is now you are recomputing this function again and again, which creates a lot of overhead. I might also suggest LocatorPane which has a background argument. This might allow for some further optimizations in which Mathematica does not have to redraw the background as much as it would have with the naive approach, although I don't know if this is the case. It also makes the syntax a bit simpler.

region = ParametricRegion[{Sin[u], Sin[2*u]}, {{u, 0, 2*Pi}}];
background = ParametricPlot[{Sin[u], Sin[2*u]}, {u, 0, 2*Pi}];
nf = RegionNearest[region];

DynamicModule[{pt = {0, 0}},
LocatorPane[Dynamic[pt, (pt = nf[#]) &], background]
]


You can make background a function of pt if you wish to update the plot label. Another option would be to use Column[{Dynamic[pt], LocatorPane[...]}].

## With Nearest

If you need something that is very, very fast and which you have more control over, you can try Nearest instead.

region = Table[{Sin[u], Sin[2 u]}, {u, 0, 2 Pi, 0.01}];
background = ParametricPlot[{Sin[u], Sin[2 u]}, {u, 0, 2 Pi}];
nf = Nearest[region];

DynamicModule[{pt = {0, 0}},
LocatorPane[Dynamic[pt, (pt = First@nf[#]) &], background]
]


The upside and the downside is that you have to decide how to sample the curve yourself.

• That's great, much much faster. Like you say, you can make background a function, or just use Show[background , PlotLabel -> Dynamic[pt]] in place of background. – Jason B. Jan 19 '16 at 11:36

This seems to be a bit faster. First off, there's no reason to redraw the ParametricPlot every time you change p. That sped it up a bit. Then I figured, why make the If statement? Let's just always set p equal to the nearest region point. Getting rid of the If statement sped it up some more.

region = ParametricRegion[{Sin[u], Sin[2*u]}, {{u, 0, 2*Pi}}];
plot = ParametricPlot[{Sin[u], Sin[2*u]}, {u, 0,
2*Pi}];
DynamicModule[{p = {0, 0}},
Show[plot,
Graphics[
Locator[
Dynamic[
p,
(p = RegionNearest[region, #1]; &)
]
]
]
, PlotLabel -> Dynamic[p]]]

• It's seem to be slightly slow too. – yode Jan 19 '16 at 14:11
• It's faster than your original version, but there's no question that Pickett's solution is the best. – Jason B. Jan 19 '16 at 14:13