Example #1
0
def schwarzD(size: Tuple[int, int, int] = (15, 15, 15),
             scale: int = 15,
             coords: Tuple[int, int, int] = (0, 0, 0),
             material1: int = 1,
             material2: int = 2,
             resolution: float = 1):
    """
    Generate a Schwarz D-surface over a rectangular region.

    This function will generate two models representing the "positive" and
    "negative" halves of the pattern. If a thin surface is desired,
    these two models can be dilated and the intersection of the results found.
    However, due to the voxel-based representation, this "surface" will have
    a non-zero thickness.

    Args:
        size: Size of rectangular region
        scale: Period of the surface function in voxels
        coords: Model origin coordinates
        material1: Material index for negative model, corresponds to materials.py
        material2: Material index for positive model, corresponds to materials.py
        resolution: Number of voxels per mm
    
    Returns:
        Negative model, Positive model
    """
    s = (2 * math.pi) / scale  # scaling multipler

    modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16)
    surface_model_inner = VoxelModel(modelData,
                                     generateMaterials(material1),
                                     coords=coords,
                                     resolution=resolution)
    surface_model_outer = VoxelModel(modelData,
                                     generateMaterials(material2),
                                     coords=coords,
                                     resolution=resolution)

    for x in tqdm(range(size[0]), desc='Generating Gyroid'):
        for y in range(size[1]):
            for z in range(size[2]):
                t_calc = math.sin(x * s) * math.sin(y * s) * math.sin(z * s)
                t_calc = math.sin(x * s) * math.cos(y * s) * math.cos(
                    z * s) + t_calc
                t_calc = math.cos(x * s) * math.sin(y * s) * math.cos(
                    z * s) + t_calc
                t_calc = math.cos(x * s) * math.cos(y * s) * math.sin(
                    z * s) + t_calc

                if t_calc < 0:
                    surface_model_inner.voxels[x, y, z] = 1
                else:
                    surface_model_outer.voxels[x, y, z] = 1

    return surface_model_inner, surface_model_outer
Example #2
0
def sphere(radius: int = 1,
           coords: Tuple[int, int, int] = (0, 0, 0),
           material: int = 1,
           resolution: float = 1):
    """
    Create a VoxelModel containing a sphere.

    :param radius: Radius of sphere in voxels
    :param coords: Model origin coordinates
    :param material: Material index corresponding to materials.py
    :param resolution: Number of voxels per mm
    :return: VoxelModel
    """
    diameter = (radius * 2) + 1
    model_data = np.zeros((diameter, diameter, diameter), dtype=np.uint16)

    for x in range(diameter):
        for y in range(diameter):
            for z in range(diameter):
                xd = (x - radius)
                yd = (y - radius)
                zd = (z - radius)
                r = np.sqrt(xd**2 + yd**2 + zd**2)

                if r < (radius + .5):
                    model_data[x, y, z] = 1

    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=(coords[0] - radius, coords[1] - radius,
                               coords[2] - radius),
                       resolution=resolution)
    return model
Example #3
0
def pyramid(min_radius: int = 0,
            max_radius: int = 4,
            height: int = 5,
            coords: Tuple[int, int, int] = (0, 0, 0),
            material: int = 1,
            resolution: float = 1):
    """
    Create a VoxelModel containing a cylinder.

    :param min_radius: Point radius of pyramid in voxels
    :param max_radius: Base radius of pyramid in voxels
    :param height: Height of pyramid in voxels
    :param coords: Model origin coordinates
    :param material: Material index corresponding to materials.py
    :param resolution: Number of voxels per mm
    :return: VoxelModel
    """
    max_diameter = (max_radius * 2) + 1
    model_data = np.zeros((max_diameter, max_diameter, height),
                          dtype=np.uint16)

    for z in range(height):
        radius = round((abs(max_radius - min_radius) * (z / (height - 1))))

        if radius == 0:
            model_data[:, :, z].fill(1)
        else:
            model_data[radius:-radius, radius:-radius, z].fill(1)

    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=(coords[0] - max_radius, coords[1] - max_radius,
                               coords[2]),
                       resolution=resolution)
    return model
Example #4
0
def empty(coords: Tuple[int, int, int] = (0, 0, 0), resolution: float = 1):
    """
    Create a VoxelModel containing a single empty voxel at the specified coordinates.

    :param coords: Model origin coordinates
    :param resolution: Number of voxels per mm
    :return: VoxelModel
    """
    model_data = np.zeros((1, 1, 1), dtype=np.uint16)
    materials = np.zeros((1, len(material_properties) + 1), dtype=np.float)
    model = VoxelModel(model_data,
                       materials,
                       coords=coords,
                       resolution=resolution)
    return model
Example #5
0
def ellipsoid(size: Tuple[int, int, int],
              coords: Tuple[int, int, int] = (0, 0, 0),
              material: int = 1,
              resolution: float = 1):
    """
    Create a VoxelModel containing an ellipsoid.

    Args:
        size: Lengths of ellipsoid principal semi-axes in voxels
        coords: Model origin coordinates
        material: Material index corresponding to materials.py
        resolution: Number of voxels per mm

    Returns:
        VoxelModel
    """
    # lengths of principal semi-axes
    a, b, c = size

    # bounding box size (+1 ensures there is a voxel centered on the origin)
    dx = (a * 2) + 1
    dy = (b * 2) + 1
    dz = (c * 2) + 1
    model_data = np.zeros((dx, dy, dz), dtype=np.uint16)

    # check each voxel in the bounding box and determine if it falls inside the ellipsoid
    for x in range(dx):
        for y in range(dy):
            for z in range(dz):
                # get coords relative to origin
                xx = (x - a)
                yy = (y - b)
                zz = (z - c)

                # apply ellipsoid formula
                f = np.sqrt(((xx**2) / (a**2)) + ((yy**2) / (b**2)) +
                            ((zz**2) / (c**2)))
                if f < 1:
                    model_data[x, y, z] = 1

    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=(coords[0] - a, coords[1] - b, coords[2] - c),
                       resolution=resolution)
    return model
Example #6
0
def cuboid(size: Tuple[int, int, int] = (1, 1, 1),
           coords: Tuple[int, int, int] = (0, 0, 0),
           material: int = 1,
           resolution: float = 1):
    """
    Create a VoxelModel containing a cuboid.

    :param size: Lengths of cuboid sides in voxels
    :param coords: Model origin coordinates
    :param material: Material index corresponding to materials.py
    :param resolution: Number of voxels per mm
    :return: VoxelModel
    """
    model_data = np.ones((size[0], size[1], size[2]), dtype=np.uint16)
    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=coords,
                       resolution=resolution)
    return model
Example #7
0
def cone(min_radius: int,
         max_radius: int,
         height: int,
         coords: Tuple[int, int, int] = (0, 0, 0),
         material: int = 1,
         resolution: float = 1):
    """
    Create a VoxelModel containing a cylinder.

    Args:
        min_radius: Point radius of cone in voxels
        max_radius: Base radius of cone in voxels
        height: Height of cone in voxels
        coords: Model origin coordinates
        material: Material index corresponding to materials.py
        resolution: Number of voxels per mm
    
    Returns:
        VoxelModel
    """
    max_diameter = (max_radius * 2) + 1
    model_data = np.zeros((max_diameter, max_diameter, height),
                          dtype=np.uint16)

    for z in range(height):
        radius = (abs(max_radius - min_radius) * (((height - 1) - z) /
                                                  (height - 1))) + min_radius

        for x in range(max_diameter):
            for y in range(max_diameter):
                xd = (x - max_radius)
                yd = (y - max_radius)
                r = np.sqrt(xd**2 + yd**2)

                if r < (radius + .5):
                    model_data[x, y, z] = 1

    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=(coords[0] - max_radius, coords[1] - max_radius,
                               coords[2]),
                       resolution=resolution)
    return model
Example #8
0
def toIndexedMaterials(voxels, model):
    x_len = model.voxels.shape[0]
    y_len = model.voxels.shape[1]
    z_len = model.voxels.shape[2]

    new_voxels = np.zeros((x_len, y_len, z_len), dtype=np.int32)
    new_materials = np.zeros((1, len(material_properties) + 1),
                             dtype=np.float32)

    for x in range(x_len):
        for y in range(y_len):
            for z in range(z_len):
                m = voxels[x, y, z, :]
                i = np.where(np.equal(new_materials, m).all(1))[0]

                if len(i) > 0:
                    new_voxels[x, y, z] = i[0]
                else:
                    new_materials = np.vstack((new_materials, m))
                    new_voxels[x, y, z] = len(new_materials) - 1

    return VoxelModel(new_voxels, new_materials, model.coords)
Example #9
0
def cube(size: int,
         coords: Tuple[int, int, int] = (0, 0, 0),
         material: int = 1,
         resolution: float = 1):
    """
    Create a VoxelModel containing a cube.

    Args:
        size: Length of cube side in voxels
        coords: Model origin coordinates
        material: Material index corresponding to materials.py
        resolution: Number of voxels per mm
    
    Returns:
        VoxelModel
    """
    model_data = np.ones((size, size, size), dtype=np.uint16)
    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=coords,
                       resolution=resolution)
    return model
Example #10
0
def cylinder(radius: int,
             height: int,
             coords: Tuple[int, int, int] = (0, 0, 0),
             material: int = 1,
             resolution: float = 1):
    """
    Create a VoxelModel containing a cylinder.

    Args:
        radius: Radius of cylinder in voxels
        height: Height of cylinder in voxels
        coords: Model origin coordinates
        material: Material index corresponding to materials.py
        resolution: Number of voxels per mm
    
    Returns:
        VoxelModel
    """
    diameter = (radius * 2) + 1
    model_data = np.zeros((diameter, diameter, 1), dtype=np.uint16)

    for x in range(diameter):
        for y in range(diameter):
            xd = (x - radius)
            yd = (y - radius)
            r = np.sqrt(xd**2 + yd**2)

            if r < (radius + .5):
                model_data[x, y, 0] = 1

    model_data = np.repeat(model_data, height, 2)

    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=(coords[0] - radius, coords[1] - radius,
                               coords[2]),
                       resolution=resolution)
    return model
Example #11
0
def prism(size: Tuple[int, int, int],
          point_offset: int = 0,
          coords: Tuple[int, int, int] = (0, 0, 0),
          material: int = 1,
          resolution: float = 1):
    """
    Create a VoxelModel containing a prism.

    Args:
        size: Size of prism in voxels (base,
        point_offset: Distance that prism point is offset from model center in voxels
        coords: Model origin coordinates
        material: Material index corresponding to materials.py
        resolution: Number of voxels per mm

    Returns:
        VoxelModel
    """
    point_pos = (size[0] / 2) + point_offset
    min_x = min(0, round(point_pos))
    max_x = max(size[0], round(point_pos))
    dx = max_x - min_x
    model_data = np.zeros((dx, size[1], size[2]), dtype=np.uint16)

    for z in range(size[2]):
        width = (size[0] / size[2]) * (size[2] - z)
        side_1_index = round((point_pos / size[2]) * z) - min_x
        side_2_index = round((point_pos / size[2]) * z + width) - min_x

        model_data[side_1_index:side_2_index, :, z].fill(1)

    model = VoxelModel(model_data,
                       generateMaterials(material),
                       coords=(coords[0] + min_x, coords[1], coords[2]),
                       resolution=resolution)
    return model
def thin(model, max_iter):
    x_len = model.voxels.shape[0] + 4
    y_len = model.voxels.shape[1] + 4
    z_len = model.voxels.shape[2] + 4

    struct = ndimage.generate_binary_structure(3, 3)

    sphere = np.zeros((5, 5, 5), dtype=np.int32)
    for x in range(5):
        for y in range(5):
            for z in range(5):
                xd = (x - 2)
                yd = (y - 2)
                zd = (z - 2)
                r = np.sqrt(xd ** 2 + yd ** 2 + zd ** 2)

                if r < 2.5:
                    sphere[x, y, z] = 1

    input_model = VoxelModel(np.zeros((x_len, y_len, z_len), dtype=np.int32), model.materials, model.coords)
    input_model.voxels[2:-2, 2:-2, 2:-2] = model.voxels
    new_model = VoxelModel.emptyLike(input_model)

    for i in tqdm(range(max_iter), desc='Thinning'):
        # Find exterior voxels
        interior_voxels = input_model.erode(radius=1, plane=Axes.XYZ, structType=Struct.STANDARD, connectivity=1)
        exterior_voxels = input_model.difference(interior_voxels)

        x_len = len(exterior_voxels.voxels[:, 0, 0])
        y_len = len(exterior_voxels.voxels[0, :, 0])
        z_len = len(exterior_voxels.voxels[0, 0, :])

        # Create list of exterior voxel coordinates
        exterior_coords = []
        for x in range(x_len):
            for y in range(y_len):
                for z in range(z_len):
                    if exterior_voxels.voxels[x, y, z] != 0:
                        exterior_coords.append([x, y, z])

        # Store voxels that must be part of the center line
        for coords in exterior_coords:
            x = coords[0]
            y = coords[1]
            z = coords[2]

            if input_model.voxels[x,y,z] != 0:
                # Get matrix of neighbors
                n = np.copy(input_model.voxels[x - 2:x + 3, y - 2:y + 3, z - 2:z + 3])
                n[n != 0] = 1

                # Find V - number of voxels near current along xyz axes
                Vx = np.sum(n[:, 2, 2])
                Vy = np.sum(n[2, :, 2])
                Vz = np.sum(n[2, 2, :])

                # Subtract sphere
                n = n - sphere
                n[n < 1] = 0

                # Check if subtraction split model
                C = ndimage.label(n, structure=struct)[1]

                # Apply conditions
                if (C > 1) or (Vx <= 2) or (Vy <= 2) or (Vz <= 2):
                    new_model.voxels[x, y, z] = input_model.voxels[x, y, z]

        if np.sum(interior_voxels.voxels) < 1:
            break
        else:
            input_model = VoxelModel.copy(interior_voxels)

    new_model = new_model.union(input_model)

    return new_model
        print('Importing Files')
        end1 = VoxelModel.fromMeshFile('coupon_templates/' + couponStandard +
                                       '-End.stl', (0, 0, 0),
                                       resolution=res).fitWorkspace()
        center = VoxelModel.fromMeshFile('coupon_templates/' + couponStandard +
                                         '-Center-2.stl', (0, 0, 0),
                                         resolution=res).fitWorkspace()
        end2 = end1.rotate90(2, axis=Axes.Z)
        center.coords = (end1.voxels.shape[0],
                         round(
                             (end1.voxels.shape[1] - center.voxels.shape[1]) /
                             2), 0)
        end2.coords = (end1.voxels.shape[0] + center.voxels.shape[0], 0, 0)

        # Trim center
        center_cross_section = VoxelModel(center.voxels[0:2, :, :],
                                          3).fitWorkspace()
        centerLength = center.voxels.shape[0]
        centerWidth = center_cross_section.voxels.shape[1]
        centerHeight = center_cross_section.voxels.shape[2]

        centerCoordsOffset = (center.coords[0], center.coords[1] + round(
            ((center.voxels.shape[1] - centerWidth) / 2)), center.coords[2])
        center = cuboid((centerLength, centerWidth, centerHeight),
                        centerCoordsOffset)

        # Set materials
        end1 = end1.setMaterial(1)
        end2 = end2.setMaterial(1)
        center = center.setMaterial(2)

        # Combine components