Last active
February 9, 2017 16:48
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This code was used to create the answer | |
# http://tex.stackexchange.com/a/352766/12571 | |
from scipy.optimize import fsolve | |
from math import * | |
import numpy as np | |
def ellipse(a,b,t): | |
return (a*cos(t), b*sin(t)) | |
def distance(p1,p2): | |
return sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2) | |
def generate_equations(n, a, b, x_0=0): | |
"""Generates a function suitable to be solved by scipy.optimize.fsolve | |
This functions creates the set of equations to solve to place n | |
points in the edge of an ellipse of radii (a,b), so that all points | |
are equi-distant. x_0 is the angle for the first point""" | |
result = [] | |
result.append("def equations(p):") | |
result.append(" {unknowns} = p" | |
.format(unknowns = ",".join("x_{i}".format(i=i) for i in range(n+1))) | |
) | |
distance_equations = [] | |
for i in range(n): | |
next_i = (i+1) % n | |
distance_to_next = "distance(ellipse(a,b,x_{i}), ellipse(a,b,x_{next_i}))"\ | |
.format(a=a, b=b, i=i, next_i=next_i) | |
distance_equations.append(distance_to_next) | |
for i in range(n-1): | |
next_i = (i+1) % n | |
result.append(" f_{i} = {eq_i} - {eq_i_next}" | |
.format(i=i, eq_i=distance_equations[i], | |
eq_i_next = distance_equations[next_i]) | |
) | |
result.append(" f_{i} = x_0 - {x_0}" | |
.format(i=n-1, x_0=x_0)) | |
result.append(" f_{i} = {any_distance} - x_{n}" | |
.format(i=n, any_distance = distance_equations[-1], n=n)) | |
result.append(" return({equations})" | |
.format(equations = ",".join("f_{i}".format(i=i) for i in range(n+1))) | |
) | |
return "\n".join(result) | |
def generate_equations_old(n, a, b, t_0=0): | |
"""Generates a function suitable to be solved by scipy.optimize.fsolve | |
This functions creates the set of equations to solve to place n | |
points in the edge of an ellipse of diameter (a,b), so that all points | |
are equi-distant. t_0 is the angle for the first point""" | |
result = [] | |
result.append("from math import *") | |
result.append("def equations(p):") | |
result.append(" {unknowns} = p" | |
.format(unknowns = ",".join("t_{i}".format(i=i) for i in range(n+1))) | |
) | |
distance_equations = [] | |
for i in range(n): | |
next_i = (i+1) % n | |
distance_to_next = "sqrt(({a}*cos(t_{i}) - {a}*cos(t_{next_i}))**2 "\ | |
"+ ({b}*sin(t_{i}) - {b}*sin(t_{next_i}))**2)"\ | |
.format(a=a, b=b, i=i, next_i=next_i) | |
distance_equations.append(distance_to_next) | |
for i in range(n-1): | |
next_i = (i+1) % n | |
result.append(" f_{i} = {eq_i} - {eq_i_next}" | |
.format(i=i, eq_i=distance_equations[i], | |
eq_i_next = distance_equations[next_i]) | |
) | |
result.append(" f_{i} = t_0 - {t_0}" | |
.format(i=n-1, t_0=t_0)) | |
result.append(" f_{i} = {any_distance} - t_{n}" | |
.format(i=n, any_distance = distance_equations[0], n=n)) | |
result.append(" return({equations})" | |
.format(equations = ",".join("f_{i}".format(i=i) for i in range(n+1))) | |
) | |
return "\n".join(result) | |
def generate_tikz_list(r): | |
return ",".join(["%f/%f" % (ellipse(a,b,x)) for x in r]) | |
def print_tikzpicture(a,b,n,l): | |
print(r""" | |
\begin{tikzpicture} | |
\fill[white] (-3.5, -1.5) rectangle (3.5, 1.5); | |
\draw[blue] (0,0) ellipse(%d and %d); | |
\foreach \x/\y [count=\n from 0] in {%s} { | |
\node[fill=blue,circle] (node-\n) at (\x,\y) {}; | |
} | |
\foreach \n [remember=\n as \previous (initially 0)] in {1,...,%d} { | |
\draw[thick,red] (node-\previous.center) -- (node-\n.center); | |
} | |
\node[fill=yellow, circle] at (node-0) {}; | |
\draw[thick,red] (node-%d.center) -- (node-0.center); | |
\end{tikzpicture} | |
""" % (a, b, l, n-1, n-1)) | |
import sys | |
from math import * | |
# Parameters for the ellipse | |
a = 3 | |
b = 1 | |
n = 7 # Number of nodes | |
for angle in range(0,360,2): | |
# Generate the code which defines the equations | |
eqs = generate_equations(n,a,b,radians(angle)) | |
# Execute that code to define function "equations" | |
exec(eqs) | |
# Use simpy to solve the equations | |
print("angle=", angle, file=sys.stderr) | |
r = fsolve(equations, np.append(np.linspace(radians(angle), radians(angle)+ 2*pi, n, endpoint=False), [2*a])) | |
# Convert the solution to tikz syntax | |
tikz_points = generate_tikz_list(r[:-1]) | |
print_tikzpicture(a,b,n,tikz_points) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment