sevgi-geometry 0.95.0 → 0.98.2

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.
@@ -2,7 +2,13 @@
2
2
 
3
3
  module Sevgi
4
4
  module Geometry
5
- # Dispatches geometry operations to operation handler modules.
5
+ # Stateless operations that relate or derive geometry values.
6
+ #
7
+ # `alignment` returns a translation offset, while `align` applies that
8
+ # offset to a copy. Center alignment works on both axes; edge alignments
9
+ # change only the named axis and preserve the other coordinate. `sweep`
10
+ # derives boundary-to-boundary spans from a closed lined element, and
11
+ # `sweep!` additionally requires at least one span.
6
12
  module Operation
7
13
  extend self
8
14
 
@@ -15,24 +21,36 @@ module Sevgi
15
21
  # @!parse
16
22
  # class << self
17
23
  # # Returns an element translated to align with another element.
24
+ # # Center alignment changes both axes. Edge alignments change only the named axis.
18
25
  # # @param element [Sevgi::Geometry::Element] element to move
19
26
  # # @param other [Sevgi::Geometry::Element] reference element
20
27
  # # @param alignment [Symbol] one of :center, :left, :right, :top, or :bottom
21
28
  # # @return [Sevgi::Geometry::Element] translated element
22
29
  # # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when an argument is not a geometry element
23
30
  # # @raise [Sevgi::ArgumentError] when alignment is unknown
31
+ # # @example Center one rectangle inside another
32
+ # # inner = Sevgi::Geometry::Rect[4, 2]
33
+ # # outer = Sevgi::Geometry::Rect[20, 10, position: [5, 5]]
34
+ # # Sevgi::Geometry::Operation.align(inner, outer).position.deconstruct # => [13.0, 9.0]
24
35
  # def align(element, other, alignment = :center); end
25
36
  #
26
37
  # # Returns the offset needed to align one element with another.
38
+ # # Center alignment includes both axes. Edge alignments return zero on the other axis.
27
39
  # # @param element [Sevgi::Geometry::Element] element to move
28
40
  # # @param other [Sevgi::Geometry::Element] reference element
29
41
  # # @param alignment [Symbol] one of :center, :left, :right, :top, or :bottom
30
42
  # # @return [Sevgi::Geometry::Point] translation offset
31
43
  # # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when an argument is not a geometry element
32
44
  # # @raise [Sevgi::ArgumentError] when alignment is unknown
45
+ # # @example Calculate an offset without moving the element
46
+ # # inner = Sevgi::Geometry::Rect[4, 2]
47
+ # # outer = Sevgi::Geometry::Rect[20, 10, position: [5, 5]]
48
+ # # Sevgi::Geometry::Operation.alignment(inner, outer, :bottom).approx.deconstruct # => [0.0, 13.0]
33
49
  # def alignment(element, other, alignment = :center); end
34
50
  #
35
51
  # # Sweeps parallel lines across a lined element in both directions.
52
+ # # `angle` is the direction of the returned lines; `step` is their signed perpendicular spacing.
53
+ # # Open paths yield no interior spans.
36
54
  # # @param element [Sevgi::Geometry::Element::Lined] element to intersect
37
55
  # # @param initial [Sevgi::Geometry::Point, Array<Numeric>] point on the initial sweep line
38
56
  # # @param angle [Numeric] clockwise sweep line angle in degrees
@@ -43,11 +61,17 @@ module Sevgi
43
61
  # # @yieldreturn [void]
44
62
  # # @return [Array<Sevgi::Geometry::Line>] generated sweep lines
45
63
  # # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when element is not sweepable
46
- # # @raise [Sevgi::Geometry::Error] when initial cannot be coerced
64
+ # # @raise [Sevgi::Geometry::Error] when initial, angle, step, or limit is invalid
47
65
  # # @raise [Sevgi::Geometry::Operation::OperationError] when iteration reaches the limit
66
+ # # @example Generate horizontal spans through a rectangle
67
+ # # rect = Sevgi::Geometry::Rect[10, 6]
68
+ # # lines = Sevgi::Geometry::Operation.sweep(rect, initial: [0, 0], angle: 0, step: 2)
69
+ # # lines.size # => 4
70
+ # # lines.map(&:length).uniq # => [10.0]
48
71
  # def sweep(element, initial:, angle:, step:, limit: Sweep::LIMIT); end
49
72
  #
50
73
  # # Sweeps parallel lines across a lined element and requires at least one result.
74
+ # # It has the same geometry as {sweep}, but raises when the result would be empty.
51
75
  # # @param element [Sevgi::Geometry::Element::Lined] element to intersect
52
76
  # # @param initial [Sevgi::Geometry::Point, Array<Numeric>] point on the initial sweep line
53
77
  # # @param angle [Numeric] clockwise sweep line angle in degrees
@@ -58,19 +82,9 @@ module Sevgi
58
82
  # # @yieldreturn [void]
59
83
  # # @return [Array<Sevgi::Geometry::Line>] generated sweep lines
60
84
  # # @raise [Sevgi::Geometry::Operation::OperationInapplicableError] when element is not sweepable
61
- # # @raise [Sevgi::Geometry::Error] when initial cannot be coerced
85
+ # # @raise [Sevgi::Geometry::Error] when initial, angle, step, or limit is invalid
62
86
  # # @raise [Sevgi::Geometry::Operation::OperationError] when no lines are found or iteration reaches the limit
63
87
  # 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
88
  # end
75
89
  # Registers one or more public operation methods.
76
90
  # @api private
@@ -87,7 +101,7 @@ module Sevgi
87
101
  define_singleton_method(operation) do |element, *args, **kwargs, &block|
88
102
  OperationInapplicableError.("Not a Geometric Element: #{element}") unless element.is_a?(Element)
89
103
  unless handler.applicable?(element)
90
- OperationInapplicableError.("Unapplicable operation for #{element}: #{handler}")
104
+ OperationInapplicableError.("Operation not applicable to #{element}: #{handler}")
91
105
  end
92
106
 
93
107
  handler.public_send(operation, element, *args, **kwargs, &block)
@@ -2,7 +2,8 @@
2
2
 
3
3
  module Sevgi
4
4
  module Geometry
5
- # Affine transforms shared by immutable geometry tuples.
5
+ # Implementation owner and registry for public affine transformations on Point and lined elements.
6
+ # @api private
6
7
  module Affinity
7
8
  # Reflects a point across the selected axes.
8
9
  #
@@ -11,45 +12,141 @@ module Sevgi
11
12
  # @param x [Boolean] reflect across the x-axis
12
13
  # @param y [Boolean] reflect across the y-axis
13
14
  # @return [Sevgi::Geometry::Point]
14
- def reflect(x: true, y: true) = with(x: (y ? -1 : 1) * self.x(), y: (x ? -1 : 1) * self.y())
15
+ # @raise [Sevgi::Geometry::Error] when a flag is not Boolean
16
+ def reflect(x: true, y: true)
17
+ Error.("Reflection x flag must be Boolean") unless x.equal?(true) || x.equal?(false)
18
+ Error.("Reflection y flag must be Boolean") unless y.equal?(true) || y.equal?(false)
19
+
20
+ with(x: (y ? -1 : 1) * self.x(), y: (x ? -1 : 1) * self.y())
21
+ end
15
22
 
16
23
  # Rotates a point around the origin using screen-space degrees.
17
24
  # @param a [Numeric] clockwise angle in degrees
18
25
  # @return [Sevgi::Geometry::Point]
19
- def rotate(a) = with(x: (x * F.cos(a)) - (y * F.sin(a)), y: (x * F.sin(a)) + (y * F.cos(a)))
26
+ # @raise [Sevgi::Geometry::Error] when angle is not a finite real number
27
+ def rotate(a)
28
+ a = Real[:angle, a]
29
+ with(x: (x * F.cos(a)) - (y * F.sin(a)), y: (x * F.sin(a)) + (y * F.cos(a)))
30
+ end
20
31
 
21
32
  # Scales a point from the origin.
22
33
  # @param sx [Numeric] x scale factor
23
34
  # @param sy [Numeric, Sevgi::Undefined] y scale factor, defaulting to sx
24
35
  # @return [Sevgi::Geometry::Point]
25
- def scale(sx, sy = Undefined) = with(x: sx * x, y: Undefined.default(sy, sx) * y)
36
+ # @raise [Sevgi::Geometry::Error] when a scale is not a finite real number
37
+ def scale(sx, sy = Undefined)
38
+ sx = Real[:sx, sx]
39
+ sy = Real[:sy, Undefined.default(sy, sx)]
40
+ with(x: sx * x, y: sy * y)
41
+ end
26
42
 
27
43
  # Skews a point from the origin.
28
44
  # @param ax [Numeric] x-axis skew angle in degrees
29
45
  # @param ay [Numeric, Sevgi::Undefined] y-axis skew angle in degrees, defaulting to ax
30
46
  # @return [Sevgi::Geometry::Point]
31
- def skew(ax, ay = Undefined) = with(x: x + (y * F.tan(ax)), y: y + (x * F.tan(Undefined.default(ay, ax))))
47
+ # @raise [Sevgi::Geometry::Error] when an angle is not a finite real number
48
+ def skew(ax, ay = Undefined)
49
+ ax = Real[:ax, ax]
50
+ ay = Real[:ay, Undefined.default(ay, ax)]
51
+ with(x: x + (y * F.tan(ax)), y: y + (x * F.tan(ay)))
52
+ end
32
53
 
33
54
  # Skews a point along x.
34
55
  # @param a [Numeric] skew angle in degrees
35
56
  # @return [Sevgi::Geometry::Point]
36
- def skew_x(a) = with(x: x + (y * F.tan(a)))
57
+ # @raise [Sevgi::Geometry::Error] when angle is not a finite real number
58
+ def skew_x(a) = with(x: x + (y * F.tan(Real[:angle, a])))
37
59
 
38
60
  # Skews a point along y.
39
61
  # @param a [Numeric] skew angle in degrees
40
62
  # @return [Sevgi::Geometry::Point]
41
- def skew_y(a) = with(y: y + (x * F.tan(a)))
63
+ # @raise [Sevgi::Geometry::Error] when angle is not a finite real number
64
+ def skew_y(a) = with(y: y + (x * F.tan(Real[:angle, a])))
42
65
 
43
66
  # Translates a point.
44
67
  # @param dx [Numeric] x offset
45
68
  # @param dy [Numeric, Sevgi::Undefined] y offset, defaulting to dx
46
69
  # @return [Sevgi::Geometry::Point]
47
- def translate(dx, dy = Undefined) = with(x: x + dx, y: y + Undefined.default(dy, dx))
70
+ # @raise [Sevgi::Geometry::Error] when an offset is not a finite real number
71
+ def translate(dx, dy = Undefined)
72
+ dx = Real[:dx, dx]
73
+ dy = Real[:dy, Undefined.default(dy, dx)]
74
+ with(x: x + dx, y: y + dy)
75
+ end
48
76
  end
49
77
 
50
78
  # Immutable point in SVG/screen coordinates.
51
79
  #
52
- # Use `Point[x, y]` to create a point from two coordinates.
80
+ # Use `Point[x, y]` to create a point from two coordinates. Public geometry
81
+ # methods that expect a point also accept `[x, y]`; explicit Point values are
82
+ # most useful when a result will be transformed, compared, or reused.
83
+ # @example Measure and rotate a point in screen coordinates
84
+ # point = Sevgi::Geometry::Point[3, 4]
85
+ # Sevgi::Geometry::Point.length(Sevgi::Geometry::Origin, point) # => 5.0
86
+ # point.rotate(90).approx.deconstruct # => [-4.0, 3.0]
87
+ # @example Compare positions in screen coordinates
88
+ # upper = Sevgi::Geometry::Point[4, 2]
89
+ # lower = Sevgi::Geometry::Point[4, 8]
90
+ # upper.above?(lower) # => true
91
+ # upper.left?([6, 2]) # => true
92
+ # @see Sevgi::Geometry::Segment
93
+ # @!parse
94
+ # class Point
95
+ # # Creates a point from two coordinates.
96
+ # # @param x [Numeric] x coordinate
97
+ # # @param y [Numeric] y coordinate
98
+ # # @return [Sevgi::Geometry::Point]
99
+ # # @raise [Sevgi::Geometry::Error] when a coordinate is not a finite Numeric
100
+ # # @example Create a point with mathematical notation
101
+ # # Sevgi::Geometry::Point[3, 5]
102
+ # def self.[](x, y); end
103
+ #
104
+ # # Returns a point reflected across the selected axes.
105
+ # # @param x [Boolean] reflect across the x-axis
106
+ # # @param y [Boolean] reflect across the y-axis
107
+ # # @return [Sevgi::Geometry::Point]
108
+ # # @raise [Sevgi::Geometry::Error] when a flag is not Boolean
109
+ # def reflect(x: true, y: true); end
110
+ #
111
+ # # Returns a point rotated around the origin.
112
+ # # @param a [Numeric] clockwise angle in degrees
113
+ # # @return [Sevgi::Geometry::Point]
114
+ # # @raise [Sevgi::Geometry::Error] when angle is not a finite real number
115
+ # def rotate(a); end
116
+ #
117
+ # # Returns a point scaled from the origin.
118
+ # # @param sx [Numeric] x scale factor
119
+ # # @param sy [Numeric, Sevgi::Undefined] y scale factor, defaulting to sx
120
+ # # @return [Sevgi::Geometry::Point]
121
+ # # @raise [Sevgi::Geometry::Error] when a scale is not a finite real number
122
+ # def scale(sx, sy = Undefined); end
123
+ #
124
+ # # Returns a point skewed from the origin.
125
+ # # @param ax [Numeric] x-axis skew angle in degrees
126
+ # # @param ay [Numeric, Sevgi::Undefined] y-axis skew angle in degrees, defaulting to ax
127
+ # # @return [Sevgi::Geometry::Point]
128
+ # # @raise [Sevgi::Geometry::Error] when an angle is not a finite real number
129
+ # def skew(ax, ay = Undefined); end
130
+ #
131
+ # # Returns a point skewed along x.
132
+ # # @param a [Numeric] skew angle in degrees
133
+ # # @return [Sevgi::Geometry::Point]
134
+ # # @raise [Sevgi::Geometry::Error] when angle is not a finite real number
135
+ # def skew_x(a); end
136
+ #
137
+ # # Returns a point skewed along y.
138
+ # # @param a [Numeric] skew angle in degrees
139
+ # # @return [Sevgi::Geometry::Point]
140
+ # # @raise [Sevgi::Geometry::Error] when angle is not a finite real number
141
+ # def skew_y(a); end
142
+ #
143
+ # # Returns a translated point.
144
+ # # @param dx [Numeric] x offset
145
+ # # @param dy [Numeric, Sevgi::Undefined] y offset, defaulting to dx
146
+ # # @return [Sevgi::Geometry::Point]
147
+ # # @raise [Sevgi::Geometry::Error] when an offset is not a finite real number
148
+ # def translate(dx, dy = Undefined); end
149
+ # end
53
150
  Point = Data.define(:x, :y) do
54
151
  include Comparable
55
152
  include Affinity
@@ -104,10 +201,13 @@ module Sevgi
104
201
  def initialize(x:, y:) = super(x: Real[:x, x], y: Real[:y, y])
105
202
 
106
203
  # Compares points by x, then y.
107
- # @param other [Sevgi::Geometry::Point, Array<Numeric>] point to compare
108
- # @return [Integer, nil]
109
- # @raise [Sevgi::Geometry::Error] when other cannot be coerced
110
- def <=>(other) = deconstruct <=> Tuple[Point, other].deconstruct
204
+ # @param other [Object] point or two-item coordinate array to compare
205
+ # @return [Integer, nil] comparison result, or nil when other is not a valid point value
206
+ def <=>(other)
207
+ deconstruct <=> Tuple[Point, other].deconstruct
208
+ rescue Error
209
+ nil
210
+ end
111
211
 
112
212
  # Reports whether this point is at or above another point in screen coordinates.
113
213
  # @param other [Sevgi::Geometry::Point, Array<Numeric>] point to compare
@@ -165,6 +265,8 @@ module Sevgi
165
265
  alias_method :==, :eql?
166
266
  end
167
267
 
268
+ private_constant :Affinity
269
+
168
270
  # Origin point in SVG/screen coordinates.
169
271
  Origin = Point.origin
170
272
  end
@@ -2,10 +2,31 @@
2
2
 
3
3
  module Sevgi
4
4
  module Geometry
5
- # Immutable polar segment in SVG/screen coordinates.
5
+ # Immutable polar displacement in SVG/screen coordinates.
6
6
  #
7
- # `length` is a distance and `angle` is a clockwise angle in degrees.
8
- # Use `Segment[length, angle]` to create a segment from polar components.
7
+ # A Segment has no position: `length` is a distance and `angle` is a
8
+ # clockwise direction. Use {#ending} to apply it to a starting point or
9
+ # {#line} when a placed, finite line is required. `Segment[length, angle]`
10
+ # starts from polar components; `Segment.(starting, ending)` derives them
11
+ # from two points.
12
+ # @example Derive polar components from two points
13
+ # segment = Sevgi::Geometry::Segment.([1, 2], [4, 6])
14
+ # segment.length # => 5.0
15
+ # segment.ending([1, 2]).deconstruct # => [4.0, 6.0]
16
+ # @example Use a cardinal direction
17
+ # Sevgi::Geometry::Segment.upward(3).ending([5, 5]).deconstruct # => [5.0, 2.0]
18
+ # @see Sevgi::Geometry::Line
19
+ # @!parse
20
+ # class Segment
21
+ # # Creates a segment from polar components.
22
+ # # @param length [Numeric] non-negative segment length
23
+ # # @param angle [Numeric] clockwise angle in degrees
24
+ # # @return [Sevgi::Geometry::Segment]
25
+ # # @raise [Sevgi::Geometry::Error] when a component is not finite or length is negative
26
+ # # @example Create a segment with mathematical notation
27
+ # # Sevgi::Geometry::Segment[5, 30]
28
+ # def self.[](length, angle); end
29
+ # end
9
30
  Segment = Data.define(:length, :angle) do
10
31
  include Comparable
11
32
 
@@ -56,9 +77,15 @@ module Sevgi
56
77
  def self.upward(length) = self[length, -90.0]
57
78
 
58
79
  class << self
59
- # @return [Sevgi::Geometry::Segment]
80
+ # @overload horizontal(length)
81
+ # Returns a rightward segment.
82
+ # @param length [Numeric] segment length
83
+ # @return [Sevgi::Geometry::Segment]
60
84
  alias_method :horizontal, :rightward
61
- # @return [Sevgi::Geometry::Segment]
85
+ # @overload vertical(length)
86
+ # Returns a downward segment.
87
+ # @param length [Numeric] segment length
88
+ # @return [Sevgi::Geometry::Segment]
62
89
  alias_method :vertical, :downward
63
90
  end
64
91
 
@@ -66,14 +93,22 @@ module Sevgi
66
93
  # @param length [Numeric] segment length
67
94
  # @param angle [Numeric] clockwise angle in degrees
68
95
  # @return [void]
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])
96
+ # @raise [Sevgi::Geometry::Error] when a component is not finite or length is negative
97
+ def initialize(length:, angle:)
98
+ length = Real[:length, length]
99
+ Error.("Segment length cannot be negative") if length.negative?
100
+
101
+ super(length:, angle: Real[:angle, angle])
102
+ end
71
103
 
72
104
  # Compares segments by length.
73
- # @param other [Sevgi::Geometry::Segment, Array<Numeric>] segment to compare
74
- # @return [Integer, nil]
75
- # @raise [Sevgi::Geometry::Error] when other cannot be coerced
76
- def <=>(other) = length <=> Tuple[Segment, other].length
105
+ # @param other [Object] segment or two-item length/angle array to compare
106
+ # @return [Integer, nil] comparison result, or nil when other is not a valid segment value
107
+ def <=>(other)
108
+ length <=> Tuple[Segment, other].length
109
+ rescue Error
110
+ nil
111
+ end
77
112
 
78
113
  # Returns a segment rounded to precision.
79
114
  # @param precision [Integer, nil] decimal precision, or nil for the current function default
@@ -121,7 +156,35 @@ module Sevgi
121
156
  def y = length * F.sin(angle)
122
157
  end
123
158
 
124
- # Lightweight polar value used where a plain length/angle tuple is enough.
125
- Polar = Data.define(:length, :angle)
159
+ # Immutable length/angle constraint used when a full segment is not implied.
160
+ #
161
+ # @!attribute [r] length
162
+ # @return [Float] non-negative target measure
163
+ # @!attribute [r] angle
164
+ # @return [Float] direction used to derive a segment
165
+ # @!parse
166
+ # class LengthAngle
167
+ # # Creates a length-and-angle constraint.
168
+ # # @param length [Numeric] finite non-negative target width or height
169
+ # # @param angle [Numeric] finite direction in degrees
170
+ # # @return [Sevgi::Geometry::LengthAngle]
171
+ # # @raise [Sevgi::Geometry::Error] when a component is not finite or length is negative
172
+ # # @example Create a constraint with mathematical notation
173
+ # # Sevgi::Geometry::LengthAngle[3, 90]
174
+ # def self.[](length, angle); end
175
+ # end
176
+ LengthAngle = Data.define(:length, :angle) do
177
+ # Creates a target-measure constraint.
178
+ # @param length [Numeric] finite non-negative target width or height
179
+ # @param angle [Numeric] finite direction in degrees
180
+ # @return [void]
181
+ # @raise [Sevgi::Geometry::Error] when a component is not finite or length is negative
182
+ def initialize(length:, angle:)
183
+ length = Real[:length, length]
184
+ Error.("LengthAngle length cannot be negative") if length.negative?
185
+
186
+ super(length:, angle: Real[:angle, angle])
187
+ end
188
+ end
126
189
  end
127
190
  end
@@ -3,6 +3,6 @@
3
3
  module Sevgi
4
4
  module Geometry
5
5
  # Component version.
6
- VERSION = "0.95.0"
6
+ VERSION = "0.98.2"
7
7
  end
8
8
  end
@@ -14,10 +14,33 @@ require_relative "geometry/operation"
14
14
  require_relative "geometry/version"
15
15
 
16
16
  module Sevgi
17
- # Screen-space geometry primitives used by Sevgi layout and drawing helpers.
17
+ # Immutable screen-space geometry values used by Sevgi layout and drawing helpers.
18
18
  #
19
19
  # Coordinates follow SVG screen conventions: +x points right, +y points down,
20
- # and positive angles turn clockwise.
20
+ # and positive angles turn clockwise. Constructors accept Point and Segment
21
+ # objects or their two-number Array forms. Transformations return new values;
22
+ # they do not mutate their receiver.
23
+ #
24
+ # Shape constructors have two complementary notations: `Shape[...]` accepts
25
+ # dimensions or segments, while `Shape.(...)` accepts points. Named factories
26
+ # such as `Rect.from_size` and `Rect.from_corners` expose the same distinction
27
+ # when a call site benefits from spelling it out.
28
+ #
29
+ # Trigonometric construction can retain ordinary floating-point noise. Use
30
+ # `approx` for presentation values and `eq?` for precision-aware comparison;
31
+ # strict `==` intentionally compares the exact immutable value.
32
+ #
33
+ # @example Measure and move a line
34
+ # line = Sevgi::Geometry::Line.([0, 0], [3, 4])
35
+ # line.length #=> 5.0
36
+ # line.translate(2, 1).starting #=> Point[2.0, 1.0]
37
+ # @example Follow SVG screen directions
38
+ # origin = Sevgi::Geometry::Point.origin
39
+ # Sevgi::Geometry::Point.angle(origin, [0, 10]) #=> 90.0
40
+ # origin.translate(0, 10).below?(origin) #=> true
41
+ # @see Sevgi::Geometry::Element::Lined
42
+ # @see Sevgi::Geometry::Operation
43
+ # @see https://sevgi.roktas.dev/geometry/ Geometry guide
21
44
  module Geometry
22
45
  end
23
46
  end
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.95.0
4
+ version: 0.98.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Recai Oktaş
@@ -15,15 +15,15 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.95.0
18
+ version: 0.98.2
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.95.0
26
- description: Enhances the Sevgi toolkit with geometry objects and methods.
25
+ version: 0.98.2
26
+ description: Models the points, lines, shapes, and transforms used by the DSL.
27
27
  email: roktas@gmail.com
28
28
  executables: []
29
29
  extensions: []
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 4.0.11
76
+ rubygems_version: 4.0.16
77
77
  specification_version: 4
78
- summary: Tiny library for geometric computations.
78
+ summary: Geometry values and operations for Sevgi drawings.
79
79
  test_files: []