def execute(self, context): if self.use_abso == True: extra_helper = (self.abso_major_rad - self.abso_minor_rad) * 0.5 self.major_radius = self.abso_minor_rad + extra_helper self.minor_radius = extra_helper verts_loc, faces = add_torus(self.major_radius, self.minor_radius, self.major_segments, self.minor_segments) mesh = bpy.data.meshes.new("Torus") mesh.vertices.add(len(verts_loc) // 3) mesh.faces.add(len(faces) // 4) mesh.vertices.foreach_set("co", verts_loc) mesh.faces.foreach_set("vertices_raw", faces) mesh.update() import add_object_utils add_object_utils.object_data_add(context, mesh, operator=self) return {'FINISHED'}
def create_mesh_object(context, verts, edges, faces, name, operator=None): # Create new mesh mesh = bpy.data.meshes.new(name) # Make a mesh from a list of verts/edges/faces. mesh.from_pydata(verts, edges, faces) # Update mesh geometry after adding stuff. mesh.update() return object_data_add(context, mesh, operator)
def execute(self, context): verts_loc, faces = add_box(self.width, self.height, self.depth, ) mesh = bpy.data.meshes.new("Box") mesh.vertices.add(len(verts_loc) // 3) mesh.faces.add(len(faces) // 4) mesh.vertices.foreach_set("co", verts_loc) mesh.faces.foreach_set("vertices_raw", faces) mesh.update() # add the mesh as an object into the scene with this utility module import add_object_utils add_object_utils.object_data_add(context, mesh, operator=self) return {'FINISHED'}
def execute(self, context): verts_loc, faces = add_box( self.width, self.height, self.depth, ) mesh = bpy.data.meshes.new("Box") mesh.vertices.add(len(verts_loc) // 3) mesh.faces.add(len(faces) // 4) mesh.vertices.foreach_set("co", verts_loc) mesh.faces.foreach_set("vertices_raw", faces) mesh.update() # add the mesh as an object into the scene with this utility module import add_object_utils add_object_utils.object_data_add(context, mesh, operator=self) return {'FINISHED'}
def create_mesh_object(context, verts, edges, faces, name): scene = context.scene obj_act = scene.objects.active # Create new mesh mesh = bpy.data.meshes.new(name) # Make a mesh from a list of verts/edges/faces. mesh.from_pydata(verts, edges, faces) # Update mesh geometry after adding stuff. mesh.update() import add_object_utils return add_object_utils.object_data_add(context, mesh, operator=None)
def create_mesh_object(context, verts, edges, faces, name): # Create new mesh mesh = bpy.data.meshes.new(name) # Make a mesh from a list of verts/edges/faces. mesh.from_pydata(verts, edges, faces) # Remove doubles #bpy.ops.mesh.remove_doubles(threshold=0.0001, use_unselected=True) # Update mesh geometry after adding stuff. mesh.update() v = bpy.app.version if (v[0] == 2 and v[1] > 57) or (v[0] > 2): # Blender 2.58 and 2.63a or future versions... from bpy_extras.object_utils import object_data_add return object_data_add(context, mesh, operator=None) else: # Blender 2.57 import add_object_utils return add_object_utils.object_data_add(context, mesh, operator=None)
def execute(self, context): # only keep image if using it if not self.image_based: if self.image: if self.image.users: self.image.user_clear() if self.image.name in bpy.data.images: bpy.data.images.remove(self.image) self.image = None # Toggle Edit mode try: is_editmode = (context.active_object.mode == 'EDIT') except: is_editmode = False if is_editmode: bpy.ops.object.mode_set(mode='OBJECT') verts_u = self.faces_u + 1 verts_v = self.faces_v + 1 if self.wrap_u and self.faces_u == 1: verts_u += 1 if self.wrap_v and self.faces_v == 1: verts_v += 1 uvgrid_u = [] uvgrid_v = [] uvgrid_s = [] uvgrid_t = [] if self.sculpty: # get settings from sculpty map size function s, t, w, h, clean_s, clean_t = map_size(verts_u - 1, verts_v - 1, self.subdivision) else: # fixed u v spacing w = h = 1 s = verts_u - 1 t = verts_v - 1 clean_s = False clean_t = False verts_u = s + 1 verts_v = t + 1 actual_u = verts_u - self.wrap_u actual_v = verts_v - self.wrap_v clean_s = clean_s & self.sculpty_clean clean_t = clean_t & self.sculpty_clean level_mask = 0xFFFE for i in range(self.subdivision): level_mask = level_mask << 1 # uvgrid_s and uvgrid_t will hold uv layout positions for i in range(s): p = w * i / float(s) if clean_s: p = int(p) & level_mask if p: p = p / float(w) uvgrid_s.append(p) uvgrid_s.append(1.0) for i in range(t): p = h * i / float(t) if clean_t: p = int(p) & level_mask if p: p = p / float(h) uvgrid_t.append(p) uvgrid_t.append(1.0) # build list of 3D locations for vertices verts = [] for self.v in range(actual_v): for self.u in range(actual_u): vec_u = self.u / (verts_u - 1) if self.wrap_u: vec_u += self.rotate_u / 360.0 vec_v = self.v / (verts_v - 1) if self.wrap_v: vec_v += self.rotate_v / 360.0 verts.append(self.get_vector(vec_u, vec_v)) # build list of faces faces = [] first_row = range(actual_u) for v in range(1, actual_v): second_row = [idx + actual_u for idx in first_row] faces.extend(createFaces(first_row, second_row, self.wrap_u)) first_row = second_row if self.wrap_v: faces.extend(createFaces(second_row, range(actual_u), self.wrap_u)) # build list of seams - these should be all edges with # u=0 and/or with v=0 depending on wrap settings seams = [] if self.wrap_u: first_vertex = 0 for i in range(actual_v - 1): second_vertex = first_vertex + actual_u seams.append((first_vertex, second_vertex)) first_vertex = second_vertex if self.wrap_v: seams.append((0, first_vertex)) if self.wrap_v: first_vertex = 0 for i in range(actual_u - 1): second_vertex = first_vertex + 1 seams.append((first_vertex, second_vertex)) first_vertex = second_vertex if self.wrap_u: seams.append((0, first_vertex)) create_mesh_object(context, verts, [], faces, self.obj_name, self) obj = context.active_object # end up in edit mode here if set in preferences, so set back. bpy.ops.object.mode_set(mode='OBJECT') markSeams(obj.data, seams) # build list of uv faces uvfaces = [] first_row = [(uvgrid_s[u], 0.0) for u in range(verts_u)] for v in range(1, verts_v): second_row = [(uvgrid_s[u], uvgrid_t[v]) for u in range(verts_u)] faces = createFaces(first_row, second_row, False) if self.wrap_u: # match face order of wrapped mesh faces = [faces[-1]] + faces[:-1] # correct vert order for wrapped face fix = faces[0] faces[0] = (fix[2], fix[3], fix[0], fix[1]) uvfaces.extend(faces) first_row = second_row # create UVTex layout uvtex = obj.data.uv_textures.new() for face_idx in range(len(uvfaces)): uvtex.data[face_idx].uv1 = uvfaces[face_idx][0] uvtex.data[face_idx].uv2 = uvfaces[face_idx][1] uvtex.data[face_idx].uv3 = uvfaces[face_idx][2] uvtex.data[face_idx].uv4 = uvfaces[face_idx][3] if self.sculpty: if self.uvtex: s_map = obj.data.uv_textures.new(name="sculptie") else: s_map = uvtex s_map.name = "sculptie" if self.image == None: if not config.minimise_map: levels = self.subdivision while w * h <= 1024: levels += 1 s, t, w, h, cs, ct = map_size(uc, vc, levels) self.image = bpy.data.images.new(name=self.obj_name, width=w, height=h, alpha=True) for f in s_map.data: f.image = self.image f.use_image = True obj.prim.type = 'PRIM_TYPE_SCULPT' obj.prim.sculpt_type = self.sculpt_type if self.subdivision: bpy.ops.object.modifier_add(type=self.subdivision_mod) if self.subdivision_mod == 'MULTIRES': m = obj.modifiers['Multires'] m.subdivision_type = self.subdivision_type if self.sculpty: uv_layer = 'sculptie' else: uv_layer = 'UVTex' for i in range(self.subdivision): bpy.ops.object.multires_subdivide(modifier="Multires") hires = obj.to_mesh(context.scene, True, 'RENDER') for v, uv in vertex_uvs(hires, uv_layer): vec_u = uv[0] if self.wrap_u: vec_u += self.rotate_u / 360.0 vec_v = uv[1] if self.wrap_v: vec_v += self.rotate_v / 360.0 v.co = self.get_vector(vec_u, vec_v) object_data_add(context, hires, self) obj2 = context.active_object context.scene.objects.active = obj bpy.ops.object.multires_reshape(modifier="Multires") context.scene.objects.unlink(obj2) bpy.data.objects.remove(obj2) bpy.data.meshes.remove(hires) bpy.ops.object.multires_base_apply(modifier="Multires") else: m = obj.modifiers['Subsurf'] m.subdivision_type = self.subdivision_type m.levels = self.subdivision m.render_levels = self.subdivision m.use_subsurf_uv = False m.show_on_cage = True bpy.ops.object.mode_set(mode='EDIT') # blender bug: inside not working when set to self.flip_normals bpy.ops.mesh.normals_make_consistent(inside=False) if self.flip_normals: bpy.ops.mesh.flip_normals() # arrgh.. still not flipping cone normals correctly.. # works if done manually.. test again when bug fixed.. if self.smooth: bpy.ops.mesh.faces_shade_smooth() if not (is_editmode or \ context.user_preferences.edit.use_enter_edit_mode): bpy.ops.object.mode_set(mode='OBJECT') return {'FINISHED'}
def execute(self, context): # only keep image if using it if not self.image_based: if self.image: if self.image.users: self.image.user_clear() if self.image.name in bpy.data.images: bpy.data.images.remove(self.image) self.image = None # Toggle Edit mode try: is_editmode = (context.active_object.mode == 'EDIT') except: is_editmode = False if is_editmode: bpy.ops.object.mode_set(mode='OBJECT') verts_u = self.faces_u + 1 verts_v = self.faces_v + 1 if self.wrap_u and self.faces_u == 1: verts_u += 1 if self.wrap_v and self.faces_v == 1: verts_v += 1 uvgrid_u = [] uvgrid_v = [] uvgrid_s = [] uvgrid_t = [] if self.sculpty: # get settings from sculpty map size function s, t, w, h, clean_s, clean_t = map_size( verts_u - 1, verts_v - 1, self.subdivision) else: # fixed u v spacing w = h = 1 s = verts_u - 1 t = verts_v - 1 clean_s = False clean_t = False verts_u = s + 1 verts_v = t + 1 actual_u = verts_u - self.wrap_u actual_v = verts_v - self.wrap_v clean_s = clean_s & self.sculpty_clean clean_t = clean_t & self.sculpty_clean level_mask = 0xFFFE for i in range(self.subdivision): level_mask = level_mask << 1 # uvgrid_s and uvgrid_t will hold uv layout positions for i in range(s): p = w * i / float(s) if clean_s: p = int(p) & level_mask if p: p = p / float(w) uvgrid_s.append(p) uvgrid_s.append(1.0) for i in range(t): p = h * i / float(t) if clean_t: p = int(p) & level_mask if p: p = p / float(h) uvgrid_t.append(p) uvgrid_t.append(1.0) # build list of 3D locations for vertices verts = [] for self.v in range(actual_v): for self.u in range(actual_u): vec_u = self.u / (verts_u - 1) if self.wrap_u: vec_u += self.rotate_u / 360.0 vec_v = self.v / (verts_v - 1) if self.wrap_v: vec_v += self.rotate_v / 360.0 verts.append(self.get_vector(vec_u, vec_v)) # build list of faces faces = [] first_row = range(actual_u) for v in range(1, actual_v): second_row = [idx + actual_u for idx in first_row] faces.extend(createFaces(first_row, second_row, self.wrap_u)) first_row = second_row if self.wrap_v: faces.extend(createFaces(second_row, range(actual_u), self.wrap_u)) # build list of seams - these should be all edges with # u=0 and/or with v=0 depending on wrap settings seams = [] if self.wrap_u: first_vertex = 0 for i in range(actual_v - 1): second_vertex = first_vertex + actual_u seams.append((first_vertex, second_vertex)) first_vertex = second_vertex if self.wrap_v: seams.append((0, first_vertex)) if self.wrap_v: first_vertex = 0 for i in range(actual_u - 1): second_vertex = first_vertex + 1 seams.append((first_vertex, second_vertex)) first_vertex = second_vertex if self.wrap_u: seams.append((0, first_vertex)) create_mesh_object(context, verts, [], faces, self.obj_name, self) obj = context.active_object # end up in edit mode here if set in preferences, so set back. bpy.ops.object.mode_set(mode='OBJECT') markSeams(obj.data, seams) # build list of uv faces uvfaces = [] first_row = [(uvgrid_s[u], 0.0) for u in range(verts_u)] for v in range(1, verts_v): second_row = [(uvgrid_s[u], uvgrid_t[v]) for u in range(verts_u)] faces = createFaces(first_row, second_row, False) if self.wrap_u: # match face order of wrapped mesh faces = [faces[-1]] + faces[:-1] # correct vert order for wrapped face fix = faces[0] faces[0] = (fix[2], fix[3], fix[0], fix[1]) uvfaces.extend(faces) first_row = second_row # create UVTex layout uvtex = obj.data.uv_textures.new() for face_idx in range(len(uvfaces)): uvtex.data[face_idx].uv1 = uvfaces[face_idx][0] uvtex.data[face_idx].uv2 = uvfaces[face_idx][1] uvtex.data[face_idx].uv3 = uvfaces[face_idx][2] uvtex.data[face_idx].uv4 = uvfaces[face_idx][3] if self.sculpty: if self.uvtex: s_map = obj.data.uv_textures.new(name="sculptie") else: s_map = uvtex s_map.name = "sculptie" if self.image == None: if not config.minimise_map: levels = self.subdivision while w * h <= 1024: levels += 1 s, t, w, h, cs, ct = map_size(uc, vc, levels) self.image = bpy.data.images.new(name=self.obj_name, width=w, height=h, alpha=True) for f in s_map.data: f.image = self.image f.image!=None obj.prim.type = 'PRIM_TYPE_SCULPT' obj.prim.sculpt_type = self.sculpt_type if self.subdivision: bpy.ops.object.modifier_add(type=self.subdivision_mod) if self.subdivision_mod == 'MULTIRES': m = obj.modifiers['Multires'] m.subdivision_type = self.subdivision_type if self.sculpty: uv_layer = 'sculptie' else: uv_layer = 'UVTex' for i in range(self.subdivision): bpy.ops.object.multires_subdivide(modifier="Multires") hires = obj.to_mesh(context.scene, True, 'RENDER') for v, uv in vertex_uvs(hires, uv_layer): vec_u = uv[0] if self.wrap_u: vec_u += self.rotate_u / 360.0 vec_v = uv[1] if self.wrap_v: vec_v += self.rotate_v / 360.0 v.co = self.get_vector(vec_u, vec_v) object_data_add(context, hires, self) obj2 = context.active_object context.scene.objects.active = obj bpy.ops.object.multires_reshape(modifier="Multires") context.scene.objects.unlink(obj2) bpy.data.objects.remove(obj2) bpy.data.meshes.remove(hires) bpy.ops.object.multires_base_apply(modifier="Multires") else: m = obj.modifiers['Subsurf'] m.subdivision_type = self.subdivision_type m.levels = self.subdivision m.render_levels = self.subdivision m.use_subsurf_uv = False m.show_on_cage = True bpy.ops.object.mode_set(mode='EDIT') # blender bug: inside not working when set to self.flip_normals bpy.ops.mesh.normals_make_consistent(inside=False) if self.flip_normals: bpy.ops.mesh.flip_normals() # arrgh.. still not flipping cone normals correctly.. # works if done manually.. test again when bug fixed.. if self.smooth: bpy.ops.mesh.faces_shade_smooth() if not (is_editmode or \ context.user_preferences.edit.use_enter_edit_mode): bpy.ops.object.mode_set(mode='OBJECT') return {'FINISHED'}
def Cells(object, cell, solid = False): print("L130 ===Cells called=== object is =",object.name," cell is", cell.name) t0 = time() es = [Vector((1.0, 0.0, 0.0)), Vector((0.0, 1.0, 0.0)), Vector((0.0, 0.0, 1.0))] # transform object/mesh (to get cell-alignment right) ###################################################### cm = cell.matrix_local.copy() cmi = cm.inverted() # is different matrix! om = object.matrix_local.copy() omi = om.inverted() tm = om * cmi tmi = cm * omi mesh = object.data # transform mesh to align with cell mesh.transform(tm) # calculate cell dimensions ########################### boundingbox is a box with (0 1 2 3)(4 5 6 7) # 0 and 6 are diagonal 1 7, 2 4, 3 5 too cell_gbb_min = cell.bound_box[0] #for debug pkhg print("L153 cellinfo =",type(cell_gbb_min),cell_gbb_min) cell_lbb_min = Vector(cell_gbb_min).to_4d() * cmi cell_lbb_max = cell.bound_box[6] cell_lbb_max = Vector(cell_lbb_max).to_4d() * cmi cell_dimensions = cell_lbb_max - cell_lbb_min cell_dimension_x,cell_dimension_y,cell_dimension_z = cell_dimensions[0:3] # bin vertices ############## # everything in object's local coordinates (aligned with cell) v_cells = {} for vert in mesh.vertices: coords = vert.co v_cells[vert.index] = (int(round(coords[0] / cell_dimension_x)), int(round(coords[1] / cell_dimension_y)), int(round(coords[2] / cell_dimension_z))) #dbg pkhg print("L161 v_CELLS",v_cells) # bin faces ########### # everything in object's local coordinates (aligned with cell) f_cells = {} for face in mesh.faces: verts = face.vertices #dbg pkhg print("L190 verts",verts[:]) fidxs = [v_cells[vert][0] for vert in verts] #dbg pkhg print("l192 fidxs ",fidxs,min(fidxs)) fidxs.sort() min_fidx = fidxs[0] max_fidx = fidxs[-1] fidys = [v_cells[vert][1] for vert in verts] fidys.sort() min_fidy = fidys[0] max_fidy = fidys[-1] fidzs = [v_cells[vert][2] for vert in verts] fidzs.sort() min_fidz = fidzs[0] max_fidz = fidzs[-1] # fast path for special cases (especially small faces spanning a single cell only) category = 0 if (max_fidx > min_fidx): category |= 1 if (max_fidy > min_fidy): category |= 2 if (max_fidz > min_fidz): category |= 4 if category == 0: # single cell f_cells.setdefault((min_fidx, min_fidy, min_fidz), set()).add(face) continue if category == 1: # multiple cells in x-, single cell in y- and z-direction for fidx in range(min_fidx, max_fidx + 1): f_cells.setdefault((fidx, min_fidy, min_fidz), set()).add(face) continue if category == 2: # multiple cells in y-, single cell in x- and z-direction for fidy in range(min_fidy, max_fidy + 1): f_cells.setdefault((min_fidx, fidy, min_fidz), set()).add(face) continue if category == 4: # multiple cells in z-, single cell in x- and y-direction for fidz in range(min_fidz, max_fidz + 1): f_cells.setdefault((min_fidx, min_fidy, fidz), set()).add(face) continue # long path (face spans multiple cells in more than one direction) ########### pkhg ???? I think I have not checked this??? possible? ########## a0 = face.normal r0 = 0.5 * (fabs(a0[0]) * cell_dimension_x + fabs(a0[1]) * cell_dimension_y + fabs(a0[2]) * cell_dimension_z) #xrange -> range?! cc = Vector((0.0, 0.0, 0.0)) for fidx in range(min_fidx, max_fidx + 1): cc[0] = fidx * cell_dimensions[0] for fidy in range(min_fidy, max_fidy + 1): cc[1] = fidy * cell_dimensions[1] for fidz in range(min_fidz, max_fidz + 1): cc[2] = fidz * cell_dimensions[2] if not solid and (fidx, fidy, fidz) in f_cells: continue # cell already populated -> no further processing needed for hollow model vertsNew = [mesh.vertices[el] for el in verts] #dbg pkhg print("L261-----------\n verts vertsNew",verts[:], vertsNew[:]) vs = [vert.co - cc for vert in vertsNew] if not (-r0 <= a0 * vs[0] <= r0): continue # cell not intersecting face hyperplane # check overlap of cell with face (separating axis theorem) fs = [vs[1] - vs[0], vs[2] - vs[1], vs[0] - vs[2]] overlap = True for f in fs: if not overlap: break for e in es: if not overlap: break # a = CrossVecs(e, f) a = e.cross(f) r = 0.5 * (fabs(a[0]) * cell_dimension_x + fabs(a[1]) * cell_dimension_y + fabs(a[2]) * cell_dimension_z) ds = [a * v for v in vs] ds.sort() if (ds[0] > r or ds[-1] < -r): overlap = False if overlap: f_cells.setdefault((fidx, fidy, fidz), set()).add(face) # the hollow voxel representation is complete #dbg pkhg print("L301 f_cells = ",f_cells) #dbg for i,el in enumerate(f_cells.keys()): #dbg tmp = [t.index for t in f_cells[el]] #dbg print("L298",tmp) # fill ###### if solid: # find min, max cells in x, y, z ##### ERROR f_cell may contain only two elments!???? for open? idxs = [id[0] for id in f_cells] min_idx = min(idxs) max_idx = max(idxs) idys = [id[1] for id in f_cells] min_idy = min(idys) max_idy = max(idys) idzs = [id[2] for id in f_cells] min_idz = min(idzs) max_idz = max(idzs) testpoint = Vector((0.0, 0.0, 0.0)) # for x,y for idx in range(min_idx, max_idx + 1): testpoint[0] = idx * cell_dimension_x for idy in range(min_idy, max_idy + 1): testpoint[1] = idy * cell_dimension_y odd_parity = False tested_faces = set() # walk the z pile and keep track of parity for idz in range(min_idz, max_idz + 1): fs = f_cells.get((idx, idy, idz), set()) - tested_faces # cell contains faces if fs: # categorize faces in this cell by normal pfaces = [] nfaces = [] for f in fs: fnoz = f.normal[2] #was no pkhg if fnoz >= 0.0: pfaces.append(f) if fnoz <= 0.0: nfaces.append(f) tested_faces.add(f) # check if testpoint inside z projections if pfaces: #,mesh added in InsideZProjection pkhg if InsideZProjection(testpoint, pfaces,mesh): odd_parity = not odd_parity if nfaces: if InsideZProjection(testpoint, nfaces,mesh): odd_parity = not odd_parity # cell contains no faces (empty cell) else: if odd_parity: f_cells[(idx, idy, idz)] = 1 # odd parity -> empty cell inside object # create new object ################### mesh_new = bpy.data.meshes.new("Cells("+object.name+")") vertexList = [[(id[0] * cell_dimension_x,id[1] * cell_dimension_y, id[2] * cell_dimension_z)] for id in f_cells] #### debug ??? ##### # print("L386===============================\n f_cells=",f_cells) # print("L369 =========\n vertexList =",vertexList) # for el in vertexList:print(el) # scene = Scene.GetCurrent() scene = bpy.context.scene mesh_new = bpy.data.meshes.new("Cells("+object.name+")") #####startpkhg added edges = [] faces = [] verts = [] for el in vertexList: verts.extend(el) mesh_new.from_pydata(verts, edges, faces) # Update mesh geometry after adding stuff. mesh_new.update() import add_object_utils add_object_utils.object_data_add(bpy.context, mesh_new, operator=None) object_new = bpy.context.active_object #dbg pkhg print("\n---------L409 object_new",object_new,object_new.name) ########end pkhg added object_new.layers = object.layers object_new.name = "Cells("+object.name+")" # transform objects/meshes back ############################### object_new.matrix_local = om mesh.transform(tmi) mesh_new.transform(tmi) # parent new object to cell for dupliverts ########################################### cell.location = object.location cell.layers = object_new.layers scene.update() #??? object.select = True # object_new.select = False # cell.select = False #??? bpy.ops.object.editmode_toggle() #co oc no # cell.select = True # object_new.select = True # bpy.ops.object.editmode_toggle() # bpy.ops.object.editmode_toggle() # bpy.context.scene.objects.active = cell # bpy.ops.object.select_all(action='TOGGLE') # cell.select = True # object_new.select = True #bpy.ops.object.parent_set(type='OBJECT') # object_new.makeParent([cell]) object_new.dupli_type = "VERTS" # select ######## object.select = False cell.select= False # object_new.select= True # done ###### t1 = time() print(str(len(mesh.faces))+" faces ... "+str(len(f_cells))+" cells: "+str(round(t1-t0, 3))+" s") bpy.context.scene.update() return object_new
def Cells(object, cell, solid=False): print("L130 ===Cells called=== object is =", object.name, " cell is", cell.name) t0 = time() es = [ Vector((1.0, 0.0, 0.0)), Vector((0.0, 1.0, 0.0)), Vector((0.0, 0.0, 1.0)) ] # transform object/mesh (to get cell-alignment right) ###################################################### cm = cell.matrix_local.copy() cmi = cm.inverted() # is different matrix! om = object.matrix_local.copy() omi = om.inverted() tm = om * cmi tmi = cm * omi mesh = object.data # transform mesh to align with cell mesh.transform(tm) # calculate cell dimensions ########################### boundingbox is a box with (0 1 2 3)(4 5 6 7) # 0 and 6 are diagonal 1 7, 2 4, 3 5 too cell_gbb_min = cell.bound_box[0] #for debug pkhg print("L153 cellinfo =",type(cell_gbb_min),cell_gbb_min) cell_lbb_min = Vector(cell_gbb_min).to_4d() * cmi cell_lbb_max = cell.bound_box[6] cell_lbb_max = Vector(cell_lbb_max).to_4d() * cmi cell_dimensions = cell_lbb_max - cell_lbb_min cell_dimension_x, cell_dimension_y, cell_dimension_z = cell_dimensions[0:3] # bin vertices ############## # everything in object's local coordinates (aligned with cell) v_cells = {} for vert in mesh.vertices: coords = vert.co v_cells[vert.index] = (int(round(coords[0] / cell_dimension_x)), int(round(coords[1] / cell_dimension_y)), int(round(coords[2] / cell_dimension_z))) #dbg pkhg print("L161 v_CELLS",v_cells) # bin faces ########### # everything in object's local coordinates (aligned with cell) f_cells = {} for face in mesh.faces: verts = face.vertices #dbg pkhg print("L190 verts",verts[:]) fidxs = [v_cells[vert][0] for vert in verts] #dbg pkhg print("l192 fidxs ",fidxs,min(fidxs)) fidxs.sort() min_fidx = fidxs[0] max_fidx = fidxs[-1] fidys = [v_cells[vert][1] for vert in verts] fidys.sort() min_fidy = fidys[0] max_fidy = fidys[-1] fidzs = [v_cells[vert][2] for vert in verts] fidzs.sort() min_fidz = fidzs[0] max_fidz = fidzs[-1] # fast path for special cases (especially small faces spanning a single cell only) category = 0 if (max_fidx > min_fidx): category |= 1 if (max_fidy > min_fidy): category |= 2 if (max_fidz > min_fidz): category |= 4 if category == 0: # single cell f_cells.setdefault((min_fidx, min_fidy, min_fidz), set()).add(face) continue if category == 1: # multiple cells in x-, single cell in y- and z-direction for fidx in range(min_fidx, max_fidx + 1): f_cells.setdefault((fidx, min_fidy, min_fidz), set()).add(face) continue if category == 2: # multiple cells in y-, single cell in x- and z-direction for fidy in range(min_fidy, max_fidy + 1): f_cells.setdefault((min_fidx, fidy, min_fidz), set()).add(face) continue if category == 4: # multiple cells in z-, single cell in x- and y-direction for fidz in range(min_fidz, max_fidz + 1): f_cells.setdefault((min_fidx, min_fidy, fidz), set()).add(face) continue # long path (face spans multiple cells in more than one direction) ########### pkhg ???? I think I have not checked this??? possible? ########## a0 = face.normal r0 = 0.5 * (fabs(a0[0]) * cell_dimension_x + fabs(a0[1]) * cell_dimension_y + fabs(a0[2]) * cell_dimension_z) #xrange -> range?! cc = Vector((0.0, 0.0, 0.0)) for fidx in range(min_fidx, max_fidx + 1): cc[0] = fidx * cell_dimensions[0] for fidy in range(min_fidy, max_fidy + 1): cc[1] = fidy * cell_dimensions[1] for fidz in range(min_fidz, max_fidz + 1): cc[2] = fidz * cell_dimensions[2] if not solid and (fidx, fidy, fidz) in f_cells: continue # cell already populated -> no further processing needed for hollow model vertsNew = [mesh.vertices[el] for el in verts] #dbg pkhg print("L261-----------\n verts vertsNew",verts[:], vertsNew[:]) vs = [vert.co - cc for vert in vertsNew] if not (-r0 <= a0 * vs[0] <= r0): continue # cell not intersecting face hyperplane # check overlap of cell with face (separating axis theorem) fs = [vs[1] - vs[0], vs[2] - vs[1], vs[0] - vs[2]] overlap = True for f in fs: if not overlap: break for e in es: if not overlap: break # a = CrossVecs(e, f) a = e.cross(f) r = 0.5 * (fabs(a[0]) * cell_dimension_x + fabs(a[1]) * cell_dimension_y + fabs(a[2]) * cell_dimension_z) ds = [a * v for v in vs] ds.sort() if (ds[0] > r or ds[-1] < -r): overlap = False if overlap: f_cells.setdefault((fidx, fidy, fidz), set()).add(face) # the hollow voxel representation is complete #dbg pkhg print("L301 f_cells = ",f_cells) #dbg for i,el in enumerate(f_cells.keys()): #dbg tmp = [t.index for t in f_cells[el]] #dbg print("L298",tmp) # fill ###### if solid: # find min, max cells in x, y, z ##### ERROR f_cell may contain only two elments!???? for open? idxs = [id[0] for id in f_cells] min_idx = min(idxs) max_idx = max(idxs) idys = [id[1] for id in f_cells] min_idy = min(idys) max_idy = max(idys) idzs = [id[2] for id in f_cells] min_idz = min(idzs) max_idz = max(idzs) testpoint = Vector((0.0, 0.0, 0.0)) # for x,y for idx in range(min_idx, max_idx + 1): testpoint[0] = idx * cell_dimension_x for idy in range(min_idy, max_idy + 1): testpoint[1] = idy * cell_dimension_y odd_parity = False tested_faces = set() # walk the z pile and keep track of parity for idz in range(min_idz, max_idz + 1): fs = f_cells.get((idx, idy, idz), set()) - tested_faces # cell contains faces if fs: # categorize faces in this cell by normal pfaces = [] nfaces = [] for f in fs: fnoz = f.normal[2] #was no pkhg if fnoz >= 0.0: pfaces.append(f) if fnoz <= 0.0: nfaces.append(f) tested_faces.add(f) # check if testpoint inside z projections if pfaces: #,mesh added in InsideZProjection pkhg if InsideZProjection(testpoint, pfaces, mesh): odd_parity = not odd_parity if nfaces: if InsideZProjection(testpoint, nfaces, mesh): odd_parity = not odd_parity # cell contains no faces (empty cell) else: if odd_parity: f_cells[( idx, idy, idz )] = 1 # odd parity -> empty cell inside object # create new object ################### mesh_new = bpy.data.meshes.new("Cells(" + object.name + ")") vertexList = [[(id[0] * cell_dimension_x, id[1] * cell_dimension_y, id[2] * cell_dimension_z)] for id in f_cells] #### debug ??? ##### # print("L386===============================\n f_cells=",f_cells) # print("L369 =========\n vertexList =",vertexList) # for el in vertexList:print(el) # scene = Scene.GetCurrent() scene = bpy.context.scene mesh_new = bpy.data.meshes.new("Cells(" + object.name + ")") #####startpkhg added edges = [] faces = [] verts = [] for el in vertexList: verts.extend(el) mesh_new.from_pydata(verts, edges, faces) # Update mesh geometry after adding stuff. mesh_new.update() import add_object_utils add_object_utils.object_data_add(bpy.context, mesh_new, operator=None) object_new = bpy.context.active_object #dbg pkhg print("\n---------L409 object_new",object_new,object_new.name) ########end pkhg added object_new.layers = object.layers object_new.name = "Cells(" + object.name + ")" # transform objects/meshes back ############################### object_new.matrix_local = om mesh.transform(tmi) mesh_new.transform(tmi) # parent new object to cell for dupliverts ########################################### cell.location = object.location cell.layers = object_new.layers scene.update() #??? object.select = True # object_new.select = False # cell.select = False #??? bpy.ops.object.editmode_toggle() #co oc no # cell.select = True # object_new.select = True # bpy.ops.object.editmode_toggle() # bpy.ops.object.editmode_toggle() # bpy.context.scene.objects.active = cell # bpy.ops.object.select_all(action='TOGGLE') # cell.select = True # object_new.select = True #bpy.ops.object.parent_set(type='OBJECT') # object_new.makeParent([cell]) object_new.dupli_type = "VERTS" # select ######## object.select = False cell.select = False # object_new.select= True # done ###### t1 = time() print( str(len(mesh.faces)) + " faces ... " + str(len(f_cells)) + " cells: " + str(round(t1 - t0, 3)) + " s") bpy.context.scene.update() return object_new