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.
Note that only the path of the arc itself is added to the canvas. So depending on the use-case the path itself still has to be, for example, stroked.
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, defaults to 1.
-
#b ⇒ Object
readonly
Length of semi-minor axis which (without altering the #inclination) is parallel to the y-axis, defaults to 1.
-
#clockwise ⇒ Object
readonly
Direction of arc - if
true
in clockwise direction, else in counterclockwise direction (the default). -
#cx ⇒ Object
readonly
x-coordinate of center point, defaults to 0.
-
#cy ⇒ Object
readonly
y-coordinate of center point, defaults to 0.
-
#end_angle ⇒ Object
readonly
End angle of the arc in degrees, defaults to 0.
-
#inclination ⇒ Object
readonly
Inclination in degrees of the semi-major axis with respect to the x-axis, defaults to 0.
-
#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, defaults to 0.
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, max_curves: 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
180 181 182 183 184 185 186 187 188 189 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 180 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, defaults to 1.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc).stroke
canvas.stroke_color("hp-blue").draw(arc, a: 60).stroke
116 117 118 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 116 def a @a end |
#b ⇒ Object (readonly)
Length of semi-minor axis which (without altering the #inclination) is parallel to the y-axis, defaults to 1.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc).stroke
canvas.stroke_color("hp-blue").draw(arc, b: 60).stroke
127 128 129 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 127 def b @b end |
#clockwise ⇒ Object (readonly)
Direction of arc - if true
in clockwise direction, else in counterclockwise direction (the default).
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.fill_color("hp-blue").
draw(arc, cx: -50).draw(arc, cx: 50).
draw(arc, cx: -50, b: 80).
draw(arc, cx: 50, b: 80, clockwise: true).
fill(:nonzero)
171 172 173 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 171 def clockwise @clockwise end |
#cx ⇒ Object (readonly)
x-coordinate of center point, defaults to 0.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 20)
canvas.draw(arc).stroke
canvas.stroke_color("hp-blue").draw(arc, cx: 50).stroke
95 96 97 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 95 def cx @cx end |
#cy ⇒ Object (readonly)
y-coordinate of center point, defaults to 0.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 20)
canvas.draw(arc).stroke
canvas.stroke_color("hp-blue").draw(arc, cy: 50).stroke
105 106 107 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 105 def cy @cy end |
#end_angle ⇒ Object (readonly)
End angle of the arc in degrees, defaults to 0.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc, end_angle: 160).stroke
145 146 147 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 145 def end_angle @end_angle end |
#inclination ⇒ Object (readonly)
Inclination in degrees of the semi-major axis with respect to the x-axis, defaults to 0.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 60, b: 30)
canvas.draw(arc, inclination: 45).stroke
154 155 156 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 154 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, max_curves: 2)
canvas.draw(arc)
canvas.draw(arc, cx: 50, max_curves: 10)
canvas.stroke
85 86 87 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 85 def max_curves @max_curves end |
#start_angle ⇒ Object (readonly)
Start angle of the arc in degrees, defaults to 0.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 30, b: 30)
canvas.draw(arc, start_angle: 110).stroke
136 137 138 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 136 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.
68 69 70 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 68 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, max_curves: 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, -
as well as the maximal number of curves
max_curves
used for approximation.
The clockwise
argument determines if the arc is drawn in the counterclockwise direction (false
) or in the clockwise direction (true
).
For the meaning of max_curves
see the description of #max_curves.
Any arguments not specified are not modified and retain their old value, see #initialize for the inital values.
Returns self.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc)
arc.configure(cx: 50, a: 40, b: 20, inclination: 10)
canvas.draw(arc).stroke
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 217 def configure(cx: nil, cy: nil, a: nil, b: nil, start_angle: nil, end_angle: nil, inclination: nil, clockwise: nil, max_curves: 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? @max_curves = max_curves if max_curves 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)
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 313 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. This functionality is used, for example, by the SolidArc implementation.
The #max_curves value, if not already changed, is set to the value of the configuration option ‘graphic_object.arc.max_curves’ before drawing.
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 40, b: 30)
canvas.stroke_color("hp-blue").move_to(-50, 0)
arc.draw(canvas, move_to_start: false)
canvas.stroke
293 294 295 296 297 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 293 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("hp-blue").circle(*arc.end_point, 2).fill
255 256 257 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 255 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!
Examples:
#>pdf-center
arc = canvas.graphic_object(:arc, a: 40, b: 30, end_angle: 245)
canvas.draw(arc).stroke
canvas.fill_color("hp-blue").
circle(*arc.point_at(150), 2).
circle(*arc.point_at(290), 2).
fill
272 273 274 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 272 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("hp-blue").circle(*arc.start_point, 2).fill
243 244 245 |
# File 'lib/hexapdf/content/graphic_object/arc.rb', line 243 def start_point evaluate(@start_eta) end |