class DYI::Shape::Path::ArcCommand

Attributes

rotation[R]
rx[R]
ry[R]

Public Class Methods

new(relative, preceding_command, rx, ry, rotation, is_large_arc, is_clockwise, point) click to toggle source
# File lib/dyi/shape/path.rb, line 945
def initialize(relative, preceding_command, rx, ry, rotation, is_large_arc, is_clockwise, point)
  raise ArgumentError, 'preceding_command is nil' if preceding_command.nil?
  @relative = relative
  @preceding_command = preceding_command
  @point = Coordinate.new(point)
  @rotation = rotation
  @is_large_arc = is_large_arc
  @is_clockwise = is_clockwise
  @rx = Length.new(rx).abs
  @ry = Length.new(ry).abs
  l = (modified_mid_point.x.to_f / @rx.to_f) ** 2 + (modified_mid_point.y.to_f / @ry.to_f) ** 2
  if 1 < l
    @rx *= Math.sqrt(l)
    @ry *= Math.sqrt(l)
  end
end

Private Class Methods

commands(relative, preceding_command, *args) click to toggle source
# File lib/dyi/shape/path.rb, line 1060
def commands(relative, preceding_command, *args)
  raise ArgumentError, "number of arguments must be a multipule of 6" if args.size % 6 != 0
  cmd = preceding_command
  args.each_slice(6).inject([]) do |cmds, ars|
    if ars[0].zero? || ars[1].zero?
      cmds << (cmd = LineCommand.new(relative, cmd, ars.last))
    else
      cmds << (cmd = new(relative, cmd, *ars))
    end
  end
end

Public Instance Methods

center_point() click to toggle source
# File lib/dyi/shape/path.rb, line 1009
def center_point
  st_pt = relative? ? Coordinate::ZERO : preceding_point
  Matrix.rotate(rotation).transform(modified_center_point) + (st_pt + point) * 0.5
end
clockwise?() click to toggle source
# File lib/dyi/shape/path.rb, line 966
def clockwise?
  @is_clockwise
end
instructions_char() click to toggle source
# File lib/dyi/shape/path.rb, line 1005
def instructions_char
  relative? ? 'a' : 'A'
end
large_arc?() click to toggle source
# File lib/dyi/shape/path.rb, line 962
def large_arc?
  @is_large_arc
end
to_compatible_commands(preceding_command) click to toggle source
# File lib/dyi/shape/path.rb, line 970
def to_compatible_commands(preceding_command)
  return LineCommand.new(relative?, preceding_command, point) if rx.zero? || ry.zero?
  division_count = (center_angle / 30.0).ceil
  division_angle = center_angle / division_count * (clockwise? ? 1 : -1)
  current_point = start_angle_point
  compat_commands = []
  division_count.times do |i|
    end_point = if i == division_count - 1
                  end_angle_point
                else
                  Matrix.rotate(division_angle).transform(current_point)
                end
    control_point1 = control_point_of_curve(current_point, division_angle, true)
    control_point2 = control_point_of_curve(end_point, division_angle, false)
    path_point = (i == division_count - 1) ? point : transform_orginal_shape(end_point)
    if relative?
      control_point1 += preceding_point
      control_point2 += preceding_point
      path_point += preceding_point
    end
    preceding_command = CurveCommand.absolute_commands(preceding_command,
                                                       control_point1,
                                                       control_point2,
                                                       path_point).first
    compat_commands << preceding_command
    current_point = end_point
  end
  compat_commands
end
to_concise_syntax_fragments() click to toggle source
# File lib/dyi/shape/path.rb, line 1000
def to_concise_syntax_fragments
  [used_same_command? ? rx.to_s : instructions_char + rx.to_s,
   ry, rotation, large_arc? ? 1 : 0, clockwise? ? 1 : 0, point.to_s]
end

Private Instance Methods

center_angle() click to toggle source
# File lib/dyi/shape/path.rb, line 1039
def center_angle
  angle = DYI::Util.acos(start_angle_point.x.to_f * end_angle_point.x.to_f +
                    start_angle_point.y.to_f * end_angle_point.y.to_f)
  large_arc? ? 360.0 - angle : angle
end
control_point_of_curve(point, center_angle, is_start_point) click to toggle source
# File lib/dyi/shape/path.rb, line 1053
def control_point_of_curve(point, center_angle, is_start_point)
  handle_length = DYI::Util.tan(center_angle / 4.0) * 4.0 / 3.0
  handle = is_start_point ? handle_length : -handle_length
  transform_matrix.transform(Matrix.new(1, handle, -handle, 1, 0, 0).transform(point))
end
end_angle_point() click to toggle source
# File lib/dyi/shape/path.rb, line 1034
def end_angle_point
  Coordinate.new((-modified_mid_point.x - modified_center_point.x) / rx,
                 (-modified_mid_point.y - modified_center_point.y) / ry)
end
modified_center_point() click to toggle source
# File lib/dyi/shape/path.rb, line 1021
def modified_center_point
  pt = modified_mid_point
  Coordinate.new(pt.y * (rx / ry), -pt.x * (ry / rx)) *
    Math.sqrt(((rx.to_f * ry.to_f) ** 2 - (rx.to_f * pt.y.to_f) ** 2 - (ry.to_f * pt.x.to_f) ** 2) /
      ((rx.to_f * pt.y.to_f) ** 2 + (ry.to_f * pt.x.to_f) ** 2)) *
    ((large_arc? == clockwise?) ? -1 : 1)
end
modified_mid_point() click to toggle source
# File lib/dyi/shape/path.rb, line 1016
def modified_mid_point
  st_pt = relative? ? Coordinate::ZERO : preceding_point
  Matrix.rotate(-rotation).transform((st_pt - point) * 0.5)
end
start_angle_point() click to toggle source
# File lib/dyi/shape/path.rb, line 1029
def start_angle_point
  Coordinate.new((modified_mid_point.x - modified_center_point.x) / rx,
                 (modified_mid_point.y - modified_center_point.y) / ry)
end
transform_matrix() click to toggle source
# File lib/dyi/shape/path.rb, line 1045
def transform_matrix
  Matrix.translate(center_point.x.to_f, center_point.y.to_f).rotate(rotation).scale(rx.to_f, ry.to_f)
end
transform_orginal_shape(modified_point) click to toggle source
# File lib/dyi/shape/path.rb, line 1049
def transform_orginal_shape(modified_point)
  transform_matrix.transform(modified_point)
end