class HexaPDF::Content::GraphicObject::EndpointArc

web.archive.org/web/20160310153722/https://www.w3.org/TR/SVG/implnote.html).
version of about 2016, see
See: Arc, ARC - www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes (in the
canvas.move_to(0, 0).draw(arc).stroke
arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 10)
#>pdf-center
Examples:
HexaPDF::Content::Canvas class.
This graphic object is registered under the :endpoint_arc key for use with the
use-case the path itself still has to be, for example, stroked.
Note that only the path of the arc itself is added to the canvas. So depending on the
with Arc.
the scenes the endpoint parameterization is turned into a center parameterization and drawn
generate an arc from the current point to a given point, similar to Canvas#line_to. Behind
This class describes an elliptical arc in endpoint parameterization. It allows one to

def self.configure(**kwargs)

See #configure for the allowed keyword arguments.

Creates and configures a new endpoint arc object.
def self.configure(**kwargs)
  new.configure(**kwargs)
end

def compute_angle_to_x_axis(vx, vy)

Computes the angle in degrees between the x-axis and the vector.
def compute_angle_to_x_axis(vx, vy)
  (vy < 0 ? -1 : 1) * rad_to_deg(Math.acos(vx / Math.sqrt(vx**2 + vy**2)))
end

def compute_arc_values(x1, y1)

See: ARC F.6.5, F.6.6

The argument (x1, y1) is the starting point.

Compute the center parameterization from the endpoint parameterization.
def compute_arc_values(x1, y1)
  x2 = @x
  y2 = @y
  rx = @a
  ry = @b
  theta = deg_to_rad(@inclination)
  cos_theta = Math.cos(theta)
  sin_theta = Math.sin(theta)
  # F.6.5.1
  x1p = (x1 - x2) / 2.0 * cos_theta + (y1 - y2) / 2.0 * sin_theta
  y1p = (x1 - x2) / 2.0 * -sin_theta + (y1 - y2) / 2.0 * cos_theta
  x1ps = x1p**2
  y1ps = y1p**2
  rxs = rx**2
  rys = ry**2
  # F.6.6.2
  l = x1ps / rxs + y1ps / rys
  if l > 1
    rx *= Math.sqrt(l)
    ry *= Math.sqrt(l)
    rxs = rx**2
    rys = ry**2
  end
  # F.6.5.2
  sqrt = (rxs * rys - rxs * y1ps - rys * x1ps) / (rxs * y1ps + rys * x1ps)
  sqrt = 0 if sqrt.abs < Utils::EPSILON
  sqrt = Math.sqrt(sqrt)
  sqrt *= -1 unless @large_arc == @clockwise
  cxp = sqrt * rx * y1p / ry
  cyp = - sqrt * ry * x1p / rx
  # F.6.5.3
  cx = cos_theta * cxp - sin_theta * cyp + (x1 + x2) / 2.0
  cy = sin_theta * cxp + cos_theta * cyp + (y1 + y2) / 2.0
  # F.6.5.5
  start_angle = compute_angle_to_x_axis((x1p - cxp), (y1p - cyp)) % 360
  # F.6.5.6 (modified bc we just need the end angle)
  end_angle = compute_angle_to_x_axis((-x1p - cxp), (-y1p - cyp)) % 360
  {cx: cx, cy: cy, a: rx, b: ry, start_angle: start_angle, end_angle: end_angle,
   inclination: @inclination, clockwise: @clockwise, max_curves: @max_curves}
end

def configure(x: nil, y: nil, a: nil, b: nil, inclination: nil, large_arc: nil,

canvas.move_to(0, 0).draw(arc).stroke
arc.configure(x: 50, y: 20, a: 30, b: 10)
arc = canvas.graphic_object(:endpoint_arc)
#>pdf-center

Examples:

Returns self.

for the inital values.
Any arguments not specified are not modified and retain their old value, see #initialize

(+false+) or in the clockwise direction (+true+).
The +clockwise+ option determines if the arc is drawn in the counterclockwise direction

180 degrees, is used (+true+) or the small arc (+false+).
The +large_arc+ option determines whether the large arc, i.e. the one spanning more than

* the given maximum number of approximation curves.
* the given clockwise flag and.
* the given large_arc flag,
* an inclination in respect to the x-axis of +inclination+ degrees,
* semi-minor axis +b+,
* semi-major axis +a+,
* endpoint (+x+, +y+),

Configures the endpoint arc with
def configure(x: nil, y: nil, a: nil, b: nil, inclination: nil, large_arc: nil,
              clockwise: nil, max_curves: nil)
  @x = x if x
  @y = y if y
  @a = a.abs if a
  @b = b.abs if b
  @inclination = inclination % 360 if inclination
  @large_arc = large_arc unless large_arc.nil?
  @clockwise = clockwise unless clockwise.nil?
  @max_curves = max_curves if max_curves
  self
end

def draw(canvas)

canvas.stroke
arc.draw(canvas)
canvas.move_to(-20, -20)
arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 10)
#>pdf-center

Examples:

easier to use Canvas#draw.
Since this method doesn't have any other arguments than +canvas+, it is usually better and

Draws the arc on the given Canvas.
def draw(canvas)
  x1, y1 = *canvas.current_point
  # ARC F.6.2 - nothing to do if endpoint is equal to current point
  return if float_equal(x1, @x) && float_equal(y1, @y)
  if @a == 0 || @b == 0
    # ARC F.6.2, F.6.6 - just use a line if it is not really an arc
    canvas.line_to(@x, @y)
  else
    values = compute_arc_values(x1, y1)
    arc = canvas.graphic_object(:arc, **values)
    arc.draw(canvas, move_to_start: false)
  end
end

def initialize

canvas.move_to(30, 30).draw(:endpoint_arc).stroke
#>pdf-center

Examples:

large_arc=true, clockwise=false (a line to the origin).
Creates an endpoint arc with default values x=0, y=0, a=0, b=0, inclination=0,
def initialize
  @x = @y = 0
  @a = @b = 0
  @inclination = 0
  @large_arc = true
  @clockwise = false
  @max_curves = nil
end