def fit(data, guess_angles=None):
Xs, t = preprocess_data(data)  <EOL>start_points = [(<NUM_LIT:0>, <NUM_LIT:0>), (np.pi / <NUM_LIT:2>, <NUM_LIT:0>), (np.pi / <NUM_LIT:2>, np.pi / <NUM_LIT:2>)]<EOL>if guess_angles:<EOL><INDENT>start_points = guess_angles<EOL><DEDENT>best_fit = None<EOL>best_score = float('<STR_LIT>')<EOL>for sp in start_points:<EOL><INDENT>fitted = minimize(lambda x : G(direction(x[<NUM_LIT:0>], x[<NUM_LIT:1>]), Xs),<EOL>sp, method='<STR_LIT>', tol=<NUM_LIT>)<EOL>if fitted.fun < best_score:<EOL><INDENT>best_score = fitted.fun<EOL>best_fit = fitted<EOL><DEDENT><DEDENT>w = direction(best_fit.x[<NUM_LIT:0>], best_fit.x[<NUM_LIT:1>])<EOL>return w, C(w, Xs) + t, r(w, Xs), best_fit.fun<EOL>
Fit a list of data points to a cylinder surface. The algorithm implemented
    here is from David Eberly's paper "Fitting 3D Data with a Cylinder" from 
    https://www.geometrictools.com/Documentation/CylinderFitting.pdf

    Arguments:
        data - A list of 3D data points to be fitted.
        guess_angles[0] - Guess of the theta angle of the axis direction
        guess_angles[1] - Guess of the phi angle of the axis direction

    Return:
        Direction of the cylinder axis
        A point on the cylinder axis
        Radius of the cylinder
        Fitting error (G function)