Update object_carver to 2.8 thanks @clarkx
This commit is contained in:
parent
89568c1a42
commit
175202efb2
Notes:
blender-bot
2023-02-14 19:17:40 +01:00
Referenced by issue #63476, Update Carver addon 2.8
3469
mesh_carver.py
3469
mesh_carver.py
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,308 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
bl_info = {
|
||||
"name": "Carver",
|
||||
"author": "Pixivore, Cedric LEPILLER, Ted Milker, Clarkx",
|
||||
"description": "Multiple tools to carve or to create objects",
|
||||
"version": (1, 2, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "3D View",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"support": 'COMMUNITY',
|
||||
"category": "Object"
|
||||
}
|
||||
|
||||
import bpy
|
||||
import imp
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
StringProperty,
|
||||
IntProperty
|
||||
)
|
||||
from bpy.types import (AddonPreferences, WorkSpaceTool)
|
||||
from bpy.utils.toolsystem import ToolDef
|
||||
|
||||
from . import carver_utils
|
||||
imp.reload(carver_utils)
|
||||
from . import carver_profils
|
||||
imp.reload(carver_profils)
|
||||
from . import carver_draw
|
||||
imp.reload(carver_draw)
|
||||
from . import carver_operator
|
||||
imp.reload(carver_operator)
|
||||
|
||||
# TODO : Create an icon for Carver MT
|
||||
# Add an icon in the toolbar
|
||||
# class CarverTool(WorkSpaceTool):
|
||||
# bl_space_type='VIEW_3D'
|
||||
# bl_context_mode='OBJECT'
|
||||
# bl_idname = "carver.operator"
|
||||
# bl_label = "Carver"
|
||||
# bl_description = (
|
||||
# "Multiple tools to carve \n"
|
||||
# "or to create objects"
|
||||
# )
|
||||
#
|
||||
# #Icons : \blender-2.80\2.80\datafiles\icons
|
||||
# #Todo: Create a new icon for Carver
|
||||
# bl_icon = "ops.mesh.knife_tool"
|
||||
# bl_widget = None
|
||||
# bl_keymap = (
|
||||
# ("carver.operator", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
|
||||
# )
|
||||
#
|
||||
# def draw_settings(context, layout, tool):
|
||||
# layout.prop(tool.operator_properties, "carver")
|
||||
|
||||
|
||||
class CarverPreferences(AddonPreferences):
|
||||
bl_idname = __name__
|
||||
|
||||
|
||||
Enable_Tab_01: BoolProperty(
|
||||
name="Info",
|
||||
description="Some general information and settings about the add-on",
|
||||
default=False
|
||||
)
|
||||
Enable_Tab_02: BoolProperty(
|
||||
name="Hotkeys",
|
||||
description="List of the shortcuts used during carving",
|
||||
default=False
|
||||
)
|
||||
Key_Create: StringProperty(
|
||||
name="Object creation",
|
||||
description="Object creation",
|
||||
maxlen=1,
|
||||
default="C"
|
||||
)
|
||||
Key_Update: StringProperty(
|
||||
name="Auto Bevel Update",
|
||||
description="Auto Bevel Update",
|
||||
maxlen=1,
|
||||
default="A",
|
||||
)
|
||||
Key_Bool: StringProperty(
|
||||
name="Boolean type",
|
||||
description="Boolean operation type",
|
||||
maxlen=1,
|
||||
default="T",
|
||||
)
|
||||
Key_Brush: StringProperty(
|
||||
name="Brush Mode",
|
||||
description="Brush Mode",
|
||||
maxlen=1,
|
||||
default="B",
|
||||
)
|
||||
Key_Help: StringProperty(
|
||||
name="Help display",
|
||||
description="Help display",
|
||||
maxlen=1,
|
||||
default="H",
|
||||
)
|
||||
Key_Instant: StringProperty(
|
||||
name="Instantiate",
|
||||
description="Instantiate object",
|
||||
maxlen=1,
|
||||
default="I",
|
||||
)
|
||||
Key_Close: StringProperty(
|
||||
name="Close polygonal shape",
|
||||
description="Close polygonal shape",
|
||||
maxlen=1,
|
||||
default="X",
|
||||
)
|
||||
Key_Apply: StringProperty(
|
||||
name="Apply operation",
|
||||
description="Apply operation",
|
||||
maxlen=1,
|
||||
default="Q",
|
||||
)
|
||||
Key_Scale: StringProperty(
|
||||
name="Scale object",
|
||||
description="Scale object",
|
||||
maxlen=1,
|
||||
default="S",
|
||||
)
|
||||
Key_Gapy: StringProperty(
|
||||
name="Gap rows",
|
||||
description="Scale gap between columns",
|
||||
maxlen=1,
|
||||
default="J",
|
||||
)
|
||||
Key_Gapx: StringProperty(
|
||||
name="Gap columns",
|
||||
description="Scale gap between columns",
|
||||
maxlen=1,
|
||||
default="U",
|
||||
)
|
||||
Key_Depth: StringProperty(
|
||||
name="Depth",
|
||||
description="Cursor depth or solidify pattern",
|
||||
maxlen=1,
|
||||
default="D",
|
||||
)
|
||||
Key_BrushDepth: StringProperty(
|
||||
name="Brush Depth",
|
||||
description="Brush depth",
|
||||
maxlen=1,
|
||||
default="C",
|
||||
)
|
||||
Key_Subadd: StringProperty(
|
||||
name="Add subdivision",
|
||||
description="Add subdivision",
|
||||
maxlen=1,
|
||||
default="X",
|
||||
)
|
||||
Key_Subrem: StringProperty(
|
||||
name="Remove subdivision",
|
||||
description="Remove subdivision",
|
||||
maxlen=1,
|
||||
default="W",
|
||||
)
|
||||
Key_Randrot: StringProperty(
|
||||
name="Random rotation",
|
||||
description="Random rotation",
|
||||
maxlen=1,
|
||||
default="R",
|
||||
)
|
||||
ProfilePrefix: StringProperty(
|
||||
name="Profile prefix",
|
||||
description="Prefix to look for profiles with",
|
||||
default="Carver_Profile-",
|
||||
)
|
||||
LineWidth: IntProperty(
|
||||
name="Line Width",
|
||||
description="Thickness of the drawing lines",
|
||||
default=1,
|
||||
)
|
||||
Key_Snap: StringProperty(
|
||||
name="Grid Snap",
|
||||
description="Grid Snap",
|
||||
maxlen=1,
|
||||
default="G",
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
scene = context.scene
|
||||
layout = self.layout
|
||||
|
||||
icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN"
|
||||
box = layout.box()
|
||||
|
||||
box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1)
|
||||
if self.Enable_Tab_01:
|
||||
box.label(text="Carver Operator:", icon="LAYER_ACTIVE")
|
||||
box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve",
|
||||
icon="LAYER_USED")
|
||||
box.label(text="To finish carving press [ESC] or [RIGHT CLICK]",
|
||||
icon="LAYER_USED")
|
||||
box.prop(self, "ProfilePrefix", text="Profile prefix")
|
||||
row = box.row(align=True)
|
||||
row.label(text="Line width:")
|
||||
row.prop(self, "LineWidth", text="")
|
||||
|
||||
icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN"
|
||||
box = layout.box()
|
||||
box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2)
|
||||
if self.Enable_Tab_02:
|
||||
split = box.split(align=True)
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Object Creation:")
|
||||
col.prop(self, "Key_Create", text="")
|
||||
col.label(text="Auto bevel update:")
|
||||
col.prop(self, "Key_Update", text="")
|
||||
col.label(text="Boolean operation type:")
|
||||
col.prop(self, "Key_Bool", text="")
|
||||
col.label(text="Brush Depth:")
|
||||
col.prop(self, "Key_BrushDepth", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Brush Mode:")
|
||||
col.prop(self, "Key_Brush", text="")
|
||||
col.label(text="Help display:")
|
||||
col.prop(self, "Key_Help", text="")
|
||||
col.label(text="Instantiate object:")
|
||||
col.prop(self, "Key_Instant", text="")
|
||||
col.label(text="Random rotation:")
|
||||
col.prop(self, "Key_Randrot", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Close polygonal shape:")
|
||||
col.prop(self, "Key_Close", text="")
|
||||
col.label(text="Apply operation:")
|
||||
col.prop(self, "Key_Apply", text="")
|
||||
col.label(text="Scale object:")
|
||||
col.prop(self, "Key_Scale", text="")
|
||||
col.label(text="Subdiv add:")
|
||||
col.prop(self, "Key_Subadd", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Gap rows:")
|
||||
col.prop(self, "Key_Gapy", text="")
|
||||
col.label(text="Gap columns:")
|
||||
col.prop(self, "Key_Gapx", text="")
|
||||
col.label(text="Depth / Solidify:")
|
||||
col.prop(self, "Key_Depth", text="")
|
||||
col.label(text="Subdiv Remove:")
|
||||
col.prop(self, "Key_Subrem", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Grid Snap:")
|
||||
col.prop(self, "Key_Snap", text="")
|
||||
|
||||
addon_keymaps = []
|
||||
|
||||
def register():
|
||||
print("Registered Carver")
|
||||
|
||||
bpy.utils.register_class(CarverPreferences)
|
||||
# Todo : Add an icon in the toolbat
|
||||
# bpy.utils.register_tool(CarverTool, separator=True, group=True)
|
||||
carver_operator.register()
|
||||
|
||||
# add keymap entry
|
||||
kcfg = bpy.context.window_manager.keyconfigs.addon
|
||||
if kcfg:
|
||||
km = kcfg.keymaps.new(name='3D View', space_type='VIEW_3D')
|
||||
kmi = km.keymap_items.new("carver.operator", 'X', 'PRESS', shift=True, ctrl=True)
|
||||
addon_keymaps.append((km, kmi))
|
||||
|
||||
def unregister():
|
||||
# Todo : Add an icon in the toolbat
|
||||
# bpy.utils.unregister_tool(CarverTool)
|
||||
carver_operator.unregister()
|
||||
bpy.utils.unregister_class(CarverPreferences)
|
||||
|
||||
print("Unregistered Carver")
|
||||
|
||||
# remove keymap entry
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -0,0 +1,494 @@
|
|||
import bpy
|
||||
import bgl
|
||||
import blf
|
||||
import bpy_extras
|
||||
import numpy as np
|
||||
import gpu
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
from math import(
|
||||
cos,
|
||||
sin,
|
||||
ceil,
|
||||
floor,
|
||||
)
|
||||
|
||||
from bpy_extras.view3d_utils import (
|
||||
region_2d_to_location_3d,
|
||||
location_3d_to_region_2d,
|
||||
)
|
||||
|
||||
from .carver_utils import (
|
||||
draw_circle,
|
||||
draw_shader,
|
||||
objDiagonal,
|
||||
mini_grid,
|
||||
)
|
||||
|
||||
from mathutils import (
|
||||
Color,
|
||||
Euler,
|
||||
Vector,
|
||||
Quaternion,
|
||||
)
|
||||
|
||||
def get_text_info(self, context, help_txt):
|
||||
""" Return the dimensions of each part of the text """
|
||||
|
||||
#Extract the longest first option in sublist
|
||||
max_option = max(list(blf.dimensions(0, row[0])[0] for row in help_txt))
|
||||
|
||||
#Extract the longest key in sublist
|
||||
max_key = max(list(blf.dimensions(0, row[1])[0] for row in help_txt))
|
||||
|
||||
#Space between option and key with a comma separator (" : ")
|
||||
comma = blf.dimensions(0, "_:_")[0]
|
||||
|
||||
#Get a default height for all the letters
|
||||
line_height = (blf.dimensions(0, "gM")[1] * 1.45)
|
||||
|
||||
#Get the total height of the text
|
||||
bloc_height = 0
|
||||
for row in help_txt:
|
||||
bloc_height += line_height
|
||||
|
||||
return(help_txt, bloc_height, max_option, max_key, comma)
|
||||
|
||||
def draw_string(self, color1, color2, left, bottom, text, max_option, divide = 1):
|
||||
""" Draw the text like 'option : key' or just 'option' """
|
||||
|
||||
font_id = 0
|
||||
blf.enable(font_id,blf.SHADOW)
|
||||
blf.shadow(font_id, 0, 0.0, 0.0, 0.0, 1.0)
|
||||
blf.shadow_offset(font_id,2,-2)
|
||||
line_height = (blf.dimensions(font_id, "gM")[1] * 1.45)
|
||||
y_offset = 5
|
||||
|
||||
# Test if the text is a list formated like : ('option', 'key')
|
||||
if isinstance(text,list):
|
||||
for string in text:
|
||||
blf.position(font_id, (left), (bottom + y_offset), 0)
|
||||
blf.color(font_id, *color1)
|
||||
blf.draw(font_id, string[0])
|
||||
blf.position(font_id, (left + max_option), (bottom + y_offset), 0)
|
||||
blf.draw(font_id, " : ")
|
||||
blf.color(font_id, *color2)
|
||||
blf.position(font_id, (left + max_option + 15), (bottom + y_offset), 0)
|
||||
blf.draw(font_id, string[1])
|
||||
y_offset += line_height
|
||||
else:
|
||||
# The text is formated like : ('option')
|
||||
blf.position(font_id, left, (bottom + y_offset), 0)
|
||||
blf.color(font_id, *color1)
|
||||
blf.draw(font_id, text)
|
||||
y_offset += line_height
|
||||
|
||||
blf.disable(font_id,blf.SHADOW)
|
||||
|
||||
# Opengl draw on screen
|
||||
def draw_callback_px(self, context):
|
||||
font_id = 0
|
||||
region = context.region
|
||||
UIColor = (0.992, 0.5518, 0.0, 1.0)
|
||||
|
||||
# Cut Type
|
||||
RECTANGLE = 0
|
||||
LINE = 1
|
||||
CIRCLE = 2
|
||||
self.carver_prefs = context.preferences.addons[__package__].preferences
|
||||
|
||||
# Color
|
||||
color1 = (1.0, 1.0, 1.0, 1.0)
|
||||
color2 = UIColor
|
||||
|
||||
#The mouse is outside the active region
|
||||
if not self.in_view_3d:
|
||||
color1 = color2 = (1.0, 0.2, 0.1, 1.0)
|
||||
|
||||
# Primitives type
|
||||
PrimitiveType = "Rectangle"
|
||||
if self.CutType == CIRCLE:
|
||||
PrimitiveType = "Circle"
|
||||
if self.CutType == LINE:
|
||||
PrimitiveType = "Line"
|
||||
|
||||
# Width screen
|
||||
overlap = context.preferences.system.use_region_overlap
|
||||
|
||||
t_panel_width = 0
|
||||
if overlap:
|
||||
for region in context.area.regions:
|
||||
if region.type == 'TOOLS':
|
||||
t_panel_width = region.width
|
||||
|
||||
# Initial position
|
||||
region_width = int(region.width / 2.0)
|
||||
y_txt = 10
|
||||
|
||||
|
||||
# Draw the center command from bottom to top
|
||||
|
||||
# Get the size of the text
|
||||
text_size = 18 if region.width >= 850 else 12
|
||||
blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale, 0)), 72)
|
||||
|
||||
# Help Display
|
||||
if (self.ObjectMode is False) and (self.ProfileMode is False):
|
||||
|
||||
# Depth Cursor
|
||||
TypeStr = "Cursor Depth [" + self.carver_prefs.Key_Depth + "]"
|
||||
BoolStr = "(ON)" if self.snapCursor else "(OFF)"
|
||||
help_txt = [[TypeStr, BoolStr]]
|
||||
|
||||
# Close poygonal shape
|
||||
if self.CreateMode and self.CutType == LINE:
|
||||
TypeStr = "Close [" + self.carver_prefs.Key_Close + "]"
|
||||
BoolStr = "(ON)" if self.Closed else "(OFF)"
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
if self.CreateMode is False:
|
||||
# Apply Booleans
|
||||
TypeStr = "Apply Operations [" + self.carver_prefs.Key_Apply + "]"
|
||||
BoolStr = "(OFF)" if self.dont_apply_boolean else "(ON)"
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
#Auto update for bevel
|
||||
TypeStr = "Bevel Update [" + self.carver_prefs.Key_Update + "]"
|
||||
BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)"
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
# Circle subdivisions
|
||||
if self.CutType == CIRCLE:
|
||||
TypeStr = "Subdivisions [" + self.carver_prefs.Key_Subrem + "][" + self.carver_prefs.Key_Subadd + "]"
|
||||
BoolStr = str((int(360 / self.stepAngle[self.step])))
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
if self.CreateMode:
|
||||
help_txt += [["Type [Space]", PrimitiveType]]
|
||||
else:
|
||||
help_txt += [["Cut Type [Space]", PrimitiveType]]
|
||||
|
||||
else:
|
||||
# Instantiate
|
||||
TypeStr = "Instantiate [" + self.carver_prefs.Key_Instant + "]"
|
||||
BoolStr = "(ON)" if self.Instantiate else "(OFF)"
|
||||
help_txt = [[TypeStr, BoolStr]]
|
||||
|
||||
# Random rotation
|
||||
if self.alt:
|
||||
TypeStr = "Random Rotation [" + self.carver_prefs.Key_Randrot + "]"
|
||||
BoolStr = "(ON)" if self.RandomRotation else "(OFF)"
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
# Thickness
|
||||
if self.BrushSolidify:
|
||||
TypeStr = "Thickness [" + self.carver_prefs.Key_Depth + "]"
|
||||
if self.ProfileMode:
|
||||
BoolStr = str(round(self.ProfileBrush.modifiers["CT_SOLIDIFY"].thickness, 2))
|
||||
if self.ObjectMode:
|
||||
BoolStr = str(round(self.ObjectBrush.modifiers["CT_SOLIDIFY"].thickness, 2))
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
# Brush depth
|
||||
if (self.ObjectMode):
|
||||
TypeStr = "Carve Depth [" + self.carver_prefs.Key_Depth + "]"
|
||||
BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2))
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
TypeStr = "Brush Depth [" + self.carver_prefs.Key_BrushDepth + "]"
|
||||
BoolStr = str(round(self.BrushDepthOffset, 2))
|
||||
help_txt += [[TypeStr, BoolStr]]
|
||||
|
||||
help_txt, bloc_height, max_option, max_key, comma = get_text_info(self, context, help_txt)
|
||||
xCmd = region_width - (max_option + max_key + comma) / 2
|
||||
draw_string(self, color1, color2, xCmd, y_txt, help_txt, max_option, divide = 2)
|
||||
|
||||
|
||||
# Separator (Line)
|
||||
LineWidth = (max_option + max_key + comma) / 2
|
||||
if region.width >= 850:
|
||||
LineWidth = 140
|
||||
|
||||
LineWidth = (max_option + max_key + comma)
|
||||
coords = [(int(region_width - LineWidth/2), y_txt + bloc_height + 8), \
|
||||
(int(region_width + LineWidth/2), y_txt + bloc_height + 8)]
|
||||
draw_shader(self, UIColor, 1, 'LINES', coords, self.carver_prefs.LineWidth)
|
||||
|
||||
# Command Display
|
||||
if self.CreateMode and ((self.ObjectMode is False) and (self.ProfileMode is False)):
|
||||
BooleanMode = "Create"
|
||||
else:
|
||||
if self.ObjectMode or self.ProfileMode:
|
||||
BooleanType = "Difference) [T]" if self.BoolOps == self.difference else "Union) [T]"
|
||||
BooleanMode = \
|
||||
"Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType
|
||||
else:
|
||||
BooleanMode = \
|
||||
"Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool"
|
||||
|
||||
# Display boolean mode
|
||||
text_size = 40 if region.width >= 850 else 20
|
||||
blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale, 0)), 72)
|
||||
|
||||
draw_string(self, color2, color2, region_width - (blf.dimensions(0, BooleanMode)[0]) / 2, \
|
||||
y_txt + bloc_height + 16, BooleanMode, 0, divide = 2)
|
||||
|
||||
if region.width >= 850:
|
||||
|
||||
if self.AskHelp is False:
|
||||
# "H for Help" text
|
||||
blf.size(0, int(round(13 * bpy.context.preferences.view.ui_scale, 0)), 72)
|
||||
help_txt = "[" + self.carver_prefs.Key_Help + "] for help"
|
||||
txt_width = blf.dimensions(0, help_txt)[0]
|
||||
txt_height = (blf.dimensions(0, "gM")[1] * 1.45)
|
||||
|
||||
# Draw a rectangle and put the text "H for Help"
|
||||
xrect = 40
|
||||
yrect = 40
|
||||
rect_vertices = [(xrect - 5, yrect - 5), (xrect + txt_width + 5, yrect - 5), \
|
||||
(xrect + txt_width + 5, yrect + txt_height + 5), (xrect - 5, yrect + txt_height + 5)]
|
||||
draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', rect_vertices, self.carver_prefs.LineWidth)
|
||||
draw_string(self, color1, color2, xrect, yrect, help_txt, 0)
|
||||
|
||||
else:
|
||||
#Draw the help text
|
||||
xHelp = 30 + t_panel_width
|
||||
yHelp = 10
|
||||
|
||||
if self.ObjectMode or self.ProfileMode:
|
||||
if self.ProfileMode:
|
||||
help_txt = [["Object Mode", self.carver_prefs.Key_Brush]]
|
||||
else:
|
||||
help_txt = [["Cut Mode", self.carver_prefs.Key_Brush]]
|
||||
|
||||
else:
|
||||
help_txt =[
|
||||
["Profil Brush", self.carver_prefs.Key_Brush],\
|
||||
["Move Cursor", "Ctrl + LMB"]
|
||||
]
|
||||
|
||||
if (self.ObjectMode is False) and (self.ProfileMode is False):
|
||||
if self.CreateMode is False:
|
||||
help_txt +=[
|
||||
["Create geometry", self.carver_prefs.Key_Create],\
|
||||
]
|
||||
else:
|
||||
help_txt +=[
|
||||
["Cut", self.carver_prefs.Key_Create],\
|
||||
]
|
||||
if self.CutMode == RECTANGLE:
|
||||
help_txt +=[
|
||||
["Dimension", "MouseMove"],\
|
||||
["Move all", "Alt"],\
|
||||
["Validate", "LMB"],\
|
||||
["Rebool", "Shift"]
|
||||
]
|
||||
|
||||
elif self.CutMode == CIRCLE:
|
||||
help_txt +=[
|
||||
["Rotation and Radius", "MouseMove"],\
|
||||
["Move all", "Alt"],\
|
||||
["Subdivision", self.carver_prefs.Key_Subrem + " " + self.carver_prefs.Key_Subadd],\
|
||||
["Incremental rotation", "Ctrl"],\
|
||||
["Rebool", "Shift"]
|
||||
]
|
||||
|
||||
elif self.CutMode == LINE:
|
||||
help_txt +=[
|
||||
["Dimension", "MouseMove"],\
|
||||
["Move all", "Alt"],\
|
||||
["Validate", "Space"],\
|
||||
["Rebool", "Shift"],\
|
||||
["Snap", "Ctrl"],\
|
||||
["Scale Snap", "WheelMouse"],\
|
||||
]
|
||||
else:
|
||||
# ObjectMode
|
||||
help_txt +=[
|
||||
["Difference", "Space"],\
|
||||
["Rebool", "Shift + Space"],\
|
||||
["Duplicate", "Alt + Space"],\
|
||||
["Scale", self.carver_prefs.Key_Scale],\
|
||||
["Rotation", "LMB + Move"],\
|
||||
["Step Angle", "CTRL + LMB + Move"],\
|
||||
]
|
||||
|
||||
if self.ProfileMode:
|
||||
help_txt +=[["Previous or Next Profile", self.carver_prefs.Key_Subadd + " " + self.carver_prefs.Key_Subrem]]
|
||||
|
||||
help_txt +=[
|
||||
["Create / Delete rows", chr(8597)],\
|
||||
["Create / Delete cols", chr(8596)],\
|
||||
["Gap for rows or columns", self.carver_prefs.Key_Gapy + " " + self.carver_prefs.Key_Gapx]
|
||||
]
|
||||
|
||||
blf.size(0, int(round(15 * bpy.context.preferences.view.ui_scale, 0)), 72)
|
||||
help_txt, bloc_height, max_option, max_key, comma = get_text_info(self, context, help_txt)
|
||||
draw_string(self, color1, color2, xHelp, yHelp, help_txt, max_option)
|
||||
|
||||
if self.ProfileMode:
|
||||
xrect = region.width - t_panel_width - 80
|
||||
yrect = 80
|
||||
coords = [(xrect, yrect), (xrect+60, yrect), (xrect+60, yrect-60), (xrect, yrect-60)]
|
||||
|
||||
# Draw rectangle background in the lower right
|
||||
draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth)
|
||||
|
||||
# Use numpy to get the vertices and indices of the profile object to draw
|
||||
WidthProfil = 50
|
||||
location = Vector((region.width - t_panel_width - WidthProfil, 50, 0))
|
||||
ProfilScale = 20.0
|
||||
coords = []
|
||||
mesh = bpy.data.meshes[self.Profils[self.nProfil][0]]
|
||||
mesh.calc_loop_triangles()
|
||||
vertices = np.empty((len(mesh.vertices), 3), 'f')
|
||||
indices = np.empty((len(mesh.loop_triangles), 3), 'i')
|
||||
mesh.vertices.foreach_get("co", np.reshape(vertices, len(mesh.vertices) * 3))
|
||||
mesh.loop_triangles.foreach_get("vertices", np.reshape(indices, len(mesh.loop_triangles) * 3))
|
||||
|
||||
for idx, vals in enumerate(vertices):
|
||||
coords.append([
|
||||
vals[0] * ProfilScale + location.x,
|
||||
vals[1] * ProfilScale + location.y,
|
||||
vals[2] * ProfilScale + location.z
|
||||
])
|
||||
|
||||
#Draw the silhouette of the mesh
|
||||
draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices)
|
||||
|
||||
|
||||
if self.CutMode:
|
||||
|
||||
if len(self.mouse_path) > 1:
|
||||
x0 = self.mouse_path[0][0]
|
||||
y0 = self.mouse_path[0][1]
|
||||
x1 = self.mouse_path[1][0]
|
||||
y1 = self.mouse_path[1][1]
|
||||
|
||||
# Cut rectangle
|
||||
if self.CutType == RECTANGLE:
|
||||
coords = [
|
||||
(x0 + self.xpos, y0 + self.ypos), (x1 + self.xpos, y0 + self.ypos), \
|
||||
(x1 + self.xpos, y1 + self.ypos), (x0 + self.xpos, y1 + self.ypos)
|
||||
]
|
||||
indices = ((0, 1, 2), (2, 0, 3))
|
||||
|
||||
self.rectangle_coord = coords
|
||||
|
||||
draw_shader(self, UIColor, 1, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth)
|
||||
|
||||
#Draw points
|
||||
draw_shader(self, UIColor, 1, 'POINTS', coords, size=3)
|
||||
|
||||
if self.shift or self.CreateMode:
|
||||
draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices)
|
||||
|
||||
# Draw grid (based on the overlay options) to show the incremental snapping
|
||||
if self.ctrl:
|
||||
mini_grid(self, context, UIColor)
|
||||
|
||||
# Cut Line
|
||||
elif self.CutType == LINE:
|
||||
coords = []
|
||||
indices = []
|
||||
top_grid = False
|
||||
|
||||
for idx, vals in enumerate(self.mouse_path):
|
||||
coords.append([vals[0] + self.xpos, vals[1] + self.ypos])
|
||||
indices.append([idx])
|
||||
|
||||
# Draw lines
|
||||
if self.Closed:
|
||||
draw_shader(self, UIColor, 1.0, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth)
|
||||
else:
|
||||
draw_shader(self, UIColor, 1.0, 'LINE_STRIP', coords, size=self.carver_prefs.LineWidth)
|
||||
|
||||
# Draw points
|
||||
draw_shader(self, UIColor, 1.0, 'POINTS', coords, size=3)
|
||||
|
||||
# Draw polygon
|
||||
if (self.shift) or (self.CreateMode and self.Closed):
|
||||
draw_shader(self, UIColor, 0.5, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth)
|
||||
|
||||
# Draw grid (based on the overlay options) to show the incremental snapping
|
||||
if self.ctrl:
|
||||
mini_grid(self, context, UIColor)
|
||||
|
||||
# Circle Cut
|
||||
elif self.CutType == CIRCLE:
|
||||
# Create a circle using a tri fan
|
||||
tris_coords, indices = draw_circle(self, x0, y0)
|
||||
|
||||
# Remove the vertex in the center to get the outer line of the circle
|
||||
line_coords = tris_coords[1:]
|
||||
draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=self.carver_prefs.LineWidth)
|
||||
|
||||
if self.shift or self.CreateMode:
|
||||
draw_shader(self, UIColor, 0.5, 'TRIS', tris_coords, size=self.carver_prefs.LineWidth, indices=indices)
|
||||
|
||||
if (self.ObjectMode or self.ProfileMode) and len(self.CurrentSelection) > 0:
|
||||
if self.ShowCursor:
|
||||
region = context.region
|
||||
rv3d = context.space_data.region_3d
|
||||
|
||||
if self.ObjectMode:
|
||||
ob = self.ObjectBrush
|
||||
if self.ProfileMode:
|
||||
ob = self.ProfileBrush
|
||||
mat = ob.matrix_world
|
||||
|
||||
# 50% alpha, 2 pixel width line
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
|
||||
bbox = [mat @ Vector(b) for b in ob.bound_box]
|
||||
objBBDiagonal = objDiagonal(self.CurrentSelection[0])
|
||||
|
||||
if self.shift:
|
||||
gl_size = 4
|
||||
UIColor = (0.5, 1.0, 0.0, 1.0)
|
||||
else:
|
||||
gl_size = 2
|
||||
UIColor = (1.0, 0.8, 0.0, 1.0)
|
||||
|
||||
line_coords = []
|
||||
idx = 0
|
||||
CRadius = ((bbox[7] - bbox[0]).length) / 2
|
||||
for i in range(int(len(self.CLR_C) / 3)):
|
||||
vector3d = (self.CLR_C[idx * 3] * CRadius + self.CurLoc.x, \
|
||||
self.CLR_C[idx * 3 + 1] * CRadius + self.CurLoc.y, \
|
||||
self.CLR_C[idx * 3 + 2] * CRadius + self.CurLoc.z)
|
||||
vector2d = bpy_extras.view3d_utils.location_3d_to_region_2d(region, rv3d, vector3d)
|
||||
if vector2d is not None:
|
||||
line_coords.append((vector2d[0], vector2d[1]))
|
||||
idx += 1
|
||||
if len(line_coords) > 0 :
|
||||
draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=gl_size)
|
||||
|
||||
# Object display
|
||||
if self.quat_rot is not None:
|
||||
ob.location = self.CurLoc
|
||||
v = Vector()
|
||||
v.x = v.y = 0.0
|
||||
v.z = self.BrushDepthOffset
|
||||
ob.location += self.quat_rot @ v
|
||||
|
||||
e = Euler()
|
||||
e.x = 0.0
|
||||
e.y = 0.0
|
||||
e.z = self.aRotZ / 25.0
|
||||
|
||||
qe = e.to_quaternion()
|
||||
qRot = self.quat_rot @ qe
|
||||
ob.rotation_mode = 'QUATERNION'
|
||||
ob.rotation_quaternion = qRot
|
||||
ob.rotation_mode = 'XYZ'
|
||||
|
||||
if self.ProfileMode:
|
||||
if self.ProfileBrush is not None:
|
||||
self.ProfileBrush.location = self.CurLoc
|
||||
self.ProfileBrush.rotation_mode = 'QUATERNION'
|
||||
self.ProfileBrush.rotation_quaternion = qRot
|
||||
self.ProfileBrush.rotation_mode = 'XYZ'
|
||||
|
||||
# Opengl defaults
|
||||
bgl.glLineWidth(1)
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,194 @@
|
|||
import bpy
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
PointerProperty,
|
||||
StringProperty,
|
||||
)
|
||||
|
||||
class CarverPrefs(bpy.types.AddonPreferences):
|
||||
bl_idname = __name__
|
||||
|
||||
Enable_Tab_01: BoolProperty(
|
||||
name="Info",
|
||||
description="Some general information and settings about the add-on",
|
||||
default=False
|
||||
)
|
||||
Enable_Tab_02: BoolProperty(
|
||||
name="Hotkeys",
|
||||
description="List of the shortcuts used during carving",
|
||||
default=False
|
||||
)
|
||||
bpy.types.Scene.Key_Create: StringProperty(
|
||||
name="Object creation",
|
||||
description="Object creation",
|
||||
maxlen=1,
|
||||
default="C"
|
||||
)
|
||||
bpy.types.Scene.Key_Update: StringProperty(
|
||||
name="Auto Bevel Update",
|
||||
description="Auto Bevel Update",
|
||||
maxlen=1,
|
||||
default="A",
|
||||
)
|
||||
bpy.types.Scene.Key_Bool: StringProperty(
|
||||
name="Boolean type",
|
||||
description="Boolean operation type",
|
||||
maxlen=1,
|
||||
default="T",
|
||||
)
|
||||
bpy.types.Scene.Key_Brush: StringProperty(
|
||||
name="Brush Mode",
|
||||
description="Brush Mode",
|
||||
maxlen=1,
|
||||
default="B",
|
||||
)
|
||||
bpy.types.Scene.Key_Help: StringProperty(
|
||||
name="Help display",
|
||||
description="Help display",
|
||||
maxlen=1,
|
||||
default="H",
|
||||
)
|
||||
bpy.types.Scene.Key_Instant: StringProperty(
|
||||
name="Instantiate",
|
||||
description="Instantiate object",
|
||||
maxlen=1,
|
||||
default="I",
|
||||
)
|
||||
bpy.types.Scene.Key_Close: StringProperty(
|
||||
name="Close polygonal shape",
|
||||
description="Close polygonal shape",
|
||||
maxlen=1,
|
||||
default="X",
|
||||
)
|
||||
bpy.types.Scene.Key_Apply: StringProperty(
|
||||
name="Apply operation",
|
||||
description="Apply operation",
|
||||
maxlen=1,
|
||||
default="Q",
|
||||
)
|
||||
bpy.types.Scene.Key_Scale: StringProperty(
|
||||
name="Scale object",
|
||||
description="Scale object",
|
||||
maxlen=1,
|
||||
default="S",
|
||||
)
|
||||
bpy.types.Scene.Key_Gapy: StringProperty(
|
||||
name="Gap rows",
|
||||
description="Scale gap between columns",
|
||||
maxlen=1,
|
||||
default="J",
|
||||
)
|
||||
bpy.types.Scene.Key_Gapx: StringProperty(
|
||||
name="Gap columns",
|
||||
description="Scale gap between columns",
|
||||
maxlen=1,
|
||||
default="U",
|
||||
)
|
||||
bpy.types.Scene.Key_Depth: StringProperty(
|
||||
name="Depth",
|
||||
description="Cursor depth or solidify pattern",
|
||||
maxlen=1,
|
||||
default="D",
|
||||
)
|
||||
bpy.types.Scene.Key_BrushDepth: StringProperty(
|
||||
name="Brush Depth",
|
||||
description="Brush depth",
|
||||
maxlen=1,
|
||||
default="C",
|
||||
)
|
||||
bpy.types.Scene.Key_Subadd: StringProperty(
|
||||
name="Add subdivision",
|
||||
description="Add subdivision",
|
||||
maxlen=1,
|
||||
default="X",
|
||||
)
|
||||
bpy.types.Scene.Key_Subrem: StringProperty(
|
||||
name="Remove subdivision",
|
||||
description="Remove subdivision",
|
||||
maxlen=1,
|
||||
default="W",
|
||||
)
|
||||
bpy.types.Scene.Key_Randrot: StringProperty(
|
||||
name="Random rotation",
|
||||
description="Random rotation",
|
||||
maxlen=1,
|
||||
default="R",
|
||||
)
|
||||
bpy.types.Scene.ProfilePrefix: StringProperty(
|
||||
name="Profile prefix",
|
||||
description="Prefix to look for profiles with",
|
||||
default="Carver_Profile-"
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
scene = context.scene
|
||||
layout = self.layout
|
||||
print("DRAW !")
|
||||
|
||||
icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN"
|
||||
box = layout.box()
|
||||
|
||||
box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1)
|
||||
if self.Enable_Tab_01:
|
||||
box.label(text="Carver Operator:", icon="LAYER_ACTIVE")
|
||||
box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve",
|
||||
icon="LAYER_USED")
|
||||
box.label(text="To finish carving press [ESC] or [RIGHT CLICK]",
|
||||
icon="LAYER_USED")
|
||||
box.prop(scene, "ProfilePrefix", text="Profile prefix")
|
||||
|
||||
icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN"
|
||||
box = layout.box()
|
||||
box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2)
|
||||
if self.Enable_Tab_02:
|
||||
split = box.split(align=True)
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Object Creation:")
|
||||
col.prop(scene, "Key_Create", text="")
|
||||
col.label(text="Auto bevel update:")
|
||||
col.prop(scene, "Key_Update", text="")
|
||||
col.label(text="Boolean operation type:")
|
||||
col.prop(scene, "Key_Bool", text="")
|
||||
col.label(text="Brush Depth:")
|
||||
col.prop(scene, "Key_BrushDepth", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Brush Mode:")
|
||||
col.prop(scene, "Key_Brush", text="")
|
||||
col.label(text="Help display:")
|
||||
col.prop(scene, "Key_Help", text="")
|
||||
col.label(text="Instantiate object:")
|
||||
col.prop(scene, "Key_Instant", text="")
|
||||
col.label(text="Random rotation:")
|
||||
col.prop(scene, "Key_Randrot", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Close polygonal shape:")
|
||||
col.prop(scene, "Key_Close", text="")
|
||||
col.label(text="Apply operation:")
|
||||
col.prop(scene, "Key_Apply", text="")
|
||||
col.label(text="Scale object:")
|
||||
col.prop(scene, "Key_Scale", text="")
|
||||
col.label(text="Subdiv add:")
|
||||
col.prop(scene, "Key_Subadd", text="")
|
||||
|
||||
box = split.box()
|
||||
col = box.column(align=True)
|
||||
col.label(text="Gap rows:")
|
||||
col.prop(scene, "Key_Gapy", text="")
|
||||
col.label(text="Gap columns:")
|
||||
col.prop(scene, "Key_Gapx", text="")
|
||||
col.label(text="Depth / Solidify:")
|
||||
col.prop(scene, "Key_Depth", text="")
|
||||
col.label(text="Subdiv Remove:")
|
||||
col.prop(scene, "Key_Subrem", text="")
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(CarverPrefs)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(CarverPrefs)
|
|
@ -0,0 +1,409 @@
|
|||
from mathutils import (
|
||||
Vector,
|
||||
)
|
||||
|
||||
|
||||
Profils = [
|
||||
("TEST",
|
||||
Vector((0,0,1)),
|
||||
[(-1, 1, 0.032334), (1, 1, 0.032334),(-1, -1, 0.032334), (1, -1, 0.01032334)],
|
||||
[(0, 1, 2), (2,1,3)]),
|
||||
("CTP_4882",
|
||||
Vector((2.61824, -5.56469, 0)),
|
||||
[(-1.156501, 0.799282, 0.032334),
|
||||
(-0.967583, 0.838861, 0.032334),
|
||||
(-1.10386, 0.846403, 0.032334),
|
||||
(-1.034712, 0.86089, 0.032334),
|
||||
(-1.88472, -0.564419, 0.032334),
|
||||
(-1.924299, -0.375502, 0.032334),
|
||||
(-1.93184, -0.511778, 0.032334),
|
||||
(-1.946327, -0.44263, 0.032334),
|
||||
(-0.219065, -0.869195, 0.032334),
|
||||
(-0.149916, -0.854708, 0.032334),
|
||||
(-0.286193, -0.847167, 0.032334),
|
||||
(-0.097275, -0.807588, 0.032334),
|
||||
(0.692551, 0.434324, 0.032334),
|
||||
(0.678064, 0.503472, 0.032334),
|
||||
(0.670523, 0.367196, 0.032334),
|
||||
(0.630943, 0.556113, 0.032334),
|
||||
(-0.780424, -0.44263, 0.032334),
|
||||
(-0.765937, -0.511778, 0.032334),
|
||||
(-0.758396, -0.375502, 0.032334),
|
||||
(-0.718817, -0.564419, 0.032334),
|
||||
(-0.53496, 0.556113, 0.032334),
|
||||
(-0.49538, 0.367196, 0.032334),
|
||||
(-0.487839, 0.503472, 0.032334),
|
||||
(-0.473352, 0.434324, 0.032334),
|
||||
(-1.263178, -0.807588, 0.032334),
|
||||
(-1.452096, -0.847167, 0.032334),
|
||||
(-1.315819, -0.854708, 0.032334),
|
||||
(-1.384968, -0.869195, 0.032334),
|
||||
(0.131191, 0.86089, 0.032334),
|
||||
(0.062043, 0.846403, 0.032334),
|
||||
(0.19832, 0.838861, 0.032334),
|
||||
(0.009402, 0.799282, 0.032334),
|
||||
(0.946838, -0.869195, 0.032334),
|
||||
(1.015987, -0.854708, 0.032334),
|
||||
(0.87971, -0.847167, 0.032334),
|
||||
(1.068628, -0.807588, 0.032334),
|
||||
(1.858454, 0.434324, 0.032334),
|
||||
(1.843967, 0.503472, 0.032334),
|
||||
(1.836426, 0.367196, 0.032334),
|
||||
(1.796846, 0.556113, 0.032334),
|
||||
(0.385479, -0.44263, 0.032334),
|
||||
(0.399966, -0.511778, 0.032334),
|
||||
(0.407507, -0.375502, 0.032334),
|
||||
(0.447086, -0.564419, 0.032334),
|
||||
(1.297095, 0.86089, 0.032334),
|
||||
(1.227946, 0.846403, 0.032334),
|
||||
(1.364223, 0.838861, 0.032334),
|
||||
(1.175305, 0.799282, 0.032334),
|
||||
],
|
||||
[[16, 17, 19], [5, 4, 24], [14, 12, 15], [14, 15, 31], [10, 8, 11], [15, 30, 31], [19, 10, 11],
|
||||
[11, 14, 31], [31, 18, 11], [8, 9, 11], [18, 16, 19], [12, 13, 15], [18, 19, 11], [28, 29, 31],
|
||||
[30, 28, 31], [24, 21, 0], [23, 22, 20], [20, 1, 0], [3, 2, 0], [0, 5, 24], [7, 6, 4], [4, 25, 24],
|
||||
[27, 26, 24], [21, 23, 20], [1, 3, 0], [5, 7, 4], [25, 27, 24], [21, 20, 0], [40, 41, 43], [38, 36, 39],
|
||||
[38, 39, 47], [34, 32, 35], [39, 46, 47], [43, 34, 35], [35, 38, 47], [47, 42, 35], [32, 33, 35],
|
||||
[42, 40, 43], [36, 37, 39], [42, 43, 35], [44, 45, 47], [46, 44, 47]]),
|
||||
("CTP_8354",
|
||||
Vector((-0.06267, -2.43829, -0.0)),
|
||||
[(-0.534254, -1.0, 0.032334),
|
||||
(-1.0, -0.534254, 0.032334),
|
||||
(-0.654798, -0.98413, 0.032334),
|
||||
(-0.767127, -0.937602, 0.032334),
|
||||
(-0.863586, -0.863586, 0.032334),
|
||||
(-0.937602, -0.767127, 0.032334),
|
||||
(-0.98413, -0.654798, 0.032334),
|
||||
(1.0, -0.534254, 0.032334),
|
||||
(0.534254, -1.0, 0.032334),
|
||||
(0.98413, -0.654798, 0.032334),
|
||||
(0.937602, -0.767127, 0.032334),
|
||||
(0.863586, -0.863586, 0.032334),
|
||||
(0.767127, -0.937602, 0.032334),
|
||||
(0.654798, -0.98413, 0.032334),
|
||||
(-1.0, 0.534254, 0.032334),
|
||||
(-0.534254, 1.0, 0.032334),
|
||||
(-0.98413, 0.654798, 0.032334),
|
||||
(-0.937602, 0.767127, 0.032334),
|
||||
(-0.863586, 0.863586, 0.032334),
|
||||
(-0.767127, 0.937602, 0.032334),
|
||||
(-0.654798, 0.98413, 0.032334),
|
||||
(0.534254, 1.0, 0.032334),
|
||||
(1.0, 0.534254, 0.032334),
|
||||
(0.654798, 0.98413, 0.032334),
|
||||
(0.767127, 0.937602, 0.032334),
|
||||
(0.863586, 0.863586, 0.032334),
|
||||
(0.937602, 0.767127, 0.032334),
|
||||
(0.98413, 0.654798, 0.032334),
|
||||
(-0.763998, 0.518786, 0.032334),
|
||||
(-0.763998, -0.518786, 0.032334),
|
||||
(-0.754202, -0.593189, 0.032334),
|
||||
(-0.731454, -0.648108, 0.032334),
|
||||
(-0.695267, -0.695267, 0.032334),
|
||||
(-0.648108, -0.731454, 0.032334),
|
||||
(-0.593189, -0.754202, 0.032334),
|
||||
(-0.518786, -0.763998, 0.032334),
|
||||
(0.518786, -0.763998, 0.032334),
|
||||
(0.593189, -0.754202, 0.032334),
|
||||
(0.648108, -0.731454, 0.032334),
|
||||
(0.695267, -0.695267, 0.032334),
|
||||
(0.731454, -0.648108, 0.032334),
|
||||
(0.754202, -0.593189, 0.032334),
|
||||
(0.763998, -0.518786, 0.032334),
|
||||
(0.763998, 0.518786, 0.032334),
|
||||
(0.754202, 0.593189, 0.032334),
|
||||
(0.731454, 0.648108, 0.032334),
|
||||
(0.695267, 0.695267, 0.032334),
|
||||
(0.648108, 0.731454, 0.032334),
|
||||
(0.593189, 0.754202, 0.032334),
|
||||
(0.518786, 0.763998, 0.032334),
|
||||
(-0.518786, 0.763998, 0.032334),
|
||||
(-0.593189, 0.754202, 0.032334),
|
||||
(-0.648108, 0.731454, 0.032334),
|
||||
(-0.695267, 0.695267, 0.032334),
|
||||
(-0.731454, 0.648108, 0.032334),
|
||||
(-0.754202, 0.593189, 0.032334),
|
||||
(0.518786, 0.518786, 0.032334),
|
||||
(-0.518786, 0.518786, 0.032334),
|
||||
(0.518786, -0.518786, 0.032334),
|
||||
(-0.518786, -0.518786, 0.032334),
|
||||
(-0.593189, 0.518786, 0.032334),
|
||||
(-0.593189, -0.518786, 0.032334),
|
||||
(0.518786, -0.593189, 0.032334),
|
||||
(-0.518786, -0.593189, 0.032334),
|
||||
(-0.593189, -0.593189, 0.032334),
|
||||
(0.593189, 0.518786, 0.032334),
|
||||
(0.593189, -0.518786, 0.032334),
|
||||
(0.593189, -0.593189, 0.032334),
|
||||
(-0.593189, 0.593189, 0.032334),
|
||||
(-0.518786, 0.593189, 0.032334),
|
||||
(0.518786, 0.593189, 0.032334),
|
||||
(0.593189, 0.593189, 0.032334),
|
||||
(-0.648108, 0.593189, 0.032334),
|
||||
(-0.648108, 0.518786, 0.032334),
|
||||
(-0.648108, -0.518786, 0.032334),
|
||||
(-0.648108, -0.593189, 0.032334),
|
||||
(-0.695267, 0.593189, 0.032334),
|
||||
(-0.695267, 0.518786, 0.032334),
|
||||
(-0.695267, -0.518786, 0.032334),
|
||||
(-0.695267, -0.593189, 0.032334),
|
||||
(0.648108, 0.593189, 0.032334),
|
||||
(0.648108, 0.518786, 0.032334),
|
||||
(0.648108, -0.518786, 0.032334),
|
||||
(0.648108, -0.593189, 0.032334),
|
||||
(0.695267, 0.593189, 0.032334),
|
||||
(0.695267, 0.518786, 0.032334),
|
||||
(0.695267, -0.518786, 0.032334),
|
||||
(0.695267, -0.593189, 0.032334),
|
||||
],
|
||||
[[87, 39, 40, 41], [29, 28, 14, 1], [30, 29, 1, 6], [31, 30, 6, 5], [32, 31, 5, 4], [33, 32, 4, 3],
|
||||
[34, 33, 3, 2], [35, 34, 2, 0], [36, 35, 0, 8], [37, 36, 8, 13], [38, 37, 13, 12], [39, 38, 12, 11],
|
||||
[40, 39, 11, 10], [41, 40, 10, 9], [42, 41, 9, 7], [43, 42, 7, 22], [44, 43, 22, 27], [45, 44, 27, 26],
|
||||
[46, 45, 26, 25], [47, 46, 25, 24], [48, 47, 24, 23], [49, 48, 23, 21], [50, 49, 21, 15], [51, 50, 15, 20],
|
||||
[52, 51, 20, 19], [53, 52, 19, 18], [54, 53, 18, 17], [55, 54, 17, 16], [28, 55, 16, 14], [68, 69, 50, 51],
|
||||
[63, 35, 36, 62], [69, 57, 56, 70], [84, 85, 43, 44], [64, 34, 35, 63], [57, 59, 58, 56], [85, 86, 42, 43],
|
||||
[60, 61, 59, 57], [73, 74, 61, 60], [72, 68, 51, 52], [75, 33, 34, 64], [61, 64, 63, 59], [59, 63, 62, 58],
|
||||
[86, 87, 41, 42], [74, 75, 64, 61], [58, 62, 67, 66], [56, 58, 66, 65], [70, 56, 65, 71], [62, 36, 37, 67],
|
||||
[49, 70, 71, 48], [50, 69, 70, 49], [60, 57, 69, 68], [73, 60, 68, 72], [46, 84, 44, 45], [78, 79, 75, 74],
|
||||
[77, 78, 74, 73], [77, 73, 72, 76], [76, 72, 52, 53], [79, 32, 33, 75], [29, 30, 79, 78], [28, 29, 78, 77],
|
||||
[28, 77, 76, 55], [55, 76, 53, 54], [30, 31, 32, 79], [66, 67, 83, 82], [65, 66, 82, 81], [71, 65, 81, 80],
|
||||
[48, 71, 80, 47], [67, 37, 38, 83], [82, 83, 87, 86], [81, 82, 86, 85], [80, 81, 85, 84], [47, 80, 84, 46],
|
||||
[83, 38, 39, 87]]),
|
||||
("CTP_5585",
|
||||
Vector((5.0114, -2.4281, 0.0)),
|
||||
[(-0.490711, -1.0, 0.032334),
|
||||
(-1.0, -0.490711, 0.032334),
|
||||
(1.0, -0.490711, 0.032334),
|
||||
(0.490711, -1.0, 0.032334),
|
||||
(-1.0, 0.490711, 0.032334),
|
||||
(-0.490711, 1.0, 0.032334),
|
||||
(0.490711, 1.0, 0.032334),
|
||||
(1.0, 0.490711, 0.032334),
|
||||
(-0.51852, 0.291276, 0.032334),
|
||||
(-0.51852, -0.291276, 0.032334),
|
||||
(-0.291276, -0.51852, 0.032334),
|
||||
(0.291276, -0.51852, 0.032334),
|
||||
(0.51852, -0.291276, 0.032334),
|
||||
(0.51852, 0.291276, 0.032334),
|
||||
(0.291276, 0.51852, 0.032334),
|
||||
(-0.291276, 0.51852, 0.032334),
|
||||
],
|
||||
[[11, 12, 13, 14], [9, 8, 4, 1], [10, 9, 1, 0], [11, 10, 0, 3], [12, 11, 3, 2], [13, 12, 2, 7],
|
||||
[14, 13, 7, 6], [15, 14, 6, 5], [8, 15, 5, 4], [9, 10, 15, 8], [10, 11, 14, 15]]),
|
||||
("CTP_6960",
|
||||
Vector((-0.11417, 2.48371, -0.0)),
|
||||
[(0.0, 1.0, 0.016827),
|
||||
(-0.382683, 0.92388, 0.016827),
|
||||
(-0.707107, 0.707107, 0.016827),
|
||||
(-0.92388, 0.382683, 0.016827),
|
||||
(-1.0, -0.0, 0.016827),
|
||||
(-0.92388, -0.382684, 0.016827),
|
||||
(-0.707107, -0.707107, 0.016827),
|
||||
(-0.382683, -0.92388, 0.016827),
|
||||
(-0.0, -1.0, 0.016827),
|
||||
(0.382683, -0.92388, 0.016827),
|
||||
(0.707107, -0.707107, 0.016827),
|
||||
(0.92388, -0.382684, 0.016827),
|
||||
(1.0, 0.0, 0.016827),
|
||||
(0.923879, 0.382684, 0.016827),
|
||||
(0.707107, 0.707107, 0.016827),
|
||||
(0.382683, 0.92388, 0.016827),
|
||||
(-0.0, 0.546859, 0.016827),
|
||||
(-0.209274, 0.505231, 0.016827),
|
||||
(-0.386687, 0.386687, 0.016827),
|
||||
(-0.505231, 0.209274, 0.016827),
|
||||
(-0.546859, -0.0, 0.016827),
|
||||
(-0.505231, -0.209274, 0.016827),
|
||||
(-0.386687, -0.386687, 0.016827),
|
||||
(-0.209274, -0.505231, 0.016827),
|
||||
(-0.0, -0.546859, 0.016827),
|
||||
(0.209274, -0.505231, 0.016827),
|
||||
(0.386687, -0.386688, 0.016827),
|
||||
(0.505231, -0.209274, 0.016827),
|
||||
(0.546858, 0.0, 0.016827),
|
||||
(0.505231, 0.209274, 0.016827),
|
||||
(0.386687, 0.386688, 0.016827),
|
||||
(0.209273, 0.505232, 0.016827),
|
||||
],
|
||||
[[3, 19, 18, 2], [11, 27, 26, 10], [4, 20, 19, 3], [12, 28, 27, 11], [5, 21, 20, 4], [13, 29, 28, 12],
|
||||
[6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0],
|
||||
[0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]),
|
||||
("CTP_5359",
|
||||
Vector((5.50446, 2.41669, -0.0)),
|
||||
[(0.0, 0.714247, 0.023261),
|
||||
(-0.382683, 0.659879, 0.023261),
|
||||
(-0.707107, 0.505049, 0.023261),
|
||||
(-0.92388, 0.273331, 0.023261),
|
||||
(-1.0, -0.0, 0.023261),
|
||||
(-0.92388, -0.273331, 0.023261),
|
||||
(-0.707107, -0.505049, 0.023261),
|
||||
(-0.382683, -0.659879, 0.023261),
|
||||
(-0.0, -0.714247, 0.023261),
|
||||
(0.382683, -0.659879, 0.023261),
|
||||
(0.707107, -0.505049, 0.023261),
|
||||
(0.92388, -0.273331, 0.023261),
|
||||
(1.0, 0.0, 0.023261),
|
||||
(0.923879, 0.273331, 0.023261),
|
||||
(0.707107, 0.505049, 0.023261),
|
||||
(0.382683, 0.659879, 0.023261),
|
||||
(-0.0, 0.303676, 0.023261),
|
||||
(-0.162705, 0.28056, 0.023261),
|
||||
(-0.30064, 0.214731, 0.023261),
|
||||
(-0.392805, 0.116212, 0.023261),
|
||||
(-0.425169, -0.0, 0.023261),
|
||||
(-0.392805, -0.116212, 0.023261),
|
||||
(-0.30064, -0.214731, 0.023261),
|
||||
(-0.162705, -0.28056, 0.023261),
|
||||
(-0.0, -0.303676, 0.023261),
|
||||
(0.162705, -0.28056, 0.023261),
|
||||
(0.30064, -0.214731, 0.023261),
|
||||
(0.392805, -0.116212, 0.023261),
|
||||
(0.425169, 0.0, 0.023261),
|
||||
(0.392805, 0.116212, 0.023261),
|
||||
(0.30064, 0.214731, 0.023261),
|
||||
(0.162705, 0.28056, 0.023261),
|
||||
],
|
||||
[[3, 19, 18, 2], [11, 27, 26, 10], [4, 20, 19, 3], [12, 28, 27, 11], [5, 21, 20, 4], [13, 29, 28, 12],
|
||||
[6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0],
|
||||
[0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]),
|
||||
("CTP_5424",
|
||||
Vector((2.61824, 2.34147, 0.0)),
|
||||
[(1.0, -1.0, 0.032334),
|
||||
(-1.0, 1.0, 0.032334),
|
||||
(1.0, 1.0, 0.032334),
|
||||
(0.783867, -0.259989, 0.032334),
|
||||
(-0.393641, 0.857073, 0.032334),
|
||||
(0.73142, -0.116299, 0.032334),
|
||||
(0.657754, 0.02916, 0.032334),
|
||||
(0.564682, 0.172804, 0.032334),
|
||||
(0.454497, 0.311098, 0.032334),
|
||||
(0.329912, 0.440635, 0.032334),
|
||||
(0.193995, 0.558227, 0.032334),
|
||||
(0.050092, 0.660978, 0.032334),
|
||||
(-0.098254, 0.746358, 0.032334),
|
||||
(-0.247389, 0.812263, 0.032334),
|
||||
],
|
||||
[[3, 0, 2], [10, 9, 2], [2, 1, 4], [2, 4, 13], [5, 3, 2], [6, 5, 2], [2, 13, 12], [2, 12, 11], [7, 6, 2],
|
||||
[8, 7, 2], [2, 11, 10], [9, 8, 2]]),
|
||||
("CTP_3774",
|
||||
Vector((2.61824, -2.52425, 0.0)),
|
||||
[(1.0, 0.0, 0.020045),
|
||||
(-1.0, 0.0, 0.020045),
|
||||
(0.31903, -0.664947, 0.020045),
|
||||
(-0.31903, -0.664947, 0.020045),
|
||||
(-0.31903, 1.0, 0.020045),
|
||||
(0.31903, 1.0, 0.020045),
|
||||
(0.31903, 0.0, 0.020045),
|
||||
(-0.31903, 0.0, 0.020045),
|
||||
(-1.0, 0.614333, 0.020045),
|
||||
(-0.614333, 1.0, 0.020045),
|
||||
(-0.970643, 0.761921, 0.020045),
|
||||
(-0.887041, 0.887041, 0.020045),
|
||||
(-0.761921, 0.970643, 0.020045),
|
||||
(0.614333, 1.0, 0.020045),
|
||||
(1.0, 0.614333, 0.020045),
|
||||
(0.761921, 0.970643, 0.020045),
|
||||
(0.887041, 0.887041, 0.020045),
|
||||
(0.970643, 0.761921, 0.020045),
|
||||
(-0.31903, 0.614333, 0.020045),
|
||||
(0.31903, 0.614333, 0.020045),
|
||||
(0.31903, 0.761921, 0.020045),
|
||||
(-0.31903, 0.761921, 0.020045),
|
||||
(0.31903, 0.887041, 0.020045),
|
||||
(-0.31903, 0.887041, 0.020045),
|
||||
(0.614333, 0.614333, 0.020045),
|
||||
(0.614333, 0.0, 0.020045),
|
||||
(0.614333, 0.761921, 0.020045),
|
||||
(0.614333, 0.887041, 0.020045),
|
||||
(-0.614333, 0.761921, 0.020045),
|
||||
(-0.614333, 0.0, 0.020045),
|
||||
(-0.614333, 0.887041, 0.020045),
|
||||
(-0.614333, 0.614333, 0.020045),
|
||||
],
|
||||
[[6, 25, 24, 19], [6, 19, 18, 7], [2, 6, 7, 3], [1, 29, 31, 8], [8, 31, 28, 10], [19, 24, 26, 20],
|
||||
[18, 19, 20, 21], [21, 20, 22, 23], [10, 28, 30, 11], [20, 26, 27, 22], [22, 27, 13, 5], [23, 22, 5, 4],
|
||||
[11, 30, 9, 12], [17, 16, 27, 26], [14, 17, 26, 24], [24, 25, 0, 14], [15, 13, 27, 16], [9, 30, 23, 4],
|
||||
[31, 29, 7, 18], [28, 31, 18, 21], [30, 28, 21, 23]]),
|
||||
("CTP_4473",
|
||||
Vector((7.31539, 0.0, 0.0)),
|
||||
[(0.24549, -1.0, 0.022454),
|
||||
(-0.24549, -1.0, 0.022454),
|
||||
(-0.24549, 1.0, 0.022454),
|
||||
(0.24549, 1.0, 0.022454),
|
||||
(1.0, 0.267452, 0.022454),
|
||||
(1.0, -0.267452, 0.022454),
|
||||
(-1.0, -0.267452, 0.022454),
|
||||
(-1.0, 0.267452, 0.022454),
|
||||
(0.24549, 0.267452, 0.022454),
|
||||
(0.24549, -0.267452, 0.022454),
|
||||
(-0.24549, 0.267452, 0.022454),
|
||||
(-0.24549, -0.267452, 0.022454),
|
||||
],
|
||||
[[8, 3, 2, 10], [0, 9, 11, 1], [4, 8, 9, 5], [8, 10, 11, 9], [10, 7, 6, 11]]),
|
||||
("CTP_4003",
|
||||
Vector((4.91276, 0.0, 0.0)),
|
||||
[(-1.0, -1.0, 0.026945),
|
||||
(1.0, -1.0, 0.026945),
|
||||
(-1.0, 1.0, 0.026945),
|
||||
(-0.026763, -1.0, 0.026945),
|
||||
(-0.026763, 1.0, 0.026945),
|
||||
(1.0, -0.026763, 0.026945),
|
||||
(0.238983, 0.965014, 0.026945),
|
||||
(0.486619, 0.86244, 0.026945),
|
||||
(0.699268, 0.699268, 0.026945),
|
||||
(0.86244, 0.486619, 0.026945),
|
||||
(0.965014, 0.238983, 0.026945),
|
||||
(0.238983, -1.0, 0.026945),
|
||||
(0.486619, -1.0, 0.026945),
|
||||
(0.699268, -1.0, 0.026945),
|
||||
(0.86244, -1.0, 0.026945),
|
||||
(-0.026763, 0.479676, 0.026945),
|
||||
(0.486619, 0.479676, 0.026945),
|
||||
(0.699268, 0.479676, 0.026945),
|
||||
(0.238983, 0.479676, 0.026945),
|
||||
(0.865316, 0.479676, 0.026945),
|
||||
(-1.0, 0.479676, 0.026945),
|
||||
(0.86244, 0.479676, 0.026945),
|
||||
(-0.026763, 0.238983, 0.026945),
|
||||
(0.486619, 0.238983, 0.026945),
|
||||
(0.699268, 0.238983, 0.026945),
|
||||
(0.238983, 0.238983, 0.026945),
|
||||
(-1.0, 0.238983, 0.026945),
|
||||
(0.86244, 0.238983, 0.026945),
|
||||
(-0.026763, -0.026763, 0.026945),
|
||||
(0.486619, -0.026763, 0.026945),
|
||||
(0.699268, -0.026763, 0.026945),
|
||||
(0.238983, -0.026763, 0.026945),
|
||||
(-1.0, -0.026763, 0.026945),
|
||||
(0.86244, -0.026763, 0.026945),
|
||||
],
|
||||
[[0, 3, 28, 32], [4, 15, 18, 6], [6, 18, 16, 7], [7, 16, 17, 8], [8, 17, 21, 9], [9, 21, 19], [18, 15, 22, 25],
|
||||
[19, 21, 27, 10], [16, 18, 25, 23], [17, 16, 23, 24], [20, 15, 4, 2], [21, 17, 24, 27], [27, 24, 30, 33],
|
||||
[23, 25, 31, 29], [24, 23, 29, 30], [25, 22, 28, 31], [26, 22, 15, 20], [10, 27, 33, 5], [31, 28, 3, 11],
|
||||
[33, 30, 13, 14], [29, 31, 11, 12], [5, 33, 14, 1], [30, 29, 12, 13], [32, 28, 22, 26]]),
|
||||
("CTP_3430",
|
||||
Vector((2.61824, 0.0, 0.0)),
|
||||
[(-1.0, -1.0, 0.032334),
|
||||
(1.0, -1.0, 0.032334),
|
||||
(-1.0, 1.0, 0.032334),
|
||||
(1.0, 1.0, 0.032334),
|
||||
],
|
||||
[[0, 1, 3, 2]]),
|
||||
("CTP_7175",
|
||||
Vector((0.0, 0.0, 0.0)),
|
||||
[(-1.0, -1.0, 0.032334),
|
||||
(1.0, -1.0, 0.032334),
|
||||
(-1.0, 1.0, 0.032334),
|
||||
(1.0, 1.0, 0.032334),
|
||||
(0.0, 0.0, 0.032334),
|
||||
(0.0, 0.0, 0.032334),
|
||||
(0.0, 0.0, 0.032334),
|
||||
(0.0, 0.0, 0.032334),
|
||||
(0.0, 0.0, 0.032334),
|
||||
(-0.636126, 0.636126, 0.032334),
|
||||
(-0.636126, -0.636126, 0.032334),
|
||||
(0.636126, -0.636126, 0.032334),
|
||||
(0.636126, 0.636126, 0.032334),
|
||||
],
|
||||
[[10, 9, 2, 0], [11, 10, 0, 1], [12, 11, 1, 3], [9, 12, 3, 2]]),
|
||||
]
|
|
@ -0,0 +1,941 @@
|
|||
|
||||
import bpy
|
||||
import bgl
|
||||
import gpu
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
import math
|
||||
import sys
|
||||
import random
|
||||
import bmesh
|
||||
from mathutils import (
|
||||
Euler,
|
||||
Matrix,
|
||||
Vector,
|
||||
Quaternion,
|
||||
)
|
||||
from mathutils.geometry import (
|
||||
intersect_line_plane,
|
||||
)
|
||||
|
||||
from math import (
|
||||
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,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
# 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)))
|
||||
|
||||
# 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)
|
||||
|
||||
# Object dimensions (SCULPT Tools tips)
|
||||
def objDiagonal(obj):
|
||||
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
|
||||
|
||||
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')
|
||||
|
||||
else:
|
||||
# No subdiv mode : bevel weight + Crease + Sharp
|
||||
CreateBevel(context, obj)
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
bpy.ops.object.shade_smooth()
|
||||
|
||||
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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
# 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.depsgraph
|
||||
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
|
||||
|
||||
def SelectObject(self, copyobj):
|
||||
copyobj.select_set(True)
|
||||
|
||||
for child in copyobj.children:
|
||||
SelectObject(self, child)
|
||||
|
||||
if copyobj.parent is None:
|
||||
bpy.context.view_layer.objects.active = copyobj
|
||||
|
||||
# Undo
|
||||
def printUndo(self):
|
||||
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
|
||||
|
||||
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()
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
if o[1] == "DUPLICATE":
|
||||
o[0].select_set(True)
|
||||
o[0].hide_viewport = 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
def boolean_operation(bool_type="DIFFERENCE"):
|
||||
ActiveObj = bpy.context.active_object
|
||||
sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1
|
||||
|
||||
# bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
|
||||
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
|
||||
|
||||
Brush = context.selected_objects[1]
|
||||
Brush.display_type = "WIRE"
|
||||
|
||||
#Deselect all
|
||||
bpy.ops.object.select_all(action='TOGGLE')
|
||||
|
||||
target_obj.display_type = "SOLID"
|
||||
target_obj.select_set(True)
|
||||
bpy.ops.object.duplicate()
|
||||
|
||||
rebool_obj = context.active_object
|
||||
|
||||
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
|
||||
|
||||
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.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')
|
||||
|
||||
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))
|
||||
|
||||
bpy.ops.object.select_all(action='TOGGLE')
|
||||
|
||||
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.scene.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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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))
|
Loading…
Reference in New Issue