Skip to content
Snippets Groups Projects
mesh_carver.py 140 KiB
Newer Older
  • Learn to ignore specific revisions
  •     ob_new.location += self.qRot * v
    
    
        if self.ObjectMode:
            ob_new.scale = self.ObjectBrush.scale
        if self.ProfileMode:
            ob_new.scale = self.ProfileBrush.scale
    
        e = mathutils.Euler()
        e.x = e.y = 0.0
        e.z = self.aRotZ / 25.0
    
    
        # If duplicate with a grid, no random rotation (each mesh in the grid is already rotated randomly)
    
        if (self.alt == True) and ((self.nbcol + self.nbrow) < 3):
            if self.RandomRotation:
                e.z += random.random()
    
        qe = e.to_quaternion()
        qRot = self.qRot * qe
        ob_new.rotation_mode = 'QUATERNION'
        ob_new.rotation_quaternion = qRot
        ob_new.rotation_mode = 'XYZ'
    
        if (ob_new.draw_type == "WIRE") and (self.BrushSolidify == False):
            ob_new.hide = True
    
        if self.BrushSolidify:
            ob_new.draw_type = "SOLID"
            ob_new.show_x_ray = False
    
        for o in bpy.context.selected_objects:
            UndoAdd(self, "DUPLICATE", o)
    
        if len(bpy.context.selected_objects) > 0:
            bpy.ops.object.select_all(action='TOGGLE')
        for o in self.SavSel:
            o.select = True
    
        bpy.context.scene.objects.active = self.OpsObj
    
    
    def update_grid(self, context):
        """
        Thanks to batFINGER for his help :
        source : http://blender.stackexchange.com/questions/55864/multiple-meshes-not-welded-with-pydata
        """
        verts = []
        edges = []
        faces = []
        numface = 0
    
        if self.nbcol < 1:
            self.nbcol = 1
        if self.nbrow < 1:
            self.nbrow = 1
        if self.gapx < 0:
            self.gapx = 0
        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 = mathutils.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 the object the active one to remove double
        context.scene.objects.active = obj
    
    
    def boolean_difference():
        ActiveObj = bpy.context.active_object
    
        if bpy.context.selected_objects[0] != bpy.context.active_object:
            bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
            BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[0].name, "BOOLEAN")
            BoolMod.object = bpy.context.selected_objects[0]
            BoolMod.operation = "DIFFERENCE"
    
            BoolMod.solver = bpy.context.scene.CarverSolver
    
            bpy.context.selected_objects[0].draw_type = 'WIRE'
        else:
            BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[1].name, "BOOLEAN")
            BoolMod.object = bpy.context.selected_objects[1]
            BoolMod.operation = "DIFFERENCE"
    
            BoolMod.solver = bpy.context.scene.CarverSolver
    
            bpy.context.selected_objects[1].draw_type = 'WIRE'
    
    
    def boolean_union():
        ActiveObj = bpy.context.active_object
    
        if bpy.context.selected_objects[0] != bpy.context.active_object:
            BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[0].name, "BOOLEAN")
            BoolMod.object = bpy.context.selected_objects[0]
            BoolMod.operation = "UNION"
            bpy.context.selected_objects[0].draw_type = 'WIRE'
        else:
            BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[1].name, "BOOLEAN")
            BoolMod.object = bpy.context.selected_objects[1]
            BoolMod.operation = "UNION"
            bpy.context.selected_objects[1].draw_type = 'WIRE'
    
    
    def Rebool(context, self):
        SelObj_Name = []
        BoolObj = []
    
        LastObj = context.active_object
    
        Brush = context.selected_objects[0]
        Brush.draw_type = "WIRE"
        obj = context.selected_objects[1]
    
        bpy.ops.object.select_all(action='TOGGLE')
    
        context.scene.objects.active = obj
        obj.draw_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.solver = context.scene.CarverSolver
    
        m.object = Brush
    
        m = obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN")
        m.operation = "DIFFERENCE"
    
        m.solver = context.scene.CarverSolver
    
        m.object = Brush
    
        for mb in LastObj.modifiers:
            if mb.type == 'BEVEL':
                mb.show_viewport = False
    
        if self.ObjectBrush or self.ProfileBrush:
            LastObjectCreated.show_x_ray = 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 == 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 == 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 = mathutils.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 = mathutils.Vector((10000.0, 0.0, 0.0))
            ob.draw_type = "WIRE"
    
            self.SolidifyPossible = True
        else:
            bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]]
    
    
    def Selection_Save(self):
        self.SavSel = bpy.context.selected_objects.copy()
        self.Sav_ac = bpy.context.active_object
    
    
    def Selection_Restore(self):
        for o in self.SavSel:
            o.select = True
        bpy.context.scene.objects.active = self.Sav_ac
    
    
    # Modal Operator
    class Carver(bpy.types.Operator):
        bl_idname = "object.carver"
        bl_label = "Carver"
        bl_description = "Cut or create 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 = False
                if event.shift:
                    self.shift = True
    
                # [Ctrl]
                self.ctrl = False
                if event.ctrl:
                    self.ctrl = True
    
                # [Alt]
                self.alt = False
                if event.alt:
                    if self.InitPosition == 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 == False:
                    # Update coordonnee
                    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 == 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.DepthCursor = self.snapCursor
                                    # Object Instantiate
                                    context.scene.OInstanciate = self.Instantiate
                                    # Random rotation
                                    context.scene.ORandom = self.RandomRotation
    
                                    return {'FINISHED'}
                                else:
                                    # Cut
                                    self.Cut()
                                    UndoListUpdate(self)
    
                # Object creation
                if event.type == context.scene.Key_Create and event.value == 'PRESS':
                    if self.ExclusiveCreateMode == 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 == True) or (self.ObjectMode == 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 == False) and (self.ObjectMode == False):
                        self.ProfileMode = True
                    else:
                        self.ProfileMode = False
                        if self.ObjectBrush is not None:
                            if self.ObjectMode == False:
                                self.ObjectMode = True
                                self.BrushSolidify = False
                                self.CList = self.OB_List
    
                                if "CT_Profil" in bpy.data.objects:
                                    Selection_Save(self)
                                    bpy.ops.object.select_all(action='DESELECT')
                                    bpy.data.objects["CT_Profil"].select = True
                                    context.scene.objects.active = bpy.data.objects["CT_Profil"]
                                    bpy.ops.object.delete(use_global=False)
                                    Selection_Restore(self)
    
                                context.scene.nProfile = self.nProfil
    
                            else:
                                self.ObjectMode = False
                        else:
                            self.BrushSolidify = False
    
                            if "CT_Profil" in bpy.data.objects:
                                Selection_Save(self)
                                bpy.ops.object.select_all(action='DESELECT')
                                bpy.data.objects["CT_Profil"].select = True
                                context.scene.objects.active = bpy.data.objects["CT_Profil"]
                                bpy.ops.object.delete(use_global=False)
                                Selection_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_x_ray = 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 == 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.draw_type = self.ObjectBrush_DT
                                    self.ObjectBrush.show_x_ray = 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_x_ray = 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
    
    
                if event.type == context.scene.Key_Solver and event.value == 'PRESS':
                    if context.scene.CarverSolver == "CARVE":
                        context.scene.CarverSolver = "BMESH"
                    else:
                        context.scene.CarverSolver = "CARVE"
    
    
                # Scale object
                if event.type == context.scene.Key_Scale and event.value == 'PRESS':
                    if self.ObjectScale == 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 == 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 == 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 == False) and (self.ProfileMode == 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 == 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_x_ray = True
                                    else:
                                        self.ProfileBrush.select = True
                                        context.scene.objects.active = self.ProfileBrush
                                        # Active le xray
                                        self.ProfileBrush.show_x_ray = 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 = mathutils.Vector((0.0, 0.0, 1.0))
                                        qR = RBenVe(NormalObject, vBack[1])
    
                                        self.qRot = vBack[3] * qR
    
                                        Pos = vBack[0]
                                        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 = mathutils.Vector(
                                                        (vBack[0].x, self.SavMousePos.y, self.SavMousePos.z))
                                                if (yEcart > xEcart) and (yEcart > zEcart):
                                                    self.CurLoc = mathutils.Vector(
                                                        (self.SavMousePos.x, vBack[0].y, self.SavMousePos.z))
                                                if (zEcart > xEcart) and (zEcart > yEcart):
                                                    self.CurLoc = mathutils.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 == 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 == False:
                            vBack = Pick(context, event, self)
                            if vBack[0] is not None:
                                NormalObject = mathutils.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 == True:
                            self.ObjectScale = False
    
                        if self.GridScaleX == True:
                            self.GridScaleX = False
    
                        if self.GridScaleY == True:
                            self.GridScaleY = False
    
                        if self.WidthSolidify:
                            self.WidthSolidify = False
    
    
                        if self.CarveDepth == True:
                            self.CarveDepth = False
    
    
                        if self.BrushDepth == True:
                            self.BrushDepth = False
    
                    else:
                        if self.bDone == False:
                            if self.ctrl:
                                Picking(context, event)
                            else:
                                if self.CutMode == LINE:
                                    if self.bDone == 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.DepthCursor = self.snapCursor
                                    # Instantiate object
                                    context.scene.OInstanciate = self.Instantiate
                                    # Random rotation
                                    context.scene.ORandom = self.RandomRotation
                                    # Apply operation
                                    context.scene.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.draw_type = self.ObjectBrush_DT
                                        self.ObjectBrush.show_x_ray = 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.nProfile = self.nProfil
    
                                    return {'FINISHED'}
                                else:
                                    # Cut
                                    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.DepthCursor = self.snapCursor
                    # Instantiate object
                    context.scene.OInstanciate = self.Instantiate
                    # Random Rotation
                    context.scene.ORandom = self.RandomRotation
                    # Apply boolean operation
                    context.scene.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.draw_type = self.ObjectBrush_DT
                        self.ObjectBrush.show_x_ray = 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)
    
                    if "CT_Profil" in bpy.data.objects:
                        Selection_Save(self)
                        bpy.ops.object.select_all(action='DESELECT')
                        bpy.data.objects["CT_Profil"].select = True
                        context.scene.objects.active = bpy.data.objects["CT_Profil"]
                        bpy.ops.object.delete(use_global=False)
                        Selection_Restore(self)
    
                    context.scene.objects.active = self.CurrentActive
    
                    context.scene.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 invoke(self, context, event):
            if context.area.type == 'VIEW_3D':
                if context.mode == 'EDIT_MESH':
                    bpy.ops.object.mode_set(mode='OBJECT')