Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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"}
            ]
share|improve this question
1  
I think you need to reconstruct this using either While or TakeWhile –  Verbeia Jan 20 '12 at 1:19
    
Do you really want to do this with Goto? It'll be more complicated than what I gave below. –  acl Jan 20 '12 at 1:24
add comment

3 Answers

up vote 4 down vote accepted

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

share|improve this answer
    
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. –  balboa Jan 20 '12 at 1:26
    
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. –  acl Jan 20 '12 at 1:30
1  
@balboa: maybe you should be asking about your "complicated graphics" instead of this toy example... –  J. M. Jan 20 '12 at 1:34
1  
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. –  balboa Jan 20 '12 at 1:55
1  
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...) –  acl Jan 20 '12 at 1:58
show 2 more comments

(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]
share|improve this answer
    
"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. –  J. M. Jan 20 '12 at 1:33
add comment

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

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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