Class: Geometry::Point

Inherits:
Vector
  • Object
show all
Defined in:
lib/geometry/point.rb

Overview

An object repesenting a Point in N-dimensional space

Supports all of the familiar Vector methods and adds convenience accessors for those variables you learned to hate in your high school geometry class (x, y, z).

Usage

Constructor

point = Geometry::Point[x,y]

Constant Summary

Constants inherited from Vector

Vector::X, Vector::Y, Vector::Z

Accessors collapse

Attributes collapse

Accessors collapse

Unary operators collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Vector

#cross

Instance Attribute Details

#xNumeric (readonly)

Returns X-component.

Returns:

  • (Numeric)

    X-component



221
222
223
# File 'lib/geometry/point.rb', line 221

def x
    @elements[0]
end

#yNumeric (readonly)

Returns Y-component.

Returns:

  • (Numeric)

    Y-component



227
228
229
# File 'lib/geometry/point.rb', line 227

def y
    @elements[1]
end

#zNumeric (readonly)

Returns Z-component.

Returns:

  • (Numeric)

    Z-component



233
234
235
# File 'lib/geometry/point.rb', line 233

def z
    @elements[2]
end

Class Method Details

.[](x, y, z, ...) ⇒ Object .[](Array) ⇒ Object .[](Point) ⇒ Object .[](Vector) ⇒ Object

Allow vector-style initialization, but override to support copy-init from Vector or another Point



31
32
33
34
35
36
# File 'lib/geometry/point.rb', line 31

def self.[](*array)
    return array[0] if array[0].is_a?(Point)
    array = array[0] if array[0].is_a?(Array)
    array = array[0].to_a if array[0].is_a?(Vector)
    super(*array)
end

.iso(value, size = nil) ⇒ PointIso

Creates and returns a new Geometry::PointIso instance. Or, a Geometry::Point full of the given value if the size argument is given.

Parameters:

  • value (Number)

    the value of the elements

  • size (Number) (defaults to: nil)

    the size of the new Geometry::Point full of ones

Returns:



42
43
44
# File 'lib/geometry/point.rb', line 42

def self.iso(value, size=nil)
    size ? Point[Array.new(size, value)] : PointIso.new(value)
end

.one(size = nil) ⇒ PointOne

Creates and returns a new Geometry::PointOne instance. Or, a Geometry::Point full of ones if the size argument is given.

Parameters:

  • size (Number) (defaults to: nil)

    the size of the new Geometry::Point full of ones

Returns:



49
50
51
# File 'lib/geometry/point.rb', line 49

def self.one(size=nil)
    size ? Point[Array.new(size, 1)] : PointOne.new
end

.zero(size = nil) ⇒ PointZero

Creates and returns a new Geometry::PointZero instance. Or, a Geometry::Point full of zeros if the size argument is given.

Parameters:

  • size (Number) (defaults to: nil)

    the size of the new Geometry::Point full of zeros

Returns:



56
57
58
# File 'lib/geometry/point.rb', line 56

def self.zero(size=nil)
    size ? Point[Array.new(size, 0)] : PointZero.new
end

Instance Method Details

#*(other) ⇒ Object



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/geometry/point.rb', line 286

def *(other)
    case other
	when NilClass
	    nil
	when Numeric
	    Point[@elements.map {|e| e * other}]
	when PointZero
	    Point.zero
	else
	    if other.respond_to?(:[])
		raise OperationNotDefined, "#{other.class} must respond to :size" unless other.respond_to?(:size)
		raise DimensionMismatch, "Can't multiply #{self} by #{other}" if size != other.size
		Point[Array.new(size) {|i| @elements[i] * other[i] }]
	    else
		Point[@elements.map {|e| e * other}]
	    end
    end
end

#+(other) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/geometry/point.rb', line 250

def +(other)
    case other
	when Numeric
	    Point[@elements.map {|e| e + other}]
	when PointIso
	    value = other.value
	    Point[@elements.map {|e| e + value}]
	when PointOne
	    Point[@elements.map {|e| e + 1}]
	when PointZero, NilClass
	    self.dup
	else
	    raise OperationNotDefined, "#{other.class} must respond to :size and :[]" unless other.respond_to?(:size) && other.respond_to?(:[])
	    raise DimensionMismatch,  "Can't add #{other} to #{self}" if size != other.size
	    Point[Array.new(size) {|i| @elements[i] + other[i] }]
    end
end

#+@Object



241
242
243
# File 'lib/geometry/point.rb', line 241

def +@
    self
end

#-(other) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/geometry/point.rb', line 268

def -(other)
    case other
	when Numeric
	    Point[@elements.map {|e| e - other}]
	when PointIso
	    value = other.value
	    Point[@elements.map {|e| e - value}]
	when PointOne
	    Point[@elements.map {|e| e - 1}]
	when PointZero, NilClass
	    self.dup
	else
	    raise OperationNotDefined, "#{other.class} must respond to :size and :[]" unless other.respond_to?(:size) && other.respond_to?(:[])
	    raise DimensionMismatch, "Can't subtract #{other} from #{self}" if size != other.size
	    Point[Array.new(size) {|i| @elements[i] - other[i] }]
    end
end

#-@Object



245
246
247
# File 'lib/geometry/point.rb', line 245

def -@
    Point[@elements.map {|e| -e }]
end

#/(other) ⇒ Object



305
306
307
308
309
310
311
312
# File 'lib/geometry/point.rb', line 305

def /(other)
    case other
	when Matrix, Vector, Point, Size, NilClass, PointZero, SizeZero
	    raise OperationNotDefined, "Can't divide #{self} by #{other}"
	else
	    Point[@elements.map {|e| e / other}]
    end
end

#<=>(other) ⇒ Point

Combined comparison operator

Returns:

  • (Point)

    The <=> operator is applied to the elements of the arguments pairwise and the results are returned in a Point



99
100
101
# File 'lib/geometry/point.rb', line 99

def <=>(other)
    Point[self.to_a.zip(other.to_a).map {|a,b| a <=> b}.compact]
end

#==(other) ⇒ Object

Allow comparison with an Array, otherwise do the normal thing



82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/geometry/point.rb', line 82

def ==(other)
    if other.is_a?(Array)
	@elements.eql? other
    elsif other.is_a?(PointIso)
	value = other.value
	@elements.all? {|e| e.eql? value }
    elsif other.is_a?(PointOne)
	@elements.all? {|e| e.eql? 1 }
    elsif other.is_a?(PointZero)
	@elements.all? {|e| e.eql? 0 }
    else
	super other
    end
end

#[](*args) ⇒ Numeric

Returns Element i (starting at 0).

Parameters:

Returns:

  • (Numeric)

    Element i (starting at 0)



215
216
217
# File 'lib/geometry/point.rb', line 215

def [](*args)
    @elements[*args]
end

#cloneObject

Return a copy of the Geometry::Point



61
62
63
# File 'lib/geometry/point.rb', line 61

def clone
    Point[@elements.clone]
end

#coerce(other) ⇒ Object



103
104
105
106
107
108
109
110
111
# File 'lib/geometry/point.rb', line 103

def coerce(other)
    case other
	when Array then [Point[*other], self]
	when Numeric then [Point[Array.new(self.size, other)], self]
	when Vector then [Point[*other], self]
	else
	    raise TypeError, "#{self.class} can't be coerced into #{other.class}"
    end
end

#eql?(other) ⇒ Boolean

Allow comparison with an Array, otherwise do the normal thing

Returns:

  • (Boolean)


66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/geometry/point.rb', line 66

def eql?(other)
    if other.is_a?(Array)
	@elements.eql? other
    elsif other.is_a?(PointIso)
	value = other.value
	@elements.all? {|e| e.eql? value }
    elsif other.is_a?(PointOne)
	@elements.all? {|e| e.eql? 1 }
    elsif other.is_a?(PointZero)
	@elements.all? {|e| e.eql? 0 }
    else
	super other
    end
end

#inspectObject



113
114
115
# File 'lib/geometry/point.rb', line 113

def inspect
    'Point' + @elements.inspect
end

#max(*args) ⇒ Number, Point

Returns:



126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/geometry/point.rb', line 126

def max(*args)
    if args.empty?
	@elements.max
    else
	args = args.first if 1 == args.size
	case args
	    when PointIso   then    self.class[@elements.map {|e| [e, args.value].max }]
	    when PointOne   then    self.class[@elements.map {|e| [e, 1].max }]
	    when PointZero  then    self.class[@elements.map {|e| [e, 0].max }]
	    else
		self.class[@elements.zip(args).map(&:max)]
	end
    end
end

#min(*args) ⇒ Number, Point

Returns:



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/geometry/point.rb', line 145

def min(*args)
    if args.empty?
	@elements.min
    else
	args = args.first if 1 == args.size
	case args
	    when PointIso   then    self.class[@elements.map {|e| [e, args.value].min }]
	    when PointOne   then    self.class[@elements.map {|e| [e, 1].min }]
	    when PointZero  then    self.class[@elements.map {|e| [e, 0].min }]
	    else
		self.class[@elements.zip(args).map(&:min)]
	end
    end
end

#minmax(*args) ⇒ Array<Number>, Array<Point>

Returns:



164
165
166
167
168
169
170
# File 'lib/geometry/point.rb', line 164

def minmax(*args)
    if args.empty?
	@elements.minmax
    else
	[min(*args), max(*args)]
    end
end

#pop(count = 1) ⇒ Point

Returns a new Geometry::Point with the given number of elements removed from the end

Returns:

  • (Point)

    the popped elements



190
191
192
# File 'lib/geometry/point.rb', line 190

def pop(count=1)
    self.class[to_a.pop(count)]
end

#push(*args) ⇒ Point

Returns a new Geometry::Point with the given elements appended

Returns:



196
197
198
# File 'lib/geometry/point.rb', line 196

def push(*args)
    self.class[to_a.push(*args)]
end

#quadrantBool

TODO:

Define the results for points on the axes

Note:

Undefined for all points on the axes, and for dimensionalities other than 2

Return the Geometry::Point‘s quadrant in the 2D Cartesian Euclidean Plane en.wikipedia.org/wiki/Quadrant_(plane_geometry)

Returns:

  • (Bool)

    The Geometry::Point‘s quadrant in the 2D Cartesian Euclidean Plane



177
178
179
180
181
182
183
184
# File 'lib/geometry/point.rb', line 177

def quadrant
    return nil unless elements[1]
    if elements.first > 0
	(elements[1] > 0) ? 1 : 4
    else
	(elements[1] > 0) ? 2 : 3
    end
end

#shift(count = 1) ⇒ Point

Removes the first element and returns it

Returns:

  • (Point)

    the shifted elements



202
203
204
# File 'lib/geometry/point.rb', line 202

def shift(count=1)
    self.class[to_a.shift(count)]
end

#to_sObject



116
117
118
# File 'lib/geometry/point.rb', line 116

def to_s
    'Point' + @elements.to_s
end

#unshift(*args) ⇒ Point

Prepend the given objects and return a new Geometry::Point

Returns:



208
209
210
# File 'lib/geometry/point.rb', line 208

def unshift(*args)
    self.class[to_a.unshift(*args)]
end