4
$\begingroup$

What I want to do is to draw graphics part by part, because I made a function that generates coordinates according to which I will draw graphics. The problem is that MMA does not operate as I expected. To figure out what I'm doing here's simplified example:

Graphics[{
  a = 1;
  Label[tag];
  If[a < 3,
   {Circle[{a, 1}, 1],
    a = a + 1;
    Goto[tag];},
   {Text["It's finished", {0, 0}]}]
  }]

And what I get as output is simply text "It's finished". But what I want as output is graphics with two circles with radii 1 and centers positioned at {1,1} and {2,1} together with text "It's finished".

I figure out the way MMA thinks, and why it gives me this as output. But how can I accomplish my desired output?

Edit:

Here's the code, It's really messy and tips on how to neatly write code in MMA would be appreciated.

   Manipulate[

    Graphics[{

    (*calculating incident angle*)
    α = ArcSin[H/R];
    (*calculating x-coordinate where incident ray leaves prism*)
    p = Sqrt[R^2 - H^2];
    (*Drawing incident ray*)
    {Red, Thick, Line[{{-2, H}, {p, H}}]},

    (*Drawing prism*)
    {Blue, Opacity[.5], Disk[{0, 0}, R, {0, Pi/2}]},

    (*checking whether it's reflection or refraction*)
    If[H < R/n,
            {(*refraction*)
            (*calculating x-coordinate where refracted ray hits surface*)
            l = (R^2 n)/(Sqrt[R^2 - H^2] n - Sqrt[R^2 - H^2 n^2]);
            (*Drawing refracted ray*)
            {Red, Thick, Line[{{p, H}, {l, 0}}]}
            },

    {(*internal reflection*)
                (*calculating x-coordinate where after internal reflection ray hits \
surface*)
                new = H;
                k = 1;
            Label[tag];
            s = R Cos[α] - new/Tan[2 α];
                If[s <= R,
                {
                {Red, Thick, Line[{{p, new}, {s, 0}}]}
                },

                  {
                θ = (2 k + 1) α - k Pi;
                f = R Cos[θ];
                h = R Sin[θ];
                k = k + 1;
                Line[{{{p, new}, {f, h}}}],
                new = h;
                p = f;
                Goto[tag];
                }
                ]
            }
        ]
            }],

    {{H, 3, "Height"}, 0.0001, R - 0.0001, Appearance -> "Labeled"},
    {{n, 1.5, "Refraction"}, 1.001, 2, Appearance -> "Labeled"},
    {{R, 10, "Radius"}, 0, 10, Appearance -> "Labeled"}
            ]
$\endgroup$
2
  • 1
    $\begingroup$ I think you need to reconstruct this using either While or TakeWhile $\endgroup$
    – Verbeia
    Jan 20, 2012 at 1:19
  • $\begingroup$ Do you really want to do this with Goto? It'll be more complicated than what I gave below. $\endgroup$
    – acl
    Jan 20, 2012 at 1:24

3 Answers 3

4
$\begingroup$

What you want is done by

Graphics[Table[Circle[{a, 1}, 1], {a, 1, 2}] ~Append~ Text["It's finished", {0, 0}]]

enter image description here

Here's another approach, with minimal changes to your code:

Graphics[
  {
     a = 1;
     Label[tag];
     If[a < 3,
        {Sow @ Circle[{a, 1}, 1], a = a + 1; Goto[tag];},
        {Sow @ Text["It's finished", {0, 0}]}]
  } // Reap // Last // Last
]

EDIT: I'm afraid I am not sure what that is supposed to look like, but does this

Manipulate[
 Graphics[
  {
   α = ArcSin[H/R];
   p = Sqrt[R^2 - H^2];
   {Red, Thick, Line[{{-2, H}, {p, H}}]},
   {Blue, Opacity[.5], Disk[{0, 0}, R, {0, Pi/2}]},
   If[
    H < R/n,
    {
     l = (R^2 n)/(Sqrt[R^2 - H^2] n - Sqrt[R^2 - H^2 n^2]);
     {Red, Thick, Line[{{p, H}, {l, 0}}]}
     },
    Last@Last@Reap[
       {
        novo = H;
        k = 2;
        Sow@Text[θ, {10, 5}], Text[α, {10, 7}], 
        Text[k, {10, 9}],
        Label[oznaka];
        s = R Cos[α] - novo/Tan[2 α];
        If[s <= R,
         Sow@{{Red, Thick, Line[{{p, novo}, {s, 0}}]}},
         {θ = (2 k + 1) α - k Pi;
          f = R Cos[θ];
          h = R Sin[θ];
          k = k + 1;
          Sow@Line[{{{p, novo}, {f, h}}}], novo = h;
          p = f;
          Goto[oznaka];}]}
       ]
    ]
   }
  ],
 {{H, 9.45991`, "Vertikalna udaljenost upadne zrake"}, 0.0001, 
  R - 0.0001, 
  Appearance -> "Labeled"}, {{n, 1.5, 
   "Koeficijent prelamanja stakla"}, 1.001, 2, 
  Appearance -> "Labeled"}, {{R, 10, "Poluprecnik prizme"}, 0, 10, 
  Appearance -> "Labeled"}]

work?

enter image description here

$\endgroup$
7
  • $\begingroup$ I don't think that Table[] will help me, because I have complicated graphics. But it's my fault, I did't explained it in my question, I'll edit it now. $\endgroup$
    – balboa
    Jan 20, 2012 at 1:26
  • $\begingroup$ This is a minimally-altered version of your code that (I think) does what you want. Are you sure Table won't work? It's practically equivalent to the If-Goto structure you have. $\endgroup$
    – acl
    Jan 20, 2012 at 1:30
  • 1
    $\begingroup$ @balboa: maybe you should be asking about your "complicated graphics" instead of this toy example... $\endgroup$ Jan 20, 2012 at 1:34
  • 1
    $\begingroup$ yes, you solved it, I don't know how because I rushed with question and code I put was bad. But you did it. Thank you very much. And sorry for bad asked question. $\endgroup$
    – balboa
    Jan 20, 2012 at 1:55
  • 1
    $\begingroup$ No problem. I will try to make some suggestions on how to make this more readable/less error prone tomorrow (although this is the first time I've seen Goto used in mathematica, which makes this exotic...) $\endgroup$
    – acl
    Jan 20, 2012 at 1:58
2
$\begingroup$

(Starting remark: Just like in any other language, Goto is an evil statement that should never ever be used.)

One way of accomplishing what you want is generating the code as an ordinary list, and then giving this to Graphics:

 In[1] := circles = Table[Circle[{a, 1}], {a, 1, 2}]
Out[1]  = {Circle[{1, 1}], Circle[{2, 1}]}

 In[2] := text = {Text["It's finished", {0, 0}]}
Out[2]  = {Text["It's finished", {0, 0}]}

 In[3] := Join[circles, text]
          Graphics[%]
Out[3]  = {Circle[{1, 1}], Circle[{2, 1}], Text["It's finished", {0, 0}]}

enter image description here

You could also have created two separate graphics first, and then combined these with Show:

circles = Graphics@Table[Circle[{a, 1}], {a, 1, 2}];
text = Graphics@{Text["It's finished", {0, 0}]};
Show[circles, text]
$\endgroup$
1
  • $\begingroup$ "Goto[] is an evil statement that should never ever be used." - that's quite harsh; there are times one might need to use a label-goto pair. On the other hand, due to the richness of Mathematica, times like those are exceedingly rare. $\endgroup$ Jan 20, 2012 at 1:33
1
$\begingroup$

If you know for sure that it is just a matter of $a = 1, 2, 3,...$ and you want to stop at 3, then this is sufficient.

Graphics[Join[
 Circle[{#, 1}, 1] & /@ Range[3], {Text["It's finished", {0, 0}]}]]

If the values of $a$ are not known in advance and not in order of magnitude, then something like this would be sufficient:

Graphics[Join[
 Circle[{#, 1}, 1] & /@ 
  TakeWhile[RandomInteger[4, {10}], # < 4 &], {Text["It's finished", {0, 0}]}]]

Note I've used $a<4$ as the criterion not $a<3$ as in the question, to make the second example a bit more interesting. Both cases generate a graphic identical to this one.

enter image description here

But from the title of your question, I get the impression that what you really want is a sequence of graphics, showing the image built up step by step. For that you want something using NestWhileList, FoldList or similar. Below is an example using NestWhileList. If you only want the last one to have the text, this is a straightforward modification of the code below.

Graphics[Join[#, {Text["It's finished", {0, 0}]}]] & /@ 
Rest@NestWhileList[
Flatten@Join[{#}, {Circle[{Length[#] + 1, 1}, 1]}] &, {}, 
Length[#] < 3 &]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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