You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

请求实现圆沿正弦曲线滚动的变加速动画(基于现有直线运动代码)

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_acceleration function with any time-dependent formula you want—linear, oscillating, or even random.
  • Resize the circle: Change circle_radius to make the circle larger or smaller.
  • Adjust animation speed: Modify the interval parameter in FuncAnimation (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_acceleration function lets you control how the speed of the circle changes over time, creating the desired dynamic effect.

内容的提问来源于stack exchange,提问作者Vinsmoke Mau

火山引擎 最新活动