sevgi-geometry 0.93.1 → 0.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +152 -0
- data/LICENSE +674 -0
- data/README.md +34 -2
- data/lib/sevgi/geometry/element.rb +106 -28
- data/lib/sevgi/geometry/elements/line.rb +24 -9
- data/lib/sevgi/geometry/elements/rect.rb +32 -0
- data/lib/sevgi/geometry/elements/triangle.rb +17 -13
- data/lib/sevgi/geometry/equation/linear.rb +13 -8
- data/lib/sevgi/geometry/equation/quadratic.rb +8 -2
- data/lib/sevgi/geometry/equation.rb +3 -0
- data/lib/sevgi/geometry/internal.rb +34 -2
- data/lib/sevgi/geometry/operation/align.rb +2 -0
- data/lib/sevgi/geometry/operation/sweep.rb +51 -8
- data/lib/sevgi/geometry/operation.rb +62 -0
- data/lib/sevgi/geometry/point.rb +3 -10
- data/lib/sevgi/geometry/segment.rb +3 -10
- data/lib/sevgi/geometry/version.rb +1 -1
- metadata +7 -8
- data/lib/sevgi/geometry/elements/circle.rb +0 -1
- data/lib/sevgi/geometry/elements/curve.rb +0 -1
- data/lib/sevgi/geometry/elements/ellipse.rb +0 -1
|
@@ -10,8 +10,11 @@ module Sevgi
|
|
|
10
10
|
# Default maximum number of sweep iterations.
|
|
11
11
|
LIMIT = 1_000
|
|
12
12
|
|
|
13
|
-
# Sweeps parallel lines across
|
|
14
|
-
#
|
|
13
|
+
# Sweeps parallel lines across a lined element in both directions.
|
|
14
|
+
#
|
|
15
|
+
# Generated lines are boundary-to-boundary interior spans. A single
|
|
16
|
+
# sweep position can produce multiple lines for closed concave elements; open paths produce no interior lines.
|
|
17
|
+
# @param element [Sevgi::Geometry::Element::Lined] element to intersect
|
|
15
18
|
# @param initial [Sevgi::Geometry::Point, Array<Numeric>] point on the initial sweep line
|
|
16
19
|
# @param angle [Numeric] clockwise sweep line angle in degrees
|
|
17
20
|
# @param step [Numeric] signed distance between sweep lines
|
|
@@ -33,8 +36,11 @@ module Sevgi
|
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
|
|
36
|
-
# Sweeps parallel lines and requires at least one result.
|
|
37
|
-
#
|
|
39
|
+
# Sweeps parallel lines across a lined element and requires at least one result.
|
|
40
|
+
#
|
|
41
|
+
# Generated lines are boundary-to-boundary interior spans. A single
|
|
42
|
+
# sweep position can produce multiple lines for closed concave elements; open paths produce no interior lines.
|
|
43
|
+
# @param element [Sevgi::Geometry::Element::Lined] element to intersect
|
|
38
44
|
# @param initial [Sevgi::Geometry::Point, Array<Numeric>] point on the initial sweep line
|
|
39
45
|
# @param angle [Numeric] clockwise sweep line angle in degrees
|
|
40
46
|
# @param step [Numeric] signed distance between sweep lines
|
|
@@ -56,7 +62,10 @@ module Sevgi
|
|
|
56
62
|
end
|
|
57
63
|
|
|
58
64
|
# Sweeps parallel lines in one signed direction from an equation.
|
|
59
|
-
#
|
|
65
|
+
#
|
|
66
|
+
# Generated lines are boundary-to-boundary interior spans. A single
|
|
67
|
+
# sweep position can produce multiple lines for closed concave elements; open paths produce no interior lines.
|
|
68
|
+
# @param element [Sevgi::Geometry::Element::Lined] element to intersect
|
|
60
69
|
# @param equation [Sevgi::Geometry::Equation] initial sweep equation
|
|
61
70
|
# @param step [Numeric] signed distance between sweep lines
|
|
62
71
|
# @param limit [Integer] maximum iterations
|
|
@@ -69,9 +78,7 @@ module Sevgi
|
|
|
69
78
|
points = element.intersection(equation)
|
|
70
79
|
return lines if points.empty?
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
lines << line
|
|
74
|
-
end
|
|
81
|
+
lines.concat(interior_lines(element, equation, points))
|
|
75
82
|
|
|
76
83
|
equation = equation.shift(step)
|
|
77
84
|
end
|
|
@@ -86,9 +93,45 @@ module Sevgi
|
|
|
86
93
|
def applicable?(element)
|
|
87
94
|
element.respond_to?(:intersection)
|
|
88
95
|
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def interior_lines(element, equation, points)
|
|
100
|
+
return [] if element.class.respond_to?(:open?) && element.class.open?
|
|
101
|
+
|
|
102
|
+
if points.size == 2
|
|
103
|
+
line = simple_line(points)
|
|
104
|
+
|
|
105
|
+
return line ? [line] : []
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
sorted_points(equation, points).each_cons(2).filter_map do |starting, ending|
|
|
109
|
+
next unless element.inside?(midpoint(starting, ending))
|
|
110
|
+
|
|
111
|
+
simple_line([starting, ending])
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def midpoint(starting, ending)
|
|
116
|
+
Point[(starting.x + ending.x) / 2.0, (starting.y + ending.y) / 2.0]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def simple_line(points)
|
|
120
|
+
line = Line.(*points)
|
|
121
|
+
|
|
122
|
+
line unless line.ignorable?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def sorted_points(equation, points)
|
|
126
|
+
points.sort_by do |point|
|
|
127
|
+
equation.is_a?(Equation::Linear::Vertical) ? [point.y, point.x] : [point.x, point.y]
|
|
128
|
+
end
|
|
129
|
+
end
|
|
89
130
|
end
|
|
90
131
|
|
|
91
132
|
register(Sweep, :sweep, :sweep!, :unisweep)
|
|
133
|
+
|
|
134
|
+
private_constant :Sweep
|
|
92
135
|
end
|
|
93
136
|
end
|
|
94
137
|
end
|
|
@@ -12,6 +12,66 @@ module Sevgi
|
|
|
12
12
|
# Raised when an operation does not apply to the target element.
|
|
13
13
|
OperationInapplicableError = Class.new(Error)
|
|
14
14
|
|
|
15
|
+
# @!parse
|
|
16
|
+
# class << self
|
|
17
|
+
# # Returns an element translated to align with another element.
|
|
18
|
+
# # @param element [Sevgi::Geometry::Element] element to move
|
|
19
|
+
# # @param other [Sevgi::Geometry::Element] reference element
|
|
20
|
+
# # @param alignment [Symbol] one of :center, :left, :right, :top, or :bottom
|
|
21
|
+
# # @return [Sevgi::Geometry::Element] translated element
|
|
22
|
+
# # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when an argument is not a geometry element
|
|
23
|
+
# # @raise [Sevgi::ArgumentError] when alignment is unknown
|
|
24
|
+
# def align(element, other, alignment = :center); end
|
|
25
|
+
#
|
|
26
|
+
# # Returns the offset needed to align one element with another.
|
|
27
|
+
# # @param element [Sevgi::Geometry::Element] element to move
|
|
28
|
+
# # @param other [Sevgi::Geometry::Element] reference element
|
|
29
|
+
# # @param alignment [Symbol] one of :center, :left, :right, :top, or :bottom
|
|
30
|
+
# # @return [Sevgi::Geometry::Point] translation offset
|
|
31
|
+
# # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when an argument is not a geometry element
|
|
32
|
+
# # @raise [Sevgi::ArgumentError] when alignment is unknown
|
|
33
|
+
# def alignment(element, other, alignment = :center); end
|
|
34
|
+
#
|
|
35
|
+
# # Sweeps parallel lines across a lined element in both directions.
|
|
36
|
+
# # @param element [Sevgi::Geometry::Element::Lined] element to intersect
|
|
37
|
+
# # @param initial [Sevgi::Geometry::Point, Array<Numeric>] point on the initial sweep line
|
|
38
|
+
# # @param angle [Numeric] clockwise sweep line angle in degrees
|
|
39
|
+
# # @param step [Numeric] signed distance between sweep lines
|
|
40
|
+
# # @param limit [Integer] maximum iterations per direction
|
|
41
|
+
# # @yield [lines] optional hook receiving the generated lines
|
|
42
|
+
# # @yieldparam lines [Array<Sevgi::Geometry::Line>] generated sweep lines
|
|
43
|
+
# # @yieldreturn [void]
|
|
44
|
+
# # @return [Array<Sevgi::Geometry::Line>] generated sweep lines
|
|
45
|
+
# # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when element is not sweepable
|
|
46
|
+
# # @raise [Sevgi::Geometry::Error] when initial cannot be coerced
|
|
47
|
+
# # @raise [Sevgi::Geometry::Operation::OperationError] when iteration reaches the limit
|
|
48
|
+
# def sweep(element, initial:, angle:, step:, limit: Sweep::LIMIT); end
|
|
49
|
+
#
|
|
50
|
+
# # Sweeps parallel lines across a lined element and requires at least one result.
|
|
51
|
+
# # @param element [Sevgi::Geometry::Element::Lined] element to intersect
|
|
52
|
+
# # @param initial [Sevgi::Geometry::Point, Array<Numeric>] point on the initial sweep line
|
|
53
|
+
# # @param angle [Numeric] clockwise sweep line angle in degrees
|
|
54
|
+
# # @param step [Numeric] signed distance between sweep lines
|
|
55
|
+
# # @param limit [Integer] maximum iterations per direction
|
|
56
|
+
# # @yield [lines] optional hook receiving the generated lines
|
|
57
|
+
# # @yieldparam lines [Array<Sevgi::Geometry::Line>] generated sweep lines
|
|
58
|
+
# # @yieldreturn [void]
|
|
59
|
+
# # @return [Array<Sevgi::Geometry::Line>] generated sweep lines
|
|
60
|
+
# # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when element is not sweepable
|
|
61
|
+
# # @raise [Sevgi::Geometry::Error] when initial cannot be coerced
|
|
62
|
+
# # @raise [Sevgi::Geometry::Operation::OperationError] when no lines are found or iteration reaches the limit
|
|
63
|
+
# def sweep!(element, initial:, angle:, step:, limit: Sweep::LIMIT); end
|
|
64
|
+
#
|
|
65
|
+
# # Sweeps parallel lines in one signed direction from an equation.
|
|
66
|
+
# # @param element [Sevgi::Geometry::Element::Lined] element to intersect
|
|
67
|
+
# # @param equation [Sevgi::Geometry::Equation] initial sweep equation
|
|
68
|
+
# # @param step [Numeric] signed distance between sweep lines
|
|
69
|
+
# # @param limit [Integer] maximum iterations
|
|
70
|
+
# # @return [Array<Sevgi::Geometry::Line>] generated sweep lines
|
|
71
|
+
# # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when element is not sweepable
|
|
72
|
+
# # @raise [Sevgi::Geometry::Operation::OperationError] when iteration reaches the limit
|
|
73
|
+
# def unisweep(element, equation, step, limit: Sweep::LIMIT); end
|
|
74
|
+
# end
|
|
15
75
|
# Registers one or more public operation methods.
|
|
16
76
|
# @api private
|
|
17
77
|
# @param handler [Module] operation handler module
|
|
@@ -19,6 +79,8 @@ module Sevgi
|
|
|
19
79
|
# @return [Array<Symbol>] registered operation names
|
|
20
80
|
def register(handler, *operations) = operations.each { |operation| def_operation(operation, handler) }
|
|
21
81
|
|
|
82
|
+
private :register
|
|
83
|
+
|
|
22
84
|
private
|
|
23
85
|
|
|
24
86
|
def def_operation(operation, handler)
|
data/lib/sevgi/geometry/point.rb
CHANGED
|
@@ -100,13 +100,14 @@ module Sevgi
|
|
|
100
100
|
# @param x [Numeric] x coordinate
|
|
101
101
|
# @param y [Numeric] y coordinate
|
|
102
102
|
# @return [void]
|
|
103
|
-
|
|
103
|
+
# @raise [Sevgi::Geometry::Error] when a coordinate is not a finite Numeric
|
|
104
|
+
def initialize(x:, y:) = super(x: Real[:x, x], y: Real[:y, y])
|
|
104
105
|
|
|
105
106
|
# Compares points by x, then y.
|
|
106
107
|
# @param other [Sevgi::Geometry::Point, Array<Numeric>] point to compare
|
|
107
108
|
# @return [Integer, nil]
|
|
108
109
|
# @raise [Sevgi::Geometry::Error] when other cannot be coerced
|
|
109
|
-
def <=>(other) =
|
|
110
|
+
def <=>(other) = deconstruct <=> Tuple[Point, other].deconstruct
|
|
110
111
|
|
|
111
112
|
# Reports whether this point is at or above another point in screen coordinates.
|
|
112
113
|
# @param other [Sevgi::Geometry::Point, Array<Numeric>] point to compare
|
|
@@ -141,20 +142,12 @@ module Sevgi
|
|
|
141
142
|
# @return [Integer]
|
|
142
143
|
def hash = [self.class, *deconstruct].hash
|
|
143
144
|
|
|
144
|
-
# Reports whether any coordinate is infinite.
|
|
145
|
-
# @return [Boolean]
|
|
146
|
-
def infinite? = deconstruct.any?(&:infinite?)
|
|
147
|
-
|
|
148
145
|
# Reports whether this point is at or left of another point.
|
|
149
146
|
# @param other [Sevgi::Geometry::Point, Array<Numeric>] point to compare
|
|
150
147
|
# @return [Boolean]
|
|
151
148
|
# @raise [Sevgi::Geometry::Error] when other cannot be coerced
|
|
152
149
|
def left?(other) = x <= Tuple[Point, other].x
|
|
153
150
|
|
|
154
|
-
# Reports whether any coordinate is NaN.
|
|
155
|
-
# @return [Boolean]
|
|
156
|
-
def nan? = deconstruct.any?(&:nan?)
|
|
157
|
-
|
|
158
151
|
# Reports whether this point is at or right of another point.
|
|
159
152
|
# @param other [Sevgi::Geometry::Point, Array<Numeric>] point to compare
|
|
160
153
|
# @return [Boolean]
|
|
@@ -66,13 +66,14 @@ module Sevgi
|
|
|
66
66
|
# @param length [Numeric] segment length
|
|
67
67
|
# @param angle [Numeric] clockwise angle in degrees
|
|
68
68
|
# @return [void]
|
|
69
|
-
|
|
69
|
+
# @raise [Sevgi::Geometry::Error] when a component is not a finite Numeric
|
|
70
|
+
def initialize(length:, angle:) = super(length: Real[:length, length], angle: Real[:angle, angle])
|
|
70
71
|
|
|
71
72
|
# Compares segments by length.
|
|
72
73
|
# @param other [Sevgi::Geometry::Segment, Array<Numeric>] segment to compare
|
|
73
74
|
# @return [Integer, nil]
|
|
74
75
|
# @raise [Sevgi::Geometry::Error] when other cannot be coerced
|
|
75
|
-
def <=>(other) =
|
|
76
|
+
def <=>(other) = length <=> Tuple[Segment, other].length
|
|
76
77
|
|
|
77
78
|
# Returns a segment rounded to precision.
|
|
78
79
|
# @param precision [Integer, nil] decimal precision, or nil for the current function default
|
|
@@ -101,20 +102,12 @@ module Sevgi
|
|
|
101
102
|
# @return [Integer]
|
|
102
103
|
def hash = [self.class, *deconstruct].hash
|
|
103
104
|
|
|
104
|
-
# Reports whether any component is infinite.
|
|
105
|
-
# @return [Boolean]
|
|
106
|
-
def infinite? = deconstruct.any?(&:infinite?)
|
|
107
|
-
|
|
108
105
|
# Converts the segment into a line at a point.
|
|
109
106
|
# @param point [Sevgi::Geometry::Point, Array<Numeric>] line start point
|
|
110
107
|
# @return [Sevgi::Geometry::Line]
|
|
111
108
|
# @raise [Sevgi::Geometry::Error] when point cannot be coerced
|
|
112
109
|
def line(point = Origin) = Line[length, angle, position: Tuple[Point, point]]
|
|
113
110
|
|
|
114
|
-
# Reports whether any component is NaN.
|
|
115
|
-
# @return [Boolean]
|
|
116
|
-
def nan? = deconstruct.any?(&:nan?)
|
|
117
|
-
|
|
118
111
|
# Returns the opposite segment.
|
|
119
112
|
# @return [Sevgi::Geometry::Segment]
|
|
120
113
|
def reverse = with(angle: angle + 180.0)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sevgi-geometry
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.95.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Recai Oktaş
|
|
@@ -15,26 +15,25 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.95.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.95.0
|
|
26
26
|
description: Enhances the Sevgi toolkit with geometry objects and methods.
|
|
27
27
|
email: roktas@gmail.com
|
|
28
28
|
executables: []
|
|
29
29
|
extensions: []
|
|
30
30
|
extra_rdoc_files: []
|
|
31
31
|
files:
|
|
32
|
+
- CHANGELOG.md
|
|
33
|
+
- LICENSE
|
|
32
34
|
- README.md
|
|
33
35
|
- lib/sevgi/geometry.rb
|
|
34
36
|
- lib/sevgi/geometry/element.rb
|
|
35
|
-
- lib/sevgi/geometry/elements/circle.rb
|
|
36
|
-
- lib/sevgi/geometry/elements/curve.rb
|
|
37
|
-
- lib/sevgi/geometry/elements/ellipse.rb
|
|
38
37
|
- lib/sevgi/geometry/elements/line.rb
|
|
39
38
|
- lib/sevgi/geometry/elements/parallelogram.rb
|
|
40
39
|
- lib/sevgi/geometry/elements/polygon.rb
|
|
@@ -67,14 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
67
66
|
requirements:
|
|
68
67
|
- - ">="
|
|
69
68
|
- !ruby/object:Gem::Version
|
|
70
|
-
version: 3.4.0
|
|
69
|
+
version: 3.4.0
|
|
71
70
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
71
|
requirements:
|
|
73
72
|
- - ">="
|
|
74
73
|
- !ruby/object:Gem::Version
|
|
75
74
|
version: '0'
|
|
76
75
|
requirements: []
|
|
77
|
-
rubygems_version: 4.0.
|
|
76
|
+
rubygems_version: 4.0.11
|
|
78
77
|
specification_version: 4
|
|
79
78
|
summary: Tiny library for geometric computations.
|
|
80
79
|
test_files: []
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|