I'm working on a project which revolves around chaotic oscillators.
Now, I've just coded a Lorenz Attractor in Python using a Runge-Kutta of fourth order:
'''
Created on 19 feb. 2018
#author: judvuyst
'''
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.animation as animation
#Differential equations of a Lorenz System
def X(x, y, s):
return s * (y - x)
def Y(x, y, z, r):
return (-x) * z + r * x - y
def Z(x, y, z, b):
return x * y - b * z
#RK4 for the differential equations
def RK4(x, y, z, s, r, b, h):
k_1 = X(x, y, s)
l_1 = Y(x, y, z, r)
m_1 = Z(x, y, z, b)
k_2 = X((x + k_1 * h * 0.5), (y + l_1 * h * 0.5), s)
l_2 = Y((x + k_1 * h * 0.5), (y + l_1 * h * 0.5), (z + m_1 * h * 0.5), r)
m_2 = Z((x + k_1 * h * 0.5), (y + l_1 * h * 0.5), (z + m_1 * h * 0.5), b)
k_3 = X((x + k_2 * h * 0.5), (y + l_2 * h * 0.5), s)
l_3 = Y((x + k_2 * h * 0.5), (y + l_2 * h * 0.5), (z + m_2 * h * 0.5), r)
m_3 = Z((x + k_2 * h * 0.5), (y + l_2 * h * 0.5), (z + m_2 * h * 0.5), b)
k_4 = X((x + k_3 * h), (y + l_3 * h), s)
l_4 = Y((x + k_3 * h), (y + l_3 * h), (z + m_3 * h), r)
m_4 = Z((x + k_3 * h), (y + l_3 * h), (z + m_3 * h), b)
x += (k_1 + 2 * k_2 + 2 * k_3 + k_4) * h * (1/6)
y += (l_1 + 2 * l_2 + 2 * l_3 + l_4) * h * (1/6)
z += (m_1 + 2 * m_2 + 2 * m_3 + m_4) * h * (1/6)
return (x, y, z)
#Initial values and Parameters
x_0, y_0, z_0 = 1, 1, 1
s, r, b = 10, 28, 8/3
#RK4 iteration
x_list = [x_0]
y_list = [y_0]
z_list = [z_0]
h = 0
i = 0
while h < 0.15:
x = x_list[i]
y = y_list[i]
z = z_list[i]
position = RK4(x, y, z, s, r, b, h)
x_list.append(position[0])
y_list.append(position[1])
z_list.append(position[2])
h += 0.0000005
i += 1
#plotten
fig = plt.figure()
ax = fig.gca(projection = '3d')
x_array = np.array(x_list)
y_array = np.array(y_list)
z_array = np.array(z_list)
ax.plot(x_array, y_array, z_array, ',')
plt.show()
My question is: can I use this code to make a simulation of the attractor? Some sort of dot and line which follows these equations and leave behind a trail which at the end is the full attractor image.
I'm not really familiar with the animation module of matplotlib.
Thx in advance!
Kind regards
Julian
Related
We have two terms, two parameters (h, h0) and a variable T. We can define a certain value of T, where the difference of the two terms divided by L is equal to zero.
With this T value, we can calculate g0, gc and gs operators, and then witness1 and witness2.
Then we make this whole calculation with running parameters (from 0.03 to 3): h0=0.03, h=0.03; h0=0.06, h=0.03; ...; h0=3, h=0.03; h0=0.03, h=0.06; ...; h0=3, h=3
Then we select the witness with the lower value, and put it to the proper place in the matrix.
The values can be both positive and negative. We are interested in where will be the result negative, and from which witness we got the result. I have plotted the results from the matrix, the negative values with yellow, and the positive with white. Now I would like to plot the negative numbers from witness1 with blue, and the negative numbers from witness2 with yellow. Then I would like to norm the graph from 0-100 to 0-3.
How can I make this?
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
def g0operator(T, gamma, h, L):
k = -math.pi
d=2*math.pi/L
g0=0
while k <= math.pi:
g0 = g0 + (((math.tanh(math.sqrt(((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2) / T))) * (
1 / (math.sqrt(
((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2))) * ((h - math.cos(k))))
k = k + d
g0 = g0 / L
return g0
def gsoperator(T, gamma, h, L):
gs=0
k = -math.pi
d=2*math.pi/L
while k <= math.pi:
gs = gs + ((math.tanh(math.sqrt(((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2) / T)) * (1 /
(math.sqrt(((gamma * math.sin(k)) ** 2) + (h - math.cos(k)) ** 2))) * (
((math.sin(k)) ** 2)))
k = k + d
gs = -(gs / L) * gamma
return gs
def gcoperator(T, gamma, h, L):
d=2*math.pi/L
gc=0
k = -math.pi
while k <= math.pi:
gc = gc + ((math.tanh(np.sqrt(((gamma * np.sin(k)) ** 2) + (h - np.cos(k)) ** 2) / T)) * (1 /
np.sqrt(((gamma * np.sin(k)) ** 2) + (h - np.cos(k)) ** 2))) * (np.cos(k) * ((np.cos(k) - h)))
k = k + d
gc = gc / L
return gc
def first_term(gamma, h, T, L):
c=-math.pi
d=2*math.pi/L
first=0
while c <= math.pi:
first = first + (math.tanh(math.sqrt(((gamma * math.sin(c)) ** 2) + (h - math.cos(c)) ** 2) / T) * math.sqrt(
((gamma * math.sin(c))
** 2) + (h - math.cos(c)) ** 2))
c=c+d
return first
def second_term(h, h0, gamma, L):
second=0
c=-math.pi
d=2*math.pi/L
while c<=math.pi:
second = second + abs(((math.cos(c) - h0) * (math.cos(c) - h) + ((gamma * math.sin(c)) ** 2)) / (
math.sqrt(((gamma * math.sin(c)) ** 2) + (h0 - math.cos(c)) ** 2)))
c = c + d
return second
def witness1(gs, g0, gc):
W = (-1 / 4) * (2 * abs(gs) + ((g0) ** 2) - ((gc) ** 2) + ((gs) ** 2) - 1)
return W
def witness2(gs, g0, gc):
w=-(1/4)*(-(g0**2)+(gc**2)-(gs**2)-1+2*math.sqrt((g0**2)+(gc**2)))
return w
h=0.03
h0=0.03
T=2.5
gamma=0.6
K=2.5
L=100000
matrix=np.zeros((100,100))
for i in range(100):
for b in range(100):
K = 2.5
T = 2.5
result=1
while abs(result) > 10 ** (-12):
c = -math.pi
first = first_term(gamma, h, T, L)
second = second_term(h, h0, gamma, L)
result = (first - second) / L
if result > 0:
T = T + K / 2
elif result < 0:
T = T - K / 2
K = K / 2
gc = gcoperator(T, gamma, h, L)
gs = gsoperator(T, gamma, h, L)
g0 = g0operator(T, gamma, h, L)
W = witness1(gs, g0, gc)
w = witness2(gs, g0, gc)
if W < w:
matrix[i, b] = W
else:
matrix[i, b] = w
h0=h0+0.03
h=h+0.03
h0=0.03
np.savetxt('matrixgamma=0.6.txt', matrix)
a=np.loadtxt('matrixgamma=0.6.txt')
cmap=colors.ListedColormap(['yellow', 'white'])
bounds=[-2, 0, 2]
norm=colors.BoundaryNorm(bounds, cmap.N)
img=plt.imshow(a, interpolation='nearest', origin='lower', cmap=cmap, norm=norm)
plt.colorbar(img, cmap=cmap, norm=norm, boundaries=bounds)
plt.show()
I'm sorry but I have simplified a little bit your witnessN functions, but I hope that you can adapt my solution, in which the key points are
to save the values for the grid evaluations of witnessN
to use Numpy's logical functions
to use the fact that Booleans can be used as 0 or 1 integers,
With respect to plotting, you can omit the plt.contourf statement, but I like the additional lines subdividing the fields.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm, ListedColormap
witness1 = lambda X, Y: np.sin(X-Y/2)
witness2 = lambda X, Y: np.cos(X/2+2*Y)
x = np.linspace(-6, 6, 241)
X, Y = np.meshgrid(x, x)
W = witness1(X, Y)
w = witness2(X, Y)
Wp, wp, Wgtw = W>0, w>0, W>w
values = np.where(Wgtw, W, w)
colors = np.where(np.logical_and(1-Wgtw, 1-wp), 0, 0)
colors += np.where(np.logical_and( Wgtw, 1-Wp), 1, 0)
colors += np.where(np.logical_and( Wgtw, Wp), 2, 0)
colors += np.where(np.logical_and(1-Wgtw, wp), 3, 0)
# change colors to your taste
# w<0, W<0, W>0, w>0
cm = ListedColormap([ 'y', 'b', 'r', 'g'])
norm=BoundaryNorm([-0.5, 0.5, 1.5, 2.5, 3.5], 4)
pc = plt.pcolor(X, Y, colors, norm=norm, cmap=cm)
ct = plt.contour(X, Y, values, [-.9, -0.1, 0.1, 0.9], colors='k')
lb = plt.clabel(ct)
cf = plt.contourf(X, Y, colors, norm=norm, cmap=cm, alpha=0.6)
cb = plt.colorbar(pc)
cb.set_ticks([0, 1, 2, 3])
cb.set_ticklabels(['w<0', 'W<0', 'W>0', 'w>0'])
plt.show()
Trying to replace the function U2(x,y,z) with specified values of x,y,z. Not sure how to do that with sympy because they are as "x = arange.(-h,h,0.001)" as seen in the code below.
Below you will find my implementation with sympy. Additionally I am using PyCharm.
This implementation is based on Dr. Annabestani and Dr. Naghavis' paper: A 3D analytical ion transport model for ionic polymer metal composite actuators in large bending deformations
import sympy as sp
h = 0.1 # [mm] half of thickness
W: float = 6 # [mm] width
L: float = 28 # [mm] length
F: float = 96458 # [C/mol] Faraday's constant
k_e = 1.34E-6 # [F/m]
Y = 5.71E8 # [Pa]
d = 1.03 - 11 # [m^2/s] diffiusitivity coefficient
T = 293 # [K]
C_minus = 1200 # [mol/m^3] Cation concentration
C_plus = 1200 # [mol/m^3] anion concentration
R = 8.3143 # [J/mol*K] Gas constant
Vol = 2*h*W*L
#dVol = diff(Vol,x) + diff(Vol, y) + diff(Vol, z) # change in Volume
theta = 1 / W
x, y, z, m, n, p, t = sp.symbols('x y z m n p t')
V_1 = 0.5 * sp.sin(2 * sp.pi * t) # Voltage as a function of time
k_f = 0.5
t_f = 44
k_g = 4.5
t_g = 0.07
B_mnp = 0.003
b_mnp: float = B_mnp
gamma_hat_2 = 0.04
gamma_hat_5 = 0.03
gamma_hat_6 = 5E-3
r_M = 0.15 # membrane resistance
r_ew = 0.175 # transverse resistance of electrode
r_el = 0.11 # longitudinal resistance of electrode
mu = 2.4
sigma_not = 0.1
a_L: float = 1.0 # distrubuted surface attentuation
r_hat = sp.sqrt(r_M ** 2 + r_ew ** 2 + r_el ** 2)
lambda_1 = 0.0001
dVol = 1
K = (F ** 2 * C_minus * d * (1 - C_minus * dVol)) / (R * T * k_e) # also K = a
K_hat = (K-lambda_1)/d
gamma_1 = 1.0
gamma_2 = 1.0
gamma_3 = 1.0
gamma_4 = 1.0
gamma_5 = 1.0
gamma_6 = 1.0
gamma_7 = 1.0
small_gamma_1 = 1.0
small_gamma_2 = 1.0
small_gamma_3 = 1.0
psi = gamma_1*x + gamma_2*y + gamma_3*z + gamma_4*x*y + gamma_5*x*z + gamma_6*y*z + gamma_7*x*y*z + (small_gamma_1/2)*x**2 + (small_gamma_2/2)*y**2 + (small_gamma_3/2)*x*z**2
psi_hat_part = ((sp.sin(((m + 1) * sp.pi) / 2 * h)) * x) * ((sp.sin(((n + 1) * sp.pi) / W)) * y) * ((sp.sin(((p + 1) * sp.pi) / L)) * z)
psi_hat = psi * psi_hat_part # Eqn. 19
print(psi_hat)
x1: float = -h
x2: float = h
y1: float = 0
y2: float = W
z1: float = 0
z2: float = L
I = psi_hat.integrate((x, x1, x2), (y, y1, y2), (z, z1, z2)) # Integration for a_mnp Eqn. 18
A_mnp = ((8 * K_hat) / (2 * h * W * L)) * I
Partial = A_mnp * ((sp.sin(((m + 1) * sp.pi) / 2 * h)) * x) * ((sp.sin(((n + 1) * sp.pi) / W)) * y) * ((sp.sin(((p + 1) * sp.pi) / L)) * z)
start = Partial.integrate((p, 0 , 10E9), (n, 0, 10E9), (m, 0, 10E9)) #when using infinity it goes weird, also integrating leads to higher thresholds than summation
a_mnp_denom = (((sp.sin(((m + 1) * sp.pi) / 2 * h)) ** 2) * ((sp.sin(((n + 1) * sp.pi) / W)) ** 2) * (
(sp.sin(((p + 1) * sp.pi) / L)) ** 2) + K_hat)
a_mnp = A_mnp / a_mnp_denom # Eqn. 18
U2 = sp.Function("U2")
U2 = a_mnp * ((sp.sin(((m + 1) * sp.pi) / 2 * h)) * x) * ((sp.sin(((n + 1) * sp.pi) / W)) * y) * (
(sp.sin(((p + 1) * sp.pi) / L)) * z) # Eqn. 13
x = np.arange(-h, h, 0.001)
y = np.arange(-h, h, 0.001)
z = np.arange(-h, h, 0.001)
f= sp.subs((U2), (x ,y ,z))
I currently get the error message: ValueError: subs accepts either 1 or 2 arguments. So that means I can't use the subs() method and replace() also doesn't work too well. Are there any other methods one can use?
Any help will be grateful, thank you!
Oscar is right: you are trying to deal with too much of the problem at once. That aside, Numpy and SymPy do not work like you think they do. What were you hoping to see when you replaced 3 variables, each with a range?
You cannot replace a SymPy variable/Symbol with a Numpy arange object, but you can replace a Symbol with a single value:
>>> from sympy.abc import x, y
>>> a = 1.0
>>> u = x + y + a
>>> u.subs(x, 1)
y + 2.0
>>> u.subs([(x,1), (y,2)])
4.0
You might iterate over the arange values, creating values of f and then doing something with each value:
f = lambda v: u.subs(dict(zip((x,y),v)))
for xi in range(1,3): # replace range with your arange call
for yi in range(-4,-2):
fi = f((xi,yi))
print(xi,yi,fi)
Be careful about iterating and using x or y as your loop variable, however, since that will then lose the assignment of the Symbol to that variable,
for x in range(2):
print(u.subs(x, x)) # no change and x is no longer a Symbol, it is now an int
I am trying to approximate the inverse of the Fourier transform in two dimensions. For the inverse Fourier transform, I use the definition,
$$
F^{-1}[\phi](x, y) = \dfrac{1}{4\pi} \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} e^{-i (ux + wy} \phi(u, w) \text{d}u \text{d}w,
$$
for the inverse of the Fourier transform. The integral will be approximated by use of the trapezoidal integration rule. The grid structure is chosen as $x_j = x_0 + j\Delta_x$, $y_k = y_0 + k\Delta_y$, $u_n = \left(n - \frac{N}{2}\right) \Delta_u$ and $w_m = \left(m - \frac{N}{2}\right) \Delta_u$,
for $j, k, n, m, N \in \mathbb{N}$. By choosing the relations $\Delta_u \Delta_x = \dfrac{2\pi}{N}$ and $\Delta_w \Delta_y = \dfrac{2\pi}{N}$, the approximation of the two dimensional Fourier transform can be written in terms of the fast Fourier transform (FFT).
I implemented the results in Python, and tried to recover the bivariate normal density for different parameters $\sigma$ and $\mu$. As the normal density decays to zero, the grid can be constructed in terms of the mean and the variance.
Below, I have included the approximation in code:
from matplotlib import pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
from scipy.fft import fft, fft2
from scipy.stats import multivariate_normal
i = complex(0.0, 1.0)
def chF(uu, ww, mu, sigma):
return np.exp(
i * (uu * mu[0] + ww * mu[1])
- 0.5 * (
uu**2 * sigma[0,0]
+ ww**2 * sigma[1,1]
+ uu * ww * (sigma[0,1] + sigma[1,0])
)
)
def pdf(xx, yy, mu, sigma):
norm = multivariate_normal(mu, sigma)
return norm.pdf(np.dstack([xx, yy]))
def powerSequence(a, N, offset=0):
# Returns a sequence of a ^ (n + offset) for n in N
return a ** (np.arange(N) + offset)
def powerSequence2d(a, N1, N2, offset=0):
# Returns a sequence of a ^ (n + j + offset) for n,j in N
return a ** (np.array([
j + np.arange(N2) for j in range(0, N1)]) + offset)
def createSimple1dGrid(c1, c2, c4=0, N:int=2**9, L:float=10):
x0 = c1 - L * np.sqrt(c2)
dx = 2 * L * np.sqrt(c2 + np.sqrt(c4)) / N
du = 2 * np.pi / (N * dx)
x = x0 + np.arange(N) * dx
u = (np.arange(N) - N / 2) * du
return x, u, du
def createSimpleGrid(c11, c21, c12, c22, c14=0, c24=0,
N:int=2**9, L1:float=10, L2:float=10):
x, u, du = createSimple1dGrid(c11, c12, c14, N=N, L=L1)
y, w , dw = createSimple1dGrid(c21, c22, c24, N=N, L=L2)
return x, y, u, w, du, dw
def inverseTransform(x, y, u, w, du, dw, phinn, N):
# Compute edges of the trapezoidal integration rule for 2-dimensional integrals.
e1 = np.exp(-i * (u[0] * x + w[0] * y)) * phinn[0, 0]
e2 = np.exp(-i * (u[0] * x + w[N-1] * y)) * phinn[0, N-1]
e3 = np.exp(-i * (u[N-1] * x + w[0] * y)) * phinn[N-1, 0]
e4 = np.exp(-i * (u[N-1] * x + w[N-1] * y)) * phinn[N-1, N-1]
e = 0.25 * (e1 + e2 + e3 + e4)
# Compute boundaries of the trapezoidal integration rule
# for 2-dimensional integrals. These can be written in
# one-dimensional Fourier transforms.
b1 = np.exp(-i * w[0] * y) * powerSequence(-1, N)\
* fft(phinn[:, 0] * np.exp(-i * x[0] * u))
b2 = np.exp(-i * w[N-1] * y) * powerSequence(-1, N)\
* fft(phinn[:, N-1] * np.exp(-i * x[0] * u))
b3 = np.exp(-i * u[0] * x) * powerSequence(-1, N)\
* fft(phinn[0, :] * np.exp(-i * y[0] * w))
b4 = np.exp(-i * u[N-1] * x) * powerSequence(-1, N)\
* fft(phinn[N-1, :] * np.exp(-i * y[0] * w))
b = 0.5 * (b1 + b2 + b3 + b4)
# Compute IFFT-2d
func = phinn * np.exp(-i *(x[0] * u + y[0] * w))
invFour2d = powerSequence2d(-1, N, N)\
* fft2(func)
invTransform = 1 / (4 * np.pi**2) * du * dw * (invFour2d - b + e)
return invTransform
def test_recover_normal_density_off_2d_non_centred():
# Initialize parameters of the two-dimensional normal density
s1, s2 = 4.0, 10.0
mu, sigma = np.array([10, 10]), np.array([
[s1, 0.0],
[0.0, s2]
])
# Create the Fourier grid
N, L = 2**9, 10
x, y, u, w, du, dw = createSimpleGrid(mu[0], mu[1], s1, s2, N=N, L1=L, L2=L)
uu, ww = np.meshgrid(u, w, indexing="ij")
xx, yy = np.meshgrid(x, y, indexing="ij")
phi = chF(uu, ww, mu, sigma)
expected = pdf(xx, yy, mu,sigma)
# Compute the inverse transform
result = inverseTransform(x, y, u, w, du, dw, phi, N)
# Plot results
_, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(xx, yy, result)
ax.plot_wireframe(xx, yy, expected, color="r", rstride=10, cstride=10)
# manually make legend for plot
col1_patch = mpatches.Patch(color="b", label="approximation")
col2_patch = mpatches.Patch(color="r", label="expected")
legends = [col1_patch, col2_patch]
ax.legend(handles=legends)
plt.show()
The resulting plot is given as:
bivariate normal approximation
The approximation is correct, however, misplaced on the grid. I thought this had something to do with the way the fft algorithm places the origin. However, trying different shifts from scipy.fft import fftshift, ifftshift only worsen the results.
Using different values for $\mu$ yielded results that were closer to the approximation or sometimes even further off.
How do I get the approximation result to coincide with the expected plot of the bivariate normal?
I want to "animate" a circle rolling over the sin graph, I made a code where the circle moves rapidly down a straight line, now I want the same but the acceleration will be changing.
My previous code:
import numpy as np
import matplotlib.pyplot as plt
theta = np.arange(0, np.pi * 2, (0.01 * np.pi))
x = np.arange(-50, 1, 1)
y = x - 7
plt.figure()
for t in np.arange(0, 4, 0.1):
plt.plot(x, y)
xc = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.cos(theta))
yc = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.sin(theta))
plt.plot(xc, yc, 'r')
xp = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.cos(np.pi * t))
yp = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.sin(np.pi * t))
plt.plot(xp, yp, 'bo')
plt.pause(0.01)
plt.cla()
plt.show()
You can do this by numerically integrating:
dt = 0.01
lst_x = []
lst_y = []
t = 0
while t < 10: #for instance
t += dt
a = get_acceleration(function, x)
x += v * dt + 0.5 * a * dt * dt
v += a * dt
y = get_position(fuction, x)
lst_x.append(x)
lst_y.append(y)
This is assuming the ball never leaves your slope! If it does, you'll also have to integrate in y in a similar way as done in x!!
Where your acceleration is going to be equal to g * cos(slope).
Right now, I am working on something (in Python) to create an ellipse and display it on the screen (in the console). I have the ellipse creation already, but rotating the ellipse gives me problems.
Ellipse Method:
def ellipse(yc, xc, b, a, rotation=0):
yc_min_b = yc - b
# divide b to account for spacing in console
b = int(round(b / 2 + 0.01)) - 1
yc = yc_min_b + b
points = []
a2 = a*a
b2 = b*b
fa2 = 4 * a2
fb2 = 4 * b2
x = 0
y = b
sigma = 2 * b2 + a2 * (1 - 2 * b)
while b2 * x <= a2 * y:
points.append((xc + x, yc + y))
points.append((xc - x, yc + y))
points.append((xc + x, yc - y))
points.append((xc - x, yc - y))
if sigma >= 0:
sigma += fa2 * (1 - y)
y -= 1
sigma += b2 * ((4 * x) + 6)
x += 1 # INCREMENT
x = a
y = 0
sigma = 2 * a2 + b2 * (1 - 2 * a)
while a2 * y <= b2 * x:
points.append((xc + x, yc + y))
points.append((xc - x, yc + y))
points.append((xc + x, yc - y))
points.append((xc - x, yc - y))
if sigma >= 0:
sigma += fb2 * (1 - x)
x -= 1
sigma += a2 * ((4 * y) + 6)
y += 1 # INCREMENT
# now rotate points
sin = math.sin(rotation)
cos = math.cos(rotation)
rotated = []
for point in points:
x = point[0]
y = point[1]
'''
px -= xc
py -= yc
xnew = px * c - py * s
ynew = px * s + py * c
px = xnew + xc
py = ynew + yc
'''
#XRot := Round(XCenter + (X - XCenter) * CAngle - (Y - YCenter) * SAngle);
#YRot := Round(YCenter + (X - XCenter) * SAngle + (Y - YCenter) * CAngle);
x = round(xc + (x + xc) * cos - (y - yc) * sin)
y = round(yc + (x - xc) * sin + (y - yc) * cos)
rotated.append((int(x), int(y)))
points = rotated
print points
ell_matr = []
# set up empty matrix
maxx = 0
maxy = 0
for point in points:
y = point[1]
x = point[0]
if y > maxy:
maxy = y
if x > maxx:
maxx = x
for i in range(maxy + 1):
ell_matr.append([])
for j in range(maxx + 1):
ell_matr[i].append(' ')
for point in points:
y = point[1]
x = point[0]
ell_matr[y][x] = fill
return ell_matr
I would ignore the matrix part, as it is translating the points into a matrix to display on screen.
Here is the output of an ellipse without rotation.
And when I add a 45 degree rotation (converted to radians)
Is there a better way to rotate the points?