sevgi-geometry 0.73.2 → 0.94.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 +4 -0
- data/LICENSE +5 -0
- data/README.md +37 -0
- data/lib/sevgi/geometry/element.rb +292 -46
- data/lib/sevgi/geometry/elements/line.rb +71 -15
- data/lib/sevgi/geometry/elements/parallelogram.rb +59 -0
- data/lib/sevgi/geometry/elements/polygon.rb +7 -1
- data/lib/sevgi/geometry/elements/polyline.rb +7 -1
- data/lib/sevgi/geometry/elements/rect.rb +88 -8
- data/lib/sevgi/geometry/elements/triangle.rb +47 -0
- data/lib/sevgi/geometry/equation/linear.rb +152 -9
- data/lib/sevgi/geometry/equation/quadratic.rb +10 -1
- data/lib/sevgi/geometry/equation.rb +50 -9
- data/lib/sevgi/geometry/errors.rb +1 -0
- data/lib/sevgi/geometry/internal.rb +36 -2
- data/lib/sevgi/geometry/operation/align.rb +37 -9
- data/lib/sevgi/geometry/operation/sweep.rb +86 -8
- data/lib/sevgi/geometry/operation.rb +71 -0
- data/lib/sevgi/geometry/point.rb +106 -8
- data/lib/sevgi/geometry/segment.rb +90 -15
- data/lib/sevgi/geometry/version.rb +2 -1
- data/lib/sevgi/geometry.rb +9 -0
- metadata +8 -9
- 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
- data/lib/sevgi/geometry/elements/parm.rb +0 -37
- data/lib/sevgi/geometry/elements/tri.rb +0 -18
|
@@ -2,59 +2,134 @@
|
|
|
2
2
|
|
|
3
3
|
module Sevgi
|
|
4
4
|
module Geometry
|
|
5
|
+
# Immutable polar segment in SVG/screen coordinates.
|
|
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.
|
|
5
9
|
Segment = Data.define(:length, :angle) do
|
|
6
10
|
include Comparable
|
|
7
11
|
|
|
12
|
+
# @!attribute [r] length
|
|
13
|
+
# @return [Float] segment length
|
|
14
|
+
# @!attribute [r] angle
|
|
15
|
+
# @return [Float] clockwise angle in degrees
|
|
16
|
+
|
|
17
|
+
# Creates a segment from start and end points.
|
|
18
|
+
# @param starting [Sevgi::Geometry::Point, Array<Numeric>] start point
|
|
19
|
+
# @param ending [Sevgi::Geometry::Point, Array<Numeric>] end point
|
|
20
|
+
# @return [Sevgi::Geometry::Segment]
|
|
21
|
+
# @raise [Sevgi::Geometry::Error] when either point cannot be coerced
|
|
8
22
|
def self.call(starting, ending)
|
|
9
23
|
starting, ending = Tuples[Point, starting, ending]
|
|
10
24
|
self[Point.length(starting, ending), Point.angle(starting, ending)]
|
|
11
25
|
end
|
|
12
26
|
|
|
27
|
+
# Compares two segments with optional numeric precision.
|
|
28
|
+
# @param this [Sevgi::Geometry::Segment, Array<Numeric>] first segment
|
|
29
|
+
# @param that [Sevgi::Geometry::Segment, Array<Numeric>] second segment
|
|
30
|
+
# @param precision [Integer, nil] decimal precision, or nil for the current function default
|
|
31
|
+
# @return [Boolean]
|
|
32
|
+
# @raise [Sevgi::Geometry::Error] when either segment cannot be coerced
|
|
13
33
|
def self.eq?(this, that, precision: nil)
|
|
14
34
|
this, that = Tuples[self, this, that]
|
|
15
35
|
F.eq?(this.length, that.length, precision:) && F.eq?(this.angle, that.angle, precision:)
|
|
16
36
|
end
|
|
17
37
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def self.
|
|
22
|
-
|
|
23
|
-
|
|
38
|
+
# Returns a downward segment.
|
|
39
|
+
# @param length [Numeric] segment length
|
|
40
|
+
# @return [Sevgi::Geometry::Segment]
|
|
41
|
+
def self.downward(length) = self[length, 90.0]
|
|
42
|
+
|
|
43
|
+
# Returns a leftward segment.
|
|
44
|
+
# @param length [Numeric] segment length
|
|
45
|
+
# @return [Sevgi::Geometry::Segment]
|
|
46
|
+
def self.leftward(length) = self[length, 180.0]
|
|
47
|
+
|
|
48
|
+
# Returns a rightward segment.
|
|
49
|
+
# @param length [Numeric] segment length
|
|
50
|
+
# @return [Sevgi::Geometry::Segment]
|
|
51
|
+
def self.rightward(length) = self[length, 0.0]
|
|
52
|
+
|
|
53
|
+
# Returns an upward segment.
|
|
54
|
+
# @param length [Numeric] segment length
|
|
55
|
+
# @return [Sevgi::Geometry::Segment]
|
|
56
|
+
def self.upward(length) = self[length, -90.0]
|
|
57
|
+
|
|
58
|
+
class << self
|
|
59
|
+
# @return [Sevgi::Geometry::Segment]
|
|
60
|
+
alias_method :horizontal, :rightward
|
|
61
|
+
# @return [Sevgi::Geometry::Segment]
|
|
62
|
+
alias_method :vertical, :downward
|
|
63
|
+
end
|
|
24
64
|
|
|
65
|
+
# Creates a segment.
|
|
66
|
+
# @param length [Numeric] segment length
|
|
67
|
+
# @param angle [Numeric] clockwise angle in degrees
|
|
68
|
+
# @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])
|
|
71
|
+
|
|
72
|
+
# 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
|
|
25
76
|
def <=>(other) = (other = Tuple[Segment, other]).nan? || nan? ? nil : length <=> other.length
|
|
26
77
|
|
|
78
|
+
# Returns a segment rounded to precision.
|
|
79
|
+
# @param precision [Integer, nil] decimal precision, or nil for the current function default
|
|
80
|
+
# @return [Sevgi::Geometry::Segment]
|
|
27
81
|
def approx(precision = nil) = with(length: F.approx(length, precision), angle: F.approx(angle, precision))
|
|
28
82
|
|
|
29
|
-
|
|
30
|
-
|
|
83
|
+
# Returns the endpoint reached from a starting point.
|
|
84
|
+
# @param starting [Sevgi::Geometry::Point, Array<Numeric>] start point
|
|
85
|
+
# @return [Sevgi::Geometry::Point]
|
|
86
|
+
# @raise [Sevgi::Geometry::Error] when starting cannot be coerced
|
|
31
87
|
def ending(starting) = Tuple[Point, starting].translate(x, y)
|
|
32
88
|
|
|
89
|
+
# Compares this segment with optional numeric precision.
|
|
90
|
+
# @param other [Sevgi::Geometry::Segment, Array<Numeric>] segment to compare
|
|
91
|
+
# @param precision [Integer, nil] decimal precision, or nil for the current function default
|
|
92
|
+
# @return [Boolean]
|
|
93
|
+
# @raise [Sevgi::Geometry::Error] when other cannot be coerced
|
|
33
94
|
def eq?(other, precision: nil) = self.class.eq?(self, other, precision:)
|
|
34
95
|
|
|
96
|
+
# Reports strict segment equality.
|
|
97
|
+
# @param other [Object] object to compare
|
|
98
|
+
# @return [Boolean]
|
|
35
99
|
def eql?(other) = self.class == other.class && deconstruct == other.deconstruct
|
|
36
100
|
|
|
101
|
+
# Returns a hash compatible with strict equality.
|
|
102
|
+
# @return [Integer]
|
|
37
103
|
def hash = [self.class, *deconstruct].hash
|
|
38
104
|
|
|
105
|
+
# Reports whether any component is infinite.
|
|
106
|
+
# @return [Boolean]
|
|
39
107
|
def infinite? = deconstruct.any?(&:infinite?)
|
|
40
108
|
|
|
109
|
+
# Converts the segment into a line at a point.
|
|
110
|
+
# @param point [Sevgi::Geometry::Point, Array<Numeric>] line start point
|
|
111
|
+
# @return [Sevgi::Geometry::Line]
|
|
112
|
+
# @raise [Sevgi::Geometry::Error] when point cannot be coerced
|
|
41
113
|
def line(point = Origin) = Line[length, angle, position: Tuple[Point, point]]
|
|
42
114
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def ly = y.abs
|
|
46
|
-
|
|
115
|
+
# Reports whether any component is NaN.
|
|
116
|
+
# @return [Boolean]
|
|
47
117
|
def nan? = deconstruct.any?(&:nan?)
|
|
48
118
|
|
|
119
|
+
# Returns the opposite segment.
|
|
120
|
+
# @return [Sevgi::Geometry::Segment]
|
|
49
121
|
def reverse = with(angle: angle + 180.0)
|
|
50
122
|
|
|
51
|
-
|
|
52
|
-
|
|
123
|
+
# Returns the x component of the segment.
|
|
124
|
+
# @return [Float]
|
|
53
125
|
def x = length * F.cos(angle)
|
|
54
126
|
|
|
127
|
+
# Returns the y component of the segment.
|
|
128
|
+
# @return [Float]
|
|
55
129
|
def y = length * F.sin(angle)
|
|
56
130
|
end
|
|
57
131
|
|
|
58
|
-
|
|
132
|
+
# Lightweight polar value used where a plain length/angle tuple is enough.
|
|
133
|
+
Polar = Data.define(:length, :angle)
|
|
59
134
|
end
|
|
60
135
|
end
|
data/lib/sevgi/geometry.rb
CHANGED
|
@@ -12,3 +12,12 @@ require_relative "geometry/equation"
|
|
|
12
12
|
require_relative "geometry/operation"
|
|
13
13
|
|
|
14
14
|
require_relative "geometry/version"
|
|
15
|
+
|
|
16
|
+
module Sevgi
|
|
17
|
+
# Screen-space geometry primitives used by Sevgi layout and drawing helpers.
|
|
18
|
+
#
|
|
19
|
+
# Coordinates follow SVG screen conventions: +x points right, +y points down,
|
|
20
|
+
# and positive angles turn clockwise.
|
|
21
|
+
module Geometry
|
|
22
|
+
end
|
|
23
|
+
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.
|
|
4
|
+
version: 0.94.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Recai Oktaş
|
|
@@ -15,32 +15,31 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.94.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.94.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
|
-
- lib/sevgi/geometry/elements/
|
|
38
|
+
- lib/sevgi/geometry/elements/parallelogram.rb
|
|
40
39
|
- lib/sevgi/geometry/elements/polygon.rb
|
|
41
40
|
- lib/sevgi/geometry/elements/polyline.rb
|
|
42
41
|
- lib/sevgi/geometry/elements/rect.rb
|
|
43
|
-
- lib/sevgi/geometry/elements/
|
|
42
|
+
- lib/sevgi/geometry/elements/triangle.rb
|
|
44
43
|
- lib/sevgi/geometry/equation.rb
|
|
45
44
|
- lib/sevgi/geometry/equation/linear.rb
|
|
46
45
|
- lib/sevgi/geometry/equation/quadratic.rb
|
|
@@ -67,7 +66,7 @@ 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
|
- - ">="
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Parallelogram
|
|
4
|
-
|
|
5
|
-
module Sevgi
|
|
6
|
-
module Geometry
|
|
7
|
-
class Parm < Element.lined(4)
|
|
8
|
-
def self.[](horizontal, vertical, position: Origin)
|
|
9
|
-
horizontal, vertical = Tuples[Segment, horizontal, vertical]
|
|
10
|
-
|
|
11
|
-
new_by_segments(horizontal, vertical.reverse, horizontal.reverse, vertical, position:)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.new_by_height(horizontal:, tallness:, position: Origin)
|
|
15
|
-
horizontal = Tuple[Segment, horizontal]
|
|
16
|
-
tallness = Tuple[LengthAngle, tallness]
|
|
17
|
-
|
|
18
|
-
height = tallness.length - horizontal.ly
|
|
19
|
-
angle = tallness.angle
|
|
20
|
-
length = height / F.sin(angle)
|
|
21
|
-
|
|
22
|
-
self[horizontal, Segment[length, angle], position:]
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.new_by_width(vertical:, wideness:, position: Origin)
|
|
26
|
-
vertical = Tuple[Segment, vertical]
|
|
27
|
-
wideness = Tuple[LengthAngle, wideness]
|
|
28
|
-
|
|
29
|
-
width = wideness.length - vertical.lx
|
|
30
|
-
angle = wideness.angle
|
|
31
|
-
length = width / F.cos(angle)
|
|
32
|
-
|
|
33
|
-
self[Segment[length, angle], vertical, position:]
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Sevgi
|
|
4
|
-
module Geometry
|
|
5
|
-
class Tri < Element.lined(3)
|
|
6
|
-
def self.[](segment_a, segment_b, position: Origin)
|
|
7
|
-
a, b = Tuples[Segment, segment_a, segment_b]
|
|
8
|
-
|
|
9
|
-
length = ::Math.sqrt((a.length ** 2) + (b.length ** 2) - (2 * a.length * b.length * F.cos(b.sup - a.angle)))
|
|
10
|
-
angle = b.sup + F.asin(a.length * F.sin(b.sup - a.angle) / length)
|
|
11
|
-
|
|
12
|
-
c = Segment[length, angle]
|
|
13
|
-
|
|
14
|
-
new_by_segments(a, b, c, position:)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|