def test_ignoring_unrecognized_lines(self):
     # Given gibberish = a file containing:
     #     """
     #     There was a young lady named Bright
     #     who traveled much faster than light.
     #     She set out one day
     #     in a relative way,
     #     and came back the previous night.
     #     """
     parser = ObjFile.parse_obj_file("tests/obj_test_files/gibberish.obj")
     self.assertEqual(parser.ignored_lines, 5)
 def test_triangles_in_groups(self):
     parser = ObjFile.parse_obj_file("tests/obj_test_files/triangles.obj")
     g1 = parser.named_groups["FirstGroup"]
     g2 = parser.named_groups["SecondGroup"]
     t1 = g1.members[0]
     t2 = g2.members[0]
     self.assertEqual(t1.p1, parser.vertices[1])
     self.assertEqual(t1.p2, parser.vertices[2])
     self.assertEqual(t1.p3, parser.vertices[3])
     self.assertEqual(t2.p1, parser.vertices[1])
     self.assertEqual(t2.p2, parser.vertices[3])
     self.assertEqual(t2.p3, parser.vertices[4])
 def test_parsing_trangle_faces(self):
     parser = ObjFile.parse_obj_file(
         "tests/obj_test_files/triangle_faces.obj")
     g = parser.default_group
     t1 = g.members[0]
     t2 = g.members[1]
     self.assertEqual(t1.p1, parser.vertices[1])
     self.assertEqual(t1.p2, parser.vertices[2])
     self.assertEqual(t1.p3, parser.vertices[3])
     self.assertEqual(t2.p1, parser.vertices[1])
     self.assertEqual(t2.p2, parser.vertices[3])
     self.assertEqual(t2.p3, parser.vertices[4])
 def test_vertex_records(self):
     # Given file = a file containing:
     #     """
     #     v -1 1 0
     #     v -1.0000 0.5000 0.0000
     #     v 1 0 0
     #     v 1 1 0
     #     """
     parser = ObjFile.parse_obj_file("tests/obj_test_files/vertex.obj")
     self.assertEqual(parser.vertices[1], Point(-1, 1, 0))
     self.assertEqual(parser.vertices[2], Point(-1, 0.5, 0))
     self.assertEqual(parser.vertices[3], Point(1, 0, 0))
     self.assertEqual(parser.vertices[4], Point(1, 1, 0))
 def test_faces_normals(self):
     parser = ObjFile.parse_obj_file(
         "tests/obj_test_files/faces_normals.obj")
     g = parser.default_group
     t1 = g.members[0]
     t2 = g.members[1]
     self.assertEqual(t1.p1, parser.vertices[1])
     self.assertEqual(t1.p2, parser.vertices[2])
     self.assertEqual(t1.p3, parser.vertices[3])
     self.assertEqual(t1.n1, parser.normals[3])
     self.assertEqual(t1.n2, parser.normals[1])
     self.assertEqual(t1.n3, parser.normals[2])
     self.assertEqual(t2, t1)
 def test_triangulating_polygons(self):
     parser = ObjFile.parse_obj_file(
         "tests/obj_test_files/triangulating_polygons.obj")
     g = parser.default_group
     t1 = g.members[0]
     t2 = g.members[1]
     t3 = g.members[2]
     self.assertEqual(t1.p1, parser.vertices[1])
     self.assertEqual(t1.p2, parser.vertices[2])
     self.assertEqual(t1.p3, parser.vertices[3])
     self.assertEqual(t2.p1, parser.vertices[1])
     self.assertEqual(t2.p2, parser.vertices[3])
     self.assertEqual(t2.p3, parser.vertices[4])
     self.assertEqual(t3.p1, parser.vertices[1])
     self.assertEqual(t3.p2, parser.vertices[4])
     self.assertEqual(t3.p3, parser.vertices[5])
Example #7
0
def convex_decomposition(mesh, cache_dir='', name='mesh'):
    """ Performs a convex deomposition of the mesh using V-HACD.
    
    Parameters
    ----------
    cache_dir : str
        a directory to store the intermediate files
    name : str
        the name of the mesh for the cache file

    Returns
    -------
    :obj:`list` of :obj:`Mesh3D`
        list of mesh objects comprising the convex pieces of the object, or None if vhacd failed
    :obj:`list` of str
        string file roots of the convex pieces
    float
        total volume of the convex pieces
    """
    # save to file
    if not os.path.exists(cache_dir):
        os.mkdir(cache_dir)
    obj_filename = os.path.join(cache_dir, '%s.obj' % (name))
    vhacd_out_filename = os.path.join(cache_dir, '%s_vhacd.obj' % (name))
    log_filename = os.path.join(cache_dir, 'vhacd_log.txt')
    print obj_filename
    ObjFile(obj_filename).write(mesh)

    # use v-hacd for convex decomposition
    cvx_decomp_cmd = 'vhacd --input %s --output %s --log %s' % (
        obj_filename, vhacd_out_filename, log_filename)
    vhacd_process = Popen(cvx_decomp_cmd,
                          bufsize=-1,
                          close_fds=True,
                          shell=True)
    vhacd_process.wait()

    # check success
    if not os.path.exists(vhacd_out_filename):
        logging.error(
            'Output mesh file %s not found. V-HACD failed. Is V-HACD installed?'
            % (vhacd_out_filename))
        return None

    # create separate convex piece files
    convex_piece_files = split_vhacd_output(vhacd_out_filename)

    # read convex pieces
    convex_piece_meshes = []
    convex_piece_filenames = []
    convex_pieces_volume = 0.0

    # read in initial meshes for global properties
    for convex_piece_filename in convex_piece_files:

        # read in meshes
        obj_file_path, obj_file_root = os.path.split(convex_piece_filename)
        of = ObjFile(convex_piece_filename)
        convex_piece = of.read()
        convex_pieces_volume += convex_piece.total_volume()
        convex_piece_meshes.append(of.read())
        convex_piece_filenames.append(obj_file_root)

    return convex_piece_meshes, convex_piece_filenames, convex_pieces_volume
Example #8
0
    def write_pieces(self, meshes, center_of_mass=np.zeros(3), density=1.0):
        """Writes a list of Mesh3D object to a .urdf file.

        Parameters
        ----------
        meshes : :obj:`list` of :obj:`Mesh3D`
            The Mesh3D objects to write to the .urdf file.
        center_of_mass : :obj:`numpy.ndarray`
            The center of mass of the combined object. Defaults to zero.
        desnity : float
            The density fo the mesh pieces

        Note
        ----
        Does not support moveable joints.
        """
        # create output directory
        out_dir = self.filepath_
        if not os.path.exists(out_dir):
            os.mkdir(out_dir)

        # read convex pieces
        mesh_filenames = []

        # write meshes to reference with URDF files
        for i, mesh in enumerate(meshes):
            # read in meshes
            obj_file_root = '%s_%04d.obj' % (self.name_, i)
            obj_filename = os.path.join(out_dir, obj_file_root)
            ObjFile(obj_filename).write(mesh)
            mesh_filenames.append(obj_file_root)

        # open an XML tree
        root = et.Element('robot', name='root')

        # loop through all pieces
        prev_piece_name = None
        for mesh, filename in zip(meshes, mesh_filenames):
            # set the mass properties
            mesh.center_of_mass = center_of_mass
            mesh.density = density

            _, file_root = os.path.split(filename)
            file_root, _ = os.path.splitext(file_root)
            obj_filename = 'package://%s/%s' % (self.name_, filename)

            # write to xml
            piece_name = 'link_%s' % (file_root)
            I = mesh.inertia
            link = et.SubElement(root, 'link', name=piece_name)

            inertial = et.SubElement(link, 'inertial')
            origin = et.SubElement(inertial,
                                   'origin',
                                   xyz="0 0 0",
                                   rpy="0 0 0")
            mass = et.SubElement(inertial, 'mass', value='%.2E' % mesh.mass)
            inertia = et.SubElement(inertial,
                                    'inertia',
                                    ixx='%.2E' % I[0, 0],
                                    ixy='%.2E' % I[0, 1],
                                    ixz='%.2E' % I[0, 2],
                                    iyy='%.2E' % I[1, 1],
                                    iyz='%.2E' % I[1, 2],
                                    izz='%.2E' % I[2, 2])

            visual = et.SubElement(link, 'visual')
            origin = et.SubElement(visual, 'origin', xyz="0 0 0", rpy="0 0 0")
            geometry = et.SubElement(visual, 'geometry')
            mesh_element = et.SubElement(geometry,
                                         'mesh',
                                         filename=obj_filename)
            material = et.SubElement(visual, 'material', name='')
            color = et.SubElement(material, 'color', rgba="0.75 0.75 0.75 1")

            collision = et.SubElement(link, 'collision')
            origin = et.SubElement(collision,
                                   'origin',
                                   xyz="0 0 0",
                                   rpy="0 0 0")
            geometry = et.SubElement(collision, 'geometry')
            mesh_element = et.SubElement(geometry,
                                         'mesh',
                                         filename=obj_filename)

            if prev_piece_name is not None:
                joint = et.SubElement(root,
                                      'joint',
                                      name='%s_joint' % (piece_name),
                                      type='fixed')
                origin = et.SubElement(joint,
                                       'origin',
                                       xyz="0 0 0",
                                       rpy="0 0 0")
                parent = et.SubElement(joint, 'parent', link=prev_piece_name)
                child = et.SubElement(joint, 'child', link=piece_name)

            prev_piece_name = piece_name

        # write URDF file
        tree = et.ElementTree(root)
        tree.write(self.urdf_filename)

        # write config file
        root = et.Element('model')
        model = et.SubElement(root, 'name')
        model.text = self.name_
        version = et.SubElement(root, 'version')
        version.text = '1.0'
        sdf = et.SubElement(root, 'sdf', version='1.4')
        urdf_root, urdf_ext = os.path.splitext(self.urdf_filename)
        urdf_path, urdf_name = os.path.split(urdf_root)
        sdf.text = urdf_name

        author = et.SubElement(root, 'author')
        et.SubElement(author, 'name').text = 'AUTOLAB meshpy'
        et.SubElement(author, 'email').text = '*****@*****.**'

        description = et.SubElement(root, 'description')
        description.text = 'My awesome %s' % (self.name_)

        tree = et.ElementTree(root)
        config_filename = os.path.join(out_dir, 'model.config')
        tree.write(config_filename)
 def test_vertex_normal_records(self):
     parser = ObjFile.parse_obj_file(
         "tests/obj_test_files/vertex_normal.obj")
     self.assertEqual(parser.normals[1], Vector(0, 0, 1))
     self.assertEqual(parser.normals[2], Vector(0.707, 0, -0.707))
     self.assertEqual(parser.normals[3], Vector(1, 2, 3))
 def test_converting_obj_file_to_group(self):
     parser = ObjFile.parse_obj_file("tests/obj_test_files/triangles.obj")
     g = ObjFile.obj_to_group(parser)
     self.assertIn(parser.named_groups["FirstGroup"], g.members)
     self.assertIn(parser.named_groups["SecondGroup"], g.members)
Example #11
0
from camera import Camera
from color import Color
from light import PointLight
from obj_file import ObjFile
from tuple import *
from world import World

if __name__ == '__main__':
    parser = ObjFile.parse_obj_file("teapot-low.obj")
    teapot = ObjFile.obj_to_group(parser)
    teapot.material.ambient = .3
    teapot.material.color = Color(.75, .1, .1)

    teapot.divide(1)

    # The light source is white, shining from above and to the left
    world = World()
    world.objects = [teapot]
    world.light = PointLight(Point(-5, 30, 25), Color(1, 1, 1))

    # Camera
    camera = Camera(200, 150, math.pi / 3)
    # camera = Camera(50, 50, math.pi / 3)
    camera.transform = World.view_transform(Point(0, 30, 25), Point(0, 0, 0),
                                            Vector(0, 0, 1))

    # render the result to a canvas
    canvas = Camera.render(camera, world)
    canvas.canvas_to_ppm()
Example #12
0
def import_obj():
    file_path, user_id, stream_id, branch_name, commit_message = sys.argv[1:]
    print(f'ImportOBJ argv[1:]: {sys.argv[1:]}')

    # Parse input
    obj = ObjFile(file_path)
    print(
        f'Parsed obj with {len(obj.faces)} faces ({len(obj.vertices) * 3} vertices)'
    )

    speckle_root = Base()
    speckle_root['@objects'] = []

    for objname in obj.objects:
        print(f'  Converting {objname}...')

        speckle_obj = Base()
        speckle_obj.name = objname
        speckle_obj['@displayValue'] = []
        speckle_root['@objects'].append(speckle_obj)

        for obj_mesh in obj.objects[objname]:
            speckle_vertices = [
                coord for point in obj_mesh['vertices'] for coord in point
            ]
            speckle_faces = []
            for obj_face in obj_mesh['faces']:
                if len(obj_face) == 3:
                    speckle_faces.append(0)
                elif len(obj_face) == 4:
                    speckle_faces.append(1)
                else:
                    speckle_faces.append(len(obj_face))
                speckle_faces.extend(obj_face)

            has_vertex_colors = False
            for vc in obj_mesh['vertex_colors']:
                if vc is not None:
                    has_vertex_colors = True
            colors = []
            if has_vertex_colors:
                for vc in obj_mesh['vertex_colors']:
                    if vc is None:
                        r, g, b = (1.0, 1.0, 1.0)
                    else:
                        r, g, b = vc
                    argb = (1.0, r, g, b)
                    color = int.from_bytes([int(val * 255) for val in argb],
                                           byteorder="big",
                                           signed=True)
                    colors.append(color)

            speckle_mesh = Mesh(vertices=speckle_vertices,
                                faces=speckle_faces,
                                colors=colors,
                                textureCoordinates=[])

            obj_material = obj_mesh['material']
            if obj_material:
                speckle_mesh['renderMaterial'] = convert_material(obj_material)

            speckle_obj['@displayValue'].append(speckle_mesh)

    # Commit

    client = SpeckleClient(host=os.getenv('SPECKLE_SERVER_URL',
                                          'localhost:3000'),
                           use_ssl=False)
    client.authenticate(os.environ['USER_TOKEN'])

    if not client.branch.get(stream_id, branch_name):
        client.branch.create(
            stream_id, branch_name,
            'File upload branch' if branch_name == 'uploads' else '')

    transport = ServerTransport(client=client, stream_id=stream_id)
    id = operations.send(base=speckle_root, transports=[transport])

    commit_id = client.commit.create(stream_id=stream_id,
                                     object_id=id,
                                     branch_name=(branch_name
                                                  or DEFAULT_BRANCH),
                                     message=(commit_message
                                              or 'OBJ file upload'),
                                     source_application='OBJ')

    return commit_id