Skip to content

Instantly share code, notes, and snippets.

@asasine
Last active March 8, 2017 22:34
Show Gist options
  • Select an option

  • Save asasine/b351901820f5fb894b945ce57bf5b37e to your computer and use it in GitHub Desktop.

Select an option

Save asasine/b351901820f5fb894b945ce57bf5b37e to your computer and use it in GitHub Desktop.
"""
Copyright (c) 2017 Adam Sasine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
import math
class Vec3f(object):
def __init__(self, x, y=None, z=None):
"""
Create a new Vec3f instance.
Takes two configurations of arguments.
Arguments:
# set one
v -- a Vec3f instance whose components will be copied.
# set two
x -- a number, the new x component.
y -- a number, the new y component.
z -- a number, the new z component.
"""
self.set(x, y, z)
@property
def x(self):
"""
The x component of a Vec3f.
"""
return self._x
@x.setter
def x(self, value):
self._x = float(value)
@property
def y(self):
"""
The y component of a Vec3f.
"""
return self._y
@y.setter
def y(self, value):
self._y = float(value)
@property
def z(self):
"""
The z value of a Vec3f.
"""
return self._z
@z.setter
def z(self, value):
self._z = float(value)
def set(self, x, y=None, z=None):
"""
Set the components of a Vec3f.
Takes two configurations of arguments.
Arguments:
# set one
v -- a Vec3f instance whose components will be copied.
# set two
x -- a number, the new x component.
y -- a number, the new y component.
z -- a number, the new z component.
Return:
The modified Vec3f instance.
"""
if isinstance(x, Vec3f):
self.x = x.x
self.y = x.y
self.z = x.z
else:
self.x = x
self.y = y
self.z = z
self._magSq = pow(self.x, 2) + pow(self.y, 2) + pow(self.z, 2)
self._mag = math.sqrt(self.magSq)
self._unit = None # calculate when retrieved
return self
@property
def mag(self):
"""
The magnitude of a Vec3f.
"""
return self._mag
@mag.setter
def mag(self, value):
self.set(self.unit().mul(value))
@property
def magSq(self):
"""
The magnitude squared of a Vec3f.
"""
return self._magSq
@magSq.setter
def magSq(self, value):
self.mag = math.sqrt(value)
def unit(self):
"""
The unit vector of a Vec3f.
"""
if self._unit is None:
self._unit = self.div(self.mag)
return self._unit
def normalize(self):
"""
Normalize and modify this Vec3f.
Internally sets the magnitude to 1.
Returns:
This Vec3f, normalized.
"""
self.mag = 1
return self
def copy(self):
"""
Copy this Vec3f into another instance.
Returns:
A new Vec3f.
"""
return Vec3f(self.x, self.y, self.z)
def add(self, v, modify=False):
"""
Add this Vec3f to another Vec3f.
Arguments:
v -- a Vec3f instance to add.
modify -- a boolean (default=False) flagging whether to create a new Vec3f or modify the current one.
Returns:
A Vec3f instance.
"""
x = self.x + v.x
y = self.y + v.y
z = self.z + v.z
if modify:
return self.set(x, y, z)
else:
return Vec3f(x, y, z)
def sub(self, v, modify=False):
"""
Subtract this Vec3f from another Vec3f.
Arguments:
v -- a Vec3f instance to subtract.
modify -- a boolean (default=False) flagging whether to create a new Vec3f or modify the current one.
Returns:
A Vec3f instance.
"""
x = self.x - v.x
y = self.y - v.y
z = self.z - v.z
if modify:
return self.set(x, y, z)
else:
return Vec3f(x, y, z)
def mul(self, s, modify=False):
"""
Multiply this Vec3f by a scalar.
Arguments:
s -- a number, the scalar.
modify -- a boolean (default=False) flagging whether to create a new Vec3f or modify the current one.
Returns:
A Vec3f instance.
"""
x = s * self.x
y = s * self.y
z = s * self.z
if modify:
return self.set(x, y, z)
else:
return Vec3f(x, y, z)
def div(self, s, modify=False):
"""
Divide this Vec3f by a scalar.
Internally calls mul with the inverse of s.
Arguments:
s -- a number, the scalar.
modify -- a boolean (default=False) flagging whether to create a new Vec3f or modify the current one.
Returns:
A Vec3f instance.
"""
return self.mul(1.0 / s, modify=modify)
def cross(self, v, modify=False):
"""
Cross product of this Vec3f and another Vec3f.
Arguments:
v -- a Vec3f instance.
modify -- a boolean (default=False) flagging whether to create a new Vec3f or modify the current one.
Returns:
A Vec3f instance.
"""
x = self.y * v.z - self.z * v.y
y = self.z * v.x - self.x * v.z
z = self.x * v.y - self.y * v.x
if modify:
return self.set(x, y, z)
else:
return Vec3f(x, y, z)
def piecewise(self, v, modify=False):
"""
Piecewise multiply this Vec3f by another Vec3f.
The Hadamard product of two column matrices.
Arguments:
v -- a Vec3f instance to piecewise multiply.
modify -- a boolean (default=False) flagging whether to create a new Vec3f or modify the current one.
Returns:
A Vec3f instance.
"""
if modify:
return self.set(self.x * v.x, self.y * v.y, self.z * v.z)
else:
return Vec3f(self.x * v.x, self.y * v.y, self.z * v.z)
def dot(self, v):
"""
Find the dot product of this Vec3f with another Vec3f.
Arguments:
v -- a Vec3f instance.
Returns:
A number, the dot product.
"""
return self.x * v.x + self.y * v.y + self.z * v.z
def dist(self, v):
"""
Euclidean distance between this Vec3f to another Vec3f.
The magnitude of this Vec3f subtracted from another Vec3f.
Arguments:
v -- a Vec3f instance.
Returns:
A number, the Euclidean distance.
"""
return self.sub(v).mag
def angle(self, v, degrees=False):
"""
The angle between this Vec3f and another Vec3f.
The arc cosine of the dot product of the unit vectors of this Vec3f and another Vec3f.
Arguments:
v -- a Vec3f instance.
degrees -- a boolean (default=False), to return in degrees (True) or radians (False)
Returns:
A number, the angle in radians or degrees.
"""
theta = math.acos(self.unit().dot(v.unit()))
if degrees:
return math.degrees(theta)
else:
return theta
def __repr__(self):
return "<Vec3f(x={}, y={}, z={})>".format(self.x, self.y, self.z)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment