def circle_segment(theta, r=1, center=(0, 0, 0), normal=(0, 0, 1), xaxis=(1, 0, 0)): """ Create a circle segment starting parallel to the rotated x-axis. :param float theta: Angle in radians :param float r: Radius :param array-like center: circle segment center :param array-like normal: normal vector to the plane that contains circle :param array-like xaxis: direction of the parametric start point t=0 :return: A quadratic rational curve :rtype: Curve :raises ValueError: If radius is not positive :raises ValueError: If theta is not in the range *[-2pi, 2pi]* """ # error test input if abs(theta) > 2 * pi: raise ValueError('theta needs to be in range [-2pi,2pi]') if r <= 0: raise ValueError('radius needs to be positive') if theta == 2 * pi: return circle(r, center, normal) # build knot vector knot_spans = int(ceil(abs(theta) / (2 * pi / 3))) knot = [0] for i in range(knot_spans + 1): knot += [i] * 2 knot += [knot_spans] # knot vector [0,0,0,1,1,2,2,..,n,n,n] knot = np.array(knot) / float( knot[-1]) * theta # set parametric space to [0,theta] n = (knot_spans - 1) * 2 + 3 # number of control points needed cp = [] t = 0 # current angle dt = float(theta) / knot_spans / 2 # angle step # build control points for i in range(n): w = 1 - (i % 2) * (1 - cos(dt) ) # weights = 1 and cos(dt) every other i x = r * cos(t) y = r * sin(t) cp += [[x, y, w]] t += dt if theta < 0: cp.reverse() result = Curve(BSplineBasis(3, np.flip(knot, 0)), cp, True) else: result = Curve(BSplineBasis(3, knot), cp, True) result.rotate(rotate_local_x_axis(xaxis, normal)) return flip_and_move_plane_geometry(result, center, normal)
def circle(r=1, center=(0,0,0), normal=(0,0,1), type='p2C0', xaxis=(1,0,0)): """ Create a circle. :param float r: Radius :param array-like center: local origin :param array-like normal: local normal :param string type: The type of parametrization ('p2C0' or 'p4C1') :param array-like xaxis: direction of sem, i.e. parametric start point t=0 :return: A periodic, quadratic rational curve :rtype: Curve :raises ValueError: If radius is not positive """ if r <= 0: raise ValueError('radius needs to be positive') if type == 'p2C0' or type == 'C0p2': w = 1.0 / sqrt(2) controlpoints = [[1, 0, 1], [w, w, w], [0, 1, 1], [-w, w, w], [-1, 0, 1], [-w, -w, w], [0, -1, 1], [w, -w, w]] knot = np.array([-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5]) / 4.0 * 2 * pi result = Curve(BSplineBasis(3, knot, 0), controlpoints, True) elif type.lower() == 'p4c1' or type.lower() == 'c1p4': w = 2*sqrt(2)/3 a = 1.0/2/sqrt(2) b = 1.0/6 * (4*sqrt(2)-1) controlpoints = [[ 1,-a, 1], [ 1, a, 1], [ b, b, w], [ a, 1, 1], [-a, 1, 1], [-b, b, w], [-1, a, 1], [-1,-a, 1], [-b,-b, w], [-a,-1, 1], [ a,-1, 1], [ b,-b, w]] knot = np.array([ -1, -1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5]) / 4.0 * 2 * pi result = Curve(BSplineBasis(5, knot, 1), controlpoints, True) else: raise ValueError('Unkown type: %s' %(type)) result *= r result.rotate(rotate_local_x_axis(xaxis, normal)) return flip_and_move_plane_geometry(result, center, normal)