763 lines
20 KiB
Python
Executable File
763 lines
20 KiB
Python
Executable File
import math
|
|
|
|
__all__ = [
|
|
# value types
|
|
'Const',
|
|
'Var',
|
|
# math functions
|
|
'Add',
|
|
'Div',
|
|
'Round',
|
|
'Pow',
|
|
'Mod',
|
|
'Mul',
|
|
'Neg',
|
|
'Sub',
|
|
'Lt',
|
|
'Le',
|
|
'Eql',
|
|
'NEql',
|
|
'Ge',
|
|
'Gt',
|
|
'Sin',
|
|
'Sinh',
|
|
'Cos',
|
|
'Cosh',
|
|
'Tan',
|
|
'Tanh',
|
|
# other types
|
|
'Vec'
|
|
]
|
|
|
|
"""
|
|
bracketLevel:
|
|
0: never
|
|
1: add, sub
|
|
2: mul, div
|
|
3: always
|
|
"""
|
|
def addBrackets(f, bl):
|
|
s = str(f)
|
|
if ( (bl >= 1 and isinstance(f, (Add, Sub)))
|
|
or (bl >= 2 and isinstance(f, (Mul, Div)))
|
|
or (bl >= 3 and not isinstance(f, (Const, Var)))):
|
|
s = "(" + s + ")"
|
|
return s
|
|
|
|
# =================================================================
|
|
# == function =====================================================
|
|
# =================================================================
|
|
|
|
class Func:
|
|
def __init__(self, left, right):
|
|
if isinstance(left, (int, float)):
|
|
self.left = Const(left)
|
|
else:
|
|
self.left = left
|
|
if isinstance(right, (int, float)):
|
|
self.right = Const(right)
|
|
else:
|
|
self.right = right
|
|
|
|
def solve(self, vars):
|
|
l = self.left.solve(vars)
|
|
r = self.right.solve(vars)
|
|
val = self.fn(l, r)
|
|
print("solve(): " + str(self.copy()(l, r)) + ' = ' + str(val))
|
|
return val
|
|
# return self.fn(self.left.solve(vars), self.right.solve(vars))
|
|
|
|
def simplify(self):
|
|
left = self.left.simplify()
|
|
right = self.right.simplify()
|
|
if isinstance(left, Const) and isinstance(right, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return self.copy()(left, right)
|
|
|
|
def __add__(self, other): # self + other
|
|
return Add(self, other)
|
|
def __truediv__(self, other): # self / other
|
|
return Div(self, other)
|
|
#TODO: change round to floor
|
|
def __floordiv__(self, other): # self // other
|
|
return Round(Div(self, other))
|
|
def __pow__(self, other): # self ** other
|
|
return Pow(self, other)
|
|
def __mod__(self, other): # self % other
|
|
return Mod(self, other)
|
|
def __mul__(self, other): # self * other
|
|
return Mul(self, other)
|
|
def __neg__(self): # -self
|
|
return Neg(self)
|
|
def __sub__(self, other): # self - other
|
|
return Sub(self, other)
|
|
def __lt__(self, other): # self < other
|
|
return Lt(self, other)
|
|
def __le__(self, other): # self <= other
|
|
return Le(self, other)
|
|
def __eq__(self, other): # self == other
|
|
return Eql(self, other)
|
|
def __ne__(self, other): # self != other
|
|
return NEql(self, other)
|
|
def __ge__(self, other): # self >= other
|
|
return Ge(self, other)
|
|
def __gt__(self, other): # self > other
|
|
return Gt(self, other)
|
|
|
|
def __str__ (self):
|
|
s = addBrackets(self.left, self.bracketLevel)
|
|
s += ' ' + self.symbol + ' '
|
|
s += addBrackets(self.right, self.bracketLevel)
|
|
return s
|
|
|
|
|
|
# =================================================================
|
|
# == Const ========================================================
|
|
# =================================================================
|
|
|
|
class Const(Func):
|
|
def __init__(self, value):
|
|
self.value = value
|
|
|
|
def solve(self, vars):
|
|
return self.value
|
|
|
|
def copy(self):
|
|
return Const
|
|
|
|
def simplify(self): #TODO: return copy of itself
|
|
return self
|
|
|
|
def __str__(self):
|
|
return str(self.value)
|
|
|
|
# =================================================================
|
|
# == Var ==========================================================
|
|
# =================================================================
|
|
|
|
class Var(Func):
|
|
def __init__ (self, name):
|
|
self.name = name
|
|
|
|
def solve(self, vars):
|
|
return vars[self.name]
|
|
|
|
def copy(self):
|
|
return Var
|
|
|
|
def simplify(self): #TODO: return copy of itself
|
|
return self
|
|
|
|
def __str__(self):
|
|
return str(self.name)
|
|
|
|
# =================================================================
|
|
# == Add ==========================================================
|
|
# =================================================================
|
|
|
|
class Add(Func):
|
|
symbol = '+'
|
|
bracketLevel = 0
|
|
|
|
def fn(self, a, b):
|
|
return a + b
|
|
|
|
def copy(self):
|
|
return Add
|
|
|
|
# =================================================================
|
|
# == Div ==========================================================
|
|
# =================================================================
|
|
|
|
class Div(Func):
|
|
symbol = '/'
|
|
bracketLevel = 1
|
|
|
|
def fn(self, a, b):
|
|
return a / b
|
|
|
|
def copy(self):
|
|
return Div
|
|
|
|
# =================================================================
|
|
# == Round ==========================================================
|
|
# =================================================================
|
|
|
|
class Round(Func):
|
|
def __init__(self, function, p=0):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
self.p = 10**p
|
|
|
|
def solve(self, vars):
|
|
anser = self.function.solve(vars)
|
|
anser = float(int(anser*self.p + 0.5)) / self.p
|
|
return anser
|
|
|
|
def copy(self):
|
|
return Round
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({})) #TODO: make use of the solved version
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__(self):
|
|
return "round(" + str(self.function) + ")"
|
|
|
|
# =================================================================
|
|
# == Pow ==========================================================
|
|
# =================================================================
|
|
|
|
class Pow(Func):
|
|
symbol = '^'
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a ** b
|
|
|
|
def copy(self):
|
|
return Pow
|
|
|
|
# =================================================================
|
|
# == Mod ==========================================================
|
|
# =================================================================
|
|
|
|
class Mod(Func):
|
|
symbol = '%'
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a % b
|
|
|
|
def copy(self):
|
|
return Mod
|
|
|
|
# =================================================================
|
|
# == Mul ==========================================================
|
|
# =================================================================
|
|
|
|
class Mul(Func):
|
|
symbol = '*'
|
|
bracketLevel = 1
|
|
|
|
def fn(self, a, b):
|
|
return a * b
|
|
|
|
def copy(self):
|
|
return Mul
|
|
|
|
# =================================================================
|
|
# == Neg ==========================================================
|
|
# =================================================================
|
|
|
|
class Neg(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return -self.function.solve(vars)
|
|
|
|
def copy(self):
|
|
return Neg
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Neg(f)
|
|
|
|
def __str__(self):
|
|
return "-" + addBrackets(self.function, 3)
|
|
|
|
# =================================================================
|
|
# == Sub ==========================================================
|
|
# =================================================================
|
|
|
|
class Sub(Func):
|
|
symbol = '-'
|
|
bracketLevel = 2
|
|
|
|
def fn(self, a, b):
|
|
return a - b
|
|
|
|
def copy(self):
|
|
return Sub
|
|
|
|
def __str__ (self):
|
|
s = addBrackets(self.left, 0)
|
|
s += ' ' + self.symbol + ' '
|
|
s += addBrackets(self.right, self.bracketLevel)
|
|
return s
|
|
|
|
# =================================================================
|
|
# == Lt ==========================================================
|
|
# =================================================================
|
|
|
|
class Lt(Func):
|
|
symbol = '<'
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a < b
|
|
|
|
def copy(self):
|
|
return Lt
|
|
|
|
# =================================================================
|
|
# == Le ==========================================================
|
|
# =================================================================
|
|
|
|
class Le(Func):
|
|
symbol = '<='
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a <= b
|
|
|
|
def copy(self):
|
|
return Le
|
|
|
|
# =================================================================
|
|
# == Eql ==========================================================
|
|
# =================================================================
|
|
|
|
class Eql(Func):
|
|
symbol = '='
|
|
bracketLevel = 0
|
|
|
|
def fn(self, a, b):
|
|
return a == b
|
|
|
|
def copy(self):
|
|
return Eql
|
|
|
|
def simplify(self):
|
|
if ( (isinstance(self.left, self.right.copy())) # same opperation
|
|
and (not isinstance(self.left, (Const, Var, Round))) # not const, var or Round
|
|
and (self.left.right is self.right.right)): # subthing is the same
|
|
return self.copy()(self.left.left.simplify(), self.right.left.simplify())
|
|
return self.copy()(self.left.simplify(), self.right.simplify())
|
|
|
|
# =================================================================
|
|
# == NEql ==========================================================
|
|
# =================================================================
|
|
|
|
class NEql(Func):
|
|
symbol = '!='
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a != b
|
|
|
|
def copy(self):
|
|
return NEql
|
|
|
|
# =================================================================
|
|
# == Ge ==========================================================
|
|
# =================================================================
|
|
|
|
class Ge(Func):
|
|
symbol = '>='
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a >= b
|
|
|
|
def copy(self):
|
|
return Ge
|
|
|
|
# =================================================================
|
|
# == Gt ==========================================================
|
|
# =================================================================
|
|
|
|
class Gt(Func):
|
|
symbol = '>'
|
|
bracketLevel = 3
|
|
|
|
def fn(self, a, b):
|
|
return a > b
|
|
|
|
def copy(self):
|
|
return Gt
|
|
|
|
# =================================================================
|
|
# == Sin ==========================================================
|
|
# =================================================================
|
|
|
|
class Sin(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return math.sin(self.function.solve(vars))
|
|
|
|
def copy(self):
|
|
return Sin
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__ (self):
|
|
return 'sin(' + str(self.function) + ')'
|
|
|
|
# =================================================================
|
|
# == Sinh =========================================================
|
|
# =================================================================
|
|
|
|
class Sinh(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return math.sinh(self.function.solve(vars))
|
|
|
|
def copy(self):
|
|
return Sinh
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__ (self):
|
|
return 'sinh(' + str(self.function) + ')'
|
|
|
|
# =================================================================
|
|
# == Cos ==========================================================
|
|
# =================================================================
|
|
|
|
class Cos(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return math.Cos(self.function.solve(vars))
|
|
|
|
def copy(self):
|
|
return Cos
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__ (self):
|
|
return 'Cos(' + str(self.function) + ')'
|
|
|
|
# =================================================================
|
|
# == Cosh =========================================================
|
|
# =================================================================
|
|
|
|
class Cosh(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return math.Cosh(self.function.solve(vars))
|
|
|
|
def copy(self):
|
|
return Cosh
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__ (self):
|
|
return 'Cosh(' + str(self.function) + ')'
|
|
|
|
# =================================================================
|
|
# == Tan ==========================================================
|
|
# =================================================================
|
|
|
|
class Tan(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return math.tan(self.function.solve(vars))
|
|
|
|
def copy(self):
|
|
return tan
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__ (self):
|
|
return 'tan(' + str(self.function) + ')'
|
|
|
|
# =================================================================
|
|
# == Tanh =========================================================
|
|
# =================================================================
|
|
|
|
class Tanh(Func):
|
|
def __init__(self, function):
|
|
if isinstance(function, (int, float)):
|
|
self.function = Const(function)
|
|
else:
|
|
self.function = function
|
|
|
|
def solve(self, vars):
|
|
return math.tanh(self.function.solve(vars))
|
|
|
|
def copy(self):
|
|
return tanh
|
|
|
|
def simplify(self):
|
|
f = self.function.simplify()
|
|
if isinstance(f, Const):
|
|
return Const(self.solve({}))
|
|
else:
|
|
return Round(f)
|
|
|
|
def __str__ (self):
|
|
return 'tanh(' + str(self.function) + ')'
|
|
|
|
# =================================================================
|
|
# == Vec ==========================================================
|
|
# =================================================================
|
|
|
|
class Vec:
|
|
def __init__ (self, x: float, y: float, z: float) -> None:
|
|
...
|
|
def __init__ (self, x: float, y: float) -> None:
|
|
...
|
|
def __init__ (self, x: float) -> None:
|
|
...
|
|
def __init__ (self, x: "Vec") -> None:
|
|
...
|
|
def __init__ (self) -> None:
|
|
...
|
|
def __init__ (self, *args) -> None:
|
|
if len(args) == 3:
|
|
self.cartesian(*args)
|
|
elif len(args) == 2:
|
|
self.cartesian(*args, 0.0)
|
|
elif len(args) == 1:
|
|
if(isinstance(args[0], Vec)):
|
|
self.cartesian(args[0].getCartasian())
|
|
self.cartesian(*args, 0.0, 0.0)
|
|
|
|
|
|
def cartesian(self, x: float, y: float, z: float) -> tuple:
|
|
...
|
|
def cartesian(self, corts: tuple) -> tuple:
|
|
...
|
|
def cartesian(self, *args) -> tuple:
|
|
if len(args) == 3:
|
|
self.x = args[0]
|
|
self.y = args[1]
|
|
self.z = args[2]
|
|
elif len(args) == 1:
|
|
self.x = args[0][0]
|
|
self.y = args[0][1]
|
|
self.z = args[0][2]
|
|
return (self.x, self.y, self.z)
|
|
|
|
|
|
def polar(self, a: tuple, l: float) -> None:
|
|
...
|
|
def polar(self) -> tuple:
|
|
...
|
|
def polar(self, *args):
|
|
if len(args) == 2:
|
|
if not isinstance(args[0], (tuple, list)):
|
|
raise ValueError('Vec.polar(): first argument must be a tuple or list. ' + str(type(args[0])) + ' given')
|
|
if len(args[0]) < 3:
|
|
raise ValueError('Vec.polar(): first argument must be at least 3 items long')
|
|
if not isinstance(args[1], (int, float)):
|
|
raise ValueError('Vec.polar(): second argument must be a int or float. ' + str(type(args[1])) + ' given')
|
|
# xy angle xz angle yz angle
|
|
self.x = math.sin(args[0][0]) #* math.sin(args[0][1])
|
|
self.y = math.cos(args[0][0]) # * math.sin(args[0][2])
|
|
self.z = math.cos(args[0][1]) * math.cos(args[0][2])
|
|
self.mul(self, args[1])
|
|
elif len(args) == 0:
|
|
return (
|
|
(
|
|
math.atan2(self.y, self.x),
|
|
math.atan2(self.z, self.x),
|
|
0.0
|
|
),
|
|
self.length(),
|
|
)
|
|
else:
|
|
raise ValueError("Vec.polar(): Wrong number of arguments given. 2 or 0 suported")
|
|
|
|
def rotate(self, angle):
|
|
if not isinstance(angle, (tuple, list)):
|
|
raise ValueError('Vec.rotate(): first argument must be a tuple or list')
|
|
if len(angle) < 3:
|
|
raise ValueError('Vec.rotate(): first argument must be at least 3 items long')
|
|
p = self.polar()
|
|
a = [p[0][0] + angle[0], p[0][1] + angle[1], p[0][2] + angle[2]]
|
|
self.polar(a, p[1])
|
|
|
|
def length(self, l: float):
|
|
...
|
|
def length(self):
|
|
...
|
|
def length(self, *args):
|
|
if(len(args) == 0):
|
|
l = self.x**2 + self.y**2 + self.z**2
|
|
return math.sqrt(l)
|
|
else:
|
|
m = args[0] / self.length()
|
|
return self * m
|
|
|
|
def __rmul__ (self, other):
|
|
return self.mul(other, self)
|
|
def __mul__(self, other):
|
|
return self.mul(self, other)
|
|
def mul(self, a, b=None):
|
|
if not isinstance(a, Vec):
|
|
# flip a and b
|
|
b = a
|
|
a = self
|
|
if(isinstance(b, Vec)):
|
|
result = a.x * b.x
|
|
result += a.y * b.y
|
|
result += a.z * b.z
|
|
return result
|
|
elif(isinstance(b, (int, float))):
|
|
n = Vec()
|
|
n.x = a.x * b
|
|
n.y = a.y * b
|
|
n.z = a.z * b
|
|
return n
|
|
else:
|
|
print('WARNING: tried to multiply Vec with ' + str(type(b)))
|
|
return b
|
|
|
|
def __neg__(self):
|
|
return ~self
|
|
def __inv__(self):
|
|
return Vec(-self.x, -self.y, -self.z)
|
|
|
|
#TODO: alow scaler
|
|
def __pow__(self, other):
|
|
n = Vec()
|
|
n.x = self.y * other.z - self.z * other.y
|
|
n.y = self.z * other.x - self.x * other.z
|
|
n.z = self.x * other.y - self.y * other.x
|
|
return n
|
|
|
|
def __add__(self, other):
|
|
if isinstance(other, Vec):
|
|
n = Vec()
|
|
n.x = self.x + other.x
|
|
n.y = self.y + other.y
|
|
n.z = self.z + other.z
|
|
return n
|
|
elif isinstance(other, (tuple, list)):
|
|
n = Vec()
|
|
n.x = self.x + other[0]
|
|
n.y = self.y + other[1]
|
|
n.z = self.z + other[2]
|
|
return n
|
|
elif isinstance(other, (float, int)):
|
|
n = Vec(self.cartesian())
|
|
n.length(self.length() + other)
|
|
return n
|
|
else:
|
|
print('WARNING: tried to add Vec with ' + str(type(other)))
|
|
return other
|
|
|
|
def __sub__(self, other):
|
|
if isinstance(other, Vec):
|
|
n = Vec()
|
|
n.x = self.x - other.x
|
|
n.y = self.y - other.y
|
|
n.z = self.z - other.z
|
|
return n
|
|
elif isinstance(other, (tuple, list)):
|
|
n = Vec()
|
|
n.x = self.x - other[0]
|
|
n.y = self.y - other[1]
|
|
n.z = self.z - other[2]
|
|
return n
|
|
elif isinstance(other, (float, int)):
|
|
n = Vec(self.cartesian())
|
|
n.length(self.length() - other)
|
|
return n
|
|
else:
|
|
print('WARNING: tried to add Vec with ' + str(type(other)))
|
|
return other
|
|
|
|
def __setitem__(self, index, value):
|
|
if(index == 0):
|
|
self.x = value
|
|
elif(index == 1):
|
|
self.y = value
|
|
elif(index == 2):
|
|
self.z = value
|
|
else:
|
|
print('ERROR: tried to set index ' + str(index) + ' of a Vec')
|
|
def __getitem__(self, index):
|
|
if(index == 0):
|
|
return self.x
|
|
elif(index == 1):
|
|
return self.y
|
|
elif(index == 2):
|
|
return self.z
|
|
else:
|
|
raise IndexError('tried to get index ' + str(index) + ' of a Vec')
|
|
|
|
def __str__(self):
|
|
return "Vec" + str(self.cartesian())
|
|
|
|
#TODO: allow compare length of Vec with number
|
|
def __lt__(self, other):
|
|
return self.length() < other.length()
|
|
def __le__(self, other):
|
|
return self.length() <= other.length()
|
|
def __eq__(self, other):
|
|
return self.length() == other.length()
|
|
def __ne__(self, other):
|
|
return self.length() != other.length()
|
|
def __ge__(self, other):
|
|
return self.length() >= other.length()
|
|
def __gt__(self, other):
|
|
return self.length() > other.length()
|
|
|
|
|