1 # SPDX-FileCopyrightText: 2018-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 __author__
= "Nutti <nutti.metro@gmail.com>"
6 __status__
= "production"
8 __date__
= "22 Apr 2022"
11 from bpy
.props
import BoolProperty
, FloatProperty
, EnumProperty
15 from ..utils
.bl_class_registry
import BlClassRegistry
16 from ..utils
.property_class_registry
import PropertyClassRegistry
17 from ..utils
import compatibility
as compat
20 def _is_valid_context(context
):
21 # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
22 # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
24 if not common
.is_valid_space(context
, ['IMAGE_EDITOR', 'VIEW_3D']):
27 objs
= common
.get_uv_editable_objects(context
)
31 # only edit mode is allowed to execute
32 if context
.object.mode
!= 'EDIT':
38 @PropertyClassRegistry()
43 def init_props(cls
, scene
):
44 scene
.muv_select_uv_enabled
= BoolProperty(
45 name
="Select UV Enabled",
46 description
="Select UV is enabled",
49 scene
.muv_select_uv_same_polygon_threshold
= FloatProperty(
50 name
="Same Polygon Threshold",
51 description
="Threshold to distinguish same polygons",
57 scene
.muv_select_uv_selection_method
= EnumProperty(
58 name
="Selection Method",
59 description
="How to select faces which have overlapped UVs",
62 "Select faces without unselecting selected faces"),
63 ('RESET', "Reset", "Select faces and unselect selected faces"),
67 scene
.muv_select_uv_sync_mesh_selection
= BoolProperty(
68 name
="Sync Mesh Selection",
69 description
="Select the mesh's faces as well as UVs' faces",
74 def del_props(cls
, scene
):
75 del scene
.muv_select_uv_enabled
76 del scene
.muv_select_uv_same_polygon_threshold
80 @compat.make_annotations
81 class MUV_OT_SelectUV_SelectOverlapped(bpy
.types
.Operator
):
83 Operation class: Select faces which have overlapped UVs
86 bl_idname
= "uv.muv_select_uv_select_overlapped"
87 bl_label
= "Overlapped"
88 bl_description
= "Select faces which have overlapped UVs"
89 bl_options
= {'REGISTER', 'UNDO'}
91 same_polygon_threshold
= FloatProperty(
92 name
="Same Polygon Threshold",
93 description
="Threshold to distinguish same polygons",
99 selection_method
= EnumProperty(
100 name
="Selection Method",
101 description
="How to select faces which have overlapped UVs",
104 "Select faces without unselecting selected faces"),
105 ('RESET', "Reset", "Select faces and unselect selected faces"),
109 sync_mesh_selection
= BoolProperty(
110 name
="Sync Mesh Selection",
111 description
="Select the mesh's faces as well as UVs' faces",
116 def poll(cls
, context
):
117 # we can not get area/space/region from console
118 if common
.is_console_mode():
120 return _is_valid_context(context
)
123 def setup_argument(ops
, scene
):
124 ops
.same_polygon_threshold
= scene
.muv_select_uv_same_polygon_threshold
125 ops
.selection_method
= scene
.muv_select_uv_selection_method
126 ops
.sync_mesh_selection
= scene
.muv_select_uv_sync_mesh_selection
128 def execute(self
, context
):
129 objs
= common
.get_uv_editable_objects(context
)
135 bm
= bmesh
.from_edit_mesh(obj
.data
)
136 if common
.check_version(2, 73, 0) >= 0:
137 bm
.faces
.ensure_lookup_table()
138 uv_layer
= bm
.loops
.layers
.uv
.verify()
140 if context
.tool_settings
.use_uv_select_sync
:
141 sel_faces
= [f
for f
in bm
.faces
]
143 sel_faces
= [f
for f
in bm
.faces
if f
.select
]
145 uv_layer_list
.append(uv_layer
)
146 faces_list
.append(sel_faces
)
148 overlapped_info
= common
.get_overlapped_uv_info(
149 bm_list
, faces_list
, uv_layer_list
, 'FACE',
150 self
.same_polygon_threshold
)
152 if self
.selection_method
== 'RESET':
153 if context
.tool_settings
.use_uv_select_sync
:
154 for faces
in faces_list
:
158 for uv_layer
, faces
in zip(uv_layer_list
, faces_list
):
160 if self
.sync_mesh_selection
:
163 l
[uv_layer
].select
= False
165 for info
in overlapped_info
:
166 if context
.tool_settings
.use_uv_select_sync
:
167 info
["subject_face"].select
= True
169 if self
.sync_mesh_selection
:
170 info
["subject_face"].select
= True
171 for l
in info
["subject_face"].loops
:
172 l
[info
["subject_uv_layer"]].select
= True
175 bmesh
.update_edit_mesh(obj
.data
)
181 @compat.make_annotations
182 class MUV_OT_SelectUV_SelectFlipped(bpy
.types
.Operator
):
184 Operation class: Select faces which have flipped UVs
187 bl_idname
= "uv.muv_select_uv_select_flipped"
189 bl_description
= "Select faces which have flipped UVs"
190 bl_options
= {'REGISTER', 'UNDO'}
192 selection_method
= EnumProperty(
193 name
="Selection Method",
194 description
="How to select faces which have overlapped UVs",
197 "Select faces without unselecting selected faces"),
198 ('RESET', "Reset", "Select faces and unselect selected faces"),
202 sync_mesh_selection
= BoolProperty(
203 name
="Sync Mesh Selection",
204 description
="Select the mesh's faces as well as UVs' faces",
209 def poll(cls
, context
):
210 # we can not get area/space/region from console
211 if common
.is_console_mode():
213 return _is_valid_context(context
)
216 def setup_argument(ops
, scene
):
217 ops
.selection_method
= scene
.muv_select_uv_selection_method
218 ops
.sync_mesh_selection
= scene
.muv_select_uv_sync_mesh_selection
220 def execute(self
, context
):
221 objs
= common
.get_uv_editable_objects(context
)
227 bm
= bmesh
.from_edit_mesh(obj
.data
)
228 if common
.check_version(2, 73, 0) >= 0:
229 bm
.faces
.ensure_lookup_table()
230 uv_layer
= bm
.loops
.layers
.uv
.verify()
232 if context
.tool_settings
.use_uv_select_sync
:
233 sel_faces
= [f
for f
in bm
.faces
]
235 sel_faces
= [f
for f
in bm
.faces
if f
.select
]
237 uv_layer_list
.append(uv_layer
)
238 faces_list
.append(sel_faces
)
240 flipped_info
= common
.get_flipped_uv_info(
241 bm_list
, faces_list
, uv_layer_list
)
243 if self
.selection_method
== 'RESET':
244 if context
.tool_settings
.use_uv_select_sync
:
245 for faces
in faces_list
:
249 for uv_layer
, faces
in zip(uv_layer_list
, faces_list
):
251 if self
.sync_mesh_selection
:
254 l
[uv_layer
].select
= False
256 for info
in flipped_info
:
257 if context
.tool_settings
.use_uv_select_sync
:
258 info
["face"].select
= True
260 if self
.sync_mesh_selection
:
261 info
["face"].select
= True
262 for l
in info
["face"].loops
:
263 l
[info
["uv_layer"]].select
= True
266 bmesh
.update_edit_mesh(obj
.data
)
272 class MUV_OT_SelectUV_ZoomSelectedUV(bpy
.types
.Operator
):
274 Operation class: Zoom selected UV in View3D space
277 bl_idname
= "uv.muv_select_uv_zoom_selected_uv"
278 bl_label
= "Zoom Selected UV"
279 bl_description
= "Zoom selected UV in View3D space"
280 bl_options
= {'REGISTER', 'UNDO'}
283 def poll(cls
, context
):
284 # we can not get area/space/region from console
285 if common
.is_console_mode():
287 return _is_valid_context(context
)
289 def _get_override_context(self
, context
):
290 for window
in context
.window_manager
.windows
:
291 screen
= window
.screen
292 for area
in screen
.areas
:
293 if area
.type == 'VIEW_3D':
294 for region
in area
.regions
:
295 if region
.type == 'WINDOW':
296 return {'window': window
, 'screen': screen
,
297 'area': area
, 'region': region
}
300 def execute(self
, context
):
301 objs
= common
.get_uv_editable_objects(context
)
307 bm
= bmesh
.from_edit_mesh(obj
.data
)
308 if common
.check_version(2, 73, 0) >= 0:
309 bm
.verts
.ensure_lookup_table()
310 uv_layer
= bm
.loops
.layers
.uv
.verify()
312 sel_verts
= [v
for v
in bm
.verts
if v
.select
]
314 uv_layer_list
.append(uv_layer
)
315 verts_list
.append(sel_verts
)
317 # Get all selected UV vertices in UV Editor.
319 for vlist
, uv_layer
in zip(verts_list
, uv_layer_list
):
321 for l
in v
.link_loops
:
322 if l
[uv_layer
].select
or \
323 context
.tool_settings
.use_uv_select_sync
:
324 sel_uv_verts
.append(v
)
327 # Select vertices only selected in UV Editor.
331 for v
in sel_uv_verts
:
334 bmesh
.update_edit_mesh(obj
.data
)
337 context_override
= self
._get
_override
_context
(context
)
338 if context_override
is None:
339 self
.report({'WARNING'}, "More than one 'VIEW_3D' area must exist")
341 with context
.temp_override(**context_override
):
342 bpy
.ops
.view3d
.view_selected(use_all_regions
=False)
344 # Revert selection of vertices.
348 bmesh
.update_edit_mesh(obj
.data
)