Class: Geo2D::LineSegment
- Inherits:
-
Object
- Object
- Geo2D::LineSegment
- Defined in:
- lib/geo2d.rb
Overview
Line segment between two points (defined by Vectors)
Instance Attribute Summary collapse
-
#end ⇒ Object
readonly
Returns the value of attribute end.
-
#start ⇒ Object
readonly
Returns the value of attribute start.
Instance Method Summary collapse
- #aligned_with?(point) ⇒ Boolean
- #angle ⇒ Object
- #angle_at(parallel_distance) ⇒ Object
-
#apply(prc, &blk) ⇒ Object
Apply arbitrary transformation (passed as a Proc or as a block).
- #bounds ⇒ Object
- #contains?(point) ⇒ Boolean
- #direction ⇒ Object
-
#distance_to(point) ⇒ Object
Distance from the segment to a point.
-
#initialize(p1, p2) ⇒ LineSegment
constructor
A new instance of LineSegment.
-
#interpolate_point(parallel_distance, separation = 0, rotation = 0) ⇒ Object
Computes the position of a point in the line given the distance along the line from the starting node.
- #length ⇒ Object
- #length_to(point) ⇒ Object
-
#line_distance_to(point) ⇒ Object
Distance from the line that contains the segment to the point.
-
#locate_point(point, corrected = false) ⇒ Object
Returns the position in the segment (distance from the start node along the line) of the nearest line point to the point (point projected on the line) and the perpendicular separation of the point from the line (the distance from the point to the line, but signed: negative when the point is on the right side of the line. If the last parameter is true, the resulting point is forced to lie in the segment (so the distance along the line is between 0 and the segment’s length) and the second result is the distance from the point to the segment (i.e. to the closest end of the segment if the projected point lies out of the segment) The third returned value is a rotation that must be applied to the perpendicular vector; it is nonzero only when the last parameter is true and the point is closer to a segment end than to any other segment point..
- #n_points ⇒ Object
- #points ⇒ Object
-
#side_of(point) ⇒ Object
Returns the side of the line that contains the segment in which the point lies: * +1 the point is to the left of the line (as seen from the orientation of the segment) * -1 is in the right side * 0 the point is on the line.
-
#transform(*t) ⇒ Object
multiply by matrix [[a11, a12], [a21, a22]].
- #vector ⇒ Object
Constructor Details
#initialize(p1, p2) ⇒ LineSegment
Returns a new instance of LineSegment.
170 171 172 173 174 |
# File 'lib/geo2d.rb', line 170 def initialize(p1, p2) @start = p1 @end = p2 raise ArgumentError,"Degenerate LineSegment" if p1==p2 end |
Instance Attribute Details
#end ⇒ Object (readonly)
Returns the value of attribute end.
176 177 178 |
# File 'lib/geo2d.rb', line 176 def end @end end |
#start ⇒ Object (readonly)
Returns the value of attribute start.
176 177 178 |
# File 'lib/geo2d.rb', line 176 def start @start end |
Instance Method Details
#aligned_with?(point) ⇒ Boolean
202 203 204 |
# File 'lib/geo2d.rb', line 202 def aligned_with?(point) vector.aligned_width?(point-@start) end |
#angle ⇒ Object
194 195 196 |
# File 'lib/geo2d.rb', line 194 def angle vector.argument end |
#angle_at(parallel_distance) ⇒ Object
198 199 200 |
# File 'lib/geo2d.rb', line 198 def angle_at(parallel_distance) angle end |
#apply(prc, &blk) ⇒ Object
Apply arbitrary transformation (passed as a Proc or as a block)
285 286 287 288 |
# File 'lib/geo2d.rb', line 285 def apply(prc, &blk) prc ||= blk LineSegment.new(prc[@start], prc[@end]) end |
#bounds ⇒ Object
299 300 301 302 303 |
# File 'lib/geo2d.rb', line 299 def bounds xmn, xmx = [@start.x, @end.x].sort ymn, ymx = [@start.y, @end.y].sort [xmn, ymn, xmx, ymx] end |
#contains?(point) ⇒ Boolean
206 207 208 209 210 211 212 213 |
# File 'lib/geo2d.rb', line 206 def contains?(point) if self.aligned_with?(point) l,d,r = self.locate_point(point) l>=0 && l<=self.length # => d==0 else false end end |
#direction ⇒ Object
215 216 217 |
# File 'lib/geo2d.rb', line 215 def direction @u ||= vector.unitary end |
#distance_to(point) ⇒ Object
Distance from the segment to a point
266 267 268 |
# File 'lib/geo2d.rb', line 266 def distance_to(point) locate_point(point, true)[1].abs end |
#interpolate_point(parallel_distance, separation = 0, rotation = 0) ⇒ Object
Computes the position of a point in the line given the distance along the line from the starting node. If a second parameter is passed it indicates the separation of the computed point in the direction perpendicular to the line; the point is on the left side of the line if the separation is > 0. The third parameter is a rotation applied to the vector from the line to the point.
255 256 257 258 259 260 261 262 263 |
# File 'lib/geo2d.rb', line 255 def interpolate_point(parallel_distance, separation=0, rotation=0) p = @start + self.direction*parallel_distance unless separation==0 d = direction.ortho*separation d = d.rotate(rotation) unless rotation==0 p += d end p end |
#length ⇒ Object
190 191 192 |
# File 'lib/geo2d.rb', line 190 def length @length ||= vector.modulus end |
#length_to(point) ⇒ Object
275 276 277 |
# File 'lib/geo2d.rb', line 275 def length_to(point) locate_point(point, true).first end |
#line_distance_to(point) ⇒ Object
Distance from the line that contains the segment to the point
271 272 273 |
# File 'lib/geo2d.rb', line 271 def line_distance_to(point) locate_point(point, false)[1].abs end |
#locate_point(point, corrected = false) ⇒ Object
Returns the position in the segment (distance from the start node along the line) of the nearest line point to the point (point projected on the line) and the perpendicular separation of the point from the line (the distance from the point to the line, but signed: negative when the point is on the right side of the line. If the last parameter is true, the resulting point is forced to lie in the segment (so the distance along the line is between 0 and the segment’s length) and the second result is the distance from the point to the segment (i.e. to the closest end of the segment if the projected point lies out of the segment) The third returned value is a rotation that must be applied to the perpendicular vector; it is nonzero only when the last parameter is true and the point is closer to a segment end than to any other segment point.
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/geo2d.rb', line 227 def locate_point(point, corrected=false) point = Geo2D.Vector(point) v = point - @start l = v.dot(direction) d = direction.cross_z(v) # == (v-l*direction).length == v.length*Math.sin(v.angle_to(direction)) rotation = 0 if corrected # rotation = atan2(-(l.modulo(length))*d.sign, d.abs) if l<0 rotation = Math.atan2(d < 0 ? l : -l, d.abs) l = 0 d = d/Math.cos(rotation) # d.sign*(point-@start).length elsif l>self.length l -= self.length rotation = Math.atan2(d < 0 ? l : -l, d.abs) l = self.length d = d/Math.cos(rotation) # d = d.sign*(point-@end).length end end [l, d, rotation] end |
#n_points ⇒ Object
182 183 184 |
# File 'lib/geo2d.rb', line 182 def n_points 2 end |
#points ⇒ Object
178 179 180 |
# File 'lib/geo2d.rb', line 178 def points [@start, @end] end |
#side_of(point) ⇒ Object
Returns the side of the line that contains the segment in which the point lies:
-
+1 the point is to the left of the line (as seen from the orientation of the segment)
-
-1 is in the right side
-
0 the point is on the line
294 295 296 297 |
# File 'lib/geo2d.rb', line 294 def side_of(point) v = vector.cross_z(point-@start) v < 0 ? -1 : (v > 0 ? +1 : 0) end |
#transform(*t) ⇒ Object
multiply by matrix [[a11, a12], [a21, a22]]
280 281 282 |
# File 'lib/geo2d.rb', line 280 def transform(*t) LineSegment.new(@start.transform(*t), @end = @end.transform(*t)) end |
#vector ⇒ Object
186 187 188 |
# File 'lib/geo2d.rb', line 186 def vector @vector ||= (@end-@start) end |