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

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



205
206
207
# File 'lib/geometry/point.rb', line 205

def x
  @x
end

#yNumeric (readonly)

Returns Y-component.

Returns:

  • (Numeric)

    Y-component



211
212
213
# File 'lib/geometry/point.rb', line 211

def y
  @y
end

#zNumeric (readonly)

Returns Z-component.

Returns:

  • (Numeric)

    Z-component



217
218
219
# File 'lib/geometry/point.rb', line 217

def z
  @z
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



33
34
35
36
37
38
# File 'lib/geometry/point.rb', line 33

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 ones 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:



44
45
46
# File 'lib/geometry/point.rb', line 44

def self.iso(value, size=nil)
    size ? Point[Array.new(size, 1)] : 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:



51
52
53
# File 'lib/geometry/point.rb', line 51

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:



58
59
60
# File 'lib/geometry/point.rb', line 58

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

Instance Method Details

#*(other) ⇒ Object



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

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



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/geometry/point.rb', line 234

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



225
226
227
# File 'lib/geometry/point.rb', line 225

def +@
    self
end

#-(other) ⇒ Object



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

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



229
230
231
# File 'lib/geometry/point.rb', line 229

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

#/(other) ⇒ Object



289
290
291
292
293
294
295
296
# File 'lib/geometry/point.rb', line 289

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



101
102
103
# File 'lib/geometry/point.rb', line 101

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



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

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)



199
200
201
# File 'lib/geometry/point.rb', line 199

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

#cloneObject

Return a copy of the Geometry::Point



63
64
65
# File 'lib/geometry/point.rb', line 63

def clone
    Point[@elements.clone]
end

#coerce(other) ⇒ Object



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

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)


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

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



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

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



174
175
176
# File 'lib/geometry/point.rb', line 174

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:



180
181
182
# File 'lib/geometry/point.rb', line 180

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

#shift(count = 1) ⇒ Point

Removes the first element and returns it

Returns:

  • (Point)

    the shifted elements



186
187
188
# File 'lib/geometry/point.rb', line 186

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

#to_sObject



118
119
120
# File 'lib/geometry/point.rb', line 118

def to_s
    'Point' + @elements.to_s
end

#unshift(*args) ⇒ Point

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

Returns:



192
193
194
# File 'lib/geometry/point.rb', line 192

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