cqfantasy 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cqfantasy/arch/BasicArch.py +117 -0
- cqfantasy/arch/StoneArch.py +267 -0
- cqfantasy/arch/__init__.py +3 -0
- cqfantasy/arch/arch.py +32 -0
- cqfantasy/corner/AshlarCorner.py +155 -0
- cqfantasy/corner/__init__.py +1 -0
- cqfantasy/door/ArchDoor.py +73 -0
- cqfantasy/door/VDoor.py +133 -0
- cqfantasy/door/__init__.py +2 -0
- cqfantasy/fence/BarGreebled.py +110 -0
- cqfantasy/fence/BaseBrick.py +115 -0
- cqfantasy/fence/BasicBarDecoration.py +133 -0
- cqfantasy/fence/BasicBase.py +68 -0
- cqfantasy/fence/BasicFence.py +113 -0
- cqfantasy/fence/BasicPillar.py +68 -0
- cqfantasy/fence/PillarBrick.py +151 -0
- cqfantasy/fence/__init__.py +7 -0
- cqfantasy/fireplace/Chimney.py +78 -0
- cqfantasy/fireplace/ChimneyTiled.py +147 -0
- cqfantasy/fireplace/FireBox.py +86 -0
- cqfantasy/fireplace/FireBoxTiled.py +159 -0
- cqfantasy/fireplace/FireTop.py +108 -0
- cqfantasy/fireplace/Fireplace.py +175 -0
- cqfantasy/fireplace/FireplaceTiled.py +30 -0
- cqfantasy/fireplace/Hearth.py +71 -0
- cqfantasy/fireplace/HearthTiled.py +111 -0
- cqfantasy/fireplace/HearthTiledTwo.py +126 -0
- cqfantasy/fireplace/__init__.py +10 -0
- cqfantasy/house/Body.py +73 -0
- cqfantasy/house/BodyGreebled.py +257 -0
- cqfantasy/house/House.py +444 -0
- cqfantasy/house/PyramidRoof.py +150 -0
- cqfantasy/house/PyramidRoofShingle.py +94 -0
- cqfantasy/house/Roof.py +171 -0
- cqfantasy/house/ShingleRoof.py +93 -0
- cqfantasy/house/SnowyRoof.py +159 -0
- cqfantasy/house/StuccoBrickBody.py +153 -0
- cqfantasy/house/TileGenerator.py +99 -0
- cqfantasy/house/TudorBody.py +145 -0
- cqfantasy/house/TudorSplitBody.py +270 -0
- cqfantasy/house/__init__.py +12 -0
- cqfantasy/house_wall/LogWall.py +99 -0
- cqfantasy/house_wall/RubbleWall.py +118 -0
- cqfantasy/house_wall/WallSplit.py +83 -0
- cqfantasy/house_wall/WallStuccoBrick.py +102 -0
- cqfantasy/house_wall/WallTudor.py +110 -0
- cqfantasy/house_wall/WallTudorPaneling.py +181 -0
- cqfantasy/house_wall/__init__.py +7 -0
- cqfantasy/house_wall/tudor_wall.py +162 -0
- cqfantasy/tower/BaseSection.py +291 -0
- cqfantasy/tower/FrameWindow.py +68 -0
- cqfantasy/tower/LatticeWindow.py +85 -0
- cqfantasy/tower/RoundBlockAltGenerator.py +111 -0
- cqfantasy/tower/RoundBlockGenerator.py +191 -0
- cqfantasy/tower/RoundBlockUnevenGenerator.py +79 -0
- cqfantasy/tower/RoundBlockUnevenStuccoGenerator.py +190 -0
- cqfantasy/tower/TileGenerator.py +101 -0
- cqfantasy/tower/Tower.py +67 -0
- cqfantasy/tower/TowerBase.py +149 -0
- cqfantasy/tower/TowerDoor.py +116 -0
- cqfantasy/tower/TowerMid.py +133 -0
- cqfantasy/tower/TowerTop.py +186 -0
- cqfantasy/tower/TowerWindow.py +125 -0
- cqfantasy/tower/__init__.py +19 -0
- cqfantasy/tower/cut_cylinder.py +29 -0
- cqfantasy/tower/magnets.py +28 -0
- cqfantasy/wall/TileGenerator.py +96 -0
- cqfantasy/wall/__init__.py +1 -0
- cqfantasy/watchtower/TowerBase.py +46 -0
- cqfantasy/watchtower/TowerBody.py +46 -0
- cqfantasy/watchtower/TowerBodyreebled.py +219 -0
- cqfantasy/watchtower/TowerDoor.py +42 -0
- cqfantasy/watchtower/TowerTop.py +46 -0
- cqfantasy/watchtower/TowerTopGreebled.py +134 -0
- cqfantasy/watchtower/WatchTower.py +80 -0
- cqfantasy/watchtower/__init__.py +7 -0
- cqfantasy/window/CasementWindow.py +108 -0
- cqfantasy/window/__init__.py +1 -0
- cqfantasy-2.3.0.dist-info/METADATA +31 -0
- cqfantasy-2.3.0.dist-info/RECORD +83 -0
- cqfantasy-2.3.0.dist-info/WHEEL +5 -0
- cqfantasy-2.3.0.dist-info/licenses/LICENSE +201 -0
- cqfantasy-2.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Copyright 2025 James Adams
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import math
|
|
16
|
+
import cadquery as cq
|
|
17
|
+
from cadqueryhelper import Base
|
|
18
|
+
from . import arch
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BasicArch(Base):
|
|
22
|
+
def __init__(self):
|
|
23
|
+
super().__init__()
|
|
24
|
+
|
|
25
|
+
# parameters
|
|
26
|
+
self.length:float = 30
|
|
27
|
+
self.width:float = 5
|
|
28
|
+
self.height:float = 75
|
|
29
|
+
self.outside_margin:float = 10
|
|
30
|
+
self.inside_margin:float = 5
|
|
31
|
+
|
|
32
|
+
# shapes
|
|
33
|
+
self.outline:cq.Workplane|None = None
|
|
34
|
+
self.outside_outline:cq.Workplane|None = None
|
|
35
|
+
self.inside_outline:cq.Workplane|None = None
|
|
36
|
+
self.column_outline:cq.Workplane|None = None
|
|
37
|
+
|
|
38
|
+
def calculate_column_height(self) -> float:
|
|
39
|
+
return (self.height)-self.length/2
|
|
40
|
+
|
|
41
|
+
def calculate_perimeter(self) -> float:
|
|
42
|
+
perimeter = 2*math.pi*self.length/2
|
|
43
|
+
return perimeter
|
|
44
|
+
|
|
45
|
+
def calculate_inside_perimeter(self) -> float:
|
|
46
|
+
perimeter = 2*math.pi*(self.length-self.inside_margin*2)/2
|
|
47
|
+
return perimeter
|
|
48
|
+
|
|
49
|
+
def calculate_outside_perimeter(self) -> float:
|
|
50
|
+
perimeter = 2*math.pi*(self.length+self.outside_margin*2)/2
|
|
51
|
+
return perimeter
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def make_outline(self):
|
|
55
|
+
self.outline = arch(
|
|
56
|
+
self.length,
|
|
57
|
+
self.width,
|
|
58
|
+
self.height
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def make_outside_outline(self):
|
|
62
|
+
self.outside_outline = arch(
|
|
63
|
+
self.length+self.outside_margin*2,
|
|
64
|
+
self.width,
|
|
65
|
+
self.height+self.outside_margin
|
|
66
|
+
).translate((0,0,self.outside_margin/2))
|
|
67
|
+
|
|
68
|
+
def make_inside_outline(self):
|
|
69
|
+
self.inside_outline = arch(
|
|
70
|
+
self.length-self.inside_margin*2,
|
|
71
|
+
self.width,
|
|
72
|
+
self.height-self.inside_margin
|
|
73
|
+
).translate((0,0,-self.inside_margin/2))
|
|
74
|
+
|
|
75
|
+
def make_column_outline(self):
|
|
76
|
+
height = self.calculate_column_height()
|
|
77
|
+
outline = (
|
|
78
|
+
cq.Workplane("XY")
|
|
79
|
+
.box(
|
|
80
|
+
self.length+self.outside_margin*2,
|
|
81
|
+
self.width,
|
|
82
|
+
height
|
|
83
|
+
)
|
|
84
|
+
.translate((0,0,-self.height/2+height/2))
|
|
85
|
+
)
|
|
86
|
+
self.column_outline = outline
|
|
87
|
+
|
|
88
|
+
def make(self, parent=None):
|
|
89
|
+
super().make(parent)
|
|
90
|
+
self.make_outline()
|
|
91
|
+
self.make_outside_outline()
|
|
92
|
+
self.make_inside_outline()
|
|
93
|
+
self.make_column_outline()
|
|
94
|
+
|
|
95
|
+
def build(self) -> cq.Workplane:
|
|
96
|
+
super().build()
|
|
97
|
+
scene = (
|
|
98
|
+
cq.Workplane("XY")
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if self.outline:
|
|
102
|
+
scene = scene.add(self.outline)
|
|
103
|
+
|
|
104
|
+
if self.outside_outline:
|
|
105
|
+
scene = scene.add(self.outside_outline)
|
|
106
|
+
|
|
107
|
+
if self.inside_outline:
|
|
108
|
+
scene = scene.cut(self.inside_outline)
|
|
109
|
+
|
|
110
|
+
return scene
|
|
111
|
+
|
|
112
|
+
def build_outline(self) -> cq.Workplane:
|
|
113
|
+
scene = cq.Workplane("XY")
|
|
114
|
+
|
|
115
|
+
if self.outline:
|
|
116
|
+
scene = scene.union(self.outline)
|
|
117
|
+
return scene
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Copyright 2025 James Adams
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import cadquery as cq
|
|
16
|
+
from . import BasicArch, arch
|
|
17
|
+
|
|
18
|
+
class StoneArch(BasicArch):
|
|
19
|
+
def __init__(self):
|
|
20
|
+
super().__init__()
|
|
21
|
+
|
|
22
|
+
# parameters
|
|
23
|
+
self.stone_count:int = 8
|
|
24
|
+
self.stone_arch_count:int = 4
|
|
25
|
+
|
|
26
|
+
self.stone_margin:float = .5
|
|
27
|
+
self.width_margin:float = .5
|
|
28
|
+
self.stone_modulus:int = 2
|
|
29
|
+
self.outside_stone_position:int = 0
|
|
30
|
+
self.stone_arch_modulus:int = 2
|
|
31
|
+
self.outside_stone_arch_position:int = 1
|
|
32
|
+
|
|
33
|
+
# shapes
|
|
34
|
+
self.inside_stone:cq.Workplane|None = None
|
|
35
|
+
self.outside_stone:cq.Workplane|None = None
|
|
36
|
+
self.column_stones:cq.Workplane|None = None
|
|
37
|
+
|
|
38
|
+
self.inside_arch_stone:cq.Workplane|None = None
|
|
39
|
+
self.outside_arch_stone:cq.Workplane|None = None
|
|
40
|
+
self.arch_stones:cq.Workplane|None = None
|
|
41
|
+
|
|
42
|
+
self.margin_outline:cq.Workplane|None = None
|
|
43
|
+
self.outside_margin_outline:cq.Workplane|None = None
|
|
44
|
+
self.inside_margin_outline:cq.Workplane|None = None
|
|
45
|
+
|
|
46
|
+
def calculate_stone_height(self) -> float:
|
|
47
|
+
column_height = self.calculate_column_height()
|
|
48
|
+
stone_height = column_height / self.stone_count
|
|
49
|
+
return stone_height
|
|
50
|
+
|
|
51
|
+
def calculate_stone_margin_height(self) -> float:
|
|
52
|
+
stone_height = self.calculate_stone_height()
|
|
53
|
+
return stone_height - self.stone_margin
|
|
54
|
+
|
|
55
|
+
def calculate_arch_stone_height(self) -> float:
|
|
56
|
+
perimeter = self.calculate_perimeter() / 2
|
|
57
|
+
height = perimeter / self.stone_arch_count
|
|
58
|
+
return height
|
|
59
|
+
|
|
60
|
+
def calculate_arch_stone_margin_height(self) -> float:
|
|
61
|
+
height = self.calculate_arch_stone_height()
|
|
62
|
+
return height - self.stone_margin
|
|
63
|
+
|
|
64
|
+
def calculate_inside_arch_stone_height(self) -> float:
|
|
65
|
+
perimeter = self.calculate_inside_perimeter() / 2
|
|
66
|
+
height = perimeter / self.stone_arch_count
|
|
67
|
+
return height
|
|
68
|
+
|
|
69
|
+
def calculate_inside_arch_stone_margin_height(self) -> float:
|
|
70
|
+
height = self.calculate_inside_arch_stone_height()
|
|
71
|
+
return height - self.stone_margin
|
|
72
|
+
|
|
73
|
+
def calculate_outside_arch_stone_height(self) -> float:
|
|
74
|
+
perimeter = self.calculate_outside_perimeter() / 2
|
|
75
|
+
height = perimeter / self.stone_arch_count
|
|
76
|
+
return height
|
|
77
|
+
|
|
78
|
+
def calculate_outside_arch_stone_margin_height(self) -> float:
|
|
79
|
+
height = self.calculate_outside_arch_stone_height()
|
|
80
|
+
return height - self.stone_margin
|
|
81
|
+
|
|
82
|
+
def make_inside_stone(self):
|
|
83
|
+
stone_height = self.calculate_stone_margin_height()
|
|
84
|
+
self.inside_stone = cq.Workplane("XY").box(
|
|
85
|
+
self.inside_margin,
|
|
86
|
+
self.width,
|
|
87
|
+
stone_height
|
|
88
|
+
).rotate((1,0,0),(0,0,0),90)
|
|
89
|
+
|
|
90
|
+
def make_outside_stone(self):
|
|
91
|
+
stone_height = self.calculate_stone_margin_height()
|
|
92
|
+
length = self.inside_margin+self.outside_margin
|
|
93
|
+
self.outside_stone = cq.Workplane("XY").box(
|
|
94
|
+
length,
|
|
95
|
+
self.width,
|
|
96
|
+
stone_height
|
|
97
|
+
).translate((-length/2+self.inside_margin/2,0,0)).rotate((1,0,0),(0,0,0),90)
|
|
98
|
+
|
|
99
|
+
def make_column_stones(self):
|
|
100
|
+
def add_stone():
|
|
101
|
+
count = 0
|
|
102
|
+
def add_stone_count(loc:cq.Location) -> cq.Shape:
|
|
103
|
+
nonlocal count
|
|
104
|
+
stone = self.inside_stone
|
|
105
|
+
|
|
106
|
+
if count % self.stone_modulus == self.outside_stone_position and self.outside_stone:
|
|
107
|
+
stone = (
|
|
108
|
+
self.outside_stone
|
|
109
|
+
.translate((
|
|
110
|
+
0,
|
|
111
|
+
0,
|
|
112
|
+
0)
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
count += 1
|
|
116
|
+
#log(f'test {count}')
|
|
117
|
+
return stone.val().located(loc) #type:ignore
|
|
118
|
+
return add_stone_count
|
|
119
|
+
|
|
120
|
+
stone_height = self.calculate_stone_height()
|
|
121
|
+
|
|
122
|
+
stones = (
|
|
123
|
+
cq.Workplane("XY")
|
|
124
|
+
.rarray(
|
|
125
|
+
xSpacing = stone_height,
|
|
126
|
+
ySpacing = stone_height,
|
|
127
|
+
xCount = 1,
|
|
128
|
+
yCount= self.stone_count,
|
|
129
|
+
center = True)
|
|
130
|
+
.eachpoint(add_stone())
|
|
131
|
+
).rotate((1,0,0),(0,0,0),90)
|
|
132
|
+
|
|
133
|
+
self.column_stones = stones
|
|
134
|
+
|
|
135
|
+
def make_margin_outline(self):
|
|
136
|
+
self.margin_outline = arch(
|
|
137
|
+
self.length-self.width_margin,
|
|
138
|
+
self.width-self.width_margin*2,
|
|
139
|
+
self.height
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def make_outside_margin_outline(self):
|
|
143
|
+
self.outside_margin_outline = arch(
|
|
144
|
+
self.length+self.outside_margin*2,
|
|
145
|
+
self.width-self.width_margin*2,
|
|
146
|
+
self.height+self.outside_margin
|
|
147
|
+
).translate((0,0,self.outside_margin/2))
|
|
148
|
+
|
|
149
|
+
def make_inside_margin_outline(self):
|
|
150
|
+
self.inside_margin_outline = arch(
|
|
151
|
+
self.length-self.inside_margin*2+self.width_margin,
|
|
152
|
+
self.width-self.width_margin*2,
|
|
153
|
+
self.height-self.inside_margin
|
|
154
|
+
).translate((0,0,-self.inside_margin/2))
|
|
155
|
+
|
|
156
|
+
def make_inside_arch_stone(self):
|
|
157
|
+
height = self.calculate_arch_stone_margin_height()
|
|
158
|
+
inside_height = self.calculate_inside_arch_stone_margin_height()
|
|
159
|
+
|
|
160
|
+
pts = [
|
|
161
|
+
(0,0),
|
|
162
|
+
(0,height),
|
|
163
|
+
(self.inside_margin,height-(height-inside_height)/2),
|
|
164
|
+
(self.inside_margin,(height-inside_height)/2)
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
stone = (
|
|
168
|
+
cq.Workplane("XZ")
|
|
169
|
+
.center(-self.inside_margin/2,-height/2)
|
|
170
|
+
.polyline(pts)
|
|
171
|
+
.close()
|
|
172
|
+
.extrude(self.width)
|
|
173
|
+
.translate((-self.length/2+self.inside_margin/2,self.width/2,0))
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
self.inside_arch_stone = stone
|
|
177
|
+
|
|
178
|
+
def make_outside_arch_stone(self):
|
|
179
|
+
length = self.inside_margin+self.outside_margin
|
|
180
|
+
height = self.calculate_outside_arch_stone_margin_height()
|
|
181
|
+
inside_height = self.calculate_inside_arch_stone_margin_height()
|
|
182
|
+
inside_length = self.length-self.inside_margin*2
|
|
183
|
+
|
|
184
|
+
pts = [
|
|
185
|
+
(0,0),
|
|
186
|
+
(0,height),
|
|
187
|
+
(length,height-(height-inside_height)/2),
|
|
188
|
+
(length,(height-inside_height)/2)
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
stone = (
|
|
192
|
+
cq.Workplane("XZ")
|
|
193
|
+
.center(-length,-height/2)
|
|
194
|
+
.polyline(pts)
|
|
195
|
+
.close()
|
|
196
|
+
.extrude(self.width)
|
|
197
|
+
.translate((-inside_length/2,self.width/2,0))
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
self.outside_arch_stone = stone
|
|
201
|
+
|
|
202
|
+
def make_arch_stones(self):
|
|
203
|
+
rotate_degrees = 180 / self.stone_arch_count
|
|
204
|
+
|
|
205
|
+
arch_stones = cq.Workplane("XY")
|
|
206
|
+
for i in range(self.stone_arch_count+1):
|
|
207
|
+
stone = cq.Workplane("XY")
|
|
208
|
+
|
|
209
|
+
if self.inside_arch_stone:
|
|
210
|
+
stone = self.inside_arch_stone
|
|
211
|
+
|
|
212
|
+
if i % self.stone_arch_modulus == self.outside_stone_arch_position:
|
|
213
|
+
stone = self.outside_arch_stone
|
|
214
|
+
|
|
215
|
+
arch_stones.add(stone.rotate((0,1,0),(0,0,0),-rotate_degrees*i)) #type:ignore
|
|
216
|
+
|
|
217
|
+
self.arch_stones = arch_stones
|
|
218
|
+
|
|
219
|
+
def make(self, parent=None):
|
|
220
|
+
super().make(parent)
|
|
221
|
+
self.make_inside_stone()
|
|
222
|
+
self.make_outside_stone()
|
|
223
|
+
self.make_column_stones()
|
|
224
|
+
|
|
225
|
+
self.make_margin_outline()
|
|
226
|
+
self.make_outside_margin_outline()
|
|
227
|
+
self.make_inside_margin_outline()
|
|
228
|
+
|
|
229
|
+
self.make_inside_arch_stone()
|
|
230
|
+
self.make_outside_arch_stone()
|
|
231
|
+
self.make_arch_stones()
|
|
232
|
+
|
|
233
|
+
def build(self) -> cq.Workplane:
|
|
234
|
+
super().build()
|
|
235
|
+
column_height = self.calculate_column_height()
|
|
236
|
+
|
|
237
|
+
scene = (
|
|
238
|
+
cq.Workplane("XY")
|
|
239
|
+
#.add(self.outside_margin_outline)
|
|
240
|
+
#.add(self.inside_stone)
|
|
241
|
+
#.add(self.outside_stone)
|
|
242
|
+
#.add(self.inside_arch_stone)
|
|
243
|
+
#.add(self.outside_arch_stone)
|
|
244
|
+
#.add(self.column_outline)
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
if self.margin_outline:
|
|
248
|
+
scene = scene.add(self.margin_outline)
|
|
249
|
+
|
|
250
|
+
if self.inside_margin_outline:
|
|
251
|
+
scene = scene.cut(self.inside_margin_outline)
|
|
252
|
+
|
|
253
|
+
if self.column_stones:
|
|
254
|
+
scene = (
|
|
255
|
+
scene
|
|
256
|
+
.add(self.column_stones.translate((-self.length/2+self.inside_margin/2,0,-self.height/2+column_height/2)))
|
|
257
|
+
.add(self.column_stones.translate((-self.length/2+self.inside_margin/2,0,-self.height/2+column_height/2)).rotate((0,0,1),(0,0,0),180))
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
if self.arch_stones and self.column_outline:
|
|
261
|
+
arch_stones = (
|
|
262
|
+
self.arch_stones.translate((0,0,self.height/2-self.length/2))
|
|
263
|
+
.cut(self.column_outline)
|
|
264
|
+
)
|
|
265
|
+
scene = scene.add(arch_stones)
|
|
266
|
+
|
|
267
|
+
return scene
|
cqfantasy/arch/arch.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Copyright 2025 James Adams
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import cadquery as cq
|
|
16
|
+
|
|
17
|
+
def arch(
|
|
18
|
+
length:float = 30,
|
|
19
|
+
width:float = 5,
|
|
20
|
+
height:float = 75
|
|
21
|
+
) -> cq.Workplane:
|
|
22
|
+
if length > height:
|
|
23
|
+
raise Exception(f'{length=} is greater than {height=}')
|
|
24
|
+
cylinder = cq.Workplane("XZ").cylinder(width, length/2)
|
|
25
|
+
base = cq.Workplane("XY").box(length, width, height-length/2)
|
|
26
|
+
|
|
27
|
+
combined_arch = (
|
|
28
|
+
base
|
|
29
|
+
.union(cylinder.translate((0,0,height/2-length/4)))
|
|
30
|
+
.translate((0,0,-length/4))
|
|
31
|
+
)
|
|
32
|
+
return combined_arch
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import cadquery as cq
|
|
2
|
+
from cadqueryhelper import Base
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
class AshlarCorner(Base):
|
|
6
|
+
def __init__(self):
|
|
7
|
+
super().__init__()
|
|
8
|
+
#parameter
|
|
9
|
+
self.length:float = 30
|
|
10
|
+
self.width:float = 30
|
|
11
|
+
self.height:float = 75
|
|
12
|
+
self.stone_height = 5
|
|
13
|
+
self.chamfer:float = 1
|
|
14
|
+
self.corner_cut_length:float|None = 3
|
|
15
|
+
self.corner_cut_width:float|None = 3
|
|
16
|
+
|
|
17
|
+
#shapes
|
|
18
|
+
self.outline:cq.Workplane|None = None
|
|
19
|
+
self.small_stone = None
|
|
20
|
+
self.large_stone = None
|
|
21
|
+
self.stones = None
|
|
22
|
+
self.mirror_stones = None
|
|
23
|
+
self.corner_cut = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def make_outline(self):
|
|
27
|
+
outline = cq.Workplane("XY").box(
|
|
28
|
+
self.length,
|
|
29
|
+
self.width,
|
|
30
|
+
self.height
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
self.outline = outline
|
|
34
|
+
|
|
35
|
+
def calculate_stone_count(self):
|
|
36
|
+
return math.floor(self.height / self.stone_height)
|
|
37
|
+
|
|
38
|
+
def make_small_stone(self):
|
|
39
|
+
length = self.length / 2
|
|
40
|
+
width = self.width / 2
|
|
41
|
+
height = self.stone_height
|
|
42
|
+
small_stone = (
|
|
43
|
+
cq.Workplane("XY")
|
|
44
|
+
.box(length,width,height)
|
|
45
|
+
.translate((length/2,width/2,0))
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if self.chamfer:
|
|
49
|
+
small_stone = small_stone.chamfer(self.chamfer)
|
|
50
|
+
|
|
51
|
+
self.small_stone = small_stone
|
|
52
|
+
|
|
53
|
+
def make_large_stone(self):
|
|
54
|
+
length = self.length
|
|
55
|
+
width = self.width
|
|
56
|
+
height = self.stone_height
|
|
57
|
+
large_stone = cq.Workplane("XY").box(length,width,height)
|
|
58
|
+
|
|
59
|
+
if self.chamfer:
|
|
60
|
+
large_stone = large_stone.chamfer(self.chamfer)
|
|
61
|
+
|
|
62
|
+
self.large_stone = large_stone
|
|
63
|
+
|
|
64
|
+
def make_corner_cut(self):
|
|
65
|
+
# cut stone
|
|
66
|
+
length = self.length / 2
|
|
67
|
+
width = self.width / 2
|
|
68
|
+
|
|
69
|
+
if self.corner_cut_length:
|
|
70
|
+
length = self.length - self.corner_cut_length
|
|
71
|
+
|
|
72
|
+
if self.corner_cut_width:
|
|
73
|
+
width = self.width - self.corner_cut_width
|
|
74
|
+
|
|
75
|
+
height = self.height
|
|
76
|
+
x_translate = self.length/2 - length/2
|
|
77
|
+
y_translate = self.width/2 - width/2
|
|
78
|
+
|
|
79
|
+
corner_cut = (
|
|
80
|
+
cq.Workplane("XY")
|
|
81
|
+
.box(length,width,height)
|
|
82
|
+
.translate((-x_translate,-y_translate,self.height/2))
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
self.corner_cut = corner_cut
|
|
86
|
+
|
|
87
|
+
def make_stones(self):
|
|
88
|
+
stones = cq.Workplane("XY")
|
|
89
|
+
stone_count = self.calculate_stone_count()
|
|
90
|
+
|
|
91
|
+
for i in range(stone_count):
|
|
92
|
+
if i % 2 == 0:
|
|
93
|
+
stones = stones.add(self.large_stone.translate((0,0,i * self.stone_height)))
|
|
94
|
+
else:
|
|
95
|
+
stones = stones.add(self.small_stone.translate((0,0,i * self.stone_height)))
|
|
96
|
+
|
|
97
|
+
self.stones = stones
|
|
98
|
+
|
|
99
|
+
def make_mirror_stones(self):
|
|
100
|
+
stones = cq.Workplane("XY")
|
|
101
|
+
stone_count = self.calculate_stone_count()
|
|
102
|
+
small_length = self.length / 2
|
|
103
|
+
|
|
104
|
+
for i in range(stone_count):
|
|
105
|
+
if i % 2 == 0:
|
|
106
|
+
stones = stones.add(self.large_stone.translate((0,0,i * self.stone_height)))
|
|
107
|
+
else:
|
|
108
|
+
stones = stones.add(self.small_stone.translate((-small_length,0,i * self.stone_height)))
|
|
109
|
+
|
|
110
|
+
self.mirror_stones = stones
|
|
111
|
+
|
|
112
|
+
def make(self):
|
|
113
|
+
super().make()
|
|
114
|
+
self.make_outline()
|
|
115
|
+
self.make_small_stone()
|
|
116
|
+
self.make_large_stone()
|
|
117
|
+
self.make_stones()
|
|
118
|
+
self.make_mirror_stones()
|
|
119
|
+
self.make_corner_cut()
|
|
120
|
+
|
|
121
|
+
def build_outline(self)->cq.Workplane:
|
|
122
|
+
super().build()
|
|
123
|
+
|
|
124
|
+
part = cq.Workplane("XY")
|
|
125
|
+
|
|
126
|
+
if self.outline:
|
|
127
|
+
part = part.add(self.outline.translate((0,0,self.height/2)))
|
|
128
|
+
|
|
129
|
+
return part
|
|
130
|
+
|
|
131
|
+
def build(self)->cq.Workplane:
|
|
132
|
+
super().build()
|
|
133
|
+
|
|
134
|
+
part = cq.Workplane("XY")
|
|
135
|
+
|
|
136
|
+
if self.stones:
|
|
137
|
+
part = part.add(self.stones.translate((0,0,self.stone_height/2)))
|
|
138
|
+
|
|
139
|
+
if self.corner_cut:
|
|
140
|
+
part = part.cut(self.corner_cut)
|
|
141
|
+
|
|
142
|
+
return part.rotate((0,0,1),(0,0,0),180)
|
|
143
|
+
|
|
144
|
+
def build_mirror(self)->cq.Workplane:
|
|
145
|
+
super().build()
|
|
146
|
+
|
|
147
|
+
part = cq.Workplane("XY")
|
|
148
|
+
|
|
149
|
+
if self.stones:
|
|
150
|
+
part = part.add(self.mirror_stones.translate((0,0,self.stone_height/2)))
|
|
151
|
+
|
|
152
|
+
if self.corner_cut:
|
|
153
|
+
part = part.cut(self.corner_cut.translate((self.corner_cut_length,0,0)))
|
|
154
|
+
|
|
155
|
+
return part.rotate((0,0,1),(0,0,0),180)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .AshlarCorner import AshlarCorner
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Copyright 2025 James Adams
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import cadquery as cq
|
|
16
|
+
from cadqueryhelper import Base
|
|
17
|
+
from ..arch import StoneArch
|
|
18
|
+
from . import VDoor
|
|
19
|
+
|
|
20
|
+
class ArchDoor(Base):
|
|
21
|
+
def __init__(self):
|
|
22
|
+
super().__init__()
|
|
23
|
+
|
|
24
|
+
self.length:float = 50
|
|
25
|
+
self.width:float = 7
|
|
26
|
+
self.height:float = 75
|
|
27
|
+
self.door_inset:float = 2
|
|
28
|
+
|
|
29
|
+
#blueprints
|
|
30
|
+
self.bp_arch = StoneArch()
|
|
31
|
+
self.bp_arch.outside_margin = 5
|
|
32
|
+
self.bp_arch.outside_stone_position = 0
|
|
33
|
+
self.bp_arch.stone_arch_count = 6
|
|
34
|
+
self.bp_arch.stone_arch_modulus = 2
|
|
35
|
+
|
|
36
|
+
self.bp_door = VDoor()
|
|
37
|
+
|
|
38
|
+
def make_arch(self):
|
|
39
|
+
if self.bp_arch:
|
|
40
|
+
self.bp_arch.length = self.length
|
|
41
|
+
self.bp_arch.width = self.width
|
|
42
|
+
self.bp_arch.height = self.height
|
|
43
|
+
self.bp_arch.make()
|
|
44
|
+
|
|
45
|
+
def make_door(self):
|
|
46
|
+
if self.bp_door:
|
|
47
|
+
self.bp_door.length = self.length - self.bp_arch.inside_margin*2
|
|
48
|
+
self.bp_door.width = self.width - self.door_inset
|
|
49
|
+
self.bp_door.height = self.height - self.bp_arch.inside_margin
|
|
50
|
+
self.bp_door.make()
|
|
51
|
+
|
|
52
|
+
def make(self, parent=None):
|
|
53
|
+
super().make(parent)
|
|
54
|
+
self.make_arch()
|
|
55
|
+
self.make_door()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def build(self):
|
|
59
|
+
super().build()
|
|
60
|
+
scene = cq.Workplane("XY")
|
|
61
|
+
|
|
62
|
+
if self.bp_arch:
|
|
63
|
+
ex_arch = self.bp_arch.build()
|
|
64
|
+
scene = scene.add(ex_arch)
|
|
65
|
+
|
|
66
|
+
if self.bp_door:
|
|
67
|
+
ex_door = self.bp_door.build()
|
|
68
|
+
scene = scene.add(ex_door.translate((0,0,- self.bp_arch.inside_margin/2)))
|
|
69
|
+
|
|
70
|
+
return scene
|
|
71
|
+
|
|
72
|
+
def build_outline(self):
|
|
73
|
+
return self.bp_arch.build_outline()
|