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()