mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
lslbasefuncs: Rewrite some things in a different way.
Also some formatting changes. No functionality changes.
This commit is contained in:
parent
ea28e13e4a
commit
028b244a9e
1 changed files with 98 additions and 112 deletions
|
@ -78,7 +78,7 @@ TOUCH_INVALID_TEXCOORD = Vector((-1.0, -1.0, 0.0))
|
||||||
|
|
||||||
Infinity = float('inf')
|
Infinity = float('inf')
|
||||||
Indet = Infinity * 0
|
Indet = Infinity * 0
|
||||||
NaN = -Indet # Don't use float("nan") - Windows gets upset.
|
NaN = -Indet # Don't use float("nan") - Windows gets upset.
|
||||||
|
|
||||||
class ELSLTypeMismatch(Exception):
|
class ELSLTypeMismatch(Exception):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -110,13 +110,13 @@ class ELSONotSupported(Exception):
|
||||||
# * LSL list -> Python list
|
# * LSL list -> Python list
|
||||||
|
|
||||||
Types = {
|
Types = {
|
||||||
int: 1, # TYPE_INTEGER
|
int: 1, # TYPE_INTEGER
|
||||||
float: 2, # TYPE_FLOAT
|
float: 2, # TYPE_FLOAT
|
||||||
unicode: 3, # TYPE_STRING
|
unicode: 3, # TYPE_STRING
|
||||||
Key: 4, # TYPE_KEY
|
Key: 4, # TYPE_KEY
|
||||||
Vector: 5, # TYPE_VECTOR
|
Vector: 5, # TYPE_VECTOR
|
||||||
Quaternion: 6, # TYPE_ROTATION
|
Quaternion: 6, # TYPE_ROTATION
|
||||||
list: 0, # TYPE_INVALID
|
list: 0, # TYPE_INVALID
|
||||||
}
|
}
|
||||||
|
|
||||||
# Utility functions
|
# Utility functions
|
||||||
|
@ -124,10 +124,10 @@ Types = {
|
||||||
def F32(f, f32=True):
|
def F32(f, f32=True):
|
||||||
"""Truncate a float to have a precision equivalent to IEEE single"""
|
"""Truncate a float to have a precision equivalent to IEEE single"""
|
||||||
|
|
||||||
if not f32: # don't truncate
|
if not f32: # don't truncate
|
||||||
return f
|
return f
|
||||||
|
|
||||||
if isinstance(f, tuple): # vector, quaternion
|
if isinstance(f, tuple): # vector, quaternion
|
||||||
return f.__class__(F32(i) for i in f)
|
return f.__class__(F32(i) for i in f)
|
||||||
|
|
||||||
# Alternative to the big blurb below. This relies on the machine using IEEE-754, though.
|
# Alternative to the big blurb below. This relies on the machine using IEEE-754, though.
|
||||||
|
@ -221,7 +221,7 @@ def F32(f, f32=True):
|
||||||
# if f < 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625:
|
# if f < 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625:
|
||||||
# # Denormal range
|
# # Denormal range
|
||||||
# f *= 713623846352979940529142984724747568191373312.0
|
# f *= 713623846352979940529142984724747568191373312.0
|
||||||
# e = 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125 # 2^-149
|
# e = 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125 # 2^-149
|
||||||
# else:
|
# else:
|
||||||
# e = 1.0
|
# e = 1.0
|
||||||
# # This first loop is an optimization to get closer to the destination faster for very small numbers
|
# # This first loop is an optimization to get closer to the destination faster for very small numbers
|
||||||
|
@ -335,13 +335,13 @@ def f2s(val, DP=6):
|
||||||
if math.isnan(val):
|
if math.isnan(val):
|
||||||
return u'NaN'
|
return u'NaN'
|
||||||
if lslcommon.LSO or val == 0.:
|
if lslcommon.LSO or val == 0.:
|
||||||
return u'%.*f' % (DP, val) # deals with -0.0 too
|
return u'%.*f' % (DP, val) # deals with -0.0 too
|
||||||
|
|
||||||
# Format according to Mono rules (7 decimals after the DP, found experimentally)
|
# Format according to Mono rules (7 decimals after the DP, found experimentally)
|
||||||
s = u'%.*f' % (DP+7, val)
|
s = u'%.*f' % (DP+7, val)
|
||||||
|
|
||||||
if s[:DP+3] == u'-0.' + '0'*DP and s[DP+3] < u'5':
|
if s[:DP+3] == u'-0.' + '0'*DP and s[DP+3] < u'5':
|
||||||
return u'0.' + '0'*DP # underflown negatives return 0.0 except for -0.0 dealt with above
|
return u'0.' + '0'*DP # underflown negatives return 0.0 except for -0.0 dealt with above
|
||||||
|
|
||||||
# Separate the sign
|
# Separate the sign
|
||||||
sgn = u'-' if s[0] == u'-' else u''
|
sgn = u'-' if s[0] == u'-' else u''
|
||||||
|
@ -368,42 +368,38 @@ def f2s(val, DP=6):
|
||||||
if s[i if i != dot else i+1] >= u'5':
|
if s[i if i != dot else i+1] >= u'5':
|
||||||
# Rounding - increment s[:i] storing result into new_s
|
# Rounding - increment s[:i] storing result into new_s
|
||||||
new_s = u''
|
new_s = u''
|
||||||
ci = i-1 # carry index
|
ci = i-1 # carry index
|
||||||
while ci >= 0 and s[ci] == u'9':
|
while ci >= 0 and s[ci] == u'9':
|
||||||
new_s = u'0' + new_s
|
new_s = u'0' + new_s
|
||||||
ci -= 1
|
ci -= 1
|
||||||
if ci == dot:
|
if ci == dot:
|
||||||
ci -= 1 # skip over the dot
|
ci -= 1 # skip over the dot
|
||||||
new_s = u'.' + new_s # but add it to new_s
|
new_s = u'.' + new_s # but add it to new_s
|
||||||
if ci < 0:
|
if ci < 0:
|
||||||
new_s = u'1' + new_s # 9...9 -> 10...0
|
new_s = u'1' + new_s # 9...9 -> 10...0
|
||||||
else:
|
else:
|
||||||
# increment s[ci] e.g. 43999 -> 44000
|
# increment s[ci] e.g. 43999 -> 44000
|
||||||
new_s = s[:ci] + chr(ord(s[ci])+1) + new_s
|
new_s = s[:ci] + chr(ord(s[ci]) + 1) + new_s
|
||||||
else:
|
else:
|
||||||
new_s = s[:i]
|
new_s = s[:i]
|
||||||
|
|
||||||
if i <= dot:
|
if i <= dot:
|
||||||
return sgn + new_s + u'0'*(dot-i) + u'.' + u'0'*DP
|
return sgn + new_s + u'0' * (dot - i) + u'.' + u'0' * DP
|
||||||
return sgn + new_s + u'0'*(dot+1+DP-i)
|
return sgn + new_s + u'0' * (dot + 1 + DP - i)
|
||||||
|
|
||||||
def vr2s(v, DP=6):
|
def vr2s(v, DP=6):
|
||||||
if type(v) == Vector:
|
assert len(v) == (3 if type(v) == Vector else 4)
|
||||||
return u'<'+f2s(v[0],DP)+u', '+f2s(v[1],DP)+u', '+f2s(v[2],DP)+u'>'
|
return u'<' + ', '.join(f2s(x, DP) for x in v) + u'>'
|
||||||
return u'<'+f2s(v[0],DP)+u', '+f2s(v[1],DP)+u', '+f2s(v[2],DP)+u', '+f2s(v[3],DP)+u'>'
|
|
||||||
|
|
||||||
|
|
||||||
def qnz(q):
|
def qnz(q):
|
||||||
if all(x == 0. for x in q):
|
return Quaternion((0.,0.,0.,1.)) if all(x == 0. for x in q) else q
|
||||||
return Quaternion((0.,0.,0.,1.))
|
|
||||||
return q
|
|
||||||
|
|
||||||
def qnorm(q):
|
def qnorm(q):
|
||||||
q = qnz(q)
|
q = qnz(q)
|
||||||
mag2 = math.fsum((q[0]*q[0], q[1]*q[1], q[2]*q[2], q[3]*q[3]))
|
mag2 = math.fsum((q[0]*q[0], q[1]*q[1], q[2]*q[2], q[3]*q[3]))
|
||||||
# Threshold for renormalization
|
# Threshold for renormalization
|
||||||
eps_h = 1.0000021457672119140625 #float.fromhex('0x1.000024p0')
|
eps_h = 1.0000021457672119140625 # float.fromhex('0x1.000024p0')
|
||||||
eps_l = 0.99999797344207763671875 # float.fromhex('0x1.FFFFBCp-1')
|
eps_l = 0.99999797344207763671875 # float.fromhex('0x1.FFFFBCp-1')
|
||||||
if mag2 >= eps_h or mag2 <= eps_l:
|
if mag2 >= eps_h or mag2 <= eps_l:
|
||||||
# Renormalize
|
# Renormalize
|
||||||
mag2 = math.sqrt(mag2)
|
mag2 = math.sqrt(mag2)
|
||||||
|
@ -421,7 +417,7 @@ def InternalTypecast(val, out, InList, f32):
|
||||||
if out == list:
|
if out == list:
|
||||||
return [val]
|
return [val]
|
||||||
|
|
||||||
if tval == int: # integer
|
if tval == int: # integer
|
||||||
val = S32(val)
|
val = S32(val)
|
||||||
if out == int: return val
|
if out == int: return val
|
||||||
if out == float: return F32(val, f32)
|
if out == float: return F32(val, f32)
|
||||||
|
@ -445,7 +441,7 @@ def InternalTypecast(val, out, InList, f32):
|
||||||
if out == Quaternion: return val
|
if out == Quaternion: return val
|
||||||
if out == unicode: return vr2s(val, 6 if InList else 5)
|
if out == unicode: return vr2s(val, 6 if InList else 5)
|
||||||
raise ELSLTypeMismatch
|
raise ELSLTypeMismatch
|
||||||
if tval == Key: # key
|
if tval == Key: # key
|
||||||
if out == Key: return zstr(val)
|
if out == Key: return zstr(val)
|
||||||
if out == unicode: return zstr(unicode(val))
|
if out == unicode: return zstr(unicode(val))
|
||||||
raise ELSLTypeMismatch
|
raise ELSLTypeMismatch
|
||||||
|
@ -505,10 +501,10 @@ def InternalTypecast(val, out, InList, f32):
|
||||||
if val[i:i+1] != u',':
|
if val[i:i+1] != u',':
|
||||||
return Z
|
return Z
|
||||||
val = val[i+1:]
|
val = val[i+1:]
|
||||||
return out(ret) # convert type
|
return out(ret) # convert type
|
||||||
|
|
||||||
# To avoid mutual recursion, this was moved:
|
# To avoid mutual recursion, this was moved:
|
||||||
#if tval == list: # etc.
|
#if tval == list: # etc.
|
||||||
|
|
||||||
raise ELSLInvalidType
|
raise ELSLInvalidType
|
||||||
|
|
||||||
|
@ -590,12 +586,8 @@ def InternalGetDeleteSubSequence(val, start, end, isGet):
|
||||||
if end == -1: end += L
|
if end == -1: end += L
|
||||||
if (start+L if start < 0 else start) > (end+L if end < 0 else end):
|
if (start+L if start < 0 else start) > (end+L if end < 0 else end):
|
||||||
# Exclusion range - get/delete from end and start
|
# Exclusion range - get/delete from end and start
|
||||||
if isGet:
|
return val[:end+1] + val[start:] if isGet else val[end+1:start]
|
||||||
return val[:end+1] + val[start:]
|
return val[start:end+1] if isGet else val[:start] + val[end+1:]
|
||||||
return val[end+1:start]
|
|
||||||
if isGet:
|
|
||||||
return val[start:end+1]
|
|
||||||
return val[:start] + val[end+1:]
|
|
||||||
|
|
||||||
def typecast(val, out, InList=False, f32=True):
|
def typecast(val, out, InList=False, f32=True):
|
||||||
"""Type cast an item. Calls InternalList2Strings for lists and
|
"""Type cast an item. Calls InternalList2Strings for lists and
|
||||||
|
@ -603,7 +595,7 @@ def typecast(val, out, InList=False, f32=True):
|
||||||
"""
|
"""
|
||||||
if type(val) == list:
|
if type(val) == list:
|
||||||
if out == list:
|
if out == list:
|
||||||
return val # NOTE: We're not duplicating it here.
|
return val # NOTE: We're not duplicating it here.
|
||||||
if out == unicode:
|
if out == unicode:
|
||||||
return u''.join(InternalList2Strings(val))
|
return u''.join(InternalList2Strings(val))
|
||||||
raise ELSLTypeMismatch
|
raise ELSLTypeMismatch
|
||||||
|
@ -680,8 +672,10 @@ def mul(a, b, f32=True):
|
||||||
if tb in (int, float):
|
if tb in (int, float):
|
||||||
if ta == tb == int:
|
if ta == tb == int:
|
||||||
return S32(a*b)
|
return S32(a*b)
|
||||||
if math.isnan(a) and math.isnan(b) and math.copysign(1, a) != math.copysign(1, b):
|
if math.isnan(a) and math.isnan(b):
|
||||||
return NaN
|
return (-NaN
|
||||||
|
if math.copysign(1, a) == math.copysign(1, b) == -1
|
||||||
|
else NaN)
|
||||||
return F32(ff(a)*ff(b), f32)
|
return F32(ff(a)*ff(b), f32)
|
||||||
if tb != Vector:
|
if tb != Vector:
|
||||||
# scalar * quat is not defined
|
# scalar * quat is not defined
|
||||||
|
@ -702,7 +696,7 @@ def mul(a, b, f32=True):
|
||||||
a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2]), f32))
|
a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2]), f32))
|
||||||
|
|
||||||
if ta != Vector:
|
if ta != Vector:
|
||||||
raise ELSLInvalidType # Should never happen at this point
|
raise ELSLInvalidType # Should never happen at this point
|
||||||
|
|
||||||
if tb in (int, float):
|
if tb in (int, float):
|
||||||
a = v2f(a)
|
a = v2f(a)
|
||||||
|
@ -716,7 +710,7 @@ def mul(a, b, f32=True):
|
||||||
return F32(math.fsum((a[0]*b[0], a[1]*b[1], a[2]*b[2])), f32)
|
return F32(math.fsum((a[0]*b[0], a[1]*b[1], a[2]*b[2])), f32)
|
||||||
|
|
||||||
if tb != Quaternion:
|
if tb != Quaternion:
|
||||||
raise ELSLInvalidType # Should never happen at this point
|
raise ELSLInvalidType # Should never happen at this point
|
||||||
|
|
||||||
# vector * quaternion: perform conjugation
|
# vector * quaternion: perform conjugation
|
||||||
#v = mul(Quaternion((-b[0], -b[1], -b[2], b[3])), mul(Quaternion((a[0], a[1], a[2], 0.0)), b, f32=False))
|
#v = mul(Quaternion((-b[0], -b[1], -b[2], b[3])), mul(Quaternion((a[0], a[1], a[2], 0.0)), b, f32=False))
|
||||||
|
@ -729,11 +723,11 @@ def mul(a, b, f32=True):
|
||||||
a[1]*2*(b[0]*b[1]-b[2]*b[3]),
|
a[1]*2*(b[0]*b[1]-b[2]*b[3]),
|
||||||
a[2]*2*(b[0]*b[2]+b[1]*b[3]))),
|
a[2]*2*(b[0]*b[2]+b[1]*b[3]))),
|
||||||
math.fsum(( a[0]*2*(b[0]*b[1]+b[2]*b[3]),
|
math.fsum(( a[0]*2*(b[0]*b[1]+b[2]*b[3]),
|
||||||
-a[1]*(b[0]*b[0]-b[1]*b[1]+b[2]*b[2]-b[3]*b[3]), # notice minus sign
|
-a[1]*(b[0]*b[0]-b[1]*b[1]+b[2]*b[2]-b[3]*b[3]), # notice minus sign
|
||||||
a[2]*2*(b[1]*b[2]-b[0]*b[3]))),
|
a[2]*2*(b[1]*b[2]-b[0]*b[3]))),
|
||||||
math.fsum(( a[0]*2*(b[0]*b[2]-b[1]*b[3]),
|
math.fsum(( a[0]*2*(b[0]*b[2]-b[1]*b[3]),
|
||||||
a[1]*2*(b[1]*b[2]+b[0]*b[3]),
|
a[1]*2*(b[1]*b[2]+b[0]*b[3]),
|
||||||
-a[2]*(b[0]*b[0]+b[1]*b[1]-b[2]*b[2]-b[3]*b[3]))) # notice minus sign
|
-a[2]*(b[0]*b[0]+b[1]*b[1]-b[2]*b[2]-b[3]*b[3]))) # notice minus sign
|
||||||
), f32))
|
), f32))
|
||||||
|
|
||||||
def div(a, b, f32=True):
|
def div(a, b, f32=True):
|
||||||
|
@ -751,13 +745,13 @@ def div(a, b, f32=True):
|
||||||
if ta == int and tb == int:
|
if ta == int and tb == int:
|
||||||
# special case
|
# special case
|
||||||
if a == -2147483648 and b == -1:
|
if a == -2147483648 and b == -1:
|
||||||
return a # this could be handled by using S32 but it's probably faster this way
|
return a # this could be handled by using S32 but it's probably faster this way
|
||||||
if (a < 0) ^ (b < 0):
|
if (a < 0) ^ (b < 0):
|
||||||
# signs differ - Python rounds towards -inf, we need rounding towards 0
|
# signs differ - Python rounds towards -inf, we need rounding towards 0
|
||||||
return -(a//-b)
|
return -(a//-b)
|
||||||
return a//b
|
return a//b
|
||||||
ret = F32(ff(a)/ff(b), f32)
|
ret = F32(ff(a)/ff(b), f32)
|
||||||
if math.isnan(ret): # A NaN result gives a math error.
|
if math.isnan(ret): # A NaN result gives a math error.
|
||||||
raise ELSLMathError
|
raise ELSLMathError
|
||||||
return ret
|
return ret
|
||||||
if ta == Vector:
|
if ta == Vector:
|
||||||
|
@ -803,15 +797,13 @@ def compare(a, b, Eq = True):
|
||||||
ret = a == b
|
ret = a == b
|
||||||
else:
|
else:
|
||||||
ret = ff(a) == ff(b)
|
ret = ff(a) == ff(b)
|
||||||
return int(ret) if Eq else 1-ret
|
return int(ret == Eq)
|
||||||
if ta in (unicode, Key) and tb in (unicode, Key):
|
if ta in (unicode, Key) and tb in (unicode, Key):
|
||||||
ret = 0 if a == b else 1 if a > b or not lslcommon.LSO else -1
|
ret = 0 if a == b else 1 if not lslcommon.LSO or a > b else -1
|
||||||
return int(not ret) if Eq else ret
|
return int(not ret) if Eq else ret
|
||||||
if ta == tb in (Vector, Quaternion):
|
if ta == tb in (Vector, Quaternion):
|
||||||
for ae,be in zip(a,b):
|
ret = not any(ae != be for ae, be in zip(a, b))
|
||||||
if ae != be:
|
return int(ret == Eq)
|
||||||
return int(not Eq)
|
|
||||||
return int(Eq)
|
|
||||||
if ta == tb == list:
|
if ta == tb == list:
|
||||||
ret = len(a) - len(b)
|
ret = len(a) - len(b)
|
||||||
return int(not ret) if Eq else ret
|
return int(not ret) if Eq else ret
|
||||||
|
@ -843,12 +835,12 @@ def cond(x):
|
||||||
if lslcommon.LSO and tx == list:
|
if lslcommon.LSO and tx == list:
|
||||||
# SVC-689: lists of 1 element count as false
|
# SVC-689: lists of 1 element count as false
|
||||||
return len(x) > 1
|
return len(x) > 1
|
||||||
return bool(x) # works fine for int, float, string, list
|
return bool(x) # works fine for int, float, string, list
|
||||||
|
|
||||||
def reduce(t):
|
def reduce(t):
|
||||||
t = F32(t)
|
t = F32(t)
|
||||||
if not t.is_integer():
|
if not t.is_integer():
|
||||||
return t # Accurate-ish until big numbers come into play
|
return t # Accurate-ish until big numbers come into play
|
||||||
return int(t * 18446744073709551616) % 115904311329233965478 / 18446744073709551616.
|
return int(t * 18446744073709551616) % 115904311329233965478 / 18446744073709551616.
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -887,12 +879,10 @@ def llAtan2(y, x):
|
||||||
y = ff(y)
|
y = ff(y)
|
||||||
x = ff(x)
|
x = ff(x)
|
||||||
if math.isnan(x) and math.isnan(y):
|
if math.isnan(x) and math.isnan(y):
|
||||||
if math.copysign(1, x) == -1 and math.copysign(1, y) == -1:
|
return mul(x, y)
|
||||||
return -NaN
|
if math.isnan(x):
|
||||||
return NaN
|
|
||||||
elif math.isnan(x):
|
|
||||||
return x
|
return x
|
||||||
elif math.isnan(y):
|
if math.isnan(y):
|
||||||
return y
|
return y
|
||||||
return F32(math.atan2(y, x))
|
return F32(math.atan2(y, x))
|
||||||
|
|
||||||
|
@ -904,7 +894,7 @@ def llAxes2Rot(fwd, left, up):
|
||||||
# One of the hardest.
|
# One of the hardest.
|
||||||
|
|
||||||
t = math.fsum((fwd[0], left[1], up[2]))
|
t = math.fsum((fwd[0], left[1], up[2]))
|
||||||
if t > 0.: # no danger of division by zero or negative roots
|
if t > 0.: # no danger of division by zero or negative roots
|
||||||
r = math.sqrt(1. + t)
|
r = math.sqrt(1. + t)
|
||||||
s = 0.5/r
|
s = 0.5/r
|
||||||
|
|
||||||
|
@ -913,12 +903,12 @@ def llAxes2Rot(fwd, left, up):
|
||||||
|
|
||||||
# Find a positive combo. LSL normalizes the result in these cases only, so we do the same.
|
# Find a positive combo. LSL normalizes the result in these cases only, so we do the same.
|
||||||
|
|
||||||
if left[1] <= fwd[0] >= up[2]: # is fwd[0] the greatest?
|
if left[1] <= fwd[0] >= up[2]: # is fwd[0] the greatest?
|
||||||
r = math.sqrt(1. + fwd[0] - left[1] - up[2])
|
r = math.sqrt(1. + fwd[0] - left[1] - up[2])
|
||||||
s = 0.5/r
|
s = 0.5/r
|
||||||
q = (r*0.5, s*(fwd[1]+left[0]), s*(up[0]+fwd[2]), s*(left[2]-up[1]))
|
q = (r*0.5, s*(fwd[1]+left[0]), s*(up[0]+fwd[2]), s*(left[2]-up[1]))
|
||||||
|
|
||||||
elif fwd[0] <= left[1] >= up[2]: # is left[1] the greatest?
|
elif fwd[0] <= left[1] >= up[2]: # is left[1] the greatest?
|
||||||
r = math.sqrt(1. - fwd[0] + left[1] - up[2])
|
r = math.sqrt(1. - fwd[0] + left[1] - up[2])
|
||||||
s = 0.5/r
|
s = 0.5/r
|
||||||
q = (s*(fwd[1]+left[0]), r*0.5, s*(left[2]+up[1]), s*(up[0]-fwd[2]))
|
q = (s*(fwd[1]+left[0]), r*0.5, s*(left[2]+up[1]), s*(up[0]-fwd[2]))
|
||||||
|
@ -934,7 +924,6 @@ def llAxes2Rot(fwd, left, up):
|
||||||
mag = math.sqrt(math.fsum((q[0]*q[0], q[1]*q[1], q[2]*q[2], q[3]*q[3])))
|
mag = math.sqrt(math.fsum((q[0]*q[0], q[1]*q[1], q[2]*q[2], q[3]*q[3])))
|
||||||
return Quaternion(F32((q[0]/mag, q[1]/mag, q[2]/mag, q[3]/mag)))
|
return Quaternion(F32((q[0]/mag, q[1]/mag, q[2]/mag, q[3]/mag)))
|
||||||
|
|
||||||
|
|
||||||
def llAxisAngle2Rot(axis, angle):
|
def llAxisAngle2Rot(axis, angle):
|
||||||
axis = v2f(axis)
|
axis = v2f(axis)
|
||||||
angle = ff(angle)
|
angle = ff(angle)
|
||||||
|
@ -964,7 +953,7 @@ def llBase64ToInteger(s):
|
||||||
b64tos_re = re.compile(
|
b64tos_re = re.compile(
|
||||||
b'('
|
b'('
|
||||||
# Those pass through and are caught by InternalUTF8toString:
|
# Those pass through and are caught by InternalUTF8toString:
|
||||||
b'\x00$' # NUL at last position (zstr removes it)
|
b'\x00$' # NUL at last position (zstr removes it)
|
||||||
b'|[\x09\x0A\x0F\x1F-\x7F\xFE\xFF]|[\xC2-\xDF][\x80-\xBF]'
|
b'|[\x09\x0A\x0F\x1F-\x7F\xFE\xFF]|[\xC2-\xDF][\x80-\xBF]'
|
||||||
b'|(?:\xE0[\xA0-\xBF]|[\xE1-\xEF][\x80-\xBF])[\x80-\xBF]'
|
b'|(?:\xE0[\xA0-\xBF]|[\xE1-\xEF][\x80-\xBF])[\x80-\xBF]'
|
||||||
b'|(?:\xF0[\x90-\xBF]|[\xF1-\xF7][\x80-\xBF])[\x80-\xBF]{2}'
|
b'|(?:\xF0[\x90-\xBF]|[\xF1-\xF7][\x80-\xBF])[\x80-\xBF]{2}'
|
||||||
|
@ -979,7 +968,7 @@ b64tos_re = re.compile(
|
||||||
b'|[\xF0-\xF7][\x80-\xBF]{0,3}'
|
b'|[\xF0-\xF7][\x80-\xBF]{0,3}'
|
||||||
b'|[\xF8-\xFB][\x80-\xBF]{0,4}'
|
b'|[\xF8-\xFB][\x80-\xBF]{0,4}'
|
||||||
b'|[\xFC-\xFD][\x80-\xBF]{0,5}'
|
b'|[\xFC-\xFD][\x80-\xBF]{0,5}'
|
||||||
b')|(.)' # should never be reached
|
b')|(.)' # should never be reached
|
||||||
)
|
)
|
||||||
|
|
||||||
def llBase64ToString(s):
|
def llBase64ToString(s):
|
||||||
|
@ -1033,7 +1022,7 @@ def llCSV2List(s):
|
||||||
bracketlevel += 1
|
bracketlevel += 1
|
||||||
elif c == u'>':
|
elif c == u'>':
|
||||||
bracketlevel -= 1
|
bracketlevel -= 1
|
||||||
elif lastwascomma and c == u' ': # eat space after comma
|
elif lastwascomma and c == u' ': # eat space after comma
|
||||||
lastwascomma = False
|
lastwascomma = False
|
||||||
lastidx = i+1
|
lastidx = i+1
|
||||||
else:
|
else:
|
||||||
|
@ -1079,7 +1068,7 @@ def llDumpList2String(lst, sep):
|
||||||
|
|
||||||
def llEscapeURL(s):
|
def llEscapeURL(s):
|
||||||
s = fs(s)
|
s = fs(s)
|
||||||
s = s.encode('utf8') # get bytes
|
s = s.encode('utf8') # get bytes
|
||||||
ret = u''
|
ret = u''
|
||||||
for c in s:
|
for c in s:
|
||||||
if b'A' <= c <= b'Z' or b'a' <= c <= b'z' or b'0' <= c <= b'9':
|
if b'A' <= c <= b'Z' or b'a' <= c <= b'z' or b'0' <= c <= b'9':
|
||||||
|
@ -1123,7 +1112,7 @@ def llEuler2Rot(v):
|
||||||
|
|
||||||
def llFabs(f):
|
def llFabs(f):
|
||||||
f = ff(f)
|
f = ff(f)
|
||||||
if f == 0.0 or math.isnan(f): # llFabs(-0.0) is -0.0; llFabs(-nan) is -nan
|
if f == 0.0 or math.isnan(f): # llFabs(-0.0) is -0.0; llFabs(-nan) is -nan
|
||||||
return f
|
return f
|
||||||
return math.fabs(f)
|
return math.fabs(f)
|
||||||
|
|
||||||
|
@ -1151,7 +1140,7 @@ def llFrand(lim):
|
||||||
if val == lim:
|
if val == lim:
|
||||||
# this should never happen
|
# this should never happen
|
||||||
# (it can happen on denormals, but these cause output of 0.0)
|
# (it can happen on denormals, but these cause output of 0.0)
|
||||||
val = 0. # pragma: no cover
|
val = 0. # pragma: no cover
|
||||||
return val
|
return val
|
||||||
|
|
||||||
# Can't give a concrete value
|
# Can't give a concrete value
|
||||||
|
@ -1165,8 +1154,7 @@ def llGenerateKey():
|
||||||
s = hashlib.md5((u'%.17g %f %f' % (time.time(), random.random(),
|
s = hashlib.md5((u'%.17g %f %f' % (time.time(), random.random(),
|
||||||
random.random())).encode('utf8')
|
random.random())).encode('utf8')
|
||||||
).hexdigest()
|
).hexdigest()
|
||||||
return Key(s[:8] + '-' + s[8:12] + '-' + s[12:16] + '-' + s[16:20]
|
return Key('-'.join((s[:8], s[8:12], s[12:16], s[16:20], s[20:32])))
|
||||||
+ '-' + s[20:32])
|
|
||||||
|
|
||||||
# Can't give a concrete value
|
# Can't give a concrete value
|
||||||
raise ELSLCantCompute
|
raise ELSLCantCompute
|
||||||
|
@ -1178,7 +1166,7 @@ def llGetListEntryType(lst, pos):
|
||||||
return Types[type(lst[pos])]
|
return Types[type(lst[pos])]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# list index out of bounds
|
# list index out of bounds
|
||||||
return 0 # TYPE_INVALID
|
return 0 # TYPE_INVALID
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# type of element not in Types
|
# type of element not in Types
|
||||||
raise ELSLInvalidType
|
raise ELSLInvalidType
|
||||||
|
@ -1195,12 +1183,13 @@ def llInsertString(s, pos, src):
|
||||||
s = fs(s)
|
s = fs(s)
|
||||||
pos = fi(pos)
|
pos = fi(pos)
|
||||||
src = fs(src)
|
src = fs(src)
|
||||||
if pos < 0: pos = 0 # llInsertString does not support negative indices
|
if pos < 0: pos = 0 # llInsertString does not support negative indices
|
||||||
return s[:pos] + src + s[pos:]
|
return s[:pos] + src + s[pos:]
|
||||||
|
|
||||||
def llIntegerToBase64(x):
|
def llIntegerToBase64(x):
|
||||||
x = fi(x)
|
x = fi(x)
|
||||||
return b64encode(chr((x>>24)&255) + chr((x>>16)&255) + chr((x>>8)&255) + chr(x&255)).decode('utf8')
|
return b64encode(chr((x>>24)&255) + chr((x>>16)&255) + chr((x>>8)&255)
|
||||||
|
+ chr(x&255)).decode('utf8')
|
||||||
|
|
||||||
def llList2CSV(lst):
|
def llList2CSV(lst):
|
||||||
lst = fl(lst)
|
lst = fl(lst)
|
||||||
|
@ -1329,7 +1318,7 @@ def llListFindList(lst, elems):
|
||||||
L1 = len(lst)
|
L1 = len(lst)
|
||||||
L2 = len(elems)
|
L2 = len(elems)
|
||||||
if L2 > L1:
|
if L2 > L1:
|
||||||
return -1 # can't find a sublist longer than the original list
|
return -1 # can't find a sublist longer than the original list
|
||||||
if L2 == 0:
|
if L2 == 0:
|
||||||
# empty list is always found at position 0 in Mono,
|
# empty list is always found at position 0 in Mono,
|
||||||
# and in LSO if the first list isn't empty
|
# and in LSO if the first list isn't empty
|
||||||
|
@ -1357,15 +1346,15 @@ def llListFindList(lst, elems):
|
||||||
# Unfortunately, Python fails to consider (NaN,) != (NaN,) sometimes
|
# Unfortunately, Python fails to consider (NaN,) != (NaN,) sometimes
|
||||||
# so we need to implement our own test
|
# so we need to implement our own test
|
||||||
for e1e,e2e in zip(e1,e2):
|
for e1e,e2e in zip(e1,e2):
|
||||||
if e1e != e2e: # NaNs are considered different to themselves here as normal
|
if e1e != e2e: # NaNs are considered different to themselves here as normal
|
||||||
# Mismatch in vector/quaternion sub-element
|
# Mismatch in vector/quaternion sub-element
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# No mismatch in any sub-element, try next list element
|
# No mismatch in any sub-element, try next list element
|
||||||
continue
|
continue
|
||||||
break # discrepancy found
|
break # discrepancy found
|
||||||
elif type(e1) != type(e2) or e1 != e2:
|
elif type(e1) != type(e2) or e1 != e2:
|
||||||
break # mismatch
|
break # mismatch
|
||||||
else:
|
else:
|
||||||
# no mismatch
|
# no mismatch
|
||||||
return i
|
return i
|
||||||
|
@ -1403,9 +1392,9 @@ def llListSort(lst, stride, asc):
|
||||||
lst = fl(lst)
|
lst = fl(lst)
|
||||||
stride = fi(stride)
|
stride = fi(stride)
|
||||||
asc = fi(asc)
|
asc = fi(asc)
|
||||||
lst = lst[:] # make a copy
|
lst = lst[:] # make a copy
|
||||||
L = len(lst)
|
L = len(lst)
|
||||||
broken = u'\ufb1a' > u'\U0001d41a' # that happens on Windows
|
broken = u'\ufb1a' > u'\U0001d41a' # that happens on Windows
|
||||||
if stride < 1: stride = 1
|
if stride < 1: stride = 1
|
||||||
if L % stride:
|
if L % stride:
|
||||||
return lst
|
return lst
|
||||||
|
@ -1414,12 +1403,12 @@ def llListSort(lst, stride, asc):
|
||||||
a = lst[i]
|
a = lst[i]
|
||||||
ta = type(a)
|
ta = type(a)
|
||||||
if ta == Vector:
|
if ta == Vector:
|
||||||
a = v2f(a) # list should contain vectors made only of floats
|
a = v2f(a) # list should contain vectors made only of floats
|
||||||
a = a[0]*a[0] + a[1]*a[1] + a[2]*a[2]
|
a = a[0]*a[0] + a[1]*a[1] + a[2]*a[2]
|
||||||
if broken and ta in (unicode, Key):
|
if broken and ta in (unicode, Key):
|
||||||
# Note this breaks type consistency between a and ta!
|
# Note this breaks type consistency between a and ta!
|
||||||
# It should be OK because only equal types are compared.
|
# It should be OK because only equal types are compared.
|
||||||
a = a.encode('utf-32-be') # pragma: no cover
|
a = a.encode('utf-32-be') # pragma: no cover
|
||||||
for j in xrange(i+stride, L, stride):
|
for j in xrange(i+stride, L, stride):
|
||||||
b = lst[j]
|
b = lst[j]
|
||||||
tb = type(b)
|
tb = type(b)
|
||||||
|
@ -1431,8 +1420,8 @@ def llListSort(lst, stride, asc):
|
||||||
# (note NaNs compare as > thus the reversed condition!)
|
# (note NaNs compare as > thus the reversed condition!)
|
||||||
elif tb != Quaternion:
|
elif tb != Quaternion:
|
||||||
if broken and tb in (unicode, Key):
|
if broken and tb in (unicode, Key):
|
||||||
b = b.encode('utf-32-be') # pragma: no cover
|
b = b.encode('utf-32-be') # pragma: no cover
|
||||||
gt = not (a <= b) # float, integer, string, key all take this branch
|
gt = not (a <= b) # float, integer, string, key all take this branch
|
||||||
# (note NaNs compare as > thus the reversed condition!)
|
# (note NaNs compare as > thus the reversed condition!)
|
||||||
if gt ^ (asc != 1):
|
if gt ^ (asc != 1):
|
||||||
# swap
|
# swap
|
||||||
|
@ -1444,7 +1433,7 @@ def llListSort(lst, stride, asc):
|
||||||
a = v2f(a)
|
a = v2f(a)
|
||||||
a = a[0]*a[0] + a[1]*a[1] + a[2]*a[2]
|
a = a[0]*a[0] + a[1]*a[1] + a[2]*a[2]
|
||||||
if broken and ta in (unicode, Key):
|
if broken and ta in (unicode, Key):
|
||||||
a = a.encode('utf-32-be') # pragma: no cover
|
a = a.encode('utf-32-be') # pragma: no cover
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
def llListStatistics(op, lst):
|
def llListStatistics(op, lst):
|
||||||
|
@ -1460,10 +1449,10 @@ def llListStatistics(op, lst):
|
||||||
if nums == []:
|
if nums == []:
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
if op == 8: # LIST_STAT_NUM_COUNT
|
if op == 8: # LIST_STAT_NUM_COUNT
|
||||||
return float(len(nums))
|
return float(len(nums))
|
||||||
|
|
||||||
if op in (0, 1, 2) : # LIST_STAT_RANGE, LIST_STAT_MIN, LIST_STAT_MAX
|
if op in (0, 1, 2): # LIST_STAT_RANGE, LIST_STAT_MIN, LIST_STAT_MAX
|
||||||
min = None
|
min = None
|
||||||
for elem in nums:
|
for elem in nums:
|
||||||
if min is None:
|
if min is None:
|
||||||
|
@ -1475,7 +1464,7 @@ def llListStatistics(op, lst):
|
||||||
max = elem
|
max = elem
|
||||||
return F32(max - min if op == 0 else min if op == 1 else max)
|
return F32(max - min if op == 0 else min if op == 1 else max)
|
||||||
|
|
||||||
if op == 4: # LIST_STAT_MEDIAN requires special treatment
|
if op == 4: # LIST_STAT_MEDIAN requires special treatment
|
||||||
# The function behaves very strangely with NaNs. This seems to reproduce it:
|
# The function behaves very strangely with NaNs. This seems to reproduce it:
|
||||||
|
|
||||||
# llListSort seems to do the right thing with NaNs as needed by the median.
|
# llListSort seems to do the right thing with NaNs as needed by the median.
|
||||||
|
@ -1485,7 +1474,7 @@ def llListStatistics(op, lst):
|
||||||
return F32(nums[L>>1])
|
return F32(nums[L>>1])
|
||||||
return F32((nums[(L>>1)-1] + nums[L>>1])*0.5)
|
return F32((nums[(L>>1)-1] + nums[L>>1])*0.5)
|
||||||
|
|
||||||
if op in (3, 5, 6, 7): # LIST_STAT_MEAN, STD_DEV, SUM, SUM_SQUARES
|
if op in (3, 5, 6, 7): # LIST_STAT_MEAN, STD_DEV, SUM, SUM_SQUARES
|
||||||
sum = 0.
|
sum = 0.
|
||||||
sumsq = 0.
|
sumsq = 0.
|
||||||
mean = 0.
|
mean = 0.
|
||||||
|
@ -1499,15 +1488,15 @@ def llListStatistics(op, lst):
|
||||||
mean += delta/N
|
mean += delta/N
|
||||||
M2 += delta*(elem-mean)
|
M2 += delta*(elem-mean)
|
||||||
|
|
||||||
if op == 5: # LIST_STAT_STD_DEV
|
if op == 5: # LIST_STAT_STD_DEV
|
||||||
return 0. if N == 1. else F32(math.sqrt(M2/(N-1.)))
|
return 0. if N == 1. else F32(math.sqrt(M2/(N-1.)))
|
||||||
if op == 6: # LIST_STAT_SUM
|
if op == 6: # LIST_STAT_SUM
|
||||||
return F32(sum)
|
return F32(sum)
|
||||||
if op == 7: # LIST_STAT_SUM_SQUARES
|
if op == 7: # LIST_STAT_SUM_SQUARES
|
||||||
return F32(sumsq)
|
return F32(sumsq)
|
||||||
return F32(mean)
|
return F32(mean)
|
||||||
|
|
||||||
if op == 9: # LIST_STAT_GEOMETRIC_MEAN
|
if op == 9: # LIST_STAT_GEOMETRIC_MEAN
|
||||||
N = 0.
|
N = 0.
|
||||||
GMlog = 0.
|
GMlog = 0.
|
||||||
for elem in nums:
|
for elem in nums:
|
||||||
|
@ -1551,12 +1540,9 @@ def llModPow(base, exp, mod):
|
||||||
if exp == 0:
|
if exp == 0:
|
||||||
return 1
|
return 1
|
||||||
# Convert all numbers to unsigned
|
# Convert all numbers to unsigned
|
||||||
if base < 0:
|
base &= 0xFFFFFFFF
|
||||||
base += 4294967296
|
exp &= 0xFFFFFFFF
|
||||||
if exp < 0:
|
mod &= 0xFFFFFFFF
|
||||||
exp += 4294967296
|
|
||||||
if mod < 0:
|
|
||||||
mod += 4294967296
|
|
||||||
prod = base
|
prod = base
|
||||||
ret = 1
|
ret = 1
|
||||||
while True:
|
while True:
|
||||||
|
@ -1606,22 +1592,22 @@ def llPow(base, exp):
|
||||||
if exp == 0.0:
|
if exp == 0.0:
|
||||||
return 1.0
|
return 1.0
|
||||||
|
|
||||||
if base == 0.0: # Python gives exception on these, LSL returns stuff
|
if base == 0.0: # Python gives exception on these, LSL returns stuff
|
||||||
if math.isinf(exp) and exp < 0:
|
if math.isinf(exp) and exp < 0:
|
||||||
return Infinity # llPow(0.0, -inf) = inf
|
return Infinity # llPow(0.0, -inf) = inf
|
||||||
|
|
||||||
if exp < 0.0:
|
if exp < 0.0:
|
||||||
# Negative finite exponent cases
|
# Negative finite exponent cases
|
||||||
if math.copysign(1, base) < 0 and exp.is_integer() and not (exp/2.).is_integer():
|
if math.copysign(1, base) < 0 and exp.is_integer() and not (exp/2.).is_integer():
|
||||||
return -Infinity # llPow(-0.0, -odd_integer) = -inf
|
return -Infinity # llPow(-0.0, -odd_integer) = -inf
|
||||||
return Infinity
|
return Infinity
|
||||||
|
|
||||||
elif abs(base) == 1.0 and math.isinf(exp):
|
elif abs(base) == 1.0 and math.isinf(exp):
|
||||||
return NaN # Python says 1.0
|
return NaN # Python says 1.0
|
||||||
|
|
||||||
f = F32(math.pow(base, exp))
|
f = F32(math.pow(base, exp))
|
||||||
return 0.0 if f == 0.0 else f # don't return -0.0
|
return 0.0 if f == 0.0 else f # don't return -0.0
|
||||||
except ValueError: # should happen only with negative base and noninteger exponent
|
except ValueError: # should happen only with negative base and noninteger exponent
|
||||||
return Indet
|
return Indet
|
||||||
|
|
||||||
def llRot2Angle(r):
|
def llRot2Angle(r):
|
||||||
|
@ -1701,7 +1687,7 @@ def llRotBetween(v1, v2):
|
||||||
# which will be perpendicular to both. But matching the SL results requires
|
# which will be perpendicular to both. But matching the SL results requires
|
||||||
# another cross product of the input with the result, so we do that.
|
# another cross product of the input with the result, so we do that.
|
||||||
ortho = mod(mod(v1, Vector((1., 0., 0.))), v1)
|
ortho = mod(mod(v1, Vector((1., 0., 0.))), v1)
|
||||||
ortho = Vector((0. if f == 0. else f for f in ortho)) # remove minus zero
|
ortho = Vector((0. if f == 0. else f for f in ortho)) # remove minus zero
|
||||||
m = mul(ortho, ortho)
|
m = mul(ortho, ortho)
|
||||||
if m < float.fromhex('0x1.b7cdfep-34'):
|
if m < float.fromhex('0x1.b7cdfep-34'):
|
||||||
# The input vectors were aligned with <1,0,0>, so this was not a
|
# The input vectors were aligned with <1,0,0>, so this was not a
|
||||||
|
@ -1749,10 +1735,10 @@ def llStringTrim(s, mode):
|
||||||
head = 0
|
head = 0
|
||||||
length = len(s)
|
length = len(s)
|
||||||
tail = length-1
|
tail = length-1
|
||||||
if mode & 1: # STRING_TRIM_HEAD
|
if mode & 1: # STRING_TRIM_HEAD
|
||||||
while head < length and s[head] in u'\x09\x0a\x0b\x0c\x0d\x20':
|
while head < length and s[head] in u'\x09\x0a\x0b\x0c\x0d\x20':
|
||||||
head += 1
|
head += 1
|
||||||
if mode & 2: # STRING_TRIM_TAIL
|
if mode & 2: # STRING_TRIM_TAIL
|
||||||
while tail >= head and s[tail] in u'\x09\x0a\x0b\x0c\x0d\x20':
|
while tail >= head and s[tail] in u'\x09\x0a\x0b\x0c\x0d\x20':
|
||||||
tail -= 1
|
tail -= 1
|
||||||
return s[head:tail+1]
|
return s[head:tail+1]
|
||||||
|
@ -1795,14 +1781,14 @@ def llUnescapeURL(s):
|
||||||
continue
|
continue
|
||||||
if i >= L:
|
if i >= L:
|
||||||
break
|
break
|
||||||
c = s[i] # First digit
|
c = s[i] # First digit
|
||||||
i += 1
|
i += 1
|
||||||
if i >= L:
|
if i >= L:
|
||||||
break
|
break
|
||||||
v = 0
|
v = 0
|
||||||
if u'0' <= c <= u'9' or u'A' <= c <= u'F' or u'a' <= c <= u'f':
|
if u'0' <= c <= u'9' or u'A' <= c <= u'F' or u'a' <= c <= u'f':
|
||||||
v = int(c, 16)<<4
|
v = int(c, 16)<<4
|
||||||
c = s[i] # Second digit
|
c = s[i] # Second digit
|
||||||
if c == u'%':
|
if c == u'%':
|
||||||
ret += chr(v)
|
ret += chr(v)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue