1 # SPDX-FileCopyrightText: 2012-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
8 from bpy_extras
import object_utils
13 from bpy
.props
import (
23 class honeycomb_geometry():
24 def __init__(self
, rows
, cols
, D
, E
):
30 self
.hE
= 0.5 * self
.E
35 self
.d
= self
.a
* self
.D
36 self
.hd
= 0.5 * self
.d
37 self
.e
= self
.hE
/ self
.a
38 self
.he
= 0.5 * self
.e
39 self
.r
= self
.R
- self
.e
40 self
.hr
= 0.5 * self
.r
42 self
.H
= self
.R
* (1.5 * self
.rows
+ 0.5) + self
.e
44 self
.W
= self
.d
* (self
.cols
+ 0.5) + self
.E
46 self
.W
= self
.d
* self
.cols
+ self
.E
48 self
.hH
= 0.5 * self
.H
49 self
.hW
= 0.5 * self
.W
51 self
.sy
= -self
.hH
+ self
.he
+ self
.R
52 self
.sx
= -self
.hW
+ self
.hE
+ self
.hd
56 self
.dy
= 1.5 * self
.R
59 def vert(self
, row
, col
):
61 if row
>= 0 and row
< self
.rows
and col
>= 0 and col
< self
.cols
:
62 return [0, 1, 2, 3, 4, 5]
64 if row
== -1 and col
== self
.cols
- 1:
66 if row
== 0 and self
.rows
> 1 and col
== self
.cols
:
69 if row
== -1 and col
== -1:
73 if row
== self
.rows
and col
== -1:
76 if row
== self
.rows
and col
== self
.cols
- 1:
78 if row
== self
.rows
- 1 and self
.rows
> 1 and col
== self
.cols
:
82 if row
== self
.rows
and col
== 0:
84 if row
== self
.rows
- 1 and self
.rows
> 1 and col
== -1:
87 if row
== self
.rows
and col
== self
.cols
:
90 if col
>= 0 and col
< self
.cols
:
96 if row
>= 0 and row
< self
.rows
:
103 if row
% 2 or self
.rows
== 1:
109 def cell(self
, row
, col
, idx
):
110 cp
= [self
.sx
+ self
.dx
* col
, self
.sy
+ self
.dy
* row
, 0] # central point
113 co
= [] # vertices coords
114 vi
= self
.vert(row
, col
)
118 a
= pi
/ 6 + i
* pi
/ 3 # angle
119 ap
[i
] = idx
+ len(co
)
120 co
.append((cp
[0] + cos(a
) * self
.r
, cp
[1] + sin(a
) * self
.r
, cp
[2]))
131 for row
in range(-ar
, self
.rows
+ ar
):
133 for col
in range(-ac
, self
.cols
+ ac
):
134 co
, ap
= self
.cell(row
, col
, len(verts
))
141 for col
in range(1, len(cells
[row
]) - 1):
143 l
= cells
[row
][col
- 1]
144 u
= cells
[row
+ 1][col
]
146 faces
.append((s
[1], u
[5], u
[4], s
[2]))
147 faces
.append((s
[2], u
[4], l
[0]))
154 for col
in range(1 + cs
, len(cells
[row
]) - 1):
156 l
= cells
[row
][col
- 1]
157 d
= cells
[row
- 1][col
- cs
]
158 faces
.append((s
[3], l
[5], d
[1]))
159 faces
.append([s
[3], d
[1], d
[0], s
[4]])
162 for row
in range(1, len(cells
) - 1):
166 for col
in range(1, len(cells
[row
]) - 1):
168 l
= cells
[row
][col
- 1]
169 u
= cells
[row
+ 1][col
- cs
]
170 d
= cells
[row
- 1][col
- cs
]
172 faces
.append((s
[1], u
[5], u
[4], s
[2]))
173 faces
.append((s
[2], u
[4], l
[0]))
174 faces
.append([s
[2], l
[0], l
[5], s
[3]])
175 faces
.append((s
[3], l
[5], d
[1]))
176 faces
.append([s
[3], d
[1], d
[0], s
[4]])
180 col
= len(cells
[row
]) - 1
181 for row
in range(1, len(cells
) - 1):
187 l
= cells
[row
][col
- 1]
188 u
= cells
[row
+ 1][col
- cs
]
189 d
= cells
[row
- 1][col
- cs
]
191 if row
% 2 and row
< len(cells
) - 2:
192 faces
.append((s
[1], u
[5], u
[4], s
[2]))
193 faces
.append((s
[2], u
[4], l
[0]))
194 faces
.append([s
[2], l
[0], l
[5], s
[3]])
195 faces
.append((s
[3], l
[5], d
[1]))
196 if row
% 2 and row
> 1:
197 faces
.append([s
[3], d
[1], d
[0], s
[4]])
200 if not self
.rows
% 2:
203 l
= cells
[row
][col
- 1]
204 d
= cells
[row
- 1][col
- 1]
205 faces
.append((s
[3], l
[5], d
[1]))
206 faces
.append([s
[3], d
[1], d
[0], s
[4]])
212 return diam
* sin(pi
/ 3)
215 class add_mesh_honeycomb(bpy
.types
.Operator
, object_utils
.AddObjectHelper
):
216 bl_idname
= "mesh.honeycomb_add"
217 bl_label
= "Add HoneyComb"
218 bl_description
= "Simple honeycomb mesh generator"
219 bl_options
= {'REGISTER', 'UNDO'}
221 def fix_edge(self
, context
):
222 m
= edge_max(self
.diam
)
226 HoneyComb
: BoolProperty(name
= "HoneyComb",
228 description
= "HoneyComb")
229 change
: BoolProperty(name
= "Change",
231 description
= "change HoneyComb")
237 description
='Number of the rows'
243 description
='Number of the columns'
246 name
='Cell Diameter',
248 min=0.0, update
=fix_edge
,
249 description
='Diameter of the cell'
254 min=0.0, update
=fix_edge
,
255 description
='Width of the edge'
258 def draw(self
, context
):
261 layout
.prop(self
, 'rows', expand
=True)
262 layout
.prop(self
, 'cols', expand
=True)
263 layout
.prop(self
, 'diam', expand
=True)
264 layout
.prop(self
, 'edge', expand
=True)
266 if self
.change
== False:
267 col
= layout
.column(align
=True)
268 col
.prop(self
, 'align', expand
=True)
269 col
= layout
.column(align
=True)
270 col
.prop(self
, 'location', expand
=True)
271 col
= layout
.column(align
=True)
272 col
.prop(self
, 'rotation', expand
=True)
275 def poll(cls
, context
):
276 return context
.scene
is not None
278 def execute(self
, context
):
279 # turn off 'Enter Edit Mode'
280 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
281 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
283 if bpy
.context
.mode
== "OBJECT":
284 if context
.selected_objects
!= [] and context
.active_object
and \
285 (context
.active_object
.data
is not None) and ('HoneyComb' in context
.active_object
.data
.keys()) and \
286 (self
.change
== True):
287 obj
= context
.active_object
289 oldmeshname
= obj
.data
.name
290 comb
= honeycomb_geometry(self
.rows
, self
.cols
, self
.diam
, self
.edge
)
291 verts
, faces
= comb
.generate()
292 mesh
= bpy
.data
.meshes
.new('HoneyComb')
293 mesh
.from_pydata(verts
, [], faces
)
295 for material
in oldmesh
.materials
:
296 obj
.data
.materials
.append(material
)
297 bpy
.data
.meshes
.remove(oldmesh
)
298 obj
.data
.name
= oldmeshname
300 comb
= honeycomb_geometry(self
.rows
, self
.cols
, self
.diam
, self
.edge
)
301 verts
, faces
= comb
.generate()
302 mesh
= bpy
.data
.meshes
.new('HoneyComb')
303 mesh
.from_pydata(verts
, [], faces
)
304 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
306 obj
.data
["HoneyComb"] = True
307 obj
.data
["change"] = False
308 for prm
in HoneyCombParameters():
309 obj
.data
[prm
] = getattr(self
, prm
)
311 if bpy
.context
.mode
== "EDIT_MESH":
312 active_object
= context
.active_object
313 name_active_object
= active_object
.name
314 bpy
.ops
.object.mode_set(mode
='OBJECT')
315 comb
= honeycomb_geometry(self
.rows
, self
.cols
, self
.diam
, self
.edge
)
316 verts
, faces
= comb
.generate()
317 mesh
= bpy
.data
.meshes
.new('HoneyComb')
318 mesh
.from_pydata(verts
, [], faces
)
319 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
321 active_object
.select_set(True)
322 bpy
.context
.view_layer
.objects
.active
= active_object
323 bpy
.ops
.object.join()
324 context
.active_object
.name
= name_active_object
325 bpy
.ops
.object.mode_set(mode
='EDIT')
327 if use_enter_edit_mode
:
328 bpy
.ops
.object.mode_set(mode
= 'EDIT')
330 # restore pre operator state
331 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
335 def HoneyCombParameters():
336 HoneyCombParameters
= [
342 return HoneyCombParameters