Class: Sevgi::Geometry::Triangle
- Inherits:
-
TriangleBase
- Object
- Sevgi::Geometry::Triangle
- Defined in:
- lib/sevgi/geometry/elements/triangle.rb
Overview
Closed three-sided element built from non-collinear segments or points. Every construction path rejects degenerate triangles; affine operations retain Triangle when the transformed points remain non-degenerate.
Instance Attribute Summary collapse
-
#A ⇒ Sevgi::Geometry::Point
readonly
First vertex.
-
#AB ⇒ Sevgi::Geometry::Line
readonly
Side from A to B.
-
#B ⇒ Sevgi::Geometry::Point
readonly
Second vertex.
-
#BC ⇒ Sevgi::Geometry::Line
readonly
Side from B to C.
-
#C ⇒ Sevgi::Geometry::Point
readonly
Third vertex.
-
#CA ⇒ Sevgi::Geometry::Line
readonly
Side from C to A.
Class Method Summary collapse
-
.[](segment_a, segment_b, position: Origin) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from two adjacent segments.
-
.call(*points) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from three boundary points.
-
.from_points(*points) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from three boundary points.
-
.from_segments(segment_a, segment_b, position: Origin) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from two adjacent segments and derives the closing side.
Instance Method Summary collapse
-
#perimeter ⇒ Float
Returns the closed path perimeter.
Instance Attribute Details
#A ⇒ Sevgi::Geometry::Point (readonly)
Returns first vertex.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
#AB ⇒ Sevgi::Geometry::Line (readonly)
Returns side from A to B.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
#B ⇒ Sevgi::Geometry::Point (readonly)
Returns second vertex.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
#BC ⇒ Sevgi::Geometry::Line (readonly)
Returns side from B to C.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
#C ⇒ Sevgi::Geometry::Point (readonly)
Returns third vertex.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
#CA ⇒ Sevgi::Geometry::Line (readonly)
Returns side from C to A.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
Class Method Details
.[](segment_a, segment_b, position: Origin) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from two adjacent segments.
The closing segment is the direct vector from the end of segment_b
back to position. Segment order controls orientation; reversing the
inputs returns the corresponding opposite orientation. Zero-length or
collinear inputs are rejected using the current numeric precision.
64 65 66 67 68 69 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 64 def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end |
.call(*points) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from three boundary points.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
.from_points(*points) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from three boundary points.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
.from_segments(segment_a, segment_b, position: Origin) ⇒ Sevgi::Geometry::Triangle
Builds a triangle from two adjacent segments and derives the closing side.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |
Instance Method Details
#perimeter ⇒ Float
Returns the closed path perimeter.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sevgi/geometry/elements/triangle.rb', line 52 class Triangle < TriangleBase # Builds a triangle from two adjacent segments. # # The closing segment is the direct vector from the end of `segment_b` # back to `position`. Segment order controls orientation; reversing the # inputs returns the corresponding opposite orientation. Zero-length or # collinear inputs are rejected using the current numeric precision. # @param segment_a [Sevgi::Geometry::Segment, Array<Numeric>] first segment # @param segment_b [Sevgi::Geometry::Segment, Array<Numeric>] second segment # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Triangle] # @raise [Sevgi::Geometry::Error] when segments or position cannot be coerced, or the segments are degenerate def self.[](segment_a, segment_b, position: Origin) a, b = Tuples[Segment, segment_a, segment_b] validate!(a, b) new_by_segments(a, b, closing_segment(a, b), position:) end class << self private def closing_segment(a, b) Segment.(b.ending(a.ending(Origin)), Origin) end def cross(a, b) = (a.x * b.y) - (a.y * b.x) def validate!(a, b) if F.zero?(a.length) || F.zero?(b.length) || F.zero?(cross(a, b)) Error.("Triangle segments must form a non-degenerate triangle") end end end private def validate_geometry! self.class.send(:validate!, segments[0], segments[1]) end end |