Add security, optimize factorial and clean code
This commit is contained in:
@@ -1,66 +1,65 @@
|
||||
class_name Bezier
|
||||
extends Node
|
||||
|
||||
static var factorial_cache: Dictionary = {}
|
||||
|
||||
|
||||
static func bezier_square_error(current_points: Array, ref_points: Array) -> float:
|
||||
var samples: Array[Vector2] = bezier_sampling(current_points, 25)
|
||||
var curve: Curve2D = Curve2D.new()
|
||||
|
||||
for point: Vector2 in samples:
|
||||
curve.add_point(point)
|
||||
|
||||
var error: float = 0.0
|
||||
for point: Vector2 in ref_points:
|
||||
var curve_point: Vector2 = curve.get_closest_point(point)
|
||||
error += pow(curve_point.distance_to(point), 2.0)
|
||||
|
||||
return error
|
||||
|
||||
|
||||
static func bezier_sampling(points: Array, number_of_samples: int) -> Array[Vector2]:
|
||||
var sample_points: Array[Vector2] = []
|
||||
if number_of_samples <= 0:
|
||||
return sample_points
|
||||
for index: int in range(number_of_samples + 1):
|
||||
var sample: Vector2 = bezier(float(index) / float(number_of_samples), points)
|
||||
sample_points.append(sample)
|
||||
|
||||
return sample_points
|
||||
|
||||
|
||||
static func bezier(t: float, control_points: Array) -> Vector2:
|
||||
var degree: int = control_points.size() - 1
|
||||
var result: Vector2 = Vector2.ZERO
|
||||
|
||||
# Compute the weighted sum of the control points using Bernstein polynomials
|
||||
for point_index: int in range(degree + 1):
|
||||
var bernstein_weight: float = bernstein(t, degree, point_index)
|
||||
var weighted_point: Vector2 = bernstein_weight * control_points[point_index]
|
||||
result += weighted_point
|
||||
|
||||
return result
|
||||
|
||||
|
||||
static func bernstein(t: float, m: int, i: int) -> float:
|
||||
var b_i_m: float = float(binomial(i, m))
|
||||
var t_i: float = pow(t, i)
|
||||
var t_m_i: float = pow(1.0 - t, m - i)
|
||||
var result: float = b_i_m * t_i * t_m_i
|
||||
|
||||
static func bernstein(time_ratio: float, degree: int, index: int) -> float:
|
||||
var binomial_coefficient: float = float(binomial(index, degree))
|
||||
var time_power_index: float = pow(time_ratio, index)
|
||||
var inverse_time_power: float = pow(1.0 - time_ratio, degree - index)
|
||||
var result: float = binomial_coefficient * time_power_index * inverse_time_power
|
||||
return result
|
||||
|
||||
|
||||
static func binomial(k: int, n: int) -> int:
|
||||
var n_f: int = factorial(n)
|
||||
var k_f: int = factorial(k)
|
||||
var n_k_f: int = factorial(n - k)
|
||||
return int(float(n_f) / (float(k_f) * float(n_k_f)))
|
||||
static func binomial(index: int, degree: int) -> int:
|
||||
if index < 0 or degree < 0 or index > degree:
|
||||
return 0
|
||||
var degree_factorial: int = factorial(degree)
|
||||
var index_factorial: int = factorial(index)
|
||||
var degree_minus_index_factorial: int = factorial(degree - index)
|
||||
return int(float(degree_factorial) / (float(index_factorial) * float(degree_minus_index_factorial)))
|
||||
|
||||
|
||||
static func factorial(k: int) -> int:
|
||||
if k == 0:
|
||||
return 1
|
||||
|
||||
static func factorial(number: int) -> int:
|
||||
assert(number >= 0, "Factorial is undefined for negative numbers")
|
||||
if number in factorial_cache:
|
||||
return factorial_cache[number]
|
||||
var result: int = 1
|
||||
for index: int in range(1, k + 1):
|
||||
result *= index
|
||||
|
||||
for value: int in range(1, number + 1):
|
||||
result *= value
|
||||
factorial_cache[number] = result
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user