Class: EasyGeometry::D2::Point

Inherits:
Object
  • Object
show all
Defined in:
lib/easy_geometry/d2/point.rb

Overview

A point in a 2-dimensional Euclidean space.

Constant Summary collapse

EQUITY_TOLERANCE =
0.0000000000001

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(x, y) ⇒ Point

Returns a new instance of Point.



9
10
11
12
13
14
# File 'lib/easy_geometry/d2/point.rb', line 9

def initialize(x, y)
  @x = x; @y = y

  validate!
  converting_to_rational!
end

Instance Attribute Details

#xObject (readonly)

Returns the value of attribute x.



5
6
7
# File 'lib/easy_geometry/d2/point.rb', line 5

def x
  @x
end

#yObject (readonly)

Returns the value of attribute y.



5
6
7
# File 'lib/easy_geometry/d2/point.rb', line 5

def y
  @y
end

Class Method Details

.affine_rank(*points) ⇒ Object

The affine rank of a set of points is the dimension of the smallest affine space containing all the points.

For example, if the points lie on a line (and are not all the same) their affine rank is 1.

If the points lie on a plane but not a line, their affine rank is 2.

By convention, the empty set has affine rank -1.

Raises:

  • (TypeError)


51
52
53
54
55
56
57
58
59
# File 'lib/easy_geometry/d2/point.rb', line 51

def self.affine_rank(*points)
  raise TypeError, 'Args should be a Points' unless points.detect { |p| !p.is_a?(Point) }.nil?
  return -1 if points.length == 0

  origin = points[0]
  points = points[1..-1].map {|p| p - origin}

  Matrix[*points.map {|p| [p.x, p.y]}].rank
end

.is_collinear?(*points) ⇒ Boolean

Returns:

true if there exists a line that contains `points`,

or if no points are given.

false otherwise.

Returns:

  • (Boolean)


39
40
41
42
# File 'lib/easy_geometry/d2/point.rb', line 39

def self.is_collinear?(*points)
  # raise TypeError, 'Args should be a Points' unless points.detect { |p| !p.is_a?(Point) }.nil?
  Point.affine_rank(*points.uniq) <= 1
end

.project(a, b) ⇒ Object

Project the point ‘a’ onto the line between the origin and point ‘b’ along the normal direction.

Parameters:

Point, Point

Returns:

Point

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
32
# File 'lib/easy_geometry/d2/point.rb', line 25

def self.project(a, b)
  unless a.is_a?(Point) && b.is_a?(Point)
    raise TypeError, "Project between #{ a.class } and #{ b.class } is not defined"
  end
  raise ArgumentError, "Cannot project to the zero vector" if b.zero?
  
  b * a.dot(b) / b.dot(b)
end

Instance Method Details

#*(scalar) ⇒ Object

Multiplication of point and number.

Raises:

  • (TypeError)


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

def *(scalar)
  raise TypeError, "Multiplication between Point and #{ scalar.class } is not defined" unless scalar.is_a?(Numeric)
  Point.new(x * scalar, y * scalar)
end

#+(other) ⇒ Object

Addition of two points.

Raises:

  • (TypeError)


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

def +(other)
  raise TypeError, "Addition between Point and #{ other.class } is not defined" unless other.is_a?(Point)
  Point.new(self.x + other.x, self.y + other.y)
end

#-(other) ⇒ Object

Subtraction of two points.

Raises:

  • (TypeError)


79
80
81
82
# File 'lib/easy_geometry/d2/point.rb', line 79

def -(other)
  raise TypeError, "Subtract between Point and #{ other.class } is not defined" unless other.is_a?(Point)
  Point.new(self.x - other.x, self.y - other.y)
end

#/(scalar) ⇒ Object

Dividing of point and number.

Raises:

  • (TypeError)


97
98
99
100
# File 'lib/easy_geometry/d2/point.rb', line 97

def /(scalar)
  raise TypeError, "Dividing between Point and #{ scalar.class } is not defined" unless scalar.is_a?(Numeric)
  Point.new(x / scalar, y / scalar)
end

#<=>(other) ⇒ Object



102
103
104
105
# File 'lib/easy_geometry/d2/point.rb', line 102

def <=>(other)
  return self.y <=> other.y if self.x == other.x 
  self.x <=> other.x
end

#==(other) ⇒ Object

Compare self and other Point.



73
74
75
76
# File 'lib/easy_geometry/d2/point.rb', line 73

def ==(other)
  return false unless other.is_a?(Point)
  (x - other.x).abs < EQUITY_TOLERANCE && (y - other.y).abs < EQUITY_TOLERANCE
end

#absObject

Returns the distance between this point and the origin.



108
109
110
# File 'lib/easy_geometry/d2/point.rb', line 108

def abs
  self.distance(Point.new(0, 0))
end

#distance(other) ⇒ Object

Distance between self and another geometry entity.

Parameters:

geometry_entity

Returns:

int

Raises:

  • (TypeError)


120
121
122
123
124
125
126
127
128
129
130
# File 'lib/easy_geometry/d2/point.rb', line 120

def distance(other)
  if other.is_a?(Point)
    return distance_between_points(self, other)
  end
  
  if other.respond_to?(:distance)
    return other.distance(self)
  end
  
  raise TypeError, "Distance between Point and #{ other.class } is not defined"
end

#dot(other) ⇒ Object

Dot product, also known as inner product or scalar product.

Raises:

  • (TypeError)


62
63
64
65
# File 'lib/easy_geometry/d2/point.rb', line 62

def dot(other)
  raise TypeError, "Scalar (dot) product between Point and #{ other.class } is not defined" unless other.is_a?(Point)
  x * other.x + y * other.y
end

#intersection(other) ⇒ Object

Intersection between point and another geometry entity.

Parameters:

geometry_entity

Returns:

Array of Points

Raises:

  • (TypeError)


140
141
142
143
144
145
146
147
148
149
150
# File 'lib/easy_geometry/d2/point.rb', line 140

def intersection(other)
  if other.is_a?(Point)
    return points_intersection(self, other)
  end

  if other.respond_to?(:intersection)
    return other.intersection(self)
  end

  raise TypeError, "Intersection between Point and #{ other.class } is not defined"
end

#midpoint(other) ⇒ Object

The midpoint between self and another point.

Parameters:

Point

Returns:

Point

Raises:

  • (TypeError)


160
161
162
163
164
165
166
167
# File 'lib/easy_geometry/d2/point.rb', line 160

def midpoint(other)
  raise TypeError, "Midpoint between Point and #{ other.class } is not defined" unless other.is_a?(Point)

  Point.new(
    (self.x + other.x) / 2,
    (self.y + other.y) / 2
  )
end

#zero?Boolean

True if every coordinate is zero, False if any coordinate is not zero.

Returns:

  • (Boolean)


68
69
70
# File 'lib/easy_geometry/d2/point.rb', line 68

def zero?
  x.zero? && y.zero? 
end