Skip to content
Snippets Groups Projects
mesh_carver.py 133 KiB
Newer Older
  • Learn to ignore specific revisions
  •     if self.gapy < 0:
            self.gapy = 0
    
    
        # Get the data from the profils or the object
    
        if self.ProfileMode:
    
            brush = bpy.data.objects.new(
                        self.Profils[self.nProfil][0],
                        bpy.data.meshes[self.Profils[self.nProfil][0]]
                        )
    
            obj = bpy.data.objects["CT_Profil"]
            obfaces = brush.data.polygons
            obverts = brush.data.vertices
            lenverts = len(obverts)
        else:
            brush = bpy.data.objects["CarverBrushCopy"]
            obj = context.selected_objects[0]
            obverts = brush.data.vertices
            obfaces = brush.data.polygons
            lenverts = len(brush.data.vertices)
    
    
        # Gap between each row / column
    
        gapx = self.gapx
        gapy = self.gapy
    
    
        # Width of each row / column
    
        widthx = brush.dimensions.x * self.scale_x
        widthy = brush.dimensions.y * self.scale_y
    
    
        # Compute the corners so the new object will be always at the center
    
        left = -((self.nbcol - 1) * (widthx + gapx)) / 2
        start = -((self.nbrow - 1) * (widthy + gapy)) / 2
    
        for i in range(self.nbrow * self.nbcol):
            row = i % self.nbrow
            col = i // self.nbrow
            startx = left + ((widthx + gapx) * col)
            starty = start + ((widthy + gapy) * row)
    
    
            # Add random rotation
    
            if (self.RandomRotation) and not (self.GridScaleX or self.GridScaleY):
    
                rotmat = Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z')
    
                for v in obverts:
                    v.co = v.co * rotmat
    
            verts.extend([((v.co.x - startx, v.co.y - starty, v.co.z)) for v in obverts])
            faces.extend([[v + numface * lenverts for v in p.vertices] for p in obfaces])
            numface += 1
    
    
        # Update the mesh
    
        # Create mesh data
        mymesh = bpy.data.meshes.new("CT_Profil")
        # Generate mesh data
        mymesh.from_pydata(verts, edges, faces)
        # Calculate the edges
        mymesh.update(calc_edges=True)
        # Update data
        obj.data = mymesh
    
        # Make the object active to remove doubles
    
        context.scene.objects.active = obj
    
    
    
    def boolean_operation(bool_type="DIFFERENCE"):
    
        ActiveObj = bpy.context.active_object
    
        sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1
    
        bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
        BoolMod = ActiveObj.modifiers.new(
                        "CT_" + bpy.context.selected_objects[sel_index].name,
                        "BOOLEAN"
                        )
        BoolMod.object = bpy.context.selected_objects[sel_index]
        BoolMod.operation = bool_type
    
        bpy.context.selected_objects[sel_index].display_type = 'WIRE'
    
    
    
    def Rebool(context, self):
        LastObj = context.active_object
    
        Brush = context.selected_objects[0]
    
        Brush.display_type = "WIRE"
    
        obj = context.selected_objects[1]
    
        bpy.ops.object.select_all(action='TOGGLE')
    
        context.scene.objects.active = obj
    
        obj.display_type = "SOLID"
    
        obj.select = True
        bpy.ops.object.duplicate_move(
            OBJECT_OT_duplicate={
                "linked": False,
                "mode": 'TRANSLATION',
            },
            TRANSFORM_OT_translate={
                "value": (0, 0, 0),
                "constraint_axis": (False, False, False),
                "constraint_orientation": 'GLOBAL',
                "mirror": False,
                "proportional": 'DISABLED',
                "proportional_edit_falloff": 'SMOOTH',
                "proportional_size": 1,
                "snap": False,
                "snap_target": 'CLOSEST',
                "snap_point": (0, 0, 0),
                "snap_align": False,
                "snap_normal": (0, 0, 0),
                "gpencil_strokes": False,
                "texture_space": False,
                "remove_on_cancel": False,
                "release_confirm": False,
            },
        )
        LastObjectCreated = context.active_object
    
        m = LastObjectCreated.modifiers.new("CT_INTERSECT", "BOOLEAN")
        m.operation = "INTERSECT"
        m.object = Brush
    
        m = obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN")
        m.operation = "DIFFERENCE"
        m.object = Brush
    
        for mb in LastObj.modifiers:
            if mb.type == 'BEVEL':
                mb.show_viewport = False
    
        if self.ObjectBrush or self.ProfileBrush:
    
            LastObjectCreated.show_in_front = False
    
            try:
                bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
            except:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                self.report({'ERROR'}, str(exc_value))
    
    
        if self.DontApply is False:
    
            try:
                bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_INTERSECT")
            except:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                self.report({'ERROR'}, str(exc_value))
    
        bpy.ops.object.select_all(action='TOGGLE')
    
        for mb in LastObj.modifiers:
            if mb.type == 'BEVEL':
                mb.show_viewport = True
    
        context.scene.objects.active = obj
        obj.select = True
    
        if self.DontApply is False:
    
            try:
                bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_DIFFERENCE")
            except:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                self.report({'ERROR'}, str(exc_value))
    
        bpy.ops.object.select_all(action='TOGGLE')
    
        LastObjectCreated.select = True
    
    
    def createMeshFromData(self):
        if self.Profils[self.nProfil][0] not in bpy.data.meshes:
            # Create mesh and object
            me = bpy.data.meshes.new(self.Profils[self.nProfil][0])
    
            # Create mesh from given verts, faces.
    
            me.from_pydata(self.Profils[self.nProfil][2], [], self.Profils[self.nProfil][3])
            # Update mesh with new data
            me.update()
    
        if "CT_Profil" not in bpy.data.objects:
            ob = bpy.data.objects.new("CT_Profil", bpy.data.meshes[self.Profils[self.nProfil][0]])
    
            ob.location = Vector((0.0, 0.0, 0.0))
    
    
            # Link object to scene and make active
            scn = bpy.context.scene
            scn.objects.link(ob)
            scn.objects.active = ob
            ob.select = True
    
            ob.location = Vector((10000.0, 0.0, 0.0))
    
            ob.display_type = "WIRE"
    
    
            self.SolidifyPossible = True
        else:
            bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]]
    
    
    
    def Selection_Save_Restore(self):
        if "CT_Profil" in bpy.data.objects:
            Selection_Save(self)
            bpy.ops.object.select_all(action='DESELECT')
            bpy.data.objects["CT_Profil"].select = True
            bpy.context.scene.objects.active = bpy.data.objects["CT_Profil"]
            if bpy.data.objects["CT_Profil"] in self.SavSel:
                self.SavSel.remove(bpy.data.objects["CT_Profil"])
            bpy.ops.object.delete(use_global=False)
            Selection_Restore(self)
    
    
    
    def Selection_Save(self):
    
        obj_name = getattr(bpy.context.active_object, "name", None)
    
        self.SavSel = bpy.context.selected_objects.copy()
    
        self.Sav_ac = obj_name
    
    
    
    def Selection_Restore(self):
        for o in self.SavSel:
            o.select = True
    
        if self.Sav_ac:
            bpy.context.scene.objects.active = bpy.data.objects.get(self.Sav_ac, None)
    
    
    
    # Modal Operator
    class Carver(bpy.types.Operator):
        bl_idname = "object.carver"
        bl_label = "Carver"
    
        bl_description = "Cut or create Meshes in Object mode"
    
        bl_options = {'REGISTER', 'UNDO'}
    
        @classmethod
        def poll(cls, context):
            ob = None
            if len(context.selected_objects) > 0:
                ob = context.selected_objects[0]
            # Test if selected object or none (for create mode)
            return (
                (ob and ob.type == 'MESH' and context.mode == 'OBJECT') or
                (context.mode == 'OBJECT' and ob is None) or
                (context.mode == 'EDIT_MESH'))
    
        def modal(self, context, event):
            PI = 3.14156
            region_types = {'WINDOW', 'UI'}
            win = context.window
    
            for area in win.screen.areas:
                if area.type in ('VIEW_3D'):
                    for region in area.regions:
                        if not region_types or region.type in region_types:
                            region.tag_redraw()
    
            if event.type in {
                    'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE',
                    'NUMPAD_1', 'NUMPAD_2', 'NUMPAD_3', 'NUMPAD_4', 'NUMPAD_6',
                    'NUMPAD_7', 'NUMPAD_8', 'NUMPAD_9', 'NUMPAD_5'}:
                return {'PASS_THROUGH'}
            try:
                # [Shift]
    
                self.shift = True if event.shift else False
    
                self.ctrl = True if event.ctrl else False
    
    
                # [Alt]
                self.alt = False
                if event.alt:
    
                    if self.InitPosition is False:
    
                        # Initialise position variable for start position
                        self.xpos = 0
                        self.ypos = 0
                        self.last_mouse_region_x = event.mouse_region_x
                        self.last_mouse_region_y = event.mouse_region_y
                        self.InitPosition = True
                    self.alt = True
                # [Alt] release
    
                if self.InitPosition and self.alt is False:
    
                    # Update coordinates
    
                    for i in range(0, len(self.mouse_path)):
                        l = list(self.mouse_path[i])
                        l[0] += self.xpos
                        l[1] += self.ypos
                        self.mouse_path[i] = tuple(l)
    
                    self.xpos = self.ypos = 0
                    self.InitPosition = False
    
                # Mode change (cut type)
                if event.type == 'SPACE' and event.value == 'PRESS':
                    if self.ObjectMode or self.ProfileMode:
                        # If grid, remove double with intersect meshes
                        if ((self.nbcol + self.nbrow) > 3):
                            # Go in edit mode mode
                            bpy.ops.object.mode_set(mode='EDIT')
                            # Remove duplicate vertices
                            bpy.ops.mesh.remove_doubles()
                            # Return in object mode
                            bpy.ops.object.mode_set(mode='OBJECT')
    
                        if self.alt:
                            # Save selected objects
                            self.SavSel = context.selected_objects.copy()
                            if len(context.selected_objects) > 0:
                                bpy.ops.object.select_all(action='TOGGLE')
    
                            if self.ObjectMode:
                                SelectObject(self, self.ObjectBrush)
                            else:
                                SelectObject(self, self.ProfileBrush)
                            duplicateObject(self)
                        else:
                            # Brush Cut
                            self.Cut()
                            # Save selected objects
                            if self.ObjectMode:
                                if len(self.ObjectBrush.children) > 0:
                                    self.SavSel = context.selected_objects.copy()
                                    if len(context.selected_objects) > 0:
                                        bpy.ops.object.select_all(action='TOGGLE')
    
                                    if self.ObjectMode:
                                        SelectObject(self, self.ObjectBrush)
                                    else:
                                        SelectObject(self, self.ProfileBrush)
                                    duplicateObject(self)
    
                            UndoListUpdate(self)
    
                        # Save cursor position
                        self.SavMousePos = self.CurLoc
                    else:
    
                        if self.bDone is False:
    
                            # Cut Mode
                            self.CutMode += 1
                            if self.CutMode > 2:
                                self.CutMode = 0
                        else:
                            if self.CutMode == LINE:
                                # Cuts creation
                                CreateCutLine(self, context)
                                if self.CreateMode:
                                    # Object creation
                                    self.CreateGeometry()
                                    bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                                    # Cursor Snap
    
                                    context.scene.mesh_carver.DepthCursor = self.snapCursor
    
                                    # Object Instantiate
    
                                    context.scene.mesh_carver.OInstanciate = self.Instantiate
    
                                    # Random rotation
    
                                    context.scene.mesh_carver.ORandom = self.RandomRotation
    
    
                                    return {'FINISHED'}
                                else:
                                    self.Cut()
                                    UndoListUpdate(self)
    
                # Object creation
                if event.type == context.scene.Key_Create and event.value == 'PRESS':
    
                    if self.ExclusiveCreateMode is False:
    
                        self.CreateMode = not self.CreateMode
    
                # Auto Bevel Update
                if event.type == context.scene.Key_Update and event.value == 'PRESS':
                    self.Auto_BevelUpdate = not self.Auto_BevelUpdate
    
                # Boolean operation type
                if event.type == context.scene.Key_Bool and event.value == 'PRESS':
    
                    if (self.ProfileMode is True) or (self.ObjectMode is True):
    
                        if self.BoolOps == DIFFERENCE:
                            self.BoolOps = UNION
                        else:
                            self.BoolOps = DIFFERENCE
    
                # Brush Mode
                if event.type == context.scene.Key_Brush and event.value == 'PRESS':
                    self.DontApply = False
    
                    if (self.ProfileMode is False) and (self.ObjectMode is False):
    
                        self.ProfileMode = True
                    else:
                        self.ProfileMode = False
                        if self.ObjectBrush is not None:
    
                            if self.ObjectMode is False:
    
                                self.ObjectMode = True
                                self.BrushSolidify = False
                                self.CList = self.OB_List
    
    
                                Selection_Save_Restore(self)
                                context.scene.mesh_carver.nProfile = self.nProfil
    
                            else:
                                self.ObjectMode = False
                        else:
                            self.BrushSolidify = False
    
                            Selection_Save_Restore(self)
    
    
                    if self.ProfileMode:
                        createMeshFromData(self)
                        self.ProfileBrush = bpy.data.objects["CT_Profil"]
                        Selection_Save(self)
                        self.BrushSolidify = True
    
                        bpy.ops.object.select_all(action='TOGGLE')
                        self.ProfileBrush.select = True
                        context.scene.objects.active = self.ProfileBrush
                        # Set xRay
    
                        self.ProfileBrush.show_in_front = True
    
    
                        bpy.ops.object.modifier_add(type='SOLIDIFY')
                        context.object.modifiers["Solidify"].name = "CT_SOLIDIFY"
                        context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1
    
                        Selection_Restore(self)
    
                        self.CList = self.CurrentSelection
                    else:
                        if self.ObjectBrush is not None:
    
                            if self.ObjectMode is False:
    
                                if self.ObjectBrush is not None:
                                    self.ObjectBrush.location = self.InitBrushPosition
                                    self.ObjectBrush.scale = self.InitBrushScale
                                    self.ObjectBrush.rotation_quaternion = self.InitBrushQRotation
                                    self.ObjectBrush.rotation_euler = self.InitBrushERotation
    
                                    self.ObjectBrush.display_type = self.ObjectBrush_DT
                                    self.ObjectBrush.show_in_front = self.XRay
    
    
                                    # Remove solidify modifier
                                    Selection_Save(self)
                                    self.BrushSolidify = False
    
                                    bpy.ops.object.select_all(action='TOGGLE')
                                    self.ObjectBrush.select = True
                                    context.scene.objects.active = self.ObjectBrush
    
                                    bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY")
    
                                    Selection_Restore(self)
                            else:
                                if self.Solidify_Active_Start:
                                    Selection_Save(self)
                                    self.BrushSolidify = True
                                    self.SolidifyPossible = True
                                    bpy.ops.object.select_all(action='TOGGLE')
                                    self.ObjectBrush.select = True
                                    context.scene.objects.active = self.ObjectBrush
                                    # Set xRay
    
                                    self.ObjectBrush.show_in_front = True
    
                                    bpy.ops.object.modifier_add(type='SOLIDIFY')
                                    context.object.modifiers["Solidify"].name = "CT_SOLIDIFY"
                                    context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1
                                    Selection_Restore(self)
    
                # Help display
                if event.type == context.scene.Key_Help and event.value == 'PRESS':
                    self.AskHelp = not self.AskHelp
    
                # Instantiate object
                if event.type == context.scene.Key_Instant and event.value == 'PRESS':
                    self.Instantiate = not self.Instantiate
    
                # Close polygonal shape
                if event.type == context.scene.Key_Close and event.value == 'PRESS':
                    if self.CreateMode:
                        self.Closed = not self.Closed
    
                if event.type == context.scene.Key_Apply and event.value == 'PRESS':
                    self.DontApply = not self.DontApply
    
                # Scale object
                if event.type == context.scene.Key_Scale and event.value == 'PRESS':
    
                    if self.ObjectScale is False:
    
                        self.am = event.mouse_region_x, event.mouse_region_y
    
                    self.ObjectScale = True
    
                # Grid : Add column
                if event.type == 'UP_ARROW' and event.value == 'PRESS':
                    self.nbcol += 1
                    update_grid(self, context)
    
                # Grid : Add row
                elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS':
                    self.nbrow += 1
                    update_grid(self, context)
    
                # Grid : Delete column
                elif event.type == 'DOWN_ARROW' and event.value == 'PRESS':
                    self.nbcol -= 1
                    update_grid(self, context)
    
                # Grid : Delete row
                elif event.type == 'LEFT_ARROW' and event.value == 'PRESS':
                    self.nbrow -= 1
                    update_grid(self, context)
    
                # Grid : Scale gap between columns
                if event.type == context.scene.Key_Gapy and event.value == 'PRESS':
    
                    if self.GridScaleX is False:
    
                        self.am = event.mouse_region_x, event.mouse_region_y
                    self.GridScaleX = True
    
                # Grid : Scale gap between rows
                if event.type == context.scene.Key_Gapx and event.value == 'PRESS':
    
                    if self.GridScaleY is False:
    
                        self.am = event.mouse_region_x, event.mouse_region_y
                    self.GridScaleY = True
    
                # Cursor depth or solidify pattern
                if event.type == context.scene.Key_Depth and event.value == 'PRESS':
    
                    if (self.ObjectMode is False) and (self.ProfileMode is False):
    
                        self.snapCursor = not self.snapCursor
                    else:
                        # Solidify
    
                        if (self.ObjectMode or self.ProfileMode) and (self.SolidifyPossible):
                            solidify = True
    
                            if self.ObjectMode:
                                z = self.ObjectBrush.data.vertices[0].co.z
                                ErrorMarge = 0.01
                                for v in self.ObjectBrush.data.vertices:
                                    if abs(v.co.z - z) > ErrorMarge:
                                        solidify = False
    
                                        self.CarveDepth = True
    
                                        self.am = event.mouse_region_x, event.mouse_region_y
                                        break
    
                            if solidify:
                                if self.ObjectMode:
                                    for mb in self.ObjectBrush.modifiers:
                                        if mb.type == 'SOLIDIFY':
                                            AlreadySoldify = True
                                else:
                                    for mb in self.ProfileBrush.modifiers:
                                        if mb.type == 'SOLIDIFY':
                                            AlreadySoldify = True
    
    
                                if AlreadySoldify is False:
    
                                    Selection_Save(self)
                                    self.BrushSolidify = True
    
                                    bpy.ops.object.select_all(action='TOGGLE')
                                    if self.ObjectMode:
                                        self.ObjectBrush.select = True
                                        context.scene.objects.active = self.ObjectBrush
                                        # Active le xray
    
                                        self.ObjectBrush.show_in_front = True
    
                                    else:
                                        self.ProfileBrush.select = True
                                        context.scene.objects.active = self.ProfileBrush
                                        # Active le xray
    
                                        self.ProfileBrush.show_in_front = True
    
    
                                    bpy.ops.object.modifier_add(type='SOLIDIFY')
                                    context.object.modifiers["Solidify"].name = "CT_SOLIDIFY"
    
                                    context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1
    
                                    Selection_Restore(self)
    
                                self.WidthSolidify = not self.WidthSolidify
                                self.am = event.mouse_region_x, event.mouse_region_y
    
    
                if event.type == context.scene.Key_BrushDepth and event.value == 'PRESS':
                    if self.ObjectMode:
                        self.CarveDepth = False
    
                        self.BrushDepth = True
                        self.am = event.mouse_region_x, event.mouse_region_y
    
    
                # Random rotation
                if event.type == 'R' and event.value == 'PRESS':
                    self.RandomRotation = not self.RandomRotation
    
                # Undo
                if event.type == 'Z' and event.value == 'PRESS':
                    if self.ctrl:
                        if (self.CutMode == LINE) and (self.bDone):
                            if len(self.mouse_path) > 1:
                                self.mouse_path[len(self.mouse_path) - 1:] = []
                        else:
                            Undo(self)
    
                # Mouse move
                if event.type == 'MOUSEMOVE':
    
                    if self.ObjectMode or self.ProfileMode:
                        fac = 50.0
                        if self.shift:
                            fac = 500.0
                        if self.WidthSolidify:
                            if self.ObjectMode:
                                bpy.data.objects[self.ObjectBrush.name].modifiers[
                                    "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.am[0]) / fac
                            elif self.ProfileMode:
                                bpy.data.objects[self.ProfileBrush.name].modifiers[
                                    "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.am[0]) / fac
                            self.am = event.mouse_region_x, event.mouse_region_y
    
                        elif self.CarveDepth:
    
                            for v in self.ObjectBrush.data.vertices:
                                v.co.z += (event.mouse_region_x - self.am[0]) / fac
                            self.am = event.mouse_region_x, event.mouse_region_y
    
                        elif self.BrushDepth:
                            self.BrushDepthOffset += (event.mouse_region_x - self.am[0]) / fac
                            self.am = event.mouse_region_x, event.mouse_region_y
    
                        else:
                            if (self.GridScaleX):
                                self.gapx += (event.mouse_region_x - self.am[0]) / 50
                                self.am = event.mouse_region_x, event.mouse_region_y
                                update_grid(self, context)
                                return {'RUNNING_MODAL'}
    
                            elif (self.GridScaleY):
                                self.gapy += (event.mouse_region_x - self.am[0]) / 50
                                self.am = event.mouse_region_x, event.mouse_region_y
                                update_grid(self, context)
                                return {'RUNNING_MODAL'}
    
                            elif self.ObjectScale:
                                self.ascale = -(event.mouse_region_x - self.am[0])
                                self.am = event.mouse_region_x, event.mouse_region_y
    
                                if self.ObjectMode:
                                    self.ObjectBrush.scale.x -= float(self.ascale) / 150.0
                                    if self.ObjectBrush.scale.x <= 0.0:
                                        self.ObjectBrush.scale.x = 0.0
                                    self.ObjectBrush.scale.y -= float(self.ascale) / 150.0
                                    if self.ObjectBrush.scale.y <= 0.0:
                                        self.ObjectBrush.scale.y = 0.0
                                    self.ObjectBrush.scale.z -= float(self.ascale) / 150.0
                                    if self.ObjectBrush.scale.z <= 0.0:
                                        self.ObjectBrush.scale.z = 0.0
    
                                elif self.ProfileMode:
                                    if self.ProfileBrush is not None:
                                        self.ProfileBrush.scale.x -= float(self.ascale) / 150.0
                                        self.ProfileBrush.scale.y -= float(self.ascale) / 150.0
                                        self.ProfileBrush.scale.z -= float(self.ascale) / 150.0
                            else:
                                if self.LMB:
                                    if self.ctrl:
                                        self.aRotZ = - \
                                            ((int((event.mouse_region_x - self.xSavMouse) / 10.0) * PI / 4.0) * 25.0)
                                    else:
                                        self.aRotZ -= event.mouse_region_x - self.am[0]
                                    self.ascale = 0.0
    
                                    self.am = event.mouse_region_x, event.mouse_region_y
                                else:
                                    vBack = Pick(context, event, self)
                                    if vBack[0] is not None:
                                        self.ShowCursor = True
    
                                        NormalObject = Vector((0.0, 0.0, 1.0))
    
                                        qR = RBenVe(NormalObject, vBack[1])
    
                                        self.qRot = vBack[3] * qR
    
                                        MoveCursor(qR, vBack[0], self)
                                        self.SavCurLoc = vBack[0]
                                        if self.ctrl:
                                            if self.SavMousePos is not None:
                                                xEcart = abs(self.SavMousePos.x - self.SavCurLoc.x)
                                                yEcart = abs(self.SavMousePos.y - self.SavCurLoc.y)
                                                zEcart = abs(self.SavMousePos.z - self.SavCurLoc.z)
                                                if (xEcart > yEcart) and (xEcart > zEcart):
    
                                                    self.CurLoc = Vector(
    
                                                        (vBack[0].x, self.SavMousePos.y, self.SavMousePos.z))
                                                if (yEcart > xEcart) and (yEcart > zEcart):
    
                                                    self.CurLoc = Vector(
    
                                                        (self.SavMousePos.x, vBack[0].y, self.SavMousePos.z))
                                                if (zEcart > xEcart) and (zEcart > yEcart):
    
                                                    self.CurLoc = Vector(
    
                                                        (self.SavMousePos.x, self.SavMousePos.y, vBack[0].z))
                                                else:
                                                    self.CurLoc = vBack[0]
                                        else:
                                            self.CurLoc = vBack[0]
                    else:
                        if self.bDone:
    
                            if self.alt is False:
    
                                if self.bDone:
                                    if self.ctrl and (self.CutMode == LINE):
                                        # Incremental mode
                                        coord = list(self.mouse_path[len(self.mouse_path) - 1])
    
                                        coord[0] = int(
                                                    self.mouse_path[len(self.mouse_path) - 2][0] +
                                                    int((event.mouse_region_x -
                                                        self.mouse_path[len(self.mouse_path) - 2][0]
                                                        ) / self.Increment) * self.Increment
                                                    )
                                        coord[1] = int(
                                                    self.mouse_path[len(self.mouse_path) - 2][1] +
                                                    int((event.mouse_region_y -
                                                        self.mouse_path[len(self.mouse_path) - 2][1]
                                                        ) / self.Increment) * self.Increment
                                                    )
    
                                        self.mouse_path[len(self.mouse_path) - 1] = tuple(coord)
                                    else:
                                        if len(self.mouse_path) > 0:
                                            self.mouse_path[len(self.mouse_path) -
                                                            1] = (event.mouse_region_x, event.mouse_region_y)
                            else:
                                # [ALT] press, update position
                                self.xpos += (event.mouse_region_x - self.last_mouse_region_x)
                                self.ypos += (event.mouse_region_y - self.last_mouse_region_y)
    
                                self.last_mouse_region_x = event.mouse_region_x
                                self.last_mouse_region_y = event.mouse_region_y
    
                elif event.type == 'LEFTMOUSE' and event.value == 'PRESS':
                    if self.ObjectMode or self.ProfileMode:
    
                        if self.LMB is False:
    
                            vBack = Pick(context, event, self)
                            if vBack[0] is not None:
    
                                NormalObject = Vector((0.0, 0.0, 1.0))
    
                                self.aqR = RBenVe(NormalObject, vBack[1])
    
                                self.qRot = vBack[3] * self.aqR
    
                            self.am = event.mouse_region_x, event.mouse_region_y
                            self.xSavMouse = event.mouse_region_x
    
                            if self.ctrl:
                                self.nRotZ = int((self.aRotZ / 25.0) / (PI / 4.0))
                                self.aRotZ = self.nRotZ * (PI / 4.0) * 25.0
    
                        self.LMB = True
    
                # LEFTMOUSE
                elif event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
                    if self.ObjectMode or self.ProfileMode:
                        # Rotation and scale
                        self.LMB = False
    
                        if self.ObjectScale is True:
    
                            self.ObjectScale = False
    
    
                        if self.GridScaleX is True:
    
                            self.GridScaleX = False
    
    
                        if self.GridScaleY is True:
    
                            self.GridScaleY = False
    
                        if self.WidthSolidify:
                            self.WidthSolidify = False
    
    
                        if self.CarveDepth is True:
    
                            self.CarveDepth = False
    
    
                        if self.BrushDepth is True:
    
                            self.BrushDepth = False
    
                    else:
    
                        if self.bDone is False:
    
                            if self.ctrl:
                                Picking(context, event)
                            else:
                                if self.CutMode == LINE:
    
                                    if self.bDone is False:
    
                                        self.mouse_path.clear()
                                        self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
                                        self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
                                else:
                                    self.mouse_path[0] = (event.mouse_region_x, event.mouse_region_y)
                                    self.mouse_path[1] = (event.mouse_region_x, event.mouse_region_y)
                                self.bDone = True
                        else:
                            if self.CutMode != LINE:
                                # Cut creation
                                if self.CutMode == RECTANGLE:
                                    CreateCutSquare(self, context)
                                if self.CutMode == CIRCLE:
                                    CreateCutCircle(self, context)
                                if self.CutMode == LINE:
                                    CreateCutLine(self, context)
    
                                if self.CreateMode:
                                    # Object creation
                                    self.CreateGeometry()
                                    bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                                    # Depth Cursor
    
                                    context.scene.mesh_carver.DepthCursor = self.snapCursor
    
                                    # Instantiate object
    
                                    context.scene.mesh_carver.OInstanciate = self.Instantiate
    
                                    # Random rotation
    
                                    context.scene.mesh_carver.ORandom = self.RandomRotation
    
                                    # Apply operation
    
                                    context.scene.mesh_carver.DontApply = self.DontApply
    
    
                                    # if Object mode, set intiale state
                                    if self.ObjectBrush is not None:
                                        self.ObjectBrush.location = self.InitBrushPosition
                                        self.ObjectBrush.scale = self.InitBrushScale
                                        self.ObjectBrush.rotation_quaternion = self.InitBrushQRotation
                                        self.ObjectBrush.rotation_euler = self.InitBrushERotation
    
                                        self.ObjectBrush.display_type = self.ObjectBrush_DT
                                        self.ObjectBrush.show_in_front = self.XRay
    
    
                                        # remove solidify
                                        Selection_Save(self)
                                        self.BrushSolidify = False
    
                                        bpy.ops.object.select_all(action='TOGGLE')
                                        self.ObjectBrush.select = True
                                        context.scene.objects.active = self.ObjectBrush
    
                                        bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY")
    
                                        Selection_Restore(self)
    
    
                                        context.scene.mesh_carver.nProfile = self.nProfil
    
    
                                    return {'FINISHED'}
                                else:
                                    self.Cut()
                                    UndoListUpdate(self)
                            else:
                                # Line
                                self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
    
                # Change circle subdivisions
    
                elif (event.type == 'COMMA' and event.value == 'PRESS') or \
                            (event.type == context.scene.Key_Subrem and event.value == 'PRESS'):
    
                    if self.ProfileMode:
                        self.nProfil += 1
                        if self.nProfil >= self.MaxProfil:
                            self.nProfil = 0
                        createMeshFromData(self)
                    # Circle rotation
                    if self.CutMode == CIRCLE:
                        if self.ctrl:
                            self.stepRotation += 1
                        else:
                            self.step += 1
                            if self.step >= len(self.stepAngle):
                                self.step = len(self.stepAngle) - 1
    
                elif (event.type == 'PERIOD' and event.value == 'PRESS') or \
                            (event.type == context.scene.Key_Subadd and event.value == 'PRESS'):
    
                    if self.ProfileMode:
                        self.nProfil -= 1
                        if self.nProfil < 0:
                            self.nProfil = self.MaxProfil - 1
                        createMeshFromData(self)
                    if self.CutMode == CIRCLE:
                        if self.ctrl:
                            self.stepRotation -= 1
                        else:
                            if self.step > 0:
                                self.step -= 1
                # Quit
                elif event.type in {'RIGHTMOUSE', 'ESC'}:
                    # Depth Cursor
    
                    context.scene.mesh_carver.DepthCursor = self.snapCursor
    
                    # Instantiate object
    
                    context.scene.mesh_carver.OInstanciate = self.Instantiate
    
                    # Random Rotation
    
                    context.scene.mesh_carver.ORandom = self.RandomRotation
    
                    # Apply boolean operation
    
                    context.scene.mesh_carver.DontApply = self.DontApply
    
    
                    # Reset Object
                    if self.ObjectBrush is not None:
                        self.ObjectBrush.location = self.InitBrushPosition
                        self.ObjectBrush.scale = self.InitBrushScale
                        self.ObjectBrush.rotation_quaternion = self.InitBrushQRotation
                        self.ObjectBrush.rotation_euler = self.InitBrushERotation
    
                        self.ObjectBrush.display_type = self.ObjectBrush_DT
                        self.ObjectBrush.show_in_front = self.XRay
    
    
                        # Remove solidify modifier
                        Selection_Save(self)
                        self.BrushSolidify = False
    
                        bpy.ops.object.select_all(action='TOGGLE')
                        self.ObjectBrush.select = True
                        context.scene.objects.active = self.ObjectBrush
    
                        bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY")
                        bpy.ops.object.select_all(action='TOGGLE')
    
                        Selection_Restore(self)
    
    
                    Selection_Save_Restore(self)
    
                    context.scene.objects.active = self.CurrentActive
    
                    context.scene.mesh_carver.nProfile = self.nProfil
    
    
                    bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
    
                    # Remove Copy Object Brush
                    if bpy.data.objects.get("CarverBrushCopy") is not None:
                        brush = bpy.data.objects["CarverBrushCopy"]
                        self.ObjectBrush.data = bpy.data.meshes[brush.data.name]
                        bpy.ops.object.select_all(action='DESELECT')
                        bpy.data.objects["CarverBrushCopy"].select = True
                        bpy.ops.object.delete()
    
                    return {'FINISHED'}
    
                return {'RUNNING_MODAL'}
    
            except:
    
                print("\n[Carver MT ERROR]\n")
                import traceback
                traceback.print_exc()
    
    
                context.window.cursor_modal_set("DEFAULT")
                context.area.header_text_set()
                bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
    
    
                self.report({'WARNING'},
                            "Operation finished. Failure during Carving (Check the console for more info)")
    
    
        def cancel(self, context):
            # Note: used to prevent memory leaks on quiting Blender while the modal operator
            # is still running, gets called on return {"CANCELLED"}
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
    
    
        def invoke(self, context, event):
    
            if context.area.type != 'VIEW_3D':
                self.report({'WARNING'},
                            "View3D not found or not currently active. Operation Cancelled")
                return {'CANCELLED'}
    
            if context.mode == 'EDIT_MESH':
                bpy.ops.object.mode_set(mode='OBJECT')
    
            # test if some other object types are selected that are not meshes
            test_selection = True
            for obj in context.selected_objects:
                if obj.type != "MESH":
                    test_selection = False
                    break
            if not test_selection:
                self.report({'WARNING'},
                            "Some selected objects are not of the Mesh type. Operation Cancelled")
                return {"CANCELLED"}
    
            # Get default patterns
            self.Profils = []
            for p in Profils:
                self.Profils.append((p[0], p[1], p[2], p[3]))
    
            for o in context.scene.objects:
                if not o.name.startswith(context.scene.ProfilePrefix):
                    continue
    
                # In-scene profiles may have changed, remove them to refresh
                for m in bpy.data.meshes:
                    if m.name.startswith(context.scene.ProfilePrefix):
                        bpy.data.meshes.remove(m)
    
                vertices = []
                for v in o.data.vertices:
                    vertices.append((v.co.x, v.co.y, v.co.z))
    
                faces = []
                for f in o.data.polygons:
                    face = []
                    for v in f.vertices:
                        face.append(v)
    
                    faces.append(face)
    
                self.Profils.append(
                    (o.name,
                    Vector((o.location.x, o.location.y, o.location.z)),
                    vertices, faces)
                )
    
            self.nProfil = context.scene.mesh_carver.nProfile
            self.MaxProfil = len(self.Profils)
    
            # reset selected profile if last profile exceeds length of array
            if self.nProfil >= self.MaxProfil:
                self.nProfil = context.scene.mesh_carver.nProfile = 0
    
            # Save selection
            self.CurrentSelection = context.selected_objects.copy()
            self.CurrentActive = context.active_object
            self.SavSel = context.selected_objects.copy()
            self.Sav_ac = None
    
            args = (self, context)
    
            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
    
            self.mouse_path = [(0, 0), (0, 0)]
    
            self.shift = False
            self.ctrl = False
            self.alt = False
            self.bDone = False
    
            self.DontApply = context.scene.mesh_carver.DontApply
            self.Auto_BevelUpdate = True
    
            # Cut type (Rectangle, Circle, Line)
            self.CutMode = 0
            self.BoolOps = DIFFERENCE
    
            # Circle variables
            self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90]
            self.step = 4
            self.stepRotation = 0
    
            # Primitives Position
            self.xpos = 0
            self.ypos = 0
            self.InitPosition = False
    
            # Line Increment
            self.Increment = 15
            # Close polygonal shape
            self.Closed = False
    
            # Depth Cursor
            self.snapCursor = context.scene.mesh_carver.DepthCursor