"""
domonic.geom.vec2
====================================
"""
import math
# import operator
[docs]
class vec2:
"""[vec2]"""
def __init__(self, x: float = 0, y: float = 0):
self.x: float = x
self.y: float = y
def __mul__(self, other):
if isinstance(other, (int, float)):
return vec2(self.x * other, self.y * other)
if isinstance(other, vec2):
return vec2(self.x * other.x, self.y * other.y)
raise ValueError("Unsupported operand type for multiplication")
def __div__(self, other):
if isinstance(other, vec2):
return self.__class__((self.x / other.x, self.y / other.y))
else:
return self.__class__((self.x / other, self.y / other))
def __mod__(self, other):
if isinstance(other, vec2):
return self.__class__(self.x % other.x, self.y % other.y)
else:
return self.__class__(self.x % other, self.y % other)
def __getitem__(self, item):
if isinstance(item, int):
if item == 0:
return self.x
elif item == 1:
return self.y
elif isinstance(item, str):
if item == "x":
return self.x
elif item == "y":
return self.y
def __len__(self):
return 2
def __add__(self, other):
if isinstance(other, vec2):
return vec2(self.x + other.x, self.y + other.y)
if isinstance(other, (int, float)):
return vec2(self.x + other, self.y + other)
raise ValueError("Unsupported operand type for subtraction")
def __sub__(self, other):
if isinstance(other, vec2):
return vec2(self.x - other.x, self.y - other.y)
if isinstance(other, (int, float)):
return vec2(self.x - other, self.y - other)
raise ValueError("Unsupported operand type for subtraction")
def __truediv__(self, other):
if isinstance(other, (int, float)):
return vec2(self.x / other, self.y / other)
if isinstance(other, vec2):
return vec2(self.x / other.x, self.y / other.y)
raise ValueError("Unsupported operand type for division")
def __floordiv__(self, other):
if isinstance(other, vec2):
return vec2(self.x // other.x, self.y // other.y)
if isinstance(other, (int, float)):
return vec2(self.x // other, self.y // other)
raise ValueError("Unsupported operand type for division")
def __neg__(self):
return vec2(-self.x, -self.y)
def __eq__(self, other):
if isinstance(other, vec2):
return self.x == other.x and self.y == other.y
return False
def __ne__(self, other):
return self.x != other.x or self.y != other.y
def __lt__(self, other):
return self.x < other.x and self.y < other.y
def __le__(self, other):
return self.x <= other.x and self.y <= other.y
def __gt__(self, other):
return self.x > other.x and self.y > other.y
def __ge__(self, other):
return self.x >= other.x and self.y >= other.y
def __hash__(self):
return hash((self.x, self.y))
def __setitem__(self, key, value):
if key == 0:
self.x = value
elif key == 1:
self.y = value
else:
raise IndexError("Index out of range")
def __iter__(self):
yield self.x
yield self.y
def __call__(self, *args, **kwargs):
return self.x, self.y
def __getstate__(self):
return self.x, self.y
def __copy__(self):
return vec2(self.x, self.y)
def __deepcopy__(self, memo):
return vec2(self.x, self.y)
def __round__(self, n):
return vec2(round(self.x, n), round(self.y, n))
def __str__(self):
return str(self.x) + " " + str(self.y)
[docs]
def add(self, pt):
"""Adds a point to this point. returns new one"""
return vec2(self.x + pt.x, self.y + pt.y)
[docs]
def subtract(self, pt):
"""Subtract from this point. returns new one"""
return vec2(self.x - pt.x, self.y - pt.y)
[docs]
def copy(self):
"""Creates a copy of this Point object."""
return vec2(self.x, self.y)
[docs]
def dot(self, other):
"""Returns the dot product of these two vectors"""
x1 = self.x
y1 = self.y
x2 = other.x
y2 = other.y
return x1 * x2 + y1 * y2
[docs]
def cross(self, other):
"""Returns the cross product of this and other. The cross product is considered 0
perpendicular to each other point"""
x1 = self.x
y1 = self.y
x2 = other.x
y2 = other.y
return x1 * y2 - y1 * x2
[docs]
def negative(self):
"""return vector but negative version"""
return vec2(-self.x, -self.y)
def distance(self, other):
x_dot = self.x - other.x
y_dot = self.y - other.y
return math.sqrt(x_dot * x_dot + y_dot * y_dot)
def squareDistance(self, other):
return self.distance(self) * self.distance(other)
[docs]
def equals(self, other):
"""Returns true if all vectors components are the same"""
return self.x == other.x and self.y == other.y
[docs]
def interpolate(self, pt1, pt2, t):
"""Calculates the point that would be reached by this Point
if we moved by a given distance vector over time t.
Only floats are handled here."""
return vec2(self.x * (1 - t) + pt1.x * t, self.y * (1 - t) + pt1.y * t)
[docs]
def copyRotateAround(self, target, angle):
"""moves the vector then rotate"""
self.rotateAround(target, angle)
return vec2(self.x, self.y)
def mirrorHorizontally(self):
return self.rotateAround(vec2(1, 0), 90)
def mirrorVertically(self):
return self.rotateAround(vec2(0, 1), 90)
[docs]
def negate(self):
"""Negate a vector. This results in vector with the same direction but different length"""
return vec2(-self.x, -self.y)
[docs]
def length(self):
"""returns the length of this vector"""
return self.x
[docs]
def squaredlength(self):
"""returns the squared length of this vector"""
return self.x * self.x + self.y * self.y
[docs]
def normalize(self):
"""returns a normalized vector"""
return self / self.length()
[docs]
def obj(self):
"""returns a obj representation of this vector"""
return {"x": self.x, "y": self.y}
# def __repr__(self):
# return str(self.x) + " " + str(self.y)
[docs]
def json(self):
"""returns a json representation of this vector"""
return str({"x": self.x, "y": self.y})
[docs]
def angle(self):
"""returns the angle of this vector in radians"""
return math.atan2(self.y, self.x)
[docs]
def angleBetween(self, other):
"""returns the angle between this and another vector in radians"""
return math.acos(self.dot(other) / (self.length() * other.length()))
[docs]
def rotate(self, angle):
"""rotates this vector by an angle in radians"""
x = self.x
y = self.y
self.x = x * math.cos(angle) - y * math.sin(angle)
self.y = y * math.cos(angle) + x * math.sin(angle)
[docs]
def rotateAround(self, target, angle):
"""Rotates the vector around another point. In fact it returns the other point."""
dot = self.dot(target)
s = math.sin(angle / 2)
c = math.cos(angle / 2)
x = s * (self.x - dot * c) + c
y = s * (self.y - dot * c) - c
return vec2(x, y)
[docs]
@staticmethod
def cmp(a, b):
"""Compare two vectors."""
return (a > b) - (a < b)
# @staticmethod
# def random():
# """ returns a random vector """
# return vec2(random.random(), random.random())
[docs]
@staticmethod
def random(min_x, max_x, min_y, max_y):
"""returns a random vector"""
import random
return vec2(random.uniform(min_x, max_x), random.uniform(min_y, max_y))
[docs]
@staticmethod
def random_unit_vector(min_x, max_x, min_y, max_y):
"""returns a random unit vector"""
vec = vec2.random(min_x, max_x, min_y, max_y)
return vec.normalize()
[docs]
@staticmethod
def random_point_in_circle(center, radius):
"""returns a random point in a circle"""
vec = vec2.random(0, radius)
return vec.add(center)
[docs]
@staticmethod
def random_point_in_rectangle(min_x, max_x, min_y, max_y):
"""returns a random point in a rectangle"""
vec = vec2.random(min_x, max_x, min_y, max_y)
return vec.add(vec2.random(0, 1))
# def rotateAround(self, target, angle):
# """ Rotates the vector around another point. In fact it returns the other point."""
# dot = self.dot(target)
# s = math.sin(angle)
# c = math.cos(angle)
# x = s * (self.x - dot * c) + c
# y = s * (self.y - dot * c) - c
# return vec2(x, y)
# def rotateAroundLocal(self, point, angle):
# """ Rotates the vector around a point. In fact it returns itself."""
# dot = self.dot(point)
# s = math.sin(angle)
# c = math.cos(angle)
# x = s * (self.x - dot * c) + c
# y = s * (self.y - dot * c) - c
# return vec2(x, y)
# def rotateLocal(self, point, angle):
# """ Rotates the vector around a point. In fact it returns itself."""
# dot = self.dot(point)
# s = math.sin(angle)
# c = math.cos(angle)
# x = s * (self.x - dot * c) + c
# y = s * (self.y - dot * c) - c
# self.x = x
# self.y = y
# return self