From 3bbc78702517f572c2a92967d2a89a68c647f0e1 Mon Sep 17 00:00:00 2001 From: Andy Meneely Date: Fri, 22 May 2015 06:12:48 -0400 Subject: [PATCH] Add polygon method to dsl Testing and documentation too. Closes #67 --- CHANGELOG.md | 1 + lib/squib/api/shapes.rb | 25 ++++++++++++++++++++++++ lib/squib/graphics/shapes.rb | 23 +++++++++++++++++++++- samples/draw_shapes.rb | 5 ++++- spec/data/samples/draw_shapes.rb.txt | 21 +++++++++++++++++++- spec/samples/expected/shape_00.png | Bin 28058 -> 30290 bytes spec/samples/samples_regression_spec.rb | 2 +- spec/spec_helper.rb | 2 +- 8 files changed, 74 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc6bb66..184b43d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Features: * Added `hand` method that draws cards around a circle. See hand.rb samples (#64) * Added an `ellipse` method to (you guessed it) draw ellipses. See the draw_shapes.rb sample (#66) * Added a `star` method to (you guessed it) draw stars. See the draw_shapes.rb sample (#72) +* Added a `polygon` method to (you guessed it) draw polygons. See the draw_shapes.rb sample (#67) * Upgraded roo (Excel parsing) to 2.0.0. Nothing major for Squib users, just keeping up with the times. Bugs: diff --git a/lib/squib/api/shapes.rb b/lib/squib/api/shapes.rb index bb47fa5..4c2d45b 100644 --- a/lib/squib/api/shapes.rb +++ b/lib/squib/api/shapes.rb @@ -199,5 +199,30 @@ module Squib end end + # Draw a regular polygon at the given x,y + # @example + # polygon x: 10, y: 10, n: 5, angle: Math::PI / 4, radius: 50, + # fill_color: :green, stroke_color: :burgundy, :stroke_width: 3 + # + # @option opts range [Enumerable, :all] (:all) the range of cards over which this will be rendered. See {file:README.md#Specifying_Ranges Specifying Ranges} + # @option opts x [Fixnum] (0) the x-coordinate of the center. Supports Unit Conversion, see {file:README.md#Units Units}. + # @option opts y [Fixnum] (0) the y-coordinate of the center. Supports Unit Conversion, see {file:README.md#Units Units}. + # @option opts n [Integer] (5) the number of points on the star + # @option opts angle [Fixnum] (0) the angle at which to rotate + # @option opts stroke_color [String] (:black) the color with which to stroke the line. See {file:README.md#Specifying_Colors___Gradients Specifying Colors & Gradients}. + # @option opts stroke_width [Decimal] (2.0) the width of the outside stroke. Supports Unit Conversion, see {file:README.md#Units Units}. + # @option opts fill_color [String] ('#0000') the color with which to fill the triangle. See {file:README.md#Specifying_Colors___Gradients Specifying Colors & Gradients} + # @option opts layout [String, Symbol] (nil) entry in the layout to use as defaults for this command. See {file:README.md#Custom_Layouts Custom Layouts} + # @return [nil] intended to be void + # @api public + def polygon(opts = {}) + opts = needs(opts, [:range, :x, :y, :n, :circle_radius, :angle, :layout, :fill_color, :stroke_color, :stroke_width]) + opts[:range].each do |i| + @cards[i].polygon(opts[:x][i], opts[:y][i], opts[:n][i], opts[:angle][i], opts[:radius][i], + opts[:fill_color][i], opts[:stroke_color][i], + opts[:stroke_width][i]) + end + end + end end diff --git a/lib/squib/graphics/shapes.rb b/lib/squib/graphics/shapes.rb index d95f167..91d3bb4 100644 --- a/lib/squib/graphics/shapes.rb +++ b/lib/squib/graphics/shapes.rb @@ -109,13 +109,34 @@ module Squib cc.translate(x, y) cc.rotate(angle) cc.translate(-x, -y) - cc.move_to(x + outer_radius, y) #i = 0, so + cc.move_to(x + outer_radius, y) #i = 0, so cos(0)=1 and sin(0)=0 theta = Math::PI / n.to_f # i.e. (2*pi) / (2*n) 0.upto(2 * n) do |i| radius = i.even? ? outer_radius : inner_radius cc.line_to(x + radius * Math::cos(i * theta), y + radius * Math::sin(i * theta)) end + cc.close_path + cc.set_source_squibcolor(stroke_color) + cc.set_line_width(stroke_width) + cc.fill_preserve + cc.set_source_squibcolor(fill_color) + cc.stroke + end + end + + def polygon(x, y, n, angle, radius, fill_color, stroke_color, stroke_width) + use_cairo do |cc| + cc.translate(x, y) + cc.rotate(angle) + cc.translate(-x, -y) + cc.move_to(x + radius, y) # i = 0, so cos(0)=1 and sin(0)=0 + theta = (2 * Math::PI) / n.to_f + 0.upto(n) do |i| + cc.line_to(x + radius * Math::cos(i * theta), + y + radius * Math::sin(i * theta)) + end + cc.close_path cc.set_source_squibcolor(stroke_color) cc.set_line_width(stroke_width) cc.fill_preserve diff --git a/samples/draw_shapes.rb b/samples/draw_shapes.rb index 4f01181..c64c199 100644 --- a/samples/draw_shapes.rb +++ b/samples/draw_shapes.rb @@ -26,7 +26,10 @@ Squib::Deck.new do fill_color: :burgundy star x: 300, y: 1000, n: 5, inner_radius: 10, outer_radius: 25, - fill_color: :burgundy, stroke_color: :cyan, stroke_width: 1 + fill_color: :burgundy, stroke_color: :cyan, stroke_width: 3 + + polygon x: 500, y: 1000, n: 5, radius: 25, angle: Math::PI / 2, + fill_color: :burgundy, stroke_color: :cyan, stroke_width: 2 save_png prefix: 'shape_' end diff --git a/spec/data/samples/draw_shapes.rb.txt b/spec/data/samples/draw_shapes.rb.txt index 99b3027..963508c 100644 --- a/spec/data/samples/draw_shapes.rb.txt +++ b/spec/data/samples/draw_shapes.rb.txt @@ -77,8 +77,27 @@ cairo: line_to([296.90983005625054, 990.4894348370485]) cairo: line_to([307.7254248593737, 976.2235870926212]) cairo: line_to([308.09016994374946, 994.1221474770753]) cairo: line_to([325.0, 1000.0]) +cairo: close_path([]) cairo: set_source_color([:cyan]) -cairo: set_line_width([1]) +cairo: set_line_width([3]) +cairo: fill_preserve([]) +cairo: set_source_color([:burgundy]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: translate([500, 1000]) +cairo: rotate([1.5707963267948966]) +cairo: translate([-500, -1000]) +cairo: move_to([525, 1000]) +cairo: line_to([525.0, 1000.0]) +cairo: line_to([507.7254248593737, 1023.7764129073788]) +cairo: line_to([479.7745751406263, 1014.6946313073119]) +cairo: line_to([479.7745751406263, 985.3053686926881]) +cairo: line_to([507.7254248593737, 976.2235870926212]) +cairo: line_to([525.0, 1000.0]) +cairo: close_path([]) +cairo: set_source_color([:cyan]) +cairo: set_line_width([2]) cairo: fill_preserve([]) cairo: set_source_color([:burgundy]) cairo: stroke([]) diff --git a/spec/samples/expected/shape_00.png b/spec/samples/expected/shape_00.png index a8cdaf716cfc28e83ad453a61d0256cda8a1f29e..5e9d5ca6bb00bd39bf9e1101a6da5c12f8a0cc49 100644 GIT binary patch delta 13063 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%0ACj5DJ3miW57OWsD+MFNURZcPXicOC@Vq(4u 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

b7I|rbZ=btu`Yy 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