Difference between revisions of "Render Part B Assignment"

From CSE425S Wiki
Jump to navigation Jump to search
 
(30 intermediate revisions by the same user not shown)
Line 1: Line 1:
In this studio we will evolve our code from [[Render_Part_A_Assignment|Render (Part A)]] to leverage class hierarchies.
+
'''Fall 2023 ALERT: there is an error in scene.rb'''
  
[[File:Render_part_b_class_hierarchy.svg]]
+
'''The require_relative at the top of the file is missing a ../'''
  
Continue editing files in the drawings directory.
+
'''Change the require_relative from:'''
  
In this studio, we will have parameters for which explicitly passed arguments are not required (for convenience and backwards compatibility).  We will [https://github.com/rubocop-hq/ruby-style-guide#keyword-arguments-vs-optional-arguments prefer keyword arguments over optional arguments].
+
<s>require_relative '../../../core/ruby/render/core/render'</s>
 +
 
 +
'''to:'''
 +
 
 +
<syntaxhighlight lang="ruby">
 +
require_relative '../../../../core/ruby/render/core/render'
 +
</syntaxhighlight>
 +
 
 +
In this assignment we will evolve our code from [[Render_Part_A_Assignment|Render (Part A)]] to leverage class hierarchies.
 +
 
 +
[[File:Diagram_part_b.png|600px]]
 +
 
 +
Continue editing files in the drawings/core directory.
 +
 
 +
In this exercise, we will have parameters for which explicitly passed arguments are not required (for convenience and backwards compatibility).  We will [https://github.com/rubocop-hq/ruby-style-guide#keyword-arguments-vs-optional-arguments prefer keyword arguments over optional arguments].
 +
 
 +
=Code To Use=
 +
[https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html Graphics]
 +
: [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#push_affine_transform-instance_method push_affine_transform]
 +
: [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#pop_affine_transform-instance_method pop_affine_transform]
 +
: [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#apply_translation-instance_method apply_translation]
 +
: [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#color=-instance_method color=]
 +
: [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#clear-instance_method clear]
  
 
=Code to Implement=
 
=Code to Implement=
 
==Transform==
 
==Transform==
{{RubyToImplement|transform|drawings|Transform|Object|initialize(x,y)<br/>x()<br/>x&#61;()<br/>y()<br/>y&#61;()<br/>render()}}
+
{{RubyToImplement|transform|drawings|Transform|Object|initialize(x,y)<br/>x()<br/>x&#61;()<br/>y()<br/>y&#61;()<br/>render(g)}}
  
 
Add accesors for x and y.
 
Add accesors for x and y.
Line 15: Line 37:
 
Transform's constructor should take x and y parameters and store them in instance variables.
 
Transform's constructor should take x and y parameters and store them in instance variables.
  
It should define a render method which [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glPushMatrix.xml preserves the current model view transformation], [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml translates in the z==0 plane], passes the render_transformed message to itself (a.k.a. invokes a method on itself), and [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glPopMatrix.xml restores the model view transformation].
+
It should define a render method which [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#push_affine_transform-instance_method preserves the current affine transformation], [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#apply_translation-instance_method translates by x and y], passes the untransformed_render message to itself (a.k.a. invokes a method on itself), and [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#pop_affine_transform-instance_method restores the model view transformation].
  
All subclasses must implement a private render_transformed method.
+
All subclasses must implement a private untransformed_render method.
  
 
==Image==
 
==Image==
{{RubyToEvolve|image|drawings|Image|Transform|initialize(path, x: 0, y: 0)|render_transformed()|render()}}
+
{{RubyToEvolve|image|drawings|Image|Transform|initialize(path, x: 0, y: 0)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#Image|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#Image|from Part A]]
Line 26: Line 48:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0 and y: 0 and invoke your superclass with these parameters.
 
Add keyword parameters for x: 0 and y: 0 and invoke your superclass with these parameters.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==ColorTransform==
 
==ColorTransform==
{{RubyToImplement|color_transform|drawings|ColorTransform|Transform|initialize(x,y,color)<br/>color()<br/>color&#61;()<br/>render()}}
+
{{RubyToImplement|color_transform|drawings|ColorTransform|Transform|initialize(x,y,color)<br/>color()<br/>color&#61;()<br/>render(g)}}
  
 
Add an accessor for color.
 
Add an accessor for color.
Line 41: Line 65:
 
ColorTransform's constructor should take x, y, and color parameters.  x and y should be passed to the superclass and color should be stored in an instance variable.
 
ColorTransform's constructor should take x, y, and color parameters.  x and y should be passed to the superclass and color should be stored in an instance variable.
  
NOTE: Override render.  Be sure to [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glColor.xml change the color] (unless it is nil) before invoking your superclass.
+
NOTE: Override render.  Be sure to [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#color=-instance_method change the color] (unless it is nil) on the graphics instance before invoking your superclass.
  
 
NOTE: invoke the [https://ruby-doc.org/core-2.5.3/Object.html#method-i-nil-3F nil?] method to check for nil.
 
NOTE: invoke the [https://ruby-doc.org/core-2.5.3/Object.html#method-i-nil-3F nil?] method to check for nil.
  
 
==Text==
 
==Text==
{{RubyToEvolve|text|drawings|Text|ColorTransform|initialize(text, font,  x: 0, y: 0, color: nil)|render_transformed()|render()}}
+
{{RubyToEvolve|text|drawings|Text|ColorTransform|initialize(text, font,  x: 0, y: 0, color: nil)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#Text|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#Text|from Part A]]
Line 52: Line 76:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'color_transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'color_transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==Ellipse==
 
==Ellipse==
{{RubyToEvolve|ellipse|drawings|Ellipse|ColorTransform|initialize(x_radius, y_radius, x: 0, y: 0, color: nil)|render_transformed()|render()}}
+
{{RubyToEvolve|ellipse|drawings|Ellipse|ColorTransform|initialize(x_radius, y_radius, x: 0, y: 0, color: nil)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#Ellipse|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#Ellipse|from Part A]]
Line 67: Line 93:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'color_transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'color_transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==EquilateralTriangle==
 
==EquilateralTriangle==
{{RubyToEvolve|equilateral_triangle|drawings|EquilateralTriangle|ColorTransform|initialize(half_side_length, x: 0, y: 0, color: nil)|render_transformed()|render()}}
+
{{RubyToEvolve|equilateral_triangle|drawings|EquilateralTriangle|ColorTransform|initialize(half_side_length, x: 0, y: 0, color: nil)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#EquilateralTriangle|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#EquilateralTriangle|from Part A]]
Line 82: Line 110:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'color_transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'color_transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==BezierCurve==
 
==BezierCurve==
{{RubyToEvolve|bezier_curve|drawings|BezierCurve|ColorTransform|initialize(control_points, x: 0, y: 0, color: nil)|render_transformed()|render()}}
+
{{RubyToEvolve|bezier_curve|drawings|BezierCurve|ColorTransform|initialize(control_points, x: 0, y: 0, color: nil)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#B.C3.A9zier_Curve|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#B.C3.A9zier_Curve|from Part A]]
Line 97: Line 127:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'color_transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'color_transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==CircularSegment==
 
==CircularSegment==
{{RubyToEvolve|circular_segment|drawings|CircularSegment|ColorTransform|initialize(x_radius, y_radius, theta_a, theta_z, x: 0, y: 0, color: nil)|render_transformed()|render()}}
+
{{RubyToEvolve|circular_segment|drawings|CircularSegment|ColorTransform|initialize(x_radius, y_radius, theta_a, theta_z, x: 0, y: 0, color: nil)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#CircularSegment|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#CircularSegment|from Part A]]
Line 112: Line 144:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'color_transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'color_transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==Rectangle==
 
==Rectangle==
{{RubyToEvolve|rectangle|drawings|Rectangle|ColorTransform|initialize(half_width, half_height, x: 0, y: 0, color: nil)|render_transformed()|render()}}
+
{{RubyToEvolve|rectangle|drawings|Rectangle|ColorTransform|initialize(half_width, half_height, x: 0, y: 0, color: nil)|untransformed_render(g)|render(g)}}
  
 
You will evolve your code from [[Render_Part_A_Assignment#Rectangle|from Part A]]
 
You will evolve your code from [[Render_Part_A_Assignment#Rectangle|from Part A]]
Line 127: Line 161:
 
be sure to add the following line above your class:
 
be sure to add the following line above your class:
  
<nowiki>require_relative 'color_transform'</nowiki>
+
<syntaxhighlight lang="ruby">
 +
require_relative 'color_transform'
 +
</syntaxhighlight>
  
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
 
Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.
  
NOTE: Be sure to not override render.  Implement the render_transformed method instead.
+
NOTE: Be sure to not override render.  Implement the untransformed_render method instead.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
==CompositeTransform==
 
==CompositeTransform==
{{RubyToImplement|composite_transform|drawings|CompositeTransform|Transform|initialize(x: 0, y: 0)<br/>components<br/>push_component(component)<br/>render_transformed()}}
+
{{RubyToImplement|composite_transform|drawings|CompositeTransform|Transform|initialize(x: 0, y: 0)<br/>components<br/>push_component(component)<br/>untransformed_render(g)}}
 +
 
 +
Instances of CompositeTransform will act like a group of objects.  When it moves all of its child components will move with it.  When it is drawn, each of its child components will be drawn.
  
 
Add a reader for components.
 
Add a reader for components.
Line 142: Line 180:
 
Add a push_component method which accepts a component which will later be rendered.
 
Add a push_component method which accepts a component which will later be rendered.
  
The render_transformed method should render each pushed component.
+
The untransformed_render method should render each pushed component.
  
NOTE: render_transformed() must be private.
+
NOTE: untransformed_render(g) must be private.
  
 
NOTE: sometimes when constructing objects we need to initialize instance variables that are not necessarily passed in as arguments.  this is one of those times.
 
NOTE: sometimes when constructing objects we need to initialize instance variables that are not necessarily passed in as arguments.  this is one of those times.
  
 
==Scene==
 
==Scene==
{{RubyToImplement|scene|drawings|Scene|Object|initialize(background_color: Color::BLACK)<br/>background_color()<br/>background_color&#61;()<br/>components()<br/>push_component(component)<br/>render()}}
+
'''Fall 2023 ALERT: there is an error in scene.rb'''
 +
 
 +
'''The require_relative at the top of the file is missing a ../'''
 +
 
 +
'''Change the require_relative from:'''
 +
 
 +
<s>require_relative '../../../core/ruby/render/core/render'</s>
 +
 
 +
'''to:'''
 +
 
 +
<syntaxhighlight lang="ruby">
 +
require_relative '../../../../core/ruby/render/core/render'
 +
</syntaxhighlight>
 +
 
 +
{{RubyToImplement|scene|drawings|Scene|Object|initialize(background_color: Color::BLACK)<br/>background_color()<br/>background_color&#61;()<br/>components()<br/>push_component(component)<br/>render(g)}}
  
 
Add an accessor for background_color and a reader for components.
 
Add an accessor for background_color and a reader for components.
Line 157: Line 209:
 
Add a push_component method which accepts a component which will later be rendered.
 
Add a push_component method which accepts a component which will later be rendered.
  
The render method should [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glClearColor.xml set the clear color] and [https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glClear.xml clear] the color buffer before rendering each pushed component.
+
The render method should [https://www.cse.wustl.edu/~dennis.cosgrove/courses/cse425s/current/doc/Graphics.html#clear-instance_method clear] the color buffer once before proceeding to render each pushed component.
 
 
<nowiki>glClearColor(@background_color.red, @background_color.green, @background_color.blue, 1.0)
 
glClear(GL_COLOR_BUFFER_BIT)</nowiki>
 
  
 
=Testing Your Solution=
 
=Testing Your Solution=
 
==Unit Test==
 
==Unit Test==
{{RubyUnitTest|*|drawings/preliminary/part_b}}
+
{{RubyUnitTest|*|drawings/core/relatively_fast/part_b}}
 +
 
 +
{{RubyUnitTest|*|drawings/core/relatively_slow/part_b}}
  
{{RubyUnitTest|*|drawings/more_comprehensive/part_b}}
+
===Backwards Compatibility===
 +
{{RubyUnitTest|*|drawings/core/relatively_fast/part_a}}
  
 
==Visual Comparison==
 
==Visual Comparison==
{{RubyToRun|part_b_snapshots_web_page_generator|drawings_snapshots|main}}
+
{{RubyToRun|part_b_components_snapshots_web_page_generator|drawings/core/snapshots|test}}
  
==Somewhat Outdated Testing Demo==
+
{{RubyToRun|part_b_composites_snapshots_web_page_generator|drawings/core/snapshots|test}}
<youtube>utK0TewIRjc</youtube>
 

Latest revision as of 04:22, 1 December 2023

Fall 2023 ALERT: there is an error in scene.rb

The require_relative at the top of the file is missing a ../

Change the require_relative from:

require_relative '../../../core/ruby/render/core/render'

to:

require_relative '../../../../core/ruby/render/core/render'

In this assignment we will evolve our code from Render (Part A) to leverage class hierarchies.

Diagram part b.png

Continue editing files in the drawings/core directory.

In this exercise, we will have parameters for which explicitly passed arguments are not required (for convenience and backwards compatibility). We will prefer keyword arguments over optional arguments.

Code To Use

Graphics

push_affine_transform
pop_affine_transform
apply_translation
color=
clear

Code to Implement

Transform

file: src/main/ruby/drawings/transform.rb Ruby logo.svg
class: Transform
superclass: Object
methods: initialize(x,y)
x()
x=()
y()
y=()
render(g)

Add accesors for x and y.

Transform's constructor should take x and y parameters and store them in instance variables.

It should define a render method which preserves the current affine transformation, translates by x and y, passes the untransformed_render message to itself (a.k.a. invokes a method on itself), and restores the model view transformation.

All subclasses must implement a private untransformed_render method.

Image

file: src/main/ruby/drawings/image.rb Ruby logo.svg
class: Image
superclass: Transform
methods to evolve: initialize(path, x: 0, y: 0)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'transform'

Add keyword parameters for x: 0 and y: 0 and invoke your superclass with these parameters.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

ColorTransform

file: src/main/ruby/drawings/color_transform.rb Ruby logo.svg
class: ColorTransform
superclass: Transform
methods: initialize(x,y,color)
color()
color=()
render(g)

Add an accessor for color.

ColorTransform's constructor should take x, y, and color parameters. x and y should be passed to the superclass and color should be stored in an instance variable.

NOTE: Override render. Be sure to change the color (unless it is nil) on the graphics instance before invoking your superclass.

NOTE: invoke the nil? method to check for nil.

Text

file: src/main/ruby/drawings/text.rb Ruby logo.svg
class: Text
superclass: ColorTransform
methods to evolve: initialize(text, font, x: 0, y: 0, color: nil)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'color_transform'

Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

Ellipse

file: src/main/ruby/drawings/ellipse.rb Ruby logo.svg
class: Ellipse
superclass: ColorTransform
methods to evolve: initialize(x_radius, y_radius, x: 0, y: 0, color: nil)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'color_transform'

Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

EquilateralTriangle

file: src/main/ruby/drawings/equilateral_triangle.rb Ruby logo.svg
class: EquilateralTriangle
superclass: ColorTransform
methods to evolve: initialize(half_side_length, x: 0, y: 0, color: nil)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'color_transform'

Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

BezierCurve

file: src/main/ruby/drawings/bezier_curve.rb Ruby logo.svg
class: BezierCurve
superclass: ColorTransform
methods to evolve: initialize(control_points, x: 0, y: 0, color: nil)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'color_transform'

Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

CircularSegment

file: src/main/ruby/drawings/circular_segment.rb Ruby logo.svg
class: CircularSegment
superclass: ColorTransform
methods to evolve: initialize(x_radius, y_radius, theta_a, theta_z, x: 0, y: 0, color: nil)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'color_transform'

Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

Rectangle

file: src/main/ruby/drawings/rectangle.rb Ruby logo.svg
class: Rectangle
superclass: ColorTransform
methods to evolve: initialize(half_width, half_height, x: 0, y: 0, color: nil)
methods to add: untransformed_render(g)
methods to remove: render(g)

You will evolve your code from from Part A

be sure to add the following line above your class:

require_relative 'color_transform'

Add keyword parameters for x: 0, y: 0, and color: nil to the constructor and pass them to the superclass.

NOTE: Be sure to not override render. Implement the untransformed_render method instead.

NOTE: untransformed_render(g) must be private.

CompositeTransform

file: src/main/ruby/drawings/composite_transform.rb Ruby logo.svg
class: CompositeTransform
superclass: Transform
methods: initialize(x: 0, y: 0)
components
push_component(component)
untransformed_render(g)

Instances of CompositeTransform will act like a group of objects. When it moves all of its child components will move with it. When it is drawn, each of its child components will be drawn.

Add a reader for components.

Add a push_component method which accepts a component which will later be rendered.

The untransformed_render method should render each pushed component.

NOTE: untransformed_render(g) must be private.

NOTE: sometimes when constructing objects we need to initialize instance variables that are not necessarily passed in as arguments. this is one of those times.

Scene

Fall 2023 ALERT: there is an error in scene.rb

The require_relative at the top of the file is missing a ../

Change the require_relative from:

require_relative '../../../core/ruby/render/core/render'

to:

require_relative '../../../../core/ruby/render/core/render'
file: src/main/ruby/drawings/scene.rb Ruby logo.svg
class: Scene
superclass: Object
methods: initialize(background_color: Color::BLACK)
background_color()
background_color=()
components()
push_component(component)
render(g)

Add an accessor for background_color and a reader for components.

Scene's constructor should take a keyword parameter background_color: Color.new(0,0,0) and store it in an instance variable.

Add a push_component method which accepts a component which will later be rendered.

The render method should clear the color buffer once before proceeding to render each pushed component.

Testing Your Solution

Unit Test

file: src/test/ruby/drawings/core/relatively_fast/part_b/*.rb Ruby logo.svg UnitTest

note: ensure that you have removed all printing to receive credit for any assignment.

file: src/test/ruby/drawings/core/relatively_slow/part_b/*.rb Ruby logo.svg UnitTest

note: ensure that you have removed all printing to receive credit for any assignment.

Backwards Compatibility

file: src/test/ruby/drawings/core/relatively_fast/part_a/*.rb Ruby logo.svg UnitTest

note: ensure that you have removed all printing to receive credit for any assignment.

Visual Comparison

file to run: src/test/ruby/drawings/core/snapshots/part_b_components_snapshots_web_page_generator.rb Ruby logo.svg
file to run: src/test/ruby/drawings/core/snapshots/part_b_composites_snapshots_web_page_generator.rb Ruby logo.svg