Skip to content

Commit 2f3ba54

Browse files
committed
tested for Blender 4.4
1 parent 96a7216 commit 2f3ba54

File tree

1 file changed

+187
-163
lines changed

1 file changed

+187
-163
lines changed

basket_arch.py

Lines changed: 187 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# ##### BEGIN GPL LICENSE BLOCK #####
22
#
33
# Basket Arch, a Blender addon
4-
# (c) 2014,2015,2020 Michel J. Anders (varkenvarken)
4+
# (c) 2014,2015,2020,2025 Michel J. Anders (varkenvarken)
55
#
66
# This program is free software; you can redistribute it and/or
77
# modify it under the terms of the GNU General Public License
@@ -19,176 +19,200 @@
1919
#
2020
# ##### END GPL LICENSE BLOCK #####
2121

22+
# This add-on creates a basket arch (a.k.a. three centered arch) mesh,
23+
# which is a type of arch with a specific geometry, often used in architecture.
24+
# See# https://en.wikipedia.org/wiki/Basket_arch for more information.
25+
2226
bl_info = {
23-
"name": "Basket Arch",
24-
"author": "Michel Anders (varkenvarken)",
25-
"version": (0, 0, 202005010941),
26-
"blender": (2, 83, 0),
27-
"location": "View3D > Add > Mesh",
28-
"description": "Adds a basket arch mesh",
29-
"warning": "",
30-
"wiki_url": "",
31-
"tracker_url": "",
32-
"category": "Add Mesh"}
33-
34-
from math import atan2, asin, sin, cos, pi, degrees, sqrt
27+
"name": "Basket Arch",
28+
"author": "Michel Anders (varkenvarken)",
29+
"version": (0, 0, 20250608095121),
30+
"blender": (2, 83, 0), # verified to work with Blender 4.4
31+
"location": "View3D > Add > Mesh",
32+
"description": "Adds a basket arch mesh",
33+
"warning": "",
34+
"wiki_url": "https://github.com/varkenvarken/blenderaddons",
35+
"tracker_url": "",
36+
"category": "Add Mesh",
37+
}
38+
39+
from math import atan2, sin, cos, pi, sqrt
3540
import bpy, bmesh
36-
from bpy.props import FloatProperty, BoolProperty, FloatVectorProperty, IntProperty, BoolVectorProperty, StringProperty
41+
from bpy.props import FloatProperty, IntProperty
3742
from bpy_extras import object_utils
3843

39-
def circle(x,y,r,s,e,w):
40-
co = []
41-
# in Blender z is considered up
42-
if s <= e :
43-
while s <= e :
44-
co.append((x+r*cos(s),0,y+r*sin(s)))
45-
s += w
46-
else:
47-
while s >= e :
48-
co.append((x+r*cos(s),0,y+r*sin(s)))
49-
s -= w
50-
return co
51-
52-
def calc_radii(W,H):
53-
r = 2*H/3.0
54-
h = H/3.0
55-
w = W/2.0
56-
alpha = atan2(h, w)
57-
b = sqrt(w*w + h*h)
58-
s = b/sin(alpha)
59-
c = s - h
60-
R = c + H
61-
62-
return r,R,c
63-
64-
def R(w,h):
65-
"""
66-
calculate the y poistion of the center circle of a basket arch given half the width and the height.
67-
"""
68-
a = h/3.0
69-
beta = atan2(a,w)
70-
c = sqrt(a**2 + w**2)
71-
d = c/2.0
72-
e = d/sin(beta)
73-
return e-a
74-
75-
def c(xA,yA,rA, xB,yB,rB):
76-
"""
77-
return the interection point(s) of two circles.
78-
"""
79-
d2 = (xB-xA)**2 + (yB-yA)**2
80-
K = (1/4.0) * sqrt(((rA+rB)**2-d2) * (d2-(rA-rB)**2))
81-
82-
xb = (1/2.0)*(xB+xA) + (1/2.0)*(xB-xA)*(rA**2-rB**2)/d2
83-
dx = 2*(yB-yA)*K/d2
84-
yb = (1/2.0)*(yB+yA) + (1/2.0)*(yB-yA)*(rA**2-rB**2)/d2
85-
dy = -2*(xB-xA)*K/d2
86-
87-
return ((xb+dx,yb+dy), (xb-dx,yb-dy))
88-
89-
90-
def basket_arch(W,D,H=0,resolution=1):
91-
if (H > 0) and (W/H >= 2.0) and (W/H <= 4.0):
92-
w=2*H/3.0
93-
s=W/2.0-w
94-
rc = R(s,H)
95-
r = rc + H
96-
c1x = -s
97-
c1y = 0
98-
cmx = 0
99-
cmy = -rc
100-
c2x = s
101-
c2y = 0
102-
CX,CY = c(c1x,c2x,w, cmx,cmy,r)[0]
103-
dx = -CX
104-
dy = CY + rc
105-
beta = atan2(dx,dy)
106-
dx = -CX-s
107-
dy = CY
108-
alpha = atan2(dx,dy)
109-
110-
else:
111-
w = W / 4.0
112-
h = sqrt(3.0) * w
113-
r = 3.0 * w
114-
c1x = -w
115-
c1y = 0
116-
cmx = 0
117-
cmy = -h
118-
c2x = w
119-
c2y = 0
120-
#alpha = atan2(h, 2.0 * w)
121-
beta = atan2(w , h)
122-
alpha = beta
123-
124-
co = circle(c1x, c1y, w, pi , pi / 2.0 + alpha, resolution * 3*pi/360)
125-
co += circle(cmx, cmy, r, pi / 2.0 + beta, pi / 2.0 - beta, resolution * pi/360)
126-
# reversing the generation of the points in this segment will ensure these segments are symmetrical
127-
# reversing the resulting list is necessary to maintain the order of the generated polygons
128-
co += reversed(circle(c2x, c2y, w, 0.0 , pi / 2.0 - alpha, resolution * 3*pi/360))
129-
130-
n = len(co)
131-
return co + [(x,y+D,z) for x,y,z in co], [(i,i+1,n+i+1,n+i) for i in range(n-1)]
132-
133-
class BasketArch(bpy.types.Operator,object_utils.AddObjectHelper):
134-
bl_idname = 'mesh.basketarch'
135-
bl_label = 'Create a basket arch'
136-
bl_options = {'REGISTER','UNDO'}
137-
138-
width : FloatProperty(
139-
name="Width",description="Width of the basket arch (span)",
140-
default=4,
141-
subtype='DISTANCE',
142-
unit='LENGTH')
143-
height : FloatProperty(
144-
name="Height",description="Height of the basket arch (0 if classical)",
145-
default=0,
146-
subtype='DISTANCE',
147-
unit='LENGTH')
148-
depth : FloatProperty(
149-
name="Depth",description="Depth of the basket arch",
150-
default=1,
151-
subtype='DISTANCE',
152-
unit='LENGTH')
153-
resolution : IntProperty(
154-
name="Resolution", description="Higher values = less polygons",
155-
default=1,
156-
min = 1)
157-
158-
def execute(self, context):
159-
160-
verts_loc, faces = basket_arch(self.width, self.depth, self.height, self.resolution)
161-
162-
mesh = bpy.data.meshes.new("BasketArch")
163-
164-
bm = bmesh.new()
165-
166-
for v_co in verts_loc:
167-
bm.verts.new(v_co)
168-
169-
# see http://blenderartists.org/forum/archive/index.php/t-354412.html for next bit
170-
if hasattr(bm.verts, "ensure_lookup_table"):
171-
bm.verts.ensure_lookup_table()
172-
173-
for f_idx in faces:
174-
bm.faces.new([bm.verts[i] for i in f_idx])
175-
176-
bm.to_mesh(mesh)
177-
mesh.update()
178-
179-
object_utils.object_data_add(context, mesh, operator=self)
180-
181-
return {"FINISHED"}
44+
45+
def circle(x, y, r, s, e, w):
46+
co = []
47+
# in Blender z is considered up
48+
if s <= e:
49+
while s <= e:
50+
co.append((x + r * cos(s), 0, y + r * sin(s)))
51+
s += w
52+
else:
53+
while s >= e:
54+
co.append((x + r * cos(s), 0, y + r * sin(s)))
55+
s -= w
56+
return co
57+
58+
59+
def calc_radii(W, H):
60+
r = 2 * H / 3.0
61+
h = H / 3.0
62+
w = W / 2.0
63+
alpha = atan2(h, w)
64+
b = sqrt(w * w + h * h)
65+
s = b / sin(alpha)
66+
c = s - h
67+
R = c + H
68+
69+
return r, R, c
70+
71+
72+
def R(w, h):
73+
"""
74+
calculate the y poistion of the center circle of a basket arch given half the width and the height.
75+
"""
76+
a = h / 3.0
77+
beta = atan2(a, w)
78+
c = sqrt(a**2 + w**2)
79+
d = c / 2.0
80+
e = d / sin(beta)
81+
return e - a
82+
83+
84+
def c(xA, yA, rA, xB, yB, rB):
85+
"""
86+
return the interection point(s) of two circles.
87+
"""
88+
d2 = (xB - xA) ** 2 + (yB - yA) ** 2
89+
K = (1 / 4.0) * sqrt(((rA + rB) ** 2 - d2) * (d2 - (rA - rB) ** 2))
90+
91+
xb = (1 / 2.0) * (xB + xA) + (1 / 2.0) * (xB - xA) * (rA**2 - rB**2) / d2
92+
dx = 2 * (yB - yA) * K / d2
93+
yb = (1 / 2.0) * (yB + yA) + (1 / 2.0) * (yB - yA) * (rA**2 - rB**2) / d2
94+
dy = -2 * (xB - xA) * K / d2
95+
96+
return ((xb + dx, yb + dy), (xb - dx, yb - dy))
97+
98+
99+
def basket_arch(W, D, H=0, resolution=1):
100+
if (H > 0) and (W / H >= 2.0) and (W / H <= 4.0):
101+
w = 2 * H / 3.0
102+
s = W / 2.0 - w
103+
rc = R(s, H)
104+
r = rc + H
105+
c1x = -s
106+
c1y = 0
107+
cmx = 0
108+
cmy = -rc
109+
c2x = s
110+
c2y = 0
111+
CX, CY = c(c1x, c2x, w, cmx, cmy, r)[0]
112+
dx = -CX
113+
dy = CY + rc
114+
beta = atan2(dx, dy)
115+
dx = -CX - s
116+
dy = CY
117+
alpha = atan2(dx, dy)
118+
119+
else:
120+
w = W / 4.0
121+
h = sqrt(3.0) * w
122+
r = 3.0 * w
123+
c1x = -w
124+
c1y = 0
125+
cmx = 0
126+
cmy = -h
127+
c2x = w
128+
c2y = 0
129+
# alpha = atan2(h, 2.0 * w)
130+
beta = atan2(w, h)
131+
alpha = beta
132+
133+
co = circle(c1x, c1y, w, pi, pi / 2.0 + alpha, resolution * 3 * pi / 360)
134+
co += circle(cmx, cmy, r, pi / 2.0 + beta, pi / 2.0 - beta, resolution * pi / 360)
135+
# reversing the generation of the points in this segment will ensure these segments are symmetrical
136+
# reversing the resulting list is necessary to maintain the order of the generated polygons
137+
co += reversed(
138+
circle(c2x, c2y, w, 0.0, pi / 2.0 - alpha, resolution * 3 * pi / 360)
139+
)
140+
141+
n = len(co)
142+
return co + [(x, y + D, z) for x, y, z in co], [
143+
(i, i + 1, n + i + 1, n + i) for i in range(n - 1)
144+
]
145+
146+
147+
class BasketArch(bpy.types.Operator, object_utils.AddObjectHelper):
148+
bl_idname = "mesh.basketarch"
149+
bl_label = "Create a basket arch"
150+
bl_options = {"REGISTER", "UNDO"}
151+
152+
width: FloatProperty(
153+
name="Width",
154+
description="Width of the basket arch (span)",
155+
default=4,
156+
subtype="DISTANCE",
157+
unit="LENGTH",
158+
)
159+
height: FloatProperty(
160+
name="Height",
161+
description="Height of the basket arch (0 if classical)",
162+
default=0,
163+
subtype="DISTANCE",
164+
unit="LENGTH",
165+
)
166+
depth: FloatProperty(
167+
name="Depth",
168+
description="Depth of the basket arch",
169+
default=1,
170+
subtype="DISTANCE",
171+
unit="LENGTH",
172+
)
173+
resolution: IntProperty(
174+
name="Resolution", description="Higher values = less polygons", default=1, min=1
175+
)
176+
177+
def execute(self, context):
178+
179+
verts_loc, faces = basket_arch(
180+
self.width, self.depth, self.height, self.resolution
181+
)
182+
183+
mesh = bpy.data.meshes.new("BasketArch")
184+
185+
bm = bmesh.new()
186+
187+
for v_co in verts_loc:
188+
bm.verts.new(v_co)
189+
190+
# see http://blenderartists.org/forum/archive/index.php/t-354412.html for next bit
191+
if hasattr(bm.verts, "ensure_lookup_table"):
192+
bm.verts.ensure_lookup_table()
193+
194+
for f_idx in faces:
195+
bm.faces.new([bm.verts[i] for i in f_idx])
196+
197+
bm.to_mesh(mesh)
198+
mesh.update()
199+
200+
object_utils.object_data_add(context, mesh, operator=self)
201+
202+
return {"FINISHED"}
203+
182204

183205
def menu_func(self, context):
184-
self.layout.operator(BasketArch.bl_idname, text="Create a basket arch mesh",
185-
icon='PLUGIN')
206+
self.layout.operator(
207+
BasketArch.bl_idname, text="Create a basket arch mesh", icon="PLUGIN"
208+
)
209+
186210

187211
def register():
188-
bpy.utils.register_class(BasketArch)
189-
bpy.types.VIEW3D_MT_mesh_add.append(menu_func)
212+
bpy.utils.register_class(BasketArch)
213+
bpy.types.VIEW3D_MT_mesh_add.append(menu_func)
190214

191215

192216
def unregister():
193-
bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)
194-
bpy.utils.unregister_class(BasketArch)
217+
bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)
218+
bpy.utils.unregister_class(BasketArch)

0 commit comments

Comments
 (0)