Class: HexaPDF::Content::GraphicObject::Arc
- Inherits:
-
Object
- Object
- HexaPDF::Content::GraphicObject::Arc
- Includes:
- Utils::MathHelpers
- Defined in:
- lib/hexapdf/content/graphic_object/arc.rb
Overview
This class describes an elliptical arc in center parameterization that is approximated using Bezier curves. It can be used to draw circles, circular arcs, ellipses and elliptical arcs, all either in clockwise or counterclockwise direction and optionally inclined in respect to the x-axis.
This graphic object is registered under the :arc key for use with the HexaPDF::Content::Canvas class.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 100, b: 50, end_angle: 150)
canvas.draw(arc).stroke
See: ELL - spaceroots.org/documents/ellipse/elliptical-arc.pdf
Instance Attribute Summary collapse
-
#a ⇒ Object
readonly
Length of semi-major axis which (without altering the #inclination) is parallel to the x-axis.
-
#b ⇒ Object
readonly
Length of semi-minor axis which (without altering the #inclination) is parallel to the y-axis.
-
#clockwise ⇒ Object
readonly
Direction of arc - if
true
in clockwise direction, else in counterclockwise direction. -
#cx ⇒ Object
readonly
x-coordinate of center point.
-
#cy ⇒ Object
readonly
y-coordinate of center point.
-
#end_angle ⇒ Object
readonly
End angle of the arc in degrees.
-
#inclination ⇒ Object
readonly
Inclination in degrees of the semi-major axis with respect to the x-axis.
-
#max_curves ⇒ Object
The maximal number of curves used for approximating a complete ellipse.
-
#start_angle ⇒ Object
readonly
Start angle of the arc in degrees.
Class Method Summary collapse
-
.configure(**kwargs) ⇒ Object
Creates and configures a new elliptical arc object.
Instance Method Summary collapse
-
#configure(cx: nil, cy: nil, a: nil, b: nil, start_angle: nil, end_angle: nil, inclination: nil, clockwise: nil) ⇒ Object
Configures the arc with.
-
#curves ⇒ Object
Returns an array of arrays that contain the points for the Bezier curves which are used for approximating the elliptical arc between #start_point and #end_point.
-
#draw(canvas, move_to_start: true) ⇒ Object
Draws the arc on the given Canvas.
-
#end_point ⇒ Object
Returns the end point of the elliptical arc.
-
#initialize ⇒ Arc
constructor
Creates an elliptical arc with default values (a counterclockwise unit circle at the origin).
-
#point_at(angle) ⇒ Object
Returns the point at
angle
degrees on the ellipse. -
#start_point ⇒ Object
Returns the start point of the elliptical arc.
Methods included from Utils::MathHelpers
Constructor Details
#initialize ⇒ Arc
Creates an elliptical arc with default values (a counterclockwise unit circle at the origin).
Examples:
#>pdf-center
canvas.draw(:arc).stroke
177 178 179 180 181 182 183 184 185 186 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 177 def initialize @max_curves = nil @cx = @cy = 0 @a = @b = 1 @start_angle = 0 @end_angle = 360 @inclination = 0 @clockwise = false calculate_cached_values end |
Instance Attribute Details
#a ⇒ Object (readonly)
Length of semi-major axis which (without altering the #inclination) is parallel to the x-axis
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc).stroke
canvas.stroke_color("red").draw(arc, a: 60).stroke
115 116 117 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 115 def a @a end |
#b ⇒ Object (readonly)
Length of semi-minor axis which (without altering the #inclination) is parallel to the y-axis
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc).stroke
canvas.stroke_color("red").draw(arc, b: 60).stroke
126 127 128 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 126 def b @b end |
#clockwise ⇒ Object (readonly)
Direction of arc - if true
in clockwise direction, else in counterclockwise direction
This is needed when filling paths using the nonzero winding number rule to achieve different effects.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 40, b: 40)
canvas.draw(arc, cx: -50).draw(arc, cx: 50).
draw(arc, cx: -50, b: 80).
draw(arc, cx: 50, b: 80, clockwise: true).
fill(:nonzero)
168 169 170 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 168 def clockwise @clockwise end |
#cx ⇒ Object (readonly)
x-coordinate of center point
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 20)
canvas.draw(arc).stroke
canvas.stroke_color("red").draw(arc, cx: -50).stroke
94 95 96 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 94 def cx @cx end |
#cy ⇒ Object (readonly)
y-coordinate of center point
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 20)
canvas.draw(arc).stroke
canvas.stroke_color("red").draw(arc, cy: 50).stroke
104 105 106 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 104 def cy @cy end |
#end_angle ⇒ Object (readonly)
End angle of the arc in degrees
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc, end_angle: 160).stroke
144 145 146 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 144 def end_angle @end_angle end |
#inclination ⇒ Object (readonly)
Inclination in degrees of the semi-major axis with respect to the x-axis
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 60, b: 30)
canvas.draw(arc, inclination: 45).stroke
153 154 155 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 153 def inclination @inclination end |
#max_curves ⇒ Object
The maximal number of curves used for approximating a complete ellipse.
The higher the value the better the approximation will be but it will also take longer to compute. The value should not be lower than 4. Default value is 6 which already provides a good approximation.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, cx: -50, a: 40, b: 40)
arc.max_curves = 2
canvas.draw(arc)
arc.max_curves = 10
canvas.draw(arc, cx: 50)
canvas.stroke
84 85 86 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 84 def max_curves @max_curves end |
#start_angle ⇒ Object (readonly)
Start angle of the arc in degrees
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc, start_angle: 45).stroke
135 136 137 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 135 def start_angle @start_angle end |
Class Method Details
.configure(**kwargs) ⇒ Object
Creates and configures a new elliptical arc object.
See #configure for the allowed keyword arguments.
65 66 67 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 65 def self.configure(**kwargs) new.configure(**kwargs) end |
Instance Method Details
#configure(cx: nil, cy: nil, a: nil, b: nil, start_angle: nil, end_angle: nil, inclination: nil, clockwise: nil) ⇒ Object
Configures the arc with
-
center point (
cx
,cy
), -
semi-major axis
a
, -
semi-minor axis
b
, -
start angle of
start_angle
degrees, -
end angle of
end_angle
degrees and -
an inclination in respect to the x-axis of
inclination
degrees.
The clockwise
argument determines if the arc is drawn in the counterclockwise direction (false
) or in the clockwise direction (true
).
Any arguments not specified are not modified and retain their old value, see #initialize for the inital values.
Returns self.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 204 def configure(cx: nil, cy: nil, a: nil, b: nil, start_angle: nil, end_angle: nil, inclination: nil, clockwise: nil) @cx = cx if cx @cy = cy if cy @a = a.abs if a @b = b.abs if b if @a == 0 || @b == 0 raise HexaPDF::Error, "Semi-major and semi-minor axes must be greater than zero" end @start_angle = start_angle if start_angle @end_angle = end_angle if end_angle @inclination = inclination if inclination @clockwise = clockwise unless clockwise.nil? calculate_cached_values self end |
#curves ⇒ Object
Returns an array of arrays that contain the points for the Bezier curves which are used for approximating the elliptical arc between #start_point and #end_point.
One subarray consists of
[end_point_x, end_point_y, p1: control_point_1, p2: control_point_2]
The first start point is the one returned by #start_point, the other start points are the end points of the curve before.
The format of the subarray is chosen so that it can be fed to the Canvas#curve_to method by using array splatting.
See: ELL s3.4.1 (especially the last box on page 18)
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 280 def curves result = [] # Number of curves to use, maximal segment angle is 2*PI/max_curves max_curves = @max_curves || 6 n = [max_curves, ((@end_eta - @start_eta).abs / (2 * Math::PI / max_curves)).ceil].min d_eta = (@end_eta - @start_eta) / n alpha = Math.sin(d_eta) * (Math.sqrt(4 + 3 * Math.tan(d_eta / 2)**2) - 1) / 3 eta2 = @start_eta p2x, p2y = evaluate(eta2) p2x_prime, p2y_prime = derivative_evaluate(eta2) 1.upto(n) do p1x = p2x p1y = p2y p1x_prime = p2x_prime p1y_prime = p2y_prime eta2 += d_eta p2x, p2y = evaluate(eta2) p2x_prime, p2y_prime = derivative_evaluate(eta2) result << [p2x, p2y, {p1: [p1x + alpha * p1x_prime, p1y + alpha * p1y_prime], p2: [p2x - alpha * p2x_prime, p2y - alpha * p2y_prime]}] end result end |
#draw(canvas, move_to_start: true) ⇒ Object
Draws the arc on the given Canvas.
If the argument move_to_start
is true
, a Canvas#move_to operation is executed to move the current point to the start point of the arc. Otherwise it is assumed that the current point already coincides with the start point
The #max_curves value, if not already changed, is set to the value of the configuration option ‘graphic_object.arc.max_curves’ before drawing.
260 261 262 263 264 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 260 def draw(canvas, move_to_start: true) @max_curves ||= canvas.context.document.config['graphic_object.arc.max_curves'] canvas.move_to(*start_point) if move_to_start curves.each {|x, y, hash| canvas.curve_to(x, y, **hash) } end |
#end_point ⇒ Object
Returns the end point of the elliptical arc.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 40, b: 30, end_angle: 245)
canvas.draw(arc).stroke
canvas.fill_color("red").circle(*arc.end_point, 2).fill
241 242 243 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 241 def end_point evaluate(@end_eta) end |
#point_at(angle) ⇒ Object
Returns the point at angle
degrees on the ellipse.
Note that the point may not lie on the arc itself!
248 249 250 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 248 def point_at(angle) evaluate(angle_to_param(angle)) end |
#start_point ⇒ Object
Returns the start point of the elliptical arc.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 40, b: 30, start_angle: 60)
canvas.draw(arc).stroke
canvas.fill_color("red").circle(*arc.start_point, 2).fill
229 230 231 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 229 def start_point evaluate(@start_eta) end |