Class: Geo2D::LineString

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

Instance Method Summary collapse

Constructor Details

#initialize(*vertices) ⇒ LineString

Returns a new instance of LineString.



309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/geo2d.rb', line 309

def initialize(*vertices)
  @vertices = vertices

  to_remove = []
  prev = nil
  @vertices.each_with_index do |v, i|
    to_remove << i if prev && prev==v
    prev = v
  end
  to_remove.each do |i|
    @vertices.delete_at i
  end

end

Instance Method Details

#<<(p) ⇒ Object



324
325
326
327
328
329
330
# File 'lib/geo2d.rb', line 324

def <<(p)
  p = Geo2D.Point(*p)
  if @vertices.last != p
    @vertices << p
    @length = nil
  end
end

#angle_at(parallel_distance, rotation = 0) ⇒ Object

Angle of the line at a point (in radians, from the X axis, counter-clockwise.) The rotation parameter is added to this angle, if the rotation obtained from locate_point is used, points external to the line have a natural orientation parallel to the line (than can be use to rotate texts or symbols to be aligned with the line.)



423
424
425
426
# File 'lib/geo2d.rb', line 423

def angle_at(parallel_distance, rotation=0)
  i,l = segment_position_of(parallel_distance)
  segment(i).angle + rotation
end

#apply(prc = nil, &blk) ⇒ Object



433
434
435
436
# File 'lib/geo2d.rb', line 433

def apply(prc=nil, &blk)
  prc = prc || blk
  LineString.new(*@vertices.map{|v| prc[v]})
end

#boundsObject



442
443
444
445
446
# File 'lib/geo2d.rb', line 442

def bounds
  xs = @vertices.map{|v| v.x}
  ys = @vertices.map{|v| v.y}
  [xs.min, ys.min, xs.max, ys.max]
end

#contains?(point) ⇒ Boolean

Returns:

  • (Boolean)


438
439
440
# File 'lib/geo2d.rb', line 438

def contains?(point)
  self.locate_point(point)[1] == 0
end

#distance_to(point) ⇒ Object



375
376
377
# File 'lib/geo2d.rb', line 375

def distance_to(point)
  locate_point(point, true)[1].abs
end

#each_pointObject



350
351
352
353
354
# File 'lib/geo2d.rb', line 350

def each_point
  @vertices.each do |v|
    yield v
  end
end

#each_segmentObject



364
365
366
367
368
# File 'lib/geo2d.rb', line 364

def each_segment
  (0...n_segments).each do |i|
    yield segment(i)
  end
end

#endObject



336
337
338
# File 'lib/geo2d.rb', line 336

def end
  @vertices.last
end

#interpolate_point(parallel_distance, separation = 0, rotation = 0) ⇒ Object

Compute a point position given the relative position in the line as returned by locate_point().



413
414
415
416
417
# File 'lib/geo2d.rb', line 413

def interpolate_point(parallel_distance, separation=0, rotation=0)
  # separation>0 => left side of line in direction of travel
  i, l = segment_position_of(parallel_distance)
  segment(i).interpolate_point(l, separation, rotation)
end

#lengthObject



340
341
342
# File 'lib/geo2d.rb', line 340

def length
  @length ||= total_length
end

#length_to(point) ⇒ Object



379
380
381
# File 'lib/geo2d.rb', line 379

def length_to(point)
  locate_point(point, true).first
end

#locate_point(point) ⇒ Object

Return the position of a point in relation to the line: parallalel distance along the line, separation and rotation of the separation (from the perpendicular.) Parallalel distance is in [0,length]. If we have l,d,r = line.locate_point(point), then the closest line point to point is: line.interpolate_point(l) and line.interpolate_point(l,d,r) is point; d.abs is the distance from line to point; point is on the left of line if d>0; on the right if d<0 and on the line if d==0. If we want to align a text with the line at point, we would use the angle line.angle_at(l,r)



390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/geo2d.rb', line 390

def locate_point(point)
  best = nil

  total_l = 0
  (0...n_segments).each do |i|

    seg = segment(i)
    seg_l = seg.length

    l,d,rotation = seg.locate_point(point, true)

    if best.nil? || d.abs<best[1].abs
      best = [total_l+l, d, rotation]
    end

    total_l += seg_l
  end

  best

end

#n_pointsObject



344
345
346
# File 'lib/geo2d.rb', line 344

def n_points
  @vertices.size
end

#n_segmentsObject



356
357
358
# File 'lib/geo2d.rb', line 356

def n_segments
  [n_points - 1,0].max
end

#pointsObject



347
348
349
# File 'lib/geo2d.rb', line 347

def points
  @vertices
end

#segment(i) ⇒ Object

Raises:

  • (ArgumentError)


370
371
372
373
# File 'lib/geo2d.rb', line 370

def segment(i)
  raise ArgumentError, "Invalid segment index #{i}" unless i>=0 && i<n_segments
  LineSegment.new(@vertices[i],@vertices[i+1])
end

#segmentsObject



360
361
362
# File 'lib/geo2d.rb', line 360

def segments
  (0...n_segments).to_a.map{|i| segment(i)}
end

#startObject



332
333
334
# File 'lib/geo2d.rb', line 332

def start
  @vertices.first
end

#transform(*t) ⇒ Object

multiply by matrix [[a11, a12], [a21, a22]]



429
430
431
# File 'lib/geo2d.rb', line 429

def transform(*t)
  LineString.new(*@vertices.map{|v| v.transform(*t)})
end