Source code for exports.obj_out

"""
Contains ObjOut class
"""
import sys
import logging

from lib.db.style.false_colour import make_false_colour_tup

[docs]class ObjKit(): ''' Class to output geometries to Wavefront OBJ format ''' # Limit to 256 colours MAX_COLOURS = 256.0 def __init__(self, debug_level): ''' Initialise class :param debug_level: debug level, using python's 'logging' module ''' # Set up logging, use an attribute of class name so it is only called once if not hasattr(ObjKit, 'logger'): ObjKit.logger = logging.getLogger(__name__) # Create console handler handler = logging.StreamHandler(sys.stdout) # Create formatter formatter = logging.Formatter('%(asctime)s -- %(name)s -- %(levelname)s - %(message)s') # Add formatter to ch handler.setFormatter(formatter) # Add handler to logger and set level ObjKit.logger.addHandler(handler) ObjKit.logger.setLevel(debug_level) self.logger = ObjKit.logger
[docs] def write_voxel_obj(self, geom_obj, out_fp, file_name, src_file_str, step_sz, use_full_cubes=False): ''' Writes out voxel data to Wavefront OBJ and MTL files :param out_fp: open file handle of OBJ file :param geom_obj: MODEL_GEOMETRY object :param fileName: filename of OBJ file without the 'OBJ' extension :param src_file_str: filename of gocad file :param step_sz: when stepping through the voxel block this is the step size :param use_full_cubes: (optional, default to false) will write out full cubes to file if true, else will remove non-visible faces ''' self.logger.debug("write_voxel_obj(%s,%s)", file_name, src_file_str) mtl_fp = open(file_name+".MTL", 'w') for colour_idx in range(int(self.MAX_COLOURS)): diffuse_colour = make_false_colour_tup(float(colour_idx), 0.0, self.MAX_COLOURS) mtl_fp.write("# Wavefront MTL file converted from '{0}'\n\n".format(src_file_str)) mtl_fp.write("newmtl colouring-{0:03d}\n".format(colour_idx)) mtl_fp.write("Ka {0:.3f} {1:.3f} {2:.3f}\n".format(diffuse_colour[0], diffuse_colour[1], diffuse_colour[2])) mtl_fp.write("Kd {0:.3f} {1:.3f} {2:.3f}\n".format(diffuse_colour[0], diffuse_colour[1], diffuse_colour[2])) mtl_fp.write("Ks 0.000 0.000 0.000\n") mtl_fp.write("d 1.0\n") mtl_fp.close() ct_done = True out_fp.write("mtllib "+file_name+".MTL\n") vert_idx = 0 break_out = False for z_val in range(0, geom_obj.vol_sz[2], step_sz): for y_val in range(0, geom_obj.vol_sz[1], step_sz): for x_val in range(0, geom_obj.vol_sz[0], step_sz): colour_num = int(255.0*(geom_obj.voxel_data[x_val][y_val][z_val] \ - geom_obj.voxel_data_stats['min']) \ /(geom_obj.voxel_data_stats['max'] \ - geom_obj.voxel_data_stats['min'])) # NB: Assumes AXIS_MIN = 0, and AXIS_MAX = 1 u_offset = geom_obj.vol_origin[0] + \ float(x_val)/geom_obj.vol_sz[0]*abs(geom_obj.vol_axis_u[0]) v_offset = geom_obj.vol_origin[1] + \ float(y_val)/geom_obj.vol_sz[1]*abs(geom_obj.vol_axis_v[1]) w_offset = geom_obj.vol_origin[2] + \ float(z_val)/geom_obj.vol_sz[2]*abs(geom_obj.vol_axis_w[2]) uvw = (u_offset, v_offset, w_offset) pt_size = (step_sz*abs(geom_obj.vol_axis_u[0])/geom_obj.vol_sz[0]/2, step_sz*abs(geom_obj.vol_axis_v[1])/geom_obj.vol_sz[1]/2, step_sz*abs(geom_obj.vol_axis_w[2])/geom_obj.vol_sz[2]/2) vert_list = [(uvw[0]-pt_size[0], uvw[1]-pt_size[1], uvw[2]+pt_size[2]), (uvw[0]-pt_size[0], uvw[1]-pt_size[1], uvw[2]-pt_size[2]), (uvw[0]-pt_size[0], uvw[1]+pt_size[1], uvw[2]-pt_size[2]), (uvw[0]-pt_size[0], uvw[1]+pt_size[1], uvw[2]+pt_size[2]), (uvw[0]+pt_size[0], uvw[1]-pt_size[1], uvw[2]+pt_size[2]), (uvw[0]+pt_size[0], uvw[1]-pt_size[1], uvw[2]-pt_size[2]), (uvw[0]+pt_size[0], uvw[1]+pt_size[1], uvw[2]-pt_size[2]), (uvw[0]+pt_size[0], uvw[1]+pt_size[1], uvw[2]+pt_size[2]), ] indice_list = [] # Create a full cube for each voxel if use_full_cubes: indice_list = [(4, 3, 2, 1), # WEST (2, 6, 5, 1), # SOUTH (3, 7, 6, 2), # BOTTOM (8, 7, 3, 4), # NORTH (5, 8, 4, 1), # TOP (6, 7, 8, 5), # EAST ] # To save space, only create surfaces at the edges, assuming a block shape else: # BOTTOM FACE if z_val == 0: indice_list.append((3, 7, 6, 2)) # TOP FACE if z_val == geom_obj.vol_sz[2]-1: indice_list.append((5, 8, 4, 1)) # SOUTH FACE if y_val == 0: indice_list.append((2, 6, 5, 1)) # NORTH FACE if y_val == geom_obj.vol_sz[1]: indice_list.append((8, 7, 3, 4)) # EAST FACE if x_val == 0: indice_list.append((6, 7, 8, 5)) # WEST FACE if x_val == geom_obj.vol_sz[0]: indice_list.append((4, 3, 2, 1)) # Only write if there are indices to write if indice_list: for vert in vert_list: out_fp.write("v {0:f} {1:f} {2:f}\n".format(vert[0], vert[1], vert[2])) out_fp.write("g main-{0:010d}\n".format(vert_idx)) out_fp.write("usemtl colouring-{0:03d}\n".format(colour_num)) for ind in indice_list: out_fp.write("f {0:d} {1:d} {2:d} {3:d}\n".format(ind[0]+vert_idx, ind[1]+vert_idx, ind[2]+vert_idx, ind[3]+vert_idx)) out_fp.write("\n") vert_idx += len(vert_list) if vert_idx > 99999999999: break_out = True break if break_out: break if break_out: break return ct_done
[docs] def write_obj(self, geom_obj, style_obj, file_name, src_file_str): ''' Writes out an OBJ file :param style_obj: STYLE object :param geom_obj: MODEL_GEOMETRY object :param fileName: filename of OBJ file, without extension :param src_file_str: filename of gocad file NOTES: OBJ is very simple, and has shortcomings: 1. Does not include annotations (only comments and a group name) 2. Lines and points do not have a colour I am only using it here because GOCAD VOXEL files are too big for COLLADA format ''' self.logger.debug("write_obj(%s,%s)", file_name, src_file_str) # Output to OBJ file print("Writing OBJ file: ", file_name+".OBJ") out_fp = open(file_name+".OBJ", 'w') out_fp.write("# Wavefront OBJ file converted from '{0}'\n\n".format(src_file_str)) ct_done = False # This dictionary returns the insertion order of the vertex # in the vrtx_arr given its sequence number vert_dict = geom_obj.make_vertex_dict() if geom_obj.is_trgl(): if len(style_obj.get_rgba_tup()) == 4: out_fp.write("mtllib "+file_name+".MTL\n") if geom_obj.is_trgl() or geom_obj.is_line() or geom_obj.is_point(): for vtx in geom_obj.vrtx_arr: out_fp.write("v {0:f} {1:f} {2:f}\n".format(vtx.xyz[0], vtx.xyz[1], vtx.xyz[2])) out_fp.write("g main\n") if geom_obj.is_trgl(): out_fp.write("usemtl colouring\n") for fac in geom_obj.trgl_arr: out_fp.write("f {0:d} {1:d} {2:d}\n".format(vert_dict[fac.abc[0]], vert_dict[fac.abc[1]], vert_dict[fac.abc[2]])) elif geom_obj.is_line(): for seg in geom_obj.seg_arr: out_fp.write("l {0:d} {1:d}\n".format(vert_dict[seg.ab[0]], vert_dict[seg.ab[1]])) elif geom_obj.is_point(): out_fp.write("p") for pnt in range(len(geom_obj.vrtx_arr)): out_fp.write(" {0:d}".format(pnt+1)) out_fp.write("\n") elif geom_obj.is_volume(): ct_done = self.write_voxel_obj(out_fp, file_name, src_file_str, 64, False) out_fp.close() # Create an MTL file for the colour rgba_tup = style_obj.get_rgba_tup() if len(rgba_tup) == 4 and not ct_done: out_fp = open(file_name+".MTL", 'w') out_fp.write("# Wavefront MTL file converted from '{0}'\n\n".format(src_file_str)) out_fp.write("newmtl colouring\n") out_fp.write("Ka {0:.3f} {1:.3f} {2:.3f}\n".format(rgba_tup[0], rgba_tup[1], rgba_tup[2])) out_fp.write("Kd {0:.3f} {1:.3f} {2:.3f}\n".format(rgba_tup[0], rgba_tup[1], rgba_tup[2])) out_fp.write("Ks 0.000 0.000 0.000\n") out_fp.write("d 1.0\n") out_fp.close()