Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'object_carver/carver_operator.py')
-rw-r--r--object_carver/carver_operator.py2620
1 files changed, 1310 insertions, 1310 deletions
diff --git a/object_carver/carver_operator.py b/object_carver/carver_operator.py
index c75a5ab7..95fa4af0 100644
--- a/object_carver/carver_operator.py
+++ b/object_carver/carver_operator.py
@@ -2,340 +2,340 @@ import bpy
import bpy_extras
import sys
from bpy.props import (
- BoolProperty,
- IntProperty,
- PointerProperty,
- StringProperty,
- EnumProperty,
- )
+ BoolProperty,
+ IntProperty,
+ PointerProperty,
+ StringProperty,
+ EnumProperty,
+ )
from mathutils import (
- Vector,
- )
+ Vector,
+ )
from bpy_extras.view3d_utils import (
- region_2d_to_vector_3d,
- region_2d_to_origin_3d,
- region_2d_to_location_3d,
- location_3d_to_region_2d,
+ region_2d_to_vector_3d,
+ region_2d_to_origin_3d,
+ region_2d_to_location_3d,
+ location_3d_to_region_2d,
)
from .carver_profils import (
- Profils
- )
+ Profils
+ )
from .carver_utils import (
- duplicateObject,
- UndoListUpdate,
- createMeshFromData,
- SelectObject,
- Selection_Save_Restore,
- Selection_Save,
- Selection_Restore,
- update_grid,
- objDiagonal,
- Undo,
- UndoAdd,
- Pick,
- rot_axis_quat,
- MoveCursor,
- Picking,
- CreateCutSquare,
- CreateCutCircle,
- CreateCutLine,
- boolean_operation,
- update_bevel,
- CreateBevel,
- Rebool,
- Snap_Cursor,
- )
+ duplicateObject,
+ UndoListUpdate,
+ createMeshFromData,
+ SelectObject,
+ Selection_Save_Restore,
+ Selection_Save,
+ Selection_Restore,
+ update_grid,
+ objDiagonal,
+ Undo,
+ UndoAdd,
+ Pick,
+ rot_axis_quat,
+ MoveCursor,
+ Picking,
+ CreateCutSquare,
+ CreateCutCircle,
+ CreateCutLine,
+ boolean_operation,
+ update_bevel,
+ CreateBevel,
+ Rebool,
+ Snap_Cursor,
+ )
from .carver_draw import draw_callback_px
# Modal Operator
class CARVER_OT_operator(bpy.types.Operator):
- bl_idname = "carver.operator"
- bl_label = "Carver"
- bl_description = "Cut or create Meshes in Object mode"
- bl_options = {'REGISTER', 'UNDO'}
+ bl_idname = "carver.operator"
+ bl_label = "Carver"
+ bl_description = "Cut or create Meshes in Object mode"
+ bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- context = bpy.context
- # Carve mode: Cut, Object, Profile
- self.CutMode = False
- self.CreateMode = False
- self.ObjectMode = False
- self.ProfileMode = False
+ def __init__(self):
+ context = bpy.context
+ # Carve mode: Cut, Object, Profile
+ self.CutMode = False
+ self.CreateMode = False
+ self.ObjectMode = False
+ self.ProfileMode = False
- # Create mode
- self.ExclusiveCreateMode = False
- if len(context.selected_objects) == 0:
- self.ExclusiveCreateMode = True
- self.CreateMode = True
+ # Create mode
+ self.ExclusiveCreateMode = False
+ if len(context.selected_objects) == 0:
+ self.ExclusiveCreateMode = True
+ self.CreateMode = True
- # Cut type (Rectangle, Circle, Line)
- self.rectangle = 0
- self.line = 1
- self.circle = 2
+ # Cut type (Rectangle, Circle, Line)
+ self.rectangle = 0
+ self.line = 1
+ self.circle = 2
- # Cut Rectangle coordinates
- self.rectangle_coord = []
+ # Cut Rectangle coordinates
+ self.rectangle_coord = []
- # Selected type of cut
- self.CutType = 0
+ # Selected type of cut
+ self.CutType = 0
- # Boolean operation
- self.difference = 0
- self.union = 1
-
- self.BoolOps = self.difference
-
- self.CurrentSelection = context.selected_objects.copy()
- self.CurrentActive = context.active_object
- self.all_sel_obj_list = context.selected_objects.copy()
- self.save_active_obj = 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)]
-
- # Keyboard event
- self.shift = False
- self.ctrl = False
- self.alt = False
-
- self.dont_apply_boolean = context.scene.mesh_carver.DontApply
- self.Auto_BevelUpdate = True
-
- # Circle variables
- self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90]
- self.step = 4
-
- # Primitives Position
- self.xpos = 0
- self.ypos = 0
- self.InitPosition = False
-
- # Close polygonal shape
- self.Closed = False
-
- # Depth Cursor
- self.snapCursor = context.scene.mesh_carver.DepthCursor
-
- # Help
- self.AskHelp = False
-
- # Working object
- self.OpsObj = context.active_object
-
- # Rebool forced (cut line)
- self.ForceRebool = False
-
- self.ViewVector = Vector()
- self.CurrentObj = None
-
- # Brush
- self.BrushSolidify = False
- self.WidthSolidify = False
- self.CarveDepth = False
- self.BrushDepth = False
- self.BrushDepthOffset = 0.0
- self.snap = False
-
- self.ObjectScale = False
-
- #Init create circle primitive
- self.CLR_C = []
-
- # Cursor location
- self.CurLoc = Vector((0.0, 0.0, 0.0))
- self.SavCurLoc = Vector((0.0, 0.0, 0.0))
-
- # Mouse region
- self.mouse_region = -1, -1
- self.SavMousePos = None
- self.xSavMouse = 0
-
- # Scale, rotate object
- self.ascale = 0
- self.aRotZ = 0
- self.nRotZ = 0
- self.quat_rot_axis = None
- self.quat_rot = None
-
- self.RandomRotation = context.scene.mesh_carver.ORandom
-
- self.ShowCursor = True
-
- self.Instantiate = context.scene.mesh_carver.OInstanciate
-
- self.ProfileBrush = None
- self.ObjectBrush = None
-
- self.InitBrush = {
- 'location' : None,
- 'scale' : None,
- 'rotation_quaternion' : None,
- 'rotation_euler' : None,
- 'display_type' : 'WIRE',
- 'show_in_front' : False
- }
-
- # Array variables
- self.nbcol = 1
- self.nbrow = 1
- self.gapx = 0
- self.gapy = 0
- self.scale_x = 1
- self.scale_y = 1
- self.GridScaleX = False
- self.GridScaleY = False
-
- @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
-
- # Find the limit of the view3d region
- self.check_region(context,event)
-
- for area in win.screen.areas:
- if area.type == 'VIEW_3D':
- for region in area.regions:
- if not region_types or region.type in region_types:
- region.tag_redraw()
-
- # Change the snap increment value using the wheel mouse
- if self.CutMode:
- if self.alt is False:
- if self.ctrl and (self.CutType in (self.line, self.rectangle)):
- # Get the VIEW3D area
- for i, a in enumerate(context.screen.areas):
- if a.type == 'VIEW_3D':
- space = context.screen.areas[i].spaces.active
- grid_scale = space.overlay.grid_scale
- grid_subdivisions = space.overlay.grid_subdivisions
-
- if event.type == 'WHEELUPMOUSE':
- space.overlay.grid_subdivisions += 1
- elif event.type == 'WHEELDOWNMOUSE':
- space.overlay.grid_subdivisions -= 1
-
- 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
-
- # [Ctrl]
- self.ctrl = True if event.ctrl else False
-
- # [Alt]
- self.alt = False
-
- # [Alt] press : Init position variable before moving the cut brush with LMB
- if event.alt:
- if self.InitPosition is False:
- 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 : update the coordinates
- if self.InitPosition and self.alt is False:
- 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
-
- if event.type == 'SPACE' and event.value == 'PRESS':
- # If object or profile mode is TRUE : Confirm the cut
- if self.ObjectMode or self.ProfileMode:
- # If array, 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.all_sel_obj_list = 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.all_sel_obj_list = 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.CutMode is False:
- # Cut Mode
- self.CutType += 1
- if self.CutType > 2:
- self.CutType = 0
- else:
- if self.CutType == self.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)
+ # Boolean operation
+ self.difference = 0
+ self.union = 1
+
+ self.BoolOps = self.difference
+
+ self.CurrentSelection = context.selected_objects.copy()
+ self.CurrentActive = context.active_object
+ self.all_sel_obj_list = context.selected_objects.copy()
+ self.save_active_obj = 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)]
+
+ # Keyboard event
+ self.shift = False
+ self.ctrl = False
+ self.alt = False
+
+ self.dont_apply_boolean = context.scene.mesh_carver.DontApply
+ self.Auto_BevelUpdate = True
+
+ # Circle variables
+ self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90]
+ self.step = 4
+
+ # Primitives Position
+ self.xpos = 0
+ self.ypos = 0
+ self.InitPosition = False
+
+ # Close polygonal shape
+ self.Closed = False
+
+ # Depth Cursor
+ self.snapCursor = context.scene.mesh_carver.DepthCursor
+
+ # Help
+ self.AskHelp = False
+
+ # Working object
+ self.OpsObj = context.active_object
+
+ # Rebool forced (cut line)
+ self.ForceRebool = False
+
+ self.ViewVector = Vector()
+ self.CurrentObj = None
+
+ # Brush
+ self.BrushSolidify = False
+ self.WidthSolidify = False
+ self.CarveDepth = False
+ self.BrushDepth = False
+ self.BrushDepthOffset = 0.0
+ self.snap = False
+
+ self.ObjectScale = False
+
+ #Init create circle primitive
+ self.CLR_C = []
+
+ # Cursor location
+ self.CurLoc = Vector((0.0, 0.0, 0.0))
+ self.SavCurLoc = Vector((0.0, 0.0, 0.0))
+
+ # Mouse region
+ self.mouse_region = -1, -1
+ self.SavMousePos = None
+ self.xSavMouse = 0
+
+ # Scale, rotate object
+ self.ascale = 0
+ self.aRotZ = 0
+ self.nRotZ = 0
+ self.quat_rot_axis = None
+ self.quat_rot = None
+
+ self.RandomRotation = context.scene.mesh_carver.ORandom
+
+ self.ShowCursor = True
+
+ self.Instantiate = context.scene.mesh_carver.OInstanciate
+
+ self.ProfileBrush = None
+ self.ObjectBrush = None
+
+ self.InitBrush = {
+ 'location' : None,
+ 'scale' : None,
+ 'rotation_quaternion' : None,
+ 'rotation_euler' : None,
+ 'display_type' : 'WIRE',
+ 'show_in_front' : False
+ }
+
+ # Array variables
+ self.nbcol = 1
+ self.nbrow = 1
+ self.gapx = 0
+ self.gapy = 0
+ self.scale_x = 1
+ self.scale_y = 1
+ self.GridScaleX = False
+ self.GridScaleY = False
+
+ @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
+
+ # Find the limit of the view3d region
+ self.check_region(context,event)
+
+ for area in win.screen.areas:
+ if area.type == 'VIEW_3D':
+ for region in area.regions:
+ if not region_types or region.type in region_types:
+ region.tag_redraw()
+
+ # Change the snap increment value using the wheel mouse
+ if self.CutMode:
+ if self.alt is False:
+ if self.ctrl and (self.CutType in (self.line, self.rectangle)):
+ # Get the VIEW3D area
+ for i, a in enumerate(context.screen.areas):
+ if a.type == 'VIEW_3D':
+ space = context.screen.areas[i].spaces.active
+ grid_scale = space.overlay.grid_scale
+ grid_subdivisions = space.overlay.grid_subdivisions
+
+ if event.type == 'WHEELUPMOUSE':
+ space.overlay.grid_subdivisions += 1
+ elif event.type == 'WHEELDOWNMOUSE':
+ space.overlay.grid_subdivisions -= 1
+
+ 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
+
+ # [Ctrl]
+ self.ctrl = True if event.ctrl else False
+
+ # [Alt]
+ self.alt = False
+
+ # [Alt] press : Init position variable before moving the cut brush with LMB
+ if event.alt:
+ if self.InitPosition is False:
+ 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 : update the coordinates
+ if self.InitPosition and self.alt is False:
+ 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
+
+ if event.type == 'SPACE' and event.value == 'PRESS':
+ # If object or profile mode is TRUE : Confirm the cut
+ if self.ObjectMode or self.ProfileMode:
+ # If array, 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.all_sel_obj_list = 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.all_sel_obj_list = 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.CutMode is False:
+ # Cut Mode
+ self.CutType += 1
+ if self.CutType > 2:
+ self.CutType = 0
+ else:
+ if self.CutType == self.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)
#-----------------------------------------------------
@@ -343,1005 +343,1005 @@ class CARVER_OT_operator(bpy.types.Operator):
#-----------------------------------------------------
- # Object creation
- if event.type == self.carver_prefs.Key_Create and event.value == 'PRESS':
- if self.ExclusiveCreateMode is False:
- self.CreateMode = not self.CreateMode
-
- # Auto Bevel Update
- if event.type == self.carver_prefs.Key_Update and event.value == 'PRESS':
- self.Auto_BevelUpdate = not self.Auto_BevelUpdate
-
- # Boolean operation type
- if event.type == self.carver_prefs.Key_Bool and event.value == 'PRESS':
- if (self.ProfileMode is True) or (self.ObjectMode is True):
- if self.BoolOps == self.difference:
- self.BoolOps = self.union
- else:
- self.BoolOps = self.difference
-
- # Brush Mode
- if event.type == self.carver_prefs.Key_Brush and event.value == 'PRESS':
- self.dont_apply_boolean = 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_set(True)
- context.view_layer.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.InitBrush['location']
- self.ObjectBrush.scale = self.InitBrush['scale']
- self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion']
- self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler']
- self.ObjectBrush.display_type = self.InitBrush['display_type']
- self.ObjectBrush.show_in_front = self.InitBrush['show_in_front']
-
- #Store active and selected objects
- Selection_Save(self)
-
- #Remove Carver modifier
- self.BrushSolidify = False
- bpy.ops.object.select_all(action='TOGGLE')
- self.ObjectBrush.select_set(True)
- context.view_layer.objects.active = self.ObjectBrush
- bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY")
-
- #Restore selected and active object
- Selection_Restore(self)
- else:
- if self.SolidifyPossible:
- #Store active and selected objects
- Selection_Save(self)
- self.BrushSolidify = True
- bpy.ops.object.select_all(action='TOGGLE')
- self.ObjectBrush.select_set(True)
- context.view_layer.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
-
- #Restore selected and active object
- Selection_Restore(self)
-
- # Help display
- if event.type == self.carver_prefs.Key_Help and event.value == 'PRESS':
- self.AskHelp = not self.AskHelp
-
- # Instantiate object
- if event.type == self.carver_prefs.Key_Instant and event.value == 'PRESS':
- self.Instantiate = not self.Instantiate
-
- # Close polygonal shape
- if event.type == self.carver_prefs.Key_Close and event.value == 'PRESS':
- if self.CreateMode:
- self.Closed = not self.Closed
-
- if event.type == self.carver_prefs.Key_Apply and event.value == 'PRESS':
- self.dont_apply_boolean = not self.dont_apply_boolean
-
- # Scale object
- if event.type == self.carver_prefs.Key_Scale and event.value == 'PRESS':
- if self.ObjectScale is False:
- self.mouse_region = event.mouse_region_x, event.mouse_region_y
- self.ObjectScale = True
-
- # Grid : Snap on grid
- if event.type == self.carver_prefs.Key_Snap and event.value == 'PRESS':
- self.snap = not self.snap
-
- # Array : Add column
- if event.type == 'UP_ARROW' and event.value == 'PRESS':
- self.nbrow += 1
- update_grid(self, context)
-
- # Array : Delete column
- elif event.type == 'DOWN_ARROW' and event.value == 'PRESS':
- self.nbrow -= 1
- update_grid(self, context)
-
- # Array : Add row
- elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS':
- self.nbcol += 1
- update_grid(self, context)
-
- # Array : Delete row
- elif event.type == 'LEFT_ARROW' and event.value == 'PRESS':
- self.nbcol -= 1
- update_grid(self, context)
-
- # Array : Scale gap between columns
- if event.type == self.carver_prefs.Key_Gapy and event.value == 'PRESS':
- if self.GridScaleX is False:
- self.mouse_region = event.mouse_region_x, event.mouse_region_y
- self.GridScaleX = True
-
- # Array : Scale gap between rows
- if event.type == self.carver_prefs.Key_Gapx and event.value == 'PRESS':
- if self.GridScaleY is False:
- self.mouse_region = event.mouse_region_x, event.mouse_region_y
- self.GridScaleY = True
-
- # Cursor depth or solidify pattern
- if event.type == self.carver_prefs.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.mouse_region = 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_set(True)
- context.view_layer.objects.active = self.ObjectBrush
- # Active le xray
- self.ObjectBrush.show_in_front = True
- else:
- self.ProfileBrush.select_set(True)
- context.view_layer.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.mouse_region = event.mouse_region_x, event.mouse_region_y
-
- if event.type == self.carver_prefs.Key_BrushDepth and event.value == 'PRESS':
- if self.ObjectMode:
- self.CarveDepth = False
-
- self.BrushDepth = True
- self.mouse_region = 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.CutType == self.line) and (self.CutMode):
- 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.mouse_region[0]) / fac
- elif self.ProfileMode:
- bpy.data.objects[self.ProfileBrush.name].modifiers[
- "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.mouse_region[0]) / fac
- self.mouse_region = 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.mouse_region[0]) / fac
- self.mouse_region = event.mouse_region_x, event.mouse_region_y
- elif self.BrushDepth:
- self.BrushDepthOffset += (event.mouse_region_x - self.mouse_region[0]) / fac
- self.mouse_region = event.mouse_region_x, event.mouse_region_y
- else:
- if (self.GridScaleX):
- self.gapx += (event.mouse_region_x - self.mouse_region[0]) / 50
- self.mouse_region = 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.mouse_region[0]) / 50
- self.mouse_region = 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.mouse_region[0])
- self.mouse_region = 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.mouse_region[0]
- self.ascale = 0.0
-
- self.mouse_region = event.mouse_region_x, event.mouse_region_y
- else:
- target_hit, target_normal, target_eul_rotation = Pick(context, event, self)
- if target_hit is not None:
- self.ShowCursor = True
- up_vector = Vector((0.0, 0.0, 1.0))
- quat_rot_axis = rot_axis_quat(up_vector, target_normal)
- self.quat_rot = target_eul_rotation @ quat_rot_axis
- MoveCursor(quat_rot_axis, target_hit, self)
- self.SavCurLoc = target_hit
- 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(
- (target_hit.x, self.SavMousePos.y, self.SavMousePos.z))
- if (yEcart > xEcart) and (yEcart > zEcart):
- self.CurLoc = Vector(
- (self.SavMousePos.x, target_hit.y, self.SavMousePos.z))
- if (zEcart > xEcart) and (zEcart > yEcart):
- self.CurLoc = Vector(
- (self.SavMousePos.x, self.SavMousePos.y, target_hit.z))
- else:
- self.CurLoc = target_hit
- else:
- self.CurLoc = target_hit
- else:
- if self.CutMode:
- if self.alt is False:
- if self.ctrl :
- # Find the closest position on the overlay grid and snap the mouse on it
- # Draw a mini grid around the cursor
- mouse_pos = [[event.mouse_region_x, event.mouse_region_y]]
- Snap_Cursor(self, context, event, mouse_pos)
-
- 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:
- target_hit, target_normal, target_eul_rotation = Pick(context, event, self)
- if target_hit is not None:
- up_vector = Vector((0.0, 0.0, 1.0))
- self.quat_rot_axis = rot_axis_quat(up_vector, target_normal)
- self.quat_rot = target_eul_rotation @ self.quat_rot_axis
- self.mouse_region = 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' and self.in_view_3d:
- 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.CutMode is False:
- if self.ctrl:
- Picking(context, event)
-
- else:
-
- if self.CutType == self.line:
- if self.CutMode 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.CutMode = True
- else:
- if self.CutType != self.line:
- # Cut creation
- if self.CutType == self.rectangle:
- CreateCutSquare(self, context)
- if self.CutType == self.circle:
- CreateCutCircle(self, context)
- if self.CutType == self.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.dont_apply_boolean
-
- # if Object mode, set initiale state
- if self.ObjectBrush is not None:
- self.ObjectBrush.location = self.InitBrush['location']
- self.ObjectBrush.scale = self.InitBrush['scale']
- self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion']
- self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler']
- self.ObjectBrush.display_type = self.InitBrush['display_type']
- self.ObjectBrush.show_in_front = self.InitBrush['show_in_front']
-
- # remove solidify
- Selection_Save(self)
- self.BrushSolidify = False
-
- bpy.ops.object.select_all(action='TOGGLE')
- self.ObjectBrush.select_set(True)
- context.view_layer.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 brush profil or circle subdivisions
- elif (event.type == 'COMMA' and event.value == 'PRESS') or \
- (event.type == self.carver_prefs.Key_Subrem and event.value == 'PRESS'):
- # Brush profil
- if self.ProfileMode:
- self.nProfil += 1
- if self.nProfil >= self.MaxProfil:
- self.nProfil = 0
- createMeshFromData(self)
- # Circle subdivisions
- if self.CutType == self.circle:
- self.step += 1
- if self.step >= len(self.stepAngle):
- self.step = len(self.stepAngle) - 1
- # Change brush profil or circle subdivisions
- elif (event.type == 'PERIOD' and event.value == 'PRESS') or \
- (event.type == self.carver_prefs.Key_Subadd and event.value == 'PRESS'):
- # Brush profil
- if self.ProfileMode:
- self.nProfil -= 1
- if self.nProfil < 0:
- self.nProfil = self.MaxProfil - 1
- createMeshFromData(self)
- # Circle subdivisions
- if self.CutType == self.circle:
- 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.dont_apply_boolean
-
- # Reset Object
- if self.ObjectBrush is not None:
- self.ObjectBrush.location = self.InitBrush['location']
- self.ObjectBrush.scale = self.InitBrush['scale']
- self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion']
- self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler']
- self.ObjectBrush.display_type = self.InitBrush['display_type']
- self.ObjectBrush.show_in_front = self.InitBrush['show_in_front']
-
- # Remove solidify modifier
- Selection_Save(self)
- self.BrushSolidify = False
-
- bpy.ops.object.select_all(action='TOGGLE')
- self.ObjectBrush.select_set(True)
- context.view_layer.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.view_layer.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_set(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(None)
- bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
-
- self.report({'WARNING'},
- "Operation finished. Failure during Carving (Check the console for more info)")
-
- return {'FINISHED'}
-
- def cancel(self, context):
- # Note: used to prevent memory leaks on quitting 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")
- self.cancel(context)
- return {'CANCELLED'}
-
- # test if some other object types are selected that are not meshes
- for obj in context.selected_objects:
- if obj.type != "MESH":
- self.report({'WARNING'},
- "Some selected objects are not of the Mesh type. Operation Cancelled")
- self.cancel(context)
- return {'CANCELLED'}
-
- if context.mode == 'EDIT_MESH':
- bpy.ops.object.mode_set(mode='OBJECT')
-
- #Load the Carver preferences
- self.carver_prefs = bpy.context.preferences.addons[__package__].preferences
-
- # 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(self.carver_prefs.ProfilePrefix):
- continue
- # In-scene profiles may have changed, remove them to refresh
- for m in bpy.data.meshes:
- if m.name.startswith(self.carver_prefs.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
-
- if len(context.selected_objects) > 1:
- self.ObjectBrush = context.active_object
-
- # Copy the brush object
- ob = bpy.data.objects.new("CarverBrushCopy", context.object.data.copy())
- ob.location = self.ObjectBrush.location
- context.collection.objects.link(ob)
- context.view_layer.update()
-
- # Save default variables
- self.InitBrush['location'] = self.ObjectBrush.location.copy()
- self.InitBrush['scale'] = self.ObjectBrush.scale.copy()
- self.InitBrush['rotation_quaternion'] = self.ObjectBrush.rotation_quaternion.copy()
- self.InitBrush['rotation_euler'] = self.ObjectBrush.rotation_euler.copy()
- self.InitBrush['display_type'] = self.ObjectBrush.display_type
- self.InitBrush['show_in_front'] = self.ObjectBrush.show_in_front
-
- # Test if flat object
- z = self.ObjectBrush.data.vertices[0].co.z
- ErrorMarge = 0.01
- self.SolidifyPossible = True
- for v in self.ObjectBrush.data.vertices:
- if abs(v.co.z - z) > ErrorMarge:
- self.SolidifyPossible = False
- break
-
- self.CList = []
- self.OPList = []
- self.RList = []
- self.OB_List = []
-
- for obj in context.selected_objects:
- if obj != self.ObjectBrush:
- self.OB_List.append(obj)
-
- # Left button
- self.LMB = False
-
- # Undo Variables
- self.undo_index = 0
- self.undo_limit = context.preferences.edit.undo_steps
- self.undo_list = []
-
- # Boolean operations type
- self.BooleanType = 0
-
- self.UList = []
- self.UList_Index = -1
- self.UndoOps = []
-
- context.window_manager.modal_handler_add(self)
- return {'RUNNING_MODAL'}
-
- #Get the region area where the operator is used
- def check_region(self,context,event):
- if context.area != None:
- if context.area.type == "VIEW_3D" :
- for region in context.area.regions:
- if region.type == "TOOLS":
- t_panel = region
- elif region.type == "UI":
- ui_panel = region
-
- view_3d_region_x = Vector((context.area.x + t_panel.width, context.area.x + context.area.width - ui_panel.width))
- view_3d_region_y = Vector((context.region.y, context.region.y+context.region.height))
-
- if (event.mouse_x > view_3d_region_x[0] and event.mouse_x < view_3d_region_x[1] \
- and event.mouse_y > view_3d_region_y[0] and event.mouse_y < view_3d_region_y[1]):
- self.in_view_3d = True
- else:
- self.in_view_3d = False
- else:
- self.in_view_3d = False
-
- def CreateGeometry(self):
- context = bpy.context
- in_local_view = False
-
- for area in context.screen.areas:
- if area.type == 'VIEW_3D':
- if area.spaces[0].local_view is not None:
- in_local_view = True
-
- if in_local_view:
- bpy.ops.view3d.localview()
-
- if self.ExclusiveCreateMode:
- # Default width
- objBBDiagonal = 0.5
- else:
- ActiveObj = self.CurrentSelection[0]
- if ActiveObj is not None:
- # Object dimensions
- objBBDiagonal = objDiagonal(ActiveObj) / 4
- subdivisions = 2
-
- if len(context.selected_objects) > 0:
- bpy.ops.object.select_all(action='TOGGLE')
-
- context.view_layer.objects.active = self.CurrentObj
-
- bpy.data.objects[self.CurrentObj.name].select_set(True)
- bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
-
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.select_mode(type="EDGE")
- if self.snapCursor is False:
- bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions)
- bpy.ops.mesh.extrude_region_move(
- TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2})
-
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.normals_make_consistent()
- bpy.ops.object.mode_set(mode='OBJECT')
-
- saved_location_0 = context.scene.cursor.location.copy()
- bpy.ops.view3d.snap_cursor_to_active()
- saved_location = context.scene.cursor.location.copy()
- bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
- context.scene.cursor.location = saved_location
- bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
- context.scene.cursor.location = saved_location_0
-
- bpy.data.objects[self.CurrentObj.name].select_set(True)
- bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
-
- for o in self.all_sel_obj_list:
- bpy.data.objects[o.name].select_set(True)
-
- if in_local_view:
- bpy.ops.view3d.localview()
-
- self.CutMode = False
- self.mouse_path.clear()
- self.mouse_path = [(0, 0), (0, 0)]
-
- def Cut(self):
- context = bpy.context
-
- # Local view ?
- in_local_view = False
- for area in context.screen.areas:
- if area.type == 'VIEW_3D':
- if area.spaces[0].local_view is not None:
- in_local_view = True
-
- if in_local_view:
- bpy.ops.view3d.localview()
-
- # Save cursor position
- CursorLocation = context.scene.cursor.location.copy()
-
- #List of selected objects
- selected_obj_list = []
-
- #Cut Mode with line
- if (self.ObjectMode is False) and (self.ProfileMode is False):
-
- #Compute the bounding Box
- objBBDiagonal = objDiagonal(self.CurrentSelection[0])
- if self.dont_apply_boolean:
- subdivisions = 1
- else:
- subdivisions = 32
-
- # Get selected objects
- selected_obj_list = context.selected_objects.copy()
-
- bpy.ops.object.select_all(action='TOGGLE')
-
- context.view_layer.objects.active = self.CurrentObj
-
- bpy.data.objects[self.CurrentObj.name].select_set(True)
- bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
-
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.select_mode(type="EDGE")
- #Translate the created mesh away from the view
- if (self.snapCursor is False) or (self.ForceRebool):
- bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions)
- #Extrude the mesh region and move the result
- bpy.ops.mesh.extrude_region_move(
- TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2})
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.normals_make_consistent()
- bpy.ops.object.mode_set(mode='OBJECT')
- else:
- # Create list
- if self.ObjectMode:
- for o in self.CurrentSelection:
- if o != self.ObjectBrush:
- selected_obj_list.append(o)
- self.CurrentObj = self.ObjectBrush
- else:
- selected_obj_list = self.CurrentSelection
- self.CurrentObj = self.ProfileBrush
-
- for obj in self.CurrentSelection:
- UndoAdd(self, "MESH", obj)
-
- # List objects create with rebool
- lastSelected = []
-
- for ActiveObj in selected_obj_list:
- context.scene.cursor.location = CursorLocation
-
- if len(context.selected_objects) > 0:
- bpy.ops.object.select_all(action='TOGGLE')
-
- # Select cut object
- bpy.data.objects[self.CurrentObj.name].select_set(True)
- context.view_layer.objects.active = self.CurrentObj
-
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Select object to cut
- bpy.data.objects[ActiveObj.name].select_set(True)
- context.view_layer.objects.active = ActiveObj
-
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='DESELECT')
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Boolean operation
- if (self.shift is False) and (self.ForceRebool is False):
- if self.ObjectMode or self.ProfileMode:
- if self.BoolOps == self.union:
- boolean_operation(bool_type="UNION")
- else:
- boolean_operation(bool_type="DIFFERENCE")
- else:
- boolean_operation(bool_type="DIFFERENCE")
-
- # Apply booleans
- if self.dont_apply_boolean is False:
- BMname = "CT_" + self.CurrentObj.name
- for mb in ActiveObj.modifiers:
- if (mb.type == 'BOOLEAN') and (mb.name == BMname):
- try:
- bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname)
- except:
- bpy.ops.object.modifier_remove(modifier=BMname)
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.report({'ERROR'}, str(exc_value))
-
- bpy.ops.object.select_all(action='TOGGLE')
- else:
- if self.ObjectMode or self.ProfileMode:
- for mb in self.CurrentObj.modifiers:
- if (mb.type == 'SOLIDIFY') and (mb.name == "CT_SOLIDIFY"):
- 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))
-
- # Rebool
- Rebool(context, self)
-
- # Test if not empty object
- if context.selected_objects[0]:
- rebool_RT = context.selected_objects[0]
- if len(rebool_RT.data.vertices) > 0:
- # Create Bevel for new objects
- CreateBevel(context, context.selected_objects[0])
-
- UndoAdd(self, "REBOOL", context.selected_objects[0])
-
- context.scene.cursor.location = ActiveObj.location
- bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
- else:
- bpy.ops.object.delete(use_global=False)
-
- context.scene.cursor.location = CursorLocation
-
- if self.ObjectMode:
- context.view_layer.objects.active = self.ObjectBrush
- if self.ProfileMode:
- context.view_layer.objects.active = self.ProfileBrush
-
- if self.dont_apply_boolean is False:
- # Apply booleans
- BMname = "CT_" + self.CurrentObj.name
- for mb in ActiveObj.modifiers:
- if (mb.type == 'BOOLEAN') and (mb.name == BMname):
- try:
- bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname)
- except:
- bpy.ops.object.modifier_remove(modifier=BMname)
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.report({'ERROR'}, str(exc_value))
- # Get new objects created with rebool operations
- if len(context.selected_objects) > 0:
- if self.shift is True:
- # Get the last object selected
- lastSelected.append(context.selected_objects[0])
-
- context.scene.cursor.location = CursorLocation
-
- if self.dont_apply_boolean is False:
- # Remove cut object
- if (self.ObjectMode is False) and (self.ProfileMode is False):
- if len(context.selected_objects) > 0:
- bpy.ops.object.select_all(action='TOGGLE')
- bpy.data.objects[self.CurrentObj.name].select_set(True)
- bpy.ops.object.delete(use_global=False)
- else:
- if self.ObjectMode:
- self.ObjectBrush.display_type = self.InitBrush['display_type']
-
- if len(context.selected_objects) > 0:
- bpy.ops.object.select_all(action='TOGGLE')
-
- # Select cut objects
- for obj in lastSelected:
- bpy.data.objects[obj.name].select_set(True)
-
- for ActiveObj in selected_obj_list:
- bpy.data.objects[ActiveObj.name].select_set(True)
- context.view_layer.objects.active = ActiveObj
- # Update bevel
- list_act_obj = context.selected_objects.copy()
- if self.Auto_BevelUpdate:
- update_bevel(context)
-
- # Re-select initial objects
- bpy.ops.object.select_all(action='TOGGLE')
- if self.ObjectMode:
- # Re-select brush
- self.ObjectBrush.select_set(True)
- for ActiveObj in selected_obj_list:
- bpy.data.objects[ActiveObj.name].select_set(True)
- context.view_layer.objects.active = ActiveObj
-
- # If object has children, set "Wire" draw type
- if self.ObjectBrush is not None:
- if len(self.ObjectBrush.children) > 0:
- self.ObjectBrush.display_type = "WIRE"
- if self.ProfileMode:
- self.ProfileBrush.display_type = "WIRE"
-
- if in_local_view:
- bpy.ops.view3d.localview()
-
- # Reset variables
- self.CutMode = False
- self.mouse_path.clear()
- self.mouse_path = [(0, 0), (0, 0)]
-
- self.ForceRebool = False
-
- # bpy.ops.mesh.customdata_custom_splitnormals_clear()
+ # Object creation
+ if event.type == self.carver_prefs.Key_Create and event.value == 'PRESS':
+ if self.ExclusiveCreateMode is False:
+ self.CreateMode = not self.CreateMode
+
+ # Auto Bevel Update
+ if event.type == self.carver_prefs.Key_Update and event.value == 'PRESS':
+ self.Auto_BevelUpdate = not self.Auto_BevelUpdate
+
+ # Boolean operation type
+ if event.type == self.carver_prefs.Key_Bool and event.value == 'PRESS':
+ if (self.ProfileMode is True) or (self.ObjectMode is True):
+ if self.BoolOps == self.difference:
+ self.BoolOps = self.union
+ else:
+ self.BoolOps = self.difference
+
+ # Brush Mode
+ if event.type == self.carver_prefs.Key_Brush and event.value == 'PRESS':
+ self.dont_apply_boolean = 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_set(True)
+ context.view_layer.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.InitBrush['location']
+ self.ObjectBrush.scale = self.InitBrush['scale']
+ self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion']
+ self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler']
+ self.ObjectBrush.display_type = self.InitBrush['display_type']
+ self.ObjectBrush.show_in_front = self.InitBrush['show_in_front']
+
+ #Store active and selected objects
+ Selection_Save(self)
+
+ #Remove Carver modifier
+ self.BrushSolidify = False
+ bpy.ops.object.select_all(action='TOGGLE')
+ self.ObjectBrush.select_set(True)
+ context.view_layer.objects.active = self.ObjectBrush
+ bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY")
+
+ #Restore selected and active object
+ Selection_Restore(self)
+ else:
+ if self.SolidifyPossible:
+ #Store active and selected objects
+ Selection_Save(self)
+ self.BrushSolidify = True
+ bpy.ops.object.select_all(action='TOGGLE')
+ self.ObjectBrush.select_set(True)
+ context.view_layer.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
+
+ #Restore selected and active object
+ Selection_Restore(self)
+
+ # Help display
+ if event.type == self.carver_prefs.Key_Help and event.value == 'PRESS':
+ self.AskHelp = not self.AskHelp
+
+ # Instantiate object
+ if event.type == self.carver_prefs.Key_Instant and event.value == 'PRESS':
+ self.Instantiate = not self.Instantiate
+
+ # Close polygonal shape
+ if event.type == self.carver_prefs.Key_Close and event.value == 'PRESS':
+ if self.CreateMode:
+ self.Closed = not self.Closed
+
+ if event.type == self.carver_prefs.Key_Apply and event.value == 'PRESS':
+ self.dont_apply_boolean = not self.dont_apply_boolean
+
+ # Scale object
+ if event.type == self.carver_prefs.Key_Scale and event.value == 'PRESS':
+ if self.ObjectScale is False:
+ self.mouse_region = event.mouse_region_x, event.mouse_region_y
+ self.ObjectScale = True
+
+ # Grid : Snap on grid
+ if event.type == self.carver_prefs.Key_Snap and event.value == 'PRESS':
+ self.snap = not self.snap
+
+ # Array : Add column
+ if event.type == 'UP_ARROW' and event.value == 'PRESS':
+ self.nbrow += 1
+ update_grid(self, context)
+
+ # Array : Delete column
+ elif event.type == 'DOWN_ARROW' and event.value == 'PRESS':
+ self.nbrow -= 1
+ update_grid(self, context)
+
+ # Array : Add row
+ elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS':
+ self.nbcol += 1
+ update_grid(self, context)
+
+ # Array : Delete row
+ elif event.type == 'LEFT_ARROW' and event.value == 'PRESS':
+ self.nbcol -= 1
+ update_grid(self, context)
+
+ # Array : Scale gap between columns
+ if event.type == self.carver_prefs.Key_Gapy and event.value == 'PRESS':
+ if self.GridScaleX is False:
+ self.mouse_region = event.mouse_region_x, event.mouse_region_y
+ self.GridScaleX = True
+
+ # Array : Scale gap between rows
+ if event.type == self.carver_prefs.Key_Gapx and event.value == 'PRESS':
+ if self.GridScaleY is False:
+ self.mouse_region = event.mouse_region_x, event.mouse_region_y
+ self.GridScaleY = True
+
+ # Cursor depth or solidify pattern
+ if event.type == self.carver_prefs.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.mouse_region = 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_set(True)
+ context.view_layer.objects.active = self.ObjectBrush
+ # Active le xray
+ self.ObjectBrush.show_in_front = True
+ else:
+ self.ProfileBrush.select_set(True)
+ context.view_layer.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.mouse_region = event.mouse_region_x, event.mouse_region_y
+
+ if event.type == self.carver_prefs.Key_BrushDepth and event.value == 'PRESS':
+ if self.ObjectMode:
+ self.CarveDepth = False
+
+ self.BrushDepth = True
+ self.mouse_region = 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.CutType == self.line) and (self.CutMode):
+ 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.mouse_region[0]) / fac
+ elif self.ProfileMode:
+ bpy.data.objects[self.ProfileBrush.name].modifiers[
+ "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.mouse_region[0]) / fac
+ self.mouse_region = 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.mouse_region[0]) / fac
+ self.mouse_region = event.mouse_region_x, event.mouse_region_y
+ elif self.BrushDepth:
+ self.BrushDepthOffset += (event.mouse_region_x - self.mouse_region[0]) / fac
+ self.mouse_region = event.mouse_region_x, event.mouse_region_y
+ else:
+ if (self.GridScaleX):
+ self.gapx += (event.mouse_region_x - self.mouse_region[0]) / 50
+ self.mouse_region = 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.mouse_region[0]) / 50
+ self.mouse_region = 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.mouse_region[0])
+ self.mouse_region = 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.mouse_region[0]
+ self.ascale = 0.0
+
+ self.mouse_region = event.mouse_region_x, event.mouse_region_y
+ else:
+ target_hit, target_normal, target_eul_rotation = Pick(context, event, self)
+ if target_hit is not None:
+ self.ShowCursor = True
+ up_vector = Vector((0.0, 0.0, 1.0))
+ quat_rot_axis = rot_axis_quat(up_vector, target_normal)
+ self.quat_rot = target_eul_rotation @ quat_rot_axis
+ MoveCursor(quat_rot_axis, target_hit, self)
+ self.SavCurLoc = target_hit
+ 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(
+ (target_hit.x, self.SavMousePos.y, self.SavMousePos.z))
+ if (yEcart > xEcart) and (yEcart > zEcart):
+ self.CurLoc = Vector(
+ (self.SavMousePos.x, target_hit.y, self.SavMousePos.z))
+ if (zEcart > xEcart) and (zEcart > yEcart):
+ self.CurLoc = Vector(
+ (self.SavMousePos.x, self.SavMousePos.y, target_hit.z))
+ else:
+ self.CurLoc = target_hit
+ else:
+ self.CurLoc = target_hit
+ else:
+ if self.CutMode:
+ if self.alt is False:
+ if self.ctrl :
+ # Find the closest position on the overlay grid and snap the mouse on it
+ # Draw a mini grid around the cursor
+ mouse_pos = [[event.mouse_region_x, event.mouse_region_y]]
+ Snap_Cursor(self, context, event, mouse_pos)
+
+ 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:
+ target_hit, target_normal, target_eul_rotation = Pick(context, event, self)
+ if target_hit is not None:
+ up_vector = Vector((0.0, 0.0, 1.0))
+ self.quat_rot_axis = rot_axis_quat(up_vector, target_normal)
+ self.quat_rot = target_eul_rotation @ self.quat_rot_axis
+ self.mouse_region = 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' and self.in_view_3d:
+ 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.CutMode is False:
+ if self.ctrl:
+ Picking(context, event)
+
+ else:
+
+ if self.CutType == self.line:
+ if self.CutMode 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.CutMode = True
+ else:
+ if self.CutType != self.line:
+ # Cut creation
+ if self.CutType == self.rectangle:
+ CreateCutSquare(self, context)
+ if self.CutType == self.circle:
+ CreateCutCircle(self, context)
+ if self.CutType == self.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.dont_apply_boolean
+
+ # if Object mode, set initiale state
+ if self.ObjectBrush is not None:
+ self.ObjectBrush.location = self.InitBrush['location']
+ self.ObjectBrush.scale = self.InitBrush['scale']
+ self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion']
+ self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler']
+ self.ObjectBrush.display_type = self.InitBrush['display_type']
+ self.ObjectBrush.show_in_front = self.InitBrush['show_in_front']
+
+ # remove solidify
+ Selection_Save(self)
+ self.BrushSolidify = False
+
+ bpy.ops.object.select_all(action='TOGGLE')
+ self.ObjectBrush.select_set(True)
+ context.view_layer.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 brush profil or circle subdivisions
+ elif (event.type == 'COMMA' and event.value == 'PRESS') or \
+ (event.type == self.carver_prefs.Key_Subrem and event.value == 'PRESS'):
+ # Brush profil
+ if self.ProfileMode:
+ self.nProfil += 1
+ if self.nProfil >= self.MaxProfil:
+ self.nProfil = 0
+ createMeshFromData(self)
+ # Circle subdivisions
+ if self.CutType == self.circle:
+ self.step += 1
+ if self.step >= len(self.stepAngle):
+ self.step = len(self.stepAngle) - 1
+ # Change brush profil or circle subdivisions
+ elif (event.type == 'PERIOD' and event.value == 'PRESS') or \
+ (event.type == self.carver_prefs.Key_Subadd and event.value == 'PRESS'):
+ # Brush profil
+ if self.ProfileMode:
+ self.nProfil -= 1
+ if self.nProfil < 0:
+ self.nProfil = self.MaxProfil - 1
+ createMeshFromData(self)
+ # Circle subdivisions
+ if self.CutType == self.circle:
+ 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.dont_apply_boolean
+
+ # Reset Object
+ if self.ObjectBrush is not None:
+ self.ObjectBrush.location = self.InitBrush['location']
+ self.ObjectBrush.scale = self.InitBrush['scale']
+ self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion']
+ self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler']
+ self.ObjectBrush.display_type = self.InitBrush['display_type']
+ self.ObjectBrush.show_in_front = self.InitBrush['show_in_front']
+
+ # Remove solidify modifier
+ Selection_Save(self)
+ self.BrushSolidify = False
+
+ bpy.ops.object.select_all(action='TOGGLE')
+ self.ObjectBrush.select_set(True)
+ context.view_layer.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.view_layer.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_set(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(None)
+ bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+
+ self.report({'WARNING'},
+ "Operation finished. Failure during Carving (Check the console for more info)")
+
+ return {'FINISHED'}
+
+ def cancel(self, context):
+ # Note: used to prevent memory leaks on quitting 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")
+ self.cancel(context)
+ return {'CANCELLED'}
+
+ # test if some other object types are selected that are not meshes
+ for obj in context.selected_objects:
+ if obj.type != "MESH":
+ self.report({'WARNING'},
+ "Some selected objects are not of the Mesh type. Operation Cancelled")
+ self.cancel(context)
+ return {'CANCELLED'}
+
+ if context.mode == 'EDIT_MESH':
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ #Load the Carver preferences
+ self.carver_prefs = bpy.context.preferences.addons[__package__].preferences
+
+ # 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(self.carver_prefs.ProfilePrefix):
+ continue
+ # In-scene profiles may have changed, remove them to refresh
+ for m in bpy.data.meshes:
+ if m.name.startswith(self.carver_prefs.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
+
+ if len(context.selected_objects) > 1:
+ self.ObjectBrush = context.active_object
+
+ # Copy the brush object
+ ob = bpy.data.objects.new("CarverBrushCopy", context.object.data.copy())
+ ob.location = self.ObjectBrush.location
+ context.collection.objects.link(ob)
+ context.view_layer.update()
+
+ # Save default variables
+ self.InitBrush['location'] = self.ObjectBrush.location.copy()
+ self.InitBrush['scale'] = self.ObjectBrush.scale.copy()
+ self.InitBrush['rotation_quaternion'] = self.ObjectBrush.rotation_quaternion.copy()
+ self.InitBrush['rotation_euler'] = self.ObjectBrush.rotation_euler.copy()
+ self.InitBrush['display_type'] = self.ObjectBrush.display_type
+ self.InitBrush['show_in_front'] = self.ObjectBrush.show_in_front
+
+ # Test if flat object
+ z = self.ObjectBrush.data.vertices[0].co.z
+ ErrorMarge = 0.01
+ self.SolidifyPossible = True
+ for v in self.ObjectBrush.data.vertices:
+ if abs(v.co.z - z) > ErrorMarge:
+ self.SolidifyPossible = False
+ break
+
+ self.CList = []
+ self.OPList = []
+ self.RList = []
+ self.OB_List = []
+
+ for obj in context.selected_objects:
+ if obj != self.ObjectBrush:
+ self.OB_List.append(obj)
+
+ # Left button
+ self.LMB = False
+
+ # Undo Variables
+ self.undo_index = 0
+ self.undo_limit = context.preferences.edit.undo_steps
+ self.undo_list = []
+
+ # Boolean operations type
+ self.BooleanType = 0
+
+ self.UList = []
+ self.UList_Index = -1
+ self.UndoOps = []
+
+ context.window_manager.modal_handler_add(self)
+ return {'RUNNING_MODAL'}
+
+ #Get the region area where the operator is used
+ def check_region(self,context,event):
+ if context.area != None:
+ if context.area.type == "VIEW_3D" :
+ for region in context.area.regions:
+ if region.type == "TOOLS":
+ t_panel = region
+ elif region.type == "UI":
+ ui_panel = region
+
+ view_3d_region_x = Vector((context.area.x + t_panel.width, context.area.x + context.area.width - ui_panel.width))
+ view_3d_region_y = Vector((context.region.y, context.region.y+context.region.height))
+
+ if (event.mouse_x > view_3d_region_x[0] and event.mouse_x < view_3d_region_x[1] \
+ and event.mouse_y > view_3d_region_y[0] and event.mouse_y < view_3d_region_y[1]):
+ self.in_view_3d = True
+ else:
+ self.in_view_3d = False
+ else:
+ self.in_view_3d = False
+
+ def CreateGeometry(self):
+ context = bpy.context
+ in_local_view = False
+
+ for area in context.screen.areas:
+ if area.type == 'VIEW_3D':
+ if area.spaces[0].local_view is not None:
+ in_local_view = True
+
+ if in_local_view:
+ bpy.ops.view3d.localview()
+
+ if self.ExclusiveCreateMode:
+ # Default width
+ objBBDiagonal = 0.5
+ else:
+ ActiveObj = self.CurrentSelection[0]
+ if ActiveObj is not None:
+ # Object dimensions
+ objBBDiagonal = objDiagonal(ActiveObj) / 4
+ subdivisions = 2
+
+ if len(context.selected_objects) > 0:
+ bpy.ops.object.select_all(action='TOGGLE')
+
+ context.view_layer.objects.active = self.CurrentObj
+
+ bpy.data.objects[self.CurrentObj.name].select_set(True)
+ bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.mesh.select_mode(type="EDGE")
+ if self.snapCursor is False:
+ bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions)
+ bpy.ops.mesh.extrude_region_move(
+ TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2})
+
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.mesh.normals_make_consistent()
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ saved_location_0 = context.scene.cursor.location.copy()
+ bpy.ops.view3d.snap_cursor_to_active()
+ saved_location = context.scene.cursor.location.copy()
+ bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
+ context.scene.cursor.location = saved_location
+ bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
+ context.scene.cursor.location = saved_location_0
+
+ bpy.data.objects[self.CurrentObj.name].select_set(True)
+ bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
+
+ for o in self.all_sel_obj_list:
+ bpy.data.objects[o.name].select_set(True)
+
+ if in_local_view:
+ bpy.ops.view3d.localview()
+
+ self.CutMode = False
+ self.mouse_path.clear()
+ self.mouse_path = [(0, 0), (0, 0)]
+
+ def Cut(self):
+ context = bpy.context
+
+ # Local view ?
+ in_local_view = False
+ for area in context.screen.areas:
+ if area.type == 'VIEW_3D':
+ if area.spaces[0].local_view is not None:
+ in_local_view = True
+
+ if in_local_view:
+ bpy.ops.view3d.localview()
+
+ # Save cursor position
+ CursorLocation = context.scene.cursor.location.copy()
+
+ #List of selected objects
+ selected_obj_list = []
+
+ #Cut Mode with line
+ if (self.ObjectMode is False) and (self.ProfileMode is False):
+
+ #Compute the bounding Box
+ objBBDiagonal = objDiagonal(self.CurrentSelection[0])
+ if self.dont_apply_boolean:
+ subdivisions = 1
+ else:
+ subdivisions = 32
+
+ # Get selected objects
+ selected_obj_list = context.selected_objects.copy()
+
+ bpy.ops.object.select_all(action='TOGGLE')
+
+ context.view_layer.objects.active = self.CurrentObj
+
+ bpy.data.objects[self.CurrentObj.name].select_set(True)
+ bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.mesh.select_mode(type="EDGE")
+ #Translate the created mesh away from the view
+ if (self.snapCursor is False) or (self.ForceRebool):
+ bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions)
+ #Extrude the mesh region and move the result
+ bpy.ops.mesh.extrude_region_move(
+ TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2})
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.mesh.normals_make_consistent()
+ bpy.ops.object.mode_set(mode='OBJECT')
+ else:
+ # Create list
+ if self.ObjectMode:
+ for o in self.CurrentSelection:
+ if o != self.ObjectBrush:
+ selected_obj_list.append(o)
+ self.CurrentObj = self.ObjectBrush
+ else:
+ selected_obj_list = self.CurrentSelection
+ self.CurrentObj = self.ProfileBrush
+
+ for obj in self.CurrentSelection:
+ UndoAdd(self, "MESH", obj)
+
+ # List objects create with rebool
+ lastSelected = []
+
+ for ActiveObj in selected_obj_list:
+ context.scene.cursor.location = CursorLocation
+
+ if len(context.selected_objects) > 0:
+ bpy.ops.object.select_all(action='TOGGLE')
+
+ # Select cut object
+ bpy.data.objects[self.CurrentObj.name].select_set(True)
+ context.view_layer.objects.active = self.CurrentObj
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Select object to cut
+ bpy.data.objects[ActiveObj.name].select_set(True)
+ context.view_layer.objects.active = ActiveObj
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Boolean operation
+ if (self.shift is False) and (self.ForceRebool is False):
+ if self.ObjectMode or self.ProfileMode:
+ if self.BoolOps == self.union:
+ boolean_operation(bool_type="UNION")
+ else:
+ boolean_operation(bool_type="DIFFERENCE")
+ else:
+ boolean_operation(bool_type="DIFFERENCE")
+
+ # Apply booleans
+ if self.dont_apply_boolean is False:
+ BMname = "CT_" + self.CurrentObj.name
+ for mb in ActiveObj.modifiers:
+ if (mb.type == 'BOOLEAN') and (mb.name == BMname):
+ try:
+ bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname)
+ except:
+ bpy.ops.object.modifier_remove(modifier=BMname)
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ self.report({'ERROR'}, str(exc_value))
+
+ bpy.ops.object.select_all(action='TOGGLE')
+ else:
+ if self.ObjectMode or self.ProfileMode:
+ for mb in self.CurrentObj.modifiers:
+ if (mb.type == 'SOLIDIFY') and (mb.name == "CT_SOLIDIFY"):
+ 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))
+
+ # Rebool
+ Rebool(context, self)
+
+ # Test if not empty object
+ if context.selected_objects[0]:
+ rebool_RT = context.selected_objects[0]
+ if len(rebool_RT.data.vertices) > 0:
+ # Create Bevel for new objects
+ CreateBevel(context, context.selected_objects[0])
+
+ UndoAdd(self, "REBOOL", context.selected_objects[0])
+
+ context.scene.cursor.location = ActiveObj.location
+ bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
+ else:
+ bpy.ops.object.delete(use_global=False)
+
+ context.scene.cursor.location = CursorLocation
+
+ if self.ObjectMode:
+ context.view_layer.objects.active = self.ObjectBrush
+ if self.ProfileMode:
+ context.view_layer.objects.active = self.ProfileBrush
+
+ if self.dont_apply_boolean is False:
+ # Apply booleans
+ BMname = "CT_" + self.CurrentObj.name
+ for mb in ActiveObj.modifiers:
+ if (mb.type == 'BOOLEAN') and (mb.name == BMname):
+ try:
+ bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname)
+ except:
+ bpy.ops.object.modifier_remove(modifier=BMname)
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ self.report({'ERROR'}, str(exc_value))
+ # Get new objects created with rebool operations
+ if len(context.selected_objects) > 0:
+ if self.shift is True:
+ # Get the last object selected
+ lastSelected.append(context.selected_objects[0])
+
+ context.scene.cursor.location = CursorLocation
+
+ if self.dont_apply_boolean is False:
+ # Remove cut object
+ if (self.ObjectMode is False) and (self.ProfileMode is False):
+ if len(context.selected_objects) > 0:
+ bpy.ops.object.select_all(action='TOGGLE')
+ bpy.data.objects[self.CurrentObj.name].select_set(True)
+ bpy.ops.object.delete(use_global=False)
+ else:
+ if self.ObjectMode:
+ self.ObjectBrush.display_type = self.InitBrush['display_type']
+
+ if len(context.selected_objects) > 0:
+ bpy.ops.object.select_all(action='TOGGLE')
+
+ # Select cut objects
+ for obj in lastSelected:
+ bpy.data.objects[obj.name].select_set(True)
+
+ for ActiveObj in selected_obj_list:
+ bpy.data.objects[ActiveObj.name].select_set(True)
+ context.view_layer.objects.active = ActiveObj
+ # Update bevel
+ list_act_obj = context.selected_objects.copy()
+ if self.Auto_BevelUpdate:
+ update_bevel(context)
+
+ # Re-select initial objects
+ bpy.ops.object.select_all(action='TOGGLE')
+ if self.ObjectMode:
+ # Re-select brush
+ self.ObjectBrush.select_set(True)
+ for ActiveObj in selected_obj_list:
+ bpy.data.objects[ActiveObj.name].select_set(True)
+ context.view_layer.objects.active = ActiveObj
+
+ # If object has children, set "Wire" draw type
+ if self.ObjectBrush is not None:
+ if len(self.ObjectBrush.children) > 0:
+ self.ObjectBrush.display_type = "WIRE"
+ if self.ProfileMode:
+ self.ProfileBrush.display_type = "WIRE"
+
+ if in_local_view:
+ bpy.ops.view3d.localview()
+
+ # Reset variables
+ self.CutMode = False
+ self.mouse_path.clear()
+ self.mouse_path = [(0, 0), (0, 0)]
+
+ self.ForceRebool = False
+
+ # bpy.ops.mesh.customdata_custom_splitnormals_clear()
class CarverProperties(bpy.types.PropertyGroup):
- DepthCursor: BoolProperty(
- name="DepthCursor",
- default=False
- )
- OInstanciate: BoolProperty(
- name="Obj_Instantiate",
- default=False
- )
- ORandom: BoolProperty(
- name="Random_Rotation",
- default=False
- )
- DontApply: BoolProperty(
- name="Dont_Apply",
- default=False
- )
- nProfile: IntProperty(
- name="Num_Profile",
- default=0
- )
+ DepthCursor: BoolProperty(
+ name="DepthCursor",
+ default=False
+ )
+ OInstanciate: BoolProperty(
+ name="Obj_Instantiate",
+ default=False
+ )
+ ORandom: BoolProperty(
+ name="Random_Rotation",
+ default=False
+ )
+ DontApply: BoolProperty(
+ name="Dont_Apply",
+ default=False
+ )
+ nProfile: IntProperty(
+ name="Num_Profile",
+ default=0
+ )
def register():
- from bpy.utils import register_class
- bpy.utils.register_class(CARVER_OT_operator)
- bpy.utils.register_class(CarverProperties)
- bpy.types.Scene.mesh_carver = bpy.props.PointerProperty(type=CarverProperties)
+ from bpy.utils import register_class
+ bpy.utils.register_class(CARVER_OT_operator)
+ bpy.utils.register_class(CarverProperties)
+ bpy.types.Scene.mesh_carver = bpy.props.PointerProperty(type=CarverProperties)
def unregister():
- from bpy.utils import unregister_class
- bpy.utils.unregister_class(CarverProperties)
- bpy.utils.unregister_class(CARVER_OT_operator)
- del bpy.types.Scene.mesh_carver
+ from bpy.utils import unregister_class
+ bpy.utils.unregister_class(CarverProperties)
+ bpy.utils.unregister_class(CARVER_OT_operator)
+ del bpy.types.Scene.mesh_carver