Mesh Extra Tools: Update to version 0.33, various fixes
Bump version to 0.33 Some Pep8 clean up and general fixes Some UI updates Replace Mesh to wall with a similar results script mesh_edges_floor_plan (for reasons see T51483) It is not 1 to 1 replacement but should be more stable If someone wants to continue development it's absolutely possible to be re-included later on Vertex Align: cleanup and refactor code introduce a stored alignment setting, proper help operator call move the property group to init, remove register call Mesh Check: cleanup Move the UI element draw code from init to the Face/Info select, cleanup mesh_info_select: Add a timer for redraw (not sure if it is the best solution) Add settings remove refresh operator (as edit mode is available) Mesh Edge Tools: remove the Intersect_Line_Face operator, add general error handling fix several crashes with non proper selections passed Select tools - replace deprecated imp call
This commit is contained in:
parent
aaeb073354
commit
48a69db544
|
@ -17,20 +17,21 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# Contributed to by:
|
||||
# meta-androcto, Hidesato Ikeya, zmj100, luxuy_BlenderCN, TrumanBlending, PKHG, #
|
||||
# meta-androcto, Hidesato Ikeya, zmj100, Gert De Roost, TrumanBlending, PKHG, #
|
||||
# Oscurart, Greg, Stanislav Blinov, komi3D, BlenderLab, Paul Marshall (brikbot), #
|
||||
# metalliandy, macouno, CoDEmanX, dustractor, Liero, lijenstina, Germano Cavalcante #
|
||||
# Pistiwique, Jimmy Hazevoet #
|
||||
|
||||
bl_info = {
|
||||
"name": "Edit Tools 2",
|
||||
"author": "meta-androcto",
|
||||
"version": (0, 3, 2),
|
||||
"version": (0, 3, 3),
|
||||
"blender": (2, 78, 0),
|
||||
"location": "View3D > Toolshelf > Tools and Specials (W-key)",
|
||||
"description": "Extra mesh edit tools - modifying meshes and selection",
|
||||
"warning": "",
|
||||
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Modeling/Extra_Tools",
|
||||
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
|
||||
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
|
||||
"Py/Scripts/Modeling/Extra_Tools",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
|
@ -46,7 +47,7 @@ if "bpy" in locals():
|
|||
importlib.reload(mesh_edge_roundifier)
|
||||
importlib.reload(mesh_cut_faces)
|
||||
importlib.reload(split_solidify)
|
||||
importlib.reload(mesh_to_wall)
|
||||
importlib.reload(mesh_edges_floor_plan)
|
||||
importlib.reload(mesh_edges_length)
|
||||
importlib.reload(random_vertices)
|
||||
importlib.reload(mesh_fastloop)
|
||||
|
@ -76,7 +77,7 @@ else:
|
|||
from . import mesh_edge_roundifier
|
||||
from . import mesh_cut_faces
|
||||
from . import split_solidify
|
||||
from . import mesh_to_wall
|
||||
from . import mesh_edges_floor_plan
|
||||
from . import mesh_edges_length
|
||||
from . import random_vertices
|
||||
from . import mesh_fastloop
|
||||
|
@ -101,8 +102,6 @@ else:
|
|||
|
||||
import bpy
|
||||
import bpy_extras.keyconfig_utils
|
||||
import bmesh
|
||||
from bpy.props import EnumProperty
|
||||
from bpy.types import (
|
||||
Menu,
|
||||
Panel,
|
||||
|
@ -112,6 +111,9 @@ from bpy.types import (
|
|||
from bpy.props import (
|
||||
BoolProperty,
|
||||
BoolVectorProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
IntVectorProperty,
|
||||
PointerProperty,
|
||||
)
|
||||
|
@ -159,7 +161,7 @@ class VIEW3D_MT_edit_mesh_extras(Menu):
|
|||
col.operator("mesh.offset_edges", text="Offset Edges")
|
||||
col.operator("mesh.edge_roundifier", text="Edge Roundify")
|
||||
col.operator("object.mesh_edge_length_set", text="Set Edge Length")
|
||||
col.operator("bpt.mesh_to_wall", text="Edge(s) to Wall")
|
||||
col.operator("mesh.edges_floor_plan")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Utilities", icon="SCRIPTWIN")
|
||||
|
@ -241,21 +243,35 @@ class EditToolsPanel(Panel):
|
|||
row.operator("mesh.random_vertices", text="Random Vertices")
|
||||
row.operator("mesh.extra_tools_help",
|
||||
icon="LAYER_USED").help_ids = "random_vertices"
|
||||
# Vertex Align Properties And Menu
|
||||
cen0 = context.scene.va_custom_props.en0 # get the properties list
|
||||
layout = self.layout
|
||||
layout.label(text="Vertex Align:", icon="VERTEXSEL")
|
||||
layout.prop(context.scene.va_custom_props, 'en0', expand = False) # Draw the menu with 2 options
|
||||
if cen0 == 'vertex':
|
||||
row = layout.split(0.60)
|
||||
row.label('Store data:')
|
||||
row.operator('va.op0_store_id', text = 'Vertex')
|
||||
row1 = layout.split(0.8, align=True)
|
||||
row1.operator('va.op2_align_id', text = 'Align to Axis')
|
||||
row1.operator('va.op7_help_id', text = '', icon = "LAYER_USED")
|
||||
elif cen0 == 'coordinates':
|
||||
layout.operator('va.op3_coord_list_id', text = 'Align Coordinates')
|
||||
|
||||
# Vertex Align Properties And Menu
|
||||
cen0 = scene.mesh_extra_tools.vert_align_to
|
||||
|
||||
layout = self.layout
|
||||
layout.label(text="Vertex Align:", icon="UV_VERTEXSEL")
|
||||
|
||||
# Draw the menu with 2 options
|
||||
layout.prop(scene.mesh_extra_tools, "vert_align_to", expand=False)
|
||||
if cen0 == 'vertex':
|
||||
row = layout.row(align=True)
|
||||
row.operator("vertex_align.store_id", text="Store Selected Vertex")
|
||||
|
||||
row = layout.split(0.8, align=True)
|
||||
row.operator("vertex_align.align_original", text="Align to Axis")
|
||||
props = row.operator("mesh.extra_tools_help", icon="LAYER_USED")
|
||||
props.help_ids = "vertex_align"
|
||||
props.popup_size = 400
|
||||
elif cen0 == "coordinates":
|
||||
layout.prop(scene.mesh_extra_tools, "vert_align_use_stored", toggle=True)
|
||||
|
||||
if scene.mesh_extra_tools.vert_align_use_stored:
|
||||
col = layout.column(align=True)
|
||||
col.prop(scene.mesh_extra_tools, "vert_align_store_axis", expand=True)
|
||||
|
||||
row = layout.split(0.8, align=True)
|
||||
row.operator("vertex_align.coord_list_id", text="Align Coordinates")
|
||||
row.operator("mesh.extra_tools_help",
|
||||
icon="LAYER_USED").help_ids = "vertex_align"
|
||||
|
||||
# Edge options
|
||||
box1 = self.layout.box()
|
||||
|
@ -276,9 +292,9 @@ class EditToolsPanel(Panel):
|
|||
row = layout.split(0.8, align=True)
|
||||
row.operator("mesh.fillet_plus", text="Fillet plus")
|
||||
|
||||
prop = row.operator("mesh.extra_tools_help", icon="LAYER_USED")
|
||||
prop.help_ids = "mesh_filletplus"
|
||||
prop.popup_size = 400
|
||||
props = row.operator("mesh.extra_tools_help", icon="LAYER_USED")
|
||||
props.help_ids = "mesh_filletplus"
|
||||
props.popup_size = 400
|
||||
|
||||
row = layout.split(0.8, align=True)
|
||||
row.operator("mesh.offset_edges", text="Offset Edges")
|
||||
|
@ -296,9 +312,11 @@ class EditToolsPanel(Panel):
|
|||
icon="LAYER_USED").help_ids = "mesh_edges_length"
|
||||
|
||||
row = layout.split(0.8, align=True)
|
||||
row.operator("bpt.mesh_to_wall", text="Edge(s) to Wall")
|
||||
row.operator("mesh.extra_tools_help",
|
||||
icon="LAYER_USED").help_ids = "mesh_to_wall"
|
||||
row.operator("mesh.edges_floor_plan")
|
||||
|
||||
props = row.operator("mesh.extra_tools_help", icon="LAYER_USED")
|
||||
props.help_ids = "mesh_edges_floor_plan"
|
||||
props.popup_size = 400
|
||||
|
||||
# Face options
|
||||
box1 = self.layout.box()
|
||||
|
@ -364,82 +382,73 @@ class EditToolsPanel(Panel):
|
|||
row = layout.split(0.8, align=True)
|
||||
row.operator("object_ot.fastloop", text="Fast Loop")
|
||||
|
||||
prop = row.operator("mesh.extra_tools_help", icon="LAYER_USED")
|
||||
prop.help_ids = "mesh_fastloop"
|
||||
prop.popup_size = 400
|
||||
props = row.operator("mesh.extra_tools_help", icon="LAYER_USED")
|
||||
props.help_ids = "mesh_fastloop"
|
||||
props.popup_size = 400
|
||||
|
||||
row = layout.row()
|
||||
row.operator("mesh.flip_normals", text="Normals Flip")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("mesh.remove_doubles", text="Remove Doubles")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("mesh.subdivide", text="Subdivide")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("mesh.dissolve_limited", text="Dissolve Limited")
|
||||
col = layout.column(align=True)
|
||||
col.operator("mesh.flip_normals", text="Normals Flip")
|
||||
col.operator("mesh.remove_doubles", text="Remove Doubles")
|
||||
col.operator("mesh.subdivide", text="Subdivide")
|
||||
col.operator("mesh.dissolve_limited", text="Dissolve Limited")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("mesh.select_vert_edge_face_index",
|
||||
icon="VERTEXSEL", text="Select By Index").select_type = 'VERT'
|
||||
|
||||
# Mesh Check
|
||||
layout = self.layout
|
||||
icons = load_icons()
|
||||
tris = icons.get("triangles")
|
||||
ngons = icons.get("ngons")
|
||||
|
||||
|
||||
|
||||
mesh_check = context.window_manager.mesh_check
|
||||
|
||||
layout.prop(mesh_check, "mesh_check_use")
|
||||
|
||||
icon_active_4 = "TRIA_RIGHT" if not mesh_check.mesh_check_use else "TRIA_DOWN"
|
||||
|
||||
row = layout.row()
|
||||
row = layout.split(0.8, align=True)
|
||||
row.prop(mesh_check, "mesh_check_use", toggle=True, icon=icon_active_4)
|
||||
row.operator("mesh.extra_tools_help", icon="LAYER_USED").help_ids = "mesh_check"
|
||||
|
||||
if mesh_check.mesh_check_use:
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
row.operator("object.face_type_select", text="Tris", icon_value=tris.icon_id).face_type = 'tris'
|
||||
row.operator("object.face_type_select", text="Ngons",icon_value=ngons.icon_id).face_type = 'ngons'
|
||||
row = layout.row(align=True)
|
||||
row.operator("object.face_type_select", text="Tris",
|
||||
icon_value=tris.icon_id).face_type = 'tris'
|
||||
row.operator("object.face_type_select", text="Ngons",
|
||||
icon_value=ngons.icon_id).face_type = 'ngons'
|
||||
|
||||
row = layout.row()
|
||||
row.prop(mesh_check, "display_faces", text="Display Faces")
|
||||
|
||||
if mesh_check.display_faces:
|
||||
col = layout.column(align=True)
|
||||
col.prop(mesh_check, "edge_width")
|
||||
col.prop(mesh_check, "face_opacity")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(mesh_check, "edge_width")
|
||||
row = layout.row()
|
||||
row.prop(mesh_check, "custom_tri_color",text="Tris color" )
|
||||
row = layout.row()
|
||||
row.prop(mesh_check, "custom_ngons_color")
|
||||
row = layout.row()
|
||||
row.prop(mesh_check, "face_opacity")
|
||||
if bpy.context.object.mode == 'EDIT':
|
||||
obj = bpy.context.object
|
||||
me = obj.data
|
||||
bm = bmesh.from_edit_mesh(me)
|
||||
row.label(text="Custom Colors:", icon="COLOR")
|
||||
|
||||
info_str = ""
|
||||
tris = ngons = 0
|
||||
col = layout.column().split(percentage=0.1, align=True)
|
||||
col.label(text="", icon_value=tris.icon_id)
|
||||
col.prop(mesh_check, "custom_tri_color", text="")
|
||||
|
||||
for f in bm.faces:
|
||||
col = layout.column().split(percentage=0.1, align=True)
|
||||
col.label(text="", icon_value=ngons.icon_id)
|
||||
col.prop(mesh_check, "custom_ngons_color", text="")
|
||||
|
||||
v = len(f.verts)
|
||||
if v == 3:
|
||||
tris += 1
|
||||
elif v > 4:
|
||||
ngons += 1
|
||||
layout.separator()
|
||||
|
||||
bmesh.update_edit_mesh(me)
|
||||
info_str = " Ngons: %i Tris: %i" % (ngons, tris)
|
||||
|
||||
split = layout.split(percentage=0.1)
|
||||
split.separator()
|
||||
split.label(info_str, icon='MESH_DATA')
|
||||
row = layout.row(align=True)
|
||||
if bpy.app.debug:
|
||||
obj_data = getattr(context.active_object, "data", None)
|
||||
if obj_data:
|
||||
row.prop(obj_data, "show_extra_indices",
|
||||
icon="LINENUMBERS_ON", toggle=True)
|
||||
|
||||
if context.mode == 'EDIT_MESH' and not context.space_data.use_occlude_geometry:
|
||||
split = layout.split(percentage=0.1)
|
||||
split.separator()
|
||||
split2 = split.split()
|
||||
row = split2.row()
|
||||
row.prop(mesh_check, "finer_lines_behind_use")
|
||||
row.prop(mesh_check, "finer_lines_behind_use", icon="ORTHO")
|
||||
|
||||
|
||||
# ********** Edit Multiselect **********
|
||||
|
@ -735,6 +744,55 @@ class MeshExtraToolsSceneProps(PropertyGroup):
|
|||
default=(False,) * 4,
|
||||
size=4,
|
||||
)
|
||||
# Vertex align
|
||||
vert_align_store_axis = FloatVectorProperty(
|
||||
name="Define Custom Coordinates",
|
||||
description="Store the values of coordinates, for repeated use\n"
|
||||
"as a starting point",
|
||||
default=(0.0, 0.0, 0.0),
|
||||
min=-100.0, max=100.0,
|
||||
step=1, size=3,
|
||||
subtype='XYZ',
|
||||
precision=3
|
||||
)
|
||||
vert_align_use_stored = BoolProperty(
|
||||
name="Use Stored Coordinates",
|
||||
description="Use starting point coordinates for alignment",
|
||||
default=False
|
||||
)
|
||||
vert_align_to = EnumProperty(
|
||||
items=(('vertex', "Original vertex",
|
||||
"Use the stored vertex coordinates for aligning"),
|
||||
('coordinates', "Custom coordinates",
|
||||
"Use defined custom coordinates for aligning")),
|
||||
name="Align to",
|
||||
default='vertex'
|
||||
)
|
||||
vert_align_axis = BoolVectorProperty(
|
||||
name="Axis",
|
||||
description="Align to a specific Axis",
|
||||
default=(True, False, False),
|
||||
size=3,
|
||||
)
|
||||
# Mesh Info select
|
||||
mesh_info_show = BoolProperty(
|
||||
name="Show Face Info",
|
||||
description="Display the Object's Face Count information\n"
|
||||
"Note: it can have some performance impact on dense meshes\n"
|
||||
"Leave it closed if not needed or set the Delay to a higher value",
|
||||
default=False
|
||||
)
|
||||
mesh_info_delay = FloatProperty(
|
||||
name="Delay",
|
||||
description="Set the Update time Delay in seconds\n"
|
||||
"Set to zero to update with the UI refresh\n"
|
||||
"Higher values will sometimes need to hover over the cursor",
|
||||
default=2.0,
|
||||
min=0.0, max=20.0,
|
||||
step=100,
|
||||
subtype='TIME',
|
||||
precision=1
|
||||
)
|
||||
|
||||
|
||||
# Add-on Preferences
|
||||
|
@ -802,7 +860,7 @@ def register():
|
|||
vfe_specials.register()
|
||||
mesh_extrude_and_reshape.register()
|
||||
mesh_check.register()
|
||||
vertex_align.register()
|
||||
|
||||
bpy.utils.register_module(__name__)
|
||||
|
||||
# Register Scene Properties
|
||||
|
@ -827,7 +885,6 @@ def unregister():
|
|||
vfe_specials.unregister()
|
||||
mesh_extrude_and_reshape.unregister()
|
||||
mesh_check.unregister()
|
||||
vertex_align.unregister()
|
||||
|
||||
del bpy.types.Scene.mesh_extra_tools
|
||||
del bpy.types.Object.tkkey
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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 LICENCE BLOCK *****
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# based completely on addon by zmj100
|
||||
# added some distance limits to prevent overlap - max12345
|
||||
|
||||
|
@ -31,7 +31,10 @@ from bpy.props import (
|
|||
BoolProperty,
|
||||
EnumProperty,
|
||||
)
|
||||
from math import tan, cos, degrees, radians, sin
|
||||
from math import (
|
||||
sin, cos, tan,
|
||||
degrees, radians,
|
||||
)
|
||||
from mathutils import Matrix
|
||||
|
||||
|
||||
|
@ -97,11 +100,17 @@ def face_inset_fillet(bme, face_index_list, inset_amount, distance,
|
|||
val = ((f.normal).normalized() * h)
|
||||
if out is True:
|
||||
# this -(p - (vec2.normalized() * adj))) is just the freaking axis afaik...
|
||||
p6 = angle_rotation(p, p + val, -(p - (vec2.normalized() * adj)), -radians(90))
|
||||
p6 = angle_rotation(
|
||||
p, p + val,
|
||||
-(p - (vec2.normalized() * adj)),
|
||||
-radians(90)
|
||||
)
|
||||
else:
|
||||
p6 = angle_rotation(p, p - val,
|
||||
((p - (vec1.normalized() * adj)) - (p - (vec2.normalized() * adj))),
|
||||
-radians(90))
|
||||
p6 = angle_rotation(
|
||||
p, p - val,
|
||||
((p - (vec1.normalized() * adj)) - (p - (vec2.normalized() * adj))),
|
||||
-radians(90)
|
||||
)
|
||||
|
||||
orientation_vertex_list.append(p6)
|
||||
|
||||
|
@ -200,6 +209,7 @@ def face_inset_fillet(bme, face_index_list, inset_amount, distance,
|
|||
bme.faces.index_update()
|
||||
|
||||
del_ = [bme.faces.remove(f) for f in list_del]
|
||||
|
||||
if del_:
|
||||
del del_
|
||||
|
||||
|
@ -209,59 +219,59 @@ def face_inset_fillet(bme, face_index_list, inset_amount, distance,
|
|||
class MESH_OT_face_inset_fillet(Operator):
|
||||
bl_idname = "mesh.face_inset_fillet"
|
||||
bl_label = "Face Inset Fillet"
|
||||
bl_description = ("Inset selected and Fillet (make round) the corners of\n"
|
||||
bl_description = ("Inset selected and Fillet (make round) the corners \n"
|
||||
"of the newly created Faces")
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
# inset amount
|
||||
inset_amount = FloatProperty(
|
||||
name="Inset amount",
|
||||
description="Define the size of the Inset relative to the selection",
|
||||
default=0.04,
|
||||
min=0, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
name="Inset amount",
|
||||
description="Define the size of the Inset relative to the selection",
|
||||
default=0.04,
|
||||
min=0, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
# number of sides
|
||||
number_of_sides = IntProperty(
|
||||
name="Number of sides",
|
||||
description="Define the roundness of the corners by specifying\n"
|
||||
"the subdivision count",
|
||||
default=4,
|
||||
min=1, max=100,
|
||||
step=1
|
||||
)
|
||||
name="Number of sides",
|
||||
description="Define the roundness of the corners by specifying\n"
|
||||
"the subdivision count",
|
||||
default=4,
|
||||
min=1, max=100,
|
||||
step=1
|
||||
)
|
||||
distance = FloatProperty(
|
||||
name="",
|
||||
description="Use distance or radius for corners' size calculation",
|
||||
default=0.04,
|
||||
min=0.00001, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
name="",
|
||||
description="Use distance or radius for corners' size calculation",
|
||||
default=0.04,
|
||||
min=0.00001, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
out = BoolProperty(
|
||||
name="Outside",
|
||||
description="Inset the Faces outwards in relation to the selection\n"
|
||||
"Note: depending on the geometry, can give unsatisfactory results",
|
||||
default=False
|
||||
)
|
||||
name="Outside",
|
||||
description="Inset the Faces outwards in relation to the selection\n"
|
||||
"Note: depending on the geometry, can give unsatisfactory results",
|
||||
default=False
|
||||
)
|
||||
radius = BoolProperty(
|
||||
name="Radius",
|
||||
description="Use radius for corners' size calculation",
|
||||
default=False
|
||||
)
|
||||
name="Radius",
|
||||
description="Use radius for corners' size calculation",
|
||||
default=False
|
||||
)
|
||||
type_enum = EnumProperty(
|
||||
items=(('opt0', "N-gon", "N-gon corners - Keep the corner Faces uncut"),
|
||||
('opt1', "Triangle", "Triangulate corners")),
|
||||
name="Corner Type",
|
||||
default="opt0"
|
||||
)
|
||||
items=(('opt0', "N-gon", "N-gon corners - Keep the corner Faces uncut"),
|
||||
('opt1', "Triangle", "Triangulate corners")),
|
||||
name="Corner Type",
|
||||
default="opt0"
|
||||
)
|
||||
kp = BoolProperty(
|
||||
name="Keep faces",
|
||||
description="Do not delete the inside Faces\n"
|
||||
"Only available if the Out option is checked",
|
||||
default=False
|
||||
)
|
||||
name="Keep faces",
|
||||
description="Do not delete the inside Faces\n"
|
||||
"Only available if the Out option is checked",
|
||||
default=False
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -308,8 +318,10 @@ class MESH_OT_face_inset_fillet(Operator):
|
|||
face_index_list = [f.index for f in bme.faces if f.select and f.is_valid]
|
||||
|
||||
if len(face_index_list) == 0:
|
||||
self.report({'WARNING'}, "No suitable Face selection found. Operation cancelled")
|
||||
self.report({'WARNING'},
|
||||
"No suitable Face selection found. Operation cancelled")
|
||||
edit_mode_in()
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
||||
elif len(face_index_list) != 0:
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
import os
|
||||
import bpy
|
||||
import bpy.utils.previews
|
||||
|
||||
|
||||
mesh_check_icon_collections = {}
|
||||
mesh_check_icons_loaded = False
|
||||
|
||||
|
||||
|
||||
def load_icons():
|
||||
global mesh_check_icon_collections
|
||||
global mesh_check_icons_loaded
|
||||
|
||||
if mesh_check_icons_loaded: return mesh_check_icon_collections["main"]
|
||||
|
||||
|
||||
if mesh_check_icons_loaded:
|
||||
return mesh_check_icon_collections["main"]
|
||||
|
||||
custom_icons = bpy.utils.previews.new()
|
||||
|
||||
|
||||
icons_dir = os.path.join(os.path.dirname(__file__))
|
||||
|
||||
|
||||
custom_icons.load("ngons", os.path.join(icons_dir, "ngon.png"), 'IMAGE')
|
||||
custom_icons.load("triangles", os.path.join(icons_dir, "triangle.png"), 'IMAGE')
|
||||
|
||||
|
||||
mesh_check_icon_collections["main"] = custom_icons
|
||||
mesh_check_icons_loaded = True
|
||||
|
||||
|
||||
return mesh_check_icon_collections["main"]
|
||||
|
||||
|
||||
|
||||
def clear_icons():
|
||||
global mesh_check_icons_loaded
|
||||
for icon in mesh_check_icon_collections.values():
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
# gpl author: Pistiwique
|
||||
|
||||
bl_info = {"name": "Mesh Check BGL edition",
|
||||
"description": "Display the triangles and ngons of the mesh",
|
||||
"author": "Pistiwique",
|
||||
"version": (1, 0, 1),
|
||||
"blender": (2, 75, 0),
|
||||
"location": "3D View(s) -> Properties -> Shading",
|
||||
"category": "3D View"
|
||||
}
|
||||
bl_info = {
|
||||
"name": "Mesh Check BGL edition",
|
||||
"description": "Display the triangles and ngons of the mesh",
|
||||
"author": "Pistiwique",
|
||||
"version": (1, 0, 1),
|
||||
"blender": (2, 75, 0),
|
||||
"location": "3D View(s) > Properties > Shading",
|
||||
"category": "3D View"
|
||||
}
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
|
@ -180,10 +181,9 @@ def mesh_check_draw_callback():
|
|||
|
||||
for f in new_faces:
|
||||
faces.append([
|
||||
(
|
||||
(matrix_world * bm.verts[i].co)[0] + face.normal.x * 0.001,
|
||||
(matrix_world * bm.verts[i].co)[1] + face.normal.y * 0.001,
|
||||
(matrix_world * bm.verts[i].co)[2] + face.normal.z * 0.001)
|
||||
((matrix_world * bm.verts[i].co)[0] + face.normal.x * 0.001,
|
||||
(matrix_world * bm.verts[i].co)[1] + face.normal.y * 0.001,
|
||||
(matrix_world * bm.verts[i].co)[2] + face.normal.z * 0.001)
|
||||
for i in f]
|
||||
)
|
||||
|
||||
|
@ -220,24 +220,28 @@ def updateBGLData(self, context):
|
|||
edge_width[0] = self.edge_width
|
||||
finer_lines[0] = self.finer_lines_behind_use
|
||||
face_opacity[0] = self.face_opacity
|
||||
edges_tri_color[0] = (self.custom_tri_color[0],
|
||||
self.custom_tri_color[1],
|
||||
self.custom_tri_color[2],
|
||||
1)
|
||||
faces_tri_color[0] = (self.custom_tri_color[0],
|
||||
self.custom_tri_color[1],
|
||||
self.custom_tri_color[2],
|
||||
self.face_opacity)
|
||||
edges_ngons_color[0] = (self.custom_ngons_color[0],
|
||||
self.custom_ngons_color[1],
|
||||
self.custom_ngons_color[2],
|
||||
1)
|
||||
|
||||
faces_ngons_color[0] = (self.custom_ngons_color[0],
|
||||
self.custom_ngons_color[1],
|
||||
self.custom_ngons_color[2],
|
||||
self.face_opacity)
|
||||
|
||||
edges_tri_color[0] = (
|
||||
self.custom_tri_color[0],
|
||||
self.custom_tri_color[1],
|
||||
self.custom_tri_color[2],
|
||||
1)
|
||||
faces_tri_color[0] = (
|
||||
self.custom_tri_color[0],
|
||||
self.custom_tri_color[1],
|
||||
self.custom_tri_color[2],
|
||||
self.face_opacity
|
||||
)
|
||||
edges_ngons_color[0] = (
|
||||
self.custom_ngons_color[0],
|
||||
self.custom_ngons_color[1],
|
||||
self.custom_ngons_color[2],
|
||||
1)
|
||||
faces_ngons_color[0] = (
|
||||
self.custom_ngons_color[0],
|
||||
self.custom_ngons_color[1],
|
||||
self.custom_ngons_color[2],
|
||||
self.face_opacity
|
||||
)
|
||||
return
|
||||
|
||||
draw_enabled[0] = False
|
||||
|
@ -246,11 +250,13 @@ def updateBGLData(self, context):
|
|||
class FaceTypeSelect(Operator):
|
||||
bl_idname = "object.face_type_select"
|
||||
bl_label = "Face type select"
|
||||
bl_description = "Select Triangles and / or Ngons on the Active Object"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
face_type = EnumProperty(
|
||||
items=(('tris', 'Tris', ""),
|
||||
('ngons', 'Ngons', "")),
|
||||
name="Face Type",
|
||||
items=(('tris', "Tris", "Colorize Triangles in the Mesh"),
|
||||
('ngons', "Ngons", "Colorize Ngons in the Mesh")),
|
||||
default='ngons'
|
||||
)
|
||||
|
||||
|
@ -273,61 +279,61 @@ class FaceTypeSelect(Operator):
|
|||
|
||||
class MeshCheckCollectionGroup(PropertyGroup):
|
||||
mesh_check_use = BoolProperty(
|
||||
name="Mesh Check",
|
||||
description="Display Mesh Check options",
|
||||
default=False,
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Mesh Check",
|
||||
description="Display Mesh Check options",
|
||||
default=False,
|
||||
update=updateBGLData
|
||||
)
|
||||
display_faces = BoolProperty(
|
||||
name="Display Faces",
|
||||
description="Use BGL to display ngons en tris of the mesh",
|
||||
default=False,
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Display Faces",
|
||||
description="Use BGL to display Ngons and Tris of the mesh",
|
||||
default=False,
|
||||
update=updateBGLData
|
||||
)
|
||||
edge_width = FloatProperty(
|
||||
name="Width",
|
||||
description="Edges width in pixels",
|
||||
min=1.0,
|
||||
max=10.0,
|
||||
default=3.0,
|
||||
subtype='PIXEL',
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Width",
|
||||
description="Drawn Edges width in pixels",
|
||||
min=1.0,
|
||||
max=10.0,
|
||||
default=3.0,
|
||||
subtype='PIXEL',
|
||||
update=updateBGLData
|
||||
)
|
||||
finer_lines_behind_use = BoolProperty(
|
||||
name="Finer Lines behind",
|
||||
description="Display partially hidden edges finer in non-occlude mode",
|
||||
default=True,
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Finer Lines behind",
|
||||
description="Display partially hidden edges finer in non-occlude mode",
|
||||
default=True,
|
||||
update=updateBGLData
|
||||
)
|
||||
custom_tri_color = FloatVectorProperty(
|
||||
name="Tri Color",
|
||||
description="Custom color for the triangles",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=(1.0, 1.0, 0.0),
|
||||
size=3,
|
||||
subtype='COLOR',
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Tri Color",
|
||||
description="Custom color for the Triangles",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=(1.0, 1.0, 0.0),
|
||||
size=3,
|
||||
subtype='COLOR',
|
||||
update=updateBGLData
|
||||
)
|
||||
custom_ngons_color = FloatVectorProperty(
|
||||
name="Ngons Color",
|
||||
description="custom color for the ngons",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=(1.0, 0.0, 0.0),
|
||||
size=3,
|
||||
subtype='COLOR',
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Ngons Color",
|
||||
description="Custom color for the Ngons",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=(1.0, 0.0, 0.0),
|
||||
size=3,
|
||||
subtype='COLOR',
|
||||
update=updateBGLData
|
||||
)
|
||||
face_opacity = FloatProperty(
|
||||
name="Face Opacity",
|
||||
description="Opacity of the color for the face",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=0.2,
|
||||
subtype='FACTOR',
|
||||
update=updateBGLData
|
||||
)
|
||||
name="Face Opacity",
|
||||
description="Opacity of the color for the face",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=0.2,
|
||||
subtype='FACTOR',
|
||||
update=updateBGLData
|
||||
)
|
||||
|
||||
|
||||
# Register
|
||||
|
@ -340,6 +346,7 @@ classes = (
|
|||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.WindowManager.mesh_check = PointerProperty(
|
||||
type=MeshCheckCollectionGroup
|
||||
)
|
||||
|
@ -354,6 +361,7 @@ def unregister():
|
|||
if mesh_check_handle:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(mesh_check_handle[0], 'WINDOW')
|
||||
mesh_check_handle[:] = []
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ bl_info = {
|
|||
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
from bpy.types import Operator
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
|
@ -99,7 +98,8 @@ def get_edge_rings(bm, keep_caps=True):
|
|||
try:
|
||||
# generate a list of edges to select:
|
||||
# traversing only tagged faces, since calc_face can walk and untag islands
|
||||
for face in filter(lambda f: f.tag, selected_faces): edges += calc_face(face, keep_caps)
|
||||
for face in filter(lambda f: f.tag, selected_faces):
|
||||
edges += calc_face(face, keep_caps)
|
||||
finally:
|
||||
# housekeeping: clear tags
|
||||
for face in selected_faces:
|
||||
|
@ -165,32 +165,32 @@ class MESH_xOT_cut_faces(Operator):
|
|||
SUBD_STRAIGHT_CUT = 3
|
||||
|
||||
num_cuts = IntProperty(
|
||||
name="Number of Cuts",
|
||||
default=1,
|
||||
min=1,
|
||||
max=100,
|
||||
subtype='UNSIGNED'
|
||||
)
|
||||
name="Number of Cuts",
|
||||
default=1,
|
||||
min=1,
|
||||
max=100,
|
||||
subtype='UNSIGNED'
|
||||
)
|
||||
use_single_edge = BoolProperty(
|
||||
name="Quad/Tri Mode",
|
||||
description="Cut boundary faces",
|
||||
default=False
|
||||
)
|
||||
name="Quad/Tri Mode",
|
||||
description="Cut boundary faces",
|
||||
default=False
|
||||
)
|
||||
corner_type = EnumProperty(
|
||||
items=[('SUBD_INNERVERT', "Inner Vert", ""),
|
||||
('SUBD_PATH', "Path", ""),
|
||||
('SUBD_FAN', "Fan", ""),
|
||||
('SUBD_STRAIGHT_CUT', "Straight Cut", ""),
|
||||
],
|
||||
name="Quad Corner Type",
|
||||
description="How to subdivide quad corners",
|
||||
default='SUBD_STRAIGHT_CUT'
|
||||
)
|
||||
items=[('SUBD_INNERVERT', "Inner Vert", ""),
|
||||
('SUBD_PATH', "Path", ""),
|
||||
('SUBD_FAN', "Fan", ""),
|
||||
('SUBD_STRAIGHT_CUT', "Straight Cut", ""),
|
||||
],
|
||||
name="Quad Corner Type",
|
||||
description="How to subdivide quad corners",
|
||||
default='SUBD_STRAIGHT_CUT'
|
||||
)
|
||||
use_grid_fill = BoolProperty(
|
||||
name="Use Grid Fill",
|
||||
description="Fill fully enclosed faces with a grid",
|
||||
default=True
|
||||
)
|
||||
name="Use Grid Fill",
|
||||
description="Fill fully enclosed faces with a grid",
|
||||
default=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -216,17 +216,18 @@ class MESH_xOT_cut_faces(Operator):
|
|||
try:
|
||||
edges = get_edge_rings(bm, keep_caps=True)
|
||||
if not edges:
|
||||
self.report({'WARNING'}, "No suitable Face selection found. Operation cancelled")
|
||||
self.report({'WARNING'},
|
||||
"No suitable Face selection found. Operation cancelled")
|
||||
return False
|
||||
|
||||
result = bmesh.ops.subdivide_edges(
|
||||
bm,
|
||||
edges=edges,
|
||||
cuts=int(self.num_cuts),
|
||||
use_grid_fill=bool(self.use_grid_fill),
|
||||
use_single_edge=bool(self.use_single_edge),
|
||||
quad_corner_type=eval("self." + self.corner_type))
|
||||
|
||||
bm,
|
||||
edges=edges,
|
||||
cuts=int(self.num_cuts),
|
||||
use_grid_fill=bool(self.use_grid_fill),
|
||||
use_single_edge=bool(self.use_single_edge),
|
||||
quad_corner_type=eval("self." + self.corner_type)
|
||||
)
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
bm.select_mode = {'EDGE'}
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
bl_info = {
|
||||
"name": "Edge Roundifier",
|
||||
|
@ -22,10 +22,10 @@ bl_info = {
|
|||
"author": "Piotr Komisarczyk (komi3D), PKHG",
|
||||
"version": (1, 0, 0),
|
||||
"blender": (2, 7, 3),
|
||||
"location": "SPACE > Edge Roundifier or CTRL-E > Edge Roundifier or Tools > Addons > Edge Roundifier",
|
||||
"location": "SPACE > Edge Roundifier or CTRL-E > "
|
||||
"Edge Roundifier or Tools > Addons > Edge Roundifier",
|
||||
"description": "Mesh editing script allowing edge rounding",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,14 @@ from bpy.props import (
|
|||
EnumProperty,
|
||||
IntProperty,
|
||||
)
|
||||
|
||||
from math import sqrt, acos, pi, radians, degrees, sin
|
||||
from mathutils import Vector, Euler, Quaternion
|
||||
from math import (
|
||||
sqrt, acos, pi,
|
||||
radians, degrees, sin,
|
||||
)
|
||||
from mathutils import (
|
||||
Vector, Euler,
|
||||
Quaternion,
|
||||
)
|
||||
|
||||
# CONSTANTS
|
||||
two_pi = 2 * pi
|
||||
|
@ -79,7 +84,6 @@ class CalculationHelper:
|
|||
"""
|
||||
Constructor
|
||||
"""
|
||||
|
||||
def getLineCoefficientsPerpendicularToVectorInPoint(self, point, vector, plane):
|
||||
x, y, z = point
|
||||
xVector, yVector, zVector = vector
|
||||
|
@ -92,7 +96,7 @@ class CalculationHelper:
|
|||
|
||||
def getQuadraticRoots(self, coef):
|
||||
if len(coef) != 3:
|
||||
return NaN # TODO lijenstina: Is this a valid return?
|
||||
return None # Replaced NaN with None
|
||||
else:
|
||||
a, b, c = coef
|
||||
delta = b ** 2 - 4 * a * c
|
||||
|
@ -155,7 +159,8 @@ class CalculationHelper:
|
|||
else:
|
||||
return None
|
||||
|
||||
def getLineCircleIntersectionsWhenXPerpendicular(self, edgeCenter, circleMidPoint, radius, plane):
|
||||
def getLineCircleIntersectionsWhenXPerpendicular(self, edgeCenter,
|
||||
circleMidPoint, radius, plane):
|
||||
# (x - a)**2 + (y - b)**2 = r**2 - circle equation
|
||||
# x = xValue - line equation
|
||||
# f * x**2 + g * x + h = 0 - quadratic equation
|
||||
|
@ -194,8 +199,8 @@ class CalculationHelper:
|
|||
|
||||
# get two of three coordinates used for further calculation of spin center
|
||||
# PKHG>nice if rescriction to these 3 types or planes is to be done
|
||||
# komi3D> from 0.0.2 there is a restriction. In future I would like Edge Roundifier to work on
|
||||
# komi3D> Normal and View coordinate systems. That would be great
|
||||
# komi3D> from 0.0.2 there is a restriction. In future I would like Edge
|
||||
# komi3D> Roundifier to work on Normal and View coordinate systems
|
||||
def getCircleMidPointOnPlane(self, V1, plane):
|
||||
X = V1[0]
|
||||
Y = V1[1]
|
||||
|
@ -260,206 +265,206 @@ class EdgeRoundifier(Operator):
|
|||
obj = None
|
||||
|
||||
edgeScaleFactor = FloatProperty(
|
||||
name="",
|
||||
description="Set the Factor of scaling",
|
||||
default=1.0,
|
||||
min=0.00001, max=100000.0,
|
||||
step=0.5,
|
||||
precision=5
|
||||
)
|
||||
name="",
|
||||
description="Set the Factor of scaling",
|
||||
default=1.0,
|
||||
min=0.00001, max=100000.0,
|
||||
step=0.5,
|
||||
precision=5
|
||||
)
|
||||
r = FloatProperty(
|
||||
name="",
|
||||
description="User Defined arc steepness by a Radius\n"
|
||||
"Enabled only if Entry mode is set to Radius\n",
|
||||
default=1,
|
||||
min=0.00001, max=1000.0,
|
||||
step=0.1,
|
||||
precision=3
|
||||
)
|
||||
name="",
|
||||
description="User Defined arc steepness by a Radius\n"
|
||||
"Enabled only if Entry mode is set to Radius\n",
|
||||
default=1,
|
||||
min=0.00001, max=1000.0,
|
||||
step=0.1,
|
||||
precision=3
|
||||
)
|
||||
a = FloatProperty(
|
||||
name="",
|
||||
description="User defined arc steepness calculated from an Angle\n"
|
||||
"Enabled only if Entry mode is set to Angle and\n"
|
||||
"Angle presets is set Other",
|
||||
default=180.0,
|
||||
min=0.1, max=180.0,
|
||||
step=0.5,
|
||||
precision=1
|
||||
)
|
||||
name="",
|
||||
description="User defined arc steepness calculated from an Angle\n"
|
||||
"Enabled only if Entry mode is set to Angle and\n"
|
||||
"Angle presets is set Other",
|
||||
default=180.0,
|
||||
min=0.1, max=180.0,
|
||||
step=0.5,
|
||||
precision=1
|
||||
)
|
||||
n = IntProperty(
|
||||
name="",
|
||||
description="Arc subdivision level",
|
||||
default=4,
|
||||
min=1, max=100,
|
||||
step=1
|
||||
)
|
||||
name="",
|
||||
description="Arc subdivision level",
|
||||
default=4,
|
||||
min=1, max=100,
|
||||
step=1
|
||||
)
|
||||
flip = BoolProperty(
|
||||
name="Flip",
|
||||
description="If True, flip the side of the selected edges where the arcs are drawn",
|
||||
default=False
|
||||
)
|
||||
name="Flip",
|
||||
description="If True, flip the side of the selected edges where the arcs are drawn",
|
||||
default=False
|
||||
)
|
||||
invertAngle = BoolProperty(
|
||||
name="Invert",
|
||||
description="If True, uses an inverted angle to draw the arc (360 degrees - angle)",
|
||||
default=False
|
||||
)
|
||||
name="Invert",
|
||||
description="If True, uses an inverted angle to draw the arc (360 degrees - angle)",
|
||||
default=False
|
||||
)
|
||||
fullCircles = BoolProperty(
|
||||
name="Circles",
|
||||
description="If True, uses an angle of 360 degrees to draw the arcs",
|
||||
default=False
|
||||
)
|
||||
name="Circles",
|
||||
description="If True, uses an angle of 360 degrees to draw the arcs",
|
||||
default=False
|
||||
)
|
||||
bothSides = BoolProperty(
|
||||
name="Both sides",
|
||||
description="If True, draw arcs on both sides of the selected edges",
|
||||
default=False
|
||||
)
|
||||
name="Both sides",
|
||||
description="If True, draw arcs on both sides of the selected edges",
|
||||
default=False
|
||||
)
|
||||
drawArcCenters = BoolProperty(
|
||||
name="Centers",
|
||||
description="If True, draws a vertex for each spin center",
|
||||
default=False
|
||||
)
|
||||
name="Centers",
|
||||
description="If True, draws a vertex for each spin center",
|
||||
default=False
|
||||
)
|
||||
removeEdges = BoolProperty(
|
||||
name="Edges",
|
||||
description="If True removes the Original selected edges",
|
||||
default=False
|
||||
)
|
||||
name="Edges",
|
||||
description="If True removes the Original selected edges",
|
||||
default=False
|
||||
)
|
||||
removeScaledEdges = BoolProperty(
|
||||
name="Scaled edges",
|
||||
description="If True removes the Scaled edges (not part of the arcs)",
|
||||
default=False
|
||||
)
|
||||
name="Scaled edges",
|
||||
description="If True removes the Scaled edges (not part of the arcs)",
|
||||
default=False
|
||||
)
|
||||
connectArcWithEdge = BoolProperty(
|
||||
name="Arc - Edge",
|
||||
description="Connect Arcs to Edges",
|
||||
default=False
|
||||
)
|
||||
name="Arc - Edge",
|
||||
description="Connect Arcs to Edges",
|
||||
default=False
|
||||
)
|
||||
connectArcs = BoolProperty(
|
||||
name="Arcs",
|
||||
description="Connect subsequent Arcs",
|
||||
default=False
|
||||
)
|
||||
name="Arcs",
|
||||
description="Connect subsequent Arcs",
|
||||
default=False
|
||||
)
|
||||
connectScaledAndBase = BoolProperty(
|
||||
name="Scaled - Base Edge",
|
||||
description="Connect Scaled to Base Edge",
|
||||
default=False
|
||||
)
|
||||
name="Scaled - Base Edge",
|
||||
description="Connect Scaled to Base Edge",
|
||||
default=False
|
||||
)
|
||||
connectArcsFlip = BoolProperty(
|
||||
name="Flip Arcs",
|
||||
description="Flip the connection of subsequent Arcs",
|
||||
default=False
|
||||
)
|
||||
name="Flip Arcs",
|
||||
description="Flip the connection of subsequent Arcs",
|
||||
default=False
|
||||
)
|
||||
connectArcWithEdgeFlip = BoolProperty(
|
||||
name="Flip Arc - Edge",
|
||||
description="Flip the connection of the Arcs to Edges",
|
||||
default=False
|
||||
)
|
||||
name="Flip Arc - Edge",
|
||||
description="Flip the connection of the Arcs to Edges",
|
||||
default=False
|
||||
)
|
||||
axisAngle = FloatProperty(
|
||||
name="",
|
||||
description="Rotate Arc around the perpendicular axis",
|
||||
default=0.0,
|
||||
min=-180.0, max=180.0,
|
||||
step=0.5,
|
||||
precision=1
|
||||
)
|
||||
name="",
|
||||
description="Rotate Arc around the perpendicular axis",
|
||||
default=0.0,
|
||||
min=-180.0, max=180.0,
|
||||
step=0.5,
|
||||
precision=1
|
||||
)
|
||||
edgeAngle = FloatProperty(
|
||||
name="",
|
||||
description="Rotate Arc around the Edge (Edge acts like as the axis)",
|
||||
default=0.0,
|
||||
min=-180.0, max=180.0,
|
||||
step=0.5,
|
||||
precision=1
|
||||
)
|
||||
name="",
|
||||
description="Rotate Arc around the Edge (Edge acts like as the axis)",
|
||||
default=0.0,
|
||||
min=-180.0, max=180.0,
|
||||
step=0.5,
|
||||
precision=1
|
||||
)
|
||||
offset = FloatProperty(
|
||||
name="",
|
||||
description="Offset Arc perpendicular the Edge",
|
||||
default=0.0,
|
||||
min=-1000000.0, max=1000000.0,
|
||||
step=0.1,
|
||||
precision=5
|
||||
)
|
||||
name="",
|
||||
description="Offset Arc perpendicular the Edge",
|
||||
default=0.0,
|
||||
min=-1000000.0, max=1000000.0,
|
||||
step=0.1,
|
||||
precision=5
|
||||
)
|
||||
offset2 = FloatProperty(
|
||||
name="",
|
||||
description="Offset Arc in parallel to the Edge",
|
||||
default=0.0,
|
||||
min=-1000000.0, max=1000000.0,
|
||||
step=0.1,
|
||||
precision=5
|
||||
)
|
||||
name="",
|
||||
description="Offset Arc in parallel to the Edge",
|
||||
default=0.0,
|
||||
min=-1000000.0, max=1000000.0,
|
||||
step=0.1,
|
||||
precision=5
|
||||
)
|
||||
ellipticFactor = FloatProperty(
|
||||
name="",
|
||||
description="Make Arc elliptic",
|
||||
default=0.0,
|
||||
min=-1000000.0, max=1000000.0,
|
||||
step=0.1,
|
||||
precision=5
|
||||
)
|
||||
name="",
|
||||
description="Make Arc elliptic",
|
||||
default=0.0,
|
||||
min=-1000000.0, max=1000000.0,
|
||||
step=0.1,
|
||||
precision=5
|
||||
)
|
||||
workModeItems = [("Normal", "Normal", ""), ("Reset", "Reset", "")]
|
||||
workMode = EnumProperty(
|
||||
items=workModeItems,
|
||||
name="",
|
||||
default='Normal',
|
||||
description="Normal work with the current given paramaters set by the user\n"
|
||||
"Reset - changes back the parameters to their default values"
|
||||
)
|
||||
items=workModeItems,
|
||||
name="",
|
||||
default='Normal',
|
||||
description="Normal work with the current given paramaters set by the user\n"
|
||||
"Reset - changes back the parameters to their default values"
|
||||
)
|
||||
entryModeItems = [("Radius", "Radius", ""), ("Angle", "Angle", "")]
|
||||
entryMode = EnumProperty(
|
||||
items=entryModeItems,
|
||||
name="",
|
||||
default='Angle',
|
||||
description="Entry mode switch between Angle and Radius\n"
|
||||
"If Angle is selected, arc radius is calculated from it"
|
||||
)
|
||||
items=entryModeItems,
|
||||
name="",
|
||||
default='Angle',
|
||||
description="Entry mode switch between Angle and Radius\n"
|
||||
"If Angle is selected, arc radius is calculated from it"
|
||||
)
|
||||
rotateCenterItems = [("Spin", "Spin", ""), ("V1", "V1", ""),
|
||||
("Edge", "Edge", ""), ("V2", "V2", "")]
|
||||
rotateCenter = EnumProperty(
|
||||
items=rotateCenterItems,
|
||||
name="",
|
||||
default='Edge',
|
||||
description="Rotate center for spin axis rotate"
|
||||
)
|
||||
items=rotateCenterItems,
|
||||
name="",
|
||||
default='Edge',
|
||||
description="Rotate center for spin axis rotate"
|
||||
)
|
||||
arcModeItems = [("FullEdgeArc", "Full", "Full"), ('HalfEdgeArc', "Half", "Half")]
|
||||
arcMode = EnumProperty(
|
||||
items=arcModeItems,
|
||||
name="",
|
||||
default='FullEdgeArc',
|
||||
description="Arc mode - switch between Full and Half arcs"
|
||||
)
|
||||
items=arcModeItems,
|
||||
name="",
|
||||
default='FullEdgeArc',
|
||||
description="Arc mode - switch between Full and Half arcs"
|
||||
)
|
||||
angleItems = [('Other', "Other", "User defined angle"), ('180', "180", "HemiCircle (2 sides)"),
|
||||
('120', "120", "TriangleCircle (3 sides)"), ('90', "90", "QuadCircle (4 sides)"),
|
||||
('72', "72", "PentagonCircle (5 sides)"), ('60', "60", "HexagonCircle (6 sides)"),
|
||||
('45', "45", "OctagonCircle (8 sides)"), ('30', "30", "DodecagonCircle (12 sides)")]
|
||||
angleEnum = EnumProperty(
|
||||
items=angleItems,
|
||||
name="",
|
||||
default='180',
|
||||
description="Presets prepare standard angles and calculate proper ray"
|
||||
)
|
||||
items=angleItems,
|
||||
name="",
|
||||
default='180',
|
||||
description="Presets prepare standard angles and calculate proper ray"
|
||||
)
|
||||
refItems = [('ORG', "Origin", "Use Origin Location"), ('CUR', "3D Cursor", "Use 3DCursor Location"),
|
||||
('EDG', "Edge", "Use Individual Edge Reference")]
|
||||
referenceLocation = EnumProperty(
|
||||
items=refItems,
|
||||
name="",
|
||||
default='ORG',
|
||||
description="Reference location used to calculate initial centers of drawn arcs"
|
||||
)
|
||||
items=refItems,
|
||||
name="",
|
||||
default='ORG',
|
||||
description="Reference location used to calculate initial centers of drawn arcs"
|
||||
)
|
||||
planeItems = [(XY, "XY", "XY Plane (Z=0)"),
|
||||
(YZ, "YZ", "YZ Plane (X=0)"),
|
||||
(XZ, "XZ", "XZ Plane (Y=0)")]
|
||||
planeEnum = EnumProperty(
|
||||
items=planeItems,
|
||||
name="",
|
||||
default='XY',
|
||||
description="Plane used to calculate spin plane of drawn arcs"
|
||||
)
|
||||
items=planeItems,
|
||||
name="",
|
||||
default='XY',
|
||||
description="Plane used to calculate spin plane of drawn arcs"
|
||||
)
|
||||
edgeScaleCenterItems = [('V1', "V1", "v1 - First Edge's Vertex"),
|
||||
('CENTER', "Center", "Center of the Edge"),
|
||||
('V2', "V2", "v2 - Second Edge's Vertex")]
|
||||
edgeScaleCenterEnum = EnumProperty(
|
||||
items=edgeScaleCenterItems,
|
||||
name="Edge scale center",
|
||||
default='CENTER',
|
||||
description="Center used for scaling the initial edge"
|
||||
)
|
||||
items=edgeScaleCenterItems,
|
||||
name="Edge scale center",
|
||||
default='CENTER',
|
||||
description="Center used for scaling the initial edge"
|
||||
)
|
||||
|
||||
calc = CalculationHelper()
|
||||
sel = SelectionHelper()
|
||||
|
@ -628,12 +633,8 @@ class EdgeRoundifier(Operator):
|
|||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bm.to_mesh(mesh)
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='TOGGLE')
|
||||
bpy.ops.mesh.select_all(action='INVERT')
|
||||
bpy.ops.mesh.remove_doubles()
|
||||
|
||||
|
||||
bm.free()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def resetValues(self, workMode):
|
||||
|
@ -753,10 +754,16 @@ class EdgeRoundifier(Operator):
|
|||
return arcVerts
|
||||
|
||||
def spinAndPostprocess(self, edge, parameters, bm, mesh, edgeCenter, roundifyParams):
|
||||
spinnedVerts, roundifyParamsUpdated = self.drawSpin(edge, edgeCenter,
|
||||
roundifyParams, parameters, bm, mesh)
|
||||
postProcessedArcVerts = self.arcPostprocessing(edge, parameters, bm, mesh,
|
||||
roundifyParamsUpdated, spinnedVerts, edgeCenter)
|
||||
spinnedVerts, roundifyParamsUpdated = self.drawSpin(
|
||||
edge, edgeCenter,
|
||||
roundifyParams,
|
||||
parameters, bm, mesh
|
||||
)
|
||||
postProcessedArcVerts = self.arcPostprocessing(
|
||||
edge, parameters, bm, mesh,
|
||||
roundifyParamsUpdated,
|
||||
spinnedVerts, edgeCenter
|
||||
)
|
||||
return postProcessedArcVerts
|
||||
|
||||
def rotateArcAroundEdge(self, bm, mesh, arcVerts, parameters):
|
||||
|
@ -768,9 +775,11 @@ class EdgeRoundifier(Operator):
|
|||
def arc_rotator(self, arcVerts, extra_rotation, parameters):
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
old_location = self.obj.location.copy()
|
||||
bpy.ops.transform.translate(value=- old_location, constraint_axis=(False, False, False),
|
||||
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
|
||||
proportional_edit_falloff='SMOOTH', proportional_size=1)
|
||||
bpy.ops.transform.translate(
|
||||
value=-old_location, constraint_axis=(False, False, False),
|
||||
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
|
||||
proportional_edit_falloff='SMOOTH', proportional_size=1
|
||||
)
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
adjust_matrix = self.obj.matrix_parent_inverse
|
||||
bm = bmesh.from_edit_mesh(self.obj.data)
|
||||
|
@ -797,9 +806,11 @@ class EdgeRoundifier(Operator):
|
|||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
# PKHG>INFO move origin object back print("old location = " , old_location)
|
||||
bpy.ops.transform.translate(value=old_location, constraint_axis=(False, False, False),
|
||||
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
|
||||
proportional_edit_falloff='SMOOTH', proportional_size=1)
|
||||
bpy.ops.transform.translate(
|
||||
value=old_location, constraint_axis=(False, False, False),
|
||||
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
|
||||
proportional_edit_falloff='SMOOTH', proportional_size=1
|
||||
)
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
def makeElliptic(self, bm, mesh, arcVertices, parameters):
|
||||
|
@ -826,21 +837,37 @@ class EdgeRoundifier(Operator):
|
|||
[chosenSpinCenter, otherSpinCenter, spinAxis, angle, steps, refObjectLocation] = roundifyParams
|
||||
rotatedVerts = []
|
||||
if parameters["rotateCenter"] == 'Edge':
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(bm, mesh, spinnedVerts, parameters, edgeCenter)
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(
|
||||
bm, mesh, spinnedVerts, parameters, edgeCenter
|
||||
)
|
||||
elif parameters["rotateCenter"] == 'Spin':
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(bm, mesh, spinnedVerts, parameters, chosenSpinCenter)
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(
|
||||
bm, mesh, spinnedVerts, parameters, chosenSpinCenter
|
||||
)
|
||||
elif parameters["rotateCenter"] == 'V1':
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(bm, mesh, spinnedVerts, parameters, edge.verts[0].co)
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(
|
||||
bm, mesh, spinnedVerts, parameters, edge.verts[0].co
|
||||
)
|
||||
elif parameters["rotateCenter"] == 'V2':
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(bm, mesh, spinnedVerts, parameters, edge.verts[1].co)
|
||||
rotatedVerts = self.rotateArcAroundSpinAxis(
|
||||
bm, mesh, spinnedVerts, parameters, edge.verts[1].co
|
||||
)
|
||||
|
||||
offsetVerts = self.offsetArcPerpendicular(bm, mesh, rotatedVerts, edge, parameters)
|
||||
offsetVerts2 = self.offsetArcParallel(bm, mesh, offsetVerts, edge, parameters)
|
||||
ellipticVerts = self.makeElliptic(bm, mesh, offsetVerts2, parameters)
|
||||
offsetVerts = self.offsetArcPerpendicular(
|
||||
bm, mesh, rotatedVerts, edge, parameters
|
||||
)
|
||||
offsetVerts2 = self.offsetArcParallel(
|
||||
bm, mesh, offsetVerts, edge, parameters
|
||||
)
|
||||
ellipticVerts = self.makeElliptic(
|
||||
bm, mesh, offsetVerts2, parameters
|
||||
)
|
||||
self.rotateArcAroundEdge(bm, mesh, ellipticVerts, parameters)
|
||||
|
||||
if parameters["connectArcWithEdge"]:
|
||||
self.connectArcTogetherWithEdge(edge, offsetVerts2, bm, mesh, parameters)
|
||||
self.connectArcTogetherWithEdge(
|
||||
edge, offsetVerts2, bm, mesh, parameters
|
||||
)
|
||||
return offsetVerts2
|
||||
|
||||
def connectArcTogetherWithEdge(self, edge, arcVertices, bm, mesh, parameters):
|
||||
|
@ -884,8 +911,10 @@ class EdgeRoundifier(Operator):
|
|||
|
||||
def connectArcsTogether(self, arcs, bm, mesh, parameters):
|
||||
for i in range(0, len(arcs) - 1):
|
||||
if arcs[i] is None or arcs[i + 1] is None: # in case on XZ or YZ there are no arcs drawn
|
||||
# in case on XZ or YZ there are no arcs drawn
|
||||
if arcs[i] is None or arcs[i + 1] is None:
|
||||
return
|
||||
|
||||
lastVert = len(arcs[i]) - 1
|
||||
if parameters["drawArcCenters"]:
|
||||
lastVert = lastVert - 1 # center gets added as last vert of arc
|
||||
|
@ -906,7 +935,9 @@ class EdgeRoundifier(Operator):
|
|||
lastArcId = len(arcs) - 1
|
||||
lastVertIdOfLastArc = len(arcs[lastArcId]) - 1
|
||||
if parameters["drawArcCenters"]:
|
||||
lastVertIdOfLastArc = lastVertIdOfLastArc - 1 # center gets added as last vert of arc
|
||||
# center gets added as last vert of arc
|
||||
lastVertIdOfLastArc = lastVertIdOfLastArc - 1
|
||||
|
||||
V1 = arcs[lastArcId][lastVertIdOfLastArc].co
|
||||
V2 = arcs[0][0].co
|
||||
if parameters["connectArcsFlip"]:
|
||||
|
@ -976,20 +1007,22 @@ class EdgeRoundifier(Operator):
|
|||
|
||||
debugPrintNew(d_Plane, "PLANE: " + parameters["plane"])
|
||||
lineAB = self.calc.getLineCoefficientsPerpendicularToVectorInPoint(
|
||||
edgeCenter, edgeVector,
|
||||
parameters["plane"]
|
||||
)
|
||||
edgeCenter, edgeVector,
|
||||
parameters["plane"]
|
||||
)
|
||||
circleMidPoint = V1
|
||||
circleMidPointOnPlane = self.calc.getCircleMidPointOnPlane(V1, parameters["plane"])
|
||||
circleMidPointOnPlane = self.calc.getCircleMidPointOnPlane(
|
||||
V1, parameters["plane"]
|
||||
)
|
||||
radius = parameters["radius"]
|
||||
|
||||
angle = 0
|
||||
if (parameters["entryMode"] == 'Angle'):
|
||||
if (parameters["angleEnum"] != 'Other'):
|
||||
radius, angle = self.CalculateRadiusAndAngleForAnglePresets(
|
||||
parameters["angleEnum"], radius,
|
||||
angle, edgeLength
|
||||
)
|
||||
parameters["angleEnum"], radius,
|
||||
angle, edgeLength
|
||||
)
|
||||
else:
|
||||
radius, angle = self.CalculateRadiusAndAngle(edgeLength)
|
||||
debugPrintNew(d_Radius_Angle, "RADIUS = " + str(radius) + " ANGLE = " + str(angle))
|
||||
|
@ -997,14 +1030,17 @@ class EdgeRoundifier(Operator):
|
|||
if angle != pi: # mode other than 180
|
||||
if lineAB is None:
|
||||
roots = self.calc.getLineCircleIntersectionsWhenXPerpendicular(
|
||||
edgeCenter, circleMidPointOnPlane,
|
||||
radius, parameters["plane"]
|
||||
)
|
||||
edgeCenter, circleMidPointOnPlane,
|
||||
radius, parameters["plane"]
|
||||
)
|
||||
else:
|
||||
roots = self.calc.getLineCircleIntersections(lineAB, circleMidPointOnPlane, radius)
|
||||
roots = self.calc.getLineCircleIntersections(
|
||||
lineAB, circleMidPointOnPlane, radius
|
||||
)
|
||||
|
||||
if roots is None:
|
||||
debugPrintNew(True, "[Edge Roundifier]: No centers were found. Change radius to higher value")
|
||||
debugPrintNew(True,
|
||||
"[Edge Roundifier]: No centers were found. Change radius to higher value")
|
||||
return None
|
||||
roots = self.addMissingCoordinate(roots, V1, parameters["plane"]) # adds X, Y or Z coordinate
|
||||
else:
|
||||
|
@ -1022,7 +1058,9 @@ class EdgeRoundifier(Operator):
|
|||
refObjectLocation = self.calc.getEdgeReference(edge, edgeCenter, parameters["plane"])
|
||||
|
||||
debugPrintNew(d_RefObject, parameters["refObject"], refObjectLocation)
|
||||
chosenSpinCenter, otherSpinCenter = self.getSpinCenterClosestToRefCenter(refObjectLocation, roots)
|
||||
chosenSpinCenter, otherSpinCenter = self.getSpinCenterClosestToRefCenter(
|
||||
refObjectLocation, roots
|
||||
)
|
||||
|
||||
if (parameters["entryMode"] == "Radius"):
|
||||
halfAngle = self.calc.getAngle(edgeCenter, chosenSpinCenter, circleMidPoint)
|
||||
|
@ -1059,8 +1097,10 @@ class EdgeRoundifier(Operator):
|
|||
|
||||
v0 = bm.verts.new(v0org.co)
|
||||
|
||||
result = bmesh.ops.spin(bm, geom=[v0], cent=chosenSpinCenter, axis=spinAxis,
|
||||
angle=angle, steps=steps, use_duplicate=False)
|
||||
result = bmesh.ops.spin(
|
||||
bm, geom=[v0], cent=chosenSpinCenter, axis=spinAxis,
|
||||
angle=angle, steps=steps, use_duplicate=False
|
||||
)
|
||||
|
||||
# it seems there is something wrong with last index of this spin
|
||||
# I need to calculate the last index manually here
|
||||
|
@ -1088,21 +1128,21 @@ class EdgeRoundifier(Operator):
|
|||
if ((parameters["invertAngle"]) or (parameters["flip"])):
|
||||
if (midVertexDistance > midEdgeDistance):
|
||||
alternativeLastSpinVertIndices = self.alternateSpin(
|
||||
bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices
|
||||
)
|
||||
bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices
|
||||
)
|
||||
else:
|
||||
if (midVertexDistance < midEdgeDistance):
|
||||
alternativeLastSpinVertIndices = self.alternateSpin(
|
||||
bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices
|
||||
)
|
||||
bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices
|
||||
)
|
||||
elif (angle != two_pi): # to allow full circles
|
||||
if (result['geom_last'][0].co - v1org.co).length > SPIN_END_THRESHOLD:
|
||||
alternativeLastSpinVertIndices = self.alternateSpin(
|
||||
bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices
|
||||
)
|
||||
bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices
|
||||
)
|
||||
alternate = True
|
||||
|
||||
self.sel.refreshMesh(bm, mesh)
|
||||
|
@ -1120,19 +1160,19 @@ class EdgeRoundifier(Operator):
|
|||
# do some more testing here!!!
|
||||
if (angle == pi or angle == -pi):
|
||||
alternativeLastSpinVertIndices = self.alternateSpinNoDelete(
|
||||
bm, mesh, -angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, []
|
||||
)
|
||||
bm, mesh, -angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, []
|
||||
)
|
||||
elif alternate:
|
||||
alternativeLastSpinVertIndices = self.alternateSpinNoDelete(
|
||||
bm, mesh, angle, otherSpinCenter,
|
||||
spinAxis, steps, v0, v1org, []
|
||||
)
|
||||
bm, mesh, angle, otherSpinCenter,
|
||||
spinAxis, steps, v0, v1org, []
|
||||
)
|
||||
elif not alternate:
|
||||
alternativeLastSpinVertIndices = self.alternateSpinNoDelete(
|
||||
bm, mesh, -angle, otherSpinCenter,
|
||||
spinAxis, steps, v0, v1org, []
|
||||
)
|
||||
bm, mesh, -angle, otherSpinCenter,
|
||||
spinAxis, steps, v0, v1org, []
|
||||
)
|
||||
bothSpinVertices = [bm.verts[i] for i in lastSpinVertIndices]
|
||||
alternativeSpinVertices = [bm.verts[i] for i in alternativeLastSpinVertIndices]
|
||||
bothSpinVertices = [v0] + bothSpinVertices + alternativeSpinVertices
|
||||
|
@ -1175,12 +1215,16 @@ class EdgeRoundifier(Operator):
|
|||
lastSpinVertIndices2 = self.getLastSpinVertIndices(steps, lastVertIndex2)
|
||||
return lastSpinVertIndices2
|
||||
|
||||
def alternateSpin(self, bm, mesh, angle, chosenSpinCenter, spinAxis, steps, v0, v1org, lastSpinVertIndices):
|
||||
def alternateSpin(self, bm, mesh, angle, chosenSpinCenter,
|
||||
spinAxis, steps, v0, v1org, lastSpinVertIndices):
|
||||
|
||||
self.deleteSpinVertices(bm, mesh, lastSpinVertIndices)
|
||||
v0prim = v0
|
||||
|
||||
result2 = bmesh.ops.spin(bm, geom=[v0prim], cent=chosenSpinCenter, axis=spinAxis,
|
||||
angle=-angle, steps=steps, use_duplicate=False)
|
||||
result2 = bmesh.ops.spin(
|
||||
bm, geom=[v0prim], cent=chosenSpinCenter, axis=spinAxis,
|
||||
angle=-angle, steps=steps, use_duplicate=False
|
||||
)
|
||||
# it seems there is something wrong with last index of this spin
|
||||
# I need to calculate the last index manually here
|
||||
vertsLength = len(bm.verts)
|
||||
|
@ -1245,7 +1289,8 @@ class EdgeRoundifier(Operator):
|
|||
self.a = angle_convert
|
||||
except:
|
||||
self.a = 180 # fallback
|
||||
debugPrintNew(True, "CalculateRadiusAndAngleForAnglePresets problem with int conversion")
|
||||
debugPrintNew(True,
|
||||
"CalculateRadiusAndAngleForAnglePresets problem with int conversion")
|
||||
|
||||
return self.CalculateRadiusAndAngle(edgeLength)
|
||||
|
||||
|
|
|
@ -0,0 +1,384 @@
|
|||
# ##### 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; version 2
|
||||
# of the License.
|
||||
#
|
||||
# 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 #####
|
||||
|
||||
# based upon the functionality of Mesh to wall by luxuy_BlenderCN
|
||||
# thanks to meta-androcto
|
||||
|
||||
bl_info = {
|
||||
"name": "Edge Floor Plan",
|
||||
"author": "lijenstina",
|
||||
"version": (0, 2),
|
||||
"blender": (2, 78, 0),
|
||||
"location": "View3D > EditMode > Mesh",
|
||||
"description": "Make a Floor Plan from Edges",
|
||||
"wiki_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
from bpy.types import Operator
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
IntProperty,
|
||||
)
|
||||
|
||||
|
||||
# Handle error notifications
|
||||
def error_handlers(self, error, reports="ERROR"):
|
||||
if self and reports:
|
||||
self.report({'WARNING'}, reports + " (See Console for more info)")
|
||||
|
||||
print("\n[mesh.edges_floor_plan]\nError: {}\n".format(error))
|
||||
|
||||
|
||||
class MESH_OT_edges_floor_plan(Operator):
|
||||
bl_idname = "mesh.edges_floor_plan"
|
||||
bl_label = "Edges Floor Plan"
|
||||
bl_description = "Top View, Extrude Flat Along Edges"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
wid = FloatProperty(
|
||||
name="Wall width:",
|
||||
description="Set the width of the generated walls\n",
|
||||
default=0.1,
|
||||
min=0.001, max=30000
|
||||
)
|
||||
depth = FloatProperty(
|
||||
name="Inner height:",
|
||||
description="Set the height of the inner wall edges",
|
||||
default=0.0,
|
||||
min=0, max=10
|
||||
)
|
||||
connect_ends = BoolProperty(
|
||||
name="Connect Ends",
|
||||
description="Connect the ends of the boundary Edge loops",
|
||||
default=False
|
||||
)
|
||||
repeat_cleanup = IntProperty(
|
||||
name="Recursive Prepare",
|
||||
description="Number of times that the preparation phase runs\n"
|
||||
"at the start of the script\n"
|
||||
"If parts of the mesh are not modified, increase this value",
|
||||
min=1, max=20,
|
||||
default=1
|
||||
)
|
||||
fill_items = [
|
||||
('EDGE_NET', "Edge Net",
|
||||
"Edge Net Method for mesh preparation - Initial Fill\n"
|
||||
"The filled in faces will be Inset individually\n"
|
||||
"Supports simple 3D objects"),
|
||||
('SINGLE_FACE', "Single Face",
|
||||
"Single Face Method for mesh preparation - Initial Fill\n"
|
||||
"The produced face will be Triangulated before Inset Region\n"
|
||||
"Good for edges forming a circle, avoid 3D objects"),
|
||||
('SOLIDIFY', "Solidify",
|
||||
"Extrude and Solidify Method\n"
|
||||
"Useful for complex meshes, however works best on flat surfaces\n"
|
||||
"as the extrude direction has to be defined")
|
||||
]
|
||||
fill_type = EnumProperty(
|
||||
name="Fill Type",
|
||||
items=fill_items,
|
||||
description="Choose the method for creating geometry",
|
||||
default='SOLIDIFY'
|
||||
)
|
||||
keep_faces = BoolProperty(
|
||||
name="Keep Faces",
|
||||
description="Keep or not the fill faces\n"
|
||||
"Can depend on Remove Ngons state",
|
||||
default=False
|
||||
)
|
||||
tri_faces = BoolProperty(
|
||||
name="Triangulate Faces",
|
||||
description="Triangulate the created fill faces\n"
|
||||
"Sometimes can lead to unsatisfactory results",
|
||||
default=False
|
||||
)
|
||||
initial_extrude = FloatVectorProperty(
|
||||
name="Initial Extrude",
|
||||
description="",
|
||||
default=(0.0, 0.0, 0.1),
|
||||
min=-20.0, max=20.0,
|
||||
subtype='XYZ',
|
||||
precision=3,
|
||||
size=3
|
||||
)
|
||||
remove_ngons = BoolProperty(
|
||||
name="Remove Ngons",
|
||||
description="Keep or not the Ngon Faces\n"
|
||||
"Note about limitations:\n"
|
||||
"Sometimes the kept Faces could be Ngons\n"
|
||||
"Removing the Ngons can lead to no geometry created",
|
||||
default=True
|
||||
)
|
||||
offset = FloatProperty(
|
||||
name="Wall Offset:",
|
||||
description="Set the offset for the Solidify modifier",
|
||||
default=0.0,
|
||||
min=-1.0, max=1.0
|
||||
)
|
||||
only_rim = BoolProperty(
|
||||
name="Rim Only",
|
||||
description="Solidify Fill Rim only option",
|
||||
default=False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.active_object
|
||||
return (ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
|
||||
|
||||
def check_edge(self, context):
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
obj = bpy.context.object
|
||||
me_check = obj.data
|
||||
if len(me_check.edges) < 1:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def ensure(bm):
|
||||
if bm:
|
||||
bm.verts.ensure_lookup_table()
|
||||
bm.edges.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
|
||||
def solidify_mod(self, context, ob, wid, offset, only_rim):
|
||||
try:
|
||||
mods = ob.modifiers.new(
|
||||
name="_Mesh_Solidify_Wall", type='SOLIDIFY'
|
||||
)
|
||||
mods.thickness = wid
|
||||
mods.use_quality_normals = True
|
||||
mods.offset = offset
|
||||
mods.use_even_offset = True
|
||||
mods.use_rim = True
|
||||
mods.use_rim_only = only_rim
|
||||
mods.show_on_cage = True
|
||||
|
||||
bpy.ops.object.modifier_apply(
|
||||
modifier="_Mesh_Solidify_Wall"
|
||||
)
|
||||
except Exception as e:
|
||||
error_handlers(self, e,
|
||||
reports="Adding a Solidify Modifier failed")
|
||||
pass
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Choose Method:", icon="SCRIPTWIN")
|
||||
box.prop(self, "fill_type")
|
||||
|
||||
col = box.column(align=True)
|
||||
|
||||
if self.fill_type == 'EDGE_NET':
|
||||
col.prop(self, "repeat_cleanup")
|
||||
col.prop(self, "remove_ngons", toggle=True)
|
||||
|
||||
elif self.fill_type == 'SOLIDIFY':
|
||||
col.prop(self, "offset", slider=True)
|
||||
col.prop(self, "initial_extrude")
|
||||
|
||||
else:
|
||||
col.prop(self, "remove_ngons", toggle=True)
|
||||
col.prop(self, "tri_faces", toggle=True)
|
||||
|
||||
box = layout.box()
|
||||
box.label(text="Settings:", icon="MOD_BUILD")
|
||||
|
||||
col = box.column(align=True)
|
||||
col.prop(self, "wid")
|
||||
|
||||
if self.fill_type != 'SOLIDIFY':
|
||||
col.prop(self, "depth")
|
||||
col.prop(self, "connect_ends", toggle=True)
|
||||
col.prop(self, "keep_faces", toggle=True)
|
||||
else:
|
||||
col.prop(self, "only_rim", toggle=True)
|
||||
|
||||
def execute(self, context):
|
||||
if not self.check_edge(context):
|
||||
self.report({'WARNING'},
|
||||
"Operation Cancelled. Needs a Mesh with at least one edge")
|
||||
return {'CANCELLED'}
|
||||
|
||||
wid = self.wid * 0.1
|
||||
depth = self.depth * 0.1
|
||||
offset = self.offset * 0.1
|
||||
store_selection_mode = context.tool_settings.mesh_select_mode
|
||||
# Note: the remove_doubles called after bmesh creation would make
|
||||
# blender crash with certain meshes - keep it in mind for the future
|
||||
bpy.ops.mesh.remove_doubles(threshold=0.003)
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
ob = bpy.context.object
|
||||
|
||||
me = ob.data
|
||||
bm = bmesh.from_edit_mesh(me)
|
||||
|
||||
bmesh.ops.delete(bm, geom=bm.faces, context=3)
|
||||
self.ensure(bm)
|
||||
context.tool_settings.mesh_select_mode = (False, True, False)
|
||||
original_edges = [edge.index for edge in bm.edges]
|
||||
original_verts = [vert.index for vert in bm.verts]
|
||||
self.ensure(bm)
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
if self.fill_type == 'EDGE_NET':
|
||||
for i in range(self.repeat_cleanup):
|
||||
bmesh.ops.edgenet_prepare(bm, edges=bm.edges)
|
||||
self.ensure(bm)
|
||||
bmesh.ops.edgenet_fill(bm, edges=bm.edges, mat_nr=0, use_smooth=True, sides=0)
|
||||
self.ensure(bm)
|
||||
if self.remove_ngons:
|
||||
ngons = [face for face in bm.faces if len(face.edges) > 4]
|
||||
self.ensure(bm)
|
||||
bmesh.ops.delete(bm, geom=ngons, context=5) # 5 - delete faces
|
||||
del ngons
|
||||
self.ensure(bm)
|
||||
|
||||
elif self.fill_type == 'SOLIDIFY':
|
||||
for vert in bm.verts:
|
||||
vert.normal_update()
|
||||
self.ensure(bm)
|
||||
bmesh.ops.extrude_edge_only(
|
||||
bm, edges=bm.edges, use_select_history=False
|
||||
)
|
||||
self.ensure(bm)
|
||||
verts_extrude = [vert for vert in bm.verts if vert.index in original_verts]
|
||||
self.ensure(bm)
|
||||
bmesh.ops.translate(
|
||||
bm,
|
||||
verts=verts_extrude,
|
||||
vec=(self.initial_extrude)
|
||||
)
|
||||
self.ensure(bm)
|
||||
del verts_extrude
|
||||
self.ensure(bm)
|
||||
|
||||
for edge in bm.edges:
|
||||
if edge.is_boundary:
|
||||
edge.select = True
|
||||
|
||||
bm = bmesh.update_edit_mesh(ob.data, 1, 1)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
self.solidify_mod(context, ob, wid, offset, self.only_rim)
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
context.tool_settings.mesh_select_mode = store_selection_mode
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
else:
|
||||
bm.faces.new(bm.verts)
|
||||
self.ensure(bm)
|
||||
|
||||
if self.tri_faces:
|
||||
bmesh.ops.triangle_fill(
|
||||
bm, use_beauty=True, use_dissolve=False, edges=bm.edges
|
||||
)
|
||||
self.ensure(bm)
|
||||
|
||||
if self.remove_ngons and self.fill_type != 'EDGE_NET':
|
||||
ngons = [face for face in bm.faces if len(face.edges) > 4]
|
||||
self.ensure(bm)
|
||||
bmesh.ops.delete(bm, geom=ngons, context=5) # 5 - delete faces
|
||||
del ngons
|
||||
self.ensure(bm)
|
||||
|
||||
del_boundary = [edge for edge in bm.edges if edge.index not in original_edges]
|
||||
self.ensure(bm)
|
||||
|
||||
del original_edges
|
||||
self.ensure(bm)
|
||||
|
||||
if self.fill_type == 'EDGE_NET':
|
||||
extrude_inner = bmesh.ops.inset_individual(
|
||||
bm, faces=bm.faces, thickness=wid, depth=depth,
|
||||
use_even_offset=True, use_interpolate=False,
|
||||
use_relative_offset=False
|
||||
)
|
||||
else:
|
||||
extrude_inner = bmesh.ops.inset_region(
|
||||
bm, faces=bm.faces, faces_exclude=[], use_boundary=True,
|
||||
use_even_offset=True, use_interpolate=False,
|
||||
use_relative_offset=False, use_edge_rail=False,
|
||||
thickness=wid, depth=depth, use_outset=False
|
||||
)
|
||||
self.ensure(bm)
|
||||
|
||||
del_faces = [faces for faces in bm.faces if faces not in extrude_inner["faces"]]
|
||||
self.ensure(bm)
|
||||
del extrude_inner
|
||||
self.ensure(bm)
|
||||
|
||||
if not self.keep_faces:
|
||||
bmesh.ops.delete(bm, geom=del_faces, context=5) # 5 delete faces
|
||||
del del_faces
|
||||
self.ensure(bm)
|
||||
|
||||
face_del = set()
|
||||
for face in bm.faces:
|
||||
for edge in del_boundary:
|
||||
if isinstance(edge, bmesh.types.BMEdge):
|
||||
if edge in face.edges:
|
||||
face_del.add(face)
|
||||
self.ensure(bm)
|
||||
face_del = list(face_del)
|
||||
self.ensure(bm)
|
||||
|
||||
del del_boundary
|
||||
self.ensure(bm)
|
||||
|
||||
if not self.connect_ends:
|
||||
bmesh.ops.delete(bm, geom=face_del, context=5)
|
||||
self.ensure(bm)
|
||||
|
||||
del face_del
|
||||
self.ensure(bm)
|
||||
|
||||
for edge in bm.edges:
|
||||
if edge.is_boundary:
|
||||
edge.select = True
|
||||
|
||||
bm = bmesh.update_edit_mesh(ob.data, 1, 1)
|
||||
|
||||
context.tool_settings.mesh_select_mode = store_selection_mode
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(MESH_OT_edges_floor_plan)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(MESH_OT_edges_floor_plan)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -2,16 +2,15 @@
|
|||
|
||||
bl_info = {
|
||||
"name": "Set edges length",
|
||||
"description": "edges length",
|
||||
"description": "Edges length",
|
||||
"author": "Giuseppe De Marco [BlenderLab] inspired by NirenYang",
|
||||
"version": (0, 1, 0),
|
||||
"blender": (2, 7, 0, 5),
|
||||
"location": "[Toolbar][Tools][Mesh Tools]: set Length(Shit+Alt+E)",
|
||||
"blender": (2, 7, 1),
|
||||
"location": "Toolbar > Tools > Mesh Tools: set Length(Shit+Alt+E)",
|
||||
"warning": "",
|
||||
"category": "Mesh",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
}
|
||||
"category": "Mesh",
|
||||
}
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
|
@ -40,8 +39,8 @@ def get_edge_vector(edge):
|
|||
|
||||
def get_selected(bmesh_obj, geometry_type):
|
||||
# geometry type should be edges, verts or faces
|
||||
|
||||
selected = []
|
||||
|
||||
for i in getattr(bmesh_obj, geometry_type):
|
||||
if i.select:
|
||||
selected.append(i)
|
||||
|
@ -66,51 +65,58 @@ class LengthSet(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
old_length = FloatProperty(
|
||||
name="Original length",
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
name="Original length",
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
set_lenght_type = EnumProperty(
|
||||
items=[
|
||||
('manual', "Manual", "Input manually the desired Target Lenght"),
|
||||
('existing', "Existing Lenght", "Use existing geometry Edges' characteristics"),
|
||||
],
|
||||
name="Set Type of Input",
|
||||
)
|
||||
items=[
|
||||
('manual', "Manual",
|
||||
"Input manually the desired Target Lenght"),
|
||||
('existing', "Existing Lenght",
|
||||
"Use existing geometry Edges' characteristics"),
|
||||
],
|
||||
name="Set Type of Input",
|
||||
)
|
||||
target_length = FloatProperty(
|
||||
name="Target Length",
|
||||
description="Input a value for an Edges Lenght target",
|
||||
default=1.00,
|
||||
unit='LENGTH',
|
||||
precision=5
|
||||
)
|
||||
name="Target Length",
|
||||
description="Input a value for an Edges Lenght target",
|
||||
default=1.00,
|
||||
unit='LENGTH',
|
||||
precision=5
|
||||
)
|
||||
existing_lenght = EnumProperty(
|
||||
items=[
|
||||
('min', "Shortest", "Set all to shortest Edge of selection"),
|
||||
('max', "Longest", "Set all to the longest Edge of selection"),
|
||||
('average', "Average", "Set all to the average Edge lenght of selection"),
|
||||
('active', "Active", "Set all to the active Edge's one\n"
|
||||
"Needs a selection to be done in Edge Select mode"),
|
||||
],
|
||||
name="Existing lenght"
|
||||
)
|
||||
items=[
|
||||
('min', "Shortest",
|
||||
"Set all to shortest Edge of selection"),
|
||||
('max', "Longest",
|
||||
"Set all to the longest Edge of selection"),
|
||||
('average', "Average",
|
||||
"Set all to the average Edge lenght of selection"),
|
||||
('active', "Active",
|
||||
"Set all to the active Edge's one\n"
|
||||
"Needs a selection to be done in Edge Select mode"),
|
||||
],
|
||||
name="Existing lenght"
|
||||
)
|
||||
mode = EnumProperty(
|
||||
items=[
|
||||
('fixed', "Fixed", "Fixed"),
|
||||
('increment', "Increment", "Increment"),
|
||||
('decrement', "Decrement", "Decrement"),
|
||||
],
|
||||
name="Mode"
|
||||
)
|
||||
items=[
|
||||
('fixed', "Fixed", "Fixed"),
|
||||
('increment', "Increment", "Increment"),
|
||||
('decrement', "Decrement", "Decrement"),
|
||||
],
|
||||
name="Mode"
|
||||
)
|
||||
behaviour = EnumProperty(
|
||||
items=[
|
||||
('proportional', "Proportional",
|
||||
"Move vertex locations proportionally to the center of the Edge"),
|
||||
('clockwise', "Clockwise",
|
||||
"Compute the Edges' vertex locations in a clockwise fashion"),
|
||||
('unclockwise', "Counterclockwise",
|
||||
"Compute the Edges' vertex locations in a counterclockwise fashion"),
|
||||
],
|
||||
name="Resize behavior")
|
||||
items=[
|
||||
('proportional', "Proportional",
|
||||
"Move vertex locations proportionally to the center of the Edge"),
|
||||
('clockwise', "Clockwise",
|
||||
"Compute the Edges' vertex locations in a clockwise fashion"),
|
||||
('unclockwise', "Counterclockwise",
|
||||
"Compute the Edges' vertex locations in a counterclockwise fashion"),
|
||||
],
|
||||
name="Resize behavior"
|
||||
)
|
||||
|
||||
originary_edge_length_dict = {}
|
||||
edge_lenghts = []
|
||||
|
@ -138,7 +144,7 @@ class LengthSet(Operator):
|
|||
layout.label("Mode:")
|
||||
layout.prop(self, "mode", text="")
|
||||
|
||||
layout.label("Resize Behavior")
|
||||
layout.label("Resize Behavior:")
|
||||
layout.prop(self, "behaviour", text="")
|
||||
|
||||
def get_existing_edge_lenght(self, bm):
|
||||
|
@ -251,7 +257,8 @@ class LengthSet(Operator):
|
|||
if edge_length_debug:
|
||||
self.report({'INFO'},
|
||||
' - '.join(('vector ' + str(vector),
|
||||
'originary_vector ' + str(self.originary_edge_length_dict[verts_index])
|
||||
'originary_vector ' +
|
||||
str(self.originary_edge_length_dict[verts_index])
|
||||
)))
|
||||
verts = (edge.verts[0].co, edge.verts[1].co)
|
||||
|
||||
|
@ -281,18 +288,22 @@ class LengthSet(Operator):
|
|||
|
||||
elif self.behaviour == 'unclockwise':
|
||||
if self.mode == 'increment':
|
||||
edge.verts[1].co = verts[0] + (self.originary_edge_length_dict[verts_index] + vector)
|
||||
edge.verts[1].co = \
|
||||
verts[0] + (self.originary_edge_length_dict[verts_index] + vector)
|
||||
elif self.mode == 'decrement':
|
||||
edge.verts[0].co = verts[1] - (self.originary_edge_length_dict[verts_index] - vector)
|
||||
edge.verts[0].co = \
|
||||
verts[1] - (self.originary_edge_length_dict[verts_index] - vector)
|
||||
else:
|
||||
edge.verts[1].co = verts[0] + vector
|
||||
|
||||
else:
|
||||
# clockwise
|
||||
if self.mode == 'increment':
|
||||
edge.verts[0].co = verts[1] - (self.originary_edge_length_dict[verts_index] + vector)
|
||||
edge.verts[0].co = \
|
||||
verts[1] - (self.originary_edge_length_dict[verts_index] + vector)
|
||||
elif self.mode == 'decrement':
|
||||
edge.verts[1].co = verts[0] + (self.originary_edge_length_dict[verts_index] - vector)
|
||||
edge.verts[1].co = \
|
||||
verts[0] + (self.originary_edge_length_dict[verts_index] - vector)
|
||||
else:
|
||||
edge.verts[0].co = verts[1] - vector
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
### BEGIN GPL LICENSE BLOCK #####
|
||||
# ##### 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
|
||||
|
@ -25,14 +25,17 @@ bl_info = {
|
|||
"version": (0, 8, 1),
|
||||
"blender": (2, 76, 5),
|
||||
"location": "View3D > TOOLS > Tools > Mesh Tools > Add: > Extrude Menu (Alt + E)",
|
||||
"description": "Extrude face and merge edge intersections between the mesh and the new edges",
|
||||
"wiki_url" : "http://blenderartists.org/forum/showthread.php?376618-Addon-Push-Pull-Face",
|
||||
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
|
||||
"description": "Extrude face and merge edge intersections "
|
||||
"between the mesh and the new edges",
|
||||
"wiki_url": "http://blenderartists.org/forum/"
|
||||
"showthread.php?376618-Addon-Push-Pull-Face",
|
||||
"category": "Mesh"}
|
||||
|
||||
import bpy, bmesh
|
||||
import bpy
|
||||
import bmesh
|
||||
from mathutils.geometry import intersect_line_line
|
||||
from bpy.props import FloatProperty
|
||||
from bpy.types import Operator
|
||||
|
||||
|
||||
class BVHco():
|
||||
i = 0
|
||||
|
@ -43,7 +46,8 @@ class BVHco():
|
|||
c2y = 0.0
|
||||
c2z = 0.0
|
||||
|
||||
def edges_BVH_overlap(bm, edges, epsilon = 0.0001):
|
||||
|
||||
def edges_BVH_overlap(bm, edges, epsilon=0.0001):
|
||||
bco = set()
|
||||
for e in edges:
|
||||
bvh = BVHco()
|
||||
|
@ -113,19 +117,19 @@ def edges_BVH_overlap(bm, edges, epsilon = 0.0001):
|
|||
overlap[e1] = oget(e1, set()).union({e2})
|
||||
return overlap
|
||||
|
||||
def intersect_edges_edges(overlap, precision = 4):
|
||||
|
||||
def intersect_edges_edges(overlap, precision=4):
|
||||
epsilon = .1**precision
|
||||
fpre_min = -epsilon
|
||||
fpre_max = 1+epsilon
|
||||
fpre_max = 1 + epsilon
|
||||
splits = {}
|
||||
sp_get = splits.get
|
||||
new_edges1 = set()
|
||||
new_edges2 = set()
|
||||
targetmap = {}
|
||||
for edg1 in overlap:
|
||||
#print("***", ed1.index, "***")
|
||||
# print("***", ed1.index, "***")
|
||||
for edg2 in overlap[edg1]:
|
||||
#print('loop', ed2.index)
|
||||
a1 = edg1.verts[0]
|
||||
a2 = edg1.verts[1]
|
||||
b1 = edg2.verts[0]
|
||||
|
@ -133,7 +137,7 @@ def intersect_edges_edges(overlap, precision = 4):
|
|||
|
||||
# test if are linked
|
||||
if a1 in {b1, b2} or a2 in {b1, b2}:
|
||||
#print('linked')
|
||||
# print('linked')
|
||||
continue
|
||||
|
||||
aco1, aco2 = a1.co, a2.co
|
||||
|
@ -141,23 +145,23 @@ def intersect_edges_edges(overlap, precision = 4):
|
|||
tp = intersect_line_line(aco1, aco2, bco1, bco2)
|
||||
if tp:
|
||||
p1, p2 = tp
|
||||
if (p1 - p2).to_tuple(precision) == (0,0,0):
|
||||
v = aco2-aco1
|
||||
if (p1 - p2).to_tuple(precision) == (0, 0, 0):
|
||||
v = aco2 - aco1
|
||||
f = p1 - aco1
|
||||
x,y,z = abs(v.x), abs(v.y), abs(v.z)
|
||||
x, y, z = abs(v.x), abs(v.y), abs(v.z)
|
||||
max1 = 0 if x >= y and x >= z else\
|
||||
1 if y >= x and y >= z else 2
|
||||
fac1 = f[max1]/v[max1]
|
||||
fac1 = f[max1] / v[max1]
|
||||
|
||||
v = bco2-bco1
|
||||
v = bco2 - bco1
|
||||
f = p2 - bco1
|
||||
x,y,z = abs(v.x), abs(v.y), abs(v.z)
|
||||
x, y, z = abs(v.x), abs(v.y), abs(v.z)
|
||||
max2 = 0 if x >= y and x >= z else\
|
||||
1 if y >= x and y >= z else 2
|
||||
fac2 = f[max2]/v[max2]
|
||||
fac2 = f[max2] / v[max2]
|
||||
|
||||
if fpre_min <= fac1 <= fpre_max:
|
||||
#print(edg1.index, 'can intersect', edg2.index)
|
||||
# print(edg1.index, 'can intersect', edg2.index)
|
||||
ed1 = edg1
|
||||
|
||||
elif edg1 in splits:
|
||||
|
@ -168,21 +172,21 @@ def intersect_edges_edges(overlap, precision = 4):
|
|||
vco1 = a1.co
|
||||
vco2 = a2.co
|
||||
|
||||
v = vco2-vco1
|
||||
v = vco2 - vco1
|
||||
f = p1 - vco1
|
||||
fac1 = f[max1]/v[max1]
|
||||
fac1 = f[max1] / v[max1]
|
||||
if fpre_min <= fac1 <= fpre_max:
|
||||
#print(e.index, 'can intersect', edg2.index)
|
||||
# print(e.index, 'can intersect', edg2.index)
|
||||
break
|
||||
else:
|
||||
#print(edg1.index, 'really does not intersect', edg2.index)
|
||||
# print(edg1.index, 'really does not intersect', edg2.index)
|
||||
continue
|
||||
else:
|
||||
#print(edg1.index, 'not intersect', edg2.index)
|
||||
# print(edg1.index, 'not intersect', edg2.index)
|
||||
continue
|
||||
|
||||
if fpre_min <= fac2 <= fpre_max:
|
||||
#print(ed1.index, 'actually intersect', edg2.index)
|
||||
# print(ed1.index, 'actually intersect', edg2.index)
|
||||
ed2 = edg2
|
||||
|
||||
elif edg2 in splits:
|
||||
|
@ -193,17 +197,17 @@ def intersect_edges_edges(overlap, precision = 4):
|
|||
vco1 = b1.co
|
||||
vco2 = b2.co
|
||||
|
||||
v = vco2-vco1
|
||||
v = vco2 - vco1
|
||||
f = p2 - vco1
|
||||
fac2 = f[max2]/v[max2]
|
||||
fac2 = f[max2] / v[max2]
|
||||
if fpre_min <= fac2 <= fpre_max:
|
||||
#print(ed1.index, 'actually intersect', e.index)
|
||||
# print(ed1.index, 'actually intersect', e.index)
|
||||
break
|
||||
else:
|
||||
#print(ed1.index, 'really does not intersect', ed2.index)
|
||||
# print(ed1.index, 'really does not intersect', ed2.index)
|
||||
continue
|
||||
else:
|
||||
#print(ed1.index, 'not intersect', edg2.index)
|
||||
# print(ed1.index, 'not intersect', edg2.index)
|
||||
continue
|
||||
|
||||
new_edges1.add(ed1)
|
||||
|
@ -227,30 +231,28 @@ def intersect_edges_edges(overlap, precision = 4):
|
|||
new_edges2.add(ne2)
|
||||
splits[edg2] = sp_get(edg2, set()).union({ne2})
|
||||
|
||||
if nv1 != nv2: #necessary?
|
||||
if nv1 != nv2: # necessary?
|
||||
targetmap[nv1] = nv2
|
||||
#else:
|
||||
#print('not coplanar')
|
||||
#else:
|
||||
#print("parallel or collinear")
|
||||
|
||||
return new_edges1, new_edges2, targetmap
|
||||
|
||||
class Extrude_and_Reshape(bpy.types.Operator):
|
||||
"""Push and pull face entities to sculpt 3d models"""
|
||||
|
||||
class Extrude_and_Reshape(Operator):
|
||||
bl_idname = "mesh.extrude_reshape"
|
||||
bl_label = "Extrude and Reshape"
|
||||
bl_description = "Push and pull face entities to sculpt 3d models"
|
||||
bl_options = {'REGISTER', 'GRAB_CURSOR', 'BLOCKING'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.mode is not 'EDIT_MESH'
|
||||
return context.mode is not 'EDIT_MESH'
|
||||
|
||||
def modal(self, context, event):
|
||||
if self.confirm:
|
||||
sface = self.bm.faces.active
|
||||
if not sface:
|
||||
for face in self.bm.faces:
|
||||
if face.select == True:
|
||||
if face.select is True:
|
||||
sface = face
|
||||
break
|
||||
else:
|
||||
|
@ -259,13 +261,13 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
edges = set()
|
||||
[[edges.add(ed) for ed in v.link_edges] for v in sface.verts]
|
||||
|
||||
overlap = edges_BVH_overlap(self.bm, edges, epsilon = 0.0001)
|
||||
overlap = {k: v for k,v in overlap.items() if k not in edges} # remove repetition
|
||||
|
||||
#print([e.index for e in edges])
|
||||
#for a, b in overlap.items():
|
||||
#print(a.index, [e.index for e in b])
|
||||
|
||||
overlap = edges_BVH_overlap(self.bm, edges, epsilon=0.0001)
|
||||
overlap = {k: v for k, v in overlap.items() if k not in edges} # remove repetition
|
||||
"""
|
||||
print([e.index for e in edges])
|
||||
for a, b in overlap.items():
|
||||
print(a.index, [e.index for e in b])
|
||||
"""
|
||||
new_edges1, new_edges2, targetmap = intersect_edges_edges(overlap)
|
||||
pos_weld = set()
|
||||
for e in new_edges1:
|
||||
|
@ -274,9 +276,11 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
pos_weld.add((targetmap[v1], targetmap[v2]))
|
||||
if targetmap:
|
||||
bmesh.ops.weld_verts(self.bm, targetmap=targetmap)
|
||||
#print([e.is_valid for e in new_edges1])
|
||||
#print([e.is_valid for e in new_edges2])
|
||||
#sp_faces1 = set()
|
||||
"""
|
||||
print([e.is_valid for e in new_edges1])
|
||||
print([e.is_valid for e in new_edges2])
|
||||
sp_faces1 = set()
|
||||
"""
|
||||
for e in pos_weld:
|
||||
v1, v2 = e
|
||||
lf1 = set(v1.link_faces)
|
||||
|
@ -285,11 +289,11 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
for f in rlfe:
|
||||
try:
|
||||
nf = bmesh.utils.face_split(f, v1, v2)
|
||||
#sp_faces1.update({f, nf[0]})
|
||||
# sp_faces1.update({f, nf[0]})
|
||||
except:
|
||||
pass
|
||||
|
||||
#sp_faces2 = set()
|
||||
# sp_faces2 = set()
|
||||
for e in new_edges2:
|
||||
lfe = set(e.link_faces)
|
||||
v1, v2 = e.verts
|
||||
|
@ -298,7 +302,7 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
rlfe = lf1.intersection(lf2)
|
||||
for f in rlfe.difference(lfe):
|
||||
nf = bmesh.utils.face_split(f, v1, v2)
|
||||
#sp_faces2.update({f, nf[0]})
|
||||
# sp_faces2.update({f, nf[0]})
|
||||
|
||||
bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True)
|
||||
return {'FINISHED'}
|
||||
|
@ -315,7 +319,7 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
selection = self.bm.select_history[-1]
|
||||
except:
|
||||
for face in self.bm.faces:
|
||||
if face.select == True:
|
||||
if face.select is True:
|
||||
selection = face
|
||||
break
|
||||
else:
|
||||
|
@ -325,22 +329,27 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
return {'FINISHED'}
|
||||
else:
|
||||
face = selection
|
||||
#face.select = False
|
||||
# face.select = False
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
geom = []
|
||||
for edge in face.edges:
|
||||
if abs(edge.calc_face_angle(0) - 1.5707963267948966) < 0.01: #self.angle_tolerance:
|
||||
if abs(edge.calc_face_angle(0) - 1.5707963267948966) < 0.01: # self.angle_tolerance:
|
||||
geom.append(edge)
|
||||
|
||||
ret_dict = bmesh.ops.extrude_discrete_faces(self.bm, faces = [face])
|
||||
ret_dict = bmesh.ops.extrude_discrete_faces(self.bm, faces=[face])
|
||||
|
||||
for face in ret_dict['faces']:
|
||||
self.bm.faces.active = face
|
||||
face.select = True
|
||||
sface = face
|
||||
dfaces = bmesh.ops.dissolve_edges(self.bm, edges = geom, use_verts=True, use_face_split=False)
|
||||
dfaces = bmesh.ops.dissolve_edges(
|
||||
self.bm, edges=geom, use_verts=True, use_face_split=False
|
||||
)
|
||||
bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True)
|
||||
bpy.ops.transform.translate('INVOKE_DEFAULT', constraint_axis=(False, False, True), constraint_orientation='NORMAL', release_confirm=True)
|
||||
bpy.ops.transform.translate(
|
||||
'INVOKE_DEFAULT', constraint_axis=(False, False, True),
|
||||
constraint_orientation='NORMAL', release_confirm=True
|
||||
)
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
|
@ -348,18 +357,22 @@ class Extrude_and_Reshape(bpy.types.Operator):
|
|||
self.confirm = False
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def operator_draw(self,context):
|
||||
|
||||
def operator_draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column(align=True)
|
||||
col.operator("mesh.extrude_reshape", text="Extrude and Reshape")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(Extrude_and_Reshape)
|
||||
bpy.types.VIEW3D_MT_edit_mesh_extrude.append(operator_draw)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.VIEW3D_MT_edit_mesh_extrude.remove(operator_draw)
|
||||
bpy.utils.unregister_class(Extrude_and_Reshape)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
|
|
@ -20,12 +20,11 @@ bl_info = {
|
|||
"name": "Fast Loop",
|
||||
"description": "Add loops fast",
|
||||
"author": "Andy Davies (metalliandy)",
|
||||
"version": (0, 16),
|
||||
"version": (0, 1, 7),
|
||||
"blender": (2, 5, 6),
|
||||
"location": "Tool Shelf",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# ##### END 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
|
||||
|
@ -17,8 +16,7 @@
|
|||
# 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 LICENCE BLOCK *****
|
||||
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
bl_info = {
|
||||
"name": "FilletPlus",
|
||||
|
@ -29,7 +27,6 @@ bl_info = {
|
|||
"description": "",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
|
@ -42,7 +39,10 @@ from bpy.props import (
|
|||
from bpy.types import Operator
|
||||
import bmesh
|
||||
from mathutils import Matrix
|
||||
from math import cos, pi, degrees, sin, tan
|
||||
from math import (
|
||||
cos, pi, sin,
|
||||
degrees, tan,
|
||||
)
|
||||
|
||||
|
||||
def list_clear_(l):
|
||||
|
@ -298,36 +298,36 @@ class MESH_OT_fillet_plus(Operator):
|
|||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
adj = FloatProperty(
|
||||
name="",
|
||||
description="Size of the filleted corners",
|
||||
default=0.1,
|
||||
min=0.00001, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
name="",
|
||||
description="Size of the filleted corners",
|
||||
default=0.1,
|
||||
min=0.00001, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
n = IntProperty(
|
||||
name="",
|
||||
description="Subdivision of the filleted corners",
|
||||
default=3,
|
||||
min=1, max=50,
|
||||
step=1
|
||||
)
|
||||
name="",
|
||||
description="Subdivision of the filleted corners",
|
||||
default=3,
|
||||
min=1, max=50,
|
||||
step=1
|
||||
)
|
||||
out = BoolProperty(
|
||||
name="Outside",
|
||||
description="Fillet towards outside",
|
||||
default=False
|
||||
)
|
||||
name="Outside",
|
||||
description="Fillet towards outside",
|
||||
default=False
|
||||
)
|
||||
flip = BoolProperty(
|
||||
name="Flip",
|
||||
description="Flip the direction of the Fillet\n"
|
||||
"Only available if Outside option is not active",
|
||||
default=False
|
||||
)
|
||||
name="Flip",
|
||||
description="Flip the direction of the Fillet\n"
|
||||
"Only available if Outside option is not active",
|
||||
default=False
|
||||
)
|
||||
radius = BoolProperty(
|
||||
name="Radius",
|
||||
description="Use radius for the size of the filleted corners",
|
||||
default=False
|
||||
)
|
||||
name="Radius",
|
||||
description="Use radius for the size of the filleted corners",
|
||||
default=False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -338,8 +338,8 @@ class MESH_OT_fillet_plus(Operator):
|
|||
layout = self.layout
|
||||
|
||||
if f_buf.check is False:
|
||||
layout.label(text="Angle equal to 0 or 180", icon="INFO")
|
||||
layout.label("Can not fillet")
|
||||
layout.label(text="Angle is equal to 0 or 180", icon="INFO")
|
||||
layout.label(text="Can not fillet", icon="BLANK1")
|
||||
else:
|
||||
layout.prop(self, "radius")
|
||||
if self.radius is True:
|
||||
|
@ -349,6 +349,7 @@ class MESH_OT_fillet_plus(Operator):
|
|||
layout.prop(self, "adj")
|
||||
layout.label("Number of sides:")
|
||||
layout.prop(self, "n")
|
||||
|
||||
if self.n > 1:
|
||||
row = layout.row(align=False)
|
||||
row.prop(self, "out")
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# gpl authors: lijenstina, meta-androcto
|
||||
|
||||
# Note: this script contains the Help Operator used by the various functions
|
||||
# Usage: add a key string the dictionary with the list of strings to pass to labels in this file
|
||||
# Usage: add a key string to the dictionary in this file with the list of strings to pass to labels
|
||||
# and call the operator from the add-on UI draw function by passing the help_ids parameter
|
||||
# If the size of the pop-up if needed, define popup_size in the call by using varibles
|
||||
# Example (variable prop):
|
||||
# prop = layout.row("mesh.extra_tools_help")
|
||||
# prop.help_ids = "default"
|
||||
# prop.popup_size = 400
|
||||
# Example (with using the variable props):
|
||||
# props = layout.row("mesh.extra_tools_help")
|
||||
# props.help_ids = "default"
|
||||
# props.popup_size = 400
|
||||
|
||||
|
||||
import bpy
|
||||
|
@ -24,16 +24,16 @@ class MESH_OT_extra_tools_help(Operator):
|
|||
bl_options = {'REGISTER'}
|
||||
|
||||
help_ids = StringProperty(
|
||||
name="ID of the Operator to display",
|
||||
options={'HIDDEN'},
|
||||
default="default"
|
||||
)
|
||||
name="ID of the Operator to display",
|
||||
options={'HIDDEN'},
|
||||
default="default"
|
||||
)
|
||||
popup_size = IntProperty(
|
||||
name="Size of the Help Pop-up Menu",
|
||||
default=350,
|
||||
min=100,
|
||||
max=600,
|
||||
)
|
||||
name="Size of the Help Pop-up Menu",
|
||||
default=350,
|
||||
min=100,
|
||||
max=600,
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -55,144 +55,174 @@ def help_custom_draw(identifier="default"):
|
|||
# and call them separately
|
||||
# In case nothing is passed from the UI call, the returned list is default
|
||||
# If undefined one is passed, it will return a warning message
|
||||
help_text = {"default": [
|
||||
"This is a placeholder text",
|
||||
"Please fill up the entries in the " + __name__ + " script",
|
||||
],
|
||||
"random_vertices": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Vertices",
|
||||
"Randomize displaced positions",
|
||||
"Note:",
|
||||
"There is an option to use Vertex Weights for displacement",
|
||||
"Before use, don't forget to assign after updating the Group Weight",
|
||||
],
|
||||
"mesh_vertex_chamfer": [
|
||||
"To use:",
|
||||
"Make a selection or selection of vertices",
|
||||
"Result is a triangle Chamfer, works on a single vertex",
|
||||
"Note:",
|
||||
"The difference to the vertex Bevel is that original geometry",
|
||||
"(selected vertices) can be kept as an option",
|
||||
"Limitation:",
|
||||
"In some cases, may need to press F to fill the result",
|
||||
],
|
||||
"mesh_filletplus": [
|
||||
"To use:",
|
||||
"Select two adjacent edges and press Fillet button",
|
||||
"Limitation:",
|
||||
"Works on a mesh whose all faces share the same normal",
|
||||
"(Flat Surface - faces have the same direction)",
|
||||
"Planes with already round corners can produce unsatisfactory results",
|
||||
"Only boundary edges will be evaluated",
|
||||
],
|
||||
"mesh_offset_edges": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Edges",
|
||||
"Extrude, rotate extrusions and more",
|
||||
"Limitation:",
|
||||
"Operates only on separate Edge loops selections",
|
||||
"(i.e. Edge loops that are not connected by a selected edge)",
|
||||
],
|
||||
"mesh_edge_roundifier": [
|
||||
"To use:",
|
||||
"Select a single or multiple Edges",
|
||||
"Make Arcs with various parameters",
|
||||
"Reference, Rotation, Scaling, Connection and Offset",
|
||||
"Note:",
|
||||
"The Mode - Reset button restores the default values",
|
||||
],
|
||||
"mesh_edges_length": [
|
||||
"To use:",
|
||||
"Select a single or multiple Edges",
|
||||
"Change length with various parameters",
|
||||
"Limitation:",
|
||||
"Does not operate on edges that share a vertex",
|
||||
"If the selection wasn't done in Edge Selection mode,",
|
||||
"the option Active will not work (due to Blender's limitation)",
|
||||
],
|
||||
"mesh_to_wall": [
|
||||
"To use:",
|
||||
"Extrudes flat along edges",
|
||||
"Adds depth on both sides of an edge wire",
|
||||
"Limitation:",
|
||||
"Works best on Flat surfaces i.e. Ground Plan like geometry",
|
||||
],
|
||||
"mesh_mextrude_plus": [
|
||||
"To use:",
|
||||
"Make a selection of Faces",
|
||||
"Extrude with Rotation, Scaling, Variation,",
|
||||
"Randomization and Offset parameters",
|
||||
"Limitation:",
|
||||
"Works only with selections that enclose Faces",
|
||||
"(i.e. all Edges or Vertices of a Face selected)",
|
||||
],
|
||||
"mesh_extrude_and_reshape": [
|
||||
"To use:",
|
||||
"Extrude Face and merge Edge intersections,",
|
||||
"between the mesh and the new Edges",
|
||||
"Note:",
|
||||
"If selected Vertices don't form Face they will be",
|
||||
"still extruded in the same direction",
|
||||
"Limitation:",
|
||||
"Works only with the last selected face",
|
||||
"(or all Edges or Vertices of a Face selected)",
|
||||
],
|
||||
"face_inset_fillet": [
|
||||
"To use:",
|
||||
"Select one or multiple faces and inset",
|
||||
"Inset square, circle or outside",
|
||||
"Note:",
|
||||
"Radius: use remove doubles to tidy joins",
|
||||
"Out: select and use normals flip before extruding",
|
||||
"Limitation:",
|
||||
"Using the Out option, sometimes can lead to unsatisfactory results",
|
||||
],
|
||||
"mesh_cut_faces": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Faces",
|
||||
"Some Functions work on a plane only",
|
||||
"Limitation:",
|
||||
"The selection must include at least two Faces with adjacent edges",
|
||||
"(Selections not sharing edges will not work)",
|
||||
],
|
||||
"split_solidify": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Faces",
|
||||
"Split Faces and Extrude results",
|
||||
"Similar to a shatter/explode effect",
|
||||
],
|
||||
"mesh_fastloop": [
|
||||
"To use:",
|
||||
"Activate the tool and hover over the mesh in the general area",
|
||||
"for the loop and left click once to confirm the loop placement",
|
||||
"Slide using the mouse to fine tune its position, left click to confirm",
|
||||
"Repeat the operations if needed for new loops",
|
||||
"Press Esc. twice to exit the tool",
|
||||
"Limitation:",
|
||||
"The tool has the same limitations as Loop Cut and Slide",
|
||||
"In the Operator Panel, only the last loop can be tweaked",
|
||||
],
|
||||
"mesh_pen_tool": [
|
||||
"To use:",
|
||||
"Press Ctrl + D key or click Draw button",
|
||||
"To draw along x use SHIFT + MOUSEMOVE",
|
||||
"To draw along y use ALT + MOUSEMOVE",
|
||||
"Press Ctrl to toggle Extrude at Cursor tool",
|
||||
"Right click to finish drawing or",
|
||||
"Press Esc to cancel",
|
||||
],
|
||||
"pkhg_faces": [
|
||||
"To use:",
|
||||
"Needs a Face Selection in Edit Mode",
|
||||
"Select an option from Face Types drop down list",
|
||||
"Extrude, rotate extrusions and more",
|
||||
"Toggle Edit Mode after use",
|
||||
"Note:",
|
||||
"After using the operator, normals could need repair,",
|
||||
"or Removing Doubles",
|
||||
],
|
||||
}
|
||||
help_text = {
|
||||
"default": [
|
||||
"This is a placeholder text",
|
||||
"Please fill up the entries in the " + __name__ + " script",
|
||||
],
|
||||
"random_vertices": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Vertices",
|
||||
"Randomize displaced positions",
|
||||
"Note:",
|
||||
"There is an option to use Vertex Weights for displacement",
|
||||
"Prior to use, don't forget to assign after updating the Group Weight",
|
||||
],
|
||||
"mesh_vertex_chamfer": [
|
||||
"To use:",
|
||||
"Make a selection or selection of vertices",
|
||||
"Result is a triangle Chamfer, works on a single vertex",
|
||||
"Note:",
|
||||
"The difference to the vertex Bevel is that original geometry",
|
||||
"(selected vertices) can optionally be kept and displaced",
|
||||
"Limitation:",
|
||||
"In some cases, may need to press F to fill the result",
|
||||
],
|
||||
"mesh_filletplus": [
|
||||
"To use:",
|
||||
"Select two adjacent edges and press Fillet button",
|
||||
"Limitation:",
|
||||
"Works on a mesh with all faces sharing the same normal",
|
||||
"(Flat Surface - faces have the same direction)",
|
||||
"Planes with already round corners can produce unsatisfactory results",
|
||||
"Only boundary edges will be evaluated",
|
||||
],
|
||||
"mesh_offset_edges": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Edges",
|
||||
"Extrude, rotate extrusions and more",
|
||||
"Limitation:",
|
||||
"Operates only on separate Edge loops selections",
|
||||
"(i.e. Edge loops that are not connected by a selected edge)",
|
||||
],
|
||||
"mesh_edge_roundifier": [
|
||||
"To use:",
|
||||
"Select a single or multiple Edges",
|
||||
"Make Arcs with various parameters",
|
||||
"Reference, Rotation, Scaling, Connection and Offset",
|
||||
"Note:",
|
||||
"The Mode - Reset button restores the default values",
|
||||
],
|
||||
"mesh_edges_length": [
|
||||
"To use:",
|
||||
"Select a single or multiple Edges",
|
||||
"Change length with various parameters",
|
||||
"Limitation:",
|
||||
"Does not operate on edges that share a vertex",
|
||||
"If the selection wasn't done in Edge Selection mode,",
|
||||
"the option Active will not work (due to Blender's limitation)",
|
||||
],
|
||||
"mesh_edges_floor_plan": [
|
||||
"To use:",
|
||||
"Starting edges will be flat extruded forming faces strips",
|
||||
"on the inside. Similar to using Face fill inset select outer",
|
||||
"Methods:",
|
||||
"Edge Net: Fills the edge grid with faces then Inset",
|
||||
"Single Face: Single Face fill (all Edges) then Inset",
|
||||
"Solidify: Extrude along defined axis, apply a Solidify modifier",
|
||||
"Note:",
|
||||
"Grid Fill and Single Face sometimes need tweaking with the options",
|
||||
"Limitation:",
|
||||
"Depending on the input geometry, Keep Ngons sometimes needs to be",
|
||||
"enabled to produce any results",
|
||||
"Edge Net and Single Face depend on bmesh face fill and inset",
|
||||
"that sometimes can fail to produce good results",
|
||||
"Avoid using Single Face Method on Edges that define a Volume - like Suzanne",
|
||||
"Solidify method works best for flat surfaces and complex geometry",
|
||||
],
|
||||
"mesh_mextrude_plus": [
|
||||
"To use:",
|
||||
"Make a selection of Faces",
|
||||
"Extrude with Rotation, Scaling, Variation,",
|
||||
"Randomization and Offset parameters",
|
||||
"Limitation:",
|
||||
"Works only with selections that enclose Faces",
|
||||
"(i.e. all Edges or Vertices of a Face selected)",
|
||||
],
|
||||
"mesh_extrude_and_reshape": [
|
||||
"To use:",
|
||||
"Extrude Face and merge Edge intersections,",
|
||||
"between the mesh and the new Edges",
|
||||
"Note:",
|
||||
"If selected Vertices don't form Face they will be",
|
||||
"still extruded in the same direction",
|
||||
"Limitation:",
|
||||
"Works only with the last selected face",
|
||||
"(or all Edges or Vertices of a Face selected)",
|
||||
],
|
||||
"face_inset_fillet": [
|
||||
"To use:",
|
||||
"Select one or multiple faces and inset",
|
||||
"Inset square, circle or outside",
|
||||
"Note:",
|
||||
"Radius: use remove doubles to tidy joins",
|
||||
"Out: select and use normals flip before extruding",
|
||||
"Limitation:",
|
||||
"Using the Out option, sometimes can lead to unsatisfactory results",
|
||||
],
|
||||
"mesh_cut_faces": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Faces",
|
||||
"Some Functions work on a plane only",
|
||||
"Limitation:",
|
||||
"The selection must include at least two Faces with adjacent edges",
|
||||
"(Selections not sharing edges will not work)",
|
||||
],
|
||||
"split_solidify": [
|
||||
"To use:",
|
||||
"Make a selection or selection of Faces",
|
||||
"Split Faces and Extrude results",
|
||||
"Similar to a shatter/explode effect",
|
||||
],
|
||||
"mesh_fastloop": [
|
||||
"To use:",
|
||||
"Activate the tool and hover over the mesh in the general area",
|
||||
"for the loop and left click once to confirm the loop placement",
|
||||
"Slide using the mouse to fine tune its position, left click to confirm",
|
||||
"Repeat the operations if needed for new loops",
|
||||
"Press Esc. twice to exit the tool",
|
||||
"Limitation:",
|
||||
"The tool has the same limitations as Loop Cut and Slide",
|
||||
"In the Operator Panel, only the last loop can be tweaked",
|
||||
],
|
||||
"mesh_pen_tool": [
|
||||
"To use:",
|
||||
"Press Ctrl + D key or click Draw button",
|
||||
"To draw along x use SHIFT + MOUSEMOVE",
|
||||
"To draw along y use ALT + MOUSEMOVE",
|
||||
"Press Ctrl to toggle Extrude at Cursor tool",
|
||||
"Right click to finish drawing or",
|
||||
"Press Esc to cancel",
|
||||
],
|
||||
"pkhg_faces": [
|
||||
"To use:",
|
||||
"Needs a Face Selection in Edit Mode",
|
||||
"Select an option from Face Types drop down list",
|
||||
"Extrude, rotate extrusions and more",
|
||||
"Toggle Edit Mode after use",
|
||||
"Note:",
|
||||
"After using the operator, normals could need repair,",
|
||||
"or Removing Doubles",
|
||||
],
|
||||
"vertex_align": [
|
||||
"To use:",
|
||||
"Select vertices that you want to align and click Align button",
|
||||
"Options include aligning to defined Custom coordinates or",
|
||||
"Stored vertex - (a single selected one with Store Selected Vertex)",
|
||||
"Note:",
|
||||
"Use Stored Coordinates - allows to save a set of coordinates",
|
||||
"as a starting point that can be tweaked on during operation",
|
||||
],
|
||||
"mesh_check": [
|
||||
"To use:",
|
||||
"Tris and Ngons will select Faces by corensponding type",
|
||||
"Display faces will color the faces depending on the",
|
||||
"defined Colors, Edges' width and Face Opacity",
|
||||
"Note:",
|
||||
"The Faces' type count is already included elsewhere:",
|
||||
"In the Properties Editor > Data > Face / Info Select Panel",
|
||||
],
|
||||
}
|
||||
|
||||
if identifier in help_text:
|
||||
return help_text[identifier]
|
||||
|
@ -202,13 +232,11 @@ def help_custom_draw(identifier="default"):
|
|||
|
||||
# register
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
pass
|
||||
bpy.utils.register_class(MESH_OT_extra_tools_help)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
pass
|
||||
bpy.utils.unregister_class(MESH_OT_extra_tools_help)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
#
|
||||
|
||||
# Repeats extrusion + rotation + scale for one or more faces
|
||||
# Original code by liero
|
||||
# Update by Jimmy Hazevoet 03/2017 for Blender 2.79
|
||||
# normal rotation, probability, scaled offset, object coörds, initial and per step noise
|
||||
# normal rotation, probability, scaled offset, object coords, initial and per step noise
|
||||
|
||||
|
||||
bl_info = {
|
||||
|
@ -31,7 +31,6 @@ bl_info = {
|
|||
"description": "Repeat extrusions from faces to create organic shapes",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "https://developer.blender.org/T28570",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
|
@ -41,32 +40,38 @@ import random
|
|||
from bpy.types import Operator
|
||||
from random import gauss
|
||||
from math import radians
|
||||
from mathutils import Euler, Vector
|
||||
from mathutils import (
|
||||
Euler, Vector,
|
||||
)
|
||||
from bpy.props import (
|
||||
FloatProperty,
|
||||
IntProperty,
|
||||
BoolProperty,
|
||||
EnumProperty,
|
||||
)
|
||||
|
||||
|
||||
def gloc(self, r):
|
||||
return Vector((self.offx, self.offy, self.offz))
|
||||
|
||||
|
||||
def vloc(self, r):
|
||||
random.seed(self.ran + r)
|
||||
return self.off * (1 + gauss(0, self.var1 / 3))
|
||||
|
||||
|
||||
def nrot(self, n):
|
||||
return Euler((radians(self.nrotx) * n[0],
|
||||
radians(self.nroty) * n[1],
|
||||
radians(self.nrotz) * n[2]), 'XYZ')
|
||||
|
||||
|
||||
def vrot(self, r):
|
||||
random.seed(self.ran + r)
|
||||
return Euler((radians(self.rotx) + gauss(0, self.var2 / 3),
|
||||
radians(self.roty) + gauss(0, self.var2 / 3),
|
||||
radians(self.rotz) + gauss(0, self.var2 / 3)), 'XYZ')
|
||||
|
||||
|
||||
def vsca(self, r):
|
||||
random.seed(self.ran + r)
|
||||
return self.sca * (1 + gauss(0, self.var3 / 3))
|
||||
|
@ -80,142 +85,142 @@ class MExtrude(Operator):
|
|||
bl_options = {"REGISTER", "UNDO", "PRESET"}
|
||||
|
||||
off = FloatProperty(
|
||||
name="Offset",
|
||||
soft_min=0.001, soft_max=10,
|
||||
min=-100, max=100,
|
||||
default=1.0,
|
||||
description="Translation"
|
||||
)
|
||||
name="Offset",
|
||||
soft_min=0.001, soft_max=10,
|
||||
min=-100, max=100,
|
||||
default=1.0,
|
||||
description="Translation"
|
||||
)
|
||||
offx = FloatProperty(
|
||||
name="Loc X",
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
min=-100.0, max=100.0,
|
||||
default=0.0,
|
||||
description="Global translation X"
|
||||
)
|
||||
name="Loc X",
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
min=-100.0, max=100.0,
|
||||
default=0.0,
|
||||
description="Global Translation X"
|
||||
)
|
||||
offy = FloatProperty(
|
||||
name="Loc Y",
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
min=-100.0, max=100.0,
|
||||
default=0.0,
|
||||
description="Global translation Y"
|
||||
)
|
||||
name="Loc Y",
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
min=-100.0, max=100.0,
|
||||
default=0.0,
|
||||
description="Global Translation Y"
|
||||
)
|
||||
offz = FloatProperty(
|
||||
name="Loc Z",
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
min=-100.0, max=100.0,
|
||||
default=0.0,
|
||||
description="Global translation Z"
|
||||
)
|
||||
name="Loc Z",
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
min=-100.0, max=100.0,
|
||||
default=0.0,
|
||||
description="Global Translation Z"
|
||||
)
|
||||
rotx = FloatProperty(
|
||||
name="Rot X",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=0,
|
||||
description="X Rotation"
|
||||
)
|
||||
name="Rot X",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=0,
|
||||
description="X Rotation"
|
||||
)
|
||||
roty = FloatProperty(
|
||||
name="Rot Y",
|
||||
min=-85, max=85,
|
||||
soft_min=-30,
|
||||
soft_max=30,
|
||||
default=0,
|
||||
description="Y Rotation"
|
||||
)
|
||||
name="Rot Y",
|
||||
min=-85, max=85,
|
||||
soft_min=-30,
|
||||
soft_max=30,
|
||||
default=0,
|
||||
description="Y Rotation"
|
||||
)
|
||||
rotz = FloatProperty(
|
||||
name="Rot Z",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=-0,
|
||||
description="Z Rotation"
|
||||
)
|
||||
name="Rot Z",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=-0,
|
||||
description="Z Rotation"
|
||||
)
|
||||
nrotx = FloatProperty(
|
||||
name="N Rot X",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=0,
|
||||
description="Normal X Rotation"
|
||||
)
|
||||
name="N Rot X",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=0,
|
||||
description="Normal X Rotation"
|
||||
)
|
||||
nroty = FloatProperty(
|
||||
name="N Rot Y",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=0,
|
||||
description="Normal Y Rotation"
|
||||
)
|
||||
name="N Rot Y",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=0,
|
||||
description="Normal Y Rotation"
|
||||
)
|
||||
nrotz = FloatProperty(
|
||||
name="N Rot Z",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=-0,
|
||||
description="Normal Z Rotation"
|
||||
)
|
||||
name="N Rot Z",
|
||||
min=-85, max=85,
|
||||
soft_min=-30, soft_max=30,
|
||||
default=-0,
|
||||
description="Normal Z Rotation"
|
||||
)
|
||||
sca = FloatProperty(
|
||||
name="Scale",
|
||||
min=0.01, max=10,
|
||||
soft_min=0.5, soft_max=1.5,
|
||||
default=1.0,
|
||||
description="Scaling of the selected faces after extrusion"
|
||||
)
|
||||
name="Scale",
|
||||
min=0.01, max=10,
|
||||
soft_min=0.5, soft_max=1.5,
|
||||
default=1.0,
|
||||
description="Scaling of the selected faces after extrusion"
|
||||
)
|
||||
var1 = FloatProperty(
|
||||
name="Offset Var", min=-10, max=10,
|
||||
soft_min=-1, soft_max=1,
|
||||
default=0,
|
||||
description="Offset variation"
|
||||
)
|
||||
name="Offset Var", min=-10, max=10,
|
||||
soft_min=-1, soft_max=1,
|
||||
default=0,
|
||||
description="Offset variation"
|
||||
)
|
||||
var2 = FloatProperty(
|
||||
name="Rotation Var",
|
||||
min=-10, max=10,
|
||||
soft_min=-1, soft_max=1,
|
||||
default=0,
|
||||
description="Rotation variation"
|
||||
)
|
||||
name="Rotation Var",
|
||||
min=-10, max=10,
|
||||
soft_min=-1, soft_max=1,
|
||||
default=0,
|
||||
description="Rotation variation"
|
||||
)
|
||||
var3 = FloatProperty(
|
||||
name="Scale Noise",
|
||||
min=-10, max=10,
|
||||
soft_min=-1, soft_max=1,
|
||||
default=0,
|
||||
description="Scaling noise"
|
||||
)
|
||||
name="Scale Noise",
|
||||
min=-10, max=10,
|
||||
soft_min=-1, soft_max=1,
|
||||
default=0,
|
||||
description="Scaling noise"
|
||||
)
|
||||
var4 = IntProperty(
|
||||
name="Probability",
|
||||
min=0, max=100,
|
||||
default=100,
|
||||
description="Probability, chance of extruding a face"
|
||||
)
|
||||
name="Probability",
|
||||
min=0, max=100,
|
||||
default=100,
|
||||
description="Probability, chance of extruding a face"
|
||||
)
|
||||
num = IntProperty(
|
||||
name="Repeat",
|
||||
min=1, max=500,
|
||||
soft_max=100,
|
||||
default=5,
|
||||
description="Repetitions"
|
||||
)
|
||||
name="Repeat",
|
||||
min=1, max=500,
|
||||
soft_max=100,
|
||||
default=5,
|
||||
description="Repetitions"
|
||||
)
|
||||
ran = IntProperty(
|
||||
name="Seed",
|
||||
min=-9999, max=9999,
|
||||
default=0,
|
||||
description="Seed to feed random values"
|
||||
)
|
||||
name="Seed",
|
||||
min=-9999, max=9999,
|
||||
default=0,
|
||||
description="Seed to feed random values"
|
||||
)
|
||||
opt1 = BoolProperty(
|
||||
name="Polygon coördinates",
|
||||
default=True,
|
||||
description="Polygon coördinates, Object coördinates"
|
||||
)
|
||||
name="Polygon coordinates",
|
||||
default=True,
|
||||
description="Polygon coordinates, Object coordinates"
|
||||
)
|
||||
opt2 = BoolProperty(
|
||||
name="Proportional offset",
|
||||
default=False,
|
||||
description="Scale * Offset"
|
||||
)
|
||||
name="Proportional offset",
|
||||
default=False,
|
||||
description="Scale * Offset"
|
||||
)
|
||||
opt3 = BoolProperty(
|
||||
name="Per step rotation noise",
|
||||
default=False,
|
||||
description="Per step rotation noise, Initial rotation noise"
|
||||
)
|
||||
name="Per step rotation noise",
|
||||
default=False,
|
||||
description="Per step rotation noise, Initial rotation noise"
|
||||
)
|
||||
opt4 = BoolProperty(
|
||||
name="Per step scale noise",
|
||||
default=False,
|
||||
description="Per step scale noise, Initial scale noise"
|
||||
)
|
||||
name="Per step scale noise",
|
||||
default=False,
|
||||
description="Per step scale noise, Initial scale noise"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -235,9 +240,9 @@ class MExtrude(Operator):
|
|||
col.prop(self, "rotx", slider=True)
|
||||
col.prop(self, "roty", slider=True)
|
||||
col.prop(self, "rotz", slider=True)
|
||||
col.prop(self, 'nrotx', slider=True)
|
||||
col.prop(self, 'nroty', slider=True)
|
||||
col.prop(self, 'nrotz', slider=True)
|
||||
col.prop(self, "nrotx", slider=True)
|
||||
col.prop(self, "nroty", slider=True)
|
||||
col.prop(self, "nrotz", slider=True)
|
||||
col = layout.column(align=True)
|
||||
col.prop(self, "sca", slider=True)
|
||||
|
||||
|
@ -288,10 +293,8 @@ class MExtrude(Operator):
|
|||
|
||||
# extrusion loop
|
||||
for r in range(self.num):
|
||||
|
||||
## random probability % for extrusions
|
||||
if self.var4 > int(random.random()*100):
|
||||
|
||||
# random probability % for extrusions
|
||||
if self.var4 > int(random.random() * 100):
|
||||
nf = of.copy()
|
||||
nf.normal_update()
|
||||
no = nf.normal.copy()
|
||||
|
@ -348,7 +351,8 @@ class MExtrude(Operator):
|
|||
bpy.ops.object.mode_set(mode=om)
|
||||
|
||||
if not len(sel):
|
||||
self.report({"WARNING"}, "No suitable Face selection found. Operation cancelled")
|
||||
self.report({"WARNING"},
|
||||
"No suitable Face selection found. Operation cancelled")
|
||||
return {'CANCELLED'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
bl_info = {
|
||||
"name": "Offset Edges",
|
||||
|
@ -24,8 +24,8 @@ bl_info = {
|
|||
"location": "VIEW3D > Edge menu(CTRL-E) > Offset Edges",
|
||||
"description": "Offset Edges",
|
||||
"warning": "",
|
||||
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Modeling/offset_edges",
|
||||
"tracker_url": "",
|
||||
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
|
||||
"Py/Scripts/Modeling/offset_edges",
|
||||
"category": "Mesh"}
|
||||
|
||||
import bpy
|
||||
|
@ -510,103 +510,103 @@ class OffsetEdges(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
geometry_mode = EnumProperty(
|
||||
items=[('offset', "Offset", "Offset edges"),
|
||||
('extrude', "Extrude", "Extrude edges"),
|
||||
('move', "Move", "Move selected edges")],
|
||||
name="Geometry mode",
|
||||
default='offset',
|
||||
update=use_cashes
|
||||
)
|
||||
items=[('offset', "Offset", "Offset edges"),
|
||||
('extrude', "Extrude", "Extrude edges"),
|
||||
('move', "Move", "Move selected edges")],
|
||||
name="Geometry mode",
|
||||
default='offset',
|
||||
update=use_cashes
|
||||
)
|
||||
width = FloatProperty(
|
||||
name="Width",
|
||||
default=.2,
|
||||
precision=4, step=1,
|
||||
update=use_cashes
|
||||
)
|
||||
name="Width",
|
||||
default=.2,
|
||||
precision=4, step=1,
|
||||
update=use_cashes
|
||||
)
|
||||
flip_width = BoolProperty(
|
||||
name="Flip Width",
|
||||
default=False,
|
||||
description="Flip width direction",
|
||||
update=use_cashes
|
||||
)
|
||||
name="Flip Width",
|
||||
default=False,
|
||||
description="Flip width direction",
|
||||
update=use_cashes
|
||||
)
|
||||
depth = FloatProperty(
|
||||
name="Depth",
|
||||
default=.0,
|
||||
precision=4, step=1,
|
||||
update=use_cashes
|
||||
)
|
||||
name="Depth",
|
||||
default=.0,
|
||||
precision=4, step=1,
|
||||
update=use_cashes
|
||||
)
|
||||
flip_depth = BoolProperty(
|
||||
name="Flip Depth",
|
||||
default=False,
|
||||
description="Flip depth direction",
|
||||
update=use_cashes
|
||||
)
|
||||
name="Flip Depth",
|
||||
default=False,
|
||||
description="Flip depth direction",
|
||||
update=use_cashes
|
||||
)
|
||||
depth_mode = EnumProperty(
|
||||
items=[('angle', "Angle", "Angle"),
|
||||
('depth', "Depth", "Depth")],
|
||||
name="Depth mode",
|
||||
default='angle',
|
||||
update=use_cashes
|
||||
)
|
||||
items=[('angle', "Angle", "Angle"),
|
||||
('depth', "Depth", "Depth")],
|
||||
name="Depth mode",
|
||||
default='angle',
|
||||
update=use_cashes
|
||||
)
|
||||
angle = FloatProperty(
|
||||
name="Angle", default=0,
|
||||
precision=3, step=.1,
|
||||
min=-2 * pi, max=2 * pi,
|
||||
subtype='ANGLE',
|
||||
description="Angle",
|
||||
update=use_cashes
|
||||
)
|
||||
name="Angle", default=0,
|
||||
precision=3, step=.1,
|
||||
min=-2 * pi, max=2 * pi,
|
||||
subtype='ANGLE',
|
||||
description="Angle",
|
||||
update=use_cashes
|
||||
)
|
||||
flip_angle = BoolProperty(
|
||||
name="Flip Angle",
|
||||
default=False,
|
||||
description="Flip Angle",
|
||||
update=use_cashes
|
||||
)
|
||||
name="Flip Angle",
|
||||
default=False,
|
||||
description="Flip Angle",
|
||||
update=use_cashes
|
||||
)
|
||||
follow_face = BoolProperty(
|
||||
name="Follow Face",
|
||||
default=False,
|
||||
description="Offset along faces around"
|
||||
)
|
||||
name="Follow Face",
|
||||
default=False,
|
||||
description="Offset along faces around"
|
||||
)
|
||||
mirror_modifier = BoolProperty(
|
||||
name="Mirror Modifier",
|
||||
default=False,
|
||||
description="Take into account of Mirror modifier"
|
||||
)
|
||||
name="Mirror Modifier",
|
||||
default=False,
|
||||
description="Take into account of Mirror modifier"
|
||||
)
|
||||
edge_rail = BoolProperty(
|
||||
name="Edge Rail",
|
||||
default=False,
|
||||
description="Align vertices along inner edges"
|
||||
)
|
||||
name="Edge Rail",
|
||||
default=False,
|
||||
description="Align vertices along inner edges"
|
||||
)
|
||||
edge_rail_only_end = BoolProperty(
|
||||
name="Edge Rail Only End",
|
||||
default=False,
|
||||
description="Apply edge rail to end verts only"
|
||||
)
|
||||
name="Edge Rail Only End",
|
||||
default=False,
|
||||
description="Apply edge rail to end verts only"
|
||||
)
|
||||
threshold = FloatProperty(
|
||||
name="Flat Face Threshold",
|
||||
default=radians(0.05), precision=5,
|
||||
step=1.0e-4, subtype='ANGLE',
|
||||
description="If difference of angle between two adjacent faces is "
|
||||
"below this value, those faces are regarded as flat",
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
name="Flat Face Threshold",
|
||||
default=radians(0.05), precision=5,
|
||||
step=1.0e-4, subtype='ANGLE',
|
||||
description="If difference of angle between two adjacent faces is "
|
||||
"below this value, those faces are regarded as flat",
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
caches_valid = BoolProperty(
|
||||
name="Caches Valid",
|
||||
default=False,
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
name="Caches Valid",
|
||||
default=False,
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
angle_presets = EnumProperty(
|
||||
items=[('0°', "0°", "0°"),
|
||||
('15°', "15°", "15°"),
|
||||
('30°', "30°", "30°"),
|
||||
('45°', "45°", "45°"),
|
||||
('60°', "60°", "60°"),
|
||||
('75°', "75°", "75°"),
|
||||
('90°', "90°", "90°"), ],
|
||||
name="Angle Presets",
|
||||
default='0°',
|
||||
update=assign_angle_presets
|
||||
)
|
||||
items=[('0°', "0°", "0°"),
|
||||
('15°', "15°", "15°"),
|
||||
('30°', "30°", "30°"),
|
||||
('45°', "45°", "45°"),
|
||||
('60°', "60°", "60°"),
|
||||
('75°', "75°", "75°"),
|
||||
('90°', "90°", "90°"), ],
|
||||
name="Angle Presets",
|
||||
default='0°',
|
||||
update=assign_angle_presets
|
||||
)
|
||||
|
||||
_cache_offset_infos = None
|
||||
_cache_edges_orig_ixs = None
|
||||
|
|
|
@ -1,33 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
bl_info = {
|
||||
"name": "Pen Tool",
|
||||
"author": "zmj100",
|
||||
"version": (0, 2, 9),
|
||||
"version": (0, 3, 1),
|
||||
"blender": (2, 78, 0),
|
||||
"location": "View3D > Tool Shelf",
|
||||
"description": "",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh",
|
||||
}
|
||||
|
||||
|
@ -47,8 +46,14 @@ from bpy.props import (
|
|||
PointerProperty,
|
||||
BoolProperty
|
||||
)
|
||||
from bpy_extras.view3d_utils import region_2d_to_location_3d, location_3d_to_region_2d
|
||||
from mathutils import Vector, Matrix
|
||||
from bpy_extras.view3d_utils import (
|
||||
region_2d_to_location_3d,
|
||||
location_3d_to_region_2d,
|
||||
)
|
||||
from mathutils import (
|
||||
Vector,
|
||||
Matrix,
|
||||
)
|
||||
from math import degrees
|
||||
|
||||
|
||||
|
@ -117,10 +122,10 @@ def draw_callback_px(self, context):
|
|||
# location 3d
|
||||
if context.scene.pen_tool_props.b2 is True:
|
||||
mloc3d = region_2d_to_location_3d(
|
||||
context.region,
|
||||
context.space_data.region_3d, Vector((pt_buf.x, pt_buf.y)),
|
||||
pt_buf.depth_location
|
||||
)
|
||||
context.region,
|
||||
context.space_data.region_3d, Vector((pt_buf.x, pt_buf.y)),
|
||||
pt_buf.depth_location
|
||||
)
|
||||
blf.position(font_id, pt_buf.x + 15, pt_buf.y - 15, 0)
|
||||
blf.size(font_id, font_size, context.user_preferences.system.dpi)
|
||||
blf.draw(font_id,
|
||||
|
@ -135,17 +140,19 @@ def draw_callback_px(self, context):
|
|||
bgl.glPointSize(4.0)
|
||||
bgl.glBegin(bgl.GL_POINTS)
|
||||
for i in pt_buf.list_m_loc_3d:
|
||||
loc_0 = location_3d_to_region_2d(context.region, context.space_data.region_3d, i)
|
||||
loc_0 = location_3d_to_region_2d(
|
||||
context.region, context.space_data.region_3d, i
|
||||
)
|
||||
bgl.glVertex2f(loc_0[0], loc_0[1])
|
||||
bgl.glEnd()
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
# text next to the mouse
|
||||
m_loc_3d = region_2d_to_location_3d(
|
||||
context.region,
|
||||
context.space_data.region_3d, Vector((pt_buf.x, pt_buf.y)),
|
||||
pt_buf.depth_location
|
||||
)
|
||||
context.region,
|
||||
context.space_data.region_3d, Vector((pt_buf.x, pt_buf.y)),
|
||||
pt_buf.depth_location
|
||||
)
|
||||
vec0 = pt_buf.list_m_loc_3d[-1] - m_loc_3d
|
||||
blf.position(font_id, pt_buf.x + 15, pt_buf.y + 15, 0)
|
||||
blf.size(font_id, font_size, context.user_preferences.system.dpi)
|
||||
|
@ -234,9 +241,9 @@ def draw_callback_px(self, context):
|
|||
pass
|
||||
else:
|
||||
loc_4 = location_3d_to_region_2d(
|
||||
context.region, context.space_data.region_3d,
|
||||
pt_buf.list_m_loc_3d[h]
|
||||
)
|
||||
context.region, context.space_data.region_3d,
|
||||
pt_buf.list_m_loc_3d[h]
|
||||
)
|
||||
bgl.glColor4f(0.0, 1.0, 0.525, alpha)
|
||||
blf.position(font_id, loc_4[0] + 10, loc_4[1] + 10, 0)
|
||||
blf.size(font_id, font_size, context.user_preferences.system.dpi)
|
||||
|
@ -252,41 +259,41 @@ def draw_callback_px(self, context):
|
|||
|
||||
class pen_tool_properties(PropertyGroup):
|
||||
a = FloatProperty(
|
||||
name="Alpha",
|
||||
description="Set Font Alpha",
|
||||
default=1.0,
|
||||
min=0.1, max=1.0,
|
||||
step=10,
|
||||
precision=1
|
||||
)
|
||||
name="Alpha",
|
||||
description="Set Font Alpha",
|
||||
default=1.0,
|
||||
min=0.1, max=1.0,
|
||||
step=10,
|
||||
precision=1
|
||||
)
|
||||
fs = IntProperty(
|
||||
name="Size",
|
||||
description="Set Font Size",
|
||||
default=14,
|
||||
min=12, max=40,
|
||||
step=1
|
||||
)
|
||||
name="Size",
|
||||
description="Set Font Size",
|
||||
default=14,
|
||||
min=12, max=40,
|
||||
step=1
|
||||
)
|
||||
b0 = BoolProperty(
|
||||
name="Angles",
|
||||
description="Display All Angles on Drawn Edges",
|
||||
default=False
|
||||
)
|
||||
name="Angles",
|
||||
description="Display All Angles on Drawn Edges",
|
||||
default=False
|
||||
)
|
||||
b1 = BoolProperty(
|
||||
name="Edge Length",
|
||||
description="Display All Lenghts of Drawn Edges",
|
||||
default=False
|
||||
)
|
||||
name="Edge Length",
|
||||
description="Display All Lenghts of Drawn Edges",
|
||||
default=False
|
||||
)
|
||||
b2 = BoolProperty(
|
||||
name="Mouse Location 3D",
|
||||
description="Display the location coordinates of the mouse cursor",
|
||||
default=False
|
||||
)
|
||||
name="Mouse Location 3D",
|
||||
description="Display the location coordinates of the mouse cursor",
|
||||
default=False
|
||||
)
|
||||
restore_view = BoolProperty(
|
||||
name="Restore View",
|
||||
description="After the tool has finished, is the Viewport restored\n"
|
||||
"to it's previous state",
|
||||
default=True
|
||||
)
|
||||
name="Restore View",
|
||||
description="After the tool has finished, is the Viewport restored\n"
|
||||
"to it's previous state",
|
||||
default=True
|
||||
)
|
||||
|
||||
|
||||
class pt_buf():
|
||||
|
@ -314,25 +321,27 @@ class pen_tool_panel(Panel):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
pen_tool_props = context.scene.pen_tool_props
|
||||
|
||||
if pt_buf.sws == "on":
|
||||
layout.active = False
|
||||
layout.label("Pen Tool Active")
|
||||
layout.label(text="Pen Tool Active", icon="INFO")
|
||||
else:
|
||||
layout.label("Font:")
|
||||
col = layout.column(align=True)
|
||||
col.label("Font:")
|
||||
col.prop(pen_tool_props, "fs", text="Size", slider=True)
|
||||
col.prop(pen_tool_props, "a", text="Alpha", slider=True)
|
||||
|
||||
row = layout.split(0.50, align=True)
|
||||
row.prop(context.scene.pen_tool_props, "fs", text="Size", slider=True)
|
||||
row.prop(context.scene.pen_tool_props, "a", text="Alpha", slider=True)
|
||||
col = layout.column(align=True)
|
||||
col.label("Settings:")
|
||||
col.prop(pen_tool_props, "b0", text="Angles", toggle=True)
|
||||
col.prop(pen_tool_props, "b1", text="Edge Length", toggle=True)
|
||||
col.prop(pen_tool_props, "b2", text="Mouse Location 3D", toggle=True)
|
||||
col.prop(pen_tool_props, "restore_view", text="Restore View", toggle=True)
|
||||
|
||||
layout.prop(context.scene.pen_tool_props, "b0", text="Angles")
|
||||
layout.prop(context.scene.pen_tool_props, "b1", text="Edge Length")
|
||||
layout.prop(context.scene.pen_tool_props, "b2", text="Mouse Location 3D")
|
||||
layout.prop(context.scene.pen_tool_props, "restore_view", text="Restore View")
|
||||
|
||||
row1 = layout.split(0.80, align=True)
|
||||
row1.operator("pen_tool.operator", text="Draw")
|
||||
row1.operator("mesh.extra_tools_help",
|
||||
split = layout.split(0.80, align=True)
|
||||
split.operator("pen_tool.operator", text="Draw")
|
||||
split.operator("mesh.extra_tools_help",
|
||||
icon="LAYER_USED").help_ids = "mesh_pen_tool"
|
||||
|
||||
|
||||
|
@ -343,10 +352,10 @@ class pen_tool_operator(Operator):
|
|||
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
||||
|
||||
text_location = IntProperty(
|
||||
name="",
|
||||
default=0,
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
name="",
|
||||
default=0,
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -498,7 +507,8 @@ class pen_tool_operator(Operator):
|
|||
self.text_location = region.width - 100
|
||||
if overlap:
|
||||
for region in context.area.regions:
|
||||
if region.type == 'TOOL_PROPS':
|
||||
# The Properties Region on the right is of UI type
|
||||
if region.type == "UI":
|
||||
self.text_location = self.text_location - region.width
|
||||
|
||||
if pt_buf.sws == 'on':
|
||||
|
@ -513,20 +523,22 @@ class pen_tool_operator(Operator):
|
|||
pt_buf.sws = 'on'
|
||||
return {'RUNNING_MODAL'}
|
||||
else:
|
||||
self.report({'WARNING'}, "Pen Tool: View3D not found, operation cancelled")
|
||||
self.report({'WARNING'}, "Pen Tool: Operation Cancelled. View3D not found")
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
class_list = [pen_tool_panel,
|
||||
pen_tool_operator,
|
||||
pen_tool_properties
|
||||
]
|
||||
class_list = (
|
||||
pen_tool_panel,
|
||||
pen_tool_operator,
|
||||
pen_tool_properties
|
||||
)
|
||||
|
||||
|
||||
KEYMAPS = (
|
||||
# First, keymap identifiers (last bool is True for modal km).
|
||||
(("3D View", "VIEW_3D", "WINDOW", False), (
|
||||
# Then a tuple of keymap items, defined by a dict of kwargs for the km new func, and a tuple of tuples (name, val)
|
||||
# Then a tuple of keymap items, defined by a dict of kwargs
|
||||
# for the km new func, and a tuple of tuples (name, val)
|
||||
# for ops properties, if needing non-default values.
|
||||
({"idname": pen_tool_operator.bl_idname, "type": 'D', "value": 'PRESS', "ctrl": True},
|
||||
()),
|
||||
|
|
|
@ -15,32 +15,34 @@
|
|||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# menu & updates by meta-androcto #
|
||||
# contributed to by Macouno, dustractor, liero, CoDEmanX, meta-androcto #
|
||||
# contributed to by :
|
||||
# Macouno, dustractor, liero, lijenstina, #
|
||||
# CoDEmanX, Dolf Veenvliet, meta-androcto #
|
||||
|
||||
bl_info = {
|
||||
"name": "Select Tools",
|
||||
"author": "Multiple Authors",
|
||||
"version": (0, 3),
|
||||
"version": (0, 3, 1),
|
||||
"blender": (2, 64, 0),
|
||||
"location": "Editmode Select Menu/Toolshelf Tools Tab",
|
||||
"description": "Adds More vert/face/edge select modes.",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"
|
||||
}
|
||||
|
||||
if "bpy" in locals():
|
||||
import imp
|
||||
imp.reload(mesh_select_by_direction)
|
||||
imp.reload(mesh_select_by_edge_length)
|
||||
imp.reload(mesh_select_by_pi)
|
||||
imp.reload(mesh_select_by_type)
|
||||
imp.reload(mesh_select_connected_faces)
|
||||
imp.reload(mesh_index_select)
|
||||
imp.reload(mesh_selection_topokit)
|
||||
imp.reload(mesh_info_select)
|
||||
import importlib
|
||||
importlib.reload(mesh_select_by_direction)
|
||||
importlib.reload(mesh_select_by_edge_length)
|
||||
importlib.reload(mesh_select_by_pi)
|
||||
importlib.reload(mesh_select_by_type)
|
||||
importlib.reload(mesh_select_connected_faces)
|
||||
importlib.reload(mesh_index_select)
|
||||
importlib.reload(mesh_selection_topokit)
|
||||
importlib.reload(mesh_info_select)
|
||||
else:
|
||||
from . import mesh_select_by_direction
|
||||
from . import mesh_select_by_edge_length
|
||||
|
|
|
@ -22,7 +22,7 @@ from bpy.props import (
|
|||
class SelVertEdgeFace(Operator):
|
||||
bl_idname = "mesh.select_vert_edge_face_index"
|
||||
bl_label = "Select mesh index"
|
||||
bl_description = "Select Vertices, Edges, Faces by index"
|
||||
bl_description = "Select Vertices, Edges, Faces by their indices"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
select_type = EnumProperty(
|
||||
|
@ -59,7 +59,6 @@ class SelVertEdgeFace(Operator):
|
|||
description="Start from no previous selection\n"
|
||||
"If unchecked the previous selection is kept"
|
||||
)
|
||||
|
||||
delta_text = {'VERT': "Use Cursor",
|
||||
'EDGE': "Use Edges' Length",
|
||||
'FACE': "Use Faces' Area"}
|
||||
|
|
|
@ -17,12 +17,58 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# By CoDEmanX
|
||||
# updated by lijenstina
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Panel,
|
||||
Operator,
|
||||
)
|
||||
import bmesh
|
||||
from bpy.types import Panel
|
||||
import time
|
||||
|
||||
# Define Globals
|
||||
STORE_COUNT = (0, 0, 0) # Store the previous count
|
||||
TIMER_STORE = 1 # Store the time.time floats
|
||||
|
||||
|
||||
def check_the_obj_polycount(context, delay=0.0):
|
||||
global STORE_COUNT
|
||||
global TIMER_STORE
|
||||
|
||||
info_str = ""
|
||||
tris = quads = ngons = 0
|
||||
try:
|
||||
# it's weak sauce but this will in certain cases run many times a second
|
||||
if TIMER_STORE == 1 or delay == 0 or time.time() > TIMER_STORE + delay:
|
||||
ob = context.active_object
|
||||
if ob.mode == 'EDIT':
|
||||
me = ob.data
|
||||
bm = bmesh.from_edit_mesh(me)
|
||||
for f in bm.faces:
|
||||
v = len(f.verts)
|
||||
if v == 3:
|
||||
tris += 1
|
||||
elif v == 4:
|
||||
quads += 1
|
||||
else:
|
||||
ngons += 1
|
||||
bmesh.update_edit_mesh(me)
|
||||
else:
|
||||
for p in ob.data.polygons:
|
||||
count = p.loop_total
|
||||
if count == 3:
|
||||
tris += 1
|
||||
elif count == 4:
|
||||
quads += 1
|
||||
else:
|
||||
ngons += 1
|
||||
STORE_COUNT = (ngons, quads, tris)
|
||||
info_str = " Ngons: %i Quads: %i Tris: %i" % (ngons, quads, tris)
|
||||
TIMER_STORE = time.time()
|
||||
else:
|
||||
info_str = " Ngons: %i Quads: %i Tris: %i" % STORE_COUNT
|
||||
except:
|
||||
info_str = " Polygon info could not be retrieved"
|
||||
|
||||
return info_str
|
||||
|
||||
|
||||
class DATA_PT_info_panel(Panel):
|
||||
|
@ -41,28 +87,20 @@ class DATA_PT_info_panel(Panel):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
ob = context.active_object
|
||||
|
||||
mesh_extra_tools = context.scene.mesh_extra_tools
|
||||
check_used = mesh_extra_tools.mesh_info_show
|
||||
check_delay = mesh_extra_tools.mesh_info_delay
|
||||
info_str = ""
|
||||
tris = quads = ngons = 0
|
||||
|
||||
for p in ob.data.polygons:
|
||||
count = p.loop_total
|
||||
if count == 3:
|
||||
tris += 1
|
||||
elif count == 4:
|
||||
quads += 1
|
||||
else:
|
||||
ngons += 1
|
||||
box = layout.box()
|
||||
col = box.column()
|
||||
split = col.split(percentage=0.6 if check_used else 0.75, align=True)
|
||||
split.prop(mesh_extra_tools, "mesh_info_show", toggle=True)
|
||||
split.prop(mesh_extra_tools, "mesh_info_delay")
|
||||
|
||||
info_str = " Ngons: %i Quads: %i Tris: %i" % (ngons, quads, tris)
|
||||
|
||||
col = layout.column()
|
||||
split = col.split(0.9)
|
||||
|
||||
split.label(info_str, icon='MESH_DATA')
|
||||
split.operator("mesh.refresh_info_panel", text="", icon="FILE_REFRESH")
|
||||
if check_used:
|
||||
info_str = check_the_obj_polycount(context, check_delay)
|
||||
col.label(info_str, icon='MESH_DATA')
|
||||
|
||||
col = layout.column()
|
||||
col.label("Select faces by type:")
|
||||
|
@ -71,38 +109,3 @@ class DATA_PT_info_panel(Panel):
|
|||
row.operator("data.facetype_select", text="Ngons").face_type = "5"
|
||||
row.operator("data.facetype_select", text="Quads").face_type = "4"
|
||||
row.operator("data.facetype_select", text="Tris").face_type = "3"
|
||||
|
||||
|
||||
class MESH_OT_refresh_info_panel(Operator):
|
||||
bl_idname = "mesh.refresh_info_panel"
|
||||
bl_label = "Refresh"
|
||||
bl_description = ("Refresh the info panel by switching to Object mode and back\n"
|
||||
"Limitation: the information doesn't account modifiers\n"
|
||||
"Be careful with usage if you need the Redo History in Edit Mode")
|
||||
bl_options = {"REGISTER", "INTERNAL"}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return (context.active_object is not None and
|
||||
context.active_object.type == 'MESH')
|
||||
|
||||
def invoke(self, context, event):
|
||||
return self.execute(context)
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
mode = bpy.context.active_object.mode
|
||||
|
||||
# switch to Object mode and restore selection
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bpy.ops.object.mode_set(mode=mode)
|
||||
|
||||
return {'FINISHED'}
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
self.report({'WARNING'},
|
||||
"The refresh could not be performed (Check the console for more info)")
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
|
|
@ -1,43 +1,31 @@
|
|||
# Copyright (C) 2011, Dolf Veenvliet
|
||||
# Extrude a selection from a mesh multiple times
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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 LICENCE BLOCK *****
|
||||
'''
|
||||
bl_info = {
|
||||
"name": "Select by direction",
|
||||
"author": "Dolf Veenvliet",
|
||||
"version": (1,),
|
||||
"blender": (2, 56, 0),
|
||||
"location": "View3D > Select",
|
||||
"description": "Select all items whose normals face a certain direction",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
"""
|
||||
Usage:
|
||||
Select all items whose normals face a certain direction
|
||||
Additional links:
|
||||
Author Site: http://www.macouno.com
|
||||
e-mail: dolf {at} macouno {dot} com
|
||||
"""
|
||||
'''
|
||||
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
|
@ -175,39 +163,39 @@ class Select_init(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
direction = FloatVectorProperty(
|
||||
name="Direction",
|
||||
description="Define a vector from the inputs axis X, Y, Z\n"
|
||||
"Used to define the normals direction",
|
||||
default=(0.0, 0.0, 1.0),
|
||||
min=-100.0, max=100.0,
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
step=100,
|
||||
precision=2
|
||||
)
|
||||
name="Direction",
|
||||
description="Define a vector from the inputs axis X, Y, Z\n"
|
||||
"Used to define the normals direction",
|
||||
default=(0.0, 0.0, 1.0),
|
||||
min=-100.0, max=100.0,
|
||||
soft_min=-10.0, soft_max=10.0,
|
||||
step=100,
|
||||
precision=2
|
||||
)
|
||||
divergence = FloatProperty(
|
||||
name="Divergence",
|
||||
description="The number of degrees the selection may differ from the Vector\n"
|
||||
"(Input is converted to radians)",
|
||||
default=radians(30.0),
|
||||
min=0.0, max=radians(360.0),
|
||||
soft_min=0.0, soft_max=radians(360.0),
|
||||
step=radians(5000),
|
||||
precision=2,
|
||||
subtype='ANGLE'
|
||||
)
|
||||
name="Divergence",
|
||||
description="The number of degrees the selection may differ from the Vector\n"
|
||||
"(Input is converted to radians)",
|
||||
default=radians(30.0),
|
||||
min=0.0, max=radians(360.0),
|
||||
soft_min=0.0, soft_max=radians(360.0),
|
||||
step=radians(5000),
|
||||
precision=2,
|
||||
subtype='ANGLE'
|
||||
)
|
||||
extend = BoolProperty(
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
# The spaces we use
|
||||
spaces = (('LOC', 'Local', ''), ('GLO', 'Global', ''))
|
||||
space = EnumProperty(
|
||||
items=spaces,
|
||||
name="Space",
|
||||
description="The space to interpret the directions in",
|
||||
default='LOC'
|
||||
)
|
||||
items=spaces,
|
||||
name="Space",
|
||||
description="The space to interpret the directions in",
|
||||
default='LOC'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
|
|
@ -1,47 +1,33 @@
|
|||
# mesh_select_by_edge_length.py Copyright (C) 2011, Dolf Veenvliet
|
||||
# Extrude a selection from a mesh multiple times
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
|
||||
'''
|
||||
bl_info = {
|
||||
"name": "Select by edge length",
|
||||
"author": "Dolf Veenvliet",
|
||||
"version": (1,),
|
||||
"blender": (2, 56, 0),
|
||||
"location": "View3D > Select",
|
||||
"description": "Select all items whose scale/length/surface matches a certain edge length",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
"""
|
||||
Usage:
|
||||
|
||||
Launch from from "Select -> By edge length"
|
||||
Launch from from "Select -> By edge length"
|
||||
Select all items whose scale/length/surface matches a certain edge length
|
||||
|
||||
Additional links:
|
||||
Author Site: http://www.macouno.com
|
||||
e-mail: dolf {at} macouno {dot} com
|
||||
"""
|
||||
'''
|
||||
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
|
@ -198,43 +184,43 @@ class Select_init(bpy.types.Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
edgeLength = FloatProperty(
|
||||
name="Edge length",
|
||||
description="The comparison scale in Blender units",
|
||||
default=1.0,
|
||||
min=0.0, max=1000.0,
|
||||
soft_min=0.0, soft_max=100.0,
|
||||
step=100,
|
||||
precision=2
|
||||
)
|
||||
name="Edge length",
|
||||
description="The comparison scale in Blender units",
|
||||
default=1.0,
|
||||
min=0.0, max=1000.0,
|
||||
soft_min=0.0, soft_max=100.0,
|
||||
step=100,
|
||||
precision=2
|
||||
)
|
||||
# Changed to Enum as two separate Booleans didn't make much sense
|
||||
sizes = (('SMALL', 'Smaller', "Select items smaller or equal the size setting"),
|
||||
('BIG', 'Bigger', "Select items bigger or equal to the size setting"),
|
||||
('EQUAL', 'Equal', "Select edges equal to the size setting"))
|
||||
edgeSize = EnumProperty(
|
||||
items=sizes,
|
||||
name="Edge comparison",
|
||||
description="Choose the relation to set edge lenght",
|
||||
default='EQUAL'
|
||||
)
|
||||
items=sizes,
|
||||
name="Edge comparison",
|
||||
description="Choose the relation to set edge lenght",
|
||||
default='EQUAL'
|
||||
)
|
||||
extend = BoolProperty(
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
start_new = BoolProperty(
|
||||
name="Fresh Start",
|
||||
default=False,
|
||||
description="Start from no previous selection"
|
||||
)
|
||||
name="Fresh Start",
|
||||
default=False,
|
||||
description="Start from no previous selection"
|
||||
)
|
||||
# The spaces we use
|
||||
spaces = (('LOC', 'Local', "Use Local space"),
|
||||
('GLO', 'Global', "Use Global Space"))
|
||||
space = EnumProperty(
|
||||
items=spaces,
|
||||
name="Space",
|
||||
description="The space to interpret the directions in",
|
||||
default='LOC'
|
||||
)
|
||||
items=spaces,
|
||||
name="Space",
|
||||
description="The space to interpret the directions in",
|
||||
default='LOC'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
|
|
@ -1,45 +1,31 @@
|
|||
# mesh_select_by_pi.py Copyright (C) 2011, Dolf Veenvliet
|
||||
# Extrude a selection from a mesh multiple times
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
|
||||
'''
|
||||
bl_info = {
|
||||
"name": "Select by pi",
|
||||
"author": "Dolf Veenvliet",
|
||||
"version": 1,
|
||||
"blender": (2, 56, 0),
|
||||
"location": "View3D > Select",
|
||||
"description": "Select fake random based on pi",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
"""
|
||||
Usage:
|
||||
|
||||
Select fake random based on pi
|
||||
Additional links:
|
||||
Author Site: http://www.macouno.com
|
||||
e-mail: dolf {at} macouno {dot} com
|
||||
"""
|
||||
'''
|
||||
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
|
@ -179,20 +165,20 @@ class Select_init(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
e = BoolProperty(
|
||||
name="Use e",
|
||||
description="Use e as the base of selection instead of pi",
|
||||
default=False
|
||||
)
|
||||
name="Use e",
|
||||
description="Use e as the base of selection instead of pi",
|
||||
default=False
|
||||
)
|
||||
invert = BoolProperty(
|
||||
name="Invert",
|
||||
description="Invert the selection result",
|
||||
default=False
|
||||
)
|
||||
name="Invert",
|
||||
description="Invert the selection result",
|
||||
default=False
|
||||
)
|
||||
extend = BoolProperty(
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
start_new = BoolProperty(
|
||||
name="Fresh Start",
|
||||
default=False,
|
||||
|
|
|
@ -33,17 +33,17 @@ class DATA_OP_facetype_select(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
face_type = EnumProperty(
|
||||
name="Select faces:",
|
||||
items=(("3", "Triangles", "Faces made up of 3 vertices"),
|
||||
("4", "Quads", "Faces made up of 4 vertices"),
|
||||
("5", "Ngons", "Faces made up of 5 and more vertices")),
|
||||
default="5"
|
||||
)
|
||||
name="Select faces:",
|
||||
items=(("3", "Triangles", "Faces made up of 3 vertices"),
|
||||
("4", "Quads", "Faces made up of 4 vertices"),
|
||||
("5", "Ngons", "Faces made up of 5 and more vertices")),
|
||||
default="5"
|
||||
)
|
||||
extend = BoolProperty(
|
||||
name="Extend",
|
||||
description="Extend Selection",
|
||||
default=False
|
||||
)
|
||||
name="Extend",
|
||||
description="Extend Selection",
|
||||
default=False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -68,11 +68,8 @@ class DATA_OP_facetype_select(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
except Exception as e:
|
||||
print("\n[Select by face type]\nERROR:\n")
|
||||
|
||||
import traceback
|
||||
traceback.printexc()
|
||||
|
||||
self.report('WARNING', "Face selection could not be performed (Check the console for more info)")
|
||||
print("\n[Select by face type]\nOperator: data.facetype_select\nERROR: %s\n" % e)
|
||||
self.report({'WARNING'},
|
||||
"Face selection could not be performed (Check the console for more info)")
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
|
|
@ -1,36 +1,23 @@
|
|||
# Copyright (C) 2011, Dolf Veenvliet
|
||||
# Extrude a selection from a mesh multiple times
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
|
||||
'''
|
||||
bl_info = {
|
||||
"name": "Select connected faces",
|
||||
"author": "Dolf Veenvliet",
|
||||
"version": (1,),
|
||||
"blender": (2, 56, 0),
|
||||
"location": "View3D > Select",
|
||||
"description": "Select all faces connected to the current selection",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
"""
|
||||
Usage:
|
||||
|
@ -40,7 +27,7 @@ Additional links:
|
|||
Author Site: http://www.macouno.com
|
||||
e-mail: dolf {at} macouno {dot} com
|
||||
"""
|
||||
'''
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
|
@ -121,16 +108,17 @@ class Select_init(Operator):
|
|||
|
||||
# Iterations
|
||||
iterations = IntProperty(
|
||||
name="Iterations",
|
||||
default=1,
|
||||
min=0, max=300,
|
||||
soft_min=0, soft_max=100
|
||||
)
|
||||
name="Iterations",
|
||||
description="Run the selection the given number of times",
|
||||
default=1,
|
||||
min=0, max=300,
|
||||
soft_min=0, soft_max=100
|
||||
)
|
||||
extend = BoolProperty(
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
name="Extend",
|
||||
description="Extend the current selection",
|
||||
default=False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
|
|
@ -21,11 +21,10 @@ bl_info = {
|
|||
"author": "dustractor",
|
||||
"version": (2, 0),
|
||||
"blender": (2, 60, 0),
|
||||
"location": "edit mesh vertices/edges/faces menus",
|
||||
"location": "Edit mesh > Vertices/ Edges/ Faces menus",
|
||||
"description": "",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
|
@ -88,13 +87,15 @@ class MESH_OT_vneighbors_edgewise(meshpoller, Operator):
|
|||
prev_state = None
|
||||
|
||||
if not prev_state:
|
||||
selected_vert_indices = filter(lambda _: mesh.vertices[_].select,
|
||||
range(len(mesh.vertices)))
|
||||
selected_vert_indices = filter(
|
||||
lambda _: mesh.vertices[_].select,
|
||||
range(len(mesh.vertices))
|
||||
)
|
||||
else:
|
||||
selected_vert_indices = filter(
|
||||
lambda _: mesh.vertices[_].select and not prev_state[_],
|
||||
range(len(mesh.vertices))
|
||||
)
|
||||
lambda _: mesh.vertices[_].select and not prev_state[_],
|
||||
range(len(mesh.vertices))
|
||||
)
|
||||
|
||||
for v in selected_vert_indices:
|
||||
for neighbor_index in vert_to_vert_map[v]:
|
||||
|
@ -242,7 +243,8 @@ class MESH_OT_eneighbors_shared_v(meshpoller, Operator):
|
|||
state_mask = bytearray(len(mesh.edges))
|
||||
|
||||
for e in mesh.edges:
|
||||
state_mask[e.index] = mesh.vertices[e.vertices[0]].select ^ mesh.vertices[e.vertices[1]].select
|
||||
state_mask[e.index] = \
|
||||
mesh.vertices[e.vertices[0]].select ^ mesh.vertices[e.vertices[1]].select
|
||||
mesh.edges.foreach_set('select', state_mask)
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
|
||||
|
@ -279,10 +281,12 @@ class MESH_OT_eneighbors_shared_f(meshpoller, Operator):
|
|||
else:
|
||||
edge_key_to_index = {k: i for i, k in enumerate(mesh.edge_keys)}
|
||||
edge_to_edges_dict = {i: set() for i in range(len(mesh.edges))}
|
||||
|
||||
for f in mesh.polygons:
|
||||
fed = [edge_key_to_index[k] for k in f.edge_keys]
|
||||
for k in f.edge_keys:
|
||||
edge_to_edges_dict[edge_key_to_index[k]].update(fed)
|
||||
|
||||
obj.tkkey = meshkey
|
||||
state_mask, esel = (bytearray(meshkey[1]), bytearray(meshkey[1]))
|
||||
mesh.edges.foreach_get('select', esel)
|
||||
|
|
|
@ -1,258 +0,0 @@
|
|||
# ##### 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; version 2
|
||||
# of the License.
|
||||
#
|
||||
# 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": "Mesh to wall",
|
||||
"author": "luxuy_BlenderCN",
|
||||
"version": (0.8),
|
||||
"blender": (2, 71, 0),
|
||||
"location": "View3D > EditMode > Mesh",
|
||||
"description": "Make wall from single mesh lines.",
|
||||
"url": "https://luxuy.github.io/BlenderAddons/Mesh-to-wall/Mesh_to_wall.html",
|
||||
"category": "Mesh"}
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
from bpy.types import Operator
|
||||
from bpy.props import FloatProperty
|
||||
from math import sin, radians
|
||||
from mathutils import Vector, Quaternion
|
||||
|
||||
|
||||
def link_verts(bm, ver_index):
|
||||
linked_verts = []
|
||||
bm.verts.ensure_lookup_table()
|
||||
v = bm.verts[ver_index]
|
||||
for e in v.link_edges:
|
||||
linked_verts.append(e.verts[1].index)
|
||||
linked_verts.append(e.verts[0].index)
|
||||
|
||||
linked_verts = list(set(linked_verts) - set([ver_index]))
|
||||
|
||||
return linked_verts
|
||||
|
||||
|
||||
def qq_sort(bm, ver_index, vm, wm):
|
||||
verts = link_verts(bm, ver_index)
|
||||
pt0 = bm.verts[ver_index].co
|
||||
|
||||
def ang_2d_sort(x):
|
||||
pt1 = bm.verts[x].co
|
||||
vec = vm * wm * pt1 - vm * wm * pt0
|
||||
vec = Vector(vec[0:2])
|
||||
ang = vec.angle_signed(Vector((1, 0)))
|
||||
|
||||
if ang < 0:
|
||||
return ang + 3.1415926 * 2
|
||||
else:
|
||||
return ang
|
||||
verts = sorted(verts, key=ang_2d_sort)
|
||||
|
||||
return verts
|
||||
|
||||
|
||||
def turn_left(bm, v1, v2, vm, wm):
|
||||
links = [v1, v2]
|
||||
|
||||
verts = qq_sort(bm, links[-1], vm, wm)
|
||||
v = verts.index(links[-2])
|
||||
|
||||
if v == 0:
|
||||
v_nxt = verts[-1]
|
||||
else:
|
||||
v_nxt = verts[v - 1]
|
||||
|
||||
links.append(v_nxt)
|
||||
|
||||
while not(links[-1] == links[1] and links[-2] == links[0]):
|
||||
|
||||
verts = qq_sort(bm, links[-1], vm, wm)
|
||||
v = verts.index(links[-2])
|
||||
if v == 0:
|
||||
v_nxt = verts[-1]
|
||||
else:
|
||||
v_nxt = verts[v - 1]
|
||||
|
||||
links.append(v_nxt)
|
||||
links.pop()
|
||||
|
||||
return links
|
||||
|
||||
|
||||
def lp_left(bm, lp, wid, vm, wm):
|
||||
size = len(lp)
|
||||
up = wm.inverted() * vm.inverted() * Vector((0, 0, 1))
|
||||
lp_off = []
|
||||
faces = []
|
||||
for i in range(size - 1):
|
||||
if i == 0:
|
||||
pt = bm.verts[lp[i]].co
|
||||
pre = bm.verts[lp[-2]].co
|
||||
nxt = bm.verts[lp[1]].co
|
||||
pre_ind = lp[size - 2]
|
||||
nxt_ind = lp[1]
|
||||
else:
|
||||
bm.verts.ensure_lookup_table()
|
||||
pt = bm.verts[lp[i]].co
|
||||
pre = bm.verts[lp[i - 1]].co
|
||||
nxt = bm.verts[lp[i + 1]].co
|
||||
pre_ind = lp[i - 1]
|
||||
nxt_ind = lp[i + 1]
|
||||
|
||||
vec1 = pt - pre
|
||||
vec2 = pt - nxt
|
||||
|
||||
mid = vec1.normalized() + vec2.normalized()
|
||||
if mid.length < 10e-4:
|
||||
|
||||
up2 = Vector((0, 0, 1))
|
||||
mid = up2.cross(vec1)
|
||||
|
||||
else:
|
||||
xx = mid.cross(vec1).dot(up)
|
||||
|
||||
if xx > 0:
|
||||
mid.negate()
|
||||
|
||||
mid.normalize()
|
||||
if pre_ind == nxt_ind:
|
||||
mid = (pt - pre).normalized()
|
||||
q_a = Quaternion((0.0, 0.0, 1.0), radians(90.0))
|
||||
q_b = Quaternion((0.0, 0.0, 1.0), radians(-180.0))
|
||||
mid.rotate(q_a)
|
||||
pt1 = pt + mid * wid
|
||||
mid.rotate(q_b)
|
||||
pt2 = pt + mid * wid
|
||||
new_vert_1 = bm.verts.new(pt1)
|
||||
new_vert_2 = bm.verts.new(pt2)
|
||||
lp_off.append([new_vert_1, new_vert_2])
|
||||
else:
|
||||
ang = mid.angle(pre - pt)
|
||||
|
||||
vec_len = wid / (sin(ang))
|
||||
pt = pt + mid * vec_len
|
||||
new_vert = bm.verts.new(pt)
|
||||
lp_off.append(new_vert)
|
||||
lp_off.append(lp_off[0])
|
||||
bm.verts.index_update()
|
||||
for i in range(len(lp_off) - 1):
|
||||
bm.verts.ensure_lookup_table()
|
||||
p1 = bm.verts[lp[i]]
|
||||
p2 = bm.verts[lp[i + 1]]
|
||||
p3 = lp_off[i + 1]
|
||||
p4 = lp_off[i]
|
||||
|
||||
if isinstance(p3, list):
|
||||
|
||||
faces.append((p1, p2, p3[0], p4))
|
||||
# faces.append((p3[0],p2,p3[1]))
|
||||
elif isinstance(p4, list):
|
||||
|
||||
faces.append((p1, p2, p3, p4[1]))
|
||||
else:
|
||||
faces.append((p1, p2, p3, p4))
|
||||
|
||||
return faces
|
||||
|
||||
|
||||
# Operators
|
||||
|
||||
class MeshtoWall(Operator):
|
||||
bl_idname = "bpt.mesh_to_wall"
|
||||
bl_label = "Edge(s) to Wall"
|
||||
bl_description = "Top View, Extrude Flat Along Edges"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
wid = FloatProperty(
|
||||
name='Wall width:',
|
||||
default=0.1,
|
||||
min=0.001, max=10
|
||||
)
|
||||
|
||||
def check_vert(self, context):
|
||||
obj = bpy.context.object
|
||||
if len(obj.data.vertices) <= 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
# Note: the remove_doubles called after bmesh creation would make
|
||||
# blender crash with certain meshes - keep it in mind for the future
|
||||
bpy.ops.mesh.remove_doubles(threshold=0.003) # <<< Remove doubles is called from here
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
if self.check_vert(context):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
ob = bpy.context.object
|
||||
|
||||
me = ob.data
|
||||
bm = bmesh.from_edit_mesh(me)
|
||||
bpy.ops.mesh.delete(type='ONLY_FACE')
|
||||
|
||||
context.tool_settings.mesh_select_mode = (True, True, False)
|
||||
|
||||
v3d = context.space_data
|
||||
rv3d = v3d.region_3d
|
||||
vm = rv3d.view_matrix
|
||||
wm = ob.matrix_world
|
||||
faces = []
|
||||
sel = []
|
||||
for v in bm.verts:
|
||||
sel.append(v.index)
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
for j in sel:
|
||||
verts = link_verts(bm, j)
|
||||
|
||||
if len(verts) > 1:
|
||||
for i in verts:
|
||||
lp = turn_left(bm, j, i, vm, wm)
|
||||
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
|
||||
faces += lp_left(bm, lp, self.wid * 0.5, vm, wm)
|
||||
lp = [bm.verts[i] for i in lp]
|
||||
|
||||
lp = lp[1:]
|
||||
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
for f in faces:
|
||||
try:
|
||||
bm.faces.new(f)
|
||||
except:
|
||||
pass
|
||||
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.003)
|
||||
bm = bmesh.update_edit_mesh(ob.data, 1, 1)
|
||||
else:
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
self.report({'WARNING'}, "None or a single vertex found, cancelling the operation")
|
||||
return {'CANCELLED'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -26,7 +26,6 @@ bl_info = {
|
|||
"location": "Spacebar Menu",
|
||||
"description": "Chamfer vertex",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
|
@ -133,9 +132,11 @@ class VertexChamfer(Operator):
|
|||
# Loop over all the loops of the vert
|
||||
for l in v.link_loops:
|
||||
# Split the face
|
||||
bmesh.utils.face_split(l.face,
|
||||
l.link_loop_next.vert,
|
||||
l.link_loop_prev.vert)
|
||||
bmesh.utils.face_split(
|
||||
l.face,
|
||||
l.link_loop_next.vert,
|
||||
l.link_loop_prev.vert
|
||||
)
|
||||
|
||||
# Remove the vert or displace otherwise
|
||||
if dissolve:
|
||||
|
@ -149,11 +150,11 @@ class VertexChamfer(Operator):
|
|||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
bpy.utils.register_class(VertexChamfer)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
bpy.utils.unregister_class(VertexChamfer)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
bl_info = {
|
||||
"name": "PKHG faces",
|
||||
"author": "PKHG",
|
||||
"version": (0, 0, 5),
|
||||
"version": (0, 0, 6),
|
||||
"blender": (2, 7, 1),
|
||||
"location": "View3D > Tools > PKHG (tab)",
|
||||
"description": "Faces selected will become added faces of different style",
|
||||
|
@ -14,10 +14,7 @@ bl_info = {
|
|||
|
||||
import bpy
|
||||
import bmesh
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Panel
|
||||
)
|
||||
from bpy.types import Operator
|
||||
from mathutils import Vector
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
|
@ -35,159 +32,158 @@ class MESH_OT_add_faces_to_object(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
||||
|
||||
reverse_faces = BoolProperty(
|
||||
name="Reverse Faces",
|
||||
default=False,
|
||||
description="Revert the normals of selected faces"
|
||||
)
|
||||
name="Reverse Faces",
|
||||
default=False,
|
||||
description="Revert the normals of selected faces"
|
||||
)
|
||||
name_source_object = StringProperty(
|
||||
name="Mesh",
|
||||
description="Choose a Source Mesh",
|
||||
default="Cube"
|
||||
)
|
||||
name="Mesh",
|
||||
description="Choose a Source Mesh",
|
||||
default="Cube"
|
||||
)
|
||||
remove_start_faces = BoolProperty(
|
||||
name="Remove Start Faces",
|
||||
default=True,
|
||||
description="Make a choice about removal of Original Faces"
|
||||
)
|
||||
name="Remove Start Faces",
|
||||
default=True,
|
||||
description="Make a choice about removal of Original Faces"
|
||||
)
|
||||
base_height = FloatProperty(
|
||||
name="Base Height",
|
||||
min=-20,
|
||||
soft_max=10, max=20,
|
||||
default=0.2,
|
||||
description="Set general Base Height"
|
||||
)
|
||||
name="Base Height",
|
||||
min=-20,
|
||||
soft_max=10, max=20,
|
||||
default=0.2,
|
||||
description="Set general Base Height"
|
||||
)
|
||||
use_relative_base_height = BoolProperty(
|
||||
name="rel.base_height",
|
||||
default=False,
|
||||
description="Relative or absolute Base Height"
|
||||
)
|
||||
name="Relative Base Height",
|
||||
default=False,
|
||||
description="Relative or absolute Base Height"
|
||||
)
|
||||
second_height = FloatProperty(
|
||||
name="2nd height", min=-5,
|
||||
soft_max=5, max=20,
|
||||
default=0.2,
|
||||
description="Second height for various shapes"
|
||||
)
|
||||
name="2nd height", min=-5,
|
||||
soft_max=5, max=20,
|
||||
default=0.2,
|
||||
description="Second height for various shapes"
|
||||
)
|
||||
width = FloatProperty(
|
||||
name="Width Faces",
|
||||
min=-20, max=20,
|
||||
default=0.5,
|
||||
description="Set general width"
|
||||
)
|
||||
name="Width Faces",
|
||||
min=-20, max=20,
|
||||
default=0.5,
|
||||
description="Set general width"
|
||||
)
|
||||
repeat_extrude = IntProperty(
|
||||
name="Repeat",
|
||||
min=1,
|
||||
soft_max=5, max=20,
|
||||
description="For longer base"
|
||||
)
|
||||
name="Repeat",
|
||||
min=1,
|
||||
soft_max=5, max=20,
|
||||
description="For longer base"
|
||||
)
|
||||
move_inside = FloatProperty(
|
||||
name="Move Inside",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=0.5,
|
||||
description="How much move to inside"
|
||||
)
|
||||
name="Move Inside",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=0.5,
|
||||
description="How much move to inside"
|
||||
)
|
||||
thickness = FloatProperty(
|
||||
name="Thickness",
|
||||
soft_min=0.01, min=0,
|
||||
soft_max=5.0, max=20.0,
|
||||
default=0
|
||||
)
|
||||
name="Thickness",
|
||||
soft_min=0.01, min=0,
|
||||
soft_max=5.0, max=20.0,
|
||||
default=0
|
||||
)
|
||||
depth = FloatProperty(
|
||||
name="Depth",
|
||||
min=-5,
|
||||
soft_max=5.0, max=20.0,
|
||||
default=0
|
||||
)
|
||||
name="Depth",
|
||||
min=-5,
|
||||
soft_max=5.0, max=20.0,
|
||||
default=0
|
||||
)
|
||||
collapse_edges = BoolProperty(
|
||||
name="Make Point",
|
||||
default=False,
|
||||
description="Collapse the vertices of edges"
|
||||
)
|
||||
name="Make Point",
|
||||
default=False,
|
||||
description="Collapse the vertices of edges"
|
||||
)
|
||||
spike_base_width = FloatProperty(
|
||||
name="Spike Base Width",
|
||||
default=0.4,
|
||||
min=-4.0,
|
||||
soft_max=1, max=20,
|
||||
description="Base width of a spike"
|
||||
)
|
||||
name="Spike Base Width",
|
||||
default=0.4,
|
||||
min=-4.0,
|
||||
soft_max=1, max=20,
|
||||
description="Base width of a spike"
|
||||
)
|
||||
base_height_inset = FloatProperty(
|
||||
name="Base Height Inset",
|
||||
default=0.0,
|
||||
min=-5, max=5,
|
||||
description="To elevate or drop the Base height Inset"
|
||||
)
|
||||
name="Base Height Inset",
|
||||
default=0.0,
|
||||
min=-5, max=5,
|
||||
description="To elevate or drop the Base height Inset"
|
||||
)
|
||||
top_spike = FloatProperty(
|
||||
name="Top Spike",
|
||||
default=1.0,
|
||||
min=-10.0, max=10.0,
|
||||
description="The Base Height of a spike"
|
||||
)
|
||||
|
||||
name="Top Spike",
|
||||
default=1.0,
|
||||
min=-10.0, max=10.0,
|
||||
description="The Base Height of a spike"
|
||||
)
|
||||
top_extra_height = FloatProperty(
|
||||
name="Top Extra Height",
|
||||
default=0.0,
|
||||
min=-10.0, max=10.0,
|
||||
description="Add extra height"
|
||||
)
|
||||
name="Top Extra Height",
|
||||
default=0.0,
|
||||
min=-10.0, max=10.0,
|
||||
description="Add extra height"
|
||||
)
|
||||
step_with_real_spike = BoolProperty(
|
||||
name="Step with Real Spike",
|
||||
default=False,
|
||||
description="In stepped, use a real spike"
|
||||
)
|
||||
name="Step with Real Spike",
|
||||
default=False,
|
||||
description="In stepped, use a real spike"
|
||||
)
|
||||
use_relative = BoolProperty(
|
||||
name="Use Relative",
|
||||
default=False,
|
||||
description="Change size using area, min or max"
|
||||
)
|
||||
name="Use Relative",
|
||||
default=False,
|
||||
description="Change size using area, min or max"
|
||||
)
|
||||
face_types = EnumProperty(
|
||||
name="Face Types",
|
||||
description="Different types of Faces",
|
||||
default="no",
|
||||
items=[
|
||||
('no', "Pick an Option", "Choose one of the available options"),
|
||||
('open_inset', "Open Inset", "Inset without closing faces (holes)"),
|
||||
('with_base', "With Base", "Base and ..."),
|
||||
('clsd_vertical', "Closed Vertical", "Closed Vertical"),
|
||||
('open_vertical', "Open Vertical", "Open Vertical"),
|
||||
('spiked', "Spiked", "Spike"),
|
||||
('stepped', "Stepped", "Stepped"),
|
||||
('boxed', "Boxed", "Boxed"),
|
||||
('bar', "Bar", "Bar"),
|
||||
]
|
||||
)
|
||||
name="Face Types",
|
||||
description="Different types of Faces",
|
||||
default="no",
|
||||
items=[
|
||||
('no', "Pick an Option", "Choose one of the available options"),
|
||||
('open_inset', "Open Inset", "Inset without closing faces (holes)"),
|
||||
('with_base', "With Base", "Base and ..."),
|
||||
('clsd_vertical', "Closed Vertical", "Closed Vertical"),
|
||||
('open_vertical', "Open Vertical", "Open Vertical"),
|
||||
('spiked', "Spiked", "Spike"),
|
||||
('stepped', "Stepped", "Stepped"),
|
||||
('boxed', "Boxed", "Boxed"),
|
||||
('bar', "Bar", "Bar"),
|
||||
]
|
||||
)
|
||||
strange_boxed_effect = BoolProperty(
|
||||
name="Strange Effect",
|
||||
default=False,
|
||||
description="Do not show one extrusion"
|
||||
)
|
||||
name="Strange Effect",
|
||||
default=False,
|
||||
description="Do not show one extrusion"
|
||||
)
|
||||
use_boundary = BoolProperty(
|
||||
name="Use Boundary",
|
||||
default=True
|
||||
)
|
||||
name="Use Boundary",
|
||||
default=True
|
||||
)
|
||||
use_even_offset = BoolProperty(
|
||||
name="Even Offset",
|
||||
default=True
|
||||
)
|
||||
name="Even Offset",
|
||||
default=True
|
||||
)
|
||||
use_relative_offset = BoolProperty(
|
||||
name="Relative Offset",
|
||||
default=True
|
||||
)
|
||||
name="Relative Offset",
|
||||
default=True
|
||||
)
|
||||
use_edge_rail = BoolProperty(
|
||||
name="Edge Rail",
|
||||
default=False
|
||||
)
|
||||
name="Edge Rail",
|
||||
default=False
|
||||
)
|
||||
use_outset = BoolProperty(
|
||||
name="Outset",
|
||||
default=False
|
||||
)
|
||||
name="Outset",
|
||||
default=False
|
||||
)
|
||||
use_select_inset = BoolProperty(
|
||||
name="Inset",
|
||||
default=False
|
||||
)
|
||||
name="Inset",
|
||||
default=False
|
||||
)
|
||||
use_interpolate = BoolProperty(
|
||||
name="Interpolate",
|
||||
default=True
|
||||
)
|
||||
name="Interpolate",
|
||||
default=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -438,21 +434,24 @@ class MESH_OT_add_faces_to_object(Operator):
|
|||
fac = top_spike
|
||||
object_matrix = startinfo['obj'].matrix_local
|
||||
for i in range(len(next_ring_edges_list)):
|
||||
translate_ONE_ring(self, context, bm=bm,
|
||||
object_matrix=object_matrix,
|
||||
ring_edges=next_ring_edges_list[i],
|
||||
normal=normals[i], distance=fac)
|
||||
|
||||
translate_ONE_ring(
|
||||
self, context, bm=bm,
|
||||
object_matrix=object_matrix,
|
||||
ring_edges=next_ring_edges_list[i],
|
||||
normal=normals[i], distance=fac
|
||||
)
|
||||
next_ring_edges_list_2 = extrude_edges(self, context, bm=bm,
|
||||
edge_l_l=next_ring_edges_list)
|
||||
|
||||
top_extra_height = self.top_extra_height
|
||||
for i in range(len(next_ring_edges_list_2)):
|
||||
move_corner_vecs_outside(self, context, bm=bm,
|
||||
edge_list=next_ring_edges_list_2[i],
|
||||
center=centers[i], normal=normals[i],
|
||||
base_height_erlier=fac + top_extra_height,
|
||||
distance=fac)
|
||||
move_corner_vecs_outside(
|
||||
self, context, bm=bm,
|
||||
edge_list=next_ring_edges_list_2[i],
|
||||
center=centers[i], normal=normals[i],
|
||||
base_height_erlier=fac + top_extra_height,
|
||||
distance=fac
|
||||
)
|
||||
bpy.ops.mesh.select_mode(type="VERT")
|
||||
bpy.ops.mesh.select_more()
|
||||
|
||||
|
@ -481,24 +480,30 @@ def find_one_ring(sel_vertices):
|
|||
|
||||
class Stepped:
|
||||
def __init__(self, spike_base_width=0.5, base_height_inset=0.0, top_spike=0.2,
|
||||
top_relative=False, top_extra_height=0, use_relative_offset=False, with_spike=False):
|
||||
top_relative=False, top_extra_height=0, use_relative_offset=False,
|
||||
with_spike=False):
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
|
||||
use_edge_rail=False, thickness=top_extra_height, depth=base_height_inset,
|
||||
use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
|
||||
use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
|
||||
use_edge_rail=False, thickness=top_extra_height, depth=base_height_inset,
|
||||
use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
|
||||
use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
if with_spike:
|
||||
bpy.ops.mesh.merge(type='COLLAPSE')
|
||||
|
||||
|
@ -510,13 +515,16 @@ class Spiked:
|
|||
|
||||
obj = bpy.context.active_object
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=False, thickness=spike_base_width, depth=base_height_inset,
|
||||
use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=top_relative,
|
||||
use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=False, thickness=spike_base_width, depth=base_height_inset,
|
||||
use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=top_relative,
|
||||
use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
bpy.ops.mesh.merge(type='COLLAPSE')
|
||||
|
@ -596,50 +604,63 @@ class StripFaces:
|
|||
use_select_inset=False, use_individual=True, use_interpolate=True):
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.inset(use_boundary=use_boundary, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=use_outset,
|
||||
use_select_inset=use_select_inset, use_individual=use_individual,
|
||||
use_interpolate=use_interpolate)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=use_boundary, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=use_outset,
|
||||
use_select_inset=use_select_inset, use_individual=use_individual,
|
||||
use_interpolate=use_interpolate
|
||||
)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# PKHG>IMFO only 3 parameters inc execution context supported!!
|
||||
if False:
|
||||
bpy.ops.mesh.inset(use_boundary, use_even_offset, use_relative_offset, use_edge_rail,
|
||||
thickness, depth, use_outset, use_select_inset, use_individual, use_interpolate)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary, use_even_offset, use_relative_offset, use_edge_rail,
|
||||
thickness, depth, use_outset, use_select_inset, use_individual,
|
||||
use_interpolate
|
||||
)
|
||||
elif type == 0:
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
elif type == 1:
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=False)
|
||||
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=True, use_relative_offset=False,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=False
|
||||
)
|
||||
bpy.ops.mesh.delete(type='FACE')
|
||||
|
||||
elif type == 2:
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=False)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=False
|
||||
)
|
||||
|
||||
bpy.ops.mesh.delete(type='FACE')
|
||||
|
||||
elif type == 3:
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=depth, depth=thickness, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=depth, depth=thickness, use_outset=False,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.delete(type='FACE')
|
||||
elif type == 4:
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True)
|
||||
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.inset(
|
||||
use_boundary=True, use_even_offset=False, use_relative_offset=True,
|
||||
use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
|
||||
use_select_inset=False, use_individual=True, use_interpolate=True
|
||||
)
|
||||
bpy.ops.mesh.delete(type='FACE')
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
@ -668,16 +689,26 @@ def prepare(self, context, remove_start_faces=True):
|
|||
centers_copy = [Vector((el[0], el[1], el[2])) for el in centers]
|
||||
normals = [face.normal for face in selectedpolygons]
|
||||
normals_copy = [Vector((el[0], el[1], el[2])) for el in normals]
|
||||
vertindicesofpolgons = [[vert for vert in face.vertices] for face in selectedpolygons]
|
||||
vertVectorsOfSelectedFaces = [[obj.data.vertices[ind].co for ind in vertIndiceofface]
|
||||
for vertIndiceofface in vertindicesofpolgons]
|
||||
vertVectorsOfSelectedFaces_copy = [[Vector((el[0], el[1], el[2])) for el in listofvecs]
|
||||
for listofvecs in vertVectorsOfSelectedFaces]
|
||||
|
||||
vertindicesofpolgons = [
|
||||
[vert for vert in face.vertices] for face in selectedpolygons
|
||||
]
|
||||
vertVectorsOfSelectedFaces = [
|
||||
[obj.data.vertices[ind].co for ind in vertIndiceofface] for
|
||||
vertIndiceofface in vertindicesofpolgons
|
||||
]
|
||||
vertVectorsOfSelectedFaces_copy = [
|
||||
[Vector((el[0], el[1], el[2])) for el in listofvecs] for
|
||||
listofvecs in vertVectorsOfSelectedFaces
|
||||
]
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
selected_bm_faces = [ele for ele in bm.faces if ele.select]
|
||||
selected_edges_per_face_ind = [[ele.index for ele in face.edges] for face in selected_bm_faces]
|
||||
|
||||
selected_edges_per_face_ind = [
|
||||
[ele.index for ele in face.edges] for face in selected_bm_faces
|
||||
]
|
||||
indices = [el.index for el in selectedpolygons]
|
||||
selected_faces_areas = [bm.faces[:][i] for i in indices]
|
||||
tmp_area = [el.calc_area() for el in selected_faces_areas]
|
||||
|
@ -692,20 +723,27 @@ def prepare(self, context, remove_start_faces=True):
|
|||
bm.verts.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
|
||||
start_ring_raw = [[bm.verts[ind].index for ind in vertIndiceofface]
|
||||
for vertIndiceofface in vertindicesofpolgons]
|
||||
start_ring_raw = [
|
||||
[bm.verts[ind].index for ind in vertIndiceofface] for
|
||||
vertIndiceofface in vertindicesofpolgons
|
||||
]
|
||||
start_ring = []
|
||||
|
||||
for el in start_ring_raw:
|
||||
start_ring.append(set(el))
|
||||
bm.edges.ensure_lookup_table()
|
||||
|
||||
bm_selected_edges_l_l = [[bm.edges[i] for i in bm_ind_list] for bm_ind_list in selected_edges_per_face_ind]
|
||||
bm_selected_edges_l_l = [
|
||||
[bm.edges[i] for i in bm_ind_list] for
|
||||
bm_ind_list in selected_edges_per_face_ind
|
||||
]
|
||||
result = {
|
||||
'obj': obj, 'centers': centers_copy, 'normals': normals_copy,
|
||||
'rings': vertVectorsOfSelectedFaces_copy, 'bm': bm,
|
||||
'areas': tmp_area, 'startBMRingVerts': start_ring,
|
||||
'base_edges': bm_selected_edges_l_l
|
||||
}
|
||||
|
||||
result = {'obj': obj, 'centers': centers_copy, 'normals': normals_copy,
|
||||
'rings': vertVectorsOfSelectedFaces_copy, 'bm': bm,
|
||||
'areas': tmp_area, 'startBMRingVerts': start_ring,
|
||||
'base_edges': bm_selected_edges_l_l}
|
||||
return result
|
||||
|
||||
|
||||
|
@ -769,8 +807,8 @@ def translate_ONE_ring(self, context, bm=None, object_matrix=None, ring_edges=No
|
|||
return ring_edges
|
||||
|
||||
|
||||
def move_corner_vecs_outside(self, context, bm=None, edge_list=None, center=None, normal=None,
|
||||
base_height_erlier=0.5, distance=0.5):
|
||||
def move_corner_vecs_outside(self, context, bm=None, edge_list=None, center=None,
|
||||
normal=None, base_height_erlier=0.5, distance=0.5):
|
||||
# move corners (outside meant mostly) dependent on the parameters
|
||||
tmp = []
|
||||
for edge in edge_list:
|
||||
|
|
|
@ -6,10 +6,9 @@ bl_info = {
|
|||
"version": (1, 3),
|
||||
"blender": (2, 6, 3),
|
||||
"location": "Object > Transform > Random Vertices",
|
||||
"description": "Randomize selected components of active object.",
|
||||
"description": "Randomize selected components of active object",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
|
@ -45,7 +44,8 @@ def add_object(self, context, valmin, valmax, factor, vgfilter):
|
|||
if vertice.select:
|
||||
listver.append(vertice.index)
|
||||
|
||||
# If the minimum value is greater than the maximum, it adds a value to the maximum
|
||||
# If the minimum value is greater than the maximum,
|
||||
# it adds a value to the maximum
|
||||
if valmin[0] >= valmax[0]:
|
||||
valmax[0] = valmin[0] + 1
|
||||
|
||||
|
@ -95,25 +95,25 @@ class MESH_OT_random_vertices(Operator):
|
|||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
vgfilter = BoolProperty(
|
||||
name="Vertex Group",
|
||||
description="Use Vertex Weight defined in the Active Group",
|
||||
default=False
|
||||
)
|
||||
name="Vertex Group",
|
||||
description="Use Vertex Weight defined in the Active Group",
|
||||
default=False
|
||||
)
|
||||
factor = FloatProperty(
|
||||
name="Factor",
|
||||
description="Base Multiplier of the randomization effect",
|
||||
default=1
|
||||
)
|
||||
name="Factor",
|
||||
description="Base Multiplier of the randomization effect",
|
||||
default=1
|
||||
)
|
||||
valmin = IntVectorProperty(
|
||||
name="Min XYZ",
|
||||
description="Define the minimum range of randomization values",
|
||||
default=(0, 0, 0)
|
||||
)
|
||||
name="Min XYZ",
|
||||
description="Define the minimum range of randomization values",
|
||||
default=(0, 0, 0)
|
||||
)
|
||||
valmax = IntVectorProperty(
|
||||
name="Max XYZ",
|
||||
description="Define the maximum range of randomization values",
|
||||
default=(1, 1, 1)
|
||||
)
|
||||
name="Max XYZ",
|
||||
description="Define the maximum range of randomization values",
|
||||
default=(1, 1, 1)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -122,6 +122,7 @@ class MESH_OT_random_vertices(Operator):
|
|||
|
||||
def execute(self, context):
|
||||
add_object(self, context, self.valmin, self.valmax, self.factor, self.vgfilter)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
# 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.
|
||||
# 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 LICENCE BLOCK *****
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
bl_info = {
|
||||
"name": "Split Solidify",
|
||||
|
@ -27,7 +27,6 @@ bl_info = {
|
|||
"description": "",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
import bpy
|
||||
|
@ -111,44 +110,44 @@ class MESH_OT_split_solidify(Operator):
|
|||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
distance = FloatProperty(
|
||||
name="",
|
||||
description="Distance of the splitted Faces to the original geometry",
|
||||
default=0.4,
|
||||
min=-100.0, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
name="",
|
||||
description="Distance of the splitted Faces to the original geometry",
|
||||
default=0.4,
|
||||
min=-100.0, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
thickness = FloatProperty(
|
||||
name="",
|
||||
description="Thickness of the splitted Faces",
|
||||
default=0.04,
|
||||
min=-100.0, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
name="",
|
||||
description="Thickness of the splitted Faces",
|
||||
default=0.04,
|
||||
min=-100.0, max=100.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
random_dist = FloatProperty(
|
||||
name="",
|
||||
description="Randomization factor of the splitted Faces' location",
|
||||
default=0.06,
|
||||
min=-10.0, max=10.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
name="",
|
||||
description="Randomization factor of the splitted Faces' location",
|
||||
default=0.06,
|
||||
min=-10.0, max=10.0,
|
||||
step=1,
|
||||
precision=3
|
||||
)
|
||||
loc_random = BoolProperty(
|
||||
name="Random",
|
||||
description="Randomize the locations of splitted faces",
|
||||
default=False
|
||||
)
|
||||
name="Random",
|
||||
description="Randomize the locations of splitted faces",
|
||||
default=False
|
||||
)
|
||||
del_original = BoolProperty(
|
||||
name="Delete original faces",
|
||||
default=True
|
||||
)
|
||||
name="Delete original faces",
|
||||
default=True
|
||||
)
|
||||
normal_extr = EnumProperty(
|
||||
items=(('opt0', "Face", "Solidify along Face Normals"),
|
||||
('opt1', "Vertex", "Solidify along Vertex Normals")),
|
||||
name="Normal",
|
||||
default='opt0'
|
||||
)
|
||||
items=(('opt0', "Face", "Solidify along Face Normals"),
|
||||
('opt1', "Vertex", "Solidify along Vertex Normals")),
|
||||
name="Normal",
|
||||
default='opt0'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -176,7 +175,8 @@ class MESH_OT_split_solidify(Operator):
|
|||
list_0 = [f.index for f in self.bm.faces if f.select]
|
||||
|
||||
if len(list_0) == 0:
|
||||
self.report({'WARNING'}, "No suitable selection found. Operation cancelled")
|
||||
self.report({'WARNING'},
|
||||
"No suitable selection found. Operation cancelled")
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
|
|
@ -1,63 +1,55 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
# ##### 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 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.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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 LICENCE BLOCK *****
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# Note: Property group was moved to __init__
|
||||
|
||||
# ------ ------
|
||||
bl_info = {
|
||||
'name': 'vertex align',
|
||||
'author': '',
|
||||
'version': (0, 1, 6),
|
||||
'blender': (2, 6, 1),
|
||||
'location': 'View3D > Tool Shelf',
|
||||
'description': '',
|
||||
'warning': '',
|
||||
'wiki_url': '',
|
||||
'tracker_url': '',
|
||||
'category': 'Mesh' }
|
||||
"name": "Vertex Align",
|
||||
"author": "",
|
||||
"version": (0, 1, 7),
|
||||
"blender": (2, 6, 1),
|
||||
"location": "View3D > Tool Shelf",
|
||||
"description": "",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"category": "Mesh"}
|
||||
|
||||
|
||||
# ------ ------
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
EnumProperty,
|
||||
PointerProperty,
|
||||
FloatProperty,
|
||||
BoolVectorProperty,
|
||||
FloatVectorProperty,
|
||||
)
|
||||
|
||||
from mathutils import Vector
|
||||
from mathutils.geometry import (
|
||||
intersect_point_line,
|
||||
intersect_line_plane,
|
||||
)
|
||||
from bpy.types import (
|
||||
PropertyGroup,
|
||||
)
|
||||
from bpy.types import Operator
|
||||
|
||||
# ------ Edit Mode Toggle------
|
||||
|
||||
# Edit Mode Toggle
|
||||
def edit_mode_out():
|
||||
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
|
||||
def edit_mode_in():
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
|
||||
# ------ ------
|
||||
def get_mesh_data_():
|
||||
edit_mode_out()
|
||||
ob_act = bpy.context.active_object
|
||||
|
@ -65,160 +57,206 @@ def get_mesh_data_():
|
|||
edit_mode_in()
|
||||
return me
|
||||
|
||||
|
||||
def list_clear_(l):
|
||||
l[:] = []
|
||||
return l
|
||||
|
||||
# -- -- Prpoerty Group-- --
|
||||
class va_property_group(PropertyGroup):
|
||||
|
||||
en0 = EnumProperty( items =( ('vertex', 'Original vertex', ''),
|
||||
('coordinates', 'Custom coordinates', '')),
|
||||
|
||||
name = 'Align to',
|
||||
default = 'vertex' )
|
||||
|
||||
en1 = EnumProperty( items =( ('en1_opt0', 'x', ''),
|
||||
('en1_opt1', 'y', ''),
|
||||
('en1_opt2', 'z', '')),
|
||||
name = 'Axis',
|
||||
default = 'en1_opt0' )
|
||||
|
||||
# ------ ------
|
||||
class va_buf():
|
||||
list_v = []
|
||||
list_f = []
|
||||
list_0 = []
|
||||
|
||||
# ------ operator 0 Store The Vert------
|
||||
class va_op0_store(bpy.types.Operator):
|
||||
bl_idname = 'va.op0_store_id'
|
||||
bl_label = ''
|
||||
bl_description = "Store single vert as align point"
|
||||
|
||||
# Store The Vertex coordinates
|
||||
class Vertex_align_store(Operator):
|
||||
bl_idname = "vertex_align.store_id"
|
||||
bl_label = "Active Vertex"
|
||||
bl_description = ("Store Selected Vertex coordinates as an align point\n"
|
||||
"Single Selected Vertex only")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.active_object
|
||||
return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
|
||||
|
||||
def execute(self, context):
|
||||
me = get_mesh_data_()
|
||||
list_clear_(va_buf.list_v)
|
||||
for v in me.vertices:
|
||||
if v.select:
|
||||
va_buf.list_v.append(v.index)
|
||||
bpy.ops.mesh.select_all(action = 'DESELECT')
|
||||
try:
|
||||
me = get_mesh_data_()
|
||||
list_0 = [v.index for v in me.vertices if v.select]
|
||||
|
||||
if len(list_0) == 1:
|
||||
list_clear_(va_buf.list_v)
|
||||
for v in me.vertices:
|
||||
if v.select:
|
||||
va_buf.list_v.append(v.index)
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
else:
|
||||
self.report({'WARNING'}, "Please select just One Vertex")
|
||||
return {'CANCELLED'}
|
||||
except:
|
||||
self.report({'WARNING'}, "Storing selection could not be completed")
|
||||
return {'CANCELLED'}
|
||||
|
||||
self.report({'INFO'}, "Selected Vertex coordinates are stored")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------ operator 1 Append to list------
|
||||
class va_op1_list(bpy.types.Operator):
|
||||
bl_idname = 'va.op1_id'
|
||||
bl_label = ''
|
||||
bl_description = "test2"
|
||||
|
||||
def execute(self, context):
|
||||
me = get_mesh_data_()
|
||||
list_clear_(va_buf.list_f)
|
||||
for f in me.faces:
|
||||
if f.select:
|
||||
va_buf.list_f.append(f.index)
|
||||
bpy.ops.mesh.select_all(action = 'DESELECT')
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------ operator 2 ------ align to original
|
||||
class va_op2_align(bpy.types.Operator):
|
||||
bl_idname = 'va.op2_align_id'
|
||||
bl_label = 'Align to original'
|
||||
# Align to original
|
||||
class Vertex_align_original(Operator):
|
||||
bl_idname = "vertex_align.align_original"
|
||||
bl_label = "Align to original"
|
||||
bl_description = "Align selection to stored single vertex coordinates"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
bl_description = "Align selection to stored single vert"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.active_object
|
||||
return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label('Axis:')
|
||||
layout.prop(context.scene.va_custom_props, 'en1', expand = True)
|
||||
layout.label("Axis:")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
|
||||
text="X", index=0, toggle=True)
|
||||
row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
|
||||
text="Y", index=1, toggle=True)
|
||||
row.prop(context.scene.mesh_extra_tools, "vert_align_axis",
|
||||
text="Z", index=2, toggle=True)
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
edit_mode_out()
|
||||
ob_act = context.active_object
|
||||
me = ob_act.data
|
||||
cen1 = context.scene.va_custom_props.en1
|
||||
cen1 = context.scene.mesh_extra_tools.vert_align_axis
|
||||
list_0 = [v.index for v in me.vertices if v.select]
|
||||
|
||||
if len(va_buf.list_v) == 0:
|
||||
self.report({'INFO'}, 'Original vertex not stored in memory')
|
||||
self.report({'INFO'},
|
||||
"Original vertex not stored in memory. Operation Cancelled")
|
||||
edit_mode_in()
|
||||
return {'CANCELLED'}
|
||||
|
||||
elif len(va_buf.list_v) != 0:
|
||||
if len(list_0) == 0:
|
||||
self.report({'INFO'}, 'No vertices selected')
|
||||
self.report({'INFO'}, "No vertices selected. Operation Cancelled")
|
||||
edit_mode_in()
|
||||
return {'CANCELLED'}
|
||||
|
||||
elif len(list_0) != 0:
|
||||
vo = (me.vertices[va_buf.list_v[0]].co).copy()
|
||||
if cen1 == 'en1_opt0':
|
||||
if cen1[0] is True:
|
||||
for i in list_0:
|
||||
v = (me.vertices[i].co).copy()
|
||||
me.vertices[i].co = Vector(( vo[0], v[1], v[2] ))
|
||||
elif cen1 == 'en1_opt1':
|
||||
me.vertices[i].co = Vector((vo[0], v[1], v[2]))
|
||||
if cen1[1] is True:
|
||||
for i in list_0:
|
||||
v = (me.vertices[i].co).copy()
|
||||
me.vertices[i].co = Vector(( v[0], vo[1], v[2] ))
|
||||
elif cen1 == 'en1_opt2':
|
||||
me.vertices[i].co = Vector((v[0], vo[1], v[2]))
|
||||
if cen1[2] is True:
|
||||
for i in list_0:
|
||||
v = (me.vertices[i].co).copy()
|
||||
me.vertices[i].co = Vector(( v[0], v[1], vo[2] ))
|
||||
me.vertices[i].co = Vector((v[0], v[1], vo[2]))
|
||||
edit_mode_in()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------ operator 3 ------ align to custom coordinates
|
||||
class va_op3_coord_list(bpy.types.Operator):
|
||||
bl_idname = 'va.op3_coord_list_id'
|
||||
bl_label = ''
|
||||
|
||||
# Align to custom coordinates
|
||||
class Vertex_align_coord_list(Operator):
|
||||
bl_idname = "vertex_align.coord_list_id"
|
||||
bl_label = ""
|
||||
bl_description = "Align to custom coordinates"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.active_object
|
||||
return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
|
||||
|
||||
def execute(self, context):
|
||||
edit_mode_out()
|
||||
ob_act = context.active_object
|
||||
me = ob_act.data
|
||||
list_clear_(va_buf.list_0)
|
||||
va_buf.list_0 = [v.index for v in me.vertices if v.select][:]
|
||||
|
||||
if len(va_buf.list_0) == 0:
|
||||
self.report({'INFO'}, 'No vertices selected')
|
||||
self.report({'INFO'}, "No vertices selected. Operation Cancelled")
|
||||
edit_mode_in()
|
||||
return {'CANCELLED'}
|
||||
|
||||
elif len(va_buf.list_0) != 0:
|
||||
bpy.ops.va.op4_id('INVOKE_DEFAULT')
|
||||
bpy.ops.vertex_align.coord_menu_id('INVOKE_DEFAULT')
|
||||
|
||||
edit_mode_in()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------ operator 4 ------ align to custom coordinates menu
|
||||
class va_op4_coord_menu(bpy.types.Operator):
|
||||
bl_idname = 'va.op4_id'
|
||||
bl_label = 'Align to custom coordinates'
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
bl_description = "Align to custom coordinates2"
|
||||
|
||||
x = y = z = FloatProperty( name = '',
|
||||
default = 0.0,
|
||||
min = -100.0,
|
||||
max = 100.0,
|
||||
step = 1,
|
||||
precision = 3 )
|
||||
b_x = b_y = b_z = BoolProperty()
|
||||
# Align to custom coordinates menu
|
||||
class Vertex_align_coord_menu(Operator):
|
||||
bl_idname = "vertex_align.coord_menu_id"
|
||||
bl_label = "Tweak custom coordinates"
|
||||
bl_description = "Change the custom coordinates for aligning"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def_axis_coord = FloatVectorProperty(
|
||||
name="",
|
||||
description="Enter the values of coordinates",
|
||||
default=(0.0, 0.0, 0.0),
|
||||
min=-100.0, max=100.0,
|
||||
step=1, size=3,
|
||||
subtype='XYZ',
|
||||
precision=3
|
||||
)
|
||||
use_axis_coord = BoolVectorProperty(
|
||||
name="Axis",
|
||||
description="Choose Custom Coordinates axis",
|
||||
default=(False,) * 3,
|
||||
size=3,
|
||||
)
|
||||
is_not_undo = False
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.active_object
|
||||
return (obj and obj.type == 'MESH')
|
||||
|
||||
def using_store(self, context):
|
||||
scene = context.scene
|
||||
return scene.mesh_extra_tools.vert_align_use_stored
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
if self.using_store(context) and self.is_not_undo:
|
||||
layout.label("Using Stored Coordinates", icon="INFO")
|
||||
|
||||
row = layout.split(0.25)
|
||||
row.prop(self, 'b_x', text = 'x')
|
||||
row.prop(self, 'x')
|
||||
row.prop(self, "use_axis_coord", index=0, text="X")
|
||||
row.prop(self, "def_axis_coord", index=0)
|
||||
|
||||
row = layout.split(0.25)
|
||||
row.prop(self, 'b_y', text = 'y')
|
||||
row.prop(self, 'y')
|
||||
row.prop(self, "use_axis_coord", index=1, text="Y")
|
||||
row.prop(self, "def_axis_coord", index=1)
|
||||
|
||||
row = layout.split(0.25)
|
||||
row.prop(self, 'b_z', text = 'z')
|
||||
row.prop(self, 'z')
|
||||
row.prop(self, "use_axis_coord", index=2, text="Z")
|
||||
row.prop(self, "def_axis_coord", index=2)
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_props_dialog(self, width = 200)
|
||||
self.is_not_undo = True
|
||||
scene = context.scene
|
||||
if self.using_store(context):
|
||||
self.def_axis_coord = scene.mesh_extra_tools.vert_align_store_axis
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self, width=200)
|
||||
|
||||
def execute(self, context):
|
||||
self.is_not_undo = False
|
||||
edit_mode_out()
|
||||
ob_act = context.active_object
|
||||
me = ob_act.data
|
||||
|
@ -226,71 +264,38 @@ class va_op4_coord_menu(bpy.types.Operator):
|
|||
for i in va_buf.list_0:
|
||||
v = (me.vertices[i].co).copy()
|
||||
tmp = Vector((v[0], v[1], v[2]))
|
||||
if self.b_x == True:
|
||||
tmp[0] = self.x
|
||||
if self.b_y == True:
|
||||
tmp[1] = self.y
|
||||
if self.b_z == True:
|
||||
tmp[2] = self.z
|
||||
|
||||
if self.use_axis_coord[0] is True:
|
||||
tmp[0] = self.def_axis_coord[0]
|
||||
if self.use_axis_coord[1] is True:
|
||||
tmp[1] = self.def_axis_coord[1]
|
||||
if self.use_axis_coord[2] is True:
|
||||
tmp[2] = self.def_axis_coord[2]
|
||||
me.vertices[i].co = tmp
|
||||
|
||||
edit_mode_in()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------ operator 7 Help------
|
||||
class va_op7_help(bpy.types.Operator):
|
||||
|
||||
bl_idname = 'va.op7_help_id'
|
||||
bl_label = ''
|
||||
bl_description = "Info"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label('Help:')
|
||||
layout.label('To use select whatever you want vertices to be aligned to ')
|
||||
layout.label('and click button next to store data label. ')
|
||||
layout.label('Select vertices that you want to align and click Align button. ')
|
||||
|
||||
def execute(self, context):
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_popup(self, width = 400)
|
||||
|
||||
# ------ operator 8 ------
|
||||
class va_op8_execute(bpy.types.Operator):
|
||||
bl_idname = 'va.op8_id'
|
||||
bl_label = ''
|
||||
bl_description = "Executs"
|
||||
def execute(self, context):
|
||||
bpy.ops.va.op7_id('INVOKE_DEFAULT')
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------ Classes ------
|
||||
|
||||
# Register
|
||||
classes = (
|
||||
va_property_group,
|
||||
va_op0_store,
|
||||
va_op1_list,
|
||||
va_op2_align,
|
||||
va_op3_coord_list,
|
||||
va_op4_coord_menu,
|
||||
va_op7_help,
|
||||
va_op8_execute,
|
||||
Vertex_align_store,
|
||||
Vertex_align_original,
|
||||
Vertex_align_coord_list,
|
||||
Vertex_align_coord_menu,
|
||||
)
|
||||
# ------ Register ------
|
||||
|
||||
|
||||
def register():
|
||||
for c in classes:
|
||||
bpy.utils.register_class(c)
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.Scene.va_custom_props = PointerProperty(type = va_property_group)
|
||||
|
||||
# ------ ------
|
||||
def unregister():
|
||||
del bpy.types.Scene.va_custom_props
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
for c in classes:
|
||||
bpy.utils.unregister_class(c)
|
||||
|
||||
# ------ ------
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
|
|
@ -11,7 +11,6 @@ bl_info = {
|
|||
|
||||
import bpy
|
||||
import bpy_extras
|
||||
|
||||
from bpy.types import (
|
||||
Menu,
|
||||
Operator,
|
||||
|
@ -60,16 +59,17 @@ class MESH_OT_CallContextMenu(Operator):
|
|||
return bpy.ops.wm.call_menu(name=MESH_MT_CombinedMenu.bl_idname)
|
||||
|
||||
|
||||
classes = [
|
||||
classes = (
|
||||
MESH_MT_CombinedMenu,
|
||||
MESH_OT_CallContextMenu
|
||||
]
|
||||
MESH_OT_CallContextMenu,
|
||||
)
|
||||
|
||||
|
||||
KEYMAPS = (
|
||||
# First, keymap identifiers (last bool is True for modal km).
|
||||
(("3D View", "VIEW_3D", "WINDOW", False), (
|
||||
# Then a tuple of keymap items, defined by a dict of kwargs for the km new func, and a tuple of tuples (name, val)
|
||||
# Then a tuple of keymap items, defined by a dict of kwargs
|
||||
# for the km new func, and a tuple of tuples (name, val)
|
||||
# for ops properties, if needing non-default values.
|
||||
({"idname": MESH_OT_CallContextMenu.bl_idname, "type": 'RIGHTMOUSE', "value": 'DOUBLE_CLICK'},
|
||||
()),
|
||||
|
|
Loading…
Reference in New Issue