2
$\begingroup$

I'm trying to create a function that uses a dynamic locatorpane to populate a list with the coordinates of user defined locators (added by alt+clicking). This code works fine:

one = ExampleData[{"TestImage", "Airplane"}]

ptsa = {};
ptsb = {};

Button["Reset points", ptsa = {}]
LocatorPane[Dynamic[ptsa],
 Dynamic[
  Show[one,
   Graphics[{
     Table[(*draw arrows between locators*)
      Arrow[{
        ptsa[[i]], ptsa[[i + 1]]
        }],
      {i, 1, Floor[Length[ptsa], 2], 2}
      ],
     Table[
      Text[(i + 1)/2, 
       ptsa[[i]] + (ptsa[[i + 1]] - ptsa[[i]])/2 + 
        Cross[ptsa[[i + 1]] - ptsa[[i]]]/
         EuclideanDistance[ptsa[[i + 1]], 
          ptsa[[i]]]*10],(*display line # 5 pixels orthogonal to line \
midpoint*)
      {i, 1, Floor[Length[ptsa], 2], 2}
      ]
     }]
   ]
  ],
 LocatorAutoCreate -> True, 
 Appearance -> Style["\[CenterDot]", Medium, Red]]

That works for the single list: "ptsa" and allows me to insert points into "ptsa" with a point-and-click interface.

However, I need to do this for many different lists (ptsb, ptsc, ptsd, etc). I tried making a function ui[ptsa_] := LocatorPane[...] so I can just do ui[ptsb] in the future, but this simply inserts {} into ptsa, which doesn't help.

I also tried defining the above simply as a = LocatorPane[...] and trying

a /. ptsa -> ptsb

but that doesn't work either. I'm not sure how to approach this.

$\endgroup$
4
  • $\begingroup$ Welcome to MMA.SE. Please try to provide a minimal working example for you questions in the future. The LocatorPane and other details are not relevant there. Please take a look at HoldFirst documentation's examples, I believe there is the answer to your question. $\endgroup$
    – Kuba
    Apr 6 '16 at 5:37
  • 4
    $\begingroup$ I'm voting to close this question as off-topic because it is to localized. $\endgroup$
    – Kuba
    Apr 8 '16 at 8:02
  • 1
    $\begingroup$ @Kuba. I don't agree. It's a simple question with a simple answer, but it certainly is an issue that often comes up. $\endgroup$
    – m_goldberg
    Apr 8 '16 at 13:57
  • $\begingroup$ @m_goldberg that's probably arguable :) I think it is in OP's reach to reduce the problem to drop Locator/Graphics context, yet my comment was left without any answer. That's why I voted to close as too localized. Furthermore, after reducing the problem what stays is a simple mistake or a duplicate candidate. $\endgroup$
    – Kuba
    Apr 8 '16 at 14:25
3
$\begingroup$

All you have to do is give ui the attribute HoldFirst. It also a good idea to make the image an argument of ui. That is, define

SetAttributes[ui, HoldFirst];
ui[pts_, img_Image] :=
  LocatorPane[
    Dynamic[pts],
    Dynamic[
     Show[
      img,
      Graphics[
        {Table[
           Arrow[{pts[[i]], pts[[i + 1]]}], 
           {i, 1, Floor[Length[pts], 2], 2}],
         Table[
           Text[
             (i + 1)/2, 
             pts[[i]] + (pts[[i + 1]] - pts[[i]])/2 + 
               Cross[pts[[i + 1]] - pts[[i]]] /
                 EuclideanDistance[pts[[i + 1]], pts[[i]]]*10], 
             {i, 1, Floor[Length[pts], 2], 2}]}]]],
    LocatorAutoCreate -> True,
    Appearance -> Style["\[CenterDot]", Medium, Red]]

Then

ptsa = {};
ui[ptsa, one]

image

Dynamic @ ptsa

{{231.6, 158.5}, {213.2, 74.}, {70.8, 130.}, {156.4, 83.5}}

$\endgroup$

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