class Geom2D::Segment

Represents a line segment.

Attributes

end_point[R]

The end point of the segment.

start_point[R]

The start point of the segment.

Public Class Methods

new(start_point, end_point) click to toggle source

Creates a new Segment from the start to the end point. The arguments are converted to proper Geom2D::Point objects if needed.

# File lib/geom2d/segment.rb, line 27
def initialize(start_point, end_point)
  @start_point = Geom2D::Point(start_point)
  @end_point = Geom2D::Point(end_point)
end

Public Instance Methods

+(other) click to toggle source

Adds the given vector (given as array or Geom2D::Point) to the segment, i.e. performs a translation.

# File lib/geom2d/segment.rb, line 168
def +(other)
  case other
  when Point, Array
    Segment.new(start_point + other, end_point + other)
  else
    raise ArgumentError, "Invalid argument class, must be Point"
  end
end
+@() click to toggle source

Returns self.

# File lib/geom2d/segment.rb, line 157
def +@
  self
end
-(other) click to toggle source

Subtracts the given vector (given as array or Geom2D::Point) from the segment, i.e. performs a translation.

# File lib/geom2d/segment.rb, line 179
def -(other)
  case other
  when Point, Array
    Segment.new(start_point - other, end_point - other)
  else
    raise ArgumentError, "Invalid argument class, must be Point"
  end
end
-@() click to toggle source

Returns the segment mirrored in the origin.

# File lib/geom2d/segment.rb, line 162
def -@
  Segment.new(-start_point, -end_point)
end
==(other) click to toggle source

Compares this segment to the other, returning true if the end points match.

# File lib/geom2d/segment.rb, line 189
def ==(other)
  return false unless other.kind_of?(Segment)
  start_point == other.start_point && end_point == other.end_point
end
degenerate?() click to toggle source

Returns true if the segment is degenerate, i.e. if it consists only of a point.

# File lib/geom2d/segment.rb, line 33
def degenerate?
  @start_point == @end_point
end
direction() click to toggle source

Returns the direction vector of the segment as Geom2D::Point object.

# File lib/geom2d/segment.rb, line 73
def direction
  end_point - start_point
end
horizontal?() click to toggle source

Returns true if the segment is horizontal.

# File lib/geom2d/segment.rb, line 43
def horizontal?
  float_equal(start_point.y, end_point.y)
end
intersect(segment) click to toggle source

Returns the intersection of this segment with the given one:

nil

No intersections

Geom2D::Point

Exactly one point

Geom2D::Segment

The segment overlapping both other segments.

# File lib/geom2d/segment.rb, line 109
def intersect(segment)
  p0 = start_point
  p1 = segment.start_point
  d0 = direction
  d1 = segment.direction
  e = p1 - p0

  cross = d0.wedge(d1).to_f # cross product of direction vectors

  if cross.abs > Utils.precision # segments are not parallel
    s = e.wedge(d1) / cross
    return nil if s < 0 || s > 1
    t = e.wedge(d0) / cross
    return nil if t < 0 || t > 1

    result = p0 + [s * d0.x, s * d0.y]
    result = start_point if result == start_point
    result = end_point if result == end_point
    result = segment.start_point if result == segment.start_point
    result = segment.end_point if result == segment.end_point
    return result
  end

  return nil if e.wedge(d0).abs > Utils.precision # non-intersecting parallel segment lines

  e0 = end_point
  e1 = segment.end_point

  # sort segment points by x-value
  p0, e0 = e0, p0 if float_compare(p0.x, e0.x) > 0
  p1, e1 = e1, p1 if float_compare(p1.x, e1.x) > 0
  if float_compare(p0.x, p1.x) > 0
    _p0, p1, e0, e1 = p1, p0, e1, e0
  end

  # p0 before or equal to p1
  if float_compare(e0.x, p1.x) < 0     # e0 before p1
    nil                                # no common point
  elsif float_compare(e1.x, e0.x) <= 0 # e1 before or equal to e0
    self.class.new(p1, e1)             # p1-e1 inside p0-e0
  elsif float_compare(p1.x, e0.x) == 0 # common endpoint p1=e0
    p1
  else
    self.class.new(p1, e0)             # s1 overlaps end of s0
  end
end
length() click to toggle source

Returns the length of the segment.

# File lib/geom2d/segment.rb, line 68
def length
  start_point.distance(end_point)
end
max() click to toggle source

Returns the right-most top-most point of the segment (either the start or the end point).

# File lib/geom2d/segment.rb, line 58
def max
  if start_point.x > end_point.x ||
      (float_equal(start_point.x, end_point.x) && start_point.y > end_point.y)
    start_point
  else
    end_point
  end
end
min() click to toggle source

Returns the left-most bottom-most point of the segment (either the start or the end point).

# File lib/geom2d/segment.rb, line 48
def min
  if start_point.x < end_point.x ||
      (float_equal(start_point.x, end_point.x) && start_point.y < end_point.y)
    start_point
  else
    end_point
  end
end
reverse!() click to toggle source

Reverses the start and end point.

# File lib/geom2d/segment.rb, line 100
def reverse!
  @start_point, @end_point = @end_point, @start_point
end
slope() click to toggle source

Returns the slope of the segment.

If the segment is vertical, Float::INFINITY is returned.

# File lib/geom2d/segment.rb, line 80
def slope
  if float_equal(start_point.x, end_point.x)
    Float::INFINITY
  else
    (end_point.y - start_point.y).to_f / (end_point.x - start_point.x)
  end
end
vertical?() click to toggle source

Returns true if the segment is vertical.

# File lib/geom2d/segment.rb, line 38
def vertical?
  float_equal(start_point.x, end_point.x)
end
y_intercept() click to toggle source

Returns the y-intercept, i.e. the point on the y-axis where the segment does/would intercept it.

# File lib/geom2d/segment.rb, line 90
def y_intercept
  slope = self.slope
  if slope == Float::INFINITY
    nil
  else
    -start_point.x * slope + start_point.y
  end
end