请求实现圆沿正弦曲线滚动的变加速动画(基于现有直线运动代码)
How to Modify Your Code for a Circle Rolling Along a Sine Curve with Variable Acceleration
Great question! Let's break down what needs to change from your original straight-line code to get a circle rolling along a sine curve with variable acceleration. The key steps are defining the sine path, calculating arc length for proper rolling, modeling variable acceleration, and adjusting the circle's position/rotation correctly.
Key Changes from Original Code
- Replace the straight line with a sine curve path.
- Compute arc length to ensure the circle rolls without slipping (no sliding).
- Implement a variable acceleration function that changes over time.
- Offset the circle's center perpendicular to the sine curve (not just a fixed y-offset).
- Rotate the circle based on the distance traveled along the curve.
Modified Code with Explanations
Here's the complete working code with comments to walk you through each part:
import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation # 1. Define the sine curve path and its derivative def sine_curve(x): return 5 * np.sin(0.1 * x) # Amplitude = 5, frequency = 0.1 (adjust these!) def sine_derivative(x): return 0.5 * np.cos(0.1 * x) # Derivative of the sine curve (dy/dx) # 2. Calculate arc length of the sine curve (for rolling without slipping) def compute_arc_length(x_start, x_end): x_vals = np.linspace(x_start, x_end, 1000) dx = x_vals[1] - x_vals[0] dy_dx = sine_derivative(x_vals) segment_lengths = np.sqrt(1 + dy_dx**2) * dx return np.sum(segment_lengths) # 3. Define your variable acceleration function (customize this!) def variable_acceleration(t): # Example: acceleration that oscillates over time return 1 + 0.5 * np.sin(t) # Other options: # return 0.5 * t # Increasing acceleration # return 3 * np.cos(0.5 * t) # Smooth oscillating acceleration # 4. Precompute motion data over time time_steps = np.arange(0, 10, 0.1) # Time from 0 to 10s, 0.1s steps initial_velocity = 0 initial_x = -20 # Starting position on the sine curve # Calculate velocity and distance traveled along the curve velocity = np.zeros_like(time_steps) distance_along_curve = np.zeros_like(time_steps) for i in range(1, len(time_steps)): dt = time_steps[i] - time_steps[i-1] a = variable_acceleration(time_steps[i-1]) velocity[i] = velocity[i-1] + a * dt distance_along_curve[i] = distance_along_curve[i-1] + velocity[i-1] * dt + 0.5 * a * dt**2 # Find x positions corresponding to the traveled distance (arc length match) x_positions = np.zeros_like(time_steps) x_positions[0] = initial_x for i in range(1, len(time_steps)): target_distance = distance_along_curve[i] # Binary search to find x where arc length from start equals target distance low, high = initial_x, initial_x + 100 for _ in range(50): mid = (low + high) / 2 current_distance = compute_arc_length(initial_x, mid) if current_distance < target_distance: low = mid else: high = mid x_positions[i] = (low + high) / 2 # 5. Precompute circle center positions and rotation angles circle_radius = 2 circle_points = np.linspace(0, 2*np.pi, 100) # Points to draw the circle center_x = [] center_y = [] rotation_angles = [] for x in x_positions: y = sine_curve(x) dy_dx = sine_derivative(x) # Normal vector pointing outward from the curve (for center offset) normal_vector = np.array([-dy_dx, 1]) normal_vector /= np.sqrt(1 + dy_dx**2) # Normalize to unit length # Calculate center position (curve point + radius along normal) center = np.array([x, y]) + circle_radius * normal_vector center_x.append(center[0]) center_y.append(center[1]) # Rotation angle: distance traveled / radius (no slipping condition) rotation_angles.append(compute_arc_length(initial_x, x) / circle_radius) # 6. Set up the animation fig, ax = plt.subplots(figsize=(10, 6)) ax.set_xlim(-30, 80) ax.set_ylim(-7, 10) ax.set_title("Circle Rolling Along Sine Curve with Variable Acceleration") ax.plot(np.linspace(-30, 80, 1000), sine_curve(np.linspace(-30, 80, 1000)), 'b-', label="Sine Path") circle_plot, = ax.plot([], [], 'r-', label="Rolling Circle") center_trace, = ax.plot([], [], 'g--', label="Center Trace") ax.legend() def update_animation(frame): # Rotate the circle points based on traveled distance rotated_x = center_x[frame] + circle_radius * np.cos(circle_points - rotation_angles[frame]) rotated_y = center_y[frame] + circle_radius * np.sin(circle_points - rotation_angles[frame]) circle_plot.set_data(rotated_x, rotated_y) # Update the trace of the center's path center_trace.set_data(center_x[:frame+1], center_y[:frame+1]) return circle_plot, center_trace # Run the animation animation = FuncAnimation(fig, update_animation, frames=len(time_steps), interval=50, blit=True) plt.show()
Customization Tips
- Adjust the sine curve: Modify the amplitude and frequency in
sine_curve(e.g.,10 * np.sin(0.2 * x)for a taller, tighter curve). - Change acceleration: Replace the
variable_accelerationfunction with any time-dependent formula you want—linear, oscillating, or even random. - Resize the circle: Change
circle_radiusto make the circle larger or smaller. - Adjust animation speed: Modify the
intervalparameter inFuncAnimation(lower values = faster animation).
Why This Works
- Arc length calculation: Ensures the circle rotates exactly the right amount to roll without slipping (each unit of distance along the curve equals one full rotation divided by the circle's circumference).
- Normal vector offset: Keeps the circle centered perpendicular to the sine curve, so it always sits correctly on the path.
- Variable acceleration: The
variable_accelerationfunction lets you control how the speed of the circle changes over time, creating the desired dynamic effect.
内容的提问来源于stack exchange,提问作者Vinsmoke Mau




