local function getTangent(points, distances, point, previousPoint, followingPoint, genericFactory) local ret = genericFactory.empty() if point == 1 and not previousPoint or point == #points and not followingPoint then return ret end local mult = 1 / math.max(0.00001, distances[point + 1] - (distances[point - 1] or 0)) genericFactory.add(ret, points[point + 1] or followingPoint, mult) genericFactory.add(ret, points[point - 1] or previousPoint, -mult) return ret end local vec3GenericFactory = { empty = vec3, distance = vec3.distance, add = vec3.addScaled, step = 5 } ---@generic T ---@param points T[] ---@param previousPoint T? ---@param followingPoint T? ---@param genericFactory nil|{empty: fun(), distance: fun(a: T, b: T): number, add: fun(a: T, b: T, mult: number), step: number} ---@return T[]? local function LineResampler(points, previousPoint, followingPoint, genericFactory) if not genericFactory then if vec3.isvec3(points[1]) then genericFactory = vec3GenericFactory end if genericFactory == nil then error('Generic factory is required for unknown type', 2) return nil end end local distance = previousPoint and -math.abs(genericFactory.distance(previousPoint, points[1])) or 0 local totalDistances = {distance} for i = 2, #points do distance = distance + math.abs(genericFactory.distance(points[i - 1], points[i])) table.insert(totalDistances, distance) end if followingPoint then table.insert(totalDistances, distance + math.abs(genericFactory.distance(followingPoint, points[#points]))) -- table.insert(totalDistances, distance + math.abs(genericFactory.distance(followingPoint, points[#points])) * 2) end local ret = { points[1] } local steps = math.ceil(distance / genericFactory.step) for i = 1, steps - 1 do local p = distance * i / steps local point = table.findLeftOfIndex(totalDistances, function (item, _, p_) return item > p_ end, p) local cur = points[point] local edgeLength = totalDistances[point + 1] - totalDistances[point] local edgePos = math.lerpInvSat(p, totalDistances[point], totalDistances[point + 1]) local fol = point == #points and cur or points[point + 1] local tangentCur = getTangent(points, totalDistances, point, previousPoint, followingPoint, genericFactory) local tangentFol = getTangent(points, totalDistances, point + 1, previousPoint, followingPoint, genericFactory) local t1 = edgePos local t2 = t1 * t1 local t3 = t1 * t2 local v = genericFactory.empty() genericFactory.add(v, cur, 2 * t3 - 3 * t2 + 1) genericFactory.add(v, tangentCur, (t3 - 2 * t2 + t1) * edgeLength) genericFactory.add(v, fol, -2 * t3 + 3 * t2) genericFactory.add(v, tangentFol, (t3 - t2) * edgeLength) table.insert(ret, v) end table.insert(ret, points[#points]) return ret end return LineResampler