# 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)),
Example #2
0
# 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])
Example #3
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
Example #4
0
def MINMAX_INIT():
    return (Vector(
        (+FLT_MAX, +FLT_MAX, +FLT_MAX)), Vector(
            (-FLT_MAX, -FLT_MAX, -FLT_MAX)))
Example #5
0
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
Example #7
0
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
Example #8
0
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)
Example #9
0
#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
Example #10
0
    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'}
Example #11
0
    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.
Example #14
0
 def __init__(self, name, scale=Vector([1, 1, 1])):
     self.name = name
     self.scale = scale
Example #15
0
 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'}
Example #19
0
    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'}
Example #21
0
    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'}
Example #23
0
    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))
Example #25
0
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
Example #26
0
 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)
Example #27
0
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
Example #28
0
 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)
Example #29
0
def vec_mult(v1, v2):
    """ componentwise multiplication for vectors """
    return Vector(e1 * e2 for e1, e2 in zip(v1, v2))
Example #30
0
 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))