Category talk:Wren-vector: Difference between revisions
Content added Content deleted
(→Source code: Bug fix.) |
(→Source code: Numerous changes most notably renaming Vector class to Vector2 and adding a generic n-dimensional Vector class.) |
||
Line 3:
<syntaxhighlight lang="ecmascript">/* Module "vector.wren" */
/*
Vector represents a vector in n-dimensional Euclidean space.
For two or three dimensional geometric vectors, the specialist
classes Vector2 or Vector3 should normally be used instead
as they have greater functionality including support for
construction using coordinate systems other than Cartesian.
*/
class Vector {
//
static
// Returns v1 * v2 or v2 * v1 depending on which order the arguments are presented.
Line 19 ⟶ 21:
}
// Efficiently sums a list of
static sumAll(
if (!(
Fiber.abort("Argument must be a non-empty list of
}
if (Vectors.count == 1) return Vectors[0].copy()
var n = Vectors[0].n
var si = List.filled(n, 0)
for (i in 0...n) {
si[i] = Vectors.map { |v| v[i] }.reduce { |acc, e| acc + e }
}
return Vector.new(si)
}
// Constructs a Vector from a non-empty list of cartesian coordinates.
construct new(a) {
if (!(a is List) || a.count == 0 || !(a[0] is Num)) {
Fiber.abort("Argument must be a non-empty list of numbers.")
}
_a = a.toList
_n = a.count // save dimension as a separate field
}
// Self-evident properties.
n { _n }
[i] {
if (!(i is Num) || !(i.isInteger) || i < 0 || i >= _n) {
Fiber.abort("Index must be an integer between 0 and %(_n - 1) inclusive.")
}
return _a[i]
}
[i]=(v) {
if (!(i is Num) || !(i.isInteger) || i < 0 || i >= _n) {
Fiber.abort("Index must be an integer between 0 and %(_n - 1) inclusive.")
}
if (!(v is Num)) Fiber.abort("Value must be a number.")
return _a[i] = v
}
square { a.map { |v| v * v }.reduce { |acc, e| acc + e } }
length { square.sqrt }
manhattan { a.map { |v| v.abs }.reduce { |acc, e| acc + e } }
// Returns a unit Vector with the same direction as this one.
unit {
if (length == 0) return Vector.zero(_n)
return Vector.new(a.map { |v| v / length }.toList)
}
// Basic operations.
-{ Vector.new(a.map { |v| -v }.toList) }
+(other) {
if (other is Num) {
return Vector.new((0..._n).map { |i| this[i] + other }.toList)
}
if (!(other is Vector) || _n != other.n) {
Fiber.abort("Other must be a Vector of dimension %(_n).")
}
return Vector.new((0..._n).map { |i| this[i] + other[i] }.toList)
}
-(other) { this + (-other) }
*(n) {
if (!(n is Num)) Fiber.abort("n must be a number.")
return Vector.new(a.map { |v| v * n }.toList)
}
/(n) {
if (!(n is Num)) Fiber.abort("n must be a number.")
return Vector.new(a.map { |v| v / n }.toList)
}
==(other) {
if (!(other is Vector || _n != other.n)) {
Fiber.abort("Other must be a Vector of dimension %(_n).")
}
return (0..._n).all { |i| this[i] == other[i] }
}
!=(other) { !(this == other) }
// Returns the dot product of this and another Vector of the same dimension.
dot(other) {
if (!(other is Vector) || _n != other.n) {
Fiber.abort("Other must be a Vector of dimension %(_n).")
}
return (0..._n).map { |i| this[i] * other[i] }.reduce { |acc, e| acc + e }
}
// Returns whether or not this Vector is perpendicular to another one.
isPerpTo(other) { this.dot(other) == 0 }
// Returns the distance between this and another Vector.
dist(other) {
if (!(other is Vector) || _n != other.n) {
Fiber.abort("Other must be a Vector of dimension %(_n).")
}
return (0..._n).map { |i| this[i] - other[i] }.reduce(0) { |acc, e| acc + e * e }.sqrt
}
// Returns a copy of this Vector.
copy() { Vector.new(_a) }
// Returns the cartesian coordinates of this Vector as a list.
toCartesian { _a.toList }
// Returns a string representation of this Vector in cartesian coordinates.
toString { "(" + _a.join(", ") + ")" }
}
/* Vector2 represents a two dimensional geometric vector in the plane. */
class Vector2 {
// Gets or sets the default angle unit.
static useDegrees { __useDeg }
static useDegrees=(v) { (v is Bool) ? __useDeg = v : Fiber.abort("Invalid argument.") }
// Returns a zero Vector2.
static zero { Vector2.new(0, 0) }
// Returns v1 * v2 or v2 * v1 depending on which order the arguments are presented.
static scale(v1, v2) {
if ((v1 is Vector2) && (v2 is Num)) return v1 * v2
if ((v1 is Num) && (v2 is Vector2)) return v2 * v1
Fiber.abort("One argument must be a Vector2 and the other a number.")
}
// Efficiently sums a list of vector2s.
static sumAll(vector2s) {
if (!(vector2s is List) || vector2s.count == 0 || !(vector2s[0] is Vector2)) {
Fiber.abort("Argument must be a non-empty list of vector2s.")
}
if (
var sx = vector2s.map { |v| v.x }.reduce { |acc, x| acc + x }
var
return Vector2.new(sx, sy)
}
// Constructs a
static fromPolar(r, theta) {
if (!(r is Num) || !(theta is Num)) Fiber.abort("Arguments must both be numbers.")
Line 38 ⟶ 170:
}
// Constructs a
construct new(x, y) {
if (!(x is Num) || !(y is Num)) Fiber.abort("Arguments must both be numbers.")
Line 63 ⟶ 195:
}
// Returns a
perp {
// Returns a unit
unit {
if (length == 0) return
return
}
// Basic operations.
-{
+(other) {
if
if (!(other is Vector2)) Fiber.abort("Other must be a Vector2 or a scalar.")
return Vector2.new(_x + other.x, _y + other.y)
}
-(other) { this + (-other) }
*(n) {
if (!(n is Num)) Fiber.abort("n must be a number.")
return
}
/(n) {
if (!(n is Num)) Fiber.abort("n must be a number.")
return
}
==(other) {
if (!(other is
return x == other.x && _y == other.y
}
Line 100 ⟶ 233:
!=(other) { !(this == other) }
// Returns the dot product of this and another
dot(other) {
if (!(other is
return _x * other.x + _y * other.y
}
// Returns whether or not this
isPerpTo(other) { this.dot(other) == 0 }
// Returns the angle between this
angleBetween(other) {
var v = (this.dot(other)/(length * other.length)).acos
if (__useDeg) v = v * 180 / Num.pi
Line 120 ⟶ 249:
}
// Returns the distance between this and another
dist(other) {
if (!(other is
var d1 = _x - other.x
var d2 = _y - other.y
Line 128 ⟶ 257:
}
// Returns a copy of this
copy() {
// Returns the cartesian coordinates of this
toCartesian { [_x, _y] }
// Returns the polar coordinates of this
toPolar { !__useDeg ? [radius, theta] : [radius, theta * 180 / Num.pi] }
//
toVector { Vector.new(toCartesian) }
// Returns a string representation of this Vector2 in cartesian coordinates.
toString { "(%(_x), %(_y))" }
}
Line 163 ⟶ 295:
}
if (vector3s.count == 1) return vector3s[0].copy()
var sx = vector3s.map { |v| v.x }.reduce { |acc, x| acc + x }
var sy = vector3s.map { |v| v.y }.reduce { |acc, y| acc + y }
Line 239 ⟶ 370:
+(other) {
if
if (!(other is Vector3)) Fiber.abort("Other must be a Vector3 or a scalar.")
return Vector3.new(_x + other.x, _y + other.y, _z + other.z)
}
Line 279 ⟶ 411:
// Returns the scalar triple product of this and two other Vector3s.
scalarTripleProd(other1, other2) { this.dot(other1.cross(other2)) }
// Returns the vector triple product of this and two other Vector3s.
vectorTripleProd(other1, other2) { this.cross(other1.cross(other2)) }
// Returns the scalar quadruple product of this and three other Vector3s.
scalarQuodProd(other1, other2, other3) { this.cross(other1).dot(other2.cross(other3)) }
// Returns the vector quadruple product of this and three other Vector3s.
vectorQuodProd(other1, other2, other3) { this.cross(other1).cross(other2.cross(other3)) }
// Returns whether or not this Vector3 is perpendicular to another one.
isPerpTo(other) { this.dot(other) == 0 }
// Returns the angle between this Vector3 and another one.
angleBetween(other) {
var v = (this.dot(other)/(length * other.length)).acos
if (__useDeg) v = v * 180 / Num.pi
Line 320 ⟶ 434:
// Returns the distance between this and another Vector3.
dist(other) {
if (!(other is
var d1 = _x - other.x
var d2 = _y - other.y
Line 334 ⟶ 448:
// Returns the cylindrical coordinates of this Vector3 as a list.
toCylindrical { !__useDeg ? [radius, theta, _z] : [radius, theta * 180 / Num.pi , _z]}
// Returns the spherical coordinates of this Vector3 as a list.
toSpherical { !__useDeg ? [length, theta, phi] : [length, theta * 180 /Num.pi, phi * 180 / Num.pi] }
// Converts this Vector3 to a generic Vector.
toVector { Vector.new(toCartesian) }
// Returns a string representation of this Vector3 in cartesian coordinates.
Line 344 ⟶ 461:
// Set initial angle unit defaults (radians).
Vector3.useDegrees = false</syntaxhighlight>
|