コード例 #1
0
def generate_trig(args):
    max_t = args.end_t
    min_t = args.start_t

    def time_t(time_step):
        return min_t + (max_t - min_t) * time_step / args.num_time_steps

    def x_t(time_step):
        t = time_t(time_step)
        return args.scale * (t + math.sin(t)**args.power)

    def y_t(time_step):
        t = time_t(time_step)
        return args.scale * args.y_coeff * math.sin(t)

    r_t = marble_path.numerical_rotation_function(x_t, y_t)

    if args.kink_replace_circle:
        x_t, y_t, r_t = combine_functions.replace_kinks_with_circles(
            args=args,
            time_t=time_t,
            x_t=x_t,
            y_t=y_t,
            r_t=r_t,
            kink_args=args,
            num_time_steps=args.num_time_steps)

    slope_angle_t = slope_function.slope_function(
        x_t=x_t,
        y_t=y_t,
        time_t=time_t,
        slope_angle=args.slope_angle,
        num_time_steps=args.num_time_steps,
        overlap_args=None,
        kink_args=args)

    z_t = marble_path.arclength_height_function(x_t,
                                                y_t,
                                                args.num_time_steps,
                                                slope_angle_t=slope_angle_t)

    print("Start x, y, z: %.4f %.4f %.4f" % (x_t(0), y_t(0), z_t(0)))
    print("End x, y, z:   %.4f %.4f %.4f" %
          (x_t(args.num_time_steps), y_t(
              args.num_time_steps), z_t(args.num_time_steps)))

    for triangle in marble_path.generate_path(
            x_t=x_t,
            y_t=y_t,
            z_t=z_t,
            r_t=r_t,
            tube_args=args,
            num_time_steps=args.num_time_steps,
            time_t=time_t,
            slope_angle_t=slope_angle_t):
        yield triangle
コード例 #2
0
def generate_limacon(args):
    # the domain of the limacon will be -domain_size to +domain_size
    domain_size = args.domain_size
    min_time = -domain_size
    time_step_width = (domain_size * 2) / (args.time_steps)

    def theta_t(time_step):
        return min_time + time_step_width * time_step
        
    def x_t(time_step):
        theta = theta_t(time_step)
        r = args.constant_factor - args.cosine_factor * math.cos(theta)
        return math.cos(theta) * r

    def y_t(time_step):
        theta = theta_t(time_step)
        r = args.constant_factor - args.cosine_factor * math.cos(theta)
        return math.sin(theta) * r

    min_y = min(y_t(y) for y in range(0, args.time_steps+1))
    max_y = max(y_t(y) for y in range(0, args.time_steps+1))
    y_scale = args.length / (max_y - min_y)

    min_x = min(x_t(x) for x in range(0, args.time_steps+1))
    max_x = max(x_t(x) for x in range(0, args.time_steps+1))
    if args.width is None:
        x_scale = y_scale
    else:
        x_scale = args.width / (max_x - min_x)

    def scaled_x_t(time_step):
        return (x_t(time_step) - min_x) * x_scale
    
    def scaled_y_t(time_step):
        return (y_t(time_step) - min_y) * y_scale

    z_t = marble_path.arclength_height_function(scaled_x_t, scaled_y_t, args.time_steps, args.slope_angle)

    def r_t(time_step):
        theta = theta_t(time_step)
        return get_normal_rotation(theta, x_scale, y_scale, args.constant_factor, args.cosine_factor)

    print("Center of tube at time step 0: ", scaled_x_t(0), scaled_y_t(0))
    print("Angle of tube: ", r_t(0))

    for triangle in marble_path.generate_path(x_t=scaled_x_t, y_t=scaled_y_t, z_t=z_t, r_t=r_t,
                                              tube_args=args,
                                              num_time_steps=args.time_steps):
        yield triangle    
コード例 #3
0
def generate_helix(args):
    """
    helix_radius is the measurement from the axis to the center of any part of the ramp
    tube_radius is the measurement from the center of ramp to its outer wall
    wall_thickness is how thick to make the wall
      special case: if wall_thickness >= tube_radius, there is no inner opening
    tube_start_angle and tube_end_angle represent which part of the ramp to draw.
      0 represents the part furthest from the axis
      180 represents the part closest to the axis
      0..180 covers the bottom of the arc.  for the top, for example, do 180..0
      special case: if 0..360 or any rotation of that is supplied, the entire circle is drawn
    tube_sides is how many sides a complete tube would have.
      tube_start_angle and tube_end_angle are discretized to these subdivisions
    helix_sides is how many sides a complete helix rotation has
    vertical_displacement is how far to move up in one complete rotation
      tube_radius*2 means the next layer will be barely touching the previous layer
    rotations is how far around to go.  will be discretized using helix_sides
    """
    num_helix_subdivisions = math.ceil(args.rotations * args.helix_sides)
    print("Num helix: {}".format(num_helix_subdivisions))
    if num_helix_subdivisions <= 0:
        raise ValueError("Must complete some positive fraction of a rotation")

    x_t = helix_x_t(args)
    y_t = helix_y_t(args)
    r_t = helix_r_t(args)

    def z_t(helix_subdivision):
        # tube_radius included again to keep everything positive
        # negative sign in slope is on account of the decision that positive slope means down
        return args.tube_radius - math.sin(
            args.slope_angle / 180 * math.pi
        ) * 2 * math.pi * args.helix_radius * helix_subdivision / args.helix_sides

    for triangle in marble_path.generate_path(
            x_t=x_t,
            y_t=y_t,
            z_t=z_t,
            r_t=r_t,
            tube_args=args,
            num_time_steps=num_helix_subdivisions):
        yield triangle
コード例 #4
0
def generate_zigzag(args):
    num_time_steps = args.subdivisions_per_zigzag * args.num_zigzags
    y_delta = args.zigzag_length / args.subdivisions_per_zigzag * 2

    def x_t(time_step):
        return time_step * args.zigzag_width / args.subdivisions_per_zigzag

    def y_t(time_step):
        time_step = time_step % args.subdivisions_per_zigzag
        if time_step < args.subdivisions_per_zigzag / 2:
            return time_step * y_delta
        else:
            return args.zigzag_length - (
                time_step - args.subdivisions_per_zigzag / 2) * y_delta

    # overkill - we could easily calculate it ourselves
    z_t = marble_path.arclength_height_function(x_t, y_t, num_time_steps,
                                                args.slope_angle)

    def r_t(time_step):
        # west to east is represented by -90, since south to north is 0
        return -90

    build_shape.print_stats(x_t=x_t,
                            y_t=y_t,
                            z_t=z_t,
                            r_t=r_t,
                            num_time_steps=num_time_steps)
    tangent = math.atan(args.zigzag_length / (args.zigzag_width / 2))
    print("Rotation of the zigzag: %.4f / %.4f degrees" %
          (tangent, tangent * 180 / math.pi))

    for triangle in marble_path.generate_path(x_t=x_t,
                                              y_t=y_t,
                                              z_t=z_t,
                                              r_t=r_t,
                                              tube_args=args,
                                              num_time_steps=num_time_steps):
        yield triangle
コード例 #5
0
def generate_astroid(args):
    # there are 4 corners in the astroid
    # we want to chop off those corners and replace them with approximated circles
    # to do this, we first calculate where the corners occur
    # this happens when the tube on one side of the corner touches the tube on the other
    # we will need to keep in mind the angle of the tube at that point
    if args.cusp_method is Cusp.CHOP:
        corner_t, corner_rotation = find_corner(args.outer_radius, args.tube_radius, args.astroid_power)
        x_offset = y_offset = 0
    elif args.cusp_method is Cusp.OFFSET:
        corner_t = 0.0
        corner_rotation = 90.0
        x_offset = y_offset = args.tube_radius
    else:
        raise ValueError('Not supported: %s' % args.cusp_method)

    num_time_steps = args.subdivisions_per_side * 12   # the extra factor of 3 is for the rounded corners

    #for i in range(num_time_steps):
    #    print(i,
    #          astroid_step(args.outer_radius, corner_t, corner_rotation, args.astroid_power, i, args.subdivisions_per_side),
    #          tube_angle(args.outer_radius, corner_t, corner_rotation, args.astroid_power, i, args.subdivisions_per_side))

    # start at 45 degrees so we can connect easily to the post in the middle
    time_step_offset = int(args.subdivisions_per_side * 1.5)

    # TODO: might be nice to make a combined x_y_t that saves on these calculations
    def x_t(time_step):
        return astroid_step(outer_radius=args.outer_radius,
                            cusp_method=args.cusp_method,
                            tube_radius=args.tube_radius,
                            corner_t=corner_t,
                            corner_rotation=corner_rotation,
                            astroid_power=args.astroid_power,
                            time_step=time_step + time_step_offset,
                            subdivisions_per_side=args.subdivisions_per_side)[0]
    
    def y_t(time_step):
        return astroid_step(outer_radius=args.outer_radius,
                            cusp_method=args.cusp_method,
                            tube_radius=args.tube_radius,
                            corner_t=corner_t,
                            corner_rotation=corner_rotation,
                            astroid_power=args.astroid_power,
                            time_step=time_step + time_step_offset,
                            subdivisions_per_side=args.subdivisions_per_side)[1]

    z_t = marble_path.arclength_height_function(x_t, y_t, num_time_steps, args.slope_angle)

    def r_t(time_step):
        return tube_angle(outer_radius=args.outer_radius,
                          cusp_method=args.cusp_method,
                          corner_t=corner_t,
                          corner_rotation=corner_rotation,
                          astroid_power=args.astroid_power,
                          time_step=time_step + time_step_offset,
                          subdivisions_per_side=args.subdivisions_per_side)

    for triangle in marble_path.generate_path(x_t=x_t, y_t=y_t, z_t=z_t, r_t=r_t,
                                              tube_args=args,
                                              num_time_steps=num_time_steps):
        yield triangle
コード例 #6
0
def generate_shape(module, args):
    module.describe_curve(args)

    if getattr(module, 'build_time_t', None) is not None:
        time_t = module.build_time_t(args)
    else:
        time_t = lambda t: t

    if getattr(module, 'build_x_y_r_t', None) is not None:
        x_t, y_t, r_t = module.build_x_y_r_t(args)
    elif getattr(module, 'build_x_y_t', None) is not None:
        x_t, y_t = module.build_x_y_t(args)
        r_t = marble_path.numerical_rotation_function(x_t, y_t)
    else:
        x_t = module.build_x_t(args)
        y_t = module.build_y_t(args)
        r_t = marble_path.numerical_rotation_function(x_t, y_t)

    num_time_steps = args.num_time_steps

    # TODO: because the circle replacement does not keep the endpoints
    # the same, this will disrupt any attempt to set a scale such as
    # in generate_hypotrochoid's closest_approach.  For now, those
    # arguments are incompatible
    if getattr(args, 'kink_replace_circle', None):
        x_t, y_t, r_t = combine_functions.replace_kinks_with_circles(
            args=args,
            time_t=time_t,
            x_t=x_t,
            y_t=y_t,
            r_t=r_t,
            kink_args=args,
            num_time_steps=num_time_steps)

    slope_angle_t = slope_function.slope_function(
        x_t=x_t,
        y_t=y_t,
        time_t=time_t,
        slope_angle=args.slope_angle,
        num_time_steps=num_time_steps,
        overlap_args=args,
        kink_args=args)

    if getattr(args, 'zero_circle', None):
        updated_functions = combine_functions.add_both_zero_circles(
            args=args,
            num_time_steps=num_time_steps,
            x_t=x_t,
            y_t=y_t,
            slope_angle_t=slope_angle_t,
            r_t=r_t)
        num_time_steps, x_t, y_t, slope_angle_t, r_t = updated_functions

    z_t = marble_path.arclength_height_function(x_t,
                                                y_t,
                                                num_time_steps,
                                                slope_angle_t=slope_angle_t)

    print_stats(x_t, y_t, z_t, r_t, num_time_steps)

    for triangle in marble_path.generate_path(x_t=x_t,
                                              y_t=y_t,
                                              z_t=z_t,
                                              r_t=r_t,
                                              tube_args=args,
                                              num_time_steps=num_time_steps,
                                              time_t=time_t,
                                              slope_angle_t=slope_angle_t):
        yield triangle