Skip to content

Commit a173d79

Browse files
committed
b spline and ex
1 parent d81ba2d commit a173d79

File tree

2 files changed

+1037
-0
lines changed

2 files changed

+1037
-0
lines changed

examples/b_spline_ex.py

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
4+
from interpolatepy.b_spline import BSpline
5+
6+
7+
def example_bspline() -> BSpline:
8+
"""
9+
Create an example B-spline curve.
10+
11+
Returns:
12+
BSpline: An example B-spline object.
13+
"""
14+
# Define the degree
15+
degree = 3
16+
17+
# Define the control points (2D for this example)
18+
control_points = np.array([[1, 2], [2, 3], [3, -3], [4, 4], [5, 5], [6, -5], [7, -6]])
19+
20+
# Create knot vector similar to the example in the document
21+
knots = np.array([0, 0, 0, 0, 1, 2, 4, 7, 7, 7, 7])
22+
23+
# Create and return the B-spline
24+
return BSpline(degree, knots, control_points)
25+
26+
27+
def demonstration() -> None:
28+
"""
29+
Demonstrate the B-spline implementation with the example from the document.
30+
"""
31+
# Create the example B-spline
32+
bspline = example_bspline()
33+
34+
# Plot the B-spline curve
35+
bspline.plot_2d(num_points=100)
36+
37+
# Add title that matches the example
38+
plt.title("Cubic B-spline and its control polygon")
39+
40+
# Evaluate the B-spline at the specific value mentioned in the document
41+
u_value = 1.5
42+
point = bspline.evaluate(u_value)
43+
44+
# Calculate and print the basis functions at this point
45+
span = bspline.find_knot_span(u_value)
46+
basis_values = bspline.basis_functions(u_value, span)
47+
48+
print(f"For u = {u_value}, the non-zero basis functions are:")
49+
for i, value in enumerate(basis_values):
50+
print(f"B^3_{span - bspline.degree + i} = {value:.4f}")
51+
52+
# Mark the evaluated point on the plot
53+
plt.plot(point[0], point[1], "go", markersize=10, label=f"Point at u={u_value}")
54+
plt.legend()
55+
56+
# Show the plot
57+
plt.tight_layout()
58+
plt.show()
59+
60+
61+
def example_b6() -> None:
62+
"""
63+
Implements Example B.6 from the document:
64+
Calculates the basis functions of degree 3 and their derivatives
65+
at u = 4.5 for knot vector [0, 0, 0, 0, 1, 2, 4, 7, 7, 7, 7]
66+
"""
67+
# Define the degree
68+
degree = 3
69+
70+
# Define the knot vector as specified in Example B.6
71+
knots = np.array([0, 0, 0, 0, 1, 2, 4, 7, 7, 7, 7])
72+
73+
# For this example, we need control points, but they don't affect the basis functions
74+
# So we'll create dummy 2D control points (7 points as required by the knot vector)
75+
control_points = np.zeros((7, 2))
76+
77+
# Create the B-spline
78+
bspline = BSpline(degree, knots, control_points)
79+
80+
# Evaluate at u = 4.5
81+
u_value = 4.5
82+
83+
# Find the knot span index (should be 6 according to the example)
84+
span = bspline.find_knot_span(u_value)
85+
print(f"For u = {u_value}, the knot span index is: {span}")
86+
87+
# Calculate derivatives up to order 3
88+
derivatives = bspline.basis_function_derivatives(u_value, span, 3)
89+
90+
# Display the results in the format shown in the example
91+
print("\nBasis function values and derivatives at u = 4.5:")
92+
print("-" * 80)
93+
94+
for k in range(4): # Derivatives 0 to 3
95+
line = (
96+
f"Ders[{k}][0] = {derivatives[k, 0]:.4f}, "
97+
f"Ders[{k}][1] = {derivatives[k, 1]:.4f}, "
98+
f"Ders[{k}][2] = {derivatives[k, 2]:.4f}, "
99+
f"Ders[{k}][3] = {derivatives[k, 3]:.4f},"
100+
)
101+
print(line)
102+
103+
print("\nWhich correspond to:")
104+
print("-" * 80)
105+
106+
# First row: B₃³, B₄³, B₅³, B₆³
107+
print(
108+
f"B₃³ = {derivatives[0, 0]:.4f}, "
109+
f"B₄³ = {derivatives[0, 1]:.4f}, "
110+
f"B₅³ = {derivatives[0, 2]:.4f}, "
111+
f"B₆³ = {derivatives[0, 3]:.4f},"
112+
)
113+
114+
# Second row: B₃³⁽¹⁾, B₄³⁽¹⁾, B₅³⁽¹⁾, B₆³⁽¹⁾
115+
print(
116+
f"B₃³⁽¹⁾ = {derivatives[1, 0]:.4f}, "
117+
f"B₄³⁽¹⁾ = {derivatives[1, 1]:.4f}, "
118+
f"B₅³⁽¹⁾ = {derivatives[1, 2]:.4f}, "
119+
f"B₆³⁽¹⁾ = {derivatives[1, 3]:.4f},"
120+
)
121+
122+
# Third row: B₃³⁽²⁾, B₄³⁽²⁾, B₅³⁽²⁾, B₆³⁽²⁾
123+
print(
124+
f"B₃³⁽²⁾ = {derivatives[2, 0]:.4f}, "
125+
f"B₄³⁽²⁾ = {derivatives[2, 1]:.4f}, "
126+
f"B₅³⁽²⁾ = {derivatives[2, 2]:.4f}, "
127+
f"B₆³⁽²⁾ = {derivatives[2, 3]:.4f},"
128+
)
129+
130+
# Fourth row: B₃³⁽³⁾, B₄³⁽³⁾, B₅³⁽³⁾, B₆³⁽³⁾
131+
print(
132+
f"B₃³⁽³⁾ = {derivatives[3, 0]:.4f}, "
133+
f"B₄³⁽³⁾ = {derivatives[3, 1]:.4f}, "
134+
f"B₅³⁽³⁾ = {derivatives[3, 2]:.4f}, "
135+
f"B₆³⁽³⁾ = {derivatives[3, 3]:.4f}."
136+
)
137+
138+
print("\nAll the other terms B_j^3(k) are null.")
139+
140+
# Plot the basis functions
141+
plot_basis_functions(bspline, u_value)
142+
143+
144+
def plot_basis_functions(bspline: BSpline, u_value: float) -> None:
145+
"""
146+
Plot the basis functions and mark the evaluation point.
147+
148+
Args:
149+
bspline: The B-spline object
150+
u_value: The parameter value to evaluate
151+
"""
152+
# Create figure
153+
_fig, ax = plt.subplots(figsize=(10, 6))
154+
155+
# Generate parameter values within the valid range
156+
u_range = np.linspace(bspline.u_min, bspline.u_max, 500)
157+
158+
# Calculate basis functions for each u in the range
159+
basis_values = []
160+
for u in u_range:
161+
span = bspline.find_knot_span(u)
162+
values = bspline.basis_functions(u, span)
163+
start_index = span - bspline.degree
164+
basis_values.append((start_index, values))
165+
166+
# Plot each basis function separately
167+
colors = ["r", "g", "b", "c", "m", "y", "k"]
168+
for i in range(len(bspline.control_points)):
169+
y_values = np.zeros_like(u_range)
170+
for j, (start_index, values) in enumerate(basis_values):
171+
idx = i - start_index
172+
if 0 <= idx < len(values):
173+
y_values[j] = values[idx]
174+
175+
ax.plot(u_range, y_values, color=colors[i % len(colors)], label=f"B_{i}^{bspline.degree}")
176+
177+
# Find the non-zero basis functions at u_value
178+
span = bspline.find_knot_span(u_value)
179+
values = bspline.basis_functions(u_value, span)
180+
181+
# Mark the evaluation point on each non-zero basis function
182+
for i in range(bspline.degree + 1):
183+
idx = span - bspline.degree + i
184+
ax.plot(u_value, values[i], "ko", markersize=6)
185+
ax.text(
186+
u_value,
187+
values[i] + 0.02,
188+
f"B_{idx}^{bspline.degree}({u_value:.1f})={values[i]:.4f}",
189+
horizontalalignment="center",
190+
verticalalignment="bottom",
191+
)
192+
193+
# Add vertical line at the evaluation point
194+
ax.axvline(x=u_value, color="k", linestyle="--", alpha=0.5)
195+
196+
# Add knot locations as vertical lines
197+
for knot in np.unique(bspline.knots):
198+
if bspline.u_min <= knot <= bspline.u_max:
199+
ax.axvline(x=knot, color="gray", linestyle="-", alpha=0.3)
200+
ax.text(knot, -0.05, f"{knot}", horizontalalignment="center")
201+
202+
# Set labels and title
203+
ax.set_xlabel("Parameter u")
204+
ax.set_ylabel("Basis function value")
205+
ax.set_title(f"B-spline basis functions of degree {bspline.degree}")
206+
ax.grid(True, alpha=0.3)
207+
ax.set_ylim(-0.1, 1.1)
208+
ax.legend(loc="upper right")
209+
210+
plt.tight_layout()
211+
plt.show()
212+
213+
214+
def create_simple_3d_bspline() -> BSpline:
215+
"""
216+
Create a simple 3D B-spline curve.
217+
218+
Returns:
219+
BSpline: A 3D B-spline object.
220+
"""
221+
# Define the degree
222+
degree = 3
223+
224+
# Define simple 3D control points for a curve
225+
control_points = np.array(
226+
[
227+
[0, 0, 0], # Start point
228+
[1, 1, 2],
229+
[2, -1, 1],
230+
[3, 0, 3],
231+
[4, 2, 0],
232+
[5, 0, 1], # End point
233+
]
234+
)
235+
236+
# Create a uniform knot vector
237+
knots = BSpline.create_uniform_knots(degree, len(control_points))
238+
239+
# Create and return the B-spline
240+
return BSpline(degree, knots, control_points)
241+
242+
243+
def demonstrate_3d_bspline() -> None:
244+
"""
245+
Demonstrate a simple 3D B-spline curve.
246+
"""
247+
# Create the B-spline
248+
bspline = create_simple_3d_bspline()
249+
250+
# Create a figure
251+
fig = plt.figure(figsize=(10, 8))
252+
ax = fig.add_subplot(111, projection="3d")
253+
254+
# Plot the B-spline curve with control polygon
255+
bspline.plot_3d(num_points=100, show_control_polygon=True, ax=ax)
256+
257+
# Set the title and adjust view
258+
ax.set_title("Simple 3D B-spline Curve (Degree 3)")
259+
ax.view_init(elev=30, azim=45)
260+
261+
# Set equal aspect ratio for better visualization
262+
ax.set_box_aspect([1, 1, 1])
263+
264+
# Show the plot
265+
plt.tight_layout()
266+
plt.show()
267+
268+
# Print some basic information about the curve
269+
print("\nB-spline Information:")
270+
print(f"- Degree: {bspline.degree}")
271+
print(f"- Number of control points: {len(bspline.control_points)}")
272+
print(f"- Parameter range: [{bspline.u_min}, {bspline.u_max}]")
273+
274+
# Evaluate a point in the middle of the curve
275+
mid_point = bspline.evaluate((bspline.u_min + bspline.u_max) / 2)
276+
print(
277+
f"\nPoint at middle of curve: ({mid_point[0]:.2f}, {mid_point[1]:.2f}, {mid_point[2]:.2f})"
278+
)
279+
280+
281+
if __name__ == "__main__":
282+
demonstration()
283+
example_b6()
284+
demonstrate_3d_bspline()

0 commit comments

Comments
 (0)