Class: Euclidean::Edge

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

Overview

An edge. It’s a line segment between 2 points. Generally part of a Polygon.

Usage

edge = Geometry::Edge([1,1], [2,2])

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(point0, point1) ⇒ Edge

Construct a new Euclidean::Edge object from any two things that can be converted to a Point.



17
18
19
# File 'lib/euclidean/edge.rb', line 17

def initialize(point0, point1)
  @first, @last = [Point[point0], Point[point1]]
end

Instance Attribute Details

#firstObject (readonly)

Returns the value of attribute first.



13
14
15
# File 'lib/euclidean/edge.rb', line 13

def first
  @first
end

#lastObject (readonly)

Returns the value of attribute last.



13
14
15
# File 'lib/euclidean/edge.rb', line 13

def last
  @last
end

Instance Method Details

#<=>(point) ⇒ Boolean

Returns 1 if the Point is strictly to the left of the receiver, -1 to the right, and 0 if the point is on the receiver

Parameters:

Returns:

  • (Boolean)

    Returns 1 if the Point is strictly to the left of the receiver, -1 to the right, and 0 if the point is on the receiver



28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/euclidean/edge.rb', line 28

def <=>(point)
  case point
  when Point
    k = (@last.x - @first.x) * (point.y - @first.y) - (point.x - @first.x) * (@last.y - @first.y)
    if 0 == k
  (((@first.x <=> point.x) + (@last.x <=> point.x)).abs <= 1) && (((@first.y <=> point.y) + (@last.y <=> point.y)).abs <= 1) ? 0 : nil
    else
  k <=> 0
    end
  else
    raise ArgumentError, "Can't spaceship with #{point.class}"
  end
end

#==(other) ⇒ Object

Two Edges are equal if both have equal Points in the same order



22
23
24
# File 'lib/euclidean/edge.rb', line 22

def ==(other)
  (@first == other.first) && (@last == other.last)
end

#connected?(other) ⇒ Bool

Returns true if the receiver and the passed Euclidean::Edge share an endpoint

Parameters:

Returns:

  • (Bool)

    Returns true if the receiver and the passed Euclidean::Edge share an endpoint



44
45
46
# File 'lib/euclidean/edge.rb', line 44

def connected?(other)
  (@first == other.last) || (@last == other.first) || (@first == other.first) || (@last == other.last)
end

#directionVector

Returns A unit Vector pointing from first to last.

Returns:



49
50
51
# File 'lib/euclidean/edge.rb', line 49

def direction
  self.vector.normalize
end

#heightObject

Return the Euclidean::Edge‘s length along the Y axis



54
55
56
# File 'lib/euclidean/edge.rb', line 54

def height
  (@first.y - @last.y).abs
end

#inspectObject Also known as: to_s



58
59
60
# File 'lib/euclidean/edge.rb', line 58

def inspect
  'Edge(' + @first.inspect + ', ' + @last.inspect + ')'
end

#intersection(other) ⇒ Point

Parameters:

Returns:

  • (Point)

    The intersection of the two Euclidean::Edges, nil if they don’t intersect, true if they’re collinear and overlapping, and false if they’re collinear and non-overlapping



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/euclidean/edge.rb', line 66

def intersection(other)
   return self.first if (self.first == other.first) or (self.first == other.last)
   return self.last if (self.last == other.first) or (self.last == other.last)

   p0, p1 = self.first, self.last
   p2, p3 = other.first, other.last
   v1, v2 = self.vector, other.vector

   denominator = v1[0] * v2[1] - v2[0] * v1[1]    # v1 x v2
   p = p0 - p2

   if denominator == 0      # collinear, so check for overlap
     if 0 == (-v1[1] * p.x + v1[0] * p.y) # collinear?
       # The edges are collinear, but do they overlap?
       # Project them onto the x and y axes to find out
       left1, right1 = [self.first[0], self.last[0]].sort
       bottom1, top1 = [self.first[1], self.last[1]].sort
       left2, right2 = [other.first[0], other.last[0]].sort
       bottom2, top2 = [other.first[1], other.last[1]].sort

       !((left2 > right1) || (right2 < left1) || (top2 < bottom1) || (bottom2 > top1))
     else
       nil
     end
   else
     s = (-v1[1] * p.x + v1[0] * p.y) / denominator # v1 x (p0 - p2) / denominator
     t = ( v2[0] * p.y - v2[1] * p.x) / denominator # v2 x (p0 - p2) / denominator

     p0 + v1 * t if ((0..1) === s) && ((0..1) === t)
   end
end

#parallel?(edge) ⇒ Bool

Returns true if the passed Euclidean::Edge is parallel to the receiver

Returns:

  • (Bool)

    Returns true if the passed Euclidean::Edge is parallel to the receiver



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/euclidean/edge.rb', line 99

def parallel?(edge)
  v1, v2   = self.direction, edge.direction
  winding  = v1[0]*v2[1] - v1[1]*v2[0]
  if 0 == winding # collinear?
    if v1 == v2
      true # 1  # same direction
    else
      true # -1 # opposite direction
    end
  else
    false
  end
end

#reverseObject

Return a new Euclidean::Edge with swapped endpoints



114
115
116
# File 'lib/euclidean/edge.rb', line 114

def reverse
  Edge.new(@last, @first)
end

#reverse!Object

In-place swap the endpoints



119
120
121
122
# File 'lib/euclidean/edge.rb', line 119

def reverse!
  @first, @last = @last, @first
  self
end

#to_aObject



124
125
126
# File 'lib/euclidean/edge.rb', line 124

def to_a
  [@first, @last]
end

#vectorVector

Returns A Vector pointing from first to last.

Returns:



129
130
131
# File 'lib/euclidean/edge.rb', line 129

def vector
  Vector[*((last-first).to_a)]
end

#widthObject

Return the Euclidean::Edge‘s length along the X axis



134
135
136
# File 'lib/euclidean/edge.rb', line 134

def width
  (@first.x - @last.x).abs
end