-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathbody.py
642 lines (475 loc) · 26 KB
/
body.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# from ast import Param
import math
import sys
from solid import *
from solid.utils import *
import logging
from cell import Cell
from support import Support
from parameters import Parameters
class Body():
def __init__(self, parameters: Parameters = Parameters()):
self.parameters = parameters
self.logger = logging.getLogger().getChild(__name__)
self.x_build_size = self.parameters.x_build_size
self.y_build_size = self.parameters.y_build_size
self.top_margin = self.parameters.top_margin
self.bottom_margin = self.parameters.bottom_margin
self.left_margin = self.parameters.left_margin
self.right_margin = self.parameters.right_margin
self.case_height = self.parameters.case_height
self.case_wall_thickness = self.parameters.case_wall_thickness
self.plate_thickness = self.parameters.plate_thickness
self.plate_corner_radius = self.parameters.plate_corner_radius
self.plate_supports = self.parameters.plate_supports
self.support_bar_height = self.parameters.support_bar_height
self.support_bar_width = self.parameters.support_bar_width
# self.create_screw_holes = False
self.screw_count = self.parameters.screw_count
self.screw_diameter = self.parameters.screw_diameter
self.screw_edge_inset = self.parameters.screw_edge_inset
self.screw_edge_x_inset = self.parameters.screw_edge_x_inset
self.screw_edge_y_inset = self.parameters.screw_edge_y_inset
self.screw_hole_body_wall_width = self.parameters.screw_hole_body_wall_width
self.screw_hole_body_support_x_factor = self.parameters.screw_hole_body_support_x_factor
self.bottom_cover_thickness = self.parameters.bottom_cover_thickness
self.case_height_extra = self.parameters.case_height_extra_fill
self.min_x = self.parameters.min_x
self.max_x = self.parameters.max_x
self.min_y = self.parameters.min_y
self.max_y = self.parameters.max_y
self.real_max_x = self.parameters.real_max_x
self.real_max_y = self.parameters.real_max_y
self.real_case_width = self.parameters.real_case_width
self.real_case_height = self.parameters.real_case_height
# self.parameter_dict = parameter_dict
# if self.parameter_dict is not None:
# self.build_attr_from_dict(self.parameter_dict)
self.screw_hole_coordinates = []
self.screw_hole_info = {}
self.case_height_base_removed = self.parameters.case_height_base_removed
self.case_height_extra_fill = self.parameters.case_height_extra_fill
self.side_margin_diff = self.parameters.side_margin_diff
self.top_margin_diff = self.parameters.top_margin_diff
self.screw_tap_hole_diameter = self.parameters.screw_tap_hole_diameter
self.screw_hole_body_diameter = self.parameters.screw_hole_body_diameter
self.screw_hole_body_radius = self.parameters.screw_hole_body_radius
self.x_screw_width = self.parameters.x_screw_width
self.y_screw_width = self.parameters.y_screw_width
self.bottom_section_count = self.parameters.bottom_section_count
self.screw_hole_body_support_end_x = (self.case_height_extra_fill / self.screw_hole_body_support_x_factor) + self.screw_hole_body_radius
# Calculated attributes
# self.update_calculated_attributes()
# self.x_build_size = 200.0
# self.y_build_size = 200.0
# self.top_margin = 8.0
# self.bottom_margin = 8.0
# self.left_margin = 8.0
# self.right_margin = 8.0
# self.case_height = 10
# self.case_wall_thickness = 2.0
# self.plate_thickness = 1.511
# self.plate_corner_radius = 4
# self.plate_only = False
# self.plate_supports = False
# self.support_bar_height = 3.0
# self.support_bar_width = 1.0
# self.create_screw_holes = False
# self.screw_count = 4
# self.screw_diameter = 4
# self.screw_edge_inset = 8
# self.screw_hole_body_wall_width = 2
# self.screw_hole_body_support_x_factor = 4
# self.bottom_cover_thickness = 2.0
# self.case_height_extra = 30
# self.min_x = 0.0
# self.max_x = 0.0
# self.min_y = 0.0
# self.max_y = 0.0
# self.real_max_x = 0.0
# self.real_max_y = 0.0
# self.real_case_width = 0.0
# self.real_case_height = 0.0
# self.parameter_dict = parameter_dict
# if self.parameter_dict is not None:
# self.build_attr_from_dict(self.parameter_dict)
# self.screw_hole_coordinates = []
# self.screw_hole_info = {}
# # Calculated attributes
# self.update_calculated_attributes()
def update_calculated_attributes(self):
# Calculated attributes
self.case_height_base_removed = self.parameters.case_height_base_removed
self.case_height_extra_fill = self.parameters.case_height_extra_fill
self.side_margin_diff = self.parameters.side_margin_diff
self.top_margin_diff = self.parameters.top_margin_diff
self.screw_tap_hole_diameter = self.parameters.screw_tap_hole_diameter
self.screw_hole_body_diameter = self.parameters.screw_hole_body_diameter
self.screw_hole_body_radius = self.parameters.screw_hole_body_radius
self.x_screw_width = self.parameters.x_screw_width
self.y_screw_width = self.parameters.y_screw_width
self.bottom_section_count = self.parameters.bottom_section_count
self.screw_hole_body_support_end_x = self.parameters.screw_hole_body_support_end_x
# def set_dimensions(self, max_x, min_y, min_x, max_y):
# this_function_name = sys._getframe( ).f_code.co_name
# self.logger = self.logger.getChild(this_function_name)
# self.max_x = max_x
# self.max_x = max_x
# self.min_y = min_y
# self.max_y = max_y
# # self.logger.debug('min_x: %f, max_x: %f, max_y: %f, min_y: %f', self.min_x, self.max_x, self.max_y, self.min_y)
# # Get rhe calculated real max and y sizes of the board
# self.real_max_x = self.parameters.U(self.max_x)
# self.real_max_y = self.parameters.U(abs(self.min_y))
# self.real_case_width = self.real_max_x + self.left_margin + self.right_margin
# self.real_case_height = self.real_max_y + self.top_margin + self.bottom_margin
# self.logger.debug('real_max_x: %d, real_max_y: %s', self.real_max_x, self.real_max_y)
# self.update_calculated_attributes()
def build_attr_from_dict(self, parameter_dict):
for param in parameter_dict.keys():
value = parameter_dict[param]
setattr(self, param, value)
# if param == 'screw_count':
# self.logger.debug('%s: %s, self.screw_count: %s', str(param), str(value), str(self.screw_count))
def set_parameter_dict(self, parameter_dict):
self.parameter_dict = parameter_dict
self.build_attr_from_dict(self.parameter_dict)
self.update_calculated_attributes()
def plate(self, case_x, case_y, pre_minkowski_thickness, round_corner):
# Get absolute value of min_y to get real y value
max_y = abs(self.min_y)
# Create plate and round the corners using cylcinder that was passed in
plate_object = cube([case_x, case_y, pre_minkowski_thickness], center = True)
plate_object = minkowski() ( plate_object, round_corner )
# Move plate to be centered on the switches
# Offset the move to ensure margin differences are accounted for.
plate_object = right( (self.real_max_x / 2) + (self.side_margin_diff / 2) ) (
back( (self.real_max_y / 2) + (self.top_margin_diff / 2) ) (
plate_object
)
)
self.logger.debug('self.plate_supports: %s', str(self.plate_supports))
# screw_holes = self.screw_hole_objects()
# if screw_holes is not None:
# plate_object -= screw_holes
# If palte supprts should be added
if self.plate_supports == True:
# Get the ceiling values for the max x and y so thet we loop ove all spaces
max_x_ceil = math.ceil(self.max_x)
max_y_ceil = math.ceil(max_y)
self.logger.debug('range(max_x_ceil): %s, range(max_y_ceil): %s', str(range(max_x_ceil)), str(range(max_y_ceil)))
# Build full border to ensure outside edges are full suppport width
perimeter_x = self.real_max_x + self.support_bar_width
perimeter_y = self.real_max_y + self.support_bar_width
perimeter_height = self.support_bar_height + self.plate_thickness
perimeter = left(self.support_bar_width / 2) ( back(self.support_bar_width / 2) ( cube([perimeter_x, perimeter_y, perimeter_height]) ) )
perimeter_inner = cube([self.real_max_x, self.real_max_y, self.support_bar_height])
perimeter -= perimeter_inner
perimeter = down(self.support_bar_height + (self.plate_thickness / 2)) ( perimeter )
perimeter = back(self.real_max_y) ( perimeter )
plate_object += perimeter
# For each x in the ceiling of max_x
for x in range(max_x_ceil):
# Set support width
w = 1.0
# Find diff between farthest end of support and max x
max_x_diff = self.max_x - (x + w)
# If the support would go beyond the max x reduce the width to fit
if max_x_diff < 0:
# Reduce w to be remaining x value
w = self.max_x - x
# For each y in the ceiling of max_y
for y in range(max_y_ceil):
# self.logger.debug('x: %f, y: %f', x, y)
# Set support height
h = 1.0
# Find diff between top of support and max y
max_y_diff = max_y - (y + h)
# If the support would go beyond the max y reduce the heght to fit
if max_y_diff < 0:
# Reduce h to be remaining y value
h = max_y - y
# Get X and Y offset to move support to corect location
# x_offset = x - ((self.real_max_x / 2) + (self.side_margin_diff / 2)) / self.parameters.switch_spacing
# y_offset = -(y - ((self.real_max_y / 2) + (self.top_margin_diff / 2)) / self.parameters.switch_spacing)
x_offset = x
y_offset = -y
# Add support object to plate
plate_object += Support(x_offset, y_offset, w, h, self.plate_thickness, self.support_bar_height, self.support_bar_width, parameters = self.parameters).get_moved()
# eturn palte object
return plate_object
def case_body_block(self, case_x, case_y, round_corner):
# Create case wall part
case_block = cube([case_x, case_y, self.case_height_extra_fill], center = True)
# Round the corners of the case wall and
case_block = minkowski() (case_block, round_corner)
return case_block
def case_border(self, case_x, case_y, round_corner, square_corner):
# Create case wall part
case_wall = self.case_body_block(case_x, case_y, round_corner)
# Create inner area that will be removed from case wall
case_inner = cube([case_x - (self.case_wall_thickness * 2), case_y - (self.case_wall_thickness * 2), self.case_height_extra_fill * 2], center = True)
# Round the corners of the case wall and case inner
case_inner = minkowski() (case_inner, square_corner)
# Remove the innser empty space from the case wall
case_wall -= case_inner
# Move case wall to match origin of rest of keyboard
self.logger.debug('side_margin_diff: %s, top_margin_diff: %s', self.side_margin_diff, self.top_margin_diff)
case_wall = right((self.real_max_x / 2) + (self.side_margin_diff / 2)) ( back((self.real_max_y / 2) + (self.top_margin_diff / 2)) ( case_wall ) )
# Move case wall down to match with the top of the plate
case_wall = down(self.case_height_extra_fill / 2) ( case_wall )
# Return the case wall object
return case_wall
def case(self, body_block_only = False, plate_only = False):
# Get the margins for the plate without the ammount that the minkowski will add
pre_minkowski_x_margin = ((self.right_margin + self.left_margin) / 2 - self.plate_corner_radius)
pre_minkowski_y_margin = ((self.top_margin + self.bottom_margin) / 2 - self.plate_corner_radius)
# get the pre minkowski plate sizes
case_x = self.real_max_x + (pre_minkowski_x_margin * 2)
case_y = self.real_max_y + (pre_minkowski_y_margin * 2)
# Get the plate thickness before the minkowski
pre_minkowski_thickness = self.plate_thickness / 2
# Create cylinder to be used for rounding case and palte border
round_corner = cylinder(r = self.plate_corner_radius, h = pre_minkowski_thickness, center = True)
square_corner = cube([self.plate_corner_radius * 2, self.plate_corner_radius * 2, pre_minkowski_thickness], center = True)
# Create Plate object. Add it to function return case object
case_object = self.plate(case_x, case_y, pre_minkowski_thickness, round_corner)
# If not only making the plate add the case border to the case object
if plate_only == False:
case_object += self.case_border(case_x, case_y, round_corner, square_corner)
# move case_object to line up with board
case_object = case_object
if body_block_only == True:
case_object = self.case_body_block(case_x, case_y, round_corner)
case_object = right((self.real_max_x / 2) + (self.side_margin_diff / 2)) ( back((self.real_max_y / 2) + (self.top_margin_diff / 2)) ( case_object ) )
# Move case wall down to match with the top of the plate
case_object = down(self.case_height_extra_fill / 2) ( case_object )
return case_object
def screw_hole(self, tap = False):
try:
if tap == False:
radius = self.screw_diameter / 2
else:
radius = self.screw_tap_hole_diameter / 2
except:
return None
return cylinder(r = radius, h = self.case_height_extra_fill * 4, center = True)
def screw_hole_body_support(self, direction = 'right', screw_name = ''):
# self.logger.debug('screw_hole_body_support: screw_name: %s, direction: %s', screw_name, direction)
x_offset = self.screw_hole_body_radius
self.screw_hole_body_support_end_x = (self.case_height_extra_fill / self.screw_hole_body_support_x_factor) + x_offset
poly_points = [
[0, 0],
[0, self.case_height_extra_fill],
[x_offset, self.case_height_extra_fill],
# [(self.case_height_extra_fill / self.screw_hole_body_support_x_factor) + x_offset, 0]
[self.screw_hole_body_support_end_x, 0]
]
poly_path = [[0, 1, 2, 3]]
# self.logger.debug(poly_points)
hole_support = polygon(poly_points, poly_path)
hole_support = linear_extrude(height = 2, center = True) ( hole_support )
hole_support = rotate(90, [1, 0, 0]) ( hole_support )
self.screw_hole_info[screw_name]['support_directions'][direction] = self.screw_hole_body_support_end_x
if direction == 'right':
return hole_support
elif direction == 'left':
return rotate(180, [0, 0, 1]) ( hole_support )
elif direction == 'forward':
return rotate(90, [0, 0, 1]) ( hole_support )
elif direction == 'back':
return rotate(270, [0, 0, 1]) ( hole_support )
return hole_support
def screw_hole_body(self, left_support = False, right_support = False, forward_support = False, back_support = False, screw_name = ''):
hole_body = cylinder(r = self.screw_hole_body_radius, h = self.case_height_extra_fill)
if right_support == True:
hole_body += self.screw_hole_body_support('right', screw_name)
if left_support == True:
hole_body += self.screw_hole_body_support('left', screw_name)
if forward_support == True:
hole_body += self.screw_hole_body_support('forward', screw_name)
if back_support == True:
hole_body += self.screw_hole_body_support('back', screw_name)
return hole_body
def generate_screw_holes_coordinates(self):
# screw_hole_collection = union()
# corner_count = 4
# remaining_screws = 0
# screw_radius = self.screw_diameter / 2
# screw_set_min_x = 0
# screw_set_min_y = 0
# self.logger.debug('self.real_case_width: %f, self.screw_edge_inset: %f, self.screw_diameter: %f', self.real_case_width, self.screw_edge_inset, self.screw_diameter)
# self.logger.debug('self.real_case_width - ((self.screw_edge_inset * 2) + self.screw_diameter): %f', self.real_case_width - ((self.screw_edge_inset * 2) + self.screw_diameter))
x_screw_count = 0
y_screw_count = 0
if self.parameters.custom_screw_hole_coordinates is None:
# Bottom Left
self.screw_hole_coordinates.append([0, 0])
# Top Left
self.screw_hole_coordinates.append([0, self.y_screw_width])
# Top Right
self.screw_hole_coordinates.append([self.x_screw_width, self.y_screw_width])
# Bottom Right
self.screw_hole_coordinates.append([self.x_screw_width, 0])
remaining_screw_count = int((self.screw_count - 4) / 2)
# self.logger.debug('remaining_screw_count: %f', type(remaining_screw_count))
x_per_screw_spacing = 0
y_per_screw_spacing = 0
for i in range(remaining_screw_count):
x_per_screw_spacing = self.x_screw_width / (x_screw_count + 1)
y_per_screw_spacing = self.y_screw_width / (y_screw_count + 1)
if x_per_screw_spacing >= y_per_screw_spacing:
x_screw_count += 1
else:
y_screw_count += 1
# self.logger.debug('x_screw_count: %d, y_screw_count: %d', x_screw_count, y_screw_count)
x_per_screw_spacing = self.x_screw_width / (x_screw_count + 1)
y_per_screw_spacing = self.y_screw_width / (y_screw_count + 1)
self.logger.debug('x_per_screw_spacing: %f, y_per_screw_spacing: %f', x_per_screw_spacing, y_per_screw_spacing)
for i in range(x_screw_count):
# Top Screws
self.screw_hole_coordinates.append([(i + 1) * x_per_screw_spacing, self.y_screw_width])
# Bottom Screws
self.screw_hole_coordinates.append([(i + 1) * x_per_screw_spacing, 0])
for i in range(y_screw_count):
# Left Screws
self.screw_hole_coordinates.append([0, (i + 1) * y_per_screw_spacing])
# Right Screws
self.screw_hole_coordinates.append([self.x_screw_width, (i + 1) * y_per_screw_spacing])
# for coord in self.screw_hole_coordinates:
# self.logger.debug(coord)
elif self.parameters.custom_screw_hole_coordinates is not None:
custom_origin = [0, 0]
if self.parameters.custom_screw_hole_coordinates_origin is not None:
custom_origin = self.parameters.custom_screw_hole_coordinates_origin
for custom_coords in self.parameters.custom_screw_hole_coordinates:
custom_coords_adjusted = [abs(custom_coords[0] - custom_origin[0]), abs(custom_coords[1] - custom_origin[1])]
if len(custom_coords) == 3:
custom_coords_adjusted.append(custom_coords[2])
self.screw_hole_coordinates.append(custom_coords_adjusted)
for coords in self.screw_hole_coordinates:
coords_string = str(coords[0]) + ',' + str(coords[1])
# coords_string = ','.join(coords)
custom_support_direction = None
if len(coords) == 3:
custom_support_direction = coords[2]
self.screw_hole_info[coords_string] = {
'coordinates': [coords[0], coords[1]],
'x': coords[0] + self.screw_edge_x_inset,
'y': coords[1] + self.screw_edge_y_inset,
'support_directions': {
'right': False,
'left': False,
'forward': False,
'back': False
},
'custom_support_direction': custom_support_direction
}
def screw_hole_objects(self, tap = False):
if len(self.screw_hole_info.keys()) == 0:
self.generate_screw_holes_coordinates()
screw_hole_collection = union()
screw_hole_body_collection = union()
screw_hole_body_scaled_collection = union()
# corner_count = 4
# remaining_screws = 0
for coord_string in self.screw_hole_info.keys():
coord = self.screw_hole_info[coord_string]['coordinates']
x = coord[0]
y = coord[1]
custom_support_direction = self.screw_hole_info[coord_string]['custom_support_direction']
self.logger.debug('coord: %s, self.x_screw_width: %f, self.y_screw_width: %f', str(coord), self.x_screw_width, self.y_screw_width)
# Skip the center top screw hole if it is in the top center and the case has a cable hole
if self.parameters.cable_hole == True and y == self.y_screw_width and x == self.x_screw_width / 2:
# self.logger.debug('coord: %s', str(coord))
continue
hole = right(x) ( forward(y) ( self.screw_hole(tap = tap) ) )
screw_hole_collection += hole
right_support = True
left_support = True
forward_support = True
back_support = True
if custom_support_direction is None:
if x - self.screw_hole_body_support_end_x <= 0:
left_support = False
if x + self.screw_hole_body_support_end_x >= self.x_screw_width:
right_support = False
if y - self.screw_hole_body_support_end_x <= 0:
back_support = False
if y + self.screw_hole_body_support_end_x >= self.y_screw_width:
forward_support = False
if left_support == True and right_support == True:
forward_support = False
back_support = False
if forward_support == True and back_support == True:
right_support = False
left_support = False
else:
if custom_support_direction == 'h':
back_support = False
forward_support = False
if custom_support_direction == 'v':
left_support = False
right_support = False
# if x == 0 and y == 0:
# forward_support = True
# right_support = True
# elif x == 0 and y == self.y_screw_width:
# back_support = True
# right_support = True
# elif x == self.x_screw_width and y == self.y_screw_width:
# back_support = True
# left_support = True
# elif x == self.x_screw_width and y == 0:
# forward_support = True
# left_support = True
# elif y != self.y_screw_width and y != 0:
# forward_support = True
# back_support = True
# elif x != self.x_screw_width and x != 0:
# right_support = True
# left_support = True
hole_body = self.screw_hole_body(right_support = right_support, left_support = left_support, forward_support = forward_support, back_support = back_support, screw_name = coord_string)
scaled_hole_body = scale([1.1, 1.1, 1.0]) (hole_body)
hole_body = right(x) (
forward(y) (
hole_body
)
)
scaled_hole_body = right(x) (
forward(y) (
scaled_hole_body
)
)
screw_hole_body_collection += hole_body
screw_hole_body_scaled_collection += scaled_hole_body
x_offset = (-self.left_margin) + self.screw_edge_x_inset
# x_offset = (-self.left_margin)
y_offset = (self.real_max_y + self.bottom_margin) - self.screw_edge_y_inset
# self.logger.debug('-self.left_margin: %f, self.screw_edge_inset: %f, x_offset: %f', -self.left_margin, self.screw_edge_inset, x_offset)
screw_hole_collection = right(x_offset) (
back(y_offset) (
screw_hole_collection
)
)
screw_hole_body_collection = right(x_offset) (
back(y_offset) (
down(self.case_height_extra_fill + (self.plate_thickness / 2)) (
screw_hole_body_collection
)
)
)
screw_hole_body_scaled_collection = right(x_offset) (
back(y_offset) (
down(self.case_height_extra_fill + (self.plate_thickness / 2)) (
screw_hole_body_scaled_collection
)
)
)
return screw_hole_collection, screw_hole_body_collection, screw_hole_body_scaled_collection
def bottom_cover(self):
if self.bottom_cover_thickness > 0:
plate = down(self.bottom_cover_thickness) ( left(self.real_case_width / 2) ( back(self.real_case_height / 2) ( cube([self.real_case_width * 2, self.real_case_height * 2, self.bottom_cover_thickness]) ) ) )
else:
plate = union()
return plate