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_utils.py')
-rw-r--r--object_carver/carver_utils.py1580
1 files changed, 790 insertions, 790 deletions
diff --git a/object_carver/carver_utils.py b/object_carver/carver_utils.py
index ce66052f..495aa1ce 100644
--- a/object_carver/carver_utils.py
+++ b/object_carver/carver_utils.py
@@ -8,934 +8,934 @@ import sys
import random
import bmesh
from mathutils import (
- Euler,
- Matrix,
- Vector,
- Quaternion,
+ Euler,
+ Matrix,
+ Vector,
+ Quaternion,
)
from mathutils.geometry import (
- intersect_line_plane,
+ intersect_line_plane,
)
from math import (
- sin,
- cos,
- pi,
- )
+ sin,
+ cos,
+ pi,
+ )
import bpy_extras
from bpy_extras import view3d_utils
from bpy_extras.view3d_utils import (
- region_2d_to_vector_3d,
- region_2d_to_location_3d,
- location_3d_to_region_2d,
+ region_2d_to_vector_3d,
+ region_2d_to_location_3d,
+ location_3d_to_region_2d,
)
# Cut Square
def CreateCutSquare(self, context):
- """ Create a rectangle mesh """
- far_limit = 10000.0
- faces=[]
-
- # Get the mouse coordinates
- coord = self.mouse_path[0][0], self.mouse_path[0][1]
-
- # New mesh
- me = bpy.data.meshes.new('CMT_Square')
- bm = bmesh.new()
- bm.from_mesh(me)
-
- # New object and link it to the scene
- ob = bpy.data.objects.new('CMT_Square', me)
- self.CurrentObj = ob
- context.collection.objects.link(ob)
-
- # Scene information
- region = context.region
- rv3d = context.region_data
- depth_location = region_2d_to_vector_3d(region, rv3d, coord)
- self.ViewVector = depth_location
-
- # Get a point on a infinite plane and its direction
- plane_normal = depth_location
- plane_direction = plane_normal.normalized()
-
- if self.snapCursor:
- plane_point = context.scene.cursor.location
- else:
- plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0))
-
- # Find the intersection of a line going thru each vertex and the infinite plane
- for v_co in self.rectangle_coord:
- vec = region_2d_to_vector_3d(region, rv3d, v_co)
- p0 = region_2d_to_location_3d(region, rv3d,v_co, vec)
- p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit
- faces.append(bm.verts.new(intersect_line_plane(p0, p1, plane_point, plane_direction)))
-
- # Update vertices index
- bm.verts.index_update()
- # New faces
- t_face = bm.faces.new(faces)
- # Set mesh
- bm.to_mesh(me)
+ """ Create a rectangle mesh """
+ far_limit = 10000.0
+ faces=[]
+
+ # Get the mouse coordinates
+ coord = self.mouse_path[0][0], self.mouse_path[0][1]
+
+ # New mesh
+ me = bpy.data.meshes.new('CMT_Square')
+ bm = bmesh.new()
+ bm.from_mesh(me)
+
+ # New object and link it to the scene
+ ob = bpy.data.objects.new('CMT_Square', me)
+ self.CurrentObj = ob
+ context.collection.objects.link(ob)
+
+ # Scene information
+ region = context.region
+ rv3d = context.region_data
+ depth_location = region_2d_to_vector_3d(region, rv3d, coord)
+ self.ViewVector = depth_location
+
+ # Get a point on a infinite plane and its direction
+ plane_normal = depth_location
+ plane_direction = plane_normal.normalized()
+
+ if self.snapCursor:
+ plane_point = context.scene.cursor.location
+ else:
+ plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0))
+
+ # Find the intersection of a line going thru each vertex and the infinite plane
+ for v_co in self.rectangle_coord:
+ vec = region_2d_to_vector_3d(region, rv3d, v_co)
+ p0 = region_2d_to_location_3d(region, rv3d,v_co, vec)
+ p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit
+ faces.append(bm.verts.new(intersect_line_plane(p0, p1, plane_point, plane_direction)))
+
+ # Update vertices index
+ bm.verts.index_update()
+ # New faces
+ t_face = bm.faces.new(faces)
+ # Set mesh
+ bm.to_mesh(me)
# Cut Line
def CreateCutLine(self, context):
- """ Create a polygon mesh """
- far_limit = 10000.0
- vertices = []
- faces = []
- loc = []
-
- # Get the mouse coordinates
- coord = self.mouse_path[0][0], self.mouse_path[0][1]
-
- # New mesh
- me = bpy.data.meshes.new('CMT_Line')
- bm = bmesh.new()
- bm.from_mesh(me)
-
- # New object and link it to the scene
- ob = bpy.data.objects.new('CMT_Line', me)
- self.CurrentObj = ob
- context.collection.objects.link(ob)
-
- # Scene information
- region = context.region
- rv3d = context.region_data
- depth_location = region_2d_to_vector_3d(region, rv3d, coord)
- self.ViewVector = depth_location
-
- # Get a point on a infinite plane and its direction
- plane_normal = depth_location
- plane_direction = plane_normal.normalized()
-
- if self.snapCursor:
- plane_point = context.scene.cursor.location
- else:
- plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0))
-
- # Use dict to remove doubles
- # Find the intersection of a line going thru each vertex and the infinite plane
- for idx, v_co in enumerate(list(dict.fromkeys(self.mouse_path))):
- vec = region_2d_to_vector_3d(region, rv3d, v_co)
- p0 = region_2d_to_location_3d(region, rv3d,v_co, vec)
- p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit
- loc.append(intersect_line_plane(p0, p1, plane_point, plane_direction))
- vertices.append(bm.verts.new(loc[idx]))
-
- if idx > 0:
- bm.edges.new([vertices[idx-1],vertices[idx]])
-
- faces.append(vertices[idx])
-
- # Update vertices index
- bm.verts.index_update()
-
- # Nothing is selected, create close geometry
- if self.CreateMode:
- if self.Closed and len(vertices) > 1:
- bm.edges.new([vertices[-1], vertices[0]])
- bm.faces.new(faces)
- else:
- # Create faces if more than 2 vertices
- if len(vertices) > 1 :
- bm.edges.new([vertices[-1], vertices[0]])
- bm.faces.new(faces)
-
- bm.to_mesh(me)
+ """ Create a polygon mesh """
+ far_limit = 10000.0
+ vertices = []
+ faces = []
+ loc = []
+
+ # Get the mouse coordinates
+ coord = self.mouse_path[0][0], self.mouse_path[0][1]
+
+ # New mesh
+ me = bpy.data.meshes.new('CMT_Line')
+ bm = bmesh.new()
+ bm.from_mesh(me)
+
+ # New object and link it to the scene
+ ob = bpy.data.objects.new('CMT_Line', me)
+ self.CurrentObj = ob
+ context.collection.objects.link(ob)
+
+ # Scene information
+ region = context.region
+ rv3d = context.region_data
+ depth_location = region_2d_to_vector_3d(region, rv3d, coord)
+ self.ViewVector = depth_location
+
+ # Get a point on a infinite plane and its direction
+ plane_normal = depth_location
+ plane_direction = plane_normal.normalized()
+
+ if self.snapCursor:
+ plane_point = context.scene.cursor.location
+ else:
+ plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0))
+
+ # Use dict to remove doubles
+ # Find the intersection of a line going thru each vertex and the infinite plane
+ for idx, v_co in enumerate(list(dict.fromkeys(self.mouse_path))):
+ vec = region_2d_to_vector_3d(region, rv3d, v_co)
+ p0 = region_2d_to_location_3d(region, rv3d,v_co, vec)
+ p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit
+ loc.append(intersect_line_plane(p0, p1, plane_point, plane_direction))
+ vertices.append(bm.verts.new(loc[idx]))
+
+ if idx > 0:
+ bm.edges.new([vertices[idx-1],vertices[idx]])
+
+ faces.append(vertices[idx])
+
+ # Update vertices index
+ bm.verts.index_update()
+
+ # Nothing is selected, create close geometry
+ if self.CreateMode:
+ if self.Closed and len(vertices) > 1:
+ bm.edges.new([vertices[-1], vertices[0]])
+ bm.faces.new(faces)
+ else:
+ # Create faces if more than 2 vertices
+ if len(vertices) > 1 :
+ bm.edges.new([vertices[-1], vertices[0]])
+ bm.faces.new(faces)
+
+ bm.to_mesh(me)
# Cut Circle
def CreateCutCircle(self, context):
- """ Create a circle mesh """
- far_limit = 10000.0
- FacesList = []
-
- # Get the mouse coordinates
- mouse_pos_x = self.mouse_path[0][0]
- mouse_pos_y = self.mouse_path[0][1]
- coord = self.mouse_path[0][0], self.mouse_path[0][1]
-
- # Scene information
- region = context.region
- rv3d = context.region_data
- depth_location = region_2d_to_vector_3d(region, rv3d, coord)
- self.ViewVector = depth_location
-
- # Get a point on a infinite plane and its direction
- plane_point = context.scene.cursor.location if self.snapCursor else Vector((0.0, 0.0, 0.0))
- plane_normal = depth_location
- plane_direction = plane_normal.normalized()
-
- # New mesh
- me = bpy.data.meshes.new('CMT_Circle')
- bm = bmesh.new()
- bm.from_mesh(me)
-
- # New object and link it to the scene
- ob = bpy.data.objects.new('CMT_Circle', me)
- self.CurrentObj = ob
- context.collection.objects.link(ob)
-
- # Create a circle using a tri fan
- tris_fan, indices = draw_circle(self, mouse_pos_x, mouse_pos_y)
-
- # Remove the vertex in the center to get the outer line of the circle
- verts = tris_fan[1:]
-
- # Find the intersection of a line going thru each vertex and the infinite plane
- for vert in verts:
- vec = region_2d_to_vector_3d(region, rv3d, vert)
- p0 = region_2d_to_location_3d(region, rv3d, vert, vec)
- p1 = p0 + plane_direction * far_limit
- loc0 = intersect_line_plane(p0, p1, plane_point, plane_direction)
- t_v0 = bm.verts.new(loc0)
- FacesList.append(t_v0)
-
- bm.verts.index_update()
- bm.faces.new(FacesList)
- bm.to_mesh(me)
+ """ Create a circle mesh """
+ far_limit = 10000.0
+ FacesList = []
+
+ # Get the mouse coordinates
+ mouse_pos_x = self.mouse_path[0][0]
+ mouse_pos_y = self.mouse_path[0][1]
+ coord = self.mouse_path[0][0], self.mouse_path[0][1]
+
+ # Scene information
+ region = context.region
+ rv3d = context.region_data
+ depth_location = region_2d_to_vector_3d(region, rv3d, coord)
+ self.ViewVector = depth_location
+
+ # Get a point on a infinite plane and its direction
+ plane_point = context.scene.cursor.location if self.snapCursor else Vector((0.0, 0.0, 0.0))
+ plane_normal = depth_location
+ plane_direction = plane_normal.normalized()
+
+ # New mesh
+ me = bpy.data.meshes.new('CMT_Circle')
+ bm = bmesh.new()
+ bm.from_mesh(me)
+
+ # New object and link it to the scene
+ ob = bpy.data.objects.new('CMT_Circle', me)
+ self.CurrentObj = ob
+ context.collection.objects.link(ob)
+
+ # Create a circle using a tri fan
+ tris_fan, indices = draw_circle(self, mouse_pos_x, mouse_pos_y)
+
+ # Remove the vertex in the center to get the outer line of the circle
+ verts = tris_fan[1:]
+
+ # Find the intersection of a line going thru each vertex and the infinite plane
+ for vert in verts:
+ vec = region_2d_to_vector_3d(region, rv3d, vert)
+ p0 = region_2d_to_location_3d(region, rv3d, vert, vec)
+ p1 = p0 + plane_direction * far_limit
+ loc0 = intersect_line_plane(p0, p1, plane_point, plane_direction)
+ t_v0 = bm.verts.new(loc0)
+ FacesList.append(t_v0)
+
+ bm.verts.index_update()
+ bm.faces.new(FacesList)
+ bm.to_mesh(me)
def create_2d_circle(self, step, radius, rotation = 0):
- """ Create the vertices of a 2d circle at (0,0) """
- verts = []
- for angle in range(0, 360, step):
- verts.append(math.cos(math.radians(angle + rotation)) * radius)
- verts.append(math.sin(math.radians(angle + rotation)) * radius)
- verts.append(0.0)
- verts.append(math.cos(math.radians(0.0 + rotation)) * radius)
- verts.append(math.sin(math.radians(0.0 + rotation)) * radius)
- verts.append(0.0)
- return(verts)
+ """ Create the vertices of a 2d circle at (0,0) """
+ verts = []
+ for angle in range(0, 360, step):
+ verts.append(math.cos(math.radians(angle + rotation)) * radius)
+ verts.append(math.sin(math.radians(angle + rotation)) * radius)
+ verts.append(0.0)
+ verts.append(math.cos(math.radians(0.0 + rotation)) * radius)
+ verts.append(math.sin(math.radians(0.0 + rotation)) * radius)
+ verts.append(0.0)
+ return(verts)
def draw_circle(self, mouse_pos_x, mouse_pos_y):
- """ Return the coordinates + indices of a circle using a triangle fan """
- tris_verts = []
- indices = []
- segments = int(360 / self.stepAngle[self.step])
- radius = self.mouse_path[1][0] - self.mouse_path[0][0]
- rotation = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 2
+ """ Return the coordinates + indices of a circle using a triangle fan """
+ tris_verts = []
+ indices = []
+ segments = int(360 / self.stepAngle[self.step])
+ radius = self.mouse_path[1][0] - self.mouse_path[0][0]
+ rotation = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 2
- # Get the vertices of a 2d circle
- verts = create_2d_circle(self, self.stepAngle[self.step], radius, rotation)
+ # Get the vertices of a 2d circle
+ verts = create_2d_circle(self, self.stepAngle[self.step], radius, rotation)
- # Create the first vertex at mouse position for the center of the circle
- tris_verts.append(Vector((mouse_pos_x + self.xpos , mouse_pos_y + self.ypos)))
+ # Create the first vertex at mouse position for the center of the circle
+ tris_verts.append(Vector((mouse_pos_x + self.xpos , mouse_pos_y + self.ypos)))
- # For each vertex of the circle, add the mouse position and the translation
- for idx in range(int(len(verts) / 3) - 1):
- tris_verts.append(Vector((verts[idx * 3] + mouse_pos_x + self.xpos, \
- verts[idx * 3 + 1] + mouse_pos_y + self.ypos)))
- i1 = idx+1
- i2 = idx+2 if idx+2 <= segments else 1
- indices.append((0,i1,i2))
+ # For each vertex of the circle, add the mouse position and the translation
+ for idx in range(int(len(verts) / 3) - 1):
+ tris_verts.append(Vector((verts[idx * 3] + mouse_pos_x + self.xpos, \
+ verts[idx * 3 + 1] + mouse_pos_y + self.ypos)))
+ i1 = idx+1
+ i2 = idx+2 if idx+2 <= segments else 1
+ indices.append((0,i1,i2))
- return(tris_verts, indices)
+ return(tris_verts, indices)
# Object dimensions (SCULPT Tools tips)
def objDiagonal(obj):
- return ((obj.dimensions[0]**2) + (obj.dimensions[1]**2) + (obj.dimensions[2]**2))**0.5
+ return ((obj.dimensions[0]**2) + (obj.dimensions[1]**2) + (obj.dimensions[2]**2))**0.5
# Bevel Update
def update_bevel(context):
- selection = context.selected_objects.copy()
- active = context.active_object
+ selection = context.selected_objects.copy()
+ active = context.active_object
- if len(selection) > 0:
- for obj in selection:
- bpy.ops.object.select_all(action='DESELECT')
- obj.select_set(True)
- context.view_layer.objects.active = obj
+ if len(selection) > 0:
+ for obj in selection:
+ bpy.ops.object.select_all(action='DESELECT')
+ obj.select_set(True)
+ context.view_layer.objects.active = obj
- # Test object name
- # Subdive mode : Only bevel weight
- if obj.data.name.startswith("S_") or obj.data.name.startswith("S "):
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.region_to_loop()
- bpy.ops.transform.edge_bevelweight(value=1)
- bpy.ops.object.mode_set(mode='OBJECT')
+ # Test object name
+ # Subdive mode : Only bevel weight
+ if obj.data.name.startswith("S_") or obj.data.name.startswith("S "):
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.region_to_loop()
+ bpy.ops.transform.edge_bevelweight(value=1)
+ bpy.ops.object.mode_set(mode='OBJECT')
- else:
- # No subdiv mode : bevel weight + Crease + Sharp
- CreateBevel(context, obj)
+ else:
+ # No subdiv mode : bevel weight + Crease + Sharp
+ CreateBevel(context, obj)
- bpy.ops.object.select_all(action='DESELECT')
+ bpy.ops.object.select_all(action='DESELECT')
- for obj in selection:
- obj.select_set(True)
- context.view_layer.objects.active = active
+ for obj in selection:
+ obj.select_set(True)
+ context.view_layer.objects.active = active
# Create bevel
def CreateBevel(context, CurrentObject):
- # Save active object
- SavActive = context.active_object
+ # Save active object
+ SavActive = context.active_object
- # Test if initial object has bevel
- bevel_modifier = False
- for modifier in SavActive.modifiers:
- if modifier.name == 'Bevel':
- bevel_modifier = True
+ # Test if initial object has bevel
+ bevel_modifier = False
+ for modifier in SavActive.modifiers:
+ if modifier.name == 'Bevel':
+ bevel_modifier = True
- if bevel_modifier:
- # Active "CurrentObject"
- context.view_layer.objects.active = CurrentObject
+ if bevel_modifier:
+ # Active "CurrentObject"
+ context.view_layer.objects.active = CurrentObject
- bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.object.mode_set(mode='EDIT')
- # Edge mode
- bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
- # Clear all
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.mark_sharp(clear=True)
- bpy.ops.transform.edge_crease(value=-1)
- bpy.ops.transform.edge_bevelweight(value=-1)
+ # Edge mode
+ bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
+ # Clear all
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.mesh.mark_sharp(clear=True)
+ bpy.ops.transform.edge_crease(value=-1)
+ bpy.ops.transform.edge_bevelweight(value=-1)
- bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.mesh.select_all(action='DESELECT')
- # Select (in radians) all 30° sharp edges
- bpy.ops.mesh.edges_select_sharp(sharpness=0.523599)
- # Apply bevel weight + Crease + Sharp to the selected edges
- bpy.ops.mesh.mark_sharp()
- bpy.ops.transform.edge_crease(value=1)
- bpy.ops.transform.edge_bevelweight(value=1)
+ # Select (in radians) all 30° sharp edges
+ bpy.ops.mesh.edges_select_sharp(sharpness=0.523599)
+ # Apply bevel weight + Crease + Sharp to the selected edges
+ bpy.ops.mesh.mark_sharp()
+ bpy.ops.transform.edge_crease(value=1)
+ bpy.ops.transform.edge_bevelweight(value=1)
- bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.mesh.select_all(action='DESELECT')
- bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
- CurrentObject.data.use_customdata_edge_bevel = True
+ CurrentObject.data.use_customdata_edge_bevel = True
- for i in range(len(CurrentObject.data.edges)):
- if CurrentObject.data.edges[i].select is True:
- CurrentObject.data.edges[i].bevel_weight = 1.0
- CurrentObject.data.edges[i].use_edge_sharp = True
+ for i in range(len(CurrentObject.data.edges)):
+ if CurrentObject.data.edges[i].select is True:
+ CurrentObject.data.edges[i].bevel_weight = 1.0
+ CurrentObject.data.edges[i].use_edge_sharp = True
- bevel_modifier = False
- for m in CurrentObject.modifiers:
- if m.name == 'Bevel':
- bevel_modifier = True
+ bevel_modifier = False
+ for m in CurrentObject.modifiers:
+ if m.name == 'Bevel':
+ bevel_modifier = True
- if bevel_modifier is False:
- bpy.ops.object.modifier_add(type='BEVEL')
- mod = context.object.modifiers[-1]
- mod.limit_method = 'WEIGHT'
- mod.width = 0.01
- mod.profile = 0.699099
- mod.use_clight_overlap = False
- mod.segments = 3
- mod.loop_slide = False
+ if bevel_modifier is False:
+ bpy.ops.object.modifier_add(type='BEVEL')
+ mod = context.object.modifiers[-1]
+ mod.limit_method = 'WEIGHT'
+ mod.width = 0.01
+ mod.profile = 0.699099
+ mod.use_clight_overlap = False
+ mod.segments = 3
+ mod.loop_slide = False
- bpy.ops.object.shade_smooth()
+ bpy.ops.object.shade_smooth()
- context.object.data.use_auto_smooth = True
- context.object.data.auto_smooth_angle = 1.0471975
+ context.object.data.use_auto_smooth = True
+ context.object.data.auto_smooth_angle = 1.0471975
- # Restore the active object
- context.view_layer.objects.active = SavActive
+ # Restore the active object
+ context.view_layer.objects.active = SavActive
def MoveCursor(qRot, location, self):
- """ In brush mode : Draw a circle around the brush """
- if qRot is not None:
- verts = create_2d_circle(self, 10, 1)
- self.CLR_C.clear()
- vc = Vector()
- for idx in range(int(len(verts) / 3)):
- vc.x = verts[idx * 3]
- vc.y = verts[idx * 3 + 1]
- vc.z = verts[idx * 3 + 2]
- vc = qRot @ vc
- self.CLR_C.append(vc.x)
- self.CLR_C.append(vc.y)
- self.CLR_C.append(vc.z)
+ """ In brush mode : Draw a circle around the brush """
+ if qRot is not None:
+ verts = create_2d_circle(self, 10, 1)
+ self.CLR_C.clear()
+ vc = Vector()
+ for idx in range(int(len(verts) / 3)):
+ vc.x = verts[idx * 3]
+ vc.y = verts[idx * 3 + 1]
+ vc.z = verts[idx * 3 + 2]
+ vc = qRot @ vc
+ self.CLR_C.append(vc.x)
+ self.CLR_C.append(vc.y)
+ self.CLR_C.append(vc.z)
def rot_axis_quat(vector1, vector2):
- """ Find the rotation (quaternion) from vector 1 to vector 2"""
- vector1 = vector1.normalized()
- vector2 = vector2.normalized()
- cosTheta = vector1.dot(vector2)
- rotationAxis = Vector((0.0, 0.0, 0.0))
- if (cosTheta < -1 + 0.001):
- v = Vector((0.0, 1.0, 0.0))
- #Get the vector at the right angles to both
- rotationAxis = vector1.cross(v)
- rotationAxis = rotationAxis.normalized()
- q = Quaternion()
- q.w = 0.0
- q.x = rotationAxis.x
- q.y = rotationAxis.y
- q.z = rotationAxis.z
- else:
- rotationAxis = vector1.cross(vector2)
- s = math.sqrt((1.0 + cosTheta) * 2.0)
- invs = 1 / s
- q = Quaternion()
- q.w = s * 0.5
- q.x = rotationAxis.x * invs
- q.y = rotationAxis.y * invs
- q.z = rotationAxis.z * invs
- return q
+ """ Find the rotation (quaternion) from vector 1 to vector 2"""
+ vector1 = vector1.normalized()
+ vector2 = vector2.normalized()
+ cosTheta = vector1.dot(vector2)
+ rotationAxis = Vector((0.0, 0.0, 0.0))
+ if (cosTheta < -1 + 0.001):
+ v = Vector((0.0, 1.0, 0.0))
+ #Get the vector at the right angles to both
+ rotationAxis = vector1.cross(v)
+ rotationAxis = rotationAxis.normalized()
+ q = Quaternion()
+ q.w = 0.0
+ q.x = rotationAxis.x
+ q.y = rotationAxis.y
+ q.z = rotationAxis.z
+ else:
+ rotationAxis = vector1.cross(vector2)
+ s = math.sqrt((1.0 + cosTheta) * 2.0)
+ invs = 1 / s
+ q = Quaternion()
+ q.w = s * 0.5
+ q.x = rotationAxis.x * invs
+ q.y = rotationAxis.y * invs
+ q.z = rotationAxis.z * invs
+ return q
# Picking (template)
def Picking(context, event):
- """ Put the 3d cursor on the closest object"""
-
- # get the context arguments
- scene = context.scene
- region = context.region
- rv3d = context.region_data
- coord = event.mouse_region_x, event.mouse_region_y
-
- # get the ray from the viewport and mouse
- view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
- ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
- ray_target = ray_origin + view_vector
-
- def visible_objects_and_duplis():
- depsgraph = context.evaluated_depsgraph_get()
- for dup in depsgraph.object_instances:
- if dup.is_instance: # Real dupli instance
- obj = dup.instance_object.original
- yield (obj, dup.matrix.copy())
- else: # Usual object
- obj = dup.object.original
- yield (obj, obj.matrix_world.copy())
-
- def obj_ray_cast(obj, matrix):
- # get the ray relative to the object
- matrix_inv = matrix.inverted()
- ray_origin_obj = matrix_inv @ ray_origin
- ray_target_obj = matrix_inv @ ray_target
- ray_direction_obj = ray_target_obj - ray_origin_obj
- # cast the ray
- success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
- if success:
- return location, normal, face_index
- return None, None, None
-
- # cast rays and find the closest object
- best_length_squared = -1.0
- best_obj = None
-
- # cast rays and find the closest object
- for obj, matrix in visible_objects_and_duplis():
- if obj.type == 'MESH':
- hit, normal, face_index = obj_ray_cast(obj, matrix)
- if hit is not None:
- hit_world = matrix @ hit
- length_squared = (hit_world - ray_origin).length_squared
- if best_obj is None or length_squared < best_length_squared:
- scene.cursor.location = hit_world
- best_length_squared = length_squared
- best_obj = obj
- else:
- if best_obj is None:
- depth_location = region_2d_to_vector_3d(region, rv3d, coord)
- loc = region_2d_to_location_3d(region, rv3d, coord, depth_location)
- scene.cursor.location = loc
+ """ Put the 3d cursor on the closest object"""
+
+ # get the context arguments
+ scene = context.scene
+ region = context.region
+ rv3d = context.region_data
+ coord = event.mouse_region_x, event.mouse_region_y
+
+ # get the ray from the viewport and mouse
+ view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
+ ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
+ ray_target = ray_origin + view_vector
+
+ def visible_objects_and_duplis():
+ depsgraph = context.evaluated_depsgraph_get()
+ for dup in depsgraph.object_instances:
+ if dup.is_instance: # Real dupli instance
+ obj = dup.instance_object.original
+ yield (obj, dup.matrix.copy())
+ else: # Usual object
+ obj = dup.object.original
+ yield (obj, obj.matrix_world.copy())
+
+ def obj_ray_cast(obj, matrix):
+ # get the ray relative to the object
+ matrix_inv = matrix.inverted()
+ ray_origin_obj = matrix_inv @ ray_origin
+ ray_target_obj = matrix_inv @ ray_target
+ ray_direction_obj = ray_target_obj - ray_origin_obj
+ # cast the ray
+ success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
+ if success:
+ return location, normal, face_index
+ return None, None, None
+
+ # cast rays and find the closest object
+ best_length_squared = -1.0
+ best_obj = None
+
+ # cast rays and find the closest object
+ for obj, matrix in visible_objects_and_duplis():
+ if obj.type == 'MESH':
+ hit, normal, face_index = obj_ray_cast(obj, matrix)
+ if hit is not None:
+ hit_world = matrix @ hit
+ length_squared = (hit_world - ray_origin).length_squared
+ if best_obj is None or length_squared < best_length_squared:
+ scene.cursor.location = hit_world
+ best_length_squared = length_squared
+ best_obj = obj
+ else:
+ if best_obj is None:
+ depth_location = region_2d_to_vector_3d(region, rv3d, coord)
+ loc = region_2d_to_location_3d(region, rv3d, coord, depth_location)
+ scene.cursor.location = loc
def Pick(context, event, self, ray_max=10000.0):
- region = context.region
- rv3d = context.region_data
- coord = event.mouse_region_x, event.mouse_region_y
- view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
- ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
- ray_target = ray_origin + (view_vector * ray_max)
-
- def obj_ray_cast(obj, matrix):
- matrix_inv = matrix.inverted()
- ray_origin_obj = matrix_inv @ ray_origin
- ray_target_obj = matrix_inv @ ray_target
- success, hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)
- if success:
- return hit, normal, face_index
- return None, None, None
-
- best_length_squared = ray_max * ray_max
- best_obj = None
- for obj in self.CList:
- matrix = obj.matrix_world
- hit, normal, face_index = obj_ray_cast(obj, matrix)
- rotation = obj.rotation_euler.to_quaternion()
- if hit is not None:
- hit_world = matrix @ hit
- length_squared = (hit_world - ray_origin).length_squared
- if length_squared < best_length_squared:
- best_length_squared = length_squared
- best_obj = obj
- hits = hit_world
- ns = normal
- fs = face_index
-
- if best_obj is not None:
- return hits, ns, rotation
-
- return None, None, None
+ region = context.region
+ rv3d = context.region_data
+ coord = event.mouse_region_x, event.mouse_region_y
+ view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
+ ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
+ ray_target = ray_origin + (view_vector * ray_max)
+
+ def obj_ray_cast(obj, matrix):
+ matrix_inv = matrix.inverted()
+ ray_origin_obj = matrix_inv @ ray_origin
+ ray_target_obj = matrix_inv @ ray_target
+ success, hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)
+ if success:
+ return hit, normal, face_index
+ return None, None, None
+
+ best_length_squared = ray_max * ray_max
+ best_obj = None
+ for obj in self.CList:
+ matrix = obj.matrix_world
+ hit, normal, face_index = obj_ray_cast(obj, matrix)
+ rotation = obj.rotation_euler.to_quaternion()
+ if hit is not None:
+ hit_world = matrix @ hit
+ length_squared = (hit_world - ray_origin).length_squared
+ if length_squared < best_length_squared:
+ best_length_squared = length_squared
+ best_obj = obj
+ hits = hit_world
+ ns = normal
+ fs = face_index
+
+ if best_obj is not None:
+ return hits, ns, rotation
+
+ return None, None, None
def SelectObject(self, copyobj):
- copyobj.select_set(True)
+ copyobj.select_set(True)
- for child in copyobj.children:
- SelectObject(self, child)
+ for child in copyobj.children:
+ SelectObject(self, child)
- if copyobj.parent is None:
- bpy.context.view_layer.objects.active = copyobj
+ if copyobj.parent is None:
+ bpy.context.view_layer.objects.active = copyobj
# Undo
def printUndo(self):
- for l in self.UList:
- print(l)
+ for l in self.UList:
+ print(l)
def UndoAdd(self, type, obj):
- """ Create a backup mesh before apply the action to the object """
- if obj is None:
- return
+ """ Create a backup mesh before apply the action to the object """
+ if obj is None:
+ return
- if type != "DUPLICATE":
- bm = bmesh.new()
- bm.from_mesh(obj.data)
- self.UndoOps.append((obj, type, bm))
- else:
- self.UndoOps.append((obj, type, None))
+ if type != "DUPLICATE":
+ bm = bmesh.new()
+ bm.from_mesh(obj.data)
+ self.UndoOps.append((obj, type, bm))
+ else:
+ self.UndoOps.append((obj, type, None))
def UndoListUpdate(self):
- self.UList.append((self.UndoOps.copy()))
- self.UList_Index += 1
- self.UndoOps.clear()
+ self.UList.append((self.UndoOps.copy()))
+ self.UList_Index += 1
+ self.UndoOps.clear()
def Undo(self):
- if self.UList_Index < 0:
- return
- # get previous mesh
- for o in self.UList[self.UList_Index]:
- if o[1] == "MESH":
- bm = o[2]
- bm.to_mesh(o[0].data)
+ if self.UList_Index < 0:
+ return
+ # get previous mesh
+ for o in self.UList[self.UList_Index]:
+ if o[1] == "MESH":
+ bm = o[2]
+ bm.to_mesh(o[0].data)
- SelectObjList = bpy.context.selected_objects.copy()
- Active_Obj = bpy.context.active_object
- bpy.ops.object.select_all(action='TOGGLE')
+ SelectObjList = bpy.context.selected_objects.copy()
+ Active_Obj = bpy.context.active_object
+ bpy.ops.object.select_all(action='TOGGLE')
- for o in self.UList[self.UList_Index]:
- if o[1] == "REBOOL":
- o[0].select_set(True)
- o[0].hide_viewport = False
+ for o in self.UList[self.UList_Index]:
+ if o[1] == "REBOOL":
+ o[0].select_set(True)
+ o[0].hide_viewport = False
- if o[1] == "DUPLICATE":
- o[0].select_set(True)
- o[0].hide_viewport = False
+ if o[1] == "DUPLICATE":
+ o[0].select_set(True)
+ o[0].hide_viewport = False
- bpy.ops.object.delete(use_global=False)
+ bpy.ops.object.delete(use_global=False)
- for so in SelectObjList:
- bpy.data.objects[so.name].select_set(True)
- bpy.context.view_layer.objects.active = Active_Obj
+ for so in SelectObjList:
+ bpy.data.objects[so.name].select_set(True)
+ bpy.context.view_layer.objects.active = Active_Obj
- self.UList_Index -= 1
- self.UList[self.UList_Index + 1:] = []
+ self.UList_Index -= 1
+ self.UList[self.UList_Index + 1:] = []
def duplicateObject(self):
- if self.Instantiate:
- bpy.ops.object.duplicate_move_linked(
- OBJECT_OT_duplicate={
- "linked": True,
- "mode": 'TRANSLATION',
- },
- TRANSFORM_OT_translate={
- "value": (0, 0, 0),
- },
- )
- else:
- bpy.ops.object.duplicate_move(
- OBJECT_OT_duplicate={
- "linked": False,
- "mode": 'TRANSLATION',
- },
- TRANSFORM_OT_translate={
- "value": (0, 0, 0),
- },
- )
-
- ob_new = bpy.context.active_object
-
- ob_new.location = self.CurLoc
- v = Vector()
- v.x = v.y = 0.0
- v.z = self.BrushDepthOffset
- 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 = 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 is 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.display_type == "WIRE") and (self.BrushSolidify is False):
- ob_new.hide_viewport = True
-
- if self.BrushSolidify:
- ob_new.display_type = "SOLID"
- ob_new.show_in_front = 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.all_sel_obj_list:
- o.select_set(True)
-
- bpy.context.view_layer.objects.active = self.OpsObj
+ if self.Instantiate:
+ bpy.ops.object.duplicate_move_linked(
+ OBJECT_OT_duplicate={
+ "linked": True,
+ "mode": 'TRANSLATION',
+ },
+ TRANSFORM_OT_translate={
+ "value": (0, 0, 0),
+ },
+ )
+ else:
+ bpy.ops.object.duplicate_move(
+ OBJECT_OT_duplicate={
+ "linked": False,
+ "mode": 'TRANSLATION',
+ },
+ TRANSFORM_OT_translate={
+ "value": (0, 0, 0),
+ },
+ )
+
+ ob_new = bpy.context.active_object
+
+ ob_new.location = self.CurLoc
+ v = Vector()
+ v.x = v.y = 0.0
+ v.z = self.BrushDepthOffset
+ 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 = 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 is 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.display_type == "WIRE") and (self.BrushSolidify is False):
+ ob_new.hide_viewport = True
+
+ if self.BrushSolidify:
+ ob_new.display_type = "SOLID"
+ ob_new.show_in_front = 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.all_sel_obj_list:
+ o.select_set(True)
+
+ bpy.context.view_layer.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 = Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z')
- for v in obverts:
- v.co = v.co @ rotmat
-
- verts.extend([((v.co.x - startx, v.co.y - starty, v.co.z)) for v in obverts])
- faces.extend([[v + numface * lenverts for v in p.vertices] for p in obfaces])
- numface += 1
-
- # Update the mesh
- # Create mesh data
- mymesh = bpy.data.meshes.new("CT_Profil")
- # Generate mesh data
- mymesh.from_pydata(verts, edges, faces)
- # Calculate the edges
- mymesh.update(calc_edges=True)
- # Update data
- obj.data = mymesh
- # Make the object active to remove doubles
- context.view_layer.objects.active = obj
+ """
+ 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 = Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z')
+ for v in obverts:
+ v.co = v.co @ rotmat
+
+ verts.extend([((v.co.x - startx, v.co.y - starty, v.co.z)) for v in obverts])
+ faces.extend([[v + numface * lenverts for v in p.vertices] for p in obfaces])
+ numface += 1
+
+ # Update the mesh
+ # Create mesh data
+ mymesh = bpy.data.meshes.new("CT_Profil")
+ # Generate mesh data
+ mymesh.from_pydata(verts, edges, faces)
+ # Calculate the edges
+ mymesh.update(calc_edges=True)
+ # Update data
+ obj.data = mymesh
+ # Make the object active to remove doubles
+ context.view_layer.objects.active = obj
def boolean_operation(bool_type="DIFFERENCE"):
- ActiveObj = bpy.context.active_object
- sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1
+ ActiveObj = bpy.context.active_object
+ sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1
- # bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
- bool_name = "CT_" + bpy.context.selected_objects[sel_index].name
- BoolMod = ActiveObj.modifiers.new(bool_name, "BOOLEAN")
- BoolMod.object = bpy.context.selected_objects[sel_index]
- BoolMod.operation = bool_type
- bpy.context.selected_objects[sel_index].display_type = 'WIRE'
- while ActiveObj.modifiers.find(bool_name) > 0:
- bpy.ops.object.modifier_move_up(modifier=bool_name)
+ # bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
+ bool_name = "CT_" + bpy.context.selected_objects[sel_index].name
+ BoolMod = ActiveObj.modifiers.new(bool_name, "BOOLEAN")
+ BoolMod.object = bpy.context.selected_objects[sel_index]
+ BoolMod.operation = bool_type
+ bpy.context.selected_objects[sel_index].display_type = 'WIRE'
+ while ActiveObj.modifiers.find(bool_name) > 0:
+ bpy.ops.object.modifier_move_up(modifier=bool_name)
def Rebool(context, self):
- target_obj = context.active_object
+ target_obj = context.active_object
- Brush = context.selected_objects[1]
- Brush.display_type = "WIRE"
+ Brush = context.selected_objects[1]
+ Brush.display_type = "WIRE"
- #Deselect all
- bpy.ops.object.select_all(action='TOGGLE')
+ #Deselect all
+ bpy.ops.object.select_all(action='TOGGLE')
- target_obj.display_type = "SOLID"
- target_obj.select_set(True)
- bpy.ops.object.duplicate()
+ target_obj.display_type = "SOLID"
+ target_obj.select_set(True)
+ bpy.ops.object.duplicate()
- rebool_obj = context.active_object
+ rebool_obj = context.active_object
- m = rebool_obj.modifiers.new("CT_INTERSECT", "BOOLEAN")
- m.operation = "INTERSECT"
- m.object = Brush
+ m = rebool_obj.modifiers.new("CT_INTERSECT", "BOOLEAN")
+ m.operation = "INTERSECT"
+ m.object = Brush
- m = target_obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN")
- m.operation = "DIFFERENCE"
- m.object = Brush
+ m = target_obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN")
+ m.operation = "DIFFERENCE"
+ m.object = Brush
- for mb in target_obj.modifiers:
- if mb.type == 'BEVEL':
- mb.show_viewport = False
+ for mb in target_obj.modifiers:
+ if mb.type == 'BEVEL':
+ mb.show_viewport = False
- if self.ObjectBrush or self.ProfileBrush:
- rebool_obj.show_in_front = False
- try:
- bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
- except:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.report({'ERROR'}, str(exc_value))
+ if self.ObjectBrush or self.ProfileBrush:
+ rebool_obj.show_in_front = False
+ try:
+ bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
+ except:
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ self.report({'ERROR'}, str(exc_value))
- if self.dont_apply_boolean is False:
- try:
- bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_INTERSECT")
- except:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.report({'ERROR'}, str(exc_value))
+ if self.dont_apply_boolean is False:
+ try:
+ bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_INTERSECT")
+ except:
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ self.report({'ERROR'}, str(exc_value))
- bpy.ops.object.select_all(action='TOGGLE')
+ bpy.ops.object.select_all(action='TOGGLE')
- for mb in target_obj.modifiers:
- if mb.type == 'BEVEL':
- mb.show_viewport = True
+ for mb in target_obj.modifiers:
+ if mb.type == 'BEVEL':
+ mb.show_viewport = True
- context.view_layer.objects.active = target_obj
- target_obj.select_set(True)
- if self.dont_apply_boolean is False:
- try:
- bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_DIFFERENCE")
- except:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.report({'ERROR'}, str(exc_value))
+ context.view_layer.objects.active = target_obj
+ target_obj.select_set(True)
+ if self.dont_apply_boolean is False:
+ try:
+ bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_DIFFERENCE")
+ except:
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ self.report({'ERROR'}, str(exc_value))
- bpy.ops.object.select_all(action='TOGGLE')
+ bpy.ops.object.select_all(action='TOGGLE')
- rebool_obj.select_set(True)
+ rebool_obj.select_set(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])
- me.validate(verbose=True, clean_customdata=True)
- # Update mesh with new data
- me.update()
-
- if "CT_Profil" not in bpy.data.objects:
- ob = bpy.data.objects.new("CT_Profil", bpy.data.meshes[self.Profils[self.nProfil][0]])
- ob.location = Vector((0.0, 0.0, 0.0))
-
- # Link object to scene and make active
- bpy.context.collection.objects.link(ob)
- bpy.context.view_layer.update()
- bpy.context.view_layer.objects.active = ob
- ob.select_set(True)
- ob.location = Vector((10000.0, 0.0, 0.0))
- ob.display_type = "WIRE"
-
- self.SolidifyPossible = True
- else:
- bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]]
+ 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])
+ me.validate(verbose=True, clean_customdata=True)
+ # Update mesh with new data
+ me.update()
+
+ if "CT_Profil" not in bpy.data.objects:
+ ob = bpy.data.objects.new("CT_Profil", bpy.data.meshes[self.Profils[self.nProfil][0]])
+ ob.location = Vector((0.0, 0.0, 0.0))
+
+ # Link object to scene and make active
+ bpy.context.collection.objects.link(ob)
+ bpy.context.view_layer.update()
+ bpy.context.view_layer.objects.active = ob
+ ob.select_set(True)
+ ob.location = Vector((10000.0, 0.0, 0.0))
+ ob.display_type = "WIRE"
+
+ self.SolidifyPossible = True
+ else:
+ bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]]
def Selection_Save_Restore(self):
- if "CT_Profil" in bpy.data.objects:
- Selection_Save(self)
- bpy.ops.object.select_all(action='DESELECT')
- bpy.data.objects["CT_Profil"].select_set(True)
- bpy.context.view_layer.objects.active = bpy.data.objects["CT_Profil"]
- if bpy.data.objects["CT_Profil"] in self.all_sel_obj_list:
- self.all_sel_obj_list.remove(bpy.data.objects["CT_Profil"])
- bpy.ops.object.delete(use_global=False)
- 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_set(True)
+ bpy.context.view_layer.objects.active = bpy.data.objects["CT_Profil"]
+ if bpy.data.objects["CT_Profil"] in self.all_sel_obj_list:
+ self.all_sel_obj_list.remove(bpy.data.objects["CT_Profil"])
+ bpy.ops.object.delete(use_global=False)
+ Selection_Restore(self)
def Selection_Save(self):
- obj_name = getattr(bpy.context.active_object, "name", None)
- self.all_sel_obj_list = bpy.context.selected_objects.copy()
- self.save_active_obj = obj_name
+ obj_name = getattr(bpy.context.active_object, "name", None)
+ self.all_sel_obj_list = bpy.context.selected_objects.copy()
+ self.save_active_obj = obj_name
def Selection_Restore(self):
- for o in self.all_sel_obj_list:
- o.select_set(True)
- if self.save_active_obj:
- bpy.context.view_layer.objects.active = bpy.data.objects.get(self.save_active_obj, None)
+ for o in self.all_sel_obj_list:
+ o.select_set(True)
+ if self.save_active_obj:
+ bpy.context.view_layer.objects.active = bpy.data.objects.get(self.save_active_obj, None)
def Snap_Cursor(self, context, event, mouse_pos):
- """ Find the closest position on the overlay grid and snap the mouse on it """
- # Get the context arguments
- region = context.region
- rv3d = context.region_data
-
- # Get the VIEW3D area
- for i, a in enumerate(context.screen.areas):
- if a.type == 'VIEW_3D':
- space = context.screen.areas[i].spaces.active
-
- # Get the grid overlay for the VIEW_3D
- grid_scale = space.overlay.grid_scale
- grid_subdivisions = space.overlay.grid_subdivisions
-
- # Use the grid scale and subdivision to get the increment
- increment = (grid_scale / grid_subdivisions)
- half_increment = increment / 2
-
- # Convert the 2d location of the mouse in 3d
- for index, loc in enumerate(reversed(mouse_pos)):
- mouse_loc_3d = region_2d_to_location_3d(region, rv3d, loc, (0, 0, 0))
-
- # Get the remainder from the mouse location and the ratio
- # Test if the remainder > to the half of the increment
- for i in range(3):
- modulo = mouse_loc_3d[i] % increment
- if modulo < half_increment:
- modulo = - modulo
- else:
- modulo = increment - modulo
-
- # Add the remainder to get the closest location on the grid
- mouse_loc_3d[i] = mouse_loc_3d[i] + modulo
-
- # Get the snapped 2d location
- snap_loc_2d = location_3d_to_region_2d(region, rv3d, mouse_loc_3d)
-
- # Replace the last mouse location by the snapped location
- if len(self.mouse_path) > 0:
- self.mouse_path[len(self.mouse_path) - (index + 1) ] = tuple(snap_loc_2d)
+ """ Find the closest position on the overlay grid and snap the mouse on it """
+ # Get the context arguments
+ region = context.region
+ rv3d = context.region_data
+
+ # Get the VIEW3D area
+ for i, a in enumerate(context.screen.areas):
+ if a.type == 'VIEW_3D':
+ space = context.screen.areas[i].spaces.active
+
+ # Get the grid overlay for the VIEW_3D
+ grid_scale = space.overlay.grid_scale
+ grid_subdivisions = space.overlay.grid_subdivisions
+
+ # Use the grid scale and subdivision to get the increment
+ increment = (grid_scale / grid_subdivisions)
+ half_increment = increment / 2
+
+ # Convert the 2d location of the mouse in 3d
+ for index, loc in enumerate(reversed(mouse_pos)):
+ mouse_loc_3d = region_2d_to_location_3d(region, rv3d, loc, (0, 0, 0))
+
+ # Get the remainder from the mouse location and the ratio
+ # Test if the remainder > to the half of the increment
+ for i in range(3):
+ modulo = mouse_loc_3d[i] % increment
+ if modulo < half_increment:
+ modulo = - modulo
+ else:
+ modulo = increment - modulo
+
+ # Add the remainder to get the closest location on the grid
+ mouse_loc_3d[i] = mouse_loc_3d[i] + modulo
+
+ # Get the snapped 2d location
+ snap_loc_2d = location_3d_to_region_2d(region, rv3d, mouse_loc_3d)
+
+ # Replace the last mouse location by the snapped location
+ if len(self.mouse_path) > 0:
+ self.mouse_path[len(self.mouse_path) - (index + 1) ] = tuple(snap_loc_2d)
def mini_grid(self, context, color):
- """ Draw a snap mini grid around the cursor based on the overlay grid"""
- # Get the context arguments
- region = context.region
- rv3d = context.region_data
-
- # Get the VIEW3D area
- for i, a in enumerate(context.screen.areas):
- if a.type == 'VIEW_3D':
- space = context.screen.areas[i].spaces.active
- screen_height = context.screen.areas[i].height
- screen_width = context.screen.areas[i].width
-
- #Draw the snap grid, only in ortho view
- if not space.region_3d.is_perspective :
- grid_scale = space.overlay.grid_scale
- grid_subdivisions = space.overlay.grid_subdivisions
- increment = (grid_scale / grid_subdivisions)
-
- # Get the 3d location of the mouse forced to a snap value in the operator
- mouse_coord = self.mouse_path[len(self.mouse_path) - 1]
-
- snap_loc = region_2d_to_location_3d(region, rv3d, mouse_coord, (0, 0, 0))
-
- # Add the increment to get the closest location on the grid
- snap_loc[0] += increment
- snap_loc[1] += increment
-
- # Get the 2d location of the snap location
- snap_loc = location_3d_to_region_2d(region, rv3d, snap_loc)
- origin = location_3d_to_region_2d(region, rv3d, (0,0,0))
-
- # Get the increment value
- snap_value = snap_loc[0] - mouse_coord[0]
-
- grid_coords = []
-
- # Draw lines on X and Z axis from the cursor through the screen
- grid_coords = [
- (0, mouse_coord[1]), (screen_width, mouse_coord[1]),
- (mouse_coord[0], 0), (mouse_coord[0], screen_height)
- ]
-
- # Draw a mlini grid around the cursor to show the snap options
- grid_coords += [
- (mouse_coord[0] + snap_value, mouse_coord[1] + 25 + snap_value),
- (mouse_coord[0] + snap_value, mouse_coord[1] - 25 - snap_value),
- (mouse_coord[0] + 25 + snap_value, mouse_coord[1] + snap_value),
- (mouse_coord[0] - 25 - snap_value, mouse_coord[1] + snap_value),
- (mouse_coord[0] - snap_value, mouse_coord[1] + 25 + snap_value),
- (mouse_coord[0] - snap_value, mouse_coord[1] - 25 - snap_value),
- (mouse_coord[0] + 25 + snap_value, mouse_coord[1] - snap_value),
- (mouse_coord[0] - 25 - snap_value, mouse_coord[1] - snap_value),
- ]
- draw_shader(self, color, 0.3, 'LINES', grid_coords, size=2)
+ """ Draw a snap mini grid around the cursor based on the overlay grid"""
+ # Get the context arguments
+ region = context.region
+ rv3d = context.region_data
+
+ # Get the VIEW3D area
+ for i, a in enumerate(context.screen.areas):
+ if a.type == 'VIEW_3D':
+ space = context.screen.areas[i].spaces.active
+ screen_height = context.screen.areas[i].height
+ screen_width = context.screen.areas[i].width
+
+ #Draw the snap grid, only in ortho view
+ if not space.region_3d.is_perspective :
+ grid_scale = space.overlay.grid_scale
+ grid_subdivisions = space.overlay.grid_subdivisions
+ increment = (grid_scale / grid_subdivisions)
+
+ # Get the 3d location of the mouse forced to a snap value in the operator
+ mouse_coord = self.mouse_path[len(self.mouse_path) - 1]
+
+ snap_loc = region_2d_to_location_3d(region, rv3d, mouse_coord, (0, 0, 0))
+
+ # Add the increment to get the closest location on the grid
+ snap_loc[0] += increment
+ snap_loc[1] += increment
+
+ # Get the 2d location of the snap location
+ snap_loc = location_3d_to_region_2d(region, rv3d, snap_loc)
+ origin = location_3d_to_region_2d(region, rv3d, (0,0,0))
+
+ # Get the increment value
+ snap_value = snap_loc[0] - mouse_coord[0]
+
+ grid_coords = []
+
+ # Draw lines on X and Z axis from the cursor through the screen
+ grid_coords = [
+ (0, mouse_coord[1]), (screen_width, mouse_coord[1]),
+ (mouse_coord[0], 0), (mouse_coord[0], screen_height)
+ ]
+
+ # Draw a mlini grid around the cursor to show the snap options
+ grid_coords += [
+ (mouse_coord[0] + snap_value, mouse_coord[1] + 25 + snap_value),
+ (mouse_coord[0] + snap_value, mouse_coord[1] - 25 - snap_value),
+ (mouse_coord[0] + 25 + snap_value, mouse_coord[1] + snap_value),
+ (mouse_coord[0] - 25 - snap_value, mouse_coord[1] + snap_value),
+ (mouse_coord[0] - snap_value, mouse_coord[1] + 25 + snap_value),
+ (mouse_coord[0] - snap_value, mouse_coord[1] - 25 - snap_value),
+ (mouse_coord[0] + 25 + snap_value, mouse_coord[1] - snap_value),
+ (mouse_coord[0] - 25 - snap_value, mouse_coord[1] - snap_value),
+ ]
+ draw_shader(self, color, 0.3, 'LINES', grid_coords, size=2)
def draw_shader(self, color, alpha, type, coords, size=1, indices=None):
- """ Create a batch for a draw type """
- bgl.glEnable(bgl.GL_BLEND)
- bgl.glEnable(bgl.GL_LINE_SMOOTH)
- if type =='POINTS':
- bgl.glPointSize(size)
- else:
- bgl.glLineWidth(size)
- try:
- if len(coords[0])>2:
- shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
- else:
- shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
- batch = batch_for_shader(shader, type, {"pos": coords}, indices=indices)
- shader.bind()
- shader.uniform_float("color", (color[0], color[1], color[2], alpha))
- batch.draw(shader)
- bgl.glLineWidth(1)
- bgl.glPointSize(1)
- bgl.glDisable(bgl.GL_LINE_SMOOTH)
- bgl.glDisable(bgl.GL_BLEND)
- except:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.report({'ERROR'}, str(exc_value))
+ """ Create a batch for a draw type """
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glEnable(bgl.GL_LINE_SMOOTH)
+ if type =='POINTS':
+ bgl.glPointSize(size)
+ else:
+ bgl.glLineWidth(size)
+ try:
+ if len(coords[0])>2:
+ shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
+ else:
+ shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
+ batch = batch_for_shader(shader, type, {"pos": coords}, indices=indices)
+ shader.bind()
+ shader.uniform_float("color", (color[0], color[1], color[2], alpha))
+ batch.draw(shader)
+ bgl.glLineWidth(1)
+ bgl.glPointSize(1)
+ bgl.glDisable(bgl.GL_LINE_SMOOTH)
+ bgl.glDisable(bgl.GL_BLEND)
+ except:
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ self.report({'ERROR'}, str(exc_value))