Class: Geo2D::LineSegment

Inherits:
Object
  • Object
show all
Defined in:
lib/geo2d.rb

Overview

Line segment between two points (defined by Vectors)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(p1, p2) ⇒ LineSegment

Returns a new instance of LineSegment.

Raises:

  • (ArgumentError)


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

#endObject (readonly)

Returns the value of attribute end.



176
177
178
# File 'lib/geo2d.rb', line 176

def end
  @end
end

#startObject (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

Returns:

  • (Boolean)


202
203
204
# File 'lib/geo2d.rb', line 202

def aligned_with?(point)
  vector.aligned_width?(point-@start)
end

#angleObject



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

#boundsObject



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

Returns:

  • (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

#directionObject



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

#lengthObject



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_pointsObject



182
183
184
# File 'lib/geo2d.rb', line 182

def n_points
  2
end

#pointsObject



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

#vectorObject



186
187
188
# File 'lib/geo2d.rb', line 186

def vector
  @vector ||= (@end-@start)
end