# Modified from the original OpenCTM python binding # for inclusion in the `trimesh` package: # https://github.com/mikedh/trimesh # # To get shared library this binding imports, you can download # and install it on Linux using this bash script: # https://github.com/mikedh/trimesh/blob/master/docker/builds/openctm.bash # ------------------------------------------------------------------------------ # Copyright (c) 2009-2010 Marcus Geelnard # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # # 2. Altered source versions must be plainly marked as such, and must not # be misrepresented as being the original software. # # 3. This notice may not be removed or altered from any source # distribution. # ------------------------------------------------------------------------------ import os import ctypes _ctm_loaders = {} _ctm_lib = None try: if os.name == 'nt': # try to import the shared library on windows _ctm_lib = ctypes.WinDLL('openctm.dll') else: # try to import on other platforms _ctm_lib_name = ctypes.util.find_library('openctm') if _ctm_lib_name: _ctm_lib = ctypes.CDLL(_ctm_lib_name) except BaseException: pass if _ctm_lib: import numpy as np # Types CTMfloat = ctypes.c_float CTMint = ctypes.c_int32 CTMuint = ctypes.c_uint32 CTMcontext = ctypes.c_void_p CTMenum = ctypes.c_uint32 # boolean CTM_TRUE = 1 CTM_FALSE = 0 # CTMenum CTM_NONE = 0x0000 CTM_IMPORT = 0x0101 CTM_EXPORT = 0x0102 CTM_VERTEX_COUNT = 0x0301 CTM_TRIANGLE_COUNT = 0x0302 CTM_HAS_NORMALS = 0x0303 CTM_INDICES = 0x0601 CTM_VERTICES = 0x0602 CTM_NORMALS = 0x0603 # Functions ctmNewContext = _ctm_lib.ctmNewContext ctmNewContext.argtypes = [CTMenum] ctmNewContext.restype = CTMcontext ctmFreeContext = _ctm_lib.ctmFreeContext ctmFreeContext.argtypes = [CTMcontext] ctmGetError = _ctm_lib.ctmGetError ctmGetError.argtypes = [CTMcontext] ctmGetError.restype = CTMenum ctmErrorString = _ctm_lib.ctmErrorString ctmErrorString.argtypes = [CTMenum] ctmErrorString.restype = ctypes.c_char_p ctmGetInteger = _ctm_lib.ctmGetInteger ctmGetInteger.argtypes = [CTMcontext, CTMenum] ctmGetInteger.restype = CTMint ctmGetFloat = _ctm_lib.ctmGetFloat ctmGetFloat.argtypes = [CTMcontext, CTMenum] ctmGetFloat.restype = CTMfloat ctmGetIntegerArray = _ctm_lib.ctmGetIntegerArray ctmGetIntegerArray.argtypes = [CTMcontext, CTMenum] ctmGetIntegerArray.restype = ctypes.POINTER(CTMuint) ctmGetFloatArray = _ctm_lib.ctmGetFloatArray ctmGetFloatArray.argtypes = [CTMcontext, CTMenum] ctmGetFloatArray.restype = ctypes.POINTER(CTMfloat) ctmLoad = _ctm_lib.ctmLoad ctmLoad.argtypes = [CTMcontext, ctypes.c_char_p] ctmSave = _ctm_lib.ctmSave ctmSave.argtypes = [CTMcontext, ctypes.c_char_p] def load_ctm(file_obj, file_type=None, **kwargs): """ Load OpenCTM files from a file object. Parameters ---------- file_obj : open file- like object Returns ---------- loaded : dict kwargs for a Trimesh constructor: {vertices: (n,3) float, vertices faces: (m,3) int, indexes of vertices} """ ctm = ctmNewContext(CTM_IMPORT) # !!load file from name # this should be replaced with something that # actually uses the file object data to support streams name = str(file_obj.name).encode('utf-8') ctmLoad(ctm, name) err = ctmGetError(ctm) if err != CTM_NONE: raise IOError("Error loading file: " + str(ctmErrorString(err))) # get vertices vertex_count = ctmGetInteger(ctm, CTM_VERTEX_COUNT) vertex_ctm = ctmGetFloatArray(ctm, CTM_VERTICES) # use fromiter to avoid loop vertices = np.fromiter(vertex_ctm, dtype=np.float, count=vertex_count * 3).reshape((-1, 3)) # get faces face_count = ctmGetInteger(ctm, CTM_TRIANGLE_COUNT) face_ctm = ctmGetIntegerArray(ctm, CTM_INDICES) faces = np.fromiter(face_ctm, dtype=np.int, count=face_count * 3).reshape((-1, 3)) # create kwargs for trimesh constructor result = {'vertices': vertices, 'faces': faces} # get face normals if available if ctmGetInteger(ctm, CTM_HAS_NORMALS) == CTM_TRUE: normals_ctm = ctmGetFloatArray(ctm, CTM_NORMALS) normals = np.fromiter(normals_ctm, dtype=np.float, count=face_count * 3).reshape((-1, 3)) result['face_normals'] = normals # free context ctmFreeContext(ctm) return result # we have a library so add load_ctm _ctm_loaders = {'ctm': load_ctm}