Class: RGeo::Cartesian::Segment
- Inherits:
-
Object
- Object
- RGeo::Cartesian::Segment
- Defined in:
- lib/rgeo/cartesian/calculations.rb
Overview
Represents a line segment in the plane.
Instance Attribute Summary collapse
-
#dx ⇒ Object
readonly
Returns the value of attribute dx.
-
#dy ⇒ Object
readonly
Returns the value of attribute dy.
-
#e ⇒ Object
readonly
Returns the value of attribute e.
-
#s ⇒ Object
readonly
Returns the value of attribute s.
Instance Method Summary collapse
- #contains_point?(point) ⇒ Boolean
- #degenerate? ⇒ Boolean
- #eql?(other) ⇒ Boolean (also: #==)
-
#initialize(start, stop) ⇒ Segment
constructor
:nodoc:.
- #intersects_segment?(seg) ⇒ Boolean
- #length ⇒ Object
-
#segment_intersection(seg) ⇒ RGeo::Feature::Point?
If this and the other segment intersect, this method will return the coordinate at which they intersect, otherwise nil.
-
#side(point) ⇒ Object
Returns a negative value if the point is to the left, a positive value if the point is to the right, or 0 if the point is collinear to the segment.
- #to_s ⇒ Object
- #tproj(point) ⇒ Object
Constructor Details
#initialize(start, stop) ⇒ Segment
:nodoc:
14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/rgeo/cartesian/calculations.rb', line 14 def initialize(start, stop) @s = start @e = stop @sx = @s.x @sy = @s.y @ex = @e.x @ey = @e.y @dx = @ex - @sx @dy = @ey - @sy @lensq = @dx * @dx + @dy * @dy end |
Instance Attribute Details
#dx ⇒ Object (readonly)
Returns the value of attribute dx.
26 27 28 |
# File 'lib/rgeo/cartesian/calculations.rb', line 26 def dx @dx end |
#dy ⇒ Object (readonly)
Returns the value of attribute dy.
26 27 28 |
# File 'lib/rgeo/cartesian/calculations.rb', line 26 def dy @dy end |
#e ⇒ Object (readonly)
Returns the value of attribute e.
26 27 28 |
# File 'lib/rgeo/cartesian/calculations.rb', line 26 def e @e end |
#s ⇒ Object (readonly)
Returns the value of attribute s.
26 27 28 |
# File 'lib/rgeo/cartesian/calculations.rb', line 26 def s @s end |
Instance Method Details
#contains_point?(point) ⇒ Boolean
59 60 61 62 63 64 65 66 |
# File 'lib/rgeo/cartesian/calculations.rb', line 59 def contains_point?(point) if side(point) == 0 t = tproj(point) t && t >= 0.0 && t <= 1.0 else false end end |
#degenerate? ⇒ Boolean
37 38 39 |
# File 'lib/rgeo/cartesian/calculations.rb', line 37 def degenerate? @lensq == 0 end |
#eql?(other) ⇒ Boolean Also known as: ==
32 33 34 |
# File 'lib/rgeo/cartesian/calculations.rb', line 32 def eql?(other) other.is_a?(Segment) && @s == other.s && @e == other.e end |
#intersects_segment?(seg) ⇒ Boolean
68 69 70 |
# File 'lib/rgeo/cartesian/calculations.rb', line 68 def intersects_segment?(seg) !segment_intersection(seg).nil? end |
#length ⇒ Object
141 142 143 |
# File 'lib/rgeo/cartesian/calculations.rb', line 141 def length Math.sqrt(@lensq) end |
#segment_intersection(seg) ⇒ RGeo::Feature::Point?
If this and the other segment intersect, this method will return the coordinate at which they intersect, otherwise nil. In the case of a partial overlap (parallel segments), this will return a single point on the overlapping portion.
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 139 |
# File 'lib/rgeo/cartesian/calculations.rb', line 80 def segment_intersection(seg) s2 = seg.s # Handle degenerate cases if seg.degenerate? return @s if @lensq == 0 && @s == s2 return contains_point?(s2) ? s2 : nil elsif @lensq == 0 return seg.contains_point?(@s) ? @s : nil end # Both segments have nonzero length. sx2 = s2.x sy2 = s2.y dx2 = seg.dx dy2 = seg.dy denom = @dx * dy2 - @dy * dx2 if denom == 0 # Segments are parallel. Make sure they are collinear. return nil unless side(s2) == 0 # return the first point it finds that intersects another line. # In many cases, the intersection is actually another line # segment, but for now, we will just return a single point. return s2 if contains_point?(s2) return seg.e if contains_point?(seg.e) return @s if seg.contains_point?(@s) return @e if seg.contains_point?(@e) nil else # Segments are not parallel. Check the intersection of their # containing lines. num1 = dx2 * (@sy - sy2) - (dy2 * (@sx - sx2)) num2 = @dx * (@sy - sy2) - (@dy * (@sx - sx2)) cross1 = num1 / denom cross2 = num2 / denom return nil if cross1 < 0.0 || cross1 > 1.0 if cross2 >= 0.0 && cross2 <= 1.0 x = @sx + (cross1 * @dx) y = @sy + (cross1 * @dy) # Check if this segment contains the point. # Sometimes round-off errors occur and intersections # are recorded as off the line segments. # # If this is the case, return the closest point from # either segment. int_pt = @s.factory.point(x, y) return int_pt if contains_point?(int_pt) # find closest of @s, @e, seg.s, seg.e [@e, seg.s, seg.e].reduce(@s) do |closest, pt| int_pt.distance(pt) < int_pt.distance(closest) ? pt : closest end end end end |
#side(point) ⇒ Object
Returns a negative value if the point is to the left, a positive value if the point is to the right, or 0 if the point is collinear to the segment.
45 46 47 48 49 |
# File 'lib/rgeo/cartesian/calculations.rb', line 45 def side(point) px = point.x py = point.y (@sx - px) * (@ey - py) - (@sy - py) * (@ex - px) end |
#to_s ⇒ Object
28 29 30 |
# File 'lib/rgeo/cartesian/calculations.rb', line 28 def to_s "#{@s} - #{@e}" end |
#tproj(point) ⇒ Object
51 52 53 54 55 56 57 |
# File 'lib/rgeo/cartesian/calculations.rb', line 51 def tproj(point) if @lensq == 0 nil else (@dx * (point.x - @sx) + @dy * (point.y - @sy)) / @lensq end end |