Как нарисовать циклоиду на кривой другой функции (другой циклоиды)? - PullRequest
0 голосов
/ 10 декабря 2018

Я хотел бы нарисовать циклоид, который идет на другой циклоиде, но я точно не знаю, как это сделать.Вот мой код.

import numpy as np
import matplotlib.pyplot as plt
import math

from matplotlib import animation

#r = float(input('write r\n'))
#R = float(input('write R\n'))
r = 1
R  = 1
x  = []
y  = []
x2 = []
y2 = []
x3 = []
y3 = []

length=[0]

fig, ax = plt.subplots()
ln, = plt.plot([], [], 'r', animated=True)
f = np.linspace(0, 10*r*math.pi, 1000)


def init():
ax.set_xlim(-r,  12*r*math.pi)
ax.set_ylim(-4*r, 4*r)
return ln,

def update2(frame):
    #parametric equations of cycloid
    x0 = r * (frame - math.sin(frame))
    y0 = r * (1 - math.cos(frame))
    x.append(x0)
    y.append(y0)

#derivative of cycloid
dx = r * (1 - math.cos(frame))
dy = r * math.sin(frame)

#center of circle
a = dy * dy + dx * dx
b = (-2 * x0 * dy) - (2 * frame * dy * dy) + (2 * y0 * dx) - (2 * frame * dx * dx)
c = (x0 * x0) + (2 * frame * x0 * dy) + (frame * frame * dy * dy) + (y0 * y0) - (2 * frame * y0 * dx) + (frame * frame * dx * dx) -1
t1 = (-b - math.sqrt(b * b - 4 * a * c)) / (2 * a)
#t2 = (-b + math.sqrt(b * b - 4 * a * c)) / (2 * a)

center1x=(x0-dy*(t1-x0))*R
center1y=(y0+dx*(t1-x0))*R
#center2x=(x0-dy*(t2-x0))*R
#center2y=(y0+dx*(t2-x0))*R

#length of cycloid
length.append(math.sqrt(x0*x0 + y0*y0))
dl=sum(length)
param = dl / R

W1x = center1x + R * math.cos(-param)
W1y = center1y + R * math.sin(-param)
#W2x = center2x + R * math.cos(-param)
#W2y = center2y + R * math.sin(-param)

x2.append(W1x)
y2.append(W1y)
#x3.append(W2x)
#y3.append(W2y)

ln.set_data([x, x2], [y, y2])
return ln,


ani = animation.FuncAnimation(fig, update2, frames=f,init_func=init, blit=True, interval = 0.1, repeat = False)
plt.show()

В своей функции update2 я создал параметрические уравнения первого циклоиды, а затем попытался получить координаты точек второго циклоида, которые должны идти по первому.

Моя идея основана на том, что этот типичный циклоид движется по прямой линии, а циклоид, который движется по другой кривой, должен двигаться по касательной к этой кривой, поэтому центр окружности, которая создает эту циклоиду, всегда помещается в нормальное положение.кривой.Из параметрических уравнений нормали я попытался получить центр круга, который создает циклоид, но я думаю, что это не очень хороший способ.

Моя цель - получить что-то вроде этого:

enter image description here

Ответы [ 3 ]

0 голосов
/ 11 декабря 2018

Вот один из способов.Исчисление дает нам формулы для определения углов направления в любой точке циклоиды и длины дуги вдоль циклоиды.Аналитическая геометрия говорит нам, как использовать эту информацию для нахождения нужных вам точек.

Кстати, график, составленный путем накатывания фигуры вдоль другой фигуры, называется рулеткой .Мой код довольно прост и может быть оптимизирован, но теперь он работает, может использоваться для других задач и разбит на части, чтобы облегчить понимание математики и алгоритма.Чтобы понять мой код, используйте эту схему.Циклоид - это синяя кривая, черные круги - это вращающийся круг на циклоиде, точка А - это «опорная точка» (точка, где точка обода касается циклоиды - я хотел сделать этот код общим), и точка Fэто точка подвижного обода.Две красные дуги имеют одинаковую длину, что мы имеем в виду, катая круг вдоль циклоиды.

enter image description here

И вот мой код.Спросите, нужна ли вам помощь с источником различных формул, но в углах направления и длинах дуг используется исчисление.

"""Numpy-compatible routines for a standard cycloid (one caused by a
circle of radius r above the y-axis rolling along the positive x-axis
starting from the origin). 
"""
import numpy as np

def x(t, r):
    """Return the x-coordinate of a point on the cycloid with parameter t."""
    return r * (t - np.sin(t))

def y(t, r):
    """Return the y-coordinate of a point on the cycloid with parameter t."""
    return r * (1.0 - np.cos(t))

def dir_angle_norm_in(t, r):
    """Return the direction angle of the vector normal to the cycloid at
    the point with parameter t that points into the cycloid."""
    return -t / 2.0

def dir_angle_norm_out(t, r):
    """Return the direction angle of the vector normal to the cycloid at
    the point with parameter t that points out of the cycloid."""
    return np.pi - t / 2.0

def arclen(t, r):
    """Return the arc length of the cycloid between the origin and the
    point on the cycloid with parameter t."""
    return 4.0 * r * (1.0 - np.cos(t / 2.0))


# Roulette problem

def xy_roulette(t, r, T, R):
    """Return the x-y coordinates of a rim point on a circle of radius
    R  rolling on a cycloid of radius r starting at the anchor point
    with parameter T currently at the point with parameter t. (Such a 
    rolling curve on another curve is called a roulette.)
    """
    # Find the coordinates of the contact point P between circle and cycloid
    px, py = x(t, r), y(t, r)
    # Find the direction angle of PC from the contact point to circle's center
    a1 = dir_angle_norm_out(t, r)
    # Find the coordinates of the center C of the circle
    cx, cy = px + R * np.cos(a1), py + R * np.sin(a1)
    # Find cycloid's arc distance AP between anchor and current contact points
    d = arclen(t, r) - arclen(T, r)  # equals arc PF
    # Find the angle φ the circle turned while rolling from the anchor pt
    phi = d / R
    # Find the direction angle of CF from circle's center to rim point
    a2 = dir_angle_norm_in(t, r) - phi  # subtract: circle rolls clockwise
    # Find the coordinates of the final point F
    fx, fy = cx + R * np.cos(a2), cy + R * np.sin(a2)
    # Return those coordinates
    return fx, fy

import matplotlib.pyplot as plt

r = 1
R = 0.75
T = np.pi / 3

t_array = np.linspace(0, 2*np.pi, 201)
cycloid_x = x(t_array, r)
cycloid_y = y(t_array, r)
roulette_x, roulette_y = xy_roulette(t_array, r, T, R)

fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')

ax.plot(cycloid_x, cycloid_y)
ax.plot(roulette_x, roulette_y)

plt.show()

А вот итоговый график.Вы можете сделать это по своему усмотрению.Обратите внимание, что это имеет только круг, катящийся вдоль одной арки циклоиды.Если вы проясните, что должно происходить на каспах, это может быть расширено.

enter image description here

Или, если вы хотите меньший круг и кривую, которая заканчивается наострые выступы (здесь r = 1, T = 0 n = 6 (количество маленьких арок) и R = 4 * r / np.pi / n)

enter image description here

0 голосов
/ 12 декабря 2018

Спасибо всем.Каким-то образом мне удалось это сделать.Решение может быть некрасивым, но мне достаточно.

import numpy as np
import matplotlib.pyplot as plt
import math

from matplotlib import animation

r = float(input('write r\n'))
R = float(input('write R\n'))
#r=1
#R=0.1
x  = []
y  = []
x2 = []
y2 = []

x_1=0
x_2=0


lengthX=[0]
lengthY=[0]
lengthabs=[0]

fig, ax = plt.subplots()
ln, = plt.plot([], [], 'r', animated=True)
f = np.linspace(0, 2*math.pi, 1000)

def init():
    ax.set_xlim(-r,  4*r*math.pi)
    ax.set_ylim(0, 4*r)
    return ln,

def update2(frame):
    #cycloid's equations
    x0 = r * (frame - math.sin(frame))
    y0 = r * (1 - math.cos(frame))
    x.append(r * (frame - math.sin(frame)))
    y.append(r * (1 - math.cos(frame)))

    #arc's length
    lengthabs.append(math.sqrt((x0-lengthX[-1])*(x0-lengthX[-1])+(y0-lengthY[-1])*(y0-lengthY[-1])))
    lengthX.append(x0)
    lengthY.append(y0)
    dl=sum(lengthabs)
    param = dl / R

    #center of circle
    center1x = r * (frame - math.sin(frame)) + R * math.cos((frame+2*math.pi) / 2)
    center1y = r * (1     - math.cos(frame)) - R * math.sin((frame+2*math.pi) / 2)

    if(frame<2*math.pi):
        W1x = center1x + R * math.cos(-param)
        W1y = center1y + R * math.sin(-param)
    else:
        W1x = center1x + R * math.cos(param)
        W1y = center1y + R * math.sin(param)

    x2.append(W1x)
    y2.append(W1y)
    ln.set_data([x,x2], [y,y2])
    return ln,

ani = animation.FuncAnimation(fig, update2, frames=f,init_func=init, blit=True, interval = 0.1, repeat = False)
plt.show()
0 голосов
/ 10 декабря 2018

Вы можете сгенерировать координаты центра вращающегося круга, используя параллельную кривую определение.Параметрические уравнения для этого центра довольно просты (если я не ошибся):

для большой циклоиды:

 X = R(t - sin(t))
 Y = R(1 - cos(t))
 X' = R(1 - cos(t))
 Y' = R*sin(t)

параллельная кривая (центр малого круга):

Sqrt(X'^2+Y'^2)=R*Sqrt(1-2*cos(t)+cos^2(t)+sin^2(t)) =
                R*Sqrt(2-2*cos(t))=
                R*Sqrt(4*sin^2(t/2))=
                2*R*sin(t/2)

 x(t) = X(t) + r*R*sin(t)/(2R*sin(t/2)) =
        R(t - sin(t)) + r*2*sin(t/2)*cos(t/2) / (2*sin(t/2)) = 

        R(t - sin(t)) + r*cos(t/2)

  y(t) = Y(t) - r*R*(1-cos(t))/(2*R*sin(t/2)) =
         R(1 - cos(t)) - r*(2*sin^2(t/2)/(2*sin(t/2)) =  

         R(1 - cos(t)) - r*sin(t/2)

Но траектория точки на окружности - это суперпозиция положения центра и вращение вокруг него с угловой скоростью, которая зависит от длины главной циклоиды плюс вращение главной касательной.

Добавлено из предположений в комментариях:

длина циклоидальной дуги

  L(t) = 4R*(1-cos(t/2))
  to use it for small circle rotation, divide by r

вывод касательного вращения

fi(t) = atan(Y'/X') = atan(sin(t)/(1-cos(t)) = 
                      atan(2*sin(t/2)*cos(t/2)/(2(sin^2(t/2))) = 
                      atan(ctg(t/2)) = Pi/2 - t/2

, поэтому изменение направления касательной пропорционально параметру большой циклоиды

и конечный результат (возможно,некоторые признаки не верны)

 theta(t) = L(t)/r + t/2 + Phase
 ox(t) = x(t) + r * cos(theta(t))
 oy(t) = y(t) + r * sin(theta(t))
...