# Curvature data to coordinates

I want to determine a path (x and y coordinates) by using curvature data (radius, with constant distance (length_of_arc) travelled between data points. I want to repeat this calculation every 0.010 seconds and visualize the points in pyhon kivy (at the moment a raw calculation takes 0.006 - 0.014 seconds).

Assume sample data

radius = [68.96551724, 69.73500697, 71.78750897, 75.98784195, 81.96721311, 90.74410163, 102.6694045, 120.0480192,
146.1988304, 187.9699248, 265.9574468, 458.7155963, 1694.915254, -1020.408163, -393.7007874, -244.4987775]


This is the code (inside a class) that I use to calculate the coordinates. Is there a way to increase performance / readability of the code. It is important to note that performance has higher priority.

EDIT: I already tried small angle approximation (sin x \approx x, cos x \approx 1 - 0.5 x^2) but that did only lead to insignificant changes.

# positive curvature is a right bend, negative curvature is a left bend
# scale_factor: used to scale the values for plotting them
# initial_displacement_x and initial_displacement_y: values are displaced such that the plot is in the Center of the screen.
@staticmethod
initial_displacement_x, initial_displacement_y):
phi = 0  # accumulation of angle
x_accumulated = number_of_data_points * 
y_accumulated = number_of_data_points * 
track_coordinates = 2 * number_of_data_points *  # x,y alternating needed for ploting values as line in python kivy

for data_point in range(number_of_data_points - 1):
delta_phi = - length_of_arc / _radius[data_point]
phi = phi + delta_phi
dx = - _radius[data_point] * (cos(delta_phi) - 1)
dy = - _radius[data_point] * sin(delta_phi)

if data_point != 0:
dx_rotated = cos(phi) * dx - sin(phi) * dy # apply rotation matrix
dy_rotated = sin(phi) * dx + cos(phi) * dy # apply rotation matrix
else:
dx_rotated = dx  # the displacements are not rotated
dy_rotated = dy  # for the first data point

x_accumulated[data_point + 1] = x_accumulated[data_point] + dx_rotated
y_accumulated[data_point + 1] = y_accumulated[data_point] + dy_rotated
track_coordinates[2 * data_point + 2] = scale_factor * (x_accumulated[data_point] + dx_rotated)
track_coordinates[2 * data_point + 3] = scale_factor * (y_accumulated[data_point] + dy_rotated)

for data_point in range(len(track_coordinates)):
if data_point % 2:
track_coordinates[data_point] = track_coordinates[data_point] + initial_displacement_x
elif not data_point % 2:
track_coordinates[data_point] = track_coordinates[data_point] + initial_displacement_y
return track_coordinates

• Which version of Python are you using? – Ludisposed Aug 21 '18 at 9:18
• @Ludisposed: I am using Python version 3.7.0 – MrYouMath Aug 21 '18 at 9:26
• @Graipher: You could use random.shuffle(array) from random and shuffle the array that I have given. Would that suffice? – MrYouMath Aug 21 '18 at 10:20
• Opps, did not see the example data...my bad – Graipher Aug 21 '18 at 10:22
• at the moment I am using length_of_arc = 1, scale_factor=4, initial_displacements are scalars, which are set to 350 and 690 at the moment. – MrYouMath Aug 21 '18 at 10:26

If you are doing a lot of numerical calculations in Python and want them to be fast, you should use numpy, a package specifically for this purpose.

It allows you to write your code in a vectorized way, making it easer to understand at the same time:

import numpy as np

@staticmethod
def arc_coordinates(_radius, length_of_arc, scale_factor, x0, y0):
"""
positive curvature is a right bend, negative curvature is a left bend
scale_factor: used to scale the values for plotting them
x0 and y0: values are displaced such that the plot is in the center of the screen.
"""
delta_phi = - length_of_arc / radius
phi = np.cumsum(delta_phi)
dx = - radius * (np.cos(delta_phi) - 1)
dy = - radius * np.sin(delta_phi)
track_coordinates = np.vstack([dx, dy]).T
track_coordinates[1:, 0] = np.cos(phi[1:]) * dx[1:] - np.sin(phi[1:]) * dy[1:]
track_coordinates[1:, 1] = np.sin(phi[1:]) * dx[1:] + np.cos(phi[1:]) * dy[1:]
track_coordinates = scale_factor * np.cumsum(track_coordinates, axis=0) + np.array([[y0, x0]])
track_coordinates = np.concatenate([np.array([y0, x0]), track_coordinates.flatten()[:-2]])
return track_coordinates


This gives the same results as your code. Note that it (just like your code) uses the weird convention that the output array is flat, alternating between x and y values, starting with a y-value.

On my machine this is not actually faster than your implementation, though:

%timeit arc_coordinates(radius, 1, 1, 0, 0)
39.4 µs ± 849 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

I also renamed your function to a (hopefully) also clear but shorter name as well as the initial displacements. I also made your comment detailing the parameters a docstring.
• @MrYouMath For me as well. Currently profiling to see where I can gain some speed. Your radius list might just be too short for this to help a lot, though. – Graipher Aug 21 '18 at 13:12