# -*- encoding: utf-8; frozen_string_literal: true -*-
#
#--
# This file is part of HexaPDF.
#
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
# Copyright (C) 2014-2019 Thomas Leitner
#
# HexaPDF is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License version 3 as
# published by the Free Software Foundation with the addition of the
# following permission added to Section 15 as permitted in Section 7(a):
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
# INFRINGEMENT OF THIRD PARTY RIGHTS.
#
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with HexaPDF. If not, see .
#
# The interactive user interfaces in modified source and object code
# versions of HexaPDF must display Appropriate Legal Notices, as required
# under Section 5 of the GNU Affero General Public License version 3.
#
# In accordance with Section 7(b) of the GNU Affero General Public
# License, a covered work must retain the producer line in every PDF that
# is created or manipulated using HexaPDF.
#
# If the GNU Affero General Public License doesn't fit your need,
# commercial licenses are available at .
#++
module HexaPDF
module Content
module GraphicObject
# This graphic object represents a solid elliptical arc, i.e. an arc that has an inner and
# an outer set of a/b values.
#
# Thus it can be used to create
#
# * an (elliptical) disk (when the inner a/b are zero and the difference between start and
# end angles is greater than or equal to 360),
#
# * an (elliptical) sector (when the inner a/b are zero and the difference between start
# and end angles is less than 360),
#
# * an (elliptical) annulus (when the inner a/b are nonzero and the difference between
# start and end angles is greater than or equal to 360), and
#
# * an (elliptical) annular sector (when the inner a/b are nonzero and the difference
# between start and end angles is less than 360)
#
# See: Arc
class SolidArc
# Creates and configures a new solid arc object.
#
# See #configure for the allowed keyword arguments.
def self.configure(**kwargs)
new.configure(kwargs)
end
# x-coordinate of center point
attr_reader :cx
# y-coordinate of center point
attr_reader :cy
# Length of inner semi-major axis
attr_reader :inner_a
# Length of inner semi-minor axis
attr_reader :inner_b
# Length of outer semi-major axis
attr_reader :outer_a
# Length of outer semi-minor axis
attr_reader :outer_b
# Start angle in degrees
attr_reader :start_angle
# End angle in degrees
attr_reader :end_angle
# Inclination in degrees of semi-major axis in respect to x-axis
attr_reader :inclination
# Creates a solid arc with default values (a unit disk at the origin).
def initialize
@cx = @cy = 0
@inner_a = @inner_b = 0
@outer_a = @outer_b = 1
@start_angle = 0
@end_angle = 0
@inclination = 0
end
# Configures the solid arc with
#
# * center point (+cx+, +cy+),
# * inner semi-major axis +inner_a+,
# * inner semi-minor axis +inner_b+,
# * outer semi-major axis +outer_a+,
# * outer semi-minor axis +outer_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.
#
# Any arguments not specified are not modified and retain their old value, see #initialize
# for the inital values.
#
# Returns self.
def configure(cx: nil, cy: nil, inner_a: nil, inner_b: nil, outer_a: nil, outer_b: nil,
start_angle: nil, end_angle: nil, inclination: nil)
@cx = cx if cx
@cy = cy if cy
@inner_a = inner_a.abs if inner_a
@inner_b = inner_b.abs if inner_b
@outer_a = outer_a.abs if outer_a
@outer_b = outer_b.abs if outer_b
@start_angle = start_angle % 360 if start_angle
@end_angle = end_angle % 360 if end_angle
@inclination = inclination if inclination
self
end
# Draws the solid arc on the given Canvas.
def draw(canvas)
angle_difference = (@end_angle - @start_angle).abs
if @inner_a == 0 && @inner_b == 0
arc = canvas.graphic_object(:arc, cx: @cx, cy: @cy, a: @outer_a, b: @outer_b,
start_angle: @start_angle, end_angle: @end_angle,
inclination: @inclination, clockwise: false)
if angle_difference == 0
arc.draw(canvas)
else
canvas.move_to(@cx, @cy)
canvas.line_to(*arc.start_point)
arc.draw(canvas, move_to_start: false)
end
else
inner = canvas.graphic_object(:arc, cx: @cx, cy: @cy, a: @inner_a, b: @inner_b,
start_angle: @end_angle, end_angle: @start_angle,
inclination: @inclination, clockwise: true)
outer = canvas.graphic_object(:arc, cx: @cx, cy: @cy, a: @outer_a, b: @outer_b,
start_angle: @start_angle, end_angle: @end_angle,
inclination: @inclination, clockwise: false)
outer.draw(canvas)
if angle_difference == 0
canvas.close_subpath
inner.draw(canvas)
else
canvas.line_to(*inner.start_point)
inner.draw(canvas, move_to_start: false)
end
end
canvas.close_subpath
end
end
end
end
end