Import_3ds: Improved distance cue chunk import
[blender-addons.git] / mesh_tools / pkhg_faces.py
blob4853166e1ed7f57003cd4b85b2e62ce384bf1619
1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "PKHG faces",
7 "author": "PKHG",
8 "version": (0, 0, 6),
9 "blender": (2, 71, 0),
10 "location": "View3D > Tools > PKHG (tab)",
11 "description": "Faces selected will become added faces of different style",
12 "warning": "",
13 "doc_url": "",
14 "category": "Mesh",
17 import bpy
18 import bmesh
19 from bpy.types import Operator
20 from mathutils import Vector
21 from bpy.props import (
22 BoolProperty,
23 StringProperty,
24 IntProperty,
25 FloatProperty,
26 EnumProperty,
30 class MESH_OT_add_faces_to_object(Operator):
31 bl_idname = "mesh.add_faces_to_object"
32 bl_label = "Face Shape"
33 bl_description = "Set parameters and build object with added faces"
34 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
36 reverse_faces: BoolProperty(
37 name="Reverse Faces",
38 default=False,
39 description="Revert the normals of selected faces"
41 name_source_object: StringProperty(
42 name="Mesh",
43 description="Choose a Source Mesh",
44 default="Cube"
46 remove_start_faces: BoolProperty(
47 name="Remove Start Faces",
48 default=True,
49 description="Make a choice about removal of Original Faces"
51 base_height: FloatProperty(
52 name="Base Height",
53 min=-20,
54 soft_max=10, max=20,
55 default=0.2,
56 description="Set general Base Height"
58 use_relative_base_height: BoolProperty(
59 name="Relative Base Height",
60 default=False,
61 description="Relative or absolute Base Height"
63 second_height: FloatProperty(
64 name="2nd height", min=-5,
65 soft_max=5, max=20,
66 default=0.2,
67 description="Second height for various shapes"
69 width: FloatProperty(
70 name="Width Faces",
71 min=-20, max=20,
72 default=0.5,
73 description="Set general width"
75 repeat_extrude: IntProperty(
76 name="Repeat",
77 min=1,
78 soft_max=5, max=20,
79 description="For longer base"
81 move_inside: FloatProperty(
82 name="Move Inside",
83 min=0.0,
84 max=1.0,
85 default=0.5,
86 description="How much move to inside"
88 thickness: FloatProperty(
89 name="Thickness",
90 soft_min=0.01, min=0,
91 soft_max=5.0, max=20.0,
92 default=0
94 depth: FloatProperty(
95 name="Depth",
96 min=-5,
97 soft_max=5.0, max=20.0,
98 default=0
100 collapse_edges: BoolProperty(
101 name="Make Point",
102 default=False,
103 description="Collapse the vertices of edges"
105 spike_base_width: FloatProperty(
106 name="Spike Base Width",
107 default=0.4,
108 min=-4.0,
109 soft_max=1, max=20,
110 description="Base width of a spike"
112 base_height_inset: FloatProperty(
113 name="Base Height Inset",
114 default=0.0,
115 min=-5, max=5,
116 description="To elevate or drop the Base height Inset"
118 top_spike: FloatProperty(
119 name="Top Spike",
120 default=1.0,
121 min=-10.0, max=10.0,
122 description="The Base Height of a spike"
124 top_extra_height: FloatProperty(
125 name="Top Extra Height",
126 default=0.0,
127 min=-10.0, max=10.0,
128 description="Add extra height"
130 step_with_real_spike: BoolProperty(
131 name="Step with Real Spike",
132 default=False,
133 description="In stepped, use a real spike"
135 use_relative: BoolProperty(
136 name="Use Relative",
137 default=False,
138 description="Change size using area, min or max"
140 face_types: EnumProperty(
141 name="Face Types",
142 description="Different types of Faces",
143 default="no",
144 items=[
145 ('no', "Pick an Option", "Choose one of the available options"),
146 ('open_inset', "Open Inset", "Inset without closing faces (holes)"),
147 ('with_base', "With Base", "Base and ..."),
148 ('clsd_vertical', "Closed Vertical", "Closed Vertical"),
149 ('open_vertical', "Open Vertical", "Open Vertical"),
150 ('spiked', "Spiked", "Spike"),
151 ('stepped', "Stepped", "Stepped"),
152 ('boxed', "Boxed", "Boxed"),
153 ('bar', "Bar", "Bar"),
156 strange_boxed_effect: BoolProperty(
157 name="Strange Effect",
158 default=False,
159 description="Do not show one extrusion"
161 use_boundary: BoolProperty(
162 name="Use Boundary",
163 default=True
165 use_even_offset: BoolProperty(
166 name="Even Offset",
167 default=True
169 use_relative_offset: BoolProperty(
170 name="Relative Offset",
171 default=True
173 use_edge_rail: BoolProperty(
174 name="Edge Rail",
175 default=False
177 use_outset: BoolProperty(
178 name="Outset",
179 default=False
181 use_select_inset: BoolProperty(
182 name="Inset",
183 default=False
185 use_interpolate: BoolProperty(
186 name="Interpolate",
187 default=True
190 @classmethod
191 def poll(cls, context):
192 result = False
193 active_object = context.active_object
194 if active_object:
195 mesh_objects_name = [el.name for el in bpy.data.objects if el.type == "MESH"]
196 if active_object.name in mesh_objects_name:
197 result = True
199 return result
201 def draw(self, context):
202 layout = self.layout
203 col = layout.column()
205 col.separator()
206 col.label(text="Using Active Object", icon="INFO")
207 col.separator()
208 col.label(text="Face Types:")
209 col.prop(self, "face_types", text="")
210 col.separator()
211 col.prop(self, "use_relative")
213 if self.face_types == "open_inset":
214 col.prop(self, "move_inside")
215 col.prop(self, "base_height")
217 elif self.face_types == "with_base":
218 col.prop(self, "move_inside")
219 col.prop(self, "base_height")
220 col.prop(self, "second_height")
221 col.prop(self, "width")
223 elif self.face_types == "clsd_vertical":
224 col.prop(self, "base_height")
226 elif self.face_types == "open_vertical":
227 col.prop(self, "base_height")
229 elif self.face_types == "boxed":
230 col.prop(self, "move_inside")
231 col.prop(self, "base_height")
232 col.prop(self, "top_spike")
233 col.prop(self, "strange_boxed_effect")
235 elif self.face_types == "spiked":
236 col.prop(self, "spike_base_width")
237 col.prop(self, "base_height_inset")
238 col.prop(self, "top_spike")
240 elif self.face_types == "bar":
241 col.prop(self, "spike_base_width")
242 col.prop(self, "top_spike")
243 col.prop(self, "top_extra_height")
245 elif self.face_types == "stepped":
246 col.prop(self, "spike_base_width")
247 col.prop(self, "base_height_inset")
248 col.prop(self, "top_extra_height")
249 col.prop(self, "second_height")
250 col.prop(self, "step_with_real_spike")
252 def execute(self, context):
253 obj_name = self.name_source_object
254 face_type = self.face_types
256 is_selected = check_is_selected()
258 if not is_selected:
259 self.report({'WARNING'},
260 "Operation Cancelled. No selected Faces found on the Active Object")
261 return {'CANCELLED'}
263 if face_type == "spiked":
264 Spiked(spike_base_width=self.spike_base_width,
265 base_height_inset=self.base_height_inset,
266 top_spike=self.top_spike, top_relative=self.use_relative)
268 elif face_type == "boxed":
269 startinfo = prepare(self, context, self.remove_start_faces)
270 bm = startinfo['bm']
271 top = self.top_spike
272 obj = startinfo['obj']
273 obj_matrix_local = obj.matrix_local
275 distance = None
276 base_heights = None
277 t = self.move_inside
278 areas = startinfo['areas']
279 base_height = self.base_height
281 if self.use_relative:
282 distance = [min(t * area, 1.0) for i, area in enumerate(areas)]
283 base_heights = [base_height * area for i, area in enumerate(areas)]
284 else:
285 distance = [t] * len(areas)
286 base_heights = [base_height] * len(areas)
288 rings = startinfo['rings']
289 centers = startinfo['centers']
290 normals = startinfo['normals']
291 for i in range(len(rings)):
292 make_one_inset(self, context, bm=bm, ringvectors=rings[i],
293 center=centers[i], normal=normals[i],
294 t=distance[i], base_height=base_heights[i])
295 bpy.ops.mesh.select_mode(type="EDGE")
296 bpy.ops.mesh.select_more()
297 bpy.ops.mesh.select_more()
298 bpy.ops.object.mode_set(mode='OBJECT')
299 # PKHG>INFO base extrusion done and set to the mesh
301 # PKHG>INFO if the extrusion is NOT done ... it'll look strange soon!
302 if not self.strange_boxed_effect:
303 bpy.ops.object.mode_set(mode='EDIT')
304 obj = context.active_object
305 bm = bmesh.from_edit_mesh(obj.data)
306 bmfaces = [face for face in bm.faces if face.select]
307 res = extrude_faces(self, context, bm=bm, face_l=bmfaces)
308 ring_edges = [face.edges[:] for face in res]
310 bpy.ops.object.mode_set(mode='OBJECT')
312 # PKHG>INFO now the extruded facec have to move in normal direction
313 bpy.ops.object.mode_set(mode='EDIT')
314 obj = bpy.context.view_layer.objects.active
315 bm = bmesh.from_edit_mesh(obj.data)
316 todo_faces = [face for face in bm.faces if face.select]
317 for face in todo_faces:
318 bmesh.ops.translate(bm, vec=face.normal * top, space=obj_matrix_local,
319 verts=face.verts)
320 bpy.ops.object.mode_set(mode='OBJECT')
322 elif face_type == "stepped":
323 Stepped(spike_base_width=self.spike_base_width,
324 base_height_inset=self.base_height_inset,
325 top_spike=self.second_height,
326 top_extra_height=self.top_extra_height,
327 use_relative_offset=self.use_relative, with_spike=self.step_with_real_spike)
329 elif face_type == "open_inset":
330 startinfo = prepare(self, context, self.remove_start_faces)
331 bm = startinfo['bm']
333 # PKHG>INFO adjust for relative, via areas
334 t = self.move_inside
335 areas = startinfo['areas']
336 base_height = self.base_height
337 base_heights = None
338 distance = None
339 if self.use_relative:
340 distance = [min(t * area, 1.0) for i, area in enumerate(areas)]
341 base_heights = [base_height * area for i, area in enumerate(areas)]
342 else:
343 distance = [t] * len(areas)
344 base_heights = [base_height] * len(areas)
346 rings = startinfo['rings']
347 centers = startinfo['centers']
348 normals = startinfo['normals']
349 for i in range(len(rings)):
350 make_one_inset(self, context, bm=bm, ringvectors=rings[i],
351 center=centers[i], normal=normals[i],
352 t=distance[i], base_height=base_heights[i])
353 bpy.ops.object.mode_set(mode='OBJECT')
355 elif face_type == "with_base":
356 startinfo = prepare(self, context, self.remove_start_faces)
357 bm = startinfo['bm']
358 obj = startinfo['obj']
359 object_matrix = obj.matrix_local
361 # PKHG>INFO for relative (using areas)
362 t = self.move_inside
363 areas = startinfo['areas']
364 base_height = self.base_height
365 distance = None
366 base_heights = None
368 if self.use_relative:
369 distance = [min(t * area, 1.0) for i, area in enumerate(areas)]
370 base_heights = [base_height * area for i, area in enumerate(areas)]
371 else:
372 distance = [t] * len(areas)
373 base_heights = [base_height] * len(areas)
375 next_rings = []
376 rings = startinfo['rings']
377 centers = startinfo['centers']
378 normals = startinfo['normals']
379 for i in range(len(rings)):
380 next_rings.append(make_one_inset(self, context, bm=bm, ringvectors=rings[i],
381 center=centers[i], normal=normals[i],
382 t=distance[i], base_height=base_heights[i]))
384 prepare_ring = extrude_edges(self, context, bm=bm, edge_l_l=next_rings)
386 second_height = self.second_height
387 width = self.width
388 vectors = [[ele.verts[:] for ele in edge] for edge in prepare_ring]
389 n_ring_vecs = []
391 for rings in vectors:
392 v = []
393 for edgv in rings:
394 v.extend(edgv)
395 # PKHF>INFO no double verts allowed, coming from two adjacents edges!
396 bm.verts.ensure_lookup_table()
397 vv = list(set([ele.index for ele in v]))
399 vvv = [bm.verts[i].co for i in vv]
400 n_ring_vecs.append(vvv)
402 for i, ring in enumerate(n_ring_vecs):
403 make_one_inset(self, context, bm=bm, ringvectors=ring,
404 center=centers[i], normal=normals[i],
405 t=width, base_height=base_heights[i] + second_height)
406 bpy.ops.object.mode_set(mode='OBJECT')
408 else:
409 if face_type == "clsd_vertical":
410 obj_name = context.active_object.name
411 ClosedVertical(name=obj_name, base_height=self.base_height,
412 use_relative_base_height=self.use_relative)
414 elif face_type == "open_vertical":
415 obj_name = context.active_object.name
416 OpenVertical(name=obj_name, base_height=self.base_height,
417 use_relative_base_height=self.use_relative)
419 elif face_type == "bar":
420 startinfo = prepare(self, context, self.remove_start_faces)
422 result = []
423 bm = startinfo['bm']
424 rings = startinfo['rings']
425 centers = startinfo['centers']
426 normals = startinfo['normals']
427 spike_base_width = self.spike_base_width
428 for i, ring in enumerate(rings):
429 result.append(make_one_inset(self, context, bm=bm,
430 ringvectors=ring, center=centers[i],
431 normal=normals[i], t=spike_base_width))
433 next_ring_edges_list = extrude_edges(self, context, bm=bm,
434 edge_l_l=result)
435 top_spike = self.top_spike
436 fac = top_spike
437 object_matrix = startinfo['obj'].matrix_local
438 for i in range(len(next_ring_edges_list)):
439 translate_ONE_ring(
440 self, context, bm=bm,
441 object_matrix=object_matrix,
442 ring_edges=next_ring_edges_list[i],
443 normal=normals[i], distance=fac
445 next_ring_edges_list_2 = extrude_edges(self, context, bm=bm,
446 edge_l_l=next_ring_edges_list)
448 top_extra_height = self.top_extra_height
449 for i in range(len(next_ring_edges_list_2)):
450 move_corner_vecs_outside(
451 self, context, bm=bm,
452 edge_list=next_ring_edges_list_2[i],
453 center=centers[i], normal=normals[i],
454 base_height_erlier=fac + top_extra_height,
455 distance=fac
457 bpy.ops.mesh.select_mode(type="VERT")
458 bpy.ops.mesh.select_more()
460 bpy.ops.object.mode_set(mode='OBJECT')
462 return {'FINISHED'}
465 def find_one_ring(sel_vertices):
466 ring0 = sel_vertices.pop(0)
467 to_delete = []
469 for i, edge in enumerate(sel_vertices):
470 len_nu = len(ring0)
471 if len(ring0 - edge) < len_nu:
472 to_delete.append(i)
473 ring0 = ring0.union(edge)
475 to_delete.reverse()
477 for el in to_delete:
478 sel_vertices.pop(el)
480 return (ring0, sel_vertices)
483 class Stepped:
484 def __init__(self, spike_base_width=0.5, base_height_inset=0.0, top_spike=0.2,
485 top_relative=False, top_extra_height=0, use_relative_offset=False,
486 with_spike=False):
488 bpy.ops.object.mode_set(mode='EDIT')
489 bpy.ops.mesh.inset(
490 use_boundary=True, use_even_offset=True, use_relative_offset=False,
491 use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
492 use_select_inset=False, use_individual=True, use_interpolate=True
494 bpy.ops.mesh.inset(
495 use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
496 use_edge_rail=False, thickness=top_extra_height, depth=base_height_inset,
497 use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True
499 bpy.ops.mesh.inset(
500 use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
501 use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
502 use_select_inset=False, use_individual=True, use_interpolate=True
504 bpy.ops.mesh.inset(
505 use_boundary=True, use_even_offset=True, use_relative_offset=False,
506 use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
507 use_select_inset=False, use_individual=True, use_interpolate=True
509 if with_spike:
510 bpy.ops.mesh.merge(type='COLLAPSE')
512 bpy.ops.object.mode_set(mode='OBJECT')
515 class Spiked:
516 def __init__(self, spike_base_width=0.5, base_height_inset=0.0, top_spike=0.2, top_relative=False):
518 obj = bpy.context.active_object
519 bpy.ops.object.mode_set(mode='EDIT')
520 bpy.ops.mesh.inset(
521 use_boundary=True, use_even_offset=True, use_relative_offset=False,
522 use_edge_rail=False, thickness=spike_base_width, depth=base_height_inset,
523 use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True
525 bpy.ops.mesh.inset(
526 use_boundary=True, use_even_offset=True, use_relative_offset=top_relative,
527 use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
528 use_select_inset=False, use_individual=True, use_interpolate=True
531 bm = bmesh.from_edit_mesh(obj.data)
532 bpy.ops.mesh.merge(type='COLLAPSE')
533 bpy.ops.object.mode_set(mode='OBJECT')
536 class ClosedVertical:
537 def __init__(self, name="Plane", base_height=1, use_relative_base_height=False):
538 obj = bpy.data.objects[name]
539 bpy.ops.object.mode_set(mode='OBJECT')
540 bm = bmesh.new()
541 bm.from_mesh(obj.data)
542 # PKHG>INFO deselect chosen faces
543 sel = [f for f in bm.faces if f.select]
544 for f in sel:
545 f.select = False
546 res = bmesh.ops.extrude_discrete_faces(bm, faces=sel)
547 # PKHG>INFO select extruded faces
548 for f in res['faces']:
549 f.select = True
551 factor = base_height
552 for face in res['faces']:
553 if use_relative_base_height:
554 area = face.calc_area()
555 factor = area * base_height
556 else:
557 factor = base_height
558 for el in face.verts:
559 tmp = el.co + face.normal * factor
560 el.co = tmp
562 me = bpy.data.meshes[name]
563 bm.to_mesh(me)
564 bm.free()
567 class OpenVertical:
568 def __init__(self, name="Plane", base_height=1, use_relative_base_height=False):
570 obj = bpy.data.objects[name]
571 bpy.ops.object.mode_set(mode='OBJECT')
572 bm = bmesh.new()
573 bm.from_mesh(obj.data)
574 # PKHG>INFO deselect chosen faces
575 sel = [f for f in bm.faces if f.select]
576 for f in sel:
577 f.select = False
578 res = bmesh.ops.extrude_discrete_faces(bm, faces=sel)
579 # PKHG>INFO select extruded faces
580 for f in res['faces']:
581 f.select = True
583 # PKHG>INFO adjust extrusion by a vector
584 factor = base_height
585 for face in res['faces']:
586 if use_relative_base_height:
587 area = face.calc_area()
588 factor = area * base_height
589 else:
590 factor = base_height
591 for el in face.verts:
592 tmp = el.co + face.normal * factor
593 el.co = tmp
595 me = bpy.data.meshes[name]
596 bm.to_mesh(me)
597 bm.free()
599 bpy.ops.object.editmode_toggle()
600 bpy.ops.mesh.delete(type='FACE')
601 bpy.ops.object.editmode_toggle()
604 class StripFaces:
605 def __init__(self, use_boundary=True, use_even_offset=True, use_relative_offset=False,
606 use_edge_rail=True, thickness=0.0, depth=0.0, use_outset=False,
607 use_select_inset=False, use_individual=True, use_interpolate=True):
609 bpy.ops.object.mode_set(mode='EDIT')
610 bpy.ops.mesh.inset(
611 use_boundary=use_boundary, use_even_offset=True, use_relative_offset=False,
612 use_edge_rail=True, thickness=thickness, depth=depth, use_outset=use_outset,
613 use_select_inset=use_select_inset, use_individual=use_individual,
614 use_interpolate=use_interpolate
617 bpy.ops.object.mode_set(mode='OBJECT')
619 # PKHG>IMFO only 3 parameters inc execution context supported!!
620 if False:
621 bpy.ops.mesh.inset(
622 use_boundary, use_even_offset, use_relative_offset, use_edge_rail,
623 thickness, depth, use_outset, use_select_inset, use_individual,
624 use_interpolate
626 elif type == 0:
627 bpy.ops.mesh.inset(
628 use_boundary=True, use_even_offset=True, use_relative_offset=False,
629 use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
630 use_select_inset=False, use_individual=True, use_interpolate=True
632 elif type == 1:
633 bpy.ops.mesh.inset(
634 use_boundary=True, use_even_offset=True, use_relative_offset=False,
635 use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
636 use_select_inset=False, use_individual=True, use_interpolate=False
638 bpy.ops.mesh.delete(type='FACE')
640 elif type == 2:
641 bpy.ops.mesh.inset(
642 use_boundary=True, use_even_offset=False, use_relative_offset=True,
643 use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
644 use_select_inset=False, use_individual=True, use_interpolate=False
647 bpy.ops.mesh.delete(type='FACE')
649 elif type == 3:
650 bpy.ops.mesh.inset(
651 use_boundary=True, use_even_offset=False, use_relative_offset=True,
652 use_edge_rail=True, thickness=depth, depth=thickness, use_outset=False,
653 use_select_inset=False, use_individual=True, use_interpolate=True
655 bpy.ops.mesh.delete(type='FACE')
656 elif type == 4:
657 bpy.ops.mesh.inset(
658 use_boundary=True, use_even_offset=False, use_relative_offset=True,
659 use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
660 use_select_inset=False, use_individual=True, use_interpolate=True
662 bpy.ops.mesh.inset(
663 use_boundary=True, use_even_offset=False, use_relative_offset=True,
664 use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
665 use_select_inset=False, use_individual=True, use_interpolate=True
667 bpy.ops.mesh.delete(type='FACE')
669 bpy.ops.object.mode_set(mode='OBJECT')
672 def check_is_selected():
673 is_selected = False
674 for face in bpy.context.active_object.data.polygons:
675 if face.select:
676 is_selected = True
677 break
678 return is_selected
681 def prepare(self, context, remove_start_faces=True):
683 Start for a face selected change of faces
684 select an object of type mesh, with activated several (all) faces
686 obj = bpy.context.view_layer.objects.active
687 bpy.ops.object.mode_set(mode='OBJECT')
688 selectedpolygons = [el for el in obj.data.polygons if el.select]
690 # PKHG>INFO copies of the vectors are needed, otherwise Blender crashes!
691 centers = [face.center for face in selectedpolygons]
692 centers_copy = [Vector((el[0], el[1], el[2])) for el in centers]
693 normals = [face.normal for face in selectedpolygons]
694 normals_copy = [Vector((el[0], el[1], el[2])) for el in normals]
696 vertindicesofpolgons = [
697 [vert for vert in face.vertices] for face in selectedpolygons
699 vertVectorsOfSelectedFaces = [
700 [obj.data.vertices[ind].co for ind in vertIndiceofface] for
701 vertIndiceofface in vertindicesofpolgons
703 vertVectorsOfSelectedFaces_copy = [
704 [Vector((el[0], el[1], el[2])) for el in listofvecs] for
705 listofvecs in vertVectorsOfSelectedFaces
708 bpy.ops.object.mode_set(mode='EDIT')
709 bm = bmesh.from_edit_mesh(obj.data)
710 selected_bm_faces = [ele for ele in bm.faces if ele.select]
712 selected_edges_per_face_ind = [
713 [ele.index for ele in face.edges] for face in selected_bm_faces
715 indices = [el.index for el in selectedpolygons]
716 selected_faces_areas = [bm.faces[:][i] for i in indices]
717 tmp_area = [el.calc_area() for el in selected_faces_areas]
719 # PKHG>INFO, selected faces are removed, only their edges are used!
720 if remove_start_faces:
721 bpy.ops.mesh.delete(type='ONLY_FACE')
722 bpy.ops.object.mode_set(mode='OBJECT')
723 obj.data.update()
724 bpy.ops.object.mode_set(mode='EDIT')
725 bm = bmesh.from_edit_mesh(obj.data)
726 bm.verts.ensure_lookup_table()
727 bm.faces.ensure_lookup_table()
729 start_ring_raw = [
730 [bm.verts[ind].index for ind in vertIndiceofface] for
731 vertIndiceofface in vertindicesofpolgons
733 start_ring = []
735 for el in start_ring_raw:
736 start_ring.append(set(el))
737 bm.edges.ensure_lookup_table()
739 bm_selected_edges_l_l = [
740 [bm.edges[i] for i in bm_ind_list] for
741 bm_ind_list in selected_edges_per_face_ind
743 result = {
744 'obj': obj, 'centers': centers_copy, 'normals': normals_copy,
745 'rings': vertVectorsOfSelectedFaces_copy, 'bm': bm,
746 'areas': tmp_area, 'startBMRingVerts': start_ring,
747 'base_edges': bm_selected_edges_l_l
750 return result
753 def make_one_inset(self, context, bm=None, ringvectors=None, center=None,
754 normal=None, t=None, base_height=0):
755 # a face will get 'inserted' faces to create (normally) a hole if t is > 0 and < 1)
756 tmp = []
758 for el in ringvectors:
759 tmp.append((el * (1 - t) + center * t) + normal * base_height)
761 tmp = [bm.verts.new(v) for v in tmp] # the new corner bmvectors
762 # PKHG>INFO so to say sentinells, to use ONE for ...
763 tmp.append(tmp[0])
764 vectorsFace_i = [bm.verts.new(v) for v in ringvectors]
765 vectorsFace_i.append(vectorsFace_i[0])
766 myres = []
767 for ii in range(len(vectorsFace_i) - 1):
768 # PKHG>INFO next line: sequence is important! for added edge
769 bmvecs = [vectorsFace_i[ii], vectorsFace_i[ii + 1], tmp[ii + 1], tmp[ii]]
770 res = bm.faces.new(bmvecs)
771 myres.append(res.edges[2])
772 myres[-1].select = True # PKHG>INFO to be used later selected!
773 return (myres)
776 def extrude_faces(self, context, bm=None, face_l=None):
777 # to make a ring extrusion
778 res = bmesh.ops.extrude_discrete_faces(bm, faces=face_l)['faces']
780 for face in res:
781 face.select = True
782 return res
785 def extrude_edges(self, context, bm=None, edge_l_l=None):
786 # to make a ring extrusion
787 all_results = []
788 for edge_l in edge_l_l:
789 for edge in edge_l:
790 edge.select = False
791 res = bmesh.ops.extrude_edge_only(bm, edges=edge_l)
792 tmp = [ele for ele in res['geom'] if isinstance(ele, bmesh.types.BMEdge)]
793 for edge in tmp:
794 edge.select = True
795 all_results.append(tmp)
796 return all_results
799 def translate_ONE_ring(self, context, bm=None, object_matrix=None, ring_edges=None,
800 normal=(0, 0, 1), distance=0.5):
801 # translate a ring in given (normal?!) direction with given (global) amount
802 tmp = []
803 for edge in ring_edges:
804 tmp.extend(edge.verts[:])
805 # PKHG>INFO no double vertices allowed by bmesh!
806 tmp = set(tmp)
807 tmp = list(tmp)
808 bmesh.ops.translate(bm, vec=normal * distance, space=object_matrix, verts=tmp)
809 # PKHG>INFO relevant edges will stay selected
810 return ring_edges
813 def move_corner_vecs_outside(self, context, bm=None, edge_list=None, center=None,
814 normal=None, base_height_erlier=0.5, distance=0.5):
815 # move corners (outside meant mostly) dependent on the parameters
816 tmp = []
817 for edge in edge_list:
818 tmp.extend([ele for ele in edge.verts if isinstance(ele, bmesh.types.BMVert)])
819 # PKHG>INFO to remove vertices, they are all used twice in the ring!
820 tmp = set(tmp)
821 tmp = list(tmp)
823 for i in range(len(tmp)):
824 vec = tmp[i].co
825 direction = vec + (vec - (normal * base_height_erlier + center)) * distance
826 tmp[i].co = direction
828 # define classes for registration
829 classes = (
830 MESH_OT_add_faces_to_object,
833 def register():
834 for cls in classes:
835 bpy.utils.register_class(cls)
838 def unregister():
839 for cls in classes:
840 bpy.utils.unregister_class(cls)
843 if __name__ == "__main__":
844 register()