SMALL_FLOAT = 0.000001

function math:SignedAnglesDelta(a1, a2)
	local a = a1 - a2
	return (a + 180) % 360 - 180
end

function math:Sign(number)
	return number < 0 and -1 or 1
end

function math:RandomSign()
	return math.random(1, 2) == 1 and -1 or 1
end

function math:RandomNumberSameType(a, b)
    if a%1>0 or b%1>0 then
        return math.random(a*1000, b*1000) / 1000
    end
    return math.random(a, b)
end

function math:RandomWeighted(table)
	local r = math.random(1, 100) / 100
	local c = 0.0
	for _, v in ipairs(table) do
		c = c+v[1]
		if r <= c then
		  	return v[2]
		end
	end
end

function math:FloatEqualToPow(a, b, pow)
	a = a * (10^pow)
	a = math.modf(a)
	b = b * (10^pow)
	b = math.modf(b)
	return a == b
end

function math:Distance2Vec(vec1, vec2)
	return VecLength(VecSub(vec2, vec1))
end

function math:DistanceWeighted(vec1, vec2, weights)
    local diff = VecSub(vec1, vec2)
    local dx, dy, dz = unpack(diff)
    -- return math.sqrt(weights[1]*dx*dx + weights[2]*dy*dy + weights[3]*dz*dz)
    return VecLength(Vec(weights[1]*dx, weights[2]*dy, weights[3]*dz))
end

function math:Near2Vec(vec1, vec2, max_dist)
    if not vec1 or not vec2 or not max_dist then return false end

    vec2 = VecCopy(vec2)
    vec2[2] = vec1[2]
    return math:Distance2Vec(vec1, vec2) <= max_dist
end

function math:AabbCheckOverlap(aMin, aMax, bMin, bMax)
    return
    (aMin[1] <= bMax[1] and aMax[1] >= bMin[1]) and
    (aMin[2] <= bMax[2] and aMax[2] >= bMin[2]) and
    (aMin[3] <= bMax[3] and aMax[3] >= bMin[3])
end

function math:VecMidPoint(...)
    local numVecs = select('#', ...)
    local sumX, sumY, sumZ = 0, 0, 0

    for i = 1, numVecs do
        local point = select(i, ...)
        sumX = sumX + point[1]
        sumY = sumY + point[2]
        sumZ = sumZ + point[3]
    end

	return Vec(sumX / numVecs, sumY / numVecs, sumZ / numVecs)
end

function math:PositionsAreEqual(pos1, pos2, pow)
    if not pos1 or not pos2 or not pow then return end

	if math:FloatEqualToPow(pos1[1], pos2[1], pow) and math:FloatEqualToPow(pos1[3], pos2[3], pow) then
		return true
	end
	return false
end

function math:QuatAngle(quat1, quat2)
    if quat1[4] then
        local dot = VecDot(quat1, quat2) + quat1[4]*quat2[4]
        return 2 * math.acos(math.abs(dot))
    end
    return 2 * math.acos(math.abs(VecDot(quat1, quat2)))
end

function math:Clamp(value, minVal, maxVal)
    if value < minVal then return minVal end
    if value > maxVal then return maxVal end
    return value
end

function math.Clamp2(value, minVal, maxVal)
    if value < minVal then return minVal end
    if value > maxVal then return maxVal end
    return value
end

function math:MapRangeClamped(value, inA, inB, outA, outB)
	return math:Lerp(outA, outB, math:Clamp(math:GetRangePercent(value, inA, inB), 0, 1))
end

function math.MapRangeClamped2(value, inA, inB, outA, outB)
	return math:Lerp(outA, outB, math:Clamp(math:GetRangePercent(value, inA, inB), 0, 1))
end

function math:MapRangeUnclamped(value, inA, inB, outA, outB)
	return math:Lerp(outA, outB, math:GetRangePercent(value, inA, inB))
end

function math:GetRangePercent(value, minValue, maxValue)
	return (value - minValue) / math.max((maxValue - minValue), SMALL_FLOAT)
end

function math:Round(num, numDecimalPlaces)
	local mult = 10^(numDecimalPlaces or 0)
	return math.floor(num * mult + 0.5) / mult
end

function math:Round2(number, decimals)
    local scale = 10^decimals
    local c = 2^52 + 2^51
    return ((number * scale + c ) - c) / scale
end

function math:Lerp(a, b, time)
    return a + (b - a) * time
end

function math:RandomAscending(A, B, N)
    math.randomseed(GetTime())

    local numbers = { A }
    local current = A

    for i = 2, N-1 do
        local remaining = N - i + 1
        local maxStep = (B - current) / remaining

        local step = math.random() * maxStep
        current = current + step

        table.insert(numbers, current)
    end
    table.insert(numbers, B)

    return numbers
end

-- avoid passing in math.huge - causes endless loop
function math:NumOfDigits(number)
    local temp = number
    local count = 0
    while temp >= 1 do
        temp = temp / 10
        count = count + 1
    end
    return count
end
