Exemplo n.º 1
0
def triangulate_face(face, vnp):
    if ( (len(face) == 1) and (len(face[0]) == 3) ):
#        print ("Already a triangle")
        return face
    sf = np.array([], dtype=np.int32)
    for ring in face:
        sf = np.hstack( (sf, np.array(ring)) )
    sfv = vnp[sf]
    rings = np.zeros(len(face), dtype=np.int32)
    total = 0
    for i in range(len(face)):
        total += len(face[i])
        rings[i] = total
        # 1. normal with Newell's method
    n = get_normal_newell(sfv)
    sfv2d = np.zeros( (sfv.shape[0], 2))
    for i,p in enumerate(sfv):
        xy = to_2d(p, n)
        sfv2d[i][0] = xy[0]
        sfv2d[i][1] = xy[1]
    result = mapbox_earcut.triangulate_float32(sfv2d, rings)

    for i,each in enumerate(result):    
        result[i] = int(sf[each])           
        
#    print (type(result.reshape(-1, 3).tolist()[0][0]))
    return result.reshape(-1, 3).tolist()
Exemplo n.º 2
0
def lineToSTL(pts, name, z = 1):
    # 3D vertices of the base and top faces.
    pts_base = [ [ax,ay,0] for (ax,ay) in pts]
    pts_top = [ [ax,ay,z] for (ax,ay) in pts]

    # Triangulate the 2D curve
    triangles_indices = earcut.triangulate_float32(np.array(pts).reshape(-1,2), np.array([len(pts)])).reshape(-1,3)

    # 2d triangles to 3d triangles
    base = [ [pts_base[a], pts_base[b], pts_base[c]] for (a,b,c) in triangles_indices]
    top = [ [pts_top[a], pts_top[b], pts_top[c]] for (a,b,c) in triangles_indices]

    # Need to get the number of triangles: 2 per segment plus twice the number given by our triangulization
    n_facets = 2 * len(pts) + 2 * triangles_indices.shape[0]

    data = np.zeros(n_facets, dtype=mesh.Mesh.dtype)

    #Add base and top triangles
    for i in range(len(base)):
        data['vectors'][2*i] = np.array([base[i][0], base[i][1], base[i][2]])
        data['vectors'][2*i + 1] = np.array([top[i][0], top[i][1], top[i][2]])
    #Add side triangles.
    for i in range(len(pts)):
        data['vectors'][2*len(base) + 2*i] = np.array([pts_base[i], pts_top[i-1], pts_base[i-1]])
        data['vectors'][2*len(base) + 2*i + 1] = np.array([pts_base[i], pts_top[i], pts_top[i-1]])

    new_mesh = mesh.Mesh(data)
    new_mesh.save(name)
Exemplo n.º 3
0
def test_empty_data():
    verts = np.array([]).reshape(-1, 2)
    rings = np.array([])

    result = earcut.triangulate_float32(verts, rings)

    assert result.shape == (0, )
def lineToSTL(pts, name, z=19):
    pts_base = [[ax, ay, 0] for (ax, ay) in pts]
    pts_top = [[ax, ay, z] for (ax, ay) in pts]

    #points to triangles

    triangles_indices = earcut.triangulate_float32(
        np.array(pts).reshape(-1, 2), np.array([len(pts)])).reshape(-1, 3)

    #2d triangles to 3d triangles

    base = [[pts_base[a], pts_base[b], pts_base[c]]
            for (a, b, c) in triangles_indices]
    top = [[pts_top[a], pts_top[b], pts_top[c]]
           for (a, b, c) in triangles_indices]

    n_facets = 2 * len(pts) + 2 * triangles_indices.shape[0]

    data = np.zeros(n_facets, dtype=mesh.Mesh.dtype)

    for i in range(len(base)):
        data['vectors'][2 * i] = np.array([base[i][0], base[i][1], base[i][2]])
        data['vectors'][2 * i + 1] = np.array(
            [top[i][0], top[i][1], top[i][2]])

    for i in range(len(pts)):
        data['vectors'][2 * len(base) + 2 * i] = np.array(
            [pts_base[i], pts_top[i - 1], pts_base[i - 1]])
        data['vectors'][2 * len(base) + 2 * i + 1] = np.array(
            [pts_base[i], pts_top[i], pts_top[i - 1]])

    new_mesh = mesh.Mesh(data)

    new_mesh.save(name)
Exemplo n.º 5
0
def test_no_triangles():
    verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.int32).reshape(-1, 2)
    rings = np.array([2, 3])

    result = earcut.triangulate_float32(verts, rings)

    assert result.dtype == np.uint32
    assert result.shape == (0, )
Exemplo n.º 6
0
def test_valid_triangulation_int64():
    verts = np.array([[0, 0], [1, 0], [1, 1]], dtype=np.int64).reshape(-1, 2)
    rings = np.array([3])

    result = earcut.triangulate_float32(verts, rings)

    assert result.dtype == np.uint32
    assert result.shape == (3, )
    assert np.all(result == np.array([1, 2, 0]))
Exemplo n.º 7
0
def test_inverted_vertex_order():
    verts = np.array(list(reversed([[0, 0], [1, 0], [1, 1]])),
                     dtype=np.int32).reshape(-1, 2)
    rings = np.array([3])

    result = earcut.triangulate_float32(verts, rings)

    assert result.dtype == np.uint32
    assert result.shape == (3, )
    assert np.all(result == np.array([1, 0, 2]))
Exemplo n.º 8
0
    def _fill_indices_mapbox_earcut(self):
        """Indexes for drawing the fill as TRIANGLES.
        
        This version uses the mapbox_earcut library, which is C++, but
        currently doesn't have a Python 3.8 release. See

        https://github.com/skogler/mapbox_earcut_python/issues/2

        """
        verts = self.orig_verts[:, :2]
        rings = np.array([len(verts)], dtype=np.uint32)
        idxs = mapbox_earcut.triangulate_float32(verts, rings)
        return idxs.reshape(-1)
Exemplo n.º 9
0
    def triangulate_face(self, face, vnp):
        #-- if already a triangle then return it
        if ((len(face) == 1) and (len(face[0]) == 3)):
            return face
        sf = np.array([], dtype=np.int32)
        for ring in face:
            sf = np.hstack((sf, np.array(ring)))
        sfv = vnp[sf]
        # print(sf)
        # print(sfv)
        rings = np.zeros(len(face), dtype=np.int32)
        total = 0
        for i in range(len(face)):
            total += len(face[i])
            rings[i] = total
        # print(rings)

        # 1. normal with Newell's method
        n = geom_help.get_normal_newell(sfv)
        # print ("Newell:", n)
        # 2. project to the plane to get xy
        sfv2d = np.zeros((sfv.shape[0], 2))
        # print (sfv2d)
        for i, p in enumerate(sfv):
            xy = geom_help.to_2d(p, n)
            # print("xy", xy)
            sfv2d[i][0] = xy[0]
            sfv2d[i][1] = xy[1]
        result = mapbox_earcut.triangulate_float32(sfv2d, rings)
        # print (result.reshape(-1, 3))

        for i, each in enumerate(result):
            # print (sf[i])
            result[i] = sf[each]

        # print (result.reshape(-1, 3))
        return result.reshape(-1, 3)
Exemplo n.º 10
0
def interpolate_stl(target, target_var, c1_1, c2_1, c1_2, c2_2, twist, z, steps, name):
    # linear interpolation of targets, c1s, c2s and twist angles which are the parameters of the curve at each slice
    targets = np.linspace(target - target_var/2, target + target_var/2, steps)
    c1s = np.linspace(c1_1, c1_2, steps)
    c2s = np.linspace(c2_1, c2_2, steps)
    twists = np.linspace(0, T, steps)

    pts_3d = [[]]*steps
    height_step = z / (steps-1)
    tuples = [()]*steps

    # For each 'slice'
    for i in range(steps):
        # Partialize the function with the right values for c1 and c2
        func_to_opt = partial(optimizable_function, targets[i], c1s[i], c2s[i])
        # Inital value for the radius, works for c1 = c2 = 0
        x0=[38]
        # minimize the length difference
        res = minimize(func_to_opt, np.array(x0), method='nelder-mead', options={'xatol': 1e-8, 'disp': False})
        # We get out (R, c1, c2) tuple, with optimized R
        tuples[i] = (res.x[0], c1s[i], c2s[i])
        # compute radii for current slice's parameters
        temp_polar = utils.radius_SC(theta, *tuples[i])
        # Convert polar coordinates to cartesian, adding the twist of the slice
        temp_cart = utils.polarToCart(theta + twists[i], temp_polar)
        # Convert to 3d and store in our array
        pts_3d[i] =  [ [ax,ay,i*height_step] for (ax,ay) in temp_cart]

    # We need to triangulize the base and top, so first we recompute the cartesian coordinates of those
    pts_base = utils.polarToCart(theta, utils.radius_SC(theta, *tuples[0]))
    pts_top = utils.polarToCart(theta + twist, utils.radius_SC(theta, *tuples[steps-1]))

    #triangulate those faces
    triangles_indices_base = earcut.triangulate_float32(np.array(pts_base).reshape(-1,2), np.array([len(pts_base)])).reshape(-1,3)
    triangles_indices_top = earcut.triangulate_float32(np.array(pts_top).reshape(-1,2), np.array([len(pts_top)])).reshape(-1,3)

    #sort the results to fit our data formatting
    base = [ [pts_3d[0][a], pts_3d[0][b], pts_3d[0][c]] for (a,b,c) in triangles_indices_base]
    top = [ [pts_3d[steps-1][a], pts_3d[steps-1][b], pts_3d[steps-1][c]] for (a,b,c) in triangles_indices_top]

    # number of facets, necessary to create our mesh object.
    # between 2 slices, we have 2 faces per segment, ie 2 faces per point because our curve is closed.
    # Plus we have the number of triangles of the top and base faces.
    n_facets = 2 * len(theta) * (steps-1) + len(base) + len(top)

    data = np.zeros(n_facets, dtype=mesh.Mesh.dtype)

    # Add faces of the base
    for i in range(len(base)):
        data['vectors'][i] = np.array([base[i][0], base[i][1], base[i][2]])

    offset = len(base)
    # Add faces of the top, minding the offset
    for i in range(len(top)):
        data['vectors'][offset + i] = np.array([top[i][0], top[i][1], top[i][2]])

    offset += len(top)
    # Add the faces of the sides. This should work out so that their normals are pointing outward.
    for i in range(steps-1):
        for j in range(len(theta)):
            data['vectors'][offset + 2*j] = np.array([pts_3d[i][j], pts_3d[i+1][j-1], pts_3d[i][j-1]])
            data['vectors'][offset + 2*j + 1] = np.array([pts_3d[i][j], pts_3d[i+1][j], pts_3d[i+1][j-1]])
        offset += 2 * len(theta)

    new_mesh = mesh.Mesh(data)

    new_mesh.save(name)
Exemplo n.º 11
0
def get_single_image_mesh_plane(
    plane_params,
    segmentations,
    img_file,
    height=480,
    width=640,
    focal_length=517.97,
    webvis=False,
    tolerance=0,
):
    plane_params = np.array(plane_params)
    offsets = np.linalg.norm(plane_params, ord=2, axis=1)
    norms = plane_params / offsets.reshape(-1, 1)

    if type(segmentations[0]) == dict:
        poly_segmentations = rle2polygon(segmentations, tolerance)
    else:
        poly_segmentations = segmentations
    verts_list = []
    faces_list = []
    verts_uvs = []
    uv_maps = []
    imgs = []

    for segm, normal, offset in zip(poly_segmentations, norms, offsets):
        if len(segm) == 0:
            continue
        I = np.array(imageio.imread(img_file))

        HUse = None

        # save uv_map
        tmp_verts = []
        for s in segm:
            tmp_verts.extend(s)
        tmp_verts = np.array(tmp_verts).reshape(-1, 2)
        # pick an arbitrary point
        # get 3d pointcloud
        tmp_pcd = get_pcd(tmp_verts, normal, offset, focal_length)
        point0 = tmp_pcd[0, :]
        # pick the furthest point from here
        dPoint0 = np.sum((tmp_pcd - point0[np.newaxis, :]) ** 2, axis=1)
        point1 = tmp_pcd[np.argmax(dPoint0), :]

        # dir1 and dir2 are orthogonal to the normal
        dir1 = point1 - point0
        dir1 = dir1 / np.linalg.norm(dir1)
        dir2 = np.cross(dir1, normal)

        # control points in 3D
        control3D = [point0, point0 + dir1, point0 + dir2, point0 + dir1 + dir2]
        control3D = np.vstack([p[None, :] for p in control3D])
        control3DProject = project2D(control3D, focal_length)

        # pick an arbitrary square
        targetSize = 300
        fakePoints = np.array(
            [[0, 0], [0, targetSize], [targetSize, 0], [targetSize, targetSize]]
        ).astype(np.float32)

        # fit, then adjust
        H = cv2.getPerspectiveTransform(control3DProject.astype(np.float32), fakePoints)
        # this maps the control points to the square; now make sure the full mask warps in
        P = cv2.perspectiveTransform(tmp_verts.reshape(1, -1, 2), H)[0, :, :]
        xTrans, yTrans = P[:, 0].min(), P[:, 1].min()
        maxScale = max(P[:, 0].max() - P[:, 0].min(), P[:, 1].max() - P[:, 1].min())
        HShuffle = np.array(
            [
                [targetSize / maxScale, 0, -xTrans * targetSize / maxScale],
                [0, targetSize / maxScale, -yTrans * targetSize / maxScale],
                [0, 0, 1],
            ]
        )
        HUse = HShuffle @ H

        # warped_image is now the rectified image; warped_image2 has it with a 100px fudge factor
        warped_image = cv2.warpPerspective(I, HUse, (targetSize, targetSize))

        uv_maps.append(warped_image)

        verts_3d = []
        faces = []
        uvs = []

        for ring in segm:
            verts = np.array(ring).reshape(-1, 2)
            # get 3d pointcloud
            pcd = get_pcd(verts, normal, offset, focal_length)

            if webvis:
                # Rotate by 11 degree around x axis to push things on the ground.
                pcd = (
                    np.array([[-1, 0, 0], [0, 1, 0], [0, 0, -1]])
                    @ np.array(
                        [
                            [1, 0, 0],
                            [0, 0.9816272, -0.1908090],
                            [0, 0.1908090, 0.9816272],
                        ]
                    )
                    @ np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
                    @ pcd.T
                ).T

            uvsRectified = cv2.perspectiveTransform(
                verts.astype(np.float32).reshape(1, -1, 2), HUse
            )[0, :, :]
            uvsRectified = np.array([0, 1]) + np.array(
                [1, -1]
            ) * uvsRectified / np.array([targetSize, targetSize])
            uvs.extend(uvsRectified)

            # triangulate polygon using earcut algorithm
            triangles = earcut.triangulate_float32(verts, [len(verts)])
            # add base index of vertice
            triangles += len(verts_3d)
            triangles = triangles.reshape(-1, 3)
            # convert to counter-clockwise
            triangles[:, [0, 2]] = triangles[:, [2, 0]]

            if triangles.shape[0] == 0:
                continue

            verts_3d.extend(pcd)
            faces.extend(triangles)

        verts_list.append(torch.tensor(verts_3d, dtype=torch.float32))
        faces_list.append(torch.tensor(faces, dtype=torch.int32))
        verts_uvs.append(torch.tensor(uvs, dtype=torch.float32))
        imgs.append(torch.FloatTensor(imageio.imread(img_file)))

    # pytorch3d mesh
    verts_uvs = pad_sequence(verts_uvs, batch_first=True)
    faces_uvs = pad_sequence(faces_list, batch_first=True, padding_value=-1)
    tex = Textures(verts_uvs=verts_uvs, faces_uvs=faces_uvs, maps=imgs)
    meshes = Meshes(verts=verts_list, faces=faces_list, textures=tex)

    return meshes, uv_maps
Exemplo n.º 12
0
def test_end_index_too_small():
    verts = np.array([[0, 0], [1, 0], [1, 1]]).reshape(-1, 2)
    rings = np.array([2])

    with pytest.raises(ValueError, message="Expecting ValueError"):
        result = earcut.triangulate_float32(verts, rings)
Exemplo n.º 13
0
def test_rings_not_increasing():
    verts = np.array([[0, 0], [1, 0], [1, 1]]).reshape(-1, 2)
    rings = np.array([3, 0, 3])

    with pytest.raises(ValueError):
        result = earcut.triangulate_float32(verts, rings)
Exemplo n.º 14
0
def test_end_index_neg():
    verts = np.array([[0, 0], [1, 0], [1, 1]]).reshape(-1, 2)
    rings = np.array([-1])

    with pytest.raises(ValueError):
        result = earcut.triangulate_float32(verts, rings)
Exemplo n.º 15
0
 def _fill_indices(self):
     """Indexes for drawing the fill as TRIANGLES."""
     verts = self.orig_verts[:, :2]
     rings = np.array([len(verts)], dtype=np.uint32)
     idxs = earcut.triangulate_float32(verts, rings)
     return idxs.reshape(-1)
Exemplo n.º 16
0
def get_single_image_mesh(
    plane_params,
    segmentations,
    img_file,
    height=480,
    width=640,
    focal_length=517.97,
    webvis=False,
    reduce_size=True,
):
    plane_params = np.array(plane_params)
    offsets = np.linalg.norm(plane_params, ord=2, axis=1)
    norms = plane_params / offsets.reshape(-1, 1)

    if type(segmentations[0]) == dict:
        poly_segmentations = rle2polygon(segmentations)
    else:
        poly_segmentations = segmentations
    verts_list = []
    faces_list = []
    verts_uvs = []
    img_files = []
    imgs = []

    for segm, normal, offset in zip(poly_segmentations, norms, offsets):
        if len(segm) == 0:
            continue
        verts_3d = []
        faces = []
        uvs = []
        if reduce_size:
            for ring in segm:
                verts = np.array(ring).reshape(-1, 2)
                # get 3d pointcloud
                pcd = get_pcd(verts, normal, offset, focal_length)
                if webvis:
                    # Rotate by 11 degree around x axis to push things on the ground.
                    pcd = (
                        np.array([[-1, 0, 0], [0, 1, 0], [0, 0, -1]])
                        @ np.array(
                            [
                                [1, 0, 0],
                                [0, 0.9816272, -0.1908090],
                                [0, 0.1908090, 0.9816272],
                            ]
                        )
                        @ np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
                        @ pcd.T
                    ).T
                # triangulate polygon using earcut algorithm
                triangles = earcut.triangulate_float32(verts, [len(verts)])
                # add base index of vertice
                triangles += len(verts_3d)
                triangles = triangles.reshape(-1, 3)
                # convert to counter-clockwise
                triangles[:, [0, 2]] = triangles[:, [2, 0]]
                verts_3d.extend(pcd)
                faces.extend(triangles)
                uvs.extend(
                    np.array([0, 1])
                    + np.array([1, -1]) * verts / np.array([width, height])
                )

        else:
            bitmask = polygons_to_bitmask(segm, height=height, width=width)
            verts = np.transpose(bitmask.nonzero())
            vert_id_map = defaultdict(dict)
            for idx, vert in enumerate(verts):
                vert_id_map[vert[0]][vert[1]] = idx + len(verts_3d)

            verts_3d = get_pcd(verts[:, ::-1], normal, offset)
            if webvis:
                # Rotate by 11 degree around x axis to push things on the ground.
                verts_3d = (
                    np.array([[-1, 0, 0], [0, 1, 0], [0, 0, -1]])
                    @ np.array(
                        [
                            [1, 0, 0],
                            [0, 0.9816272, -0.1908090],
                            [0, 0.1908090, 0.9816272],
                        ]
                    )
                    @ np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
                    @ pcd.T
                ).T
            triangles = []
            for vert in verts:
                # upper right triangle
                if (
                    vert[0] < height - 1
                    and vert[1] < width - 1
                    and bitmask[vert[0]][vert[1] + 1]
                    and bitmask[vert[0] + 1][vert[1] + 1]
                ):
                    triangles.append(
                        [
                            vert_id_map[vert[0]][vert[1]],
                            vert_id_map[vert[0] + 1][vert[1] + 1],
                            vert_id_map[vert[0]][vert[1] + 1],
                        ]
                    )
                # bottom left triangle
                if (
                    vert[0] < height - 1
                    and vert[1] < width - 1
                    and bitmask[vert[0] + 1][vert[1]]
                    and bitmask[vert[0] + 1][vert[1] + 1]
                ):
                    triangles.append(
                        [
                            vert_id_map[vert[0]][vert[1]],
                            vert_id_map[vert[0] + 1][vert[1]],
                            vert_id_map[vert[0] + 1][vert[1] + 1],
                        ]
                    )
            triangles = np.array(triangles)
            faces.extend(triangles)
            uvs.extend(
                np.array([0, 1])
                + np.array([1, -1]) * verts[:, ::-1] / np.array([width, height])
            )
        verts_list.append(torch.tensor(verts_3d, dtype=torch.float32))
        faces_list.append(torch.tensor(faces, dtype=torch.int32))
        verts_uvs.append(torch.tensor(uvs, dtype=torch.float32))
        img_files.append(img_file)
        imgs.append(torch.FloatTensor(imageio.imread(img_file)))
    verts_uvs = pad_sequence(verts_uvs, batch_first=True)
    faces_uvs = pad_sequence(faces_list, batch_first=True, padding_value=-1)

    tex = Textures(verts_uvs=verts_uvs, faces_uvs=faces_uvs, maps=imgs)

    # Initialise the mesh with textures
    meshes = Meshes(verts=verts_list, faces=faces_list, textures=tex)
    return meshes, img_files
Exemplo n.º 17
0
def test_rings_same():
    verts = np.array([[0, 0], [1, 0], [1, 1]]).reshape(-1, 2)
    rings = np.array([3, 3])

    with pytest.raises(ValueError, message="Expecting ValueError"):
        result = earcut.triangulate_float32(verts, rings)