Class: Sevgi::Geometry::Element::Lined
Overview
rubocop:disable Metrics/ClassLength
Constant Summary
collapse
- Open =
Class.new(self) do
def draw!(node, **) = node.polyline(points: points.map { it.deconstruct.join(",") }, **)
end
- Close =
Class.new(self) do
def self.new_by_points(*points) = super(*points, points.first)
def draw!(node, **) = node.polygon(points: points.map { it.deconstruct.join(",") }, **)
end
- SHORTCUTS =
("A".."Z").to_a.freeze
Class Method Summary
collapse
Instance Method Summary
collapse
arced, #at, #ignorable?, lined, #translate
Constructor Details
#initialize(&block) ⇒ Lined
Returns a new instance of Lined.
92
93
94
95
96
97
98
99
100
101
102
103
|
# File 'lib/sevgi/geometry/element.rb', line 92
def initialize(&block)
super()
Error.("Constructor block required") unless block
instance_exec(&block)
@points ||= calculate_points_from_segments
@segments ||= calculate_segments_from_points
sanitize
end
|
Class Method Details
.[] ⇒ Object
71
|
# File 'lib/sevgi/geometry/element.rb', line 71
def self.[](...) = new_by_segments(...)
|
.build(size = Undefined, open: false) ⇒ Object
rubocop:disable Metrics/MethodLength
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
# File 'lib/sevgi/geometry/element.rb', line 46
def self.build(size = Undefined, open: false)
Class.new(open ? Open : Close) do
define_singleton_method(:close?) { !open }
define_singleton_method(:open?) { open }
define_singleton_method(:poly?) { size == Undefined }
define_singleton_method(:size) { size }
unless size == Undefined
SHORTCUTS[..size.clamp(..SHORTCUTS.size)].each_with_index do |name, i|
define_method(name) { points[i] or Error.("No such point: #{name}") }
end
methods = SHORTCUTS[..size.clamp(..SHORTCUTS.size)].each_cons(2).with_index.map do |names, i|
define_method(name = names.join) { lines[i] or Error.("No such line: #{name}") }
end
alias_method("#{SHORTCUTS[size - 1]}#{SHORTCUTS.first}", methods.last)
end
end
end
|
.call ⇒ Object
73
|
# File 'lib/sevgi/geometry/element.rb', line 73
def self.call(...) = new_by_points(...)
|
.new_by_points ⇒ Object
75
|
# File 'lib/sevgi/geometry/element.rb', line 75
def self.new_by_points(...) = new_by_points!(...)
|
.new_by_points!(*points) ⇒ Object
77
78
79
80
81
|
# File 'lib/sevgi/geometry/element.rb', line 77
def self.new_by_points!(*points)
new do
@points = Tuples[Point, *points]
end
end
|
.new_by_segments(*segments, position: Origin) ⇒ Object
83
84
85
86
87
88
|
# File 'lib/sevgi/geometry/element.rb', line 83
def self.new_by_segments(*segments, position: Origin)
new do
@position = Tuple[Point, position]
@segments = Tuples[Segment, *segments]
end
end
|
Instance Method Details
#[](i) ⇒ Object
161
|
# File 'lib/sevgi/geometry/element.rb', line 161
def [](i) = lines[i].tap { |line| Error.("No line exist for index: #{i}") unless line }
|
#approx ⇒ Object
107
108
109
110
111
112
|
# File 'lib/sevgi/geometry/element.rb', line 107
def approx
points, segments = points(true), segments(true)
self.class.send(:new) do
@points, @segments = points, segments
end
end
|
#box ⇒ Object
163
|
# File 'lib/sevgi/geometry/element.rb', line 163
def box = Rect.([(xs = points.map(&:x)).min, (ys = points.map(&:y)).min], [xs.max, ys.max])
|
#call(i) ⇒ Object
165
|
# File 'lib/sevgi/geometry/element.rb', line 165
def call(i) = points[i].tap { Error.("No point exist for index: #{i}") unless it }
|
#draw ⇒ Object
114
115
116
|
# File 'lib/sevgi/geometry/element.rb', line 114
def draw(...)
approx.draw!(...)
end
|
#eql?(other) ⇒ Boolean
Also known as:
==
140
|
# File 'lib/sevgi/geometry/element.rb', line 140
def eql?(other) = self.class == other.class && points(true) == other.points(true)
|
#equations ⇒ Object
148
|
# File 'lib/sevgi/geometry/element.rb', line 148
def equations = @equations ||= lines.map(&:equation)
|
#hash ⇒ Object
142
|
# File 'lib/sevgi/geometry/element.rb', line 142
def hash = [self.class, *points(true)].hash
|
#head ⇒ Object
167
|
# File 'lib/sevgi/geometry/element.rb', line 167
def head = @head ||= segments.first
|
#inside?(point) ⇒ Boolean
181
|
# File 'lib/sevgi/geometry/element.rb', line 181
def inside?(point) = on?(point) || pnpoly(points, point)
|
#intersection(equation, precision: nil) ⇒ Object
150
151
152
153
154
155
156
157
|
# File 'lib/sevgi/geometry/element.rb', line 150
def intersection(equation, precision: nil)
equations
.map do |candidate|
equation.intersect(candidate).map { |point| point.approx(precision) }.select { |point| on?(point) }
end
.flatten
.uniq
end
|
#lines ⇒ Object
169
170
171
172
173
|
# File 'lib/sevgi/geometry/element.rb', line 169
def lines
@lines ||= segments.zip(points[...segments.size]).map { |segment, position|
segment.line(position)
}
end
|
#on?(point) ⇒ Boolean
183
|
# File 'lib/sevgi/geometry/element.rb', line 183
def on?(point) = lines.any? { it.over?(point) }
|
#outside?(point) ⇒ Boolean
185
|
# File 'lib/sevgi/geometry/element.rb', line 185
def outside?(point) = !inside?(point)
|
#perimeter ⇒ Object
175
|
# File 'lib/sevgi/geometry/element.rb', line 175
def perimeter = @perimeter ||= segments.sum(&:length)
|
#points(approximate = false) ⇒ Object
118
119
120
|
# File 'lib/sevgi/geometry/element.rb', line 118
def points(approximate = false)
approximate ? (@points_approx ||= @points.map(&:approx)) : @points
end
|
#position ⇒ Object
122
123
124
|
# File 'lib/sevgi/geometry/element.rb', line 122
def position
@position ||= points.first
end
|
#segments(approximate = false) ⇒ Object
126
127
128
|
# File 'lib/sevgi/geometry/element.rb', line 126
def segments(approximate = false)
approximate ? (@segments_approx ||= @segments.map(&:approx)) : @segments
end
|
#tail ⇒ Object
177
|
# File 'lib/sevgi/geometry/element.rb', line 177
def tail = @tail ||= segments.last
|