Skip to content
This repository has been archived by the owner on Sep 22, 2023. It is now read-only.

Fix & speed up max curvature calculation #115

Open
stklik opened this issue May 26, 2022 · 0 comments
Open

Fix & speed up max curvature calculation #115

stklik opened this issue May 26, 2022 · 0 comments

Comments

@stklik
Copy link

stklik commented May 26, 2022

The current curvature calculation is slow and relies on interation over a Python list. It also drops the last curvature value (due to a strange treatment of w in the range(len(nodes) - w).

The following code produces the same results (except for a handful of floating point issues in the 17th post-comma digit), but uses numpy instead of individual values.
As you can see, structurally, the code still resembles the original (see _fast_define_circle), but is based on numpy array.

def _fast_define_circle(p1, p2, p3):
    """
    Returns the center and radius of the circle passing the given 3 points.
    In case the 3 points form a line, returns (None, infinity).
    """
    p1_0 = p1[:,0]
    p1_1 = p1[:,1]
    p2_0 = p2[:,0]
    p2_1 = p2[:,1]
    p3_0 = p3[:,0]
    p3_1 = p3[:,1]
    
    temp = p2_0 * p2_0 + p2_1 * p2_1
    bc = (p1_0 * p1_0 + p1_1 * p1_1 - temp) / 2
    cd = (temp - p3_0 * p3_0 - p3_1 * p3_1) / 2
    det = (p1_0 - p2_0) * (p2_1 - p3_1) - (p2_0 - p3_0) * (p1_1 - p2_1)
    
    radius = np.full(temp.shape, np.inf)
    det_fltr = np.abs(det) > 1.0e-6

    # Center of circle
    cx = (bc*(p2_1 - p3_1) - cd*(p1_1 - p2_1))[det_fltr] / det[det_fltr]
    cy = ((p1_0 - p2_0) * cd - (p2_0 - p3_0) * bc)[det_fltr] / det[det_fltr]

    radius[det_fltr] = np.sqrt((cx - p1_0[det_fltr])**2 + (cy - p1_1[det_fltr])**2)
        
    return radius

def fast_max_curvature(the_test, w=5, ORIGINAL_BEHAVIOUR=False):
    if not isinstance(the_test, list):
        nodes = the_test.interpolated_points
    else:
        nodes = the_test
    min_radius = np.inf
    
    np_nodes = np.array(nodes)
    # print(np_nodes)
    
    p1 = np_nodes[:-(w-1)]
    step = int((w-1) / 2)
    p2 = np_nodes[step:-step]
    p3 = np_nodes[w-1:]

    assert len(p1) == len(p2) == len(p3)
    
    radii = _fast_define_circle(p1, p2, p3)

    if ORIGINAL_BEHAVIOUR:   # NOTE: original code for some reason does not consider the last curvature value... it's strange! (I guess it's an maybe off-by-one error?) 
        curvature = 1 / radii[:-1].min()     
        return curvature
    else:  # fixed behaviour
        curvature = 1 / radii.min()     
        return curvature

NOTE the parameter ORIGINAL_BEHAVIOUR should eventually be dropped and the fixed behaviour adopted. It's currently here to prove that the results are the same.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant