Class: EasyGeometry::D2::Segment

Inherits:
LinearEntity show all
Defined in:
lib/easy_geometry/d2/segment.rb

Overview

A segment in a 2-dimensional Euclidean space.

Instance Attribute Summary

Attributes inherited from LinearEntity

#p1, #p2

Instance Method Summary collapse

Methods inherited from LinearEntity

#angle_between, #direction, #initialize, #intersection, #parallel_line, #parallel_to?, #perpendicular_line, #perpendicular_segment, #perpendicular_to?, #projection_point, #similar_to?, #slope, #span_test

Constructor Details

This class inherits a constructor from EasyGeometry::D2::LinearEntity

Instance Method Details

#<=>(other) ⇒ Object



49
50
51
52
# File 'lib/easy_geometry/d2/segment.rb', line 49

def <=>(other)
  return self.p2 <=> other.p2 if self.p1 == other.p1 
  self.p1 <=> other.p1
end

#==(other) ⇒ Object

Returns True if self and other are the same mathematical entities.

Parameters:

GeometryEntity


44
45
46
47
# File 'lib/easy_geometry/d2/segment.rb', line 44

def ==(other)
  return false unless other.is_a?(Segment)
  [p1, p2].sort_by {|p| [p.x, p.y]} == [other.p1, other.p2].sort_by {|p| [p.x, p.y]}
end

#contains?(other) ⇒ Boolean

Is the other GeometryEntity contained within this Segment?

Parameters:

GeometryEntity or Array of Numeric(coordinates)

Returns:

true if `other` is in this Segment.
false otherwise.

Returns:

  • (Boolean)


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/easy_geometry/d2/segment.rb', line 15

def contains?(other)
  other = Point.new(other[0], other[1]) if other.is_a?(Array)

  if other.is_a?(Point)
    if Point.is_collinear?(other, self.p1, self.p2)
      # if it is collinear and is in the bounding box of the
      # segment then it must be on the segment
      vert = (1/self.slope).zero?
      
      if vert
        return (self.p1.y - other.y) * (self.p2.y - other.y) <= 0
      end
      
      return (self.p1.x - other.x) * (self.p2.x - other.x) <= 0
    end
  end

  if other.is_a?(Segment)
    return self.contains?(other.p1) && self.contains?(other.p2)
  end

  return false
end

#distance(other) ⇒ Object

Finds the shortest distance between a line segment and a point.

Parameters:

Point or Array of Numeric(coordinates)

Returns:

Number

Raises:

  • (TypeError)


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/easy_geometry/d2/segment.rb', line 62

def distance(other)
  other = Point.new(other[0], other[1]) if other.is_a?(Array)
  raise TypeError, "Distance between Segment and #{ other.class } is not defined" unless other.is_a?(Point)

  vp1 = other - self.p1
  vp2 = other - self.p2

  dot_prod_sign_1 = self.direction.to_point.dot(vp1) >= 0
  dot_prod_sign_2 = self.direction.to_point.dot(vp2) <= 0

  if dot_prod_sign_1 && dot_prod_sign_2
    return Line.new(self.p1, self.p2).distance(other)
  end

  if dot_prod_sign_1 && !dot_prod_sign_2
    return vp2.abs
  end

  if !dot_prod_sign_1 && dot_prod_sign_2
    return vp1.abs
  end
end

#lengthObject

The length of the line segment.



86
87
88
# File 'lib/easy_geometry/d2/segment.rb', line 86

def length
  @length ||= p1.distance(p2)
end

#midpointObject

The midpoint of the line segment.



91
92
93
# File 'lib/easy_geometry/d2/segment.rb', line 91

def midpoint
  @midpoint ||= p1.midpoint(p2)
end

#perpendicular_bisector(point = nil) ⇒ Object

The perpendicular bisector of this segment. If no point is specified or the point specified is not on the bisector then the bisector is returned as a Line. Otherwise a Segment is returned that joins the point specified and the intersection of the bisector and the segment.

Parameters:

Point

Returns:

Line or Segment


107
108
109
110
111
112
113
114
115
116
117
# File 'lib/easy_geometry/d2/segment.rb', line 107

def perpendicular_bisector(point=nil)
  l = self.perpendicular_line(self.midpoint)
  
  if !point.nil?
    point = Point.new(point[0], point[1]) if point.is_a?(Array)        
    raise TypeError, "This method is not defined for #{ point.class }" unless point.is_a?(Point)
    return Segment.new(point, self.midpoint) if l.contains?(point)
  end

  return l
end