Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 08:55 01 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Trying to draw fractal trees, odd behavior

Author Message
daveculp
Newbie

Joined: 02/07/2020
Location: United States
Posts: 22
Posted: 09:46pm 08 Jul 2020
Copy link to clipboard 
Print this post

Im trying to draw a simple fractal tree which draws a horizontal line then recursively draws two lines from the end point of that line by rotating -25 and + 25 degrees then keeps going fro a set number of iterations.

Here is the code, a bit messy as I've been fiddling around with it.:

The print statements are simply debug statements to let me see some values and can be REM'd out.


drawTreeLeft(MM.HRES/2, MM.VRES,-90,10)
drawTreeRight(MM.HRES/2, MM.VRES,-90,10)

SUB drawTreeLeft (x1,y1, angle, iter)
  if iter >0 then

   x2 = x1 + int(cos( RAD(angle) ) * iter * 10.0)
   y2 = y1 + int(sin( RAD (angle) ) * iter * 10.0)

   print angle,":";x1,y1,":",x2,y2
   
   line x1,y1,x2,y2,1,RGB(brown)
   
   drawTreeLeft(x2,y2, angle -25, iter - 1)
   REM drawTree(x2,y2, angle +25, iter - 1)
 else
   circle x1,y1,3,1,1,RGB(GREEN), RGB(GREEN)
 end if
END SUB

SUB drawTreeRight (x1,y1, angle, iter)
 if iter >0 then

   x2 = x1 +int(( cos( RAD(angle) )) * iter * 10.0)
   y2 = y1 +int(( sin( RAD (angle) )) * iter * 10.0)

   print angle,":";x1,y1,":",x2,y2
   line x1,y1,x2,y2,1,RGB(brown)
   
   REM drawTree(x2,y2, angle -25, iter - 1)
   drawTreeRight(x2,y2, angle +25, iter - 1)
 else
   circle x1,y1,3,1,1,RGB(GREEN), RGB(GREEN)
 end if
END SUB


The odd behavior is the following two things:

1.  x1 and x2 and y1 and y2 turn out to be the same and they shouldnt.  I NEVER change the value of x1 and y1.  Why is this?

2.  Problem #1 is solved if I do something like the following in the function:


drawTreeLeft(MM.HRES/2, MM.VRES,-90,10)
drawTreeRight(MM.HRES/2, MM.VRES,-90,10)

SUB drawTreeLeft (x1,y1, angle, iter)
  start_x = x1
  start_y = y1
  if iter >0 then

   x2 = x1 + int(cos( RAD(angle) ) * iter * 10.0)
   y2 = y1 + int(sin( RAD (angle) ) * iter * 10.0)

   print angle,":";x1,y1,":",x2,y2
   
   line start_x,start_y,x2,y2,1,RGB(brown)
   
   drawTreeLeft(x2,y2, angle -25, iter - 1)
   REM drawTree(x2,y2, angle +25, iter - 1)
 else
   circle x1,y1,3,1,1,RGB(GREEN), RGB(GREEN)
 end if
END SUB


3.  I originally had it as one function which would call the drawTree sub twice (see the REM), one for drawing the left branch and one for the right.  However, it only ever drew the left branch.

4.  It should be recursively calling the drawTree function for EVERY LINE, but it doesn't.

I figure #3 and #4 are probably due to the way MMBASIC handles recursion and I know there is a limit of 50 recursive calls.  I will probably need to figure out another way to do this.

I cant figure out #1 though.  Why are x1 and y2 being set to x2 and y2?
Edited 2020-07-09 07:50 by daveculp
 
vegipete

Guru

Joined: 29/01/2013
Location: Canada
Posts: 1132
Posted: 10:45pm 08 Jul 2020
Copy link to clipboard 
Print this post

Does it improve if you use local variables in the subroutines?
Visit Vegipete's *Mite Library for cool programs.
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 12:14am 09 Jul 2020
Copy link to clipboard 
Print this post

How about "Christmas in July"

 ' seasons greetings
 
 option explicit
 option default float
 mode 1
 dim stX=mm.hres/2           'Tree starting point
 dim stY=mm.vres*0.9
 dim newX, newY, leng
 dim angle = 30 '-30
 dim stL = mm.vres/5
 dim delta = stL/7
 dim dr = 270
 dim TurtleSpeed = 15    'speed options
 DIM as float stack(100)      'FILO stack
 DIM AS INTEGER cols(6)
 cols(0)= RGB(RED)
 cols(1)= RGB(WHITE)
 cols(2)= RGB(yellow)
 cols(3)= RGB(green)
 cols(4)= RGB(blue)
 cols(5)= RGB(magenta)
 
 dim stackpos=1
 dim c=0
 
 ' melody globals
 DIM AS FLOAT melody(160,2)
 DIM AS INTEGER tonePos, endTone, endMelody, t
 endMelody = 1 ' needs to be set so that the first melody will start playing
 
 CLS
 
 do
   IF endMelody = 1 THEN
   if tempr(42) <> 1000 then ' only print temperature if available
     text stX, stY+30, " "+str$(tempr(42),2,2)+" C  ", cm
   endif
     t = (t+1) mod 2
     select case t ' rotate melodies
       case 0
         RESTORE jingleBells
       case 1
         restore jinglebells2
     end select
     playMelody
   ENDIF
   newX=stX
   newY=stY
   leng = stL
   angle = 0 - angle ' flip this each cycle to give windscreen washer action
   dr = 270
   c=(c+1) mod 6
   LINE newX, newY-1, newX, newY ,1,cols(c)
   drawtree
 loop
END
 
SUB drawtree
 local oldx, oldy, c, n
 IF endTone = 1 THEN playNextTone
 IF (leng > 0) THEN
   c = int(rnd()*6)
   oldX=newX
   oldY=newY
   newX=oldX - COS(RAD(dr))*leng
   newY=oldY + SIN(RAD(dr))*leng
   LINE oldX, oldY, newX, newY,1,cols(c)
   for n = 1 to TurtleSpeed ' break up the pause to allow for the tune to play smoothly
   PAUSE 1
   IF endTone = 1 THEN playNextTone
   next n
   dr=dr+angle
   stack(stackpos)=leng
   stackpos=stackpos+1
   leng = leng - delta
   drawtree    'recursive calling itself
   dr=dr-(angle * 2)
   drawtree    'recursive calling itself
   dr=dr+angle
   stackpos=stackpos-1
   leng = stack(stackpos)
   oldX=newX
   oldY=newY
   newX=oldX - COS(RAD(dr)+3.14159)*leng
   newY=oldY + SIN(RAD(dr)+3.14159)*leng
   LINE oldX, oldY, newX, newY,1,cols(c)
   for n = 1 to TurtleSpeed
   PAUSE 1
   IF endTone = 1 THEN playNextTone
   next n
   text stX, stY+10, time$, cm
 ENDIF
END SUB
 
 ' music melodies
SUB playMelody
 LOCAL AS INTEGER n
 ' assumes that the DATA pointer has been restored
 ' and the DATA ends with a pair of zeros
 tonePos = 0
 endMelody = 0
 FOR n = 1 TO 160
   READ melody(n,1), melody(n,2)
   IF melody(n,1) + melody(n,2) = 0 THEN EXIT FOR
 NEXT n
 endTone = 1 ' ready to start playing
END SUB
 
SUB toneEnd
 endTone = 1
END SUB
 
SUB playNextTone
 endTone = 0
 tonePos = tonePos + 1
 'settick 0,0,1  'turn off the 'rest' timer
 ' print melody(tonePos,1),melody(tonePos,2)
 if melody(tonePos,1) + melody(tonePos,2) > 0 then
   play tone melody(tonePos,1),melody(tonePos,1),melody(tonePos,2),toneEnd
 else
   ' don't re-set the end of tone flag
   ' just flag the end of melody
   endMelody = 1
 endif
end sub
 
 ' frequency, time pairs of DATA
 ' a zero frequency indicates a period of silence
 ' 0, 0 to indicate end of the melody
JingleBells:
 DATA  392.0,  240.0, 659.3,  240.0, 587.3,  240.0, 523.3,  240.0
 DATA  392.0,  960.0, 392.0,  240.0, 659.3,  240.0, 587.3,  240.0
 DATA  523.3,  240.0, 440.0,  960.0, 440.0,  240.0, 698.5,  240.0
 DATA  587.3,   28.2, 493.9,  240.0, 392.0,  240.0, 493.9,  240.0
 DATA  587.3,  240.0, 784.0,  360.0, 784.0,  120.0, 698.5,  240.0
 DATA  587.3,  240.0, 659.3,  960.0, 392.0,  240.0, 659.3,  240.0
 DATA  587.3,  240.0, 523.3,  240.0, 392.0,  960.0, 370.0,  120.0
 DATA  392.0,  240.0, 587.3,   28.2, 523.3,  240.0, 440.0,  960.0
 DATA  440.0,  240.0, 698.5,  240.0, 659.3,  240.0, 587.3,  240.0
 DATA  784.0,  240.0, 784.0,  120.0, 740.0,  120.0, 784.0,  120.0
 DATA  740.0,  120.0, 784.0,  120.0, 830.6,  120.0, 784.0,  123.1
 DATA  659.3,  240.0, 587.3,  240.0, 523.3,  480.0, 784.0,  480.0
 DATA  659.3,  240.0, 659.3,  240.0, 659.3,  360.0, 622.3,  120.0
 DATA  659.3,  240.0, 659.3,  240.0, 659.3,  360.0, 622.3,  120.0
 DATA  659.3,  240.0, 784.0,  240.0, 587.3,  123.1, 659.3,  960.0
 DATA  698.5,  240.0, 698.5,  240.0, 698.5,  360.0, 698.5,  120.0
 DATA  698.5,  240.0, 659.3,  240.0, 659.3,  240.0, 659.3,  120.0
 DATA  659.3,  120.0, 659.3,  240.0, 587.3,  240.0, 587.3,  240.0
 DATA  659.3,  240.0, 587.3,  960.0, 0,0
' End of JingleBells

JingleBells2:
 DATA  392.0,  210.0,   0.0,   30.0, 659.3,  210.0,   0.0,   30.0
 DATA  587.3,  210.0,   0.0,   30.0, 523.3,  210.0,   0.0,   30.0
 DATA  392.0,  840.0,   0.0,  120.0, 392.0,  210.0,   0.0,   30.0
 DATA  659.3,  210.0,   0.0,   30.0, 587.3,  210.0,   0.0,   30.0
 DATA  523.3,  210.0,   0.0,   30.0, 440.0,  840.0,   0.0,  120.0
 DATA  440.0,  210.0,   0.0,   30.0, 698.5,  210.0,   0.0,   30.0
 DATA  587.3,   24.7,   0.0,    3.5, 493.9,  210.0,   0.0,   30.0
 DATA  392.0,  210.0,   0.0,   30.0, 493.9,  210.0,   0.0,   30.0
 DATA  587.3,  210.0,   0.0,   30.0, 784.0,  315.0,   0.0,   45.0
 DATA  784.0,  105.0,   0.0,   15.0, 698.5,  210.0,   0.0,   30.0
 DATA  587.3,  210.0,   0.0,   30.0, 659.3,  840.0,   0.0,  120.0
 DATA  392.0,  210.0,   0.0,   30.0, 659.3,  210.0,   0.0,   30.0
 DATA  587.3,  210.0,   0.0,   30.0, 523.3,  210.0,   0.0,   30.0
 DATA  392.0,  840.0,   0.0,  120.0, 370.0,  105.0,   0.0,   15.0
 DATA  392.0,  210.0,   0.0,   30.0, 587.3,   24.7,   0.0,    3.5
 DATA  523.3,  210.0,   0.0,   30.0, 440.0,  840.0,   0.0,  120.0
 DATA  440.0,  210.0,   0.0,   30.0, 698.5,  210.0,   0.0,   30.0
 DATA  659.3,  210.0,   0.0,   30.0, 587.3,  210.0,   0.0,   30.0
 DATA  784.0,  210.0,   0.0,   30.0, 784.0,  105.0,   0.0,   15.0
 DATA  740.0,  105.0,   0.0,   15.0, 784.0,  105.0,   0.0,   15.0
 DATA  740.0,  105.0,   0.0,   15.0, 784.0,  105.0,   0.0,   15.0
 DATA  830.6,  105.0,   0.0,   15.0, 784.0,  107.7,   0.0,   15.4
 DATA  659.3,  210.0,   0.0,   30.0, 587.3,  210.0,   0.0,   30.0
 DATA  523.3,  420.0,   0.0,   60.0, 784.0,  420.0,   0.0,   60.0
 DATA  659.3,  210.0,   0.0,   30.0, 659.3,  210.0,   0.0,   30.0
 DATA  659.3,  315.0,   0.0,   45.0, 622.3,  105.0,   0.0,   15.0
 DATA  659.3,  210.0,   0.0,   30.0, 659.3,  210.0,   0.0,   30.0
 DATA  659.3,  315.0,   0.0,   45.0, 622.3,  105.0,   0.0,   15.0
 DATA  659.3,  210.0,   0.0,   30.0, 784.0,  210.0,   0.0,   30.0
 DATA  587.3,  107.7,   0.0,   15.4, 659.3,  840.0,   0.0,  120.0
 DATA  698.5,  210.0,   0.0,   30.0, 698.5,  210.0,   0.0,   30.0
 DATA  698.5,  315.0,   0.0,   45.0, 698.5,  105.0,   0.0,   15.0
 DATA  698.5,  210.0,   0.0,   30.0, 659.3,  210.0,   0.0,   30.0
 DATA  659.3,  210.0,   0.0,   30.0, 659.3,  105.0,   0.0,   15.0
 DATA  659.3,  105.0,   0.0,   15.0, 659.3,  210.0,   0.0,   30.0
 DATA  587.3,  210.0,   0.0,   30.0, 587.3,  210.0,   0.0,   30.0
 DATA  659.3,  210.0,   0.0,   30.0, 587.3,  840.0,   0.0,  120.0, 0,0
' End of JingleBells2


Jim
VK7JH
MMedit
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4044
Posted: 06:31am 09 Jul 2020
Copy link to clipboard 
Print this post

  daveculp said  The odd behavior is the following two things:

1.  x1 and x2 and y1 and y2 turn out to be the same and they shouldnt.  I NEVER change the value of x1 and y1.  Why is this?


I wonder if in each drawtree you need
local x2, y2

I'm not sure if you meant not to specify any types and are happy with the default.

John
Edited 2020-07-09 16:33 by JohnS
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 06:50am 09 Jul 2020
Copy link to clipboard 
Print this post

  Quote  Passing Arguments by Reference
If you use an ordinary variable (ie, not an expression) as the value when calling a subroutine or a function, the
argument within the subroutine/function will point back to the variable used in the call and any changes to the
argument will also be made to the supplied variable. This is called passing arguments by reference.


 CLS
 
 drawTreeLeft(MM.HRES/2, MM.VRES,-90,10)
 drawTreeRight(MM.HRES/2, MM.VRES,-90,10)
 
SUB drawTreeLeft (x1,y1, angle, iter)
 LOCAL xx1, yy1
 xx1 = x1
 yy1 = y1
 IF iter >0 THEN
   
   x2 = xx1 + INT(COS( RAD(angle) ) * iter * 10.0)
   y2 = yy1 + INT(SIN( RAD (angle) ) * iter * 10.0)
   
   PRINT angle,":";xx1,yy1,":",x2,y2
   
   LINE xx1,yy1,x2,y2,1,RGB(BROWN)
   
   drawTreeLeft(x2,y2, angle -25, iter - 1)
   REM drawTree(x2,y2, angle +25, iter - 1)
 ELSE
   CIRCLE x1,y1,3,1,1,RGB(GREEN), RGB(GREEN)
 END IF
END SUB
 
SUB drawTreeRight (x1,y1, angle, iter)
 LOCAL xx1, yy1
 xx1 = x1
 yy1 = y1
 IF iter >0 THEN
   
   x2 = xx1 +INT(( COS( RAD(angle) )) * iter * 10.0)
   y2 = yy1 +INT(( SIN( RAD (angle) )) * iter * 10.0)
   
   PRINT angle,":";xx1,yy1,":",x2,y2,"**"
   LINE xx1,yy1,x2,y2,1,RGB(BROWN)
   
   REM drawTree(x2,y2, angle -25, iter - 1)
   drawTreeRight(x2,y2, angle +25, iter - 1)
 ELSE
   CIRCLE x1,y1,3,1,1,RGB(GREEN), RGB(GREEN)
 END IF
END SUB


Jim
VK7JH
MMedit
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025