bluer-sbc 8.188.1__py3-none-any.whl → 9.168.1__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.
- bluer_sbc/.abcli/actions.sh +3 -0
- bluer_sbc/.abcli/alias.sh +2 -2
- bluer_sbc/.abcli/{blue_sbc.sh → bluer_sbc.sh} +2 -0
- bluer_sbc/.abcli/rpi.sh +1 -1
- bluer_sbc/.abcli/sbc/parts/adjust.sh +14 -0
- bluer_sbc/.abcli/sbc/parts/cd.sh +5 -0
- bluer_sbc/.abcli/sbc/parts.sh +15 -0
- bluer_sbc/.abcli/seed/rpi_64_bit.sh +36 -0
- bluer_sbc/.abcli/tests/help.sh +7 -3
- bluer_sbc/.abcli/tests/parts_adjust.sh +13 -0
- bluer_sbc/README/aliases.py +11 -0
- bluer_sbc/README/build.py +29 -0
- bluer_sbc/README/design.py +40 -0
- bluer_sbc/README/designs/__init__.py +26 -0
- bluer_sbc/README/designs/adapter_bus.py +59 -0
- bluer_sbc/README/designs/battery_bus.py +52 -0
- bluer_sbc/README/designs/bryce.py +28 -0
- bluer_sbc/README/designs/cheshmak.py +29 -0
- bluer_sbc/README/designs/nafha.py +57 -0
- bluer_sbc/README/designs/shelter.py +63 -0
- bluer_sbc/README/designs/swallow.py +46 -0
- bluer_sbc/README/designs/swallow_head.py +89 -0
- bluer_sbc/README/designs/template.py +38 -0
- bluer_sbc/{designs → README/designs}/ultrasonic_sensor_tester.py +11 -10
- bluer_sbc/README/parts.py +29 -0
- bluer_sbc/README/root.py +33 -0
- bluer_sbc/README/shortcuts.py +18 -0
- bluer_sbc/__init__.py +2 -2
- bluer_sbc/__main__.py +3 -2
- bluer_sbc/config.env +1 -1
- bluer_sbc/env.py +4 -0
- bluer_sbc/help/functions.py +2 -0
- bluer_sbc/help/parts.py +49 -0
- bluer_sbc/help/rpi.py +2 -1
- bluer_sbc/parts/__init__.py +0 -0
- bluer_sbc/parts/__main__.py +48 -0
- bluer_sbc/parts/classes/db.py +233 -0
- bluer_sbc/parts/classes/part.py +96 -0
- bluer_sbc/parts/consts.py +3 -0
- bluer_sbc/parts/db.py +619 -0
- bluer_sbc-9.168.1.dist-info/METADATA +73 -0
- {bluer_sbc-8.188.1.dist-info → bluer_sbc-9.168.1.dist-info}/RECORD +48 -24
- bluer_sbc/README.py +0 -75
- bluer_sbc/designs/bluer_swallow.py +0 -26
- bluer_sbc/designs/bryce.py +0 -25
- bluer_sbc/designs/cheshmak.py +0 -25
- bluer_sbc-8.188.1.dist-info/METADATA +0 -63
- /bluer_sbc/{designs → README}/__init__.py +0 -0
- /bluer_sbc/{designs → README/designs}/blue_bracket.py +0 -0
- /bluer_sbc/{designs → README/designs}/consts.py +0 -0
- {bluer_sbc-8.188.1.dist-info → bluer_sbc-9.168.1.dist-info}/WHEEL +0 -0
- {bluer_sbc-8.188.1.dist-info → bluer_sbc-9.168.1.dist-info}/licenses/LICENSE +0 -0
- {bluer_sbc-8.188.1.dist-info → bluer_sbc-9.168.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from bluer_objects import README
|
|
2
|
+
from bluer_objects.README.items import ImageItems
|
|
3
|
+
|
|
4
|
+
from bluer_sbc.README.designs.consts import assets2
|
|
5
|
+
from bluer_sbc.README.design import design_doc
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
image_template = assets2 + "swallow/design/head-v1/{}?raw=true"
|
|
9
|
+
|
|
10
|
+
marquee = README.Items(
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
"name": "swallow head",
|
|
14
|
+
"marquee": image_template.format("01.jpg"),
|
|
15
|
+
"url": "./bluer_sbc/docs/swallow-head.md",
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
items = ImageItems(
|
|
21
|
+
{image_template.format(f"{index+1:02}.jpg"): "" for index in range(6)}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
parts = {
|
|
25
|
+
"sd-card-32-gb": "",
|
|
26
|
+
"rpi": "",
|
|
27
|
+
"XL4015": "",
|
|
28
|
+
"470-mF": "",
|
|
29
|
+
"Polyfuse": "optional",
|
|
30
|
+
"TVS-diode": "",
|
|
31
|
+
"resistor": "7 x 330-470 Ω + N x 2.2 kΩ + N x 3.3 kΩ",
|
|
32
|
+
"LED": "green + red + yellow + 4 x blue",
|
|
33
|
+
"rpi-camera": "",
|
|
34
|
+
"PCB-single-14x9_5": "2 x",
|
|
35
|
+
"PCB-double-9x7": "2 x",
|
|
36
|
+
"pushbutton": "",
|
|
37
|
+
"ultrasonic-sensor": "4 x",
|
|
38
|
+
"connector": "1 female",
|
|
39
|
+
"nuts-bolts-spacers": " + ".join(
|
|
40
|
+
[
|
|
41
|
+
"M2: ({})".format(
|
|
42
|
+
" + ".join(
|
|
43
|
+
[
|
|
44
|
+
"2 x bolt",
|
|
45
|
+
"2 x 5 mm spacer",
|
|
46
|
+
"4 x nut",
|
|
47
|
+
]
|
|
48
|
+
)
|
|
49
|
+
),
|
|
50
|
+
"M2.5: ({})".format(
|
|
51
|
+
" + ".join(
|
|
52
|
+
[
|
|
53
|
+
"4 x bolt",
|
|
54
|
+
"8 x 10 mm spacer",
|
|
55
|
+
"4 x nut",
|
|
56
|
+
]
|
|
57
|
+
)
|
|
58
|
+
),
|
|
59
|
+
"M3: ({})".format(
|
|
60
|
+
" + ".join(
|
|
61
|
+
[
|
|
62
|
+
"1 x bolt",
|
|
63
|
+
"3 x 35 mm spacer",
|
|
64
|
+
"3 x 25 mm spacer",
|
|
65
|
+
"7 x 15 mm spacer",
|
|
66
|
+
"4 x 5 mm spacer",
|
|
67
|
+
"5 x nut",
|
|
68
|
+
]
|
|
69
|
+
)
|
|
70
|
+
),
|
|
71
|
+
]
|
|
72
|
+
),
|
|
73
|
+
"plexiglass": "14 cm x 9.5 cm",
|
|
74
|
+
"white-terminal": "2 x",
|
|
75
|
+
"dupont-cables": "1 x 30 cm + 1 x 10 cm",
|
|
76
|
+
"16-awg-wire": "40 cm x (red + black/blue)",
|
|
77
|
+
"solid-cable-1-15": "10 cm x (red + black/blue)",
|
|
78
|
+
"strong-thread": "1 m",
|
|
79
|
+
"pin-headers": "1 x (female, 2 x 40) -> 2 x 20 + 2 x (male, 1 x 40) -> 4 x 6 + 4 x 2 + 2 x 20",
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
docs = [
|
|
84
|
+
design_doc(
|
|
85
|
+
"swallow-head",
|
|
86
|
+
items,
|
|
87
|
+
parts,
|
|
88
|
+
)
|
|
89
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from bluer_objects import README
|
|
2
|
+
from bluer_objects.README.items import ImageItems
|
|
3
|
+
from bluer_objects.README.consts import assets_url
|
|
4
|
+
|
|
5
|
+
from bluer_sbc.README.design import design_doc
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
assets2_x = assets_url(
|
|
9
|
+
suffix="x",
|
|
10
|
+
volume=2,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
marquee = README.Items(
|
|
14
|
+
[
|
|
15
|
+
{
|
|
16
|
+
"name": "x",
|
|
17
|
+
"marquee": f"{assets2_x}/TBA.jpg",
|
|
18
|
+
"url": "./bluer_sbc/docs/x.md",
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
items = ImageItems(
|
|
24
|
+
{
|
|
25
|
+
f"{assets2_x}/TBA.jpg": "",
|
|
26
|
+
f"{assets2_x}/TBA.jpg": "",
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
parts = {}
|
|
31
|
+
|
|
32
|
+
docs = [
|
|
33
|
+
design_doc(
|
|
34
|
+
"template",
|
|
35
|
+
items,
|
|
36
|
+
parts,
|
|
37
|
+
)
|
|
38
|
+
]
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from bluer_objects import README
|
|
2
|
+
from bluer_objects.README.items import ImageItems
|
|
2
3
|
|
|
3
|
-
from bluer_sbc.designs.consts import assets2
|
|
4
|
+
from bluer_sbc.README.designs.consts import assets2
|
|
5
|
+
from bluer_sbc.README.design import design_doc
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
image_template = assets2 + "ultrasonic-sensor-tester/{}?raw=true"
|
|
@@ -15,12 +17,11 @@ marquee = README.Items(
|
|
|
15
17
|
]
|
|
16
18
|
)
|
|
17
19
|
|
|
18
|
-
items =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
20
|
+
items = ImageItems({image_template.format(f"{index:02}.jpg"): "" for index in range(6)})
|
|
21
|
+
|
|
22
|
+
docs = [
|
|
23
|
+
design_doc(
|
|
24
|
+
"ultrasonic-sensor-tester",
|
|
25
|
+
items,
|
|
26
|
+
)
|
|
27
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from bluer_objects import markdown
|
|
2
|
+
|
|
3
|
+
from bluer_sbc.parts.db import db_of_parts
|
|
4
|
+
|
|
5
|
+
docs = [
|
|
6
|
+
{
|
|
7
|
+
"path": "../docs/parts",
|
|
8
|
+
"macros": {
|
|
9
|
+
"parts_list:::": db_of_parts.README,
|
|
10
|
+
"parts_images:::": markdown.generate_table(
|
|
11
|
+
db_of_parts.as_images(
|
|
12
|
+
{part.name: "" for part in db_of_parts},
|
|
13
|
+
reference="../parts",
|
|
14
|
+
),
|
|
15
|
+
cols=10,
|
|
16
|
+
log=False,
|
|
17
|
+
),
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
] + [
|
|
21
|
+
{
|
|
22
|
+
"path": part.filename(create=True),
|
|
23
|
+
"macros": {
|
|
24
|
+
"info:::": part.README(db_of_parts.url_prefix),
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
for part_name, part in db_of_parts.items()
|
|
28
|
+
if part_name != "template"
|
|
29
|
+
]
|
bluer_sbc/README/root.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from bluer_sbc.README.designs.cheshmak import marquee as cheshmak_marquee
|
|
2
|
+
from bluer_sbc.README.designs.blue_bracket import items as blue_bracket_items
|
|
3
|
+
from bluer_sbc.README.designs.swallow import marquee as swallow_marquee
|
|
4
|
+
from bluer_sbc.README.designs.swallow_head import marquee as swallow_head_marquee
|
|
5
|
+
from bluer_sbc.README.designs.bryce import marquee as bryce_marquee
|
|
6
|
+
from bluer_sbc.README.designs.nafha import marquee as nafha_marquee
|
|
7
|
+
from bluer_sbc.README.designs.shelter import marquee as shelter_marquee
|
|
8
|
+
from bluer_sbc.README.designs.adapter_bus import marquee as adapter_bus_marquee
|
|
9
|
+
from bluer_sbc.README.designs.battery_bus import marquee as battery_bus_marquee
|
|
10
|
+
from bluer_sbc.README.designs.ultrasonic_sensor_tester import (
|
|
11
|
+
marquee as ultrasonic_sensor_tester_marquee,
|
|
12
|
+
)
|
|
13
|
+
from bluer_sbc.README.shortcuts import items as shortcuts_items
|
|
14
|
+
|
|
15
|
+
docs = [
|
|
16
|
+
{
|
|
17
|
+
"items": []
|
|
18
|
+
+ swallow_head_marquee
|
|
19
|
+
+ swallow_marquee
|
|
20
|
+
+ battery_bus_marquee
|
|
21
|
+
+ adapter_bus_marquee
|
|
22
|
+
+ ultrasonic_sensor_tester_marquee
|
|
23
|
+
+ bryce_marquee
|
|
24
|
+
+ cheshmak_marquee
|
|
25
|
+
+ nafha_marquee
|
|
26
|
+
+ shelter_marquee
|
|
27
|
+
+ blue_bracket_items,
|
|
28
|
+
"path": "../..",
|
|
29
|
+
"macros": {
|
|
30
|
+
"shortcuts:::": shortcuts_items,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from bluer_objects.README.items import Items
|
|
2
|
+
from bluer_objects import markdown
|
|
3
|
+
|
|
4
|
+
from bluer_sbc.parts.db import db_of_parts
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
items = markdown.generate_table(
|
|
8
|
+
Items(
|
|
9
|
+
[
|
|
10
|
+
{
|
|
11
|
+
"name": "parts",
|
|
12
|
+
"url": "./bluer_sbc/docs/parts",
|
|
13
|
+
"marquee": f"{db_of_parts.url_prefix}/grid.png",
|
|
14
|
+
},
|
|
15
|
+
]
|
|
16
|
+
),
|
|
17
|
+
log=False,
|
|
18
|
+
)
|
bluer_sbc/__init__.py
CHANGED
bluer_sbc/__main__.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from blueness.argparse.generic import main
|
|
2
2
|
|
|
3
|
-
from bluer_sbc import NAME, VERSION, DESCRIPTION, ICON
|
|
3
|
+
from bluer_sbc import NAME, VERSION, DESCRIPTION, ICON
|
|
4
|
+
from bluer_sbc.README.build import build
|
|
4
5
|
from bluer_sbc.logger import logger
|
|
5
6
|
|
|
6
7
|
main(
|
|
@@ -10,7 +11,7 @@ main(
|
|
|
10
11
|
VERSION=VERSION,
|
|
11
12
|
main_filename=__file__,
|
|
12
13
|
tasks={
|
|
13
|
-
"build_README": lambda _:
|
|
14
|
+
"build_README": lambda _: build(),
|
|
14
15
|
},
|
|
15
16
|
logger=logger,
|
|
16
17
|
)
|
bluer_sbc/config.env
CHANGED
bluer_sbc/env.py
CHANGED
|
@@ -38,3 +38,7 @@ BLUER_SBC_SESSION_TEMPERATURE_PERIOD = get_env(
|
|
|
38
38
|
BLUER_SBC_ENV = get_env("BLUER_SBC_ENV")
|
|
39
39
|
|
|
40
40
|
BLUER_SBC_SWALLOW_HAS_STEERING = get_env("BLUER_SBC_SWALLOW_HAS_STEERING", 0)
|
|
41
|
+
BLUER_SBC_SWALLOW_HAS_FULL_KEYBOARD = get_env("BLUER_SBC_SWALLOW_HAS_FULL_KEYBOARD", 0)
|
|
42
|
+
BLUER_SBC_SWALLOW_HAS_BPS = get_env("BLUER_SBC_SWALLOW_HAS_BPS", 0)
|
|
43
|
+
|
|
44
|
+
BLUER_SBC_BPS_ANCHORED_AT = get_env("BLUER_SBC_BPS_ANCHORED_AT", "")
|
bluer_sbc/help/functions.py
CHANGED
|
@@ -10,6 +10,7 @@ from bluer_sbc.help.camera import help_functions as help_camera
|
|
|
10
10
|
from bluer_sbc.help.grove import help_functions as help_grove
|
|
11
11
|
from bluer_sbc.help.hat import help_functions as help_hat
|
|
12
12
|
from bluer_sbc.help.lepton import help_functions as help_lepton
|
|
13
|
+
from bluer_sbc.help.parts import help_functions as help_parts
|
|
13
14
|
from bluer_sbc.help.rpi import help_functions as help_rpi
|
|
14
15
|
from bluer_sbc.help.scroll_phat_hd import help_functions as help_scroll_phat_hd
|
|
15
16
|
from bluer_sbc.help.sparkfun_top_phat import help_functions as help_sparkfun_top_phat
|
|
@@ -26,6 +27,7 @@ help_functions.update(
|
|
|
26
27
|
"grove": help_grove,
|
|
27
28
|
"hat": help_hat,
|
|
28
29
|
"lepton": help_lepton,
|
|
30
|
+
"parts": help_parts,
|
|
29
31
|
"rpi": help_rpi,
|
|
30
32
|
"scroll_phat_hd": help_scroll_phat_hd,
|
|
31
33
|
"sparkfun_top_phat": help_sparkfun_top_phat,
|
bluer_sbc/help/parts.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from bluer_options.terminal import show_usage, xtra
|
|
4
|
+
|
|
5
|
+
from bluer_sbc import ALIAS
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def help_cd(
|
|
9
|
+
tokens: List[str],
|
|
10
|
+
mono: bool,
|
|
11
|
+
) -> str:
|
|
12
|
+
return show_usage(
|
|
13
|
+
[
|
|
14
|
+
"@sbc",
|
|
15
|
+
"parts",
|
|
16
|
+
"cd",
|
|
17
|
+
],
|
|
18
|
+
"cd to part images.",
|
|
19
|
+
mono=mono,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def help_adjust(
|
|
24
|
+
tokens: List[str],
|
|
25
|
+
mono: bool,
|
|
26
|
+
) -> str:
|
|
27
|
+
options = xtra("dryrun,~grid", mono=mono)
|
|
28
|
+
|
|
29
|
+
args = [
|
|
30
|
+
"[--verbose 1]",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
return show_usage(
|
|
34
|
+
[
|
|
35
|
+
"@sbc",
|
|
36
|
+
"parts",
|
|
37
|
+
"adjust",
|
|
38
|
+
f"[{options}]",
|
|
39
|
+
]
|
|
40
|
+
+ args,
|
|
41
|
+
"adjust part images.",
|
|
42
|
+
mono=mono,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
help_functions = {
|
|
47
|
+
"adjust": help_adjust,
|
|
48
|
+
"cd": help_cd,
|
|
49
|
+
}
|
bluer_sbc/help/rpi.py
CHANGED
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from blueness import module
|
|
4
|
+
from blueness.argparse.generic import sys_exit
|
|
5
|
+
|
|
6
|
+
from bluer_sbc import NAME
|
|
7
|
+
from bluer_sbc.parts.db import db_of_parts
|
|
8
|
+
from bluer_sbc.logger import logger
|
|
9
|
+
|
|
10
|
+
NAME = module.name(__file__, NAME)
|
|
11
|
+
|
|
12
|
+
parser = argparse.ArgumentParser(NAME)
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"task",
|
|
15
|
+
type=str,
|
|
16
|
+
help="adjust",
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--dryrun",
|
|
20
|
+
type=int,
|
|
21
|
+
default=1,
|
|
22
|
+
help="0 | 1",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--generate_grid",
|
|
26
|
+
type=int,
|
|
27
|
+
default=1,
|
|
28
|
+
help="0 | 1",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--verbose",
|
|
32
|
+
type=int,
|
|
33
|
+
default=0,
|
|
34
|
+
help="0 | 1",
|
|
35
|
+
)
|
|
36
|
+
args = parser.parse_args()
|
|
37
|
+
|
|
38
|
+
success = False
|
|
39
|
+
if args.task == "adjust":
|
|
40
|
+
success = db_of_parts.adjust(
|
|
41
|
+
generate_grid=args.generate_grid == 1,
|
|
42
|
+
dryrun=args.dryrun == 1,
|
|
43
|
+
verbose=args.verbose == 1,
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
success = None
|
|
47
|
+
|
|
48
|
+
sys_exit(logger, NAME, args.task, success)
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
from typing import Dict, List, Iterator, Tuple
|
|
2
|
+
import copy
|
|
3
|
+
import os
|
|
4
|
+
import numpy as np
|
|
5
|
+
import cv2
|
|
6
|
+
from functools import reduce
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
from blueness import module
|
|
10
|
+
from bluer_options.logger import log_list
|
|
11
|
+
from bluer_objects import file
|
|
12
|
+
from bluer_objects import README
|
|
13
|
+
from bluer_objects.README.consts import assets_path, assets_url
|
|
14
|
+
from bluer_objects.logger.image import log_image_grid
|
|
15
|
+
|
|
16
|
+
from bluer_sbc.host import signature
|
|
17
|
+
from bluer_sbc import NAME
|
|
18
|
+
from bluer_sbc.parts.classes.part import Part
|
|
19
|
+
from bluer_sbc.logger import logger
|
|
20
|
+
|
|
21
|
+
NAME = module.name(__file__, NAME)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PartDB:
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self._db: Dict[str, Part] = {}
|
|
27
|
+
|
|
28
|
+
suffix = "bluer-sbc/parts"
|
|
29
|
+
self.url_prefix = assets_url(
|
|
30
|
+
suffix=suffix,
|
|
31
|
+
volume=2,
|
|
32
|
+
)
|
|
33
|
+
self.path = assets_path(
|
|
34
|
+
suffix=suffix,
|
|
35
|
+
volume=2,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def __iter__(self):
|
|
39
|
+
return iter(self._db.values())
|
|
40
|
+
|
|
41
|
+
def __setitem__(
|
|
42
|
+
self,
|
|
43
|
+
name: str,
|
|
44
|
+
part: Part,
|
|
45
|
+
):
|
|
46
|
+
assert isinstance(part, Part)
|
|
47
|
+
|
|
48
|
+
self._db[name] = copy.deepcopy(part)
|
|
49
|
+
self._db[name].name = name
|
|
50
|
+
|
|
51
|
+
def __getitem__(self, name: str) -> Part:
|
|
52
|
+
return self._db[name]
|
|
53
|
+
|
|
54
|
+
def items(self) -> Iterator[Tuple[str, Part]]:
|
|
55
|
+
return self._db.items()
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def README(self) -> List[str]:
|
|
59
|
+
return sorted(
|
|
60
|
+
[
|
|
61
|
+
"1. [{}](./{}.md).".format(
|
|
62
|
+
part.info[0],
|
|
63
|
+
part.name,
|
|
64
|
+
)
|
|
65
|
+
for part in self
|
|
66
|
+
]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def adjust(
|
|
70
|
+
self,
|
|
71
|
+
generate_grid: bool = True,
|
|
72
|
+
dryrun: bool = True,
|
|
73
|
+
verbose: bool = False,
|
|
74
|
+
) -> bool:
|
|
75
|
+
logger.info(
|
|
76
|
+
"{}.adjust{}".format(
|
|
77
|
+
NAME,
|
|
78
|
+
" [dryrun]" if dryrun else "",
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
list_of_filenames = reduce(
|
|
83
|
+
lambda x, y: x + y,
|
|
84
|
+
[
|
|
85
|
+
[part.images[0]]
|
|
86
|
+
for part_name, part in self._db.items()
|
|
87
|
+
if part_name != "template" and part.images
|
|
88
|
+
],
|
|
89
|
+
[],
|
|
90
|
+
)
|
|
91
|
+
log_list(logger, "adjusting", list_of_filenames, "images")
|
|
92
|
+
|
|
93
|
+
if generate_grid:
|
|
94
|
+
if not log_image_grid(
|
|
95
|
+
items=[
|
|
96
|
+
{
|
|
97
|
+
"filename": os.path.join(self.path, part.images[0]),
|
|
98
|
+
"title": part_name,
|
|
99
|
+
}
|
|
100
|
+
for part_name, part in self._db.items()
|
|
101
|
+
if part_name != "template" and part.images
|
|
102
|
+
],
|
|
103
|
+
filename=assets_path(
|
|
104
|
+
suffix="bluer-sbc/parts/grid.png",
|
|
105
|
+
volume=2,
|
|
106
|
+
),
|
|
107
|
+
scale=3,
|
|
108
|
+
header=[
|
|
109
|
+
"{} part(s)".format(len(self._db) - 1),
|
|
110
|
+
],
|
|
111
|
+
footer=signature(),
|
|
112
|
+
):
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
max_width = 0
|
|
116
|
+
max_height = 0
|
|
117
|
+
for filename in tqdm(list_of_filenames):
|
|
118
|
+
success, image = file.load_image(
|
|
119
|
+
os.path.join(self.path, filename),
|
|
120
|
+
log=verbose,
|
|
121
|
+
)
|
|
122
|
+
if not success:
|
|
123
|
+
return success
|
|
124
|
+
|
|
125
|
+
max_height = max(max_height, image.shape[0])
|
|
126
|
+
max_width = max(max_width, image.shape[1])
|
|
127
|
+
|
|
128
|
+
logger.info(f"size: {max_height} x {max_width}")
|
|
129
|
+
|
|
130
|
+
for filename in tqdm(list_of_filenames):
|
|
131
|
+
success, image = file.load_image(
|
|
132
|
+
os.path.join(self.path, filename),
|
|
133
|
+
log=verbose,
|
|
134
|
+
)
|
|
135
|
+
if not success:
|
|
136
|
+
return success
|
|
137
|
+
|
|
138
|
+
if image.shape[0] == max_height and image.shape[1] == max_width:
|
|
139
|
+
logger.info("✅")
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
image = image[:, :, :3]
|
|
143
|
+
|
|
144
|
+
scale = min(
|
|
145
|
+
max_height / image.shape[0],
|
|
146
|
+
max_width / image.shape[1],
|
|
147
|
+
)
|
|
148
|
+
image = cv2.resize(
|
|
149
|
+
image,
|
|
150
|
+
dsize=(
|
|
151
|
+
int(scale * image.shape[1]),
|
|
152
|
+
int(scale * image.shape[0]),
|
|
153
|
+
),
|
|
154
|
+
interpolation=cv2.INTER_LINEAR,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
padded_image = (
|
|
158
|
+
np.ones(
|
|
159
|
+
(max_height, max_width, 3),
|
|
160
|
+
dtype=np.uint8,
|
|
161
|
+
)
|
|
162
|
+
* 255
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
y_offset = (max_height - image.shape[0]) // 2
|
|
166
|
+
x_offset = (max_width - image.shape[1]) // 2
|
|
167
|
+
|
|
168
|
+
padded_image[
|
|
169
|
+
y_offset : y_offset + image.shape[0],
|
|
170
|
+
x_offset : x_offset + image.shape[1],
|
|
171
|
+
] = image
|
|
172
|
+
|
|
173
|
+
if not dryrun:
|
|
174
|
+
if not file.save_image(
|
|
175
|
+
os.path.join(self.path, filename),
|
|
176
|
+
padded_image,
|
|
177
|
+
log=verbose,
|
|
178
|
+
):
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
return True
|
|
182
|
+
|
|
183
|
+
def as_images(
|
|
184
|
+
self,
|
|
185
|
+
dict_of_parts: Dict[str, str],
|
|
186
|
+
reference: str = "../../parts",
|
|
187
|
+
) -> List[str]:
|
|
188
|
+
return README.Items(
|
|
189
|
+
[
|
|
190
|
+
{
|
|
191
|
+
"name": self._db[part_name].info[0],
|
|
192
|
+
"marquee": self._db[part_name].image_url(
|
|
193
|
+
url_prefix=self.url_prefix
|
|
194
|
+
),
|
|
195
|
+
"description": description,
|
|
196
|
+
"url": f"{reference}/{part_name}.md",
|
|
197
|
+
}
|
|
198
|
+
for part_name, description in dict_of_parts.items()
|
|
199
|
+
],
|
|
200
|
+
sort=True,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def as_list(
|
|
204
|
+
self,
|
|
205
|
+
dict_of_parts: Dict[str, str],
|
|
206
|
+
reference: str = "../../parts",
|
|
207
|
+
log: bool = True,
|
|
208
|
+
) -> List[str]:
|
|
209
|
+
if log:
|
|
210
|
+
logger.info(
|
|
211
|
+
"{}.as_list: {}".format(
|
|
212
|
+
self.__class__.__name__,
|
|
213
|
+
", ".join(dict_of_parts.keys()),
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
for part_name in dict_of_parts:
|
|
218
|
+
if part_name not in self._db:
|
|
219
|
+
logger.error(f"{part_name}: part not found.")
|
|
220
|
+
assert False
|
|
221
|
+
|
|
222
|
+
return sorted(
|
|
223
|
+
[
|
|
224
|
+
(
|
|
225
|
+
"1. [{}]({}){}.".format(
|
|
226
|
+
self._db[part_name].info[0],
|
|
227
|
+
f"{reference}/{part_name}.md",
|
|
228
|
+
": {}".format(description) if description else "",
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
for part_name, description in dict_of_parts.items()
|
|
232
|
+
]
|
|
233
|
+
)
|