Difference between revisions of "Branch Assignment"

From CSE425S Wiki
Jump to navigation Jump to search
 
(7 intermediate revisions by the same user not shown)
Line 6: Line 6:
 
: [https://apidock.com/ruby/Array/push push]
 
: [https://apidock.com/ruby/Array/push push]
 
: [https://apidock.com/ruby/Array/pop pop]
 
: [https://apidock.com/ruby/Array/pop pop]
 
==OpenGL==
 
: [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glPushMatrix.xml glPushMatrix]
 
: [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glPopMatrix.xml glPopMatrix]
 
  
 
==LogoTurtle==
 
==LogoTurtle==
Line 22: Line 18:
 
Note: <code>attr_accessor :pen_color, :pen_width</code> provides pen_color, pen_color=, pen_width, and pen_width= methods.
 
Note: <code>attr_accessor :pen_color, :pen_width</code> provides pen_color, pen_color=, pen_width, and pen_width= methods.
  
<nowiki>class LogoTurtle
+
<syntaxhighlight lang="ruby">
 +
class Turtle
 +
  # https://el.media.mit.edu/logo-foundation/what_is_logo/logo_primer.html
 
   attr_accessor :pen_color, :pen_width
 
   attr_accessor :pen_color, :pen_width
   def initialize
+
 
     super
+
   def initialize(g, pen_width: 0.005, pen_color: Color::WHITE)
 +
     super()
 +
    @g = g
 
     @is_pen_down = true
 
     @is_pen_down = true
     @pen_width = 0.005
+
     @pen_width = pen_width
     @pen_color = Color::WHITE
+
     @pen_color = pen_color
 
   end
 
   end
  
 
   def pen_up
 
   def pen_up
     @is_pen_down = true
+
     @is_pen_down = false
 
   end
 
   end
  
 
   def pen_down
 
   def pen_down
     @is_pen_down = false
+
     @is_pen_down = true
 
   end
 
   end
 
  
 
   def forward(amount)
 
   def forward(amount)
Line 44: Line 43:
 
     x = @pen_width
 
     x = @pen_width
 
     if @is_pen_down
 
     if @is_pen_down
       glColor3f(@pen_color.red, @pen_color.green, @pen_color.blue)
+
       @g.color = @pen_color
       glBegin(GL_QUADS)
+
       points = [
      glVertex2d(-x, 0.0)
+
        Point2.new(-x, 0.0),
      glVertex2d(-x, y)
+
        Point2.new(-x, y),
      glVertex2d(x, y)
+
        Point2.new(x, y),
      glVertex2d(x, 0.0)
+
        Point2.new(x, 0.0)
       glEnd()
+
       ]
 +
      @g.draw_convex_polygon(points)
 
     end
 
     end
     glTranslatef(0,y,0)
+
     @g.apply_translation(0, y)
 
   end
 
   end
  
 
   def right(degrees)
 
   def right(degrees)
     glRotatef(degrees, 0, 0, 1)
+
     @g.apply_rotation(-degrees)
 
   end
 
   end
 
end
 
end
</nowiki>
+
</syntaxhighlight>
  
 
==LogoTurtle Clients==
 
==LogoTurtle Clients==
Line 65: Line 65:
 
In this example client, a square is drawn by repeatedly moving forward and turning right 90 degrees.  The flower is drawn by repeatedly drawing slightly turned from each other squares.
 
In this example client, a square is drawn by repeatedly moving forward and turning right 90 degrees.  The flower is drawn by repeatedly drawing slightly turned from each other squares.
  
<nowiki>class Flower
+
<syntaxhighlight lang="ruby">
   def initialize
+
class Flower
     super
+
   def render(g)
    @turtle = LogoTurtle.new
+
     flower(Turtle.new(g))
  end
 
 
 
  def render
 
    flower
 
 
   end
 
   end
  
 
   private
 
   private
  
   def square
+
   def square(turtle)
 
     4.times do
 
     4.times do
       @turtle.forward 0.5
+
       turtle.forward 0.5
       @turtle.right 90
+
       turtle.right 90
 
     end
 
     end
 
   end
 
   end
  
   def flower
+
   def flower(turtle)
 
     36.times do
 
     36.times do
       @turtle.right 10
+
       turtle.right 10
       square
+
       square(turtle)
 
     end
 
     end
 
   end
 
   end
end</nowiki>
+
end
 +
</syntaxhighlight>
  
{{RubyToRun|flower|logo_turtle_clients|main}}
+
 
 +
{{RubyToRun|flower|turtle/clients|core}}
  
 
[[File:Logo_turtle_flower.png]]
 
[[File:Logo_turtle_flower.png]]
Line 100: Line 98:
 
In this client we draw equilateral polygons with different pen colors.  Further, each subsequent line segment of a polygon is draw with a smaller pen width.
 
In this client we draw equilateral polygons with different pen colors.  Further, each subsequent line segment of a polygon is draw with a smaller pen width.
  
<nowiki>class EquilateralPolygons
+
<syntaxhighlight lang="ruby">
   def initialize
+
class EquilateralPolygons
    super
+
   def render(g)
     @turtle = Turtle.new
+
     turtle = Turtle.new(g)
  end
+
    turtle.pen_color = Color::HONOLULU_BLUE
 +
    triangle(turtle)
  
  def render
+
     turtle.right(90)
     @turtle.pen_color = Color::HONOLULU_BLUE
 
    triangle
 
  
     @turtle.right(90)
+
     turtle.pen_width /= 2
 +
    turtle.pen_color = Color::PARIS_DAISY
 +
    square(turtle)
  
     @turtle.pen_width /= 2
+
     turtle.right(135)
    @turtle.pen_color = Color::PARIS_DAISY
 
    square
 
  
     @turtle.right(135)
+
     turtle.pen_color = Color::FRENCH_VIOLET
 
+
     pentagon(turtle)
    @turtle.pen_color = Color::FRENCH_VIOLET
 
     pentagon
 
 
   end
 
   end
  
 
   private
 
   private
  
   def triangle
+
   def triangle(turtle)
     polygon(3)
+
     polygon(turtle, 3)
 
   end
 
   end
  
   def square
+
   def square(turtle)
     polygon(4)
+
     polygon(turtle, 4)
 
   end
 
   end
  
   def pentagon
+
   def pentagon(turtle)
     polygon(5)
+
     polygon(turtle, 5)
 
   end
 
   end
  
   def polygon(n)
+
   def polygon(turtle, n)
     @turtle.pen_width = 0.03
+
     turtle.pen_width = 0.03
 
     n.times do
 
     n.times do
       @turtle.forward 0.5
+
       turtle.forward 0.5
       @turtle.right 360/n
+
       turtle.right 360/n
       @turtle.pen_width /= 2
+
       turtle.pen_width /= 2
 
     end
 
     end
 
   end
 
   end
end</nowiki>
+
end
 +
</syntaxhighlight>
  
{{RubyToRun|equilateral_polygons|logo_turtle_clients|main}}
+
{{RubyToRun|equilateral_polygons|turtle/clients|core}}
  
 
[[File:Equilateral_Polygons_Client.png]]
 
[[File:Equilateral_Polygons_Client.png]]
Line 166: Line 162:
 
In this client, the @teleporting_turtle starts facing up.  After changing the pen color and width, it moves forward, leaving behind a DODGER_BLUE line.  Then, it invokes the preserve_yield_restore method you just implemented.  The preserve_yield_restore method should  preserves the current state of the TeleportingTurtle (that is: the pen width, pen color, and the location and direction of the turtle in the form of the glMatrix) and yields to the specified block.  Within that block, the turtle is turned right, the pen width and color are changed, and then a 135 degree arc is drawn in OUTRAGEOUS_ORANGE.  Upon the completion of this block, control is returned to your preserve_yield_restore method which should restore the state of the turtle back to its pen color and width and turtle location and direction before preserve_yield_restore was invoked.  The turtle then moves forward, leaving behind a DODGER_BLUE line.
 
In this client, the @teleporting_turtle starts facing up.  After changing the pen color and width, it moves forward, leaving behind a DODGER_BLUE line.  Then, it invokes the preserve_yield_restore method you just implemented.  The preserve_yield_restore method should  preserves the current state of the TeleportingTurtle (that is: the pen width, pen color, and the location and direction of the turtle in the form of the glMatrix) and yields to the specified block.  Within that block, the turtle is turned right, the pen width and color are changed, and then a 135 degree arc is drawn in OUTRAGEOUS_ORANGE.  Upon the completion of this block, control is returned to your preserve_yield_restore method which should restore the state of the turtle back to its pen color and width and turtle location and direction before preserve_yield_restore was invoked.  The turtle then moves forward, leaving behind a DODGER_BLUE line.
  
<nowiki>class PreserveYieldRestoreClient
+
<syntaxhighlight lang="ruby">
   def initialize
+
class PreserveYieldRestoreClient
    super
+
   def render(g)
     @teleporting_turtle = TeleportingTurtle.new
+
     teleporting_turtle = TeleportingTurtle.new(g)
  end
+
     teleporting_turtle.pen_color = Color::DODGER_BLUE
 
+
     teleporting_turtle.pen_width = 0.02
  def render
+
     teleporting_turtle.forward(0.25)
     @teleporting_turtle.pen_color = Color::DODGER_BLUE
+
     teleporting_turtle.preserve_yield_restore do
     @teleporting_turtle.pen_width = 0.02
+
       teleporting_turtle.right(90)
     @teleporting_turtle.forward(0.25)
+
       teleporting_turtle.pen_color = Color::OUTRAGEOUS_ORANGE
     @teleporting_turtle.preserve_yield_restore do
+
       teleporting_turtle.pen_width = 0.005syntaxhighlight
       @teleporting_turtle.right(90)
 
       @teleporting_turtle.pen_color = Color::OUTRAGEOUS_ORANGE
 
       @teleporting_turtle.pen_width = 0.005
 
 
       45.times do
 
       45.times do
         @teleporting_turtle.right(5)
+
         teleporting_turtle.right(5)
         @teleporting_turtle.forward(0.05)
+
         teleporting_turtle.forward(0.05)
 
       end
 
       end
 
     end
 
     end
  
     @teleporting_turtle.forward(0.25)
+
     teleporting_turtle.forward(0.25)
 
   end
 
   end
end</nowiki>
+
end
 
+
</syntaxhighlight>
  
{{RubyToRun|preserve_yield_restore_client|teleporting_turtle_clients|main}}
+
{{RubyToRun|preserve_yield_restore_client|teleporting_turtle/client|cor}}
  
 
[[File:Preserve Yield Restore Client.png]]
 
[[File:Preserve Yield Restore Client.png]]
Line 218: Line 211:
 
|}
 
|}
  
===branch(length, line_width_in_pixels, depth_remaining)===
+
===branch(length, line_width, depth_remaining)===
 
Pass a block to [[#TeleportingTurtle|preserve_yield_restore]] to handle the preservation and restoration of the necessary OpenGL and TeleportingTurtle state.
 
Pass a block to [[#TeleportingTurtle|preserve_yield_restore]] to handle the preservation and restoration of the necessary OpenGL and TeleportingTurtle state.
  
 
Note: to produce the reference images the code below was used:
 
Note: to produce the reference images the code below was used:
  
<nowiki>     next_length = length * 0.5
+
<syntaxhighlight lang="ruby">
       next_line_width_in_pixels = line_width_in_pixels * 0.8</nowiki>
+
      next_length = length * 0.5
 +
       next_line_width = line_width * 0.8
 +
</syntaxhighlight>
  
 
Note: the child branches in the reference images are located at one third and at two thirds from the beginning to the end.
 
Note: the child branches in the reference images are located at one third and at two thirds from the beginning to the end.
Line 239: Line 234:
  
 
=Visual Comparison=
 
=Visual Comparison=
{{RubyToRun|branch_snapshots_web_page_generator|branch_snapshots|main}}
+
{{RubyToRun|branch_snapshots_web_page_generator|branch/snapshots|test}}
  
 
Note: there is no image difference comparison in these snapshots.  Do not stress about the exact pixel colors.  If it looks like an L-system branch, you should be in good shape.
 
Note: there is no image difference comparison in these snapshots.  Do not stress about the exact pixel colors.  If it looks like an L-system branch, you should be in good shape.

Latest revision as of 03:06, 15 December 2023

Reference

Lindenmayer system

Dragon trees.jpg

Array

push
pop

LogoTurtle

Seymour Papert.jpg

The turtle you will use in this assignment is inspired by the Turtle Graphics in the [Logo Programming Language] created by Wally Feurzeig, Seymour Papert, and Cynthia Solomon. The turtle was a robot which would draw with a pen on paper place on the floor. We will less excitingly draw on the screen with OpenGL.

A primer on how to use a turtle in its native habitat.

The provided class LogoTurtle below provides methods to get and set its pen color and width, pick the pen up and put it down, move forward, and turn right in degrees.

Note: attr_accessor :pen_color, :pen_width provides pen_color, pen_color=, pen_width, and pen_width= methods.

class Turtle
  # https://el.media.mit.edu/logo-foundation/what_is_logo/logo_primer.html
  attr_accessor :pen_color, :pen_width

  def initialize(g, pen_width: 0.005, pen_color: Color::WHITE)
    super()
    @g = g
    @is_pen_down = true
    @pen_width = pen_width
    @pen_color = pen_color
  end

  def pen_up
    @is_pen_down = false
  end

  def pen_down
    @is_pen_down = true
  end

  def forward(amount)
    y = amount
    x = @pen_width
    if @is_pen_down
      @g.color = @pen_color
      points = [
        Point2.new(-x, 0.0),
        Point2.new(-x, y),
        Point2.new(x, y),
        Point2.new(x, 0.0)
      ]
      @g.draw_convex_polygon(points)
    end
    @g.apply_translation(0, y)
  end

  def right(degrees)
    @g.apply_rotation(-degrees)
  end
end

LogoTurtle Clients

Flower Client

In this example client, a square is drawn by repeatedly moving forward and turning right 90 degrees. The flower is drawn by repeatedly drawing slightly turned from each other squares.

class Flower
  def render(g)
    flower(Turtle.new(g))
  end

  private

  def square(turtle)
    4.times do
      turtle.forward 0.5
      turtle.right 90
    end
  end

  def flower(turtle)
    36.times do
      turtle.right 10
      square(turtle)
    end
  end
end


file to run: src/core/ruby/turtle/clients/flower.rb Ruby logo.svg

Logo turtle flower.png

Pen Width and Color Client

In this client we draw equilateral polygons with different pen colors. Further, each subsequent line segment of a polygon is draw with a smaller pen width.

class EquilateralPolygons
  def render(g)
    turtle = Turtle.new(g)
    turtle.pen_color = Color::HONOLULU_BLUE
    triangle(turtle)

    turtle.right(90)

    turtle.pen_width /= 2
    turtle.pen_color = Color::PARIS_DAISY
    square(turtle)

    turtle.right(135)

    turtle.pen_color = Color::FRENCH_VIOLET
    pentagon(turtle)
  end

  private

  def triangle(turtle)
    polygon(turtle, 3)
  end

  def square(turtle)
    polygon(turtle, 4)
  end

  def pentagon(turtle)
    polygon(turtle, 5)
  end

  def polygon(turtle, n)
    turtle.pen_width = 0.03
    n.times do
      turtle.forward 0.5
      turtle.right 360/n
      turtle.pen_width /= 2
    end
  end
end
file to run: src/core/ruby/turtle/clients/equilateral_polygons.rb Ruby logo.svg

Equilateral Polygons Client.png

Code to Implement

TeleportingTurtle

file: src/main/ruby/teleporting_turtle/teleporting_turtle.rb Ruby logo.svg
class: TeleportingTurtle
superclass: Turtle
methods: preserve_yield_restore

preserve_yield_restore

This utility method will simply preserve the current state, yield to the block passed by the client, and then restore the preserved state.

Note: the private preserve_state and restore_state methods have been provided to you.


Teleporting Turtle Client

In this client, the @teleporting_turtle starts facing up. After changing the pen color and width, it moves forward, leaving behind a DODGER_BLUE line. Then, it invokes the preserve_yield_restore method you just implemented. The preserve_yield_restore method should preserves the current state of the TeleportingTurtle (that is: the pen width, pen color, and the location and direction of the turtle in the form of the glMatrix) and yields to the specified block. Within that block, the turtle is turned right, the pen width and color are changed, and then a 135 degree arc is drawn in OUTRAGEOUS_ORANGE. Upon the completion of this block, control is returned to your preserve_yield_restore method which should restore the state of the turtle back to its pen color and width and turtle location and direction before preserve_yield_restore was invoked. The turtle then moves forward, leaving behind a DODGER_BLUE line.

class PreserveYieldRestoreClient
  def render(g)
    teleporting_turtle = TeleportingTurtle.new(g)
    teleporting_turtle.pen_color = Color::DODGER_BLUE
    teleporting_turtle.pen_width = 0.02
    teleporting_turtle.forward(0.25)
    teleporting_turtle.preserve_yield_restore do
      teleporting_turtle.right(90)
      teleporting_turtle.pen_color = Color::OUTRAGEOUS_ORANGE
      teleporting_turtle.pen_width = 0.005syntaxhighlight
      45.times do
        teleporting_turtle.right(5)
        teleporting_turtle.forward(0.05)
      end
    end

    teleporting_turtle.forward(0.25)
  end
end
file to run: src/cor/ruby/teleporting_turtle/client/preserve_yield_restore_client.rb Ruby logo.svg

Preserve Yield Restore Client.png

Branch

file: src/main/ruby/branch/branch.rb Ruby logo.svg
class: Branch
superclass: Object
methods: branch

The goal of this assignment is to render a branch that looks something akin to the progression of max_depth branches below.

Note: the initialize method constructs a new instance of TeleportingTurtle as well as hangs onto the parameter values in instance variables.

Branch MaxDepth0.png Branch MaxDepth1.png Branch MaxDepth2.png Branch MaxDepth3.png Branch MaxDepth4.png Branch MaxDepth5.png
max_depth: 0 max_depth: 1 max_depth: 2 max_depth: 3 max_depth: 4 max_depth: 5

branch(length, line_width, depth_remaining)

Pass a block to preserve_yield_restore to handle the preservation and restoration of the necessary OpenGL and TeleportingTurtle state.

Note: to produce the reference images the code below was used:

      next_length = length * 0.5
      next_line_width = line_width * 0.8

Note: the child branches in the reference images are located at one third and at two thirds from the beginning to the end.

Note: the child branches in the reference images are rotated 30.0 degrees and -30.0 degrees from their parent branch.

Note: in the recursive case the child branches were drawn before the line at the current depth to allow the green to be beneath the brown.

Do NOT worry if your images are not exact matches of the reference images.

file to run: src/main/ruby/branch/branch.rb Ruby logo.svg

Branch MaxDepth5.png

Visual Comparison

file to run: src/test/ruby/branch/snapshots/branch_snapshots_web_page_generator.rb Ruby logo.svg

Note: there is no image difference comparison in these snapshots. Do not stress about the exact pixel colors. If it looks like an L-system branch, you should be in good shape.