ursinamath
</> ursina.ursinamath
Functions
distance()
copy distance(a=None, b=None)
distance_2d()
copy distance_2 d(a=None, b=None)
distance_xz()
copy distance_xz(a=None, b=None)
lerp()
copy lerp(a=None, b=None, t=None)
inverselerp()
copy inverselerp(a=None, b=None, value=None)
get *where* between a and b, value is (0.0 - 1.0)
lerp_exponential_decay()
copy lerp_exponential_decay(a=None, b=None, decay_rate=None)
frame-rate independent lerp for use in update. use this instead of lerp(a, b, time.dt) in update.
lerp_angle()
copy lerp_angle(start_angle=None, end_angle=None, t=None)
slerp()
copy slerp(q1 =None, q2 =None, t=None)
slerp_exponential_decay()
copy slerp_exponential_decay(q1 =None, q2 =None, decay_rate=None)
frame-rate independent version of slerp for use in update.
clamp()
copy clamp(value=None, floor=None, ceiling=None)
round_to_closest()
copy round_to_closest(value=None, step=0 )
rotate_around_point_2d()
copy rotate_around_point_2 d(point=None, origin =None, deg=None)
world_position_to_screen_position()
copy world_position_to_screen_position(point=None)
get screen position(ui space) from world space.
sum()
copy sum(l=None)
make_gradient()
copy make_gradient(index_value_dict=None)
sample_gradient()
copy sample_gradient(list_of_values=None, t=None)
distribute list_of_values equally on a line and get the interpolated value at t (0-1).
Examples
copy from ursina.ursinastuff import _test
_test(inverselerp(0 , 1 0 0 , 5 0 ) == .5 )
_test(lerp(0 , 1 0 0 , .5 ) == 5 0 )
def lerp_exponential_decay(a, b, decay_rate): # frame-rate independent lerp for use in update. use this instead of lerp(a, b, time.dt) in update.
return lerp(a, b, 1 - pow(0 .0 1 , decay_rate))
def lerp_angle(start_angle, end_angle, t):
start_angle = start_angle % 3 6 0
end_angle = end_angle % 3 6 0
angle_diff = (end_angle - start_angle + 1 8 0 ) % 3 6 0 - 1 8 0
result_angle = start_angle + t * angle_diff
result_angle = (result_angle + 3 6 0 ) % 3 6 0
return result_angle
def slerp(q1 , q2 , t):
costheta = q1 .dot(q2 )
if costheta < 0 .0 :
q2 = -q2
costheta = -costheta
costheta = clamp(costheta, -1 .0 , 1 .0 ) # ensure valid range for acos
theta = acos(costheta)
if abs(theta) < 0 .0 0 0 1 :
return q2
sintheta = sqrt(1 .0 - costheta * costheta)
if abs(sintheta) < 0 .0 0 0 1 :
return (q1 + q2 ) * 0 .5
r1 = sin((1 .0 - t) * theta) / sintheta
r2 = sin(t * theta) / sintheta
return (q1 * r1 ) + (q2 * r2 )
def slerp_exponential_decay(q1 , q2 , decay_rate): # frame-rate independent version of slerp for use in update.
return slerp(q1 , q2 , 1 - pow(0 .0 1 , decay_rate))
def clamp(value, floor, ceiling):
return max(min(value, ceiling), floor)
def round_to_closest(value, step=0 ):
if not step:
return value
step = 1 /step
return round(value * step) / step
def rotate_around_point_2 d(point, origin, deg):
angle_rad = -deg/1 8 0 * pi # ursina rotation is positive=clockwise, so do *= -1
cos_angle = cos(angle_rad)
sin_angle = sin(angle_rad)
dx = point[0 ] - origin[0 ]
dy = point[1 ] - origin[1 ]
return (
origin[0 ] + (dx*cos_angle - dy*sin_angle),
origin[1 ] + (dx*sin_angle + dy*cos_angle)
)
def world_position_to_screen_position(point): # get screen position(ui space) from world space.
from ursina import camera, Entity , destroy
_temp_entity = Entity (position =point, add_to_scene_entities=False)
result = _temp_entity.screen_position
destroy(_temp_entity)
return result
def sum(l):
try:
return _sum(l)
except:
pass
total = l[0 ].__class__()
for e in l:
total += e
return total
def make_gradient(index_value_dict):
'' '
given a dict of positions and values (usually colors), interpolates the values into a list of with the interpolated values.
example input: {'0 ' :color.hex('#9 d9 8 6 7 ' ), '3 8 ' :color.hex('#8 2 8 1 3 1 ' ), '5 4 ' :color.hex('#5 d5 b2 a' ), '2 5 5 ' :color.hex('#0 0 0 0 0 0 ' )}
'' '
min_index = min(int(e) for e in index_value_dict.keys())
max_index = max(int(e) for e in index_value_dict.keys())
gradient = [None for _ in range (max_index+1 -min_index)]
sorted_dict = [(idx, index_value_dict[str(idx)]) for idx in sorted([int(key) for key in index_value_dict.keys()])]
for i in range (len(sorted_dict)-1 ):
start_index, start_value = sorted_dict[i]
next_index, next_value = sorted_dict[i+1 ]
dist = next_index - start_index
for j in range (dist+1 ):
gradient[start_index+j-min_index] = lerp(start_value, next_value, j/dist)
return gradient
if __name__ == '__main__' :
_test(make_gradient({'0 ' :color.hex('#ff0 0 0 0 ff' ), '2 ' :color.hex('#ffffffff' )}) == [
color.hex('#ff0 0 0 0 ff' ),
lerp(color.hex('#ff0 0 0 0 ff' ), color.hex('#ffffffff' ), .5 ),
color.hex('#ffffffff' ),
])
_test(make_gradient({'0 ' :color.hex('#ff0 0 0 0 ff' ), '4 ' :color.hex('#ffffffff' )}) == [
color.hex('#ff0 0 0 0 ff' ),
lerp(color.hex('#ff0 0 0 0 ff' ), color.hex('#ffffffff' ), .2 5 ),
lerp(color.hex('#ff0 0 0 0 ff' ), color.hex('#ffffffff' ), .5 ),
lerp(color.hex('#ff0 0 0 0 ff' ), color.hex('#ffffffff' ), .7 5 ),
color.hex('#ffffffff' ),
])
_test(make_gradient({'0 ' :1 6 , '2 ' :0 }) == [1 6 , 8 , 0 ])
_test(make_gradient({'6 ' :0 , '8 ' :8 }) == [0 , 4 , 8 ])
def sample_gradient(list_of_values, t): # distribute list_of_values equally on a line and get the interpolated value at t (0 -1 ).
l = len(list_of_values)
if l == 1 :
return list_of_values[0 ]
t *= l-1
index = floor(t - .0 0 1 )
index = clamp(index, 0 , l-1 )
relative = t - index
if index < l-1 :
return lerp(list_of_values[index], list_of_values[index+1 ], relative)
else :
return lerp(list_of_values[index-1 ], list_of_values[index], relative)
class Bounds:
__slots__ = ['start' , 'end' , 'center' , 'size' ]
def __init__(self, *, start:Vec3 =None, end:Vec3 =None, center:Vec3 =None, size:Vec3 =None):
if start is not None and end is not None:
self.start = start
self.end = end
self.size = end - start
self.center = start + (self.size * 0 .5 )
elif center is not None and size is not None:
self.center = center
self.size = size
half = size * 0 .5
self.start = center - half
self.end = center + half
else :
raise ValueError("Must provide either (start and end) or (center and size)")
def __repr__(self):
return f"Bounds(start={self.start}, end={self.end}, center={self.center}, size={self.size})"
if __name__ == '__main__' :
from ursina import *
from ursinastuff import _test
app = Ursina()
e1 = Entity (position = (0 ,0 ,0 ))
e2 = Entity (position = (0 ,1 ,1 ))
_test(distance(e1 , e2 ) == 1 .4 1 4 2 1 3 5 6 2 3 7 3 0 9 5 1 )
_test(distance_2 d(Vec2(0 ,0 ), Vec2(1 ,1 )) == 1 .4 1 4 2 1 3 5 6 2 3 7 3 0 9 5 1 )
distance_xz(e1 , e2 .position)
between_color = lerp(color.lime, color.magenta, .5 )
print (between_color)
print (lerp((0 ,0 ), (0 ,1 ), .5 ))
print (lerp(Vec2(0 ,0 ), Vec2(0 ,1 ), .5 ))
print (lerp([0 ,0 ], [0 ,1 ], .5 ))
print (round(Vec3(.3 8 , .1 3 5 1 , 3 5 3 .2 6 ), 2 ))
p = (1 ,0 )
print (p, 'rotated ->' , rotate_around_point_2 d(p, (0 ,0 ), 9 0 ))
app.run()