Class: Sevgi::Geometry::Line
- Inherits:
-
LineBase
- Object
- Sevgi::Geometry::Line
- Defined in:
- lib/sevgi/geometry/elements/line.rb,
lib/sevgi/geometry/equation.rb
Overview
Instance Attribute Summary collapse
-
#A ⇒ Sevgi::Geometry::Point
readonly
Starting point.
-
#AB ⇒ Sevgi::Geometry::Line
readonly
Line from A to B.
-
#B ⇒ Sevgi::Geometry::Point
readonly
Ending point.
Class Method Summary collapse
-
.[](length, angle, position: Origin) ⇒ Sevgi::Geometry::Line
Builds a line from length and angle.
-
.call(starting, ending) ⇒ Sevgi::Geometry::Line
Builds a line from two endpoints.
-
.from_length_angle(length, angle, position: Origin) ⇒ Sevgi::Geometry::Line
Builds a line from length and angle.
-
.from_points(starting, ending) ⇒ Sevgi::Geometry::Line
Builds a line from two endpoints.
Instance Method Summary collapse
-
#angle ⇒ Float
Returns the clockwise line angle in degrees.
-
#ending ⇒ Sevgi::Geometry::Point
Returns the ending point.
-
#equation ⇒ Sevgi::Geometry::Equation::Linear
Returns the linear equation containing this line.
- #left?(point) ⇒ Boolean
-
#over?(point) ⇒ Boolean
Reports whether a point lies on the finite line segment.
- #right?(point) ⇒ Boolean
-
#shift(distance) ⇒ Sevgi::Geometry::Line
Returns a parallel line shifted by a signed perpendicular offset.
-
#starting ⇒ Sevgi::Geometry::Point
Returns the starting point.
Instance Attribute Details
#A ⇒ Sevgi::Geometry::Point (readonly)
Returns starting point.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/sevgi/geometry/elements/line.rb', line 36 class Line < LineBase # @overload [](length, angle, position: Origin) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line[5, 30] == Sevgi::Geometry::Line.from_length_angle(5, 30) def self.[](length, angle, position: Origin) = new_by_segments(Segment[length, angle], position:) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values def self.from_length_angle(length, angle, position: Origin) = self[length, angle, position:] # @overload from_points(starting, ending) # Builds a line from two endpoints. # @param starting [Sevgi::Geometry::Point, Array<Numeric>] starting point # @param ending [Sevgi::Geometry::Point, Array<Numeric>] ending point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when either point cannot be coerced # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line.([0, 0], [3, 4]) == Sevgi::Geometry::Line.from_points([0, 0], [3, 4]) def self.from_points(...) = call(...) private_class_method :from_segments # Returns the clockwise line angle in degrees. # @return [Float] def angle = head.angle # Returns the ending point. # @return [Sevgi::Geometry::Point] def ending = points.last # Reports whether a point is left of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def left?(point) = F.lt?(side(point), 0.0) # Reports whether a point is right of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def right?(point) = F.gt?(side(point), 0.0) # Returns the starting point. # @return [Sevgi::Geometry::Point] def starting = points.first # Draws the line into a graphics node. # @param node [Object] graphics node receiving the drawing command # @return [Object] graphics node command result def draw!(node, **) = node.LineTo(x1: position.x, y1: position.y, x2: ending.x, y2: ending.y, **) private :draw! # Reports whether a point lies on the finite line segment. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def over?(point) point = Tuple[Point, point] within_range?(point) && equation.on?(point) end # Returns a parallel line shifted by a signed perpendicular offset. # Positive distance moves to the directed line's left in screen coordinates; reversing the endpoints reverses the # shift direction. # @param distance [Numeric] signed perpendicular offset # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when distance is not a finite real number def shift(distance) distance = Real[:distance, distance] translate(distance * F.sin(angle), -distance * F.cos(angle)) end private def cross(ax, ay, bx, by) = (ax * by) - (ay * bx) def delta(from, to) = [to.x - from.x, to.y - from.y] def side(point) point = Tuple[Point, point] cross(*delta(starting, ending), *delta(starting, point)) end def within_range?(point) point = point.approx points = [starting.approx, ending.approx] point.between?(points.min, points.max) end end |
#AB ⇒ Sevgi::Geometry::Line (readonly)
Returns line from A to B.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/sevgi/geometry/elements/line.rb', line 36 class Line < LineBase # @overload [](length, angle, position: Origin) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line[5, 30] == Sevgi::Geometry::Line.from_length_angle(5, 30) def self.[](length, angle, position: Origin) = new_by_segments(Segment[length, angle], position:) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values def self.from_length_angle(length, angle, position: Origin) = self[length, angle, position:] # @overload from_points(starting, ending) # Builds a line from two endpoints. # @param starting [Sevgi::Geometry::Point, Array<Numeric>] starting point # @param ending [Sevgi::Geometry::Point, Array<Numeric>] ending point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when either point cannot be coerced # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line.([0, 0], [3, 4]) == Sevgi::Geometry::Line.from_points([0, 0], [3, 4]) def self.from_points(...) = call(...) private_class_method :from_segments # Returns the clockwise line angle in degrees. # @return [Float] def angle = head.angle # Returns the ending point. # @return [Sevgi::Geometry::Point] def ending = points.last # Reports whether a point is left of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def left?(point) = F.lt?(side(point), 0.0) # Reports whether a point is right of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def right?(point) = F.gt?(side(point), 0.0) # Returns the starting point. # @return [Sevgi::Geometry::Point] def starting = points.first # Draws the line into a graphics node. # @param node [Object] graphics node receiving the drawing command # @return [Object] graphics node command result def draw!(node, **) = node.LineTo(x1: position.x, y1: position.y, x2: ending.x, y2: ending.y, **) private :draw! # Reports whether a point lies on the finite line segment. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def over?(point) point = Tuple[Point, point] within_range?(point) && equation.on?(point) end # Returns a parallel line shifted by a signed perpendicular offset. # Positive distance moves to the directed line's left in screen coordinates; reversing the endpoints reverses the # shift direction. # @param distance [Numeric] signed perpendicular offset # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when distance is not a finite real number def shift(distance) distance = Real[:distance, distance] translate(distance * F.sin(angle), -distance * F.cos(angle)) end private def cross(ax, ay, bx, by) = (ax * by) - (ay * bx) def delta(from, to) = [to.x - from.x, to.y - from.y] def side(point) point = Tuple[Point, point] cross(*delta(starting, ending), *delta(starting, point)) end def within_range?(point) point = point.approx points = [starting.approx, ending.approx] point.between?(points.min, points.max) end end |
#B ⇒ Sevgi::Geometry::Point (readonly)
Returns ending point.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/sevgi/geometry/elements/line.rb', line 36 class Line < LineBase # @overload [](length, angle, position: Origin) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line[5, 30] == Sevgi::Geometry::Line.from_length_angle(5, 30) def self.[](length, angle, position: Origin) = new_by_segments(Segment[length, angle], position:) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values def self.from_length_angle(length, angle, position: Origin) = self[length, angle, position:] # @overload from_points(starting, ending) # Builds a line from two endpoints. # @param starting [Sevgi::Geometry::Point, Array<Numeric>] starting point # @param ending [Sevgi::Geometry::Point, Array<Numeric>] ending point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when either point cannot be coerced # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line.([0, 0], [3, 4]) == Sevgi::Geometry::Line.from_points([0, 0], [3, 4]) def self.from_points(...) = call(...) private_class_method :from_segments # Returns the clockwise line angle in degrees. # @return [Float] def angle = head.angle # Returns the ending point. # @return [Sevgi::Geometry::Point] def ending = points.last # Reports whether a point is left of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def left?(point) = F.lt?(side(point), 0.0) # Reports whether a point is right of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def right?(point) = F.gt?(side(point), 0.0) # Returns the starting point. # @return [Sevgi::Geometry::Point] def starting = points.first # Draws the line into a graphics node. # @param node [Object] graphics node receiving the drawing command # @return [Object] graphics node command result def draw!(node, **) = node.LineTo(x1: position.x, y1: position.y, x2: ending.x, y2: ending.y, **) private :draw! # Reports whether a point lies on the finite line segment. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def over?(point) point = Tuple[Point, point] within_range?(point) && equation.on?(point) end # Returns a parallel line shifted by a signed perpendicular offset. # Positive distance moves to the directed line's left in screen coordinates; reversing the endpoints reverses the # shift direction. # @param distance [Numeric] signed perpendicular offset # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when distance is not a finite real number def shift(distance) distance = Real[:distance, distance] translate(distance * F.sin(angle), -distance * F.cos(angle)) end private def cross(ax, ay, bx, by) = (ax * by) - (ay * bx) def delta(from, to) = [to.x - from.x, to.y - from.y] def side(point) point = Tuple[Point, point] cross(*delta(starting, ending), *delta(starting, point)) end def within_range?(point) point = point.approx points = [starting.approx, ending.approx] point.between?(points.min, points.max) end end |
Class Method Details
.[](length, angle, position: Origin) ⇒ Sevgi::Geometry::Line
46 |
# File 'lib/sevgi/geometry/elements/line.rb', line 46 def self.[](length, angle, position: Origin) = new_by_segments(Segment[length, angle], position:) |
.call(starting, ending) ⇒ Sevgi::Geometry::Line
Builds a line from two endpoints.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/sevgi/geometry/elements/line.rb', line 36 class Line < LineBase # @overload [](length, angle, position: Origin) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line[5, 30] == Sevgi::Geometry::Line.from_length_angle(5, 30) def self.[](length, angle, position: Origin) = new_by_segments(Segment[length, angle], position:) # Builds a line from length and angle. # @param length [Numeric] line length # @param angle [Numeric] clockwise angle in degrees # @param position [Sevgi::Geometry::Point, Array<Numeric>] starting point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when length, angle, or position cannot be coerced to finite geometry values def self.from_length_angle(length, angle, position: Origin) = self[length, angle, position:] # @overload from_points(starting, ending) # Builds a line from two endpoints. # @param starting [Sevgi::Geometry::Point, Array<Numeric>] starting point # @param ending [Sevgi::Geometry::Point, Array<Numeric>] ending point # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when either point cannot be coerced # @example Mathematical notation and English convenience are equivalent # Sevgi::Geometry::Line.([0, 0], [3, 4]) == Sevgi::Geometry::Line.from_points([0, 0], [3, 4]) def self.from_points(...) = call(...) private_class_method :from_segments # Returns the clockwise line angle in degrees. # @return [Float] def angle = head.angle # Returns the ending point. # @return [Sevgi::Geometry::Point] def ending = points.last # Reports whether a point is left of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def left?(point) = F.lt?(side(point), 0.0) # Reports whether a point is right of the directed line from {#starting} to {#ending} in screen coordinates. # Points on the infinite line are on neither side. A zero-length line has no direction and returns false. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def right?(point) = F.gt?(side(point), 0.0) # Returns the starting point. # @return [Sevgi::Geometry::Point] def starting = points.first # Draws the line into a graphics node. # @param node [Object] graphics node receiving the drawing command # @return [Object] graphics node command result def draw!(node, **) = node.LineTo(x1: position.x, y1: position.y, x2: ending.x, y2: ending.y, **) private :draw! # Reports whether a point lies on the finite line segment. # @param point [Sevgi::Geometry::Point, Array<Numeric>] point to test # @return [Boolean] # @raise [Sevgi::Geometry::Error] when point cannot be coerced def over?(point) point = Tuple[Point, point] within_range?(point) && equation.on?(point) end # Returns a parallel line shifted by a signed perpendicular offset. # Positive distance moves to the directed line's left in screen coordinates; reversing the endpoints reverses the # shift direction. # @param distance [Numeric] signed perpendicular offset # @return [Sevgi::Geometry::Line] # @raise [Sevgi::Geometry::Error] when distance is not a finite real number def shift(distance) distance = Real[:distance, distance] translate(distance * F.sin(angle), -distance * F.cos(angle)) end private def cross(ax, ay, bx, by) = (ax * by) - (ay * bx) def delta(from, to) = [to.x - from.x, to.y - from.y] def side(point) point = Tuple[Point, point] cross(*delta(starting, ending), *delta(starting, point)) end def within_range?(point) point = point.approx points = [starting.approx, ending.approx] point.between?(points.min, points.max) end end |
.from_length_angle(length, angle, position: Origin) ⇒ Sevgi::Geometry::Line
Builds a line from length and angle.
54 |
# File 'lib/sevgi/geometry/elements/line.rb', line 54 def self.from_length_angle(length, angle, position: Origin) = self[length, angle, position:] |
.from_points(starting, ending) ⇒ Sevgi::Geometry::Line
64 |
# File 'lib/sevgi/geometry/elements/line.rb', line 64 def self.from_points(...) = call(...) |
Instance Method Details
#angle ⇒ Float
Returns the clockwise line angle in degrees.
70 |
# File 'lib/sevgi/geometry/elements/line.rb', line 70 def angle = head.angle |
#ending ⇒ Sevgi::Geometry::Point
Returns the ending point.
74 |
# File 'lib/sevgi/geometry/elements/line.rb', line 74 def ending = points.last |
#equation ⇒ Sevgi::Geometry::Equation::Linear
Returns the linear equation containing this line.
131 |
# File 'lib/sevgi/geometry/equation.rb', line 131 def equation = position.equation(angle) |
#left?(point) ⇒ Boolean
81 |
# File 'lib/sevgi/geometry/elements/line.rb', line 81 def left?(point) = F.lt?(side(point), 0.0) |
#over?(point) ⇒ Boolean
Reports whether a point lies on the finite line segment.
105 106 107 108 109 |
# File 'lib/sevgi/geometry/elements/line.rb', line 105 def over?(point) point = Tuple[Point, point] within_range?(point) && equation.on?(point) end |
#right?(point) ⇒ Boolean
88 |
# File 'lib/sevgi/geometry/elements/line.rb', line 88 def right?(point) = F.gt?(side(point), 0.0) |
#shift(distance) ⇒ Sevgi::Geometry::Line
Returns a parallel line shifted by a signed perpendicular offset. Positive distance moves to the directed line's left in screen coordinates; reversing the endpoints reverses the shift direction.
117 118 119 120 |
# File 'lib/sevgi/geometry/elements/line.rb', line 117 def shift(distance) distance = Real[:distance, distance] translate(distance * F.sin(angle), -distance * F.cos(angle)) end |
#starting ⇒ Sevgi::Geometry::Point
Returns the starting point.
92 |
# File 'lib/sevgi/geometry/elements/line.rb', line 92 def starting = points.first |