On Making a LocatorSphere
:
Okay so I'm trying to realize a Locator3D-esque
functionality for Mathematica. Something like a LocatorSphere
, possibly done in a way that the LocatorVector
can be locked to certain regions/quadrants to ease confusion for the user and prevent egregious errors from occurring.
This will ultimately not be used on a sphere as seen here, so some aspect of customization should be possible (as you see how I have begun to add my own axes) and it needs to output coordinates that can readily be accessed in order to operate other functions, to be used as a locator. For simplicity's sake, it should stay normalized in length. I have something that I think I have taken as far as my skill level can take it. Also, apologies on not having a gif, feel free to add this or a better picture in an edit.
By modifying this answer:
Forcing a locator button to remain on the surface of a sphere
I have been able to do the following, which I think is quite a bit towards this goal, but can be taken further and/or optimized and simplified.
DynamicModule[{pt}, Manipulate[
EventHandler[
Style[
Graphics3D[{
{Opacity[0.5],
First@
ParametricPlot3D[{Cos[u] Sin[v], Sin[u] Sin[v], Cos[v]}, {v,
0, Pi}, {u, 0, 2 Pi},
MaxRecursion -> ControlActive[1, Automatic],
PlotPoints -> ControlActive[Automatic, 50]]},
{Thick, Arrowheads[Large, Appearance -> "Projected"],
Arrow[{{0., 0., 0.}, Dynamic@pp[[1]]}]},
{Thick, Arrowheads[Large, Appearance -> "Projected"],
Arrow[{{0., 0., 0.}, {1.5, 0., 0.}}]},
{Thick, Arrowheads[Large, Appearance -> "Projected"],
Arrow[{{0., 0., 0.}, {0., 1.5, 0.}}]},
{Thick, Arrowheads[Large, Appearance -> "Projected"],
Arrow[{{0., 0., 0.}, {0., 0., 1.5}}]}},
Boxed -> False, PlotRange -> 1.6,
Epilog ->
Inset[Style[
"\[Phi]=" <> ToString[#[[2]]] <> ", \[Theta]=" <>
ToString[#[[3]]] &@ToSphericalCoordinates[pp[[1]]],
FontColor ->
Dynamic@If[CurrentValue["ShiftKey"], Black, Gray],
18], {Left, Top}, {Left, Top}], ImageSize -> {Automatic, 400},
RotationAction -> "Clip"],
Deployed -> Dynamic@CurrentValue["ShiftKey"]],
"MouseMoved" :>
If[CurrentValue[
"ShiftKey"], (pp[[First@
Ordering[Function[pt, (pt - #).(pt - #)] /@ pp,
1]]] = #) &@
Normalize@
First@MousePosition[
"Graphics3DBoxIntercepts", {{-1., -1., -1.}, {1., 1., 1.}}]]],
{{pp, Normalize /@ {{1., 1., 1.}}}, None},
{nf, None},
AutorunSequencing -> {2}]]
Which gives something like this:
But there are a few things I cannot make my brain figure out:
1. How to have a Locator
click-and-drag-the-end-of-the-arrow type functionality?
When you use Locator
instead of None
in the last argument for pp
in manipulate, it ends up creating several errors namely due to the fact that Locator
uses a 2-D field to deliver its coordinates rather than the implemented 3-D one given by holding shift and moving the mouse around.
2. How to make the located coordinates usable in/able to be passed to other functions?
I genuinely cannot figure out how to access these dynamic variables. Though I can get the proper manipulation of them to occur within the Manipulate
, it would be great to purposefully leak them to use in other functions, like how a Locator
is designed to work.
3. How to lock the LocatorVector
to a specific region/quadrant or set of values to prevent the user from making errors based on location choice?
I think this has something to do with the "Graphics3DBoxIntercepts"
but I could not get anything meaningful to occur through my experimentation with it.
4. How to alter the view angle so that the region the vector starts in is visible to the user without manually rotating the Graphics3D
?
This should be an easy one, I think...
5. How to improve this implementation further?
I know this can be immensely improved, and I hope others find this useful, even in its current, rough-and-tumbled format.