# Covert normals to quake's normal palette. Implementation taken from ajmdl # # AJA: I use the following shortcuts to speed up normal lookup: # # Firstly, a preliminary match only uses the first quadrant # (where all coords are >= 0). Then we use the appropriate # normal index for the actual quadrant. We can do this because # the 162 MDL/MD2 normals are not arbitrary but are mirrored in # every quadrant. The eight numbers in the lists above are the # indices for each quadrant (+++ ++- +-+ +-- -++ -+- --+ ---). # # Secondly we use the axis with the greatest magnitude (of the # incoming normal) to search an axis-specific group, which means # we only need to check about 1/3rd of the normals. # Actually, about 1/14th (taniwha) x_group = ((Vector( (1.0000, 0.0000, 0.0000)), (52, 52, 52, 52, 143, 143, 143, 143)), (Vector( (0.9554, 0.2952, 0.0000)), (51, 51, 55, 55, 141, 141, 145, 145)), (Vector( (0.9511, 0.1625, 0.2629)), (53, 63, 57, 70, 142, 148, 146, 151)), (Vector((0.8642, 0.4429, 0.2389)), (46, 61, 56, 69, 19, 147, 123, 150)), (Vector( (0.8507, 0.5257, 0.0000)), (41, 41, 54, 54, 18, 18, 116, 116)), (Vector((0.8507, 0.0000, 0.5257)), (60, 67, 60, 67, 144, 155, 144, 155)), (Vector((0.8090, 0.3090, 0.5000)), (48, 62, 58, 68, 16, 149, 124, 152)), (Vector( (0.7166, 0.6817, 0.1476)), (42, 43, 111, 100, 20, 25, 118, 117)), (Vector( (0.6882, 0.5878, 0.4253)), (47, 76, 140, 101, 21, 156, 125, 161)), (Vector((0.6817, 0.1476, 0.7166)),
# repoducibility. If the noise should be randomize, call # randomize_distance_bias laser_noise = [ 0.015798891682948433, 0.030289711937446478, 0.044832263895615468, 0.022628361223111119 ] ## If the laser noise has to be truely randomize, call this function prior ## to every scan def randomize_distance_bias(noise_mu=0.0, noise_sigma=0.04): for idx in range(len(laser_angles)): laser_noise[idx] = random.gauss(noise_mu, noise_sigma) mirror = [Vector([0, 0, 0]), Vector([0, 0, 0]), Vector([0, 0, 0])] norm_mirror = Vector([0, 1, 0]) #Create a Triangle that represents the 45° mirror #rotated around the main axis by <angle> #The mirror has a side length of 1 meter which is more #than enough to fit the small square mirror inside this triangle def createMirror(angle): mirror[0].xyz = [0, -1, -1] mirror[1].xyz = [-1, 1, 1] mirror[2].xyz = [1, 1, 1] mirror[0].rotate(Matrix.Rotation(angle, 4, norm_mirror)) mirror[1].rotate(Matrix.Rotation(angle, 4, norm_mirror)) mirror[2].rotate(Matrix.Rotation(angle, 4, norm_mirror)) n = geometry.normal(mirror[2], mirror[1], mirror[0])
def read_tet_file(self): """Read the .tet file. """ data = list() # Open the file file = open(self.tet_file, 'r') # Read every line for line in file: # If line is a comment, ignore if '#' in line: continue # Get the number of vertices and tets if 'tet' in line: data_count = line continue data.append(line.strip('\n')) # Close the file file.close() # Get the number of vertices and faces from the data_count data_count = data_count.split(' ') number_vertices = int(data_count[1]) faces = int(data_count[2]) nmv.logger.log('The volumetric mesh has [%d] vertices and [%d] faces' % (number_vertices, faces)) # Get the vertices vertices = list() for i in range(number_vertices): vertex_data = data[i].split() vertex = Vector((float(vertex_data[0]), float(vertex_data[1]), float(vertex_data[2]))) vertices.append(vertex) # Get the faces faces = list() for i in range(number_vertices, len(data)): face_data = data[i].split() face = [ int(face_data[0]), int(face_data[1]), int(face_data[2]), int(face_data[3]) ] faces.append(face) # Create the tetrahedrons tetrahedrons = list() for i, face in enumerate(faces): tetrahedron = self.Tetrahedron() tetrahedron.index = i tetrahedron.face = face tetrahedrons.append(tetrahedron) # Create the tetrahedral mesh data structure tetrahedral_mesh_data = self.TetrahedralMeshData() tetrahedral_mesh_data.vertices = vertices tetrahedral_mesh_data.tetrahedrons = tetrahedrons # Return the mesh data return tetrahedral_mesh_data
def MINMAX_INIT(): return (Vector( (+FLT_MAX, +FLT_MAX, +FLT_MAX)), Vector( (-FLT_MAX, -FLT_MAX, -FLT_MAX)))
def extract(properties, *args, **kargs): filepath = bpy.path.abspath(properties.filepath) imagepaths = list( filter(None, bpy.path.abspath(properties.imagepath).split(';'))) if not os.path.exists(filepath): if not filepath: raise AttributeError(f'VisualSfM filepath must be provided') raise AttributeError(f'Unable to locate VisualSfM file:\n"{filepath}"') # # TODO: read list.txt to get image paths to detect image size # resolution_x = int(scene.render.resolution_x * (scene.render.resolution_percentage / 100)) with open(filepath, 'r') as f: lines = f.readlines() # TODO: read optional calibration from file (tuple stored against each camera as key 'principal' (x, y) floating-point pixels) if len(lines) == 0 or not lines[0].startswith('NVM_V3'): raise Exception('Not a valid NVM file') cameras = {} trackers = {} data = { 'trackers': trackers, 'cameras': cameras, } total_cameras = int(lines[2]) total_points = int(lines[4 + total_cameras]) # numbers: optional negative, digit(s), optional decimal point and following digit(s), optional scientific notation "e-0" num = r'-?\d+(?:\.\d+)?(?:e[+-]\d+)?' camera_re = re.compile( rf'^(?P<name>.*?)\s+(?P<f>{num})\s+(?P<QW>{num})\s+(?P<QX>{num})\s+(?P<QY>{num})\s+(?P<QZ>{num})\s+(?P<X>{num})\s+(?P<Y>{num})\s+(?P<Z>{num})\s+(?P<k1>{num})\s+{num}\s*$' ) for i in range(int(total_cameras)): # each camera uses 1 line match = camera_re.match(lines[3 + i]) if not match: raise Exception( f'Camera {i} did not match the format specification') # find any filename that exists filenames = [ fp for fp in [ os.path.join(*parts) for parts in zip(imagepaths, [ match.group('name'), ] * len(imagepaths)) ] if os.path.exists(fp) ] if not filenames: # wasn't in a root path, do we search sub directories? if properties.subdirs: for imagepath in imagepaths: for root, dirs, files in os.walk(imagepath): if match.group('name') in files: filenames = [ os.path.join(root, match.group('name')) ] # still didn't find file? if not filenames: raise AttributeError( f'VisualSfM image not found for camera {i}:\n"{match.group("name")}""' ) # create cameras q = Quaternion( tuple( map(float, [ match.group('QW'), match.group('QX'), match.group('QY'), match.group('QZ') ]))) """ https://github.com/SBCV/Blender-Addon-Photogrammetry-Importer/blob/75189215dffde50dad106144111a48f29b1fed32/photogrammetry_importer/file_handler/nvm_file_handler.py#L55 VisualSFM CAMERA coordinate system is the standard CAMERA coordinate system in computer vision (not the same as in computer graphics like in bundler, blender, etc.) That means the y axis in the image is pointing downwards (not upwards) the camera is looking along the positive z axis (points in front of the camera show a positive z value) The camera coordinate system in computer vision VISUALSFM uses camera matrices, which are rotated around the x axis by 180 degree i.e. the y and z axis of the CAMERA MATRICES are inverted """ R = q.to_matrix() R.rotate(Euler((pi, 0, 0))) R.transpose() c = Vector( tuple( map(float, [match.group('X'), match.group('Y'), match.group('Z')]))) t = -1 * R @ c R.transpose() # TODO: confirm whether the distortion coefficient needs inverting cameras.setdefault( i, { 'filename': filenames[0], 'f': float(match.group('f')), 'k': (float(match.group('k1')), 0, 0), 't': tuple(t), 'R': tuple(map(tuple, tuple(R))), 'trackers': {}, }) if 'resolution' not in data: data.setdefault('resolution', get_image_size(filenames[0])) marker_re = re.compile( rf'^(?P<X>{num})\s+(?P<Y>{num})\s+(?P<Z>{num})\s+(?P<R>\d+)\s+(?P<G>\d+)\s+(?P<B>\d+)\s+(?P<num_measurements>{num})\s+(?P<measurements>.*?)\s*$' ) measurement_re = re.compile( rf'^(?P<image_idx>\d+)\s+(?P<feature_idx>\d+)\s+(?P<X>{num})\s+(?P<Y>{num}).*' ) for i in range(int(total_points)): # each point uses a single line idx = 5 + int(total_cameras) + i match = marker_re.match(lines[idx]) if not match: raise AttributeError( f'VisualSfM marker {i} did not match the format specification') trackers.setdefault( i, { 'co': tuple( map(float, [match.group('X'), match.group('Y'), match.group('Z')])), 'rgb': tuple( map(int, [match.group('R'), match.group('G'), match.group('B')])), }) cur = match.group('measurements') for m in range(int(match.group('num_measurements'))): measurement_match = measurement_re.match(cur) if not measurement_match: raise AttributeError( f'VisualSfM marker {i} did not match measurement {m} format specification' ) # Let the measurement be (mx, my), which is relative to principal point (typically image center) # As for the image coordinate system, X-axis points right, and Y-axis points downward, so Z-axis points forward. cameras[int( measurement_match.group('image_idx'))]['trackers'].setdefault( i, (float(measurement_match.group('X')), -1 * float(measurement_match.group('Y')))) cur = cur[measurement_match.end(len(measurement_match.groups()) ):].strip() return data
def OD_PasteFromExternal(_name, size): file = tempfile.gettempdir() + os.sep + "ODVertexData.txt" if os.path.exists(file): f = open(file) lines = f.readlines() f.close() else: print("Cannot find file") vertline = [] polyline = [] uvMaps = [] morphMaps = [] weightMaps = [] count = 0 #Parse File to see what Data we have here for line in lines: if line.startswith("VERTICES:"): vertline.append( [int(line.strip().split(":")[1].strip()), count]) if line.startswith("POLYGONS:"): polyline.append( [int(line.strip().split(":")[1].strip()), count]) if line.startswith("UV:"): uvMaps.append( [line.strip().split(":")[1:], count] ) # changed this to add the # of uv coordinates into the mix if line.startswith("MORPH"): morphMaps.append([line.split(":")[1].strip(), count]) if line.startswith("WEIGHT"): weightMaps.append([line.split(":")[1].strip(), count]) count += 1 #create Points for v in vertline: verts = [] for i in range(v[1] + 1, v[1] + v[0] + 1): x = lines[i].split(" ") pt = [ float(x[0].strip()), float(x[2].strip()) * -1, float(x[1].strip()) ] verts.append(pt) blenderMats = bpy.data.materials[:] blenderMatsNames = [] for bm in blenderMats: blenderMatsNames.append(bm.name) for polygons in polyline: faces = [] facesMat = [] objMats = [] for i in range(polygons[1] + 1, polygons[1] + polygons[0] + 1): pts = [] surf = (lines[i].split(";;")[1]).strip() for x in (lines[i].split(";;")[0]).strip().split(","): pts.append(int(x.strip())) faces.append(pts) if surf not in blenderMatsNames: blenderMatsNames.append(surf) bpy.data.materials.new(surf) #obj.data.materials.append(blenderSurf) if surf not in objMats: objMats.append(surf) facesMat.append(surf) #remove old object first obj = bpy.context.active_object if obj != None: me = obj.data bpy.ops.object.mode_set(mode='OBJECT') facesr = me.polygons for f in facesr: f.select = 1 bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.delete(type='FACE') bpy.ops.object.mode_set(mode='OBJECT') mesh = me mesh.from_pydata(verts, [], faces) mesh.update() mesh.update() else: # the rest keep like in this example # here the mesh data is constructed mesh = bpy.data.meshes.new(_name) mesh.from_pydata(verts, [], faces) mesh.update() mesh.update() # now generate an object to hold this data obj = bpy.data.objects.new(_name, mesh) # link the object to the scene (it is not visible so far!) bpy.context.scene.objects.link(obj) for i in range(len(obj.material_slots)): bpy.ops.object.material_slot_remove({'object': obj}) for mat in objMats: obj.data.materials.append(bpy.data.materials.get(mat)) for i in range(len(faces)): obj.data.polygons[i].material_index = objMats.index( facesMat[i]) # create vertex group lookup dictionary for names vgroup_names = { vgroup.index: vgroup.name for vgroup in obj.vertex_groups } # create dictionary of vertex group assignments per vertex vgroups = { v.index: [vgroup_names[g.group] for g in v.groups] for v in obj.data.vertices } for x in obj.vertex_groups: obj.vertex_groups.remove(x) #setup weightmaps for weightMap in weightMaps: vg = obj.vertex_groups.new(weightMap[0]) count = 0 for v in range(len(verts)): if lines[weightMap[1] + 1 + count].strip() != "None": vg.add([v], float(lines[weightMap[1] + 1 + count].strip()), "ADD") count += 1 if obj.data.shape_keys != None: bpy.ops.object.shape_key_remove(all=True) #create Base Shape Key if len(morphMaps) > 0: shapeKey = obj.shape_key_add(from_mix=False) #shapeKey.name = "Base" for vert in obj.data.vertices: shapeKey.data[vert.index].co = vert.co #Set Morph Map Values for morphMap in morphMaps: shapeKey = obj.shape_key_add(from_mix=False) shapeKey.name = morphMap[0] count = 0 for vert in obj.data.vertices: if lines[morphMap[1] + 1 + count].strip() != "None": x = float(lines[morphMap[1] + 1 + count].split(" ")[0]) y = float(lines[morphMap[1] + 1 + count].split(" ")[1]) z = float( lines[morphMap[1] + 1 + count].split(" ")[2]) * -1 newVert = Vector( (vert.co[0] + x, vert.co[1] + z, vert.co[2] + y)) shapeKey.data[vert.index].co = newVert count += 1 for x in mesh.uv_textures: mesh.uv_textures.remove(x) for uvMap in uvMaps: uv = mesh.uv_textures.new(uvMap[0][0]) bm = bmesh.new() bm.from_mesh(mesh) bm.faces.ensure_lookup_table() uv_layer = bm.loops.layers.uv[uv.name] count = 0 for i in range(int(uvMap[0][1])): line = lines[uvMap[1] + 1 + count] split = line.split(":") if len( split ) > 3: #check the format to see if it has a point and poly classifier, determining with that, whether the uv is discontinuous or continuous face = (bm.faces[int(split[2])].loops[count % (len( bm.faces[int(split[2])].loops))])[uv_layer].uv = [ float(split[0].split(" ")[0]), float(split[0].split(" ")[1]) ] else: pass count += 1 bm.to_mesh(mesh) bpy.context.scene.update() # return the object to the function caller for further stuff return obj
def mode_callback(obj, data): for obj in set(bpy.context.selected_objects + [bpy.context.active_object]): if (not obj.data or not isinstance( obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve)) or not obj.BIMObjectProperties.ifc_definition_id or not bpy.context.scene.BIMProjectProperties.is_authoring): return product = IfcStore.get_file().by_id( obj.BIMObjectProperties.ifc_definition_id) parametric = ifcopenshell.util.element.get_psets(product).get( "EPset_Parametric") if not parametric or parametric["Engine"] != "BlenderBIM.DumbProfile": return if obj.mode == "EDIT": IfcStore.edited_objs.add(obj) bm = bmesh.from_edit_mesh(obj.data) bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges) bmesh.update_edit_mesh(obj.data) bm.free() else: material_usage = ifcopenshell.util.element.get_material(product) x, y = obj.dimensions[0:2] if not material_usage.CardinalPoint: new_origin = obj.matrix_world @ (Vector(obj.bound_box[0]) + (Vector((x, y, 0)) / 2)) elif material_usage.CardinalPoint == 1: new_origin = obj.matrix_world @ Vector(obj.bound_box[4]) elif material_usage.CardinalPoint == 2: new_origin = obj.matrix_world @ (Vector(obj.bound_box[0]) + (Vector((x, 0, 0)) / 2)) elif material_usage.CardinalPoint == 3: new_origin = obj.matrix_world @ Vector(obj.bound_box[0]) elif material_usage.CardinalPoint == 4: new_origin = obj.matrix_world @ (Vector(obj.bound_box[4]) + (Vector((0, y, 0)) / 2)) elif material_usage.CardinalPoint == 5: new_origin = obj.matrix_world @ (Vector(obj.bound_box[0]) + (Vector((x, y, 0)) / 2)) elif material_usage.CardinalPoint == 6: new_origin = obj.matrix_world @ (Vector(obj.bound_box[0]) + (Vector((0, y, 0)) / 2)) elif material_usage.CardinalPoint == 7: new_origin = obj.matrix_world @ Vector(obj.bound_box[7]) elif material_usage.CardinalPoint == 8: new_origin = obj.matrix_world @ (Vector(obj.bound_box[3]) + (Vector((x, 0, 0)) / 2)) elif material_usage.CardinalPoint == 9: new_origin = obj.matrix_world @ Vector(obj.bound_box[3]) if (obj.matrix_world.translation - new_origin).length < 0.001: return obj.data.transform( Matrix.Translation( (obj.matrix_world.inverted().to_quaternion() @ (obj.matrix_world.translation - new_origin)))) obj.matrix_world.translation = new_origin
import bpy import numpy as np from mathutils import Vector p = bpy.context.active_object.particle_systems['ParticleSystem'].particles locations = 10 * np.random.random((len(p), 3)) - 5 locations = [Vector(co) for co in locations] for pp, loc in zip(p, locations): pp.location = loc bpy.ops.wm.redraw_timer(type='DRAW', iterations=1)
#directory = '/home/arvardaz/SFT_with_CNN/' ##Delete all existing objects from scene except Camera and Plane scene = bpy.context.scene #for ob in scene.objects: # ob.select = True ## bpy.ops.object.track_clear(type='CLEAR') # if ob.name == "Camera" or ob.name == 'Plane': # ob.select = False ## bpy.ops.object.track_clear(type='CLEAR') #bpy.ops.object.delete() ## Camera object ############################################################## cam = bpy.data.objects["Camera"] cam.location = Vector((0, 40, 0)) look_at(cam, Vector((0, 0, 0))) ## Import object ############################################################## bpy.ops.import_scene.obj( filepath=directory + '3D_models/American_pillow/3d_decimated_norm/pillow_2k.obj') #Find object in scene scene = bpy.context.scene for ob in scene.objects: if not ('Camera' in ob.name or 'Plane' in ob.name or 'Sphere' in ob.name): obj_name = ob.name obj = bpy.data.objects[obj_name] # #Select object
def modal(self, context, event): context.area.tag_redraw() # update mouse self.mousepos = Vector((event.mouse_region_x, event.mouse_region_y)) # set snapping self.is_snapping = event.ctrl self.is_diverging = self.is_snapping and event.alt if not self.is_snapping: self.snap_coords = [] self.snap_proximity_coords = [] self.snap_ortho_coords = [] events = [ 'MOUSEMOVE', 'LEFT_CTRL', 'LEFT_ALT', 'RIGHT_CTRL', 'RIGHT_ALT' ] if event.type in events: if self.passthrough: self.passthrough = False # update the init_loc to compensate for the viewport change self.loc = self.get_slide_vector_intersection(context) self.init_loc = self.init_loc + self.loc - self.offset_loc # snap to edge elif event.ctrl: hitobj, hitlocation, hitnormal, hitindex, hitdistance, cache = cast_bvh_ray_from_mouse( self.mousepos, candidates=self.snappable, bmeshes=self.snap_bms, bvhs=self.snap_bvhs, debug=False) # cache bmeshes if cache['bmesh']: for name, bm in cache['bmesh'].items(): if name not in self.snap_bms: bm.faces.ensure_lookup_table() self.snap_bms[name] = bm # cache bvhs if cache['bvh']: for name, bvh in cache['bvh'].items(): if name not in self.snap_bvhs: self.snap_bvhs[name] = bvh # snap to geometry if hitobj: self.slide_snap(context, hitobj, hitlocation, hitindex) # side normally if nothing is hit else: self.snap_coords = [] self.snap_proximity_coords = [] self.snap_ortho_coords = [] self.loc = self.get_slide_vector_intersection(context) self.slide(context) # slide else: self.is_snapping = False self.loc = self.get_slide_vector_intersection(context) self.slide(context) # VIEWPORT control if event.type in {'MIDDLEMOUSE'}: # store the current location, so the view change can be taken into account self.offset_loc = self.get_slide_vector_intersection(context) self.passthrough = True return {'PASS_THROUGH'} # FINISH elif event.type in {'LEFTMOUSE', 'SPACE'}: # dissolve edges when snapping if self.is_snapping: # get the average distance that was moved avg_dist = sum( (v.co - data['co']).length for v, data in self.verts.items()) / len(self.verts) # use it for dissolveing to ensure it works on very small scales as you'd expect bmesh.ops.dissolve_degenerate(self.bm, edges=self.bm.edges, dist=avg_dist / 100) self.bm.normal_update() bmesh.update_edit_mesh(self.active.data) self.finish() return {'FINISHED'} # CANCEL elif event.type in {'RIGHTMOUSE', 'ESC'}: # reset original vert locations for v, data in self.verts.items(): v.co = data['co'] self.bm.normal_update() bmesh.update_edit_mesh(self.active.data) self.finish() return {'CANCELLED'} return {'RUNNING_MODAL'}
def invoke(self, context, event): # SLIDE EXTEND if self.slideoverride: bm = bmesh.from_edit_mesh(context.active_object.data) verts = [v for v in bm.verts if v.select] history = list(bm.select_history) if len(verts) == 1: popup_message("Select more than 1 vertex.") return {'CANCELLED'} elif not history: popup_message( "Select the last vertex without Box or Circle Select.") return {'CANCELLED'} else: self.active = context.active_object self.mx = self.active.matrix_world self.bm = bmesh.from_edit_mesh(self.active.data) self.bm.normal_update() # get selected verts selected = [v for v in bm.verts if v.select] history = list(self.bm.select_history) # get each vert that is slid and the target it pushed away from or towards # also store the initial location of the moved verts # multi target sliding if len(selected) > 3 and len(selected) % 2 == 0 and set( history) == set(selected): self.verts = { history[i]: { 'co': history[i].co.copy(), 'target': history[i + 1] } for i in range(0, len(history), 2) } # single target sliding else: last = history[-1] self.verts = { v: { 'co': v.co.copy(), 'target': last } for v in selected if v != last } # get average target and slid vert locations in world space self.target_avg = self.mx @ average_locations( [data['target'].co for _, data in self.verts.items()]) self.origin = self.mx @ average_locations( [v.co for v, _ in self.verts.items()]) # init mouse self.mousepos = Vector( (event.mouse_region_x, event.mouse_region_y)) # create first intersection of the view dir with the origin-to-targetavg vector self.init_loc = self.get_slide_vector_intersection(context) if self.init_loc: # init self.loc = self.init_loc self.offset_loc = self.init_loc self.distance = 0 self.coords = [] # init snapping self.is_snapping = False self.is_diverging = False self.snap_bms = {} self.snap_bvhs = {} self.snap_coords = [] self.snap_proximity_coords = [] self.snap_ortho_coords = [] # create copy of the active to raycast on, this prevents an issue where the raycast flips from one face to the other because moving a vert changes the topology self.active.update_from_editmode() self.snap_copy = self.active.copy() self.snap_copy.data = self.active.data.copy() # snappable objects are all edit mesh object nicluding the the active's copy edit_mesh_objects = [ obj for obj in context.visible_objects if obj.mode == 'EDIT' and obj != self.active ] self.snappable = edit_mesh_objects + [self.snap_copy] # handlers self.VIEW3D = bpy.types.SpaceView3D.draw_handler_add( self.draw_VIEW3D, (), 'WINDOW', 'POST_VIEW') # draw statusbar info self.bar_orig = statusbar.draw statusbar.draw = draw_slide_status(self) context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} return {'CANCELLED'} # MERGE and CONNECT else: self.smart_vert(context) return {'FINISHED'}
def main(context, island_margin, projection_limit, user_area_weight, use_aspect, stretch_to_bounds, ): global USER_FILL_HOLES global USER_FILL_HOLES_QUALITY global USER_STRETCH_ASPECT global USER_ISLAND_MARGIN from math import cos import time global dict_matrix dict_matrix = {} # Constants: # Takes a list of faces that make up a UV island and rotate # until they optimally fit inside a square. global ROTMAT_2D_POS_90D global ROTMAT_2D_POS_45D global RotMatStepRotation main_consts() # Create the variables. USER_PROJECTION_LIMIT = projection_limit USER_ONLY_SELECTED_FACES = True USER_SHARE_SPACE = 1 # Only for hole filling. USER_STRETCH_ASPECT = stretch_to_bounds USER_ISLAND_MARGIN = island_margin # Only for hole filling. USER_FILL_HOLES = 0 USER_FILL_HOLES_QUALITY = 50 # Only for hole filling. USER_VIEW_INIT = 0 # Only for hole filling. is_editmode = (context.active_object.mode == 'EDIT') if is_editmode: obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH'] else: obList = [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH'] USER_ONLY_SELECTED_FACES = False if not obList: raise Exception("error, no selected mesh objects") # Reuse variable if len(obList) == 1: ob = "Unwrap %i Selected Mesh" else: ob = "Unwrap %i Selected Meshes" # HACK, loop until mouse is lifted. ''' while Window.GetMouseButtons() != 0: time.sleep(10) ''' #~ XXX if not Draw.PupBlock(ob % len(obList), pup_block): #~ XXX return #~ XXX del ob # Convert from being button types USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT/2) * DEG_TO_RAD) # Toggle Edit mode is_editmode = (context.active_object.mode == 'EDIT') if is_editmode: bpy.ops.object.mode_set(mode='OBJECT') # Assume face select mode! an annoying hack to toggle face select mode because Mesh doesn't like faceSelectMode. if USER_SHARE_SPACE: # Sort by data name so we get consistent results obList.sort(key = lambda ob: ob.data.name) collected_islandList= [] #XXX Window.WaitCursor(1) time1 = time.time() # Tag as False so we don't operate on the same mesh twice. #XXX bpy.data.meshes.tag = False for me in bpy.data.meshes: me.tag = False for ob in obList: me = ob.data if me.tag or me.library: continue # Tag as used me.tag = True if not me.uv_textures: # Mesh has no UV Coords, don't bother. me.uv_textures.new() uv_layer = me.uv_layers.active.data me_verts = list(me.vertices) if USER_ONLY_SELECTED_FACES: meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select] else: meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)] #XXX Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces))) # ======= # Generate a projection list from face normals, this is meant to be smart :) # make a list of face props that are in sync with meshFaces # Make a Face List that is sorted by area. # meshFaces = [] # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. meshFaces.sort(key=lambda a: -a.area) # remove all zero area faces while meshFaces and meshFaces[-1].area <= SMALL_NUM: # Set their UV's to 0,0 for uv in meshFaces[-1].uv: uv.zero() meshFaces.pop() if not meshFaces: continue # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data. # Generate Projection Vecs # 0d is 1.0 # 180 IS -0.59846 # Initialize projectVecs if USER_VIEW_INIT: # Generate Projection projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.inverted().to_3x3()] # We add to this along the way else: projectVecs = [] newProjectVec = meshFaces[0].no newProjectMeshFaces = [] # Popping stuffs it up. # Pretend that the most unique angle is ages away to start the loop off mostUniqueAngle = -1.0 # This is popped tempMeshFaces = meshFaces[:] # This while only gathers projection vecs, faces are assigned later on. while 1: # If theres none there then start with the largest face # add all the faces that are close. for fIdx in range(len(tempMeshFaces)-1, -1, -1): # Use half the angle limit so we don't overweight faces towards this # normal and hog all the faces. if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED: newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) # Add the average of all these faces normals as a projectionVec averageVec = Vector((0.0, 0.0, 0.0)) if user_area_weight == 0.0: for fprop in newProjectMeshFaces: averageVec += fprop.no elif user_area_weight == 1.0: for fprop in newProjectMeshFaces: averageVec += fprop.no * fprop.area else: for fprop in newProjectMeshFaces: averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight)) if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN projectVecs.append(averageVec.normalized()) # Get the next vec! # Pick the face thats most different to all existing angles :) mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. mostUniqueIndex = 0 # dummy for fIdx in range(len(tempMeshFaces)-1, -1, -1): angleDifference = -1.0 # 180d difference. # Get the closest vec angle we are to. for p in projectVecs: temp_angle_diff= p.dot(tempMeshFaces[fIdx].no) if angleDifference < temp_angle_diff: angleDifference= temp_angle_diff if angleDifference < mostUniqueAngle: # We have a new most different angle mostUniqueIndex = fIdx mostUniqueAngle = angleDifference if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) # Now weight the vector to all its faces, will give a more direct projection # if the face its self was not representative of the normal from surrounding faces. newProjectVec = tempMeshFaces[mostUniqueIndex].no newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] else: if len(projectVecs) >= 1: # Must have at least 2 projections break # If there are only zero area faces then its possible # there are no projectionVecs if not len(projectVecs): Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.') return faceProjectionGroupList =[[] for i in range(len(projectVecs)) ] # MAP and Arrange # We know there are 3 or 4 faces here for fIdx in range(len(meshFaces)-1, -1, -1): fvec = meshFaces[fIdx].no i = len(projectVecs) # Initialize first bestAng = fvec.dot(projectVecs[0]) bestAngIdx = 0 # Cycle through the remaining, first already done while i-1: i-=1 newAng = fvec.dot(projectVecs[i]) if newAng > bestAng: # Reverse logic for dotvecs bestAng = newAng bestAngIdx = i # Store the area for later use. faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) # Cull faceProjectionGroupList, # Now faceProjectionGroupList is full of faces that face match the project Vecs list for i in range(len(projectVecs)): # Account for projectVecs having no faces. if not faceProjectionGroupList[i]: continue # Make a projection matrix from a unit length vector. MatQuat = VectoQuat(projectVecs[i]) # Get the faces UV's from the projected vertex. for f in faceProjectionGroupList[i]: f_uv = f.uv for j, v in enumerate(f.v): # XXX - note, between mathutils in 2.4 and 2.5 the order changed. f_uv[j][:] = (MatQuat * v.co).xy if USER_SHARE_SPACE: # Should we collect and pack later? islandList = getUvIslands(faceProjectionGroupList, me) collected_islandList.extend(islandList) else: # Should we pack the islands for this 1 object? islandList = getUvIslands(faceProjectionGroupList, me) packIslands(islandList) # update the mesh here if we need to. # We want to pack all in 1 go, so pack now if USER_SHARE_SPACE: #XXX Window.DrawProgressBar(0.9, "Box Packing for all objects...") packIslands(collected_islandList) print("Smart Projection time: %.2f" % (time.time() - time1)) # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec" % (time.time() - time1)) # aspect correction is only done in edit mode - and only smart unwrap supports currently if is_editmode: bpy.ops.object.mode_set(mode='EDIT') if use_aspect: import bmesh aspect = context.scene.uvedit_aspect(context.active_object) if aspect[0] > aspect[1]: aspect[0] = aspect[1]/aspect[0]; aspect[1] = 1.0 else: aspect[1] = aspect[0]/aspect[1]; aspect[0] = 1.0 bm = bmesh.from_edit_mesh(me) uv_act = bm.loops.layers.uv.active faces = [f for f in bm.faces if f.select] for f in faces: for l in f.loops: l[uv_act].uv[0] *= aspect[0] l[uv_act].uv[1] *= aspect[1] dict_matrix.clear()
def mergeUvIslands(islandList): global USER_FILL_HOLES global USER_FILL_HOLES_QUALITY # Pack islands to bottom LHS # Sync with island #islandTotFaceArea = [] # A list of floats, each island area #islandArea = [] # a list of tuples ( area, w,h) decoratedIslandList = [] islandIdx = len(islandList) while islandIdx: islandIdx-=1 minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) w, h = maxx-minx, maxy-miny totFaceArea = 0 offset= Vector((minx, miny)) for f in islandList[islandIdx]: for uv in f.uv: uv -= offset totFaceArea += f.area islandBoundsArea = w*h efficiency = abs(islandBoundsArea - totFaceArea) # UV Edge list used for intersections as well as unique points. edges, uniqueEdgePoints = island2Edge(islandList[islandIdx]) decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w,h, edges, uniqueEdgePoints]) # Sort by island bounding box area, smallest face area first. # no.. chance that to most simple edge loop first. decoratedIslandListAreaSort =decoratedIslandList[:] decoratedIslandListAreaSort.sort(key = lambda A: A[3]) # sort by efficiency, Least Efficient first. decoratedIslandListEfficSort = decoratedIslandList[:] # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) decoratedIslandListEfficSort.sort(key = lambda A: -A[2]) # ================================================== THESE CAN BE TWEAKED. # This is a quality value for the number of tests. # from 1 to 4, generic quality value is from 1 to 100 USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1 # If 100 will test as long as there is enough free space. # this is rarely enough, and testing takes a while, so lower quality speeds this up. # 1 means they have the same quality USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY)/100.0) *5) #print 'USER_STEP_QUALITY', USER_STEP_QUALITY #print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY removedCount = 0 areaIslandIdx = 0 ctrl = Window.Qual.CTRL BREAK= False while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK: sourceIsland = decoratedIslandListAreaSort[areaIslandIdx] # Already packed? if not sourceIsland[0]: areaIslandIdx+=1 else: efficIslandIdx = 0 while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK: if Window.GetKeyQualifiers() & ctrl: BREAK= True break # Now we have 2 islands, if the efficiency of the islands lowers theres an # increasing likely hood that we can fit merge into the bigger UV island. # this ensures a tight fit. # Just use figures we have about user/unused area to see if they might fit. targetIsland = decoratedIslandListEfficSort[efficIslandIdx] if sourceIsland[0] == targetIsland[0] or\ not targetIsland[0] or\ not sourceIsland[0]: pass else: #~ ([island, totFaceArea, efficiency, islandArea, w,h]) # Wasted space on target is greater then UV bounding island area. #~ if targetIsland[3] > (sourceIsland[2]) and\ # #~ print USER_FREE_SPACE_TO_TEST_QUALITY if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\ targetIsland[4] > sourceIsland[4] and\ targetIsland[5] > sourceIsland[5]: # DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1]) # These enough spare space lets move the box until it fits # How many times does the source fit into the target x/y blockTestXUnit = targetIsland[4]/sourceIsland[4] blockTestYUnit = targetIsland[5]/sourceIsland[5] boxLeft = 0 # Distance we can move between whilst staying inside the targets bounds. testWidth = targetIsland[4] - sourceIsland[4] testHeight = targetIsland[5] - sourceIsland[5] # Increment we move each test. x/y xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY/50)+0.1))) yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY/50)+0.1))) # Make sure were not moving less then a 3rg of our width/height if xIncrement<sourceIsland[4]/3: xIncrement= sourceIsland[4] if yIncrement<sourceIsland[5]/3: yIncrement= sourceIsland[5] boxLeft = 0 # Start 1 back so we can jump into the loop. boxBottom= 0 #-yIncrement #~ testcount= 0 while boxBottom <= testHeight: # Should we use this? - not needed for now. #~ if Window.GetKeyQualifiers() & ctrl: #~ BREAK= True #~ break ##testcount+=1 #print 'Testing intersect' Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector((boxLeft, boxBottom))) #print 'Done', Intersect if Intersect == 1: # Line intersect, don't bother with this any more pass if Intersect == 2: # Source inside target """ We have an intersection, if we are inside the target then move us 1 whole width across, Its possible this is a bad idea since 2 skinny Angular faces could join without 1 whole move, but its a lot more optimal to speed this up since we have already tested for it. It gives about 10% speedup with minimal errors. """ # Move the test along its width + SMALL_NUM #boxLeft += sourceIsland[4] + SMALL_NUM boxLeft += sourceIsland[4] elif Intersect == 0: # No intersection?? Place it. # Progress removedCount +=1 #XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount) # Move faces into new island and offset targetIsland[0].extend(sourceIsland[0]) offset= Vector((boxLeft, boxBottom)) for f in sourceIsland[0]: for uv in f.uv: uv+= offset del sourceIsland[0][:] # Empty # Move edge loop into new and offset. # targetIsland[6].extend(sourceIsland[6]) #while sourceIsland[6]: targetIsland[6].extend( [ (\ (e[0]+offset, e[1]+offset, e[2])\ ) for e in sourceIsland[6] ] ) del sourceIsland[6][:] # Empty # Sort by edge length, reverse so biggest are first. try: targetIsland[6].sort(key = lambda A: A[2]) except: targetIsland[6].sort(lambda B,A: cmp(A[2], B[2] )) targetIsland[7].extend(sourceIsland[7]) offset= Vector((boxLeft, boxBottom, 0.0)) for p in sourceIsland[7]: p+= offset del sourceIsland[7][:] # Decrement the efficiency targetIsland[1]+=sourceIsland[1] # Increment totFaceArea targetIsland[2]-=sourceIsland[1] # Decrement efficiency # IF we ever used these again, should set to 0, eg sourceIsland[2] = 0 # No area if anyone wants to know break # INCREMENT NEXT LOCATION if boxLeft > testWidth: boxBottom += yIncrement boxLeft = 0.0 else: boxLeft += xIncrement ##print testcount efficIslandIdx+=1 areaIslandIdx+=1 # Remove empty islands i = len(islandList) while i: i-=1 if not islandList[i]: del islandList[i] # Can increment islands removed here.
def __init__(self, name, scale=Vector([1, 1, 1])): self.name = name self.scale = scale
def get_height(self, o): return (Vector(o.bound_box[1]) - Vector(o.bound_box[0])).length
def snap_utilities(cache, context, obj_matrix_world, bm, mcursor, outer_verts=False, constrain=None, previous_vert=None, ignore_obj=None, increment=0.0): rv3d = context.region_data region = context.region scene = context.scene is_increment = False r_loc = None r_type = None r_len = 0.0 bm_geom = None if bm.select_history: bm.select_history[0].select = False bm.select_history.clear() bpy.ops.view3d.select(location=(int(mcursor.x), int(mcursor.y))) if bm.select_history: bm_geom = bm.select_history[0] if isinstance(bm_geom, bmesh.types.BMVert): r_type = 'VERT' if cache.bvert != bm_geom: cache.bvert = bm_geom cache.vco = obj_matrix_world * cache.bvert.co # cache.v2d = location_3d_to_region_2d(region, rv3d, cache.vco) if constrain: location = intersect_point_line(cache.vco, constrain[0], constrain[1]) # factor = location[1] r_loc = location[0] else: r_loc = cache.vco elif isinstance(bm_geom, bmesh.types.BMEdge): if cache.bedge != bm_geom: cache.bedge = bm_geom cache.v0 = obj_matrix_world * bm_geom.verts[0].co cache.v1 = obj_matrix_world * bm_geom.verts[1].co cache.vmid = 0.5 * (cache.v0 + cache.v1) cache.v2d0 = location_3d_to_region_2d(region, rv3d, cache.v0) cache.v2d1 = location_3d_to_region_2d(region, rv3d, cache.v1) cache.v2dmid = location_3d_to_region_2d(region, rv3d, cache.vmid) if previous_vert and previous_vert not in bm_geom.verts: pvert_co = obj_matrix_world * previous_vert.co perp_point = intersect_point_line(pvert_co, cache.v0, cache.v1) cache.vperp = perp_point[0] # factor = point_perpendicular[1] cache.v2dperp = location_3d_to_region_2d( region, rv3d, perp_point[0]) # else: cache.v2dperp = None if constrain: location = intersect_line_line(constrain[0], constrain[1], cache.v0, cache.v1) if location is None: is_increment = True orig, view_vector = region_2d_to_orig_and_view_vector( region, rv3d, mcursor) end = orig + view_vector location = intersect_line_line(constrain[0], constrain[1], orig, end) r_loc = location[0] elif cache.v2dperp and \ abs(cache.v2dperp[0] - mcursor[0]) < 10 and abs(cache.v2dperp[1] - mcursor[1]) < 10: r_type = 'PERPENDICULAR' r_loc = cache.vperp elif abs(cache.v2dmid[0] - mcursor[0]) < 10 and abs(cache.v2dmid[1] - mcursor[1]) < 10: r_type = 'CENTER' r_loc = cache.vmid else: if increment and previous_vert in cache.bedge.verts: is_increment = True r_type = 'EDGE' orig, view_vector = region_2d_to_orig_and_view_vector( region, rv3d, mcursor) r_loc = intersect_line_line(cache.v0, cache.v1, orig, orig + view_vector)[0] elif isinstance(bm_geom, bmesh.types.BMFace): is_increment = True r_type = 'FACE' if cache.bface != bm_geom: cache.bface = bm_geom cache.fmid = obj_matrix_world * bm_geom.calc_center_median() cache.fnor = bm_geom.normal * obj_matrix_world orig, view_vector = region_2d_to_orig_and_view_vector( region, rv3d, mcursor) end = orig + view_vector r_loc = intersect_line_plane(orig, end, cache.fmid, cache.fnor, False) if constrain: is_increment = False r_loc = intersect_point_line(r_loc, constrain[0], constrain[1])[0] else: # OUT is_increment = True r_type = 'OUT' orig, view_vector = region_2d_to_orig_and_view_vector( region, rv3d, mcursor) face_index = -1 if cache.out_obj is None: ## TODO: The Scene.raycast also tests the edited object. # This is highly inefficient because the edited object # does not keep DerivedMesh which forces rebuilding the bvhtree. result, r_loc, normal, face_index, cache.out_obj, cache.out_obmat = scene.ray_cast( orig, view_vector) if result: r_type = 'FACE' cache.out_obimat = cache.out_obmat.inverted() else: face_index = -1 r_loc = None if cache.out_obj and cache.out_obj != ignore_obj: if not r_loc or outer_verts: location = None if face_index == -1: # get the ray relative to the cache.out_obj ray_origin_obj = cache.out_obimat * orig end = orig + view_vector * 1000 ray_target_obj = cache.out_obimat * end result, location, normal, face_index = cache.out_obj.ray_cast( ray_origin_obj, ray_target_obj) if face_index == -1: cache.out_obj = None elif outer_verts: vloc = None try: me = cache.out_obj.data verts = me.polygons[face_index].vertices v_dist = 100 for i in verts: v_co = cache.out_obmat * me.vertices[i].co v_2d = location_3d_to_region_2d(region, rv3d, v_co) dist = (Vector(mcursor) - v_2d.xy).length_squared if dist < v_dist: v_dist = dist vloc = v_co except Exception as e: print('Fail', e) if vloc: is_increment = False r_type = 'VERT' r_loc = vloc if not r_loc: r_type = 'FACE' r_loc = cache.out_obmat * location if constrain: if r_loc: is_increment = False r_loc = intersect_point_line(r_loc, constrain[0], constrain[1])[0] else: r_loc = intersect_line_line(constrain[0], constrain[1], orig, orig + view_vector)[0] elif not r_loc: r_loc = out_Location(rv3d, region, orig, view_vector) if previous_vert: pv_co = obj_matrix_world * previous_vert.co vec = r_loc - pv_co if is_increment and increment: r_len = round((1 / increment) * vec.length) * increment r_loc = r_len * vec.normalized() + pv_co else: r_len = vec.length return r_loc, r_type, bm_geom, r_len
def integrate(vecs, times): res=[Vector((0.0,0.0,0.0))] for i in range(len(times)-1): res.append(res[-1]+(vecs[i+1]+vecs[i])/2*(times[i+1]-times[i])) return res
class SnapUtilitiesLine(Operator): bl_idname = "mesh.snap_utilities_line" bl_label = "Line Tool" bl_description = "Draw edges. Connect them to split faces" bl_options = {'REGISTER', 'UNDO'} constrain_keys = { 'X': Vector((1, 0, 0)), 'Y': Vector((0, 1, 0)), 'Z': Vector((0, 0, 1)), 'RIGHT_SHIFT': 'shift', 'LEFT_SHIFT': 'shift', } @classmethod def poll(cls, context): preferences = context.user_preferences.addons[__name__].preferences return (context.mode in {'EDIT_MESH', 'OBJECT'} and preferences.create_new_obj or (context.object is not None and context.object.type == 'MESH')) def draw_callback_px(self, context): # draw 3d point OpenGL in the 3D View bgl.glEnable(bgl.GL_BLEND) bgl.glDisable(bgl.GL_DEPTH_TEST) # bgl.glPushMatrix() # bgl.glMultMatrixf(self.obj_glmatrix) if self.vector_constrain: vc = self.vector_constrain if hasattr(self, 'preloc') and self.type in {'VERT', 'FACE'}: bgl.glColor4f(1.0, 1.0, 1.0, 0.5) bgl.glPointSize(5) bgl.glBegin(bgl.GL_POINTS) bgl.glVertex3f(*self.preloc) bgl.glEnd() if vc[2] == 'X': Color4f = (self.axis_x_color + (1.0, )) elif vc[2] == 'Y': Color4f = (self.axis_y_color + (1.0, )) elif vc[2] == 'Z': Color4f = (self.axis_z_color + (1.0, )) else: Color4f = self.constrain_shift_color else: if self.type == 'OUT': Color4f = self.out_color elif self.type == 'FACE': Color4f = self.face_color elif self.type == 'EDGE': Color4f = self.edge_color elif self.type == 'VERT': Color4f = self.vert_color elif self.type == 'CENTER': Color4f = self.center_color elif self.type == 'PERPENDICULAR': Color4f = self.perpendicular_color else: # self.type == None Color4f = self.out_color bgl.glColor4f(*Color4f) bgl.glPointSize(10) bgl.glBegin(bgl.GL_POINTS) bgl.glVertex3f(*self.location) bgl.glEnd() # draw 3d line OpenGL in the 3D View bgl.glEnable(bgl.GL_DEPTH_TEST) bgl.glDepthRange(0, 0.9999) bgl.glColor4f(1.0, 0.8, 0.0, 1.0) bgl.glLineWidth(2) bgl.glEnable(bgl.GL_LINE_STIPPLE) bgl.glBegin(bgl.GL_LINE_STRIP) for vert_co in self.list_verts_co: bgl.glVertex3f(*vert_co) bgl.glVertex3f(*self.location) bgl.glEnd() # restore opengl defaults # bgl.glPopMatrix() bgl.glDepthRange(0, 1) bgl.glPointSize(1) bgl.glLineWidth(1) bgl.glDisable(bgl.GL_BLEND) bgl.glDisable(bgl.GL_LINE_STIPPLE) bgl.glColor4f(0.0, 0.0, 0.0, 1.0) def modal_navigation(self, context, event): evkey = (event.alt, event.ctrl, event.shift, event.type, event.value) if evkey in self.navigation_keys._rotate: bpy.ops.view3d.rotate('INVOKE_DEFAULT') return True elif evkey in self.navigation_keys._move: if event.shift and self.vector_constrain and \ self.vector_constrain[2] in {'RIGHT_SHIFT', 'LEFT_SHIFT', 'shift'}: self.vector_constrain = None bpy.ops.view3d.move('INVOKE_DEFAULT') return True else: for key in self.navigation_keys._zoom: if evkey == key[0:5]: if True: # TODO: Use Zoom to mouse position v3d = context.space_data dist_range = (v3d.clip_start, v3d.clip_end) rv3d = context.region_data if (key[5] < 0 and rv3d.view_distance < dist_range[1]) or\ (key[5] > 0 and rv3d.view_distance > dist_range[0]): rv3d.view_location += key[5] * ( self.location - rv3d.view_location) / 6 rv3d.view_distance -= key[ 5] * rv3d.view_distance / 6 else: bpy.ops.view3d.zoom('INVOKE_DEFAULT', delta=key[5]) return True #break return False def modal(self, context, event): if self.modal_navigation(context, event): return {'RUNNING_MODAL'} context.area.tag_redraw() if event.ctrl and event.type == 'Z' and event.value == 'PRESS': bpy.ops.ed.undo() self.vector_constrain = None self.list_verts_co = [] self.list_verts = [] self.list_edges = [] self.list_faces = [] self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.bm = bmesh.from_edit_mesh(self.obj.data) return {'RUNNING_MODAL'} if event.type == 'MOUSEMOVE' or self.bool_update: if self.rv3d.view_matrix != self.rotMat: self.rotMat = self.rv3d.view_matrix.copy() self.bool_update = True self.cache.bedge = None else: self.bool_update = False mval = Vector((event.mouse_region_x, event.mouse_region_y)) self.location, self.type, self.geom, self.len = snap_utilities( self.cache, context, self.obj_matrix, self.bm, mval, outer_verts=(self.outer_verts and not self.keytab), constrain=self.vector_constrain, previous_vert=(self.list_verts[-1] if self.list_verts else None), ignore_obj=self.obj, increment=self.incremental) if self.snap_to_grid and self.type == 'OUT': loc = self.location / self.rd self.location = Vector( (round(loc.x), round(loc.y), round(loc.z))) * self.rd if self.keyf8 and self.list_verts_co: lloc = self.list_verts_co[-1] orig, view_vec = region_2d_to_orig_and_view_vector( self.region, self.rv3d, mval) location = intersect_point_line(lloc, orig, (orig + view_vec)) vec = (location[0] - lloc) ax, ay, az = abs(vec.x), abs(vec.y), abs(vec.z) vec.x = ax > ay > az or ax > az > ay vec.y = ay > ax > az or ay > az > ax vec.z = az > ay > ax or az > ax > ay if vec == Vector(): self.vector_constrain = None else: vc = lloc + vec try: if vc != self.vector_constrain[1]: type = 'X' if vec.x else 'Y' if vec.y else 'Z' if vec.z else 'shift' self.vector_constrain = [lloc, vc, type] except: type = 'X' if vec.x else 'Y' if vec.y else 'Z' if vec.z else 'shift' self.vector_constrain = [lloc, vc, type] if event.value == 'PRESS': if self.list_verts_co and (event.ascii in CharMap.ascii or event.type in CharMap.type): CharMap.modal(self, context, event) elif event.type in self.constrain_keys: self.bool_update = True if self.vector_constrain and self.vector_constrain[ 2] == event.type: self.vector_constrain = () else: if event.shift: if isinstance(self.geom, bmesh.types.BMEdge): if self.list_verts: loc = self.list_verts_co[-1] self.vector_constrain = ( loc, loc + self.geom.verts[1].co - self.geom.verts[0].co, event.type) else: self.vector_constrain = [ self.obj_matrix * v.co for v in self.geom.verts ] + [event.type] else: if self.list_verts: loc = self.list_verts_co[-1] else: loc = self.location self.vector_constrain = [ loc, loc + self.constrain_keys[event.type] ] + [event.type] elif event.type == 'LEFTMOUSE': point = self.obj_matinv * self.location # with constraint the intersection can be in a different element of the selected one if self.vector_constrain and self.geom: geom2 = get_closest_edge(self.bm, point, .001) else: geom2 = self.geom self.vector_constrain = None self.list_verts_co = draw_line(self, self.obj, self.bm, geom2, point) bpy.ops.ed.undo_push(message="Undo draw line*") elif event.type == 'TAB': self.keytab = self.keytab is False if self.keytab: context.tool_settings.mesh_select_mode = (False, False, True) else: context.tool_settings.mesh_select_mode = (True, True, True) elif event.type == 'F8': self.vector_constrain = None self.keyf8 = self.keyf8 is False elif event.value == 'RELEASE': if event.type in {'RET', 'NUMPAD_ENTER'}: if self.length_entered != "" and self.list_verts_co: try: text_value = bpy.utils.units.to_value( self.unit_system, 'LENGTH', self.length_entered) vector = (self.location - self.list_verts_co[-1]).normalized() location = (self.list_verts_co[-1] + (vector * text_value)) G_location = self.obj_matinv * location self.list_verts_co = draw_line(self, self.obj, self.bm, self.geom, G_location) self.length_entered = "" self.vector_constrain = None except: # ValueError: self.report({'INFO'}, "Operation not supported yet") elif event.type in {'RIGHTMOUSE', 'ESC'}: if self.list_verts_co == [] or event.type == 'ESC': bpy.types.SpaceView3D.draw_handler_remove( self._handle, 'WINDOW') context.tool_settings.mesh_select_mode = self.select_mode context.area.header_text_set() context.user_preferences.view.use_rotate_around_active = self.use_rotate_around_active if not self.is_editmode: bpy.ops.object.editmode_toggle() return {'FINISHED'} else: self.vector_constrain = None self.list_verts = [] self.list_verts_co = [] self.list_faces = [] a = "" if self.list_verts_co: if self.length_entered: pos = self.line_pos a = 'length: ' + self.length_entered[: pos] + '|' + self.length_entered[ pos:] else: length = self.len length = convert_distance(length, self.uinfo) a = 'length: ' + length context.area.header_text_set( "hit: %.3f %.3f %.3f %s" % (self.location[0], self.location[1], self.location[2], a)) return {'RUNNING_MODAL'} def invoke(self, context, event): if context.space_data.type == 'VIEW_3D': # print('name', __name__, __package__) preferences = context.user_preferences.addons[__name__].preferences create_new_obj = preferences.create_new_obj if context.mode == 'OBJECT' and \ (create_new_obj or context.object is None or context.object.type != 'MESH'): mesh = bpy.data.meshes.new("") obj = bpy.data.objects.new("", mesh) context.scene.objects.link(obj) context.scene.objects.active = obj # bgl.glEnable(bgl.GL_POINT_SMOOTH) self.is_editmode = bpy.context.object.data.is_editmode bpy.ops.object.mode_set(mode='EDIT') context.space_data.use_occlude_geometry = True self.scale = context.scene.unit_settings.scale_length self.unit_system = context.scene.unit_settings.system self.separate_units = context.scene.unit_settings.use_separate self.uinfo = get_units_info(self.scale, self.unit_system, self.separate_units) grid = context.scene.unit_settings.scale_length / context.space_data.grid_scale relative_scale = preferences.relative_scale self.scale = grid / relative_scale self.rd = bpy.utils.units.to_value(self.unit_system, 'LENGTH', str(1 / self.scale)) incremental = preferences.incremental self.incremental = bpy.utils.units.to_value( self.unit_system, 'LENGTH', str(incremental)) self.use_rotate_around_active = context.user_preferences.view.use_rotate_around_active context.user_preferences.view.use_rotate_around_active = True self.select_mode = context.tool_settings.mesh_select_mode[:] context.tool_settings.mesh_select_mode = (True, True, True) self.region = context.region self.rv3d = context.region_data self.rotMat = self.rv3d.view_matrix.copy() self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.obj_matinv = self.obj_matrix.inverted() # self.obj_glmatrix = bgl.Buffer(bgl.GL_FLOAT, [4, 4], self.obj_matrix.transposed()) self.bm = bmesh.from_edit_mesh(self.obj.data) self.cache = SnapCache() self.location = Vector() self.list_verts = [] self.list_verts_co = [] self.bool_update = False self.vector_constrain = () self.navigation_keys = NavigationKeys(context) self.keytab = False self.keyf8 = False self.type = 'OUT' self.len = 0 self.length_entered = "" self.line_pos = 0 self.out_color = preferences.out_color self.face_color = preferences.face_color self.edge_color = preferences.edge_color self.vert_color = preferences.vert_color self.center_color = preferences.center_color self.perpendicular_color = preferences.perpendicular_color self.constrain_shift_color = preferences.constrain_shift_color self.axis_x_color = tuple( context.user_preferences.themes[0].user_interface.axis_x) self.axis_y_color = tuple( context.user_preferences.themes[0].user_interface.axis_y) self.axis_z_color = tuple( context.user_preferences.themes[0].user_interface.axis_z) self.intersect = preferences.intersect self.create_face = preferences.create_face self.outer_verts = preferences.outer_verts self.snap_to_grid = preferences.increments_grid self._handle = bpy.types.SpaceView3D.draw_handler_add( self.draw_callback_px, (context, ), 'WINDOW', 'POST_VIEW') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} else: self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'}
def create_profile(self): # A cube verts = [ Vector((-1, -1, -1)), Vector((-1, -1, 1)), Vector((-1, 1, -1)), Vector((-1, 1, 1)), Vector((1, -1, -1)), Vector((1, -1, 1)), Vector((1, 1, -1)), Vector((1, 1, 1)), ] edges = [] faces = [ [0, 2, 3, 1], [2, 3, 7, 6], [4, 5, 7, 6], [0, 1, 5, 4], [1, 3, 7, 5], [0, 2, 6, 4], ] ifc_classes = ifcopenshell.util.type.get_applicable_entities( self.relating_type.is_a(), self.file.schema) # Standard cases are deprecated, so let's cull them ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0] mesh = bpy.data.meshes.new(name="Dumb Profile") mesh.from_pydata(verts, edges, faces) obj = bpy.data.objects.new( tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh) obj.location = self.location if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id: obj.location[2] = self.collection_obj.location[2] self.collection.objects.link(obj) bpy.ops.bim.assign_class(obj=obj.name, ifc_class=ifc_class, should_add_representation=False) if self.relating_type.is_a() in ["IfcBeamType", "IfcMemberType"]: obj.rotation_euler[0] = math.pi / 2 obj.rotation_euler[2] = math.pi / 2 element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=tool.Ifc.get_entity(obj), type=self.relating_type) profile_set_usage = ifcopenshell.util.element.get_material(element) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbProfile"}) MaterialData.load(self.file) obj.select_set(True) return obj
def modal(self, context, event): if self.modal_navigation(context, event): return {'RUNNING_MODAL'} context.area.tag_redraw() if event.ctrl and event.type == 'Z' and event.value == 'PRESS': bpy.ops.ed.undo() self.vector_constrain = None self.list_verts_co = [] self.list_verts = [] self.list_edges = [] self.list_faces = [] self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.bm = bmesh.from_edit_mesh(self.obj.data) return {'RUNNING_MODAL'} if event.type == 'MOUSEMOVE' or self.bool_update: if self.rv3d.view_matrix != self.rotMat: self.rotMat = self.rv3d.view_matrix.copy() self.bool_update = True self.cache.bedge = None else: self.bool_update = False mval = Vector((event.mouse_region_x, event.mouse_region_y)) self.location, self.type, self.geom, self.len = snap_utilities( self.cache, context, self.obj_matrix, self.bm, mval, outer_verts=(self.outer_verts and not self.keytab), constrain=self.vector_constrain, previous_vert=(self.list_verts[-1] if self.list_verts else None), ignore_obj=self.obj, increment=self.incremental) if self.snap_to_grid and self.type == 'OUT': loc = self.location / self.rd self.location = Vector( (round(loc.x), round(loc.y), round(loc.z))) * self.rd if self.keyf8 and self.list_verts_co: lloc = self.list_verts_co[-1] orig, view_vec = region_2d_to_orig_and_view_vector( self.region, self.rv3d, mval) location = intersect_point_line(lloc, orig, (orig + view_vec)) vec = (location[0] - lloc) ax, ay, az = abs(vec.x), abs(vec.y), abs(vec.z) vec.x = ax > ay > az or ax > az > ay vec.y = ay > ax > az or ay > az > ax vec.z = az > ay > ax or az > ax > ay if vec == Vector(): self.vector_constrain = None else: vc = lloc + vec try: if vc != self.vector_constrain[1]: type = 'X' if vec.x else 'Y' if vec.y else 'Z' if vec.z else 'shift' self.vector_constrain = [lloc, vc, type] except: type = 'X' if vec.x else 'Y' if vec.y else 'Z' if vec.z else 'shift' self.vector_constrain = [lloc, vc, type] if event.value == 'PRESS': if self.list_verts_co and (event.ascii in CharMap.ascii or event.type in CharMap.type): CharMap.modal(self, context, event) elif event.type in self.constrain_keys: self.bool_update = True if self.vector_constrain and self.vector_constrain[ 2] == event.type: self.vector_constrain = () else: if event.shift: if isinstance(self.geom, bmesh.types.BMEdge): if self.list_verts: loc = self.list_verts_co[-1] self.vector_constrain = ( loc, loc + self.geom.verts[1].co - self.geom.verts[0].co, event.type) else: self.vector_constrain = [ self.obj_matrix * v.co for v in self.geom.verts ] + [event.type] else: if self.list_verts: loc = self.list_verts_co[-1] else: loc = self.location self.vector_constrain = [ loc, loc + self.constrain_keys[event.type] ] + [event.type] elif event.type == 'LEFTMOUSE': point = self.obj_matinv * self.location # with constraint the intersection can be in a different element of the selected one if self.vector_constrain and self.geom: geom2 = get_closest_edge(self.bm, point, .001) else: geom2 = self.geom self.vector_constrain = None self.list_verts_co = draw_line(self, self.obj, self.bm, geom2, point) bpy.ops.ed.undo_push(message="Undo draw line*") elif event.type == 'TAB': self.keytab = self.keytab is False if self.keytab: context.tool_settings.mesh_select_mode = (False, False, True) else: context.tool_settings.mesh_select_mode = (True, True, True) elif event.type == 'F8': self.vector_constrain = None self.keyf8 = self.keyf8 is False elif event.value == 'RELEASE': if event.type in {'RET', 'NUMPAD_ENTER'}: if self.length_entered != "" and self.list_verts_co: try: text_value = bpy.utils.units.to_value( self.unit_system, 'LENGTH', self.length_entered) vector = (self.location - self.list_verts_co[-1]).normalized() location = (self.list_verts_co[-1] + (vector * text_value)) G_location = self.obj_matinv * location self.list_verts_co = draw_line(self, self.obj, self.bm, self.geom, G_location) self.length_entered = "" self.vector_constrain = None except: # ValueError: self.report({'INFO'}, "Operation not supported yet") elif event.type in {'RIGHTMOUSE', 'ESC'}: if self.list_verts_co == [] or event.type == 'ESC': bpy.types.SpaceView3D.draw_handler_remove( self._handle, 'WINDOW') context.tool_settings.mesh_select_mode = self.select_mode context.area.header_text_set() context.user_preferences.view.use_rotate_around_active = self.use_rotate_around_active if not self.is_editmode: bpy.ops.object.editmode_toggle() return {'FINISHED'} else: self.vector_constrain = None self.list_verts = [] self.list_verts_co = [] self.list_faces = [] a = "" if self.list_verts_co: if self.length_entered: pos = self.line_pos a = 'length: ' + self.length_entered[: pos] + '|' + self.length_entered[ pos:] else: length = self.len length = convert_distance(length, self.uinfo) a = 'length: ' + length context.area.header_text_set( "hit: %.3f %.3f %.3f %s" % (self.location[0], self.location[1], self.location[2], a)) return {'RUNNING_MODAL'}
def importAnimations(self): lf = self.oid.oif trac = lf.getByPointer(self.link_TRAC) trac.getData() #trac.print() for i in bpy.context.scene.objects: i.select = False #deselect all objects bpy.context.scene.objects.active = None for anim in trac.data.anims: #anim = trac.data.anims[1] tram = lf.getByPointer(anim.link_TRAM) if tram.name != 'TRAMKONCOMrun_throw_fw': continue print(str(anim.weight) + ' - ' + tram.name + ':') tram.getData() #tram.print() tram.data.readBodyparts() tram.data.readPos() #print('bodyparts:') #print(tram.data.bodyparts) self.object.location = Vector(tram.data.pos) bpy.context.scene.frame_start = 0 bpy.context.scene.frame_end = tram.data.frames_num - 1 keyInterp = bpy.context.user_preferences.edit.keyframe_new_interpolation_type bpy.context.user_preferences.edit.keyframe_new_interpolation_type ='LINEAR' #self.object.animation_data_create() #self.object.animation_data.action = bpy.data.actions.new(name=tram.name) g = 3.1416/180 rotate = bpy.ops.transform.rotate for i in range(tram.data.bodyparts_num): #if i > 0: continue #bone = self.bones[i] bone = self.object.pose.bones[i] bpart = self.bodyparts[i] print(bpart) print(bone) #bpart.select = True #bpy.context.scene.objects.active = bpart trambp = tram.data.bodyparts[i] #obj = bpy.context.object #print(obj) #bone.animation_data_create() #bone.animation_data.action = bpy.data.actions.new(name=tram.name+"_"+BODYPARTS[i]) angles_sum = [0,0,0] frameN = 0 for frame in trambp.frames: frameN += frame.frames_num bpy.context.scene.frame_set(frameN) angles = [math.radians(a) for a in frame.angles] angles_delta = [self.getNearestAngle(a, b) for a,b in zip(angles_sum, angles)] angles_sum = [a+b for a,b in zip(angles_sum, angles_delta)] mode = 'ZYX' euler = Euler(angles_sum, mode) #bone.matrix = euler.to_matrix().to_4x4() bone.rotation_mode = mode bone.rotation_euler = euler bone.keyframe_insert(data_path='rotation_euler') #bone.rotation_mode = 'QUATERNION' #bone.rotation_quaternion = euler.to_quaternion() #bone.matrix = euler.to_quaternion().to_matrix().to_4x4() #bone.keyframe_insert(data_path='rotation_quaternion') #if i == 0: # print(frameN) # print(str(frame.angles) + ' - ' + str(bone.rotation_euler)) #bpart.select = False bpy.context.user_preferences.edit.keyframe_new_interpolation_type = keyInterp
def invoke(self, context, event): if context.space_data.type == 'VIEW_3D': # print('name', __name__, __package__) preferences = context.user_preferences.addons[__name__].preferences create_new_obj = preferences.create_new_obj if context.mode == 'OBJECT' and \ (create_new_obj or context.object is None or context.object.type != 'MESH'): mesh = bpy.data.meshes.new("") obj = bpy.data.objects.new("", mesh) context.scene.objects.link(obj) context.scene.objects.active = obj # bgl.glEnable(bgl.GL_POINT_SMOOTH) self.is_editmode = bpy.context.object.data.is_editmode bpy.ops.object.mode_set(mode='EDIT') context.space_data.use_occlude_geometry = True self.scale = context.scene.unit_settings.scale_length self.unit_system = context.scene.unit_settings.system self.separate_units = context.scene.unit_settings.use_separate self.uinfo = get_units_info(self.scale, self.unit_system, self.separate_units) grid = context.scene.unit_settings.scale_length / context.space_data.grid_scale relative_scale = preferences.relative_scale self.scale = grid / relative_scale self.rd = bpy.utils.units.to_value(self.unit_system, 'LENGTH', str(1 / self.scale)) incremental = preferences.incremental self.incremental = bpy.utils.units.to_value( self.unit_system, 'LENGTH', str(incremental)) self.use_rotate_around_active = context.user_preferences.view.use_rotate_around_active context.user_preferences.view.use_rotate_around_active = True self.select_mode = context.tool_settings.mesh_select_mode[:] context.tool_settings.mesh_select_mode = (True, True, True) self.region = context.region self.rv3d = context.region_data self.rotMat = self.rv3d.view_matrix.copy() self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.obj_matinv = self.obj_matrix.inverted() # self.obj_glmatrix = bgl.Buffer(bgl.GL_FLOAT, [4, 4], self.obj_matrix.transposed()) self.bm = bmesh.from_edit_mesh(self.obj.data) self.cache = SnapCache() self.location = Vector() self.list_verts = [] self.list_verts_co = [] self.bool_update = False self.vector_constrain = () self.navigation_keys = NavigationKeys(context) self.keytab = False self.keyf8 = False self.type = 'OUT' self.len = 0 self.length_entered = "" self.line_pos = 0 self.out_color = preferences.out_color self.face_color = preferences.face_color self.edge_color = preferences.edge_color self.vert_color = preferences.vert_color self.center_color = preferences.center_color self.perpendicular_color = preferences.perpendicular_color self.constrain_shift_color = preferences.constrain_shift_color self.axis_x_color = tuple( context.user_preferences.themes[0].user_interface.axis_x) self.axis_y_color = tuple( context.user_preferences.themes[0].user_interface.axis_y) self.axis_z_color = tuple( context.user_preferences.themes[0].user_interface.axis_z) self.intersect = preferences.intersect self.create_face = preferences.create_face self.outer_verts = preferences.outer_verts self.snap_to_grid = preferences.increments_grid self._handle = bpy.types.SpaceView3D.draw_handler_add( self.draw_callback_px, (context, ), 'WINDOW', 'POST_VIEW') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} else: self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'}
def sendMesh(scene): context = bpy.context if bpy.context.edit_object is not None: currentObject = context.edit_object.name else: currentObject = context.active_object.name for name, target in Splash._targets.items(): currentTime = time.clock_gettime( time.CLOCK_REALTIME) - target._startTime worldMatrix = target._object.matrix_world normalMatrix = worldMatrix.copy() normalMatrix.invert() normalMatrix.transpose() if currentObject == name and bpy.context.edit_object is not None: if currentTime - target._frameTimeMesh < target._updatePeriodEdit: continue target._frameTimeMesh = currentTime mesh = bmesh.from_edit_mesh(target._object.data) bufferVert = bytearray() bufferPoly = bytearray() buffer = bytearray() vertNbr = 0 polyNbr = 0 uv_layer = mesh.loops.layers.uv.active if uv_layer is None: bpy.ops.uv.smart_project() uv_layer = mesh.loops.layers.uv.active for face in mesh.faces: polyNbr += 1 bufferPoly += struct.pack("i", len(face.verts)) for loop in face.loops: bufferPoly += struct.pack("i", vertNbr) v = loop.vert.co tmpVector = Vector((v[0], v[1], v[2], 1.0)) tmpVector = worldMatrix * tmpVector v = Vector((tmpVector[0], tmpVector[1], tmpVector[2])) n = loop.vert.normal tmpVector = Vector((n[0], n[1], n[2], 0.0)) tmpVector = normalMatrix * tmpVector n = Vector((tmpVector[0], tmpVector[1], tmpVector[2])) if uv_layer is None: uv = Vector((0, 0)) else: uv = loop[uv_layer].uv bufferVert += struct.pack("ffffffff", v[0], v[1], v[2], uv[0], uv[1], n[0], n[1], n[2]) vertNbr += 1 buffer += struct.pack("ii", vertNbr, polyNbr) buffer += bufferVert buffer += bufferPoly target._meshWriter.push(buffer, floor(currentTime * 1e9)) else: if currentTime - target._frameTimeMesh < target._updatePeriodObject: continue target._frameTimeMesh = currentTime if type(target._object.data) is bpy.types.Mesh: # Look for UV coords, create them if needed if len(target._object.data.uv_layers) == 0: bpy.ops.object.editmode_toggle() bpy.ops.uv.smart_project() bpy.ops.object.editmode_toggle() # Apply the modifiers to the object mesh = target._object.to_mesh(context.scene, True, 'PREVIEW') bufferVert = bytearray() bufferPoly = bytearray() buffer = bytearray() vertNbr = 0 polyNbr = 0 for poly in mesh.polygons: polyNbr += 1 bufferPoly += struct.pack("i", len(poly.loop_indices)) for idx in poly.loop_indices: bufferPoly += struct.pack("i", vertNbr) v = mesh.vertices[mesh.loops[idx].vertex_index].co tmpVector = Vector((v[0], v[1], v[2], 1.0)) tmpVector = worldMatrix * tmpVector v = Vector( (tmpVector[0], tmpVector[1], tmpVector[2])) n = mesh.vertices[ mesh.loops[idx].vertex_index].normal tmpVector = Vector((n[0], n[1], n[2], 0.0)) tmpVector = normalMatrix * tmpVector n = Vector( (tmpVector[0], tmpVector[1], tmpVector[2])) if len(mesh.uv_layers) != 0: uv = mesh.uv_layers[0].data[idx].uv else: uv = Vector((0, 0)) bufferVert += struct.pack("ffffffff", v[0], v[1], v[2], uv[0], uv[1], n[0], n[1], n[2]) vertNbr += 1 buffer += struct.pack("ii", vertNbr, polyNbr) buffer += bufferVert buffer += bufferPoly target._meshWriter.push(buffer, floor(currentTime * 1e9)) bpy.data.meshes.remove(mesh)
def location_3d_to_region_2d(region, rv3d, coord): prj = rv3d.perspective_matrix * Vector((coord[0], coord[1], coord[2], 1.0)) width_half = region.width / 2.0 height_half = region.height / 2.0 return Vector((width_half + width_half * (prj.x / prj.w), height_half + height_half * (prj.y / prj.w), prj.z / prj.w))
def build_circuit_spines(morphology, blue_config, gid, material=None): """Builds all the spines on a spiny neuron using a BBP circuit. :param morphology: A given morphology. :param blue_config: BBP circuit configuration file. :param gid: Neuron gid. :param material: Spine material. :return: A list of all the reconstructed spines along the neuron. """ # Keep a list of all the spines objects spines_objects = [] # Import brain import brain # Load the circuit, silently please circuit = brain.Circuit(blue_config) # Get all the synapses for the corresponding gid. synapses = circuit.afferent_synapses({int(gid)}) # Load all the template spines and ignore the verbose messages of loading templates_spines_list = load_spines( nmv.consts.Paths.SPINES_MESHES_LQ_DIRECTORY) # Apply the shader for spine_object in templates_spines_list: # Apply the shader to each spine mesh nmv.shading.set_material_to_object(spine_object, material) # Get the local to global transforms local_to_global_transform = circuit.transforms({int(gid)})[0] # Local_to_global_transform transformation_matrix = Matrix() for i in range(4): transformation_matrix[i][:] = local_to_global_transform[i] # Invert the transformation matrix transformation_matrix = transformation_matrix.inverted() # Create a timer to report the performance building_timer = nmv.utilities.timer.Timer() nmv.logger.header('Building spines') building_timer.start() # Load the synapses from the file number_spines = len(synapses) for i, synapse in enumerate(synapses): # Show progress nmv.utilities.time_line.show_iteration_progress( 'Spines', i, number_spines) """ Ignore soma synapses """ # If the post-synaptic section id is zero, then revoke it, and continue post_section_id = synapse.post_section() if post_section_id == 0: continue # Get the pre-and post-positions in the global coordinates pre_position = synapse.pre_center_position() post_position = synapse.post_center_position() # Transform the spine positions to the circuit coordinates pre_position = Vector( (pre_position[0], pre_position[1], pre_position[2])) post_position = Vector( (post_position[0], post_position[1], post_position[2])) post_position = transformation_matrix * post_position pre_position = transformation_matrix * pre_position # Emanate a spine spine_object = emanate_a_spine(templates_spines_list, post_position, pre_position, i) # Append the spine to spines list spines_objects.append(spine_object) # Done nmv.utilities.time_line.show_iteration_progress('Spines', number_spines, number_spines, done=True) # Link the spines to the scene in a single step nmv.logger.info('Linking spines to the scene') for i in spines_objects: nmv.scene.link_object_to_scene(i) # Report the time building_timer.end() nmv.logger.info('Spines: [%f] seconds' % building_timer.duration()) # Delete the template spines nmv.scene.ops.delete_list_objects(templates_spines_list) # Return the spines objects list return spines_objects
def get_linear_length(self, o): x = (Vector(o.bound_box[4]) - Vector(o.bound_box[0])).length y = (Vector(o.bound_box[3]) - Vector(o.bound_box[0])).length z = (Vector(o.bound_box[1]) - Vector(o.bound_box[0])).length return max(x, y, z)
def scan_advanced(scanner_object, rotation_speed=25.0, simulation_fps=24, angle_resolution=0.5, max_distance=90, evd_file=None, noise_mu=0.0, noise_sigma=0.03, start_angle=-35, end_angle=50, evd_last_scan=True, add_blender_mesh=False, add_noisy_blender_mesh=False, simulation_time=0.0, laser_mirror_distance=0.05, world_transformation=Matrix()): inv_scan_x = scanner_object.inv_scan_x inv_scan_y = scanner_object.inv_scan_y inv_scan_z = scanner_object.inv_scan_z start_time = time.time() current_time = simulation_time delta_rot = angle_resolution * math.pi / 180 evd_storage = evd.evd_file(evd_file) xaxis = Vector([1, 0, 0]) yaxis = Vector([0, 1, 0]) zaxis = Vector([0, 0, 1]) rays = [] ray_info = [] angles = end_angle - start_angle steps_per_rotation = angles / angle_resolution time_per_step = (1.0 / rotation_speed) / steps_per_rotation lines = (end_angle - start_angle) / angle_resolution for line in range(int(lines)): for laser_idx in range(len(laser_angles)): current_angle = start_angle + float(line) * angles / float(lines) [ray, origion, laser_angle] = calculateRay(laser_angles[laser_idx], deg2rad(current_angle), laser_mirror_distance) #TODO: Use the origin to cast the ray. Requires changes to the blender patch rot_angle = 1e-6 + current_angle + 180.0 timestamp = ( (rot_angle - 180.0) / angle_resolution) * time_per_step rot_angle = rot_angle % 360.0 ray_info.append([deg2rad(rot_angle), laser_angle, timestamp]) rays.extend([ray[0], ray[1], ray[2]]) returns = blensor.scan_interface.scan_rays(rays, max_distance, inv_scan_x=inv_scan_x, inv_scan_y=inv_scan_y, inv_scan_z=inv_scan_z) reusable_vector = Vector([0.0, 0.0, 0.0, 0.0]) for i in range(len(returns)): idx = returns[i][-1] reusable_vector.xyzw = [ returns[i][1], returns[i][2], returns[i][3], 1.0 ] vt = (world_transformation * reusable_vector).xyz v = [returns[i][1], returns[i][2], returns[i][3]] distance_noise = laser_noise[idx % len(laser_noise)] + random.gauss( noise_mu, noise_sigma) vector_length = math.sqrt(v[0]**2 + v[1]**2 + v[2]**2) norm_vector = [ v[0] / vector_length, v[1] / vector_length, v[2] / vector_length ] vector_length_noise = vector_length + distance_noise reusable_vector.xyzw = [ norm_vector[0] * vector_length_noise, norm_vector[1] * vector_length_noise, norm_vector[2] * vector_length_noise, 1.0 ] v_noise = (world_transformation * reusable_vector).xyz evd_storage.addEntry(timestamp=ray_info[idx][2], yaw=(ray_info[idx][0] + math.pi) % (2 * math.pi), pitch=ray_info[idx][1], distance=vector_length, distance_noise=vector_length_noise, x=vt[0], y=vt[1], z=vt[2], x_noise=v_noise[0], y_noise=v_noise[1], z_noise=v_noise[2], object_id=returns[i][4], color=returns[i][5]) current_angle = start_angle + float(float(int(lines)) * angle_resolution) if evd_file: evd_storage.appendEvdFile() if not evd_storage.isEmpty(): scan_data = numpy.array(evd_storage.buffer) additional_data = None if scanner_object.store_data_in_mesh: additional_data = evd_storage.buffer if add_blender_mesh: mesh_utils.add_mesh_from_points_tf(scan_data[:, 5:8], "Scan", world_transformation, buffer=additional_data) if add_noisy_blender_mesh: mesh_utils.add_mesh_from_points_tf(scan_data[:, 8:11], "NoisyScan", world_transformation, buffer=additional_data) bpy.context.scene.update() end_time = time.time() scan_time = end_time - start_time print("Elapsed time: %.3f" % (scan_time)) return True, current_angle, scan_time
def get_width(self, o): x = (Vector(o.bound_box[4]) - Vector(o.bound_box[0])).length y = (Vector(o.bound_box[3]) - Vector(o.bound_box[0])).length return min(x, y)
def vec_mult(v1, v2): """ componentwise multiplication for vectors """ return Vector(e1 * e2 for e1, e2 in zip(v1, v2))
def initialise_convenience_variables(self): self.wall1_matrix = self.wall1.matrix_world if self.wall2: self.wall2_matrix = self.wall2.matrix_world self.pos_x = self.wall1_matrix.to_quaternion() @ Vector((1, 0, 0)) self.neg_x = self.wall1_matrix.to_quaternion() @ Vector((-1, 0, 0))