Class: VectorBeWinding::Segment

Inherits:
Shape
  • Object
show all
Defined in:
lib/vector_be_winding/segment.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Shape

#containingness, #contains?, #intersectedness, #intersects?

Constructor Details

#initialize(direction, start_point, end_point_hint, prev_segment = nil) ⇒ Segment

Returns a new instance of Segment.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/vector_be_winding/segment.rb', line 7

def initialize(direction, start_point, end_point_hint, prev_segment = nil)
  @direction = direction
  @start_point = start_point
  @end_point =
    if @direction.kind_of?(::Savage::Directions::PointTarget)
      create_vector(@direction.target.x, @direction.target.y, @direction.absolute?)
    elsif @direction.kind_of?(::Savage::Directions::HorizontalTo)
      create_vector(@direction.target, nil, @direction.absolute?)
    elsif @direction.kind_of?(::Savage::Directions::VerticalTo)
      create_vector(nil, @direction.target, @direction.absolute?)
    elsif @direction.kind_of?(::Savage::Directions::ClosePath)
      end_point_hint
    else
      raise "Unknown direction: #{@direction}"
    end

  if @direction.instance_of?(::Savage::Directions::QuadraticCurveTo)
    control = @direction.control ||
              prev_segment.control&.reflect(start_point) ||
              start_point
    @control = create_vector(control.x, control.y, @direction.absolute?)
  elsif @direction.instance_of?(::Savage::Directions::CubicCurveTo)
    control = @direction.control
    control_1 = @direction.control_1 ||
              prev_segment.control&.reflect(start_point) ||
              start_point
    @control = create_vector(control.x, control.y, @direction.absolute?)
    @control_1 = create_vector(control_1.x, control_1.y, @direction.absolute?)
  elsif @direction.instance_of?(::Savage::Directions::ArcTo)
    @radius = @direction.radius
    @rotation = @direction.rotation
    @large_arc = @direction.large_arc
    @sweep = @direction.sweep
  end
end

Instance Attribute Details

#controlObject (readonly)

Returns the value of attribute control.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def control
  @control
end

#control_1Object (readonly)

Returns the value of attribute control_1.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def control_1
  @control_1
end

#directionObject (readonly)

Returns the value of attribute direction.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def direction
  @direction
end

#end_pointObject (readonly)

Returns the value of attribute end_point.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def end_point
  @end_point
end

#large_arcObject (readonly)

Returns the value of attribute large_arc.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def large_arc
  @large_arc
end

#radiusObject (readonly)

Returns the value of attribute radius.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def radius
  @radius
end

#rotationObject (readonly)

Returns the value of attribute rotation.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def rotation
  @rotation
end

#start_pointObject (readonly)

Returns the value of attribute start_point.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def start_point
  @start_point
end

#sweepObject (readonly)

Returns the value of attribute sweep.



3
4
5
# File 'lib/vector_be_winding/segment.rb', line 3

def sweep
  @sweep
end

Instance Method Details

#area(p) ⇒ Object

Calculate direction area of the triangle (p, start_point, end_point) It must be positive iff the three points forms clockwise order.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/vector_be_winding/segment.rb', line 62

def area(p)
  if @direction.kind_of?(::Savage::Directions::QuadraticCurveTo)
    # Approximate with triangle
    (start_point - p).cross(control - start_point) +
      (control - p).cross(end_point - control)
  elsif @direction.kind_of?(::Savage::Directions::CubicCurveTo)
    # Approximate with quadrangle
    (start_point - p).cross(control_1 - start_point) +
      (control_1 - p).cross(control_2 - control_1) +
      (control_2 - p).cross(end_point - control_2)
  elsif @direction.kind_of?(::Savage::Directions::ArcTo)
    # Very rough approximation. TODO: Be more precise
    (start_point - p).cross(end_point - start_point) / 2.0 + (sweep ? 1 : -1)
  else
    (start_point - p).cross(end_point - start_point) / 2.0
  end
end

#bounding_rectObject



55
56
57
58
# File 'lib/vector_be_winding/segment.rb', line 55

def bounding_rect
  @bounding_rect ||=
    Rect.new(start_point.x, start_point.y, end_point.x, end_point.y)
end

#control_2Object



43
44
45
# File 'lib/vector_be_winding/segment.rb', line 43

def control_2
  control
end

#create_vector(x, y, absolute) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/vector_be_winding/segment.rb', line 47

def create_vector(x, y, absolute)
  if absolute
    Vector.new(x || start_point.x, y || start_point.y)
  else
    start_point + Vector.new(x || 0, y || 0)
  end
end

#reverseObject



80
81
82
# File 'lib/vector_be_winding/segment.rb', line 80

def reverse
  Segment.new(reverse_dir, end_point, start_point)
end

#reverse_dirObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/vector_be_winding/segment.rb', line 84

def reverse_dir
  case @direction.command_code.upcase
  when 'Z', 'L'
    ::Savage::Directions::LineTo.new(start_point.x, start_point.y, true)
  when 'M'
    nil  # Unable to reverse
  when 'H'
    ::Savage::Directions::HorizontalTo.new(start_point.x, true)
  when 'V'
    ::Savage::Directions::VerticalTo.new(start_point.y, true)
  when 'Q', 'T'
    ::Savage::Directions::QuadraticCurveTo.new(
      control.x, control.y, start_point.x, start_point.y, true)
  when 'C', 'S'
    ::Savage::Directions::CubicCurveTo.new(
      control.x, control.y, control_1.x, control_1.y,
      start_point.x, start_point.y, true)
  when 'A'
    ::Savage::Directions::ArcTo.new(
      radius.x, radius.y, rotation, large_arc, !sweep, start_point.x, start_point.y, true)
  else
    raise "Unknown direction: #{@direction}"
  end
end