diff --git a/extensions/fablabchemnitz/about_upgrade_mightyscape/about_upgrade_mightyscape.py b/extensions/fablabchemnitz/about_upgrade_mightyscape/about_upgrade_mightyscape.py index 342099e..40ea78b 100644 --- a/extensions/fablabchemnitz/about_upgrade_mightyscape/about_upgrade_mightyscape.py +++ b/extensions/fablabchemnitz/about_upgrade_mightyscape/about_upgrade_mightyscape.py @@ -3,7 +3,7 @@ """ Upgrade MightyScape from Inkscape Extension Dialog. Made for end users -Extension for InkScape 1.3.2 +Extension for Inkscape 1.3.2 Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org Date: 14.01.2024 diff --git a/extensions/fablabchemnitz/animate_order/animate_order.py b/extensions/fablabchemnitz/animate_order/animate_order.py index ed7501e..552079a 100644 --- a/extensions/fablabchemnitz/animate_order/animate_order.py +++ b/extensions/fablabchemnitz/animate_order/animate_order.py @@ -9,7 +9,7 @@ from lxml import etree import warnings """ -Extension for InkScape 1.X +Extension for Inkscape 1.X Features - Create SVG preview file and show it in browser. Helps to quickly evaluate line order for cutting processes diff --git a/extensions/fablabchemnitz/bounding_box/bounding_box.py b/extensions/fablabchemnitz/bounding_box/bounding_box.py index 9434dde..086de4e 100644 --- a/extensions/fablabchemnitz/bounding_box/bounding_box.py +++ b/extensions/fablabchemnitz/bounding_box/bounding_box.py @@ -50,8 +50,8 @@ class BoundingBox(inkex.EffectExtension): for element in self.svg.selected.values(): self.drawBBox(element.bounding_box()) else: #combined bbox - #self.drawBBox(self.svg.get_selected_bbox()) #works for InkScape (1:1.0+devel+202008292235+eff2292935) @ Linux and for Windows (but with deprecation) - #self.drawBBox(self.svg.selection.bounding_box()) #works for InkScape 1.1dev (9b1fc87, 2020-08-27)) @ Windows + #self.drawBBox(self.svg.get_selected_bbox()) #works for Inkscape (1:1.0+devel+202008292235+eff2292935) @ Linux and for Windows (but with deprecation) + #self.drawBBox(self.svg.selection.bounding_box()) #works for Inkscape 1.1dev (9b1fc87, 2020-08-27)) @ Windows bbox = inkex.BoundingBox() for element in self.svg.selected.values(): if isinstance (element, inkex.ShapeElement) and element.tag != inkex.addNS('use','svg') and element.get('inkscape:groupmode') != 'layer': #bbox fails for svg:use elements and layers: @@ -62,4 +62,4 @@ class BoundingBox(inkex.EffectExtension): return if __name__ == '__main__': - BoundingBox().run() \ No newline at end of file + BoundingBox().run() diff --git a/extensions/fablabchemnitz/boxes.py/ABox-thumb.svg b/extensions/fablabchemnitz/boxes.py/ABox-thumb.svg new file mode 100644 index 0000000..a21f8ea --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ABox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/AgricolaInsert-thumb.svg b/extensions/fablabchemnitz/boxes.py/AgricolaInsert-thumb.svg new file mode 100644 index 0000000..e789d17 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/AgricolaInsert-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/AirPurifier-thumb.svg b/extensions/fablabchemnitz/boxes.py/AirPurifier-thumb.svg new file mode 100644 index 0000000..8269c41 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/AirPurifier-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/AllEdges-thumb.svg b/extensions/fablabchemnitz/boxes.py/AllEdges-thumb.svg new file mode 100644 index 0000000..8cb41eb --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/AllEdges-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/AngledBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/AngledBox-thumb.svg new file mode 100644 index 0000000..c011f02 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/AngledBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/AngledCutJig-thumb.svg b/extensions/fablabchemnitz/boxes.py/AngledCutJig-thumb.svg new file mode 100644 index 0000000..368a279 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/AngledCutJig-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Arcade-thumb.svg b/extensions/fablabchemnitz/boxes.py/Arcade-thumb.svg new file mode 100644 index 0000000..4b6aae7 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Arcade-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Atreus21-thumb.svg b/extensions/fablabchemnitz/boxes.py/Atreus21-thumb.svg new file mode 100644 index 0000000..c4fc282 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Atreus21-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BasedBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/BasedBox-thumb.svg new file mode 100644 index 0000000..aedda43 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BasedBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BayonetBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/BayonetBox-thumb.svg new file mode 100644 index 0000000..2def402 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BayonetBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BinTray-thumb.svg b/extensions/fablabchemnitz/boxes.py/BinTray-thumb.svg new file mode 100644 index 0000000..580a3f3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BinTray-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BirdHouse-thumb.svg b/extensions/fablabchemnitz/boxes.py/BirdHouse-thumb.svg new file mode 100644 index 0000000..796e712 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BirdHouse-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-back-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BookHolder-back-thumb.jpg new file mode 100644 index 0000000..222ad02 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BookHolder-back-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-back-thumb.svg b/extensions/fablabchemnitz/boxes.py/BookHolder-back-thumb.svg new file mode 100644 index 0000000..f8ae746 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BookHolder-back-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-minis-side-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-side-thumb.jpg new file mode 100644 index 0000000..14de5a2 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-side-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-minis-side-thumb.svg b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-side-thumb.svg new file mode 100644 index 0000000..128b96b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-side-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-minis-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-thumb.jpg new file mode 100644 index 0000000..13fc550 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-minis-thumb.svg b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-thumb.svg new file mode 100644 index 0000000..083fdd1 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BookHolder-minis-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BookHolder-thumb.jpg new file mode 100644 index 0000000..69eb72b Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BookHolder-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BookHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/BookHolder-thumb.svg new file mode 100644 index 0000000..0fb6979 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BookHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BottleTag-thumb.svg b/extensions/fablabchemnitz/boxes.py/BottleTag-thumb.svg new file mode 100644 index 0000000..f55261a --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BottleTag-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BreadBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/BreadBox-thumb.svg new file mode 100644 index 0000000..ab23774 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BreadBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BrickSorter-2-thumb.jpg new file mode 100644 index 0000000..face87a Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BrickSorter-2-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/BrickSorter-2-thumb.svg new file mode 100644 index 0000000..468471e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BrickSorter-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BrickSorter-3-thumb.jpg new file mode 100644 index 0000000..74e5947 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BrickSorter-3-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-3-thumb.svg b/extensions/fablabchemnitz/boxes.py/BrickSorter-3-thumb.svg new file mode 100644 index 0000000..3b49cf7 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BrickSorter-3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-4-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BrickSorter-4-thumb.jpg new file mode 100644 index 0000000..c349a28 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BrickSorter-4-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-4-thumb.svg b/extensions/fablabchemnitz/boxes.py/BrickSorter-4-thumb.svg new file mode 100644 index 0000000..dae224c --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BrickSorter-4-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-5-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BrickSorter-5-thumb.jpg new file mode 100644 index 0000000..6be0231 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BrickSorter-5-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-5-thumb.svg b/extensions/fablabchemnitz/boxes.py/BrickSorter-5-thumb.svg new file mode 100644 index 0000000..9f357a7 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BrickSorter-5-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-6-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BrickSorter-6-thumb.jpg new file mode 100644 index 0000000..a72fe5a Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BrickSorter-6-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-6-thumb.svg b/extensions/fablabchemnitz/boxes.py/BrickSorter-6-thumb.svg new file mode 100644 index 0000000..db6a199 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BrickSorter-6-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-thumb.jpg b/extensions/fablabchemnitz/boxes.py/BrickSorter-thumb.jpg new file mode 100644 index 0000000..9b99a95 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/BrickSorter-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/BrickSorter-thumb.svg b/extensions/fablabchemnitz/boxes.py/BrickSorter-thumb.svg new file mode 100644 index 0000000..c39b035 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BrickSorter-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/BurnTest-thumb.svg b/extensions/fablabchemnitz/boxes.py/BurnTest-thumb.svg new file mode 100644 index 0000000..5f44455 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/BurnTest-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CanStorage-thumb.svg b/extensions/fablabchemnitz/boxes.py/CanStorage-thumb.svg new file mode 100644 index 0000000..eca5aa6 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CanStorage-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CanStorageAA-thumb.svg b/extensions/fablabchemnitz/boxes.py/CanStorageAA-thumb.svg new file mode 100644 index 0000000..ab98e74 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CanStorageAA-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CardBox-detail-thumb.svg b/extensions/fablabchemnitz/boxes.py/CardBox-detail-thumb.svg new file mode 100644 index 0000000..bc4c933 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CardBox-detail-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CardBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/CardBox-thumb.svg new file mode 100644 index 0000000..f0217b3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CardBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CardHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/CardHolder-thumb.svg new file mode 100644 index 0000000..a6fb21e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CardHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Castle-thumb.svg b/extensions/fablabchemnitz/boxes.py/Castle-thumb.svg new file mode 100644 index 0000000..0399a2f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Castle-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ClosedBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/ClosedBox-thumb.svg new file mode 100644 index 0000000..9b827b1 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ClosedBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CoffeeCapsuleHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/CoffeeCapsuleHolder-thumb.svg new file mode 100644 index 0000000..5a3be0f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CoffeeCapsuleHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CoinBankSafe-closed-thumb.svg b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-closed-thumb.svg new file mode 100644 index 0000000..dc08e21 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-closed-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CoinBankSafe-open-thumb.svg b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-open-thumb.svg new file mode 100644 index 0000000..6afbd4c --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-open-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CoinBankSafe-pins-thumb.svg b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-pins-thumb.svg new file mode 100644 index 0000000..08da28e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-pins-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CoinBankSafe-thumb.svg b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-thumb.svg new file mode 100644 index 0000000..c30ad27 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CoinBankSafe-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CoinDisplay-thumb.svg b/extensions/fablabchemnitz/boxes.py/CoinDisplay-thumb.svg new file mode 100644 index 0000000..4067154 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CoinDisplay-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CompartmentBox-closed-thumb.jpg b/extensions/fablabchemnitz/boxes.py/CompartmentBox-closed-thumb.jpg new file mode 100644 index 0000000..9812817 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/CompartmentBox-closed-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/CompartmentBox-closed-thumb.svg b/extensions/fablabchemnitz/boxes.py/CompartmentBox-closed-thumb.svg new file mode 100644 index 0000000..6e91256 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CompartmentBox-closed-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CompartmentBox-lid-thumb.jpg b/extensions/fablabchemnitz/boxes.py/CompartmentBox-lid-thumb.jpg new file mode 100644 index 0000000..42c4cf1 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/CompartmentBox-lid-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/CompartmentBox-lid-thumb.svg b/extensions/fablabchemnitz/boxes.py/CompartmentBox-lid-thumb.svg new file mode 100644 index 0000000..d7d6a68 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CompartmentBox-lid-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/CompartmentBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/CompartmentBox-thumb.jpg new file mode 100644 index 0000000..45a1555 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/CompartmentBox-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/CompartmentBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/CompartmentBox-thumb.svg new file mode 100644 index 0000000..4325d2d --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/CompartmentBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ConcaveKnob-thumb.svg b/extensions/fablabchemnitz/boxes.py/ConcaveKnob-thumb.svg new file mode 100644 index 0000000..5f122b5 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ConcaveKnob-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Console-thumb.svg b/extensions/fablabchemnitz/boxes.py/Console-thumb.svg new file mode 100644 index 0000000..28c8f6f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Console-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Console2-backwall-detail-thumb.svg b/extensions/fablabchemnitz/boxes.py/Console2-backwall-detail-thumb.svg new file mode 100644 index 0000000..d9b570e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Console2-backwall-detail-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Console2-panel-detail-thumb.svg b/extensions/fablabchemnitz/boxes.py/Console2-panel-detail-thumb.svg new file mode 100644 index 0000000..89fddd1 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Console2-panel-detail-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Console2-thumb.svg b/extensions/fablabchemnitz/boxes.py/Console2-thumb.svg new file mode 100644 index 0000000..8d61183 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Console2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickBack-thumb.svg b/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickBack-thumb.svg new file mode 100644 index 0000000..e77caef --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickBack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickFront-thumb.svg b/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickFront-thumb.svg new file mode 100644 index 0000000..8de24d2 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickFront-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickInside-thumb.svg b/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickInside-thumb.svg new file mode 100644 index 0000000..5bcdf52 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ConsoleArcadeStickInside-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Desksign-thumb.svg b/extensions/fablabchemnitz/boxes.py/Desksign-thumb.svg new file mode 100644 index 0000000..6fb8009 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Desksign-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DiceBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/DiceBox-thumb.svg new file mode 100644 index 0000000..231e5b4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DiceBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DiceTower-thumb.jpg b/extensions/fablabchemnitz/boxes.py/DiceTower-thumb.jpg new file mode 100644 index 0000000..b19f89f Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/DiceTower-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/DiceTower-thumb.svg b/extensions/fablabchemnitz/boxes.py/DiceTower-thumb.svg new file mode 100644 index 0000000..3d078e6 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DiceTower-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DiscRack-thumb.svg b/extensions/fablabchemnitz/boxes.py/DiscRack-thumb.svg new file mode 100644 index 0000000..46fc814 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DiscRack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Dispenser-thumb.svg b/extensions/fablabchemnitz/boxes.py/Dispenser-thumb.svg new file mode 100644 index 0000000..ccacc56 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Dispenser-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Display-thumb.jpg b/extensions/fablabchemnitz/boxes.py/Display-thumb.jpg index f9bfaea..18bbd46 100644 Binary files a/extensions/fablabchemnitz/boxes.py/Display-thumb.jpg and b/extensions/fablabchemnitz/boxes.py/Display-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/Display-thumb.svg b/extensions/fablabchemnitz/boxes.py/Display-thumb.svg new file mode 100644 index 0000000..b826168 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Display-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DisplayCase-thumb.svg b/extensions/fablabchemnitz/boxes.py/DisplayCase-thumb.svg new file mode 100644 index 0000000..848ea58 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DisplayCase-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DisplayShelf-thumb.svg b/extensions/fablabchemnitz/boxes.py/DisplayShelf-thumb.svg new file mode 100644 index 0000000..85b7a39 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DisplayShelf-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DividerTray-thumb.svg b/extensions/fablabchemnitz/boxes.py/DividerTray-thumb.svg new file mode 100644 index 0000000..3d36f27 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DividerTray-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DoubleFlexDoorBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/DoubleFlexDoorBox-thumb.svg new file mode 100644 index 0000000..2e9e0f4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DoubleFlexDoorBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillBox-thumb.svg new file mode 100644 index 0000000..5ec5c9b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillBoxes-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillBoxes-thumb.svg new file mode 100644 index 0000000..9be8ef0 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillBoxes-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-1-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-1-thumb.svg new file mode 100644 index 0000000..faa70ec --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-1-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-2-thumb.svg new file mode 100644 index 0000000..9d372d9 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-3-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-3-thumb.svg new file mode 100644 index 0000000..9b7f114 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-4-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-4-thumb.svg new file mode 100644 index 0000000..eeefaa2 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillStand-assembly-4-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/DrillStand-thumb.svg b/extensions/fablabchemnitz/boxes.py/DrillStand-thumb.svg new file mode 100644 index 0000000..f823e32 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/DrillStand-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ElectronicsBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/ElectronicsBox-thumb.svg new file mode 100644 index 0000000..0359fb1 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ElectronicsBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/EuroRackSkiff-thumb.svg b/extensions/fablabchemnitz/boxes.py/EuroRackSkiff-thumb.svg new file mode 100644 index 0000000..13f128f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/EuroRackSkiff-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FanHole-thumb.svg b/extensions/fablabchemnitz/boxes.py/FanHole-thumb.svg new file mode 100644 index 0000000..b3f9d20 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FanHole-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FatBallDispenser-thumb.jpg b/extensions/fablabchemnitz/boxes.py/FatBallDispenser-thumb.jpg new file mode 100644 index 0000000..e69d53d Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/FatBallDispenser-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/FatBallDispenser-thumb.svg b/extensions/fablabchemnitz/boxes.py/FatBallDispenser-thumb.svg new file mode 100644 index 0000000..8a0a400 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FatBallDispenser-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FilamentSpool-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/FilamentSpool-2-thumb.svg new file mode 100644 index 0000000..060b990 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FilamentSpool-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FilamentSpool-thumb.svg b/extensions/fablabchemnitz/boxes.py/FilamentSpool-thumb.svg new file mode 100644 index 0000000..2c23238 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FilamentSpool-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FillTest-thumb.svg b/extensions/fablabchemnitz/boxes.py/FillTest-thumb.svg new file mode 100644 index 0000000..52614e3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FillTest-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBook-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBook-2-thumb.svg new file mode 100644 index 0000000..fcde2f6 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBook-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBook-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBook-thumb.svg new file mode 100644 index 0000000..be19665 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBook-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBox-thumb.svg new file mode 100644 index 0000000..8bdf1e5 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBox2-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBox2-thumb.svg new file mode 100644 index 0000000..8fc262c --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBox2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBox3-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBox3-thumb.svg new file mode 100644 index 0000000..cdf3e88 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBox3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBox4-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBox4-thumb.svg new file mode 100644 index 0000000..784ab82 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBox4-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexBox5-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexBox5-thumb.svg new file mode 100644 index 0000000..41e1c89 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexBox5-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexTest-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexTest-thumb.svg new file mode 100644 index 0000000..bff7349 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexTest-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FlexTest2-thumb.svg b/extensions/fablabchemnitz/boxes.py/FlexTest2-thumb.svg new file mode 100644 index 0000000..db05a4f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FlexTest2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Folder-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/Folder-2-thumb.svg new file mode 100644 index 0000000..b20411f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Folder-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Folder-thumb.svg b/extensions/fablabchemnitz/boxes.py/Folder-thumb.svg new file mode 100644 index 0000000..176bf54 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Folder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/FrontPanel-thumb.svg b/extensions/fablabchemnitz/boxes.py/FrontPanel-thumb.svg new file mode 100644 index 0000000..9c18741 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/FrontPanel-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/GearBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/GearBox-thumb.svg new file mode 100644 index 0000000..df59907 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/GearBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/GridfinityBase-thumb.svg b/extensions/fablabchemnitz/boxes.py/GridfinityBase-thumb.svg new file mode 100644 index 0000000..f6d7e4f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/GridfinityBase-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/GridfinityDrillBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/GridfinityDrillBox-thumb.jpg new file mode 100644 index 0000000..5861e31 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/GridfinityDrillBox-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/GridfinityDrillBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/GridfinityDrillBox-thumb.svg new file mode 100644 index 0000000..f394d8a --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/GridfinityDrillBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/GridfinityTrayLayout-thumb.svg b/extensions/fablabchemnitz/boxes.py/GridfinityTrayLayout-thumb.svg new file mode 100644 index 0000000..f9788c3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/GridfinityTrayLayout-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HalfBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/HalfBox-thumb.svg new file mode 100644 index 0000000..5896c66 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HalfBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HalfBox_AngleJig_usage-thumb.svg b/extensions/fablabchemnitz/boxes.py/HalfBox_AngleJig_usage-thumb.svg new file mode 100644 index 0000000..a247766 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HalfBox_AngleJig_usage-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HalfBox_Bookend_usage-thumb.svg b/extensions/fablabchemnitz/boxes.py/HalfBox_Bookend_usage-thumb.svg new file mode 100644 index 0000000..1af8961 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HalfBox_Bookend_usage-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HalfBox_Shelf_usage-thumb.svg b/extensions/fablabchemnitz/boxes.py/HalfBox_Shelf_usage-thumb.svg new file mode 100644 index 0000000..47b87d3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HalfBox_Shelf_usage-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HeartBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/HeartBox-thumb.svg new file mode 100644 index 0000000..18b26e4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HeartBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HingeBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/HingeBox-thumb.svg new file mode 100644 index 0000000..14f9600 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HingeBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HobbyCase-thumb.jpg b/extensions/fablabchemnitz/boxes.py/HobbyCase-thumb.jpg new file mode 100644 index 0000000..14ad226 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/HobbyCase-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/HobbyCase-thumb.svg b/extensions/fablabchemnitz/boxes.py/HobbyCase-thumb.svg new file mode 100644 index 0000000..f2baf1b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HobbyCase-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/HolePattern-thumb.svg b/extensions/fablabchemnitz/boxes.py/HolePattern-thumb.svg new file mode 100644 index 0000000..e8676e4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/HolePattern-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Hook-thumb.svg b/extensions/fablabchemnitz/boxes.py/Hook-thumb.svg new file mode 100644 index 0000000..3a890ce --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Hook-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/IntegratedHingeBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/IntegratedHingeBox-thumb.svg new file mode 100644 index 0000000..e07d23e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/IntegratedHingeBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/JointPanel-thumb.svg b/extensions/fablabchemnitz/boxes.py/JointPanel-thumb.svg new file mode 100644 index 0000000..e5d9af3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/JointPanel-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Kamishibai-thumb.jpg b/extensions/fablabchemnitz/boxes.py/Kamishibai-thumb.jpg new file mode 100644 index 0000000..8c45db0 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/Kamishibai-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/Kamishibai-thumb.svg b/extensions/fablabchemnitz/boxes.py/Kamishibai-thumb.svg new file mode 100644 index 0000000..8564619 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Kamishibai-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/KeyHolder-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/KeyHolder-2-thumb.svg new file mode 100644 index 0000000..7825cec --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/KeyHolder-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/KeyHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/KeyHolder-thumb.svg new file mode 100644 index 0000000..d465c2b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/KeyHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Keypad-thumb.svg b/extensions/fablabchemnitz/boxes.py/Keypad-thumb.svg new file mode 100644 index 0000000..42e3176 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Keypad-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/LBeam-thumb.svg b/extensions/fablabchemnitz/boxes.py/LBeam-thumb.svg new file mode 100644 index 0000000..97ad85a --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/LBeam-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/LaptopStand-thumb.svg b/extensions/fablabchemnitz/boxes.py/LaptopStand-thumb.svg new file mode 100644 index 0000000..2666c22 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/LaptopStand-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/LaserClamp-thumb.svg b/extensions/fablabchemnitz/boxes.py/LaserClamp-thumb.svg new file mode 100644 index 0000000..a93d5e8 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/LaserClamp-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/LaserHoldfast-thumb.svg b/extensions/fablabchemnitz/boxes.py/LaserHoldfast-thumb.svg new file mode 100644 index 0000000..9f7fe2a --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/LaserHoldfast-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/MagazineFile-thumb.svg b/extensions/fablabchemnitz/boxes.py/MagazineFile-thumb.svg new file mode 100644 index 0000000..e039dc0 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/MagazineFile-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/MakitaPowerSupply-thumb.svg b/extensions/fablabchemnitz/boxes.py/MakitaPowerSupply-thumb.svg new file mode 100644 index 0000000..76de1aa --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/MakitaPowerSupply-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/March36539-box-thumb.jpg b/extensions/fablabchemnitz/boxes.py/March36539-box-thumb.jpg similarity index 100% rename from extensions/fablabchemnitz/boxes.py/boxes/static/samples/March36539-box-thumb.jpg rename to extensions/fablabchemnitz/boxes.py/March36539-box-thumb.jpg diff --git a/extensions/fablabchemnitz/boxes.py/March36539-box-thumb.svg b/extensions/fablabchemnitz/boxes.py/March36539-box-thumb.svg new file mode 100644 index 0000000..5e6717b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/March36539-box-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Matrix-thumb.jpg b/extensions/fablabchemnitz/boxes.py/Matrix-thumb.jpg new file mode 100644 index 0000000..f638ace Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/Matrix-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/Matrix-thumb.svg b/extensions/fablabchemnitz/boxes.py/Matrix-thumb.svg new file mode 100644 index 0000000..6fcbcda --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Matrix-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/NemaPattern-thumb.svg b/extensions/fablabchemnitz/boxes.py/NemaPattern-thumb.svg new file mode 100644 index 0000000..feee504 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/NemaPattern-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/NightLightBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/NightLightBox-thumb.jpg new file mode 100644 index 0000000..633d7a4 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/NightLightBox-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/NightLightBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/NightLightBox-thumb.svg new file mode 100644 index 0000000..e956fc4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/NightLightBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/NotesHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/NotesHolder-thumb.svg new file mode 100644 index 0000000..f4078a8 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/NotesHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/OpenBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/OpenBox-thumb.svg new file mode 100644 index 0000000..973ca1e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/OpenBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/OttoBody-thumb.svg b/extensions/fablabchemnitz/boxes.py/OttoBody-thumb.svg new file mode 100644 index 0000000..ddc3394 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/OttoBody-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/OttoLegs-thumb.svg b/extensions/fablabchemnitz/boxes.py/OttoLegs-thumb.svg new file mode 100644 index 0000000..9302a8e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/OttoLegs-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/OttoSoles-thumb.svg b/extensions/fablabchemnitz/boxes.py/OttoSoles-thumb.svg new file mode 100644 index 0000000..8a94289 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/OttoSoles-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/PaintStorage-thumb.svg b/extensions/fablabchemnitz/boxes.py/PaintStorage-thumb.svg new file mode 100644 index 0000000..8e1177b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/PaintStorage-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/PaperBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/PaperBox-thumb.svg new file mode 100644 index 0000000..7aaced0 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/PaperBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/PhoneHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/PhoneHolder-thumb.svg new file mode 100644 index 0000000..e28f07d --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/PhoneHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/PhotoFrame-thumb.jpg b/extensions/fablabchemnitz/boxes.py/PhotoFrame-thumb.jpg new file mode 100644 index 0000000..8da2cf5 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/PhotoFrame-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/PhotoFrame-thumb.svg b/extensions/fablabchemnitz/boxes.py/PhotoFrame-thumb.svg new file mode 100644 index 0000000..d30d92d --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/PhotoFrame-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/PirateChest-thumb.svg b/extensions/fablabchemnitz/boxes.py/PirateChest-thumb.svg new file mode 100644 index 0000000..af88c1f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/PirateChest-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/PizzaShovel-thumb.svg b/extensions/fablabchemnitz/boxes.py/PizzaShovel-thumb.svg new file mode 100644 index 0000000..4216763 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/PizzaShovel-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Platonic-Icosahedron-thumb.svg b/extensions/fablabchemnitz/boxes.py/Platonic-Icosahedron-thumb.svg new file mode 100644 index 0000000..50cc091 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Platonic-Icosahedron-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Platonic-thumb.svg b/extensions/fablabchemnitz/boxes.py/Platonic-thumb.svg new file mode 100644 index 0000000..33397b7 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Platonic-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Rack19Box-thumb.svg b/extensions/fablabchemnitz/boxes.py/Rack19Box-thumb.svg new file mode 100644 index 0000000..e972709 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Rack19Box-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RackBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/RackBox-thumb.svg new file mode 100644 index 0000000..76bc7e8 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RackBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RectangularWall-thumb.svg b/extensions/fablabchemnitz/boxes.py/RectangularWall-thumb.svg new file mode 100644 index 0000000..d42f69c --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RectangularWall-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RegularBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/RegularBox-thumb.svg new file mode 100644 index 0000000..04fb3fc --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RegularBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RegularStarBox-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/RegularStarBox-2-thumb.svg new file mode 100644 index 0000000..e977a10 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RegularStarBox-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RegularStarBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/RegularStarBox-thumb.svg new file mode 100644 index 0000000..8d300bf --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RegularStarBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RobotArm-thumb.svg b/extensions/fablabchemnitz/boxes.py/RobotArm-thumb.svg new file mode 100644 index 0000000..97978a2 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RobotArm-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RollHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/RollHolder-thumb.svg new file mode 100644 index 0000000..dc63285 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RollHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Rotary-thumb.svg b/extensions/fablabchemnitz/boxes.py/Rotary-thumb.svg new file mode 100644 index 0000000..ecbdbcc --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Rotary-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoundedBox-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoundedBox-2-thumb.svg new file mode 100644 index 0000000..161eca9 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoundedBox-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoundedBox-3-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoundedBox-3-thumb.svg new file mode 100644 index 0000000..cd4e414 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoundedBox-3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoundedBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoundedBox-thumb.svg new file mode 100644 index 0000000..bb0635e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoundedBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoundedRegularBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox-thumb.jpg new file mode 100644 index 0000000..6d8443e Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/RoundedRegularBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox-thumb.svg new file mode 100644 index 0000000..2175bdc --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoundedRegularBox2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox2-thumb.jpg new file mode 100644 index 0000000..a00c5bf Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox2-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/RoundedRegularBox2-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox2-thumb.svg new file mode 100644 index 0000000..c87c968 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoundedRegularBox2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoyalGame-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoyalGame-2-thumb.svg new file mode 100644 index 0000000..ca8a6b2 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoyalGame-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoyalGame-3-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoyalGame-3-thumb.svg new file mode 100644 index 0000000..259eb38 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoyalGame-3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/RoyalGame-thumb.svg b/extensions/fablabchemnitz/boxes.py/RoyalGame-thumb.svg new file mode 100644 index 0000000..f91a54b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/RoyalGame-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SBCMicroRack-thumb.svg b/extensions/fablabchemnitz/boxes.py/SBCMicroRack-thumb.svg new file mode 100644 index 0000000..390f427 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SBCMicroRack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SevenSegmentClock-thumb.jpg b/extensions/fablabchemnitz/boxes.py/SevenSegmentClock-thumb.jpg new file mode 100644 index 0000000..de52243 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/SevenSegmentClock-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/SevenSegmentClock-thumb.svg b/extensions/fablabchemnitz/boxes.py/SevenSegmentClock-thumb.svg new file mode 100644 index 0000000..c01b60b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SevenSegmentClock-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SevenSegmentPattern-thumb.svg b/extensions/fablabchemnitz/boxes.py/SevenSegmentPattern-thumb.svg new file mode 100644 index 0000000..9d73e79 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SevenSegmentPattern-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Shadowbox-backlit-thumb.svg b/extensions/fablabchemnitz/boxes.py/Shadowbox-backlit-thumb.svg new file mode 100644 index 0000000..f938ce8 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Shadowbox-backlit-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Shadowbox-diagram-thumb.svg b/extensions/fablabchemnitz/boxes.py/Shadowbox-diagram-thumb.svg new file mode 100644 index 0000000..d933084 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Shadowbox-diagram-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Shadowbox-thumb.svg b/extensions/fablabchemnitz/boxes.py/Shadowbox-thumb.svg new file mode 100644 index 0000000..f37783c --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Shadowbox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Shoe-thumb.svg b/extensions/fablabchemnitz/boxes.py/Shoe-thumb.svg new file mode 100644 index 0000000..7e7c336 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Shoe-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ShutterBox-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/ShutterBox-2-thumb.svg new file mode 100644 index 0000000..8fb390f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ShutterBox-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ShutterBox-3-thumb.svg b/extensions/fablabchemnitz/boxes.py/ShutterBox-3-thumb.svg new file mode 100644 index 0000000..8efae51 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ShutterBox-3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ShutterBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/ShutterBox-thumb.svg new file mode 100644 index 0000000..ba4a7ae --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ShutterBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SideDoorHousing-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/SideDoorHousing-2-thumb.svg new file mode 100644 index 0000000..aa476a1 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SideDoorHousing-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SideDoorHousing-thumb.svg b/extensions/fablabchemnitz/boxes.py/SideDoorHousing-thumb.svg new file mode 100644 index 0000000..a89d2ac --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SideDoorHousing-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SideHingeBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/SideHingeBox-thumb.jpg new file mode 100644 index 0000000..0d5a192 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/SideHingeBox-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/SideHingeBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/SideHingeBox-thumb.svg new file mode 100644 index 0000000..d870bbe --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SideHingeBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Silverware-thumb.svg b/extensions/fablabchemnitz/boxes.py/Silverware-thumb.svg new file mode 100644 index 0000000..5125ba4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Silverware-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SkadisBoard-thumb.svg b/extensions/fablabchemnitz/boxes.py/SkadisBoard-thumb.svg new file mode 100644 index 0000000..23c5f4f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SkadisBoard-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SlantedTray-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/SlantedTray-2-thumb.svg new file mode 100644 index 0000000..1efb764 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SlantedTray-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SlantedTray-thumb.svg b/extensions/fablabchemnitz/boxes.py/SlantedTray-thumb.svg new file mode 100644 index 0000000..a47fc8f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SlantedTray-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SlidingDrawer-thumb.svg b/extensions/fablabchemnitz/boxes.py/SlidingDrawer-thumb.svg new file mode 100644 index 0000000..92da54f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SlidingDrawer-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SlidingLidBox-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-2-thumb.jpg new file mode 100644 index 0000000..2238fdc Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-2-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/SlidingLidBox-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-2-thumb.svg new file mode 100644 index 0000000..cb6ab66 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SlidingLidBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-thumb.jpg new file mode 100644 index 0000000..01ee9ea Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/SlidingLidBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-thumb.svg new file mode 100644 index 0000000..0b4957f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SlidingLidBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SmallPartsTray-thumb.svg b/extensions/fablabchemnitz/boxes.py/SmallPartsTray-thumb.svg new file mode 100644 index 0000000..331dc36 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SmallPartsTray-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SmallPartsTray2-thumb.svg b/extensions/fablabchemnitz/boxes.py/SmallPartsTray2-thumb.svg new file mode 100644 index 0000000..d9a40d4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SmallPartsTray2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/SpicesRack-thumb.svg b/extensions/fablabchemnitz/boxes.py/SpicesRack-thumb.svg new file mode 100644 index 0000000..2310b6b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/SpicesRack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Spool-thumb.svg b/extensions/fablabchemnitz/boxes.py/Spool-thumb.svg new file mode 100644 index 0000000..c83fdcf --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Spool-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Stachel-thumb.svg b/extensions/fablabchemnitz/boxes.py/Stachel-thumb.svg new file mode 100644 index 0000000..8fec4f4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Stachel-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/StackableBin-thumb.jpg b/extensions/fablabchemnitz/boxes.py/StackableBin-thumb.jpg new file mode 100644 index 0000000..45f06e7 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/StackableBin-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/StackableBin-thumb.svg b/extensions/fablabchemnitz/boxes.py/StackableBin-thumb.svg new file mode 100644 index 0000000..6088691 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/StackableBin-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/StorageRack-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/StorageRack-2-thumb.svg new file mode 100644 index 0000000..a05546e --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/StorageRack-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/StorageRack-3-thumb.svg b/extensions/fablabchemnitz/boxes.py/StorageRack-3-thumb.svg new file mode 100644 index 0000000..e50e556 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/StorageRack-3-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/StorageRack-thumb.svg b/extensions/fablabchemnitz/boxes.py/StorageRack-thumb.svg new file mode 100644 index 0000000..7ce7a8b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/StorageRack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/StorageShelf-thumb.svg b/extensions/fablabchemnitz/boxes.py/StorageShelf-thumb.svg new file mode 100644 index 0000000..7085a6f --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/StorageShelf-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/Tetris-thumb.svg b/extensions/fablabchemnitz/boxes.py/Tetris-thumb.svg new file mode 100644 index 0000000..59847e1 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/Tetris-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TrafficLight-thumb.svg b/extensions/fablabchemnitz/boxes.py/TrafficLight-thumb.svg new file mode 100644 index 0000000..819591b --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TrafficLight-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TrayInsert-2-thumb.svg b/extensions/fablabchemnitz/boxes.py/TrayInsert-2-thumb.svg new file mode 100644 index 0000000..60a5999 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TrayInsert-2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TrayInsert-thumb.svg b/extensions/fablabchemnitz/boxes.py/TrayInsert-thumb.svg new file mode 100644 index 0000000..f067406 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TrayInsert-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TrayLayout-thumb.svg b/extensions/fablabchemnitz/boxes.py/TrayLayout-thumb.svg new file mode 100644 index 0000000..a6cb9e2 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TrayLayout-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TrayLayout2-thumb.svg b/extensions/fablabchemnitz/boxes.py/TrayLayout2-thumb.svg new file mode 100644 index 0000000..5b429a7 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TrayLayout2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TwoPiece-thumb.svg b/extensions/fablabchemnitz/boxes.py/TwoPiece-thumb.svg new file mode 100644 index 0000000..945030a --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TwoPiece-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TwoPiece2-thumb.svg b/extensions/fablabchemnitz/boxes.py/TwoPiece2-thumb.svg new file mode 100644 index 0000000..4e142ab --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TwoPiece2-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/TypeTray-thumb.svg b/extensions/fablabchemnitz/boxes.py/TypeTray-thumb.svg new file mode 100644 index 0000000..b348109 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/TypeTray-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/UBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/UBox-thumb.svg new file mode 100644 index 0000000..032be4d --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/UBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/UnevenHeightBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/UnevenHeightBox-thumb.svg new file mode 100644 index 0000000..d2dd4dc --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/UnevenHeightBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/UniversalBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/UniversalBox-thumb.svg new file mode 100644 index 0000000..c382a8a --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/UniversalBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallCaliper-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallCaliper-thumb.svg new file mode 100644 index 0000000..b7d0e95 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallCaliper-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallChiselHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallChiselHolder-thumb.svg new file mode 100644 index 0000000..9c3d1a6 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallChiselHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallConsole-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallConsole-thumb.svg new file mode 100644 index 0000000..f4feaa3 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallConsole-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallDrillBox-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallDrillBox-thumb.svg new file mode 100644 index 0000000..fde00c4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallDrillBox-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallHopper-thumb.jpg b/extensions/fablabchemnitz/boxes.py/WallHopper-thumb.jpg new file mode 100644 index 0000000..303537f Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/WallHopper-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/WallHopper-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallHopper-thumb.svg new file mode 100644 index 0000000..4bc51ad --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallHopper-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallPinRow-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallPinRow-thumb.svg new file mode 100644 index 0000000..1869856 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallPinRow-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallPlaneHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallPlaneHolder-thumb.svg new file mode 100644 index 0000000..90526a6 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallPlaneHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallPliersHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallPliersHolder-thumb.svg new file mode 100644 index 0000000..afdb6dd --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallPliersHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallRack-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallRack-thumb.svg new file mode 100644 index 0000000..51db15c --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallRack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallRollHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallRollHolder-thumb.svg new file mode 100644 index 0000000..2a9cd92 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallRollHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallSlottedHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallSlottedHolder-thumb.svg new file mode 100644 index 0000000..eafd41d --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallSlottedHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallStackableBin-thumb.jpg b/extensions/fablabchemnitz/boxes.py/WallStackableBin-thumb.jpg new file mode 100644 index 0000000..a10d180 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/WallStackableBin-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/WallStackableBin-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallStackableBin-thumb.svg new file mode 100644 index 0000000..e9d5c95 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallStackableBin-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallStairs-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallStairs-thumb.svg new file mode 100644 index 0000000..17121cd --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallStairs-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallTypeTray-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallTypeTray-thumb.svg new file mode 100644 index 0000000..5649063 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallTypeTray-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WallWrenchHolder-thumb.svg b/extensions/fablabchemnitz/boxes.py/WallWrenchHolder-thumb.svg new file mode 100644 index 0000000..c268092 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WallWrenchHolder-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/WineRack-thumb.svg b/extensions/fablabchemnitz/boxes.py/WineRack-thumb.svg new file mode 100644 index 0000000..0723218 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/WineRack-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ZBeam-flanged-ubeam-thumb.jpg b/extensions/fablabchemnitz/boxes.py/ZBeam-flanged-ubeam-thumb.jpg new file mode 100644 index 0000000..12f36be Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/ZBeam-flanged-ubeam-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/ZBeam-flanged-ubeam-thumb.svg b/extensions/fablabchemnitz/boxes.py/ZBeam-flanged-ubeam-thumb.svg new file mode 100644 index 0000000..9b88ad4 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ZBeam-flanged-ubeam-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/ZBeam-thumb.jpg b/extensions/fablabchemnitz/boxes.py/ZBeam-thumb.jpg new file mode 100644 index 0000000..f3034f9 Binary files /dev/null and b/extensions/fablabchemnitz/boxes.py/ZBeam-thumb.jpg differ diff --git a/extensions/fablabchemnitz/boxes.py/ZBeam-thumb.svg b/extensions/fablabchemnitz/boxes.py/ZBeam-thumb.svg new file mode 100644 index 0000000..4684789 --- /dev/null +++ b/extensions/fablabchemnitz/boxes.py/ZBeam-thumb.svg @@ -0,0 +1 @@ + diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.ABox.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.ABox.inx index a106c50..9704ebd 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.ABox.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.ABox.inx @@ -64,7 +64,7 @@ ./ABox-thumb.jpg - + all @@ -72,6 +72,7 @@ + ABox-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.FilamentSpool.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.FilamentSpool.inx index 5e0c126..fba8dfc 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.FilamentSpool.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.FilamentSpool.inx @@ -42,7 +42,7 @@ ./FilamentSpool-thumb.jpg - + all @@ -50,6 +50,7 @@ + FilamentSpool-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.HolePattern.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.HolePattern.inx index 0d3d75e..d0efff2 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.HolePattern.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.HolePattern.inx @@ -52,7 +52,7 @@ ./HolePattern-thumb.jpg - + all @@ -60,6 +60,7 @@ + HolePattern-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.KeyHolder.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.KeyHolder.inx index 297ef9f..7942137 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.KeyHolder.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.KeyHolder.inx @@ -60,7 +60,7 @@ ./KeyHolder-thumb.jpg - + all @@ -68,6 +68,7 @@ + KeyHolder-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.NotesHolder.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.NotesHolder.inx index fd92728..bdc2e5f 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.NotesHolder.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.NotesHolder.inx @@ -54,7 +54,7 @@ ./NotesHolder-thumb.jpg - + all @@ -62,6 +62,7 @@ + NotesHolder-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.SmallPartsTray.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.SmallPartsTray.inx index 982bb6d..a6f8bbf 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.SmallPartsTray.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.SmallPartsTray.inx @@ -62,7 +62,7 @@ ./SmallPartsTray-thumb.jpg - + all @@ -70,6 +70,7 @@ + SmallPartsTray-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.WallPinRow.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.WallPinRow.inx index 6b56300..3f48bc1 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.WallPinRow.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.WallPinRow.inx @@ -9,6 +9,7 @@ + 8 35 @@ -80,11 +81,19 @@ 200.0 1.0 - +5.1 + + + + + +1.0 + + ./WallPinRow-thumb.jpg - + all @@ -92,6 +101,7 @@ + WallPinRow-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes.py.WallStairs.inx b/extensions/fablabchemnitz/boxes.py/boxes.py.WallStairs.inx index cd310e7..01218ee 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes.py.WallStairs.inx +++ b/extensions/fablabchemnitz/boxes.py/boxes.py.WallStairs.inx @@ -9,6 +9,7 @@ + 250/3 40*3 @@ -76,11 +77,19 @@ 200.0 1.0 - +5.1 + + + + + +1.0 + + ./WallStairs-thumb.jpg - + all @@ -88,6 +97,7 @@ + WallStairs-thumb.svg + \ No newline at end of file diff --git a/extensions/fablabchemnitz/boxes.py/boxes/CODE_OF_CONDUCT.md b/extensions/fablabchemnitz/boxes.py/boxes/CODE_OF_CONDUCT.md deleted file mode 100644 index 124e420..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/CODE_OF_CONDUCT.md +++ /dev/null @@ -1 +0,0 @@ -This page is intentionally left blank. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/CONTRIBUTING.rst b/extensions/fablabchemnitz/boxes.py/boxes/CONTRIBUTING.rst deleted file mode 100644 index 07897bd..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/CONTRIBUTING.rst +++ /dev/null @@ -1,182 +0,0 @@ -Contributing to Boxes.py -======================== - -You are thinking about contributing to Boxes.py? That's great! -Boxes.py is designed to be re-used and extended. - -This document gives you some guidelines how your contribution is most -likely to impact the development and your changes are most likely to -be merged into the upstream repository. - -Most of them should be just general best practises and not be -surprising. Don't worry if you find them too complicated. It is OK -leave the final touch to someone else. - -Writing code for Boxes.py -------------------------- - -You will often be compelled to just do a quick thing that will solve -your immediate needs. That's fine. But nevertheless it is often worth -doing things the right way and be able to submit your changes -upstream. For one to give something back to the community. But also -for purely selfish reasons like getting the code maintained. Also -Boxes.py is designed to make doing things properly the easy way. - -Here are some guidelines that make this easier. Depending on what you -are up to they may apply to a varying degree. It's ok to submit -patches that are not quite ready yet. But please state in the pull -request message what you think the status is and whether you want help -or are going to finish it on your own. - -* Please fork the repository at GitHub before getting started -* Start with creating separate branches for each of your new generators or features - - * You can merge them into your master branch to have them all in one place - * Please continue your work in the branches and repeatedly merge them to master - -* Before submitting a pull request intended to go upstream have clean patches that are self contained and error free - - * Re-order and squash patches with *git rebase -i* - * The patches should containing meaningful changes and not (necessarily) reflect how the code was created - * Rebase your branch to the current master branch - * Be prepared that your code may get reworked before being merged upstream - -* Submit a pull request in GitHub based on your feature branch - - * Describe the status of the patch set and your intentions with it in the pull request message - -If you want to discuss your idea open a ticket describing it and ask -questions there. This is encouraged even if you think you know what -you want to do. There are many short cuts in Boxes.py and pointing you -in the right direction may save you a lot of work. - -If you want feed back on you code feel free to open a PR. State that -this is work in progress in the PR message. It's OK if it does not -follow the guidelines (yet). - -Check Code -.......... - -The `pre-commit `_ tool is used to verify the code style. -When installed, it automatically checks and corrects the code before each commit. - -* Install *pre-commit*, e.g. :code:`pip install pre-commit` -* Install githook :code:`pre-commit install` - -For manual check use :code:`pre-commit run --all-files`. - -To remove githook use :code:`pre-commit uninstall`. - -Writing new Generators -...................... - -Writing new generators is the most straight forward thing to do with -Boxes.py. Here are some guidelines that make it easier to get them added: - -* Start with a copy of another generator or *boxes/generators/_template.py* -* Commit changes to the library in separate patches -* Use parameters with sane defaults instead of hard coding dimensions -* Simple generators can end up as one single commit -* For more complicated generators there can be multiple patches - - each adding another feature - -Adding new Dependencies -....................... - -Adding new dependencies should be considered thoroughly. If a new -dependency is added it needs to be added in all these places: - -* *documentation/src/install.rst* -* RST files in *documentation/src/install/* -* *scripts/Dockerfile* - -If it is a Python module it also needs to be added: -* *requirements.txt* -* *setup.py* - -Improving the Documentation ---------------------------- - -Boxes.py comes with Sphinx based documentation that is in large parts -generated from the doc strings in the code. Nevertheless documentation -has a tendency to get outdated. If you encounter outdated pieces of -documentation feel free to submit a pull request or open a ticket -pointing out what should be changed or even suggesting a better text. - -To check your changes docs need to be build with *make html* in -*documentation/src*. This places the compiled documentation in -*documentation/build/html*. You need to have *sphinx* installed for -this to work. - -The online documentation gets build and updated automatically by the Github Actions -as soon as the changes makes it into the GitHub *master* branch. - -Provide photos for generators ------------------------------ - -Many generators still come without an example photo. If you are -creating such an item consider donating a good picture. You can -simply attach it to `ticket #628 -`_. If you want you can -also create a proper pull request instead: - -* Make sure you have sh, ImageMagick (You will need to install legacy utilities for convert), sed and sha256sum installed -* The picture needs to be an jpg file with the name of the generator - (This is case sensitive. Use CamelCase.) -* The picture should be 1200 pixels wide and square or not too far - from square (3:4 is fine). -* Minimize the file size by running it through `Tiny Png `_ -* Place the file in *static/samples/* -* Check if the picture shows up at the bottom of the settings page of - the generator when running *scripts/boxesserver* -* Change dir to *./scripts* and there execute *./gen_thumbnails.sh* -* Check if the thumbnail is seen in the main page when hovering over - the generator entry -* Create a commit including *static/samples/$GeneratorName\*.jpg* and - *static/samples/samples.sha256* -* Create a pull request from that - -Improving the User Interface ----------------------------- - -Coming up with good names and good descriptions is hard. Often writing -a new generator is much easier than coming up with a good name for it -and its arguments. If you think something deserves a better name or -description and you can come up with one please don't hesitate to open -a ticket. It is this small things that make something like Boxes.py -easy or hard to use. - -There is also an - often empty - space for a longer text for each -generator that could house assembling instructions, instructions for -use or just more detailed descriptions. If you are interested in -writing some please open a ticket. Your text does not have to be -perfect. We can work on it together. - -Running the Code ----------------------------- - -To serve website, run :code:`scripts/boxesserver` script. - -You can set the BOXES_GENERATOR_PATH environment variable to add -custom generators if you cannot easily copy them in the sources / -system installation. - -Reporting bugs --------------- - -If you encounter issues with Boxes.py, please open a ticket at -GitHub. Please provide all information necessary to reproduce the -bug. Often this can be the URL of the broken result. If the issue is -easy to spot it may be sufficient to just give a brief -description. Otherwise it can be helpful to attach the resulting SVG, -a screen shot or the error message. Add a "bug" tag to draw additional -attention. - -Suggesting new generators or features -------------------------------------- - -If you have an idea for a new generator or feature please open a -ticket. Give some short rational how or where you would use such a -thing. Try to give a precise description how it should look like and -which features and details are important. The less is left open the -easier it is to implement. You can add an "enhancement" tag. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/LICENSE.txt b/extensions/fablabchemnitz/boxes.py/boxes/LICENSE.txt deleted file mode 100644 index 94a9ed0..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/LICENSE.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/MANIFEST.in b/extensions/fablabchemnitz/boxes.py/boxes/MANIFEST.in deleted file mode 100644 index 58a9fdc..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include README.rst LICENSE.txt -include examples/*.svg -include documentation/presentation.odp -include inkex/*.txt -include po/* -include scripts/boxes2pot scripts/boxes2inkscape scripts/boxes_proxy.py diff --git a/extensions/fablabchemnitz/boxes.py/boxes/README.rst b/extensions/fablabchemnitz/boxes.py/boxes/README.rst deleted file mode 100644 index b6cf699..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/README.rst +++ /dev/null @@ -1,62 +0,0 @@ -About Boxes.py -============== - -+----------------------------------------------+----------------------------------------------+----------------------------------------------+----------------------------------------------+----------------------------------------------+ -| .. image:: static/samples/NotesHolder.jpg | .. image:: static/samples/OttoBody.jpg | .. image:: static/samples/PaintStorage.jpg | .. image:: static/samples/ShutterBox.jpg | .. image:: static/samples/TwoPiece.jpg | -+----------------------------------------------+----------------------------------------------+----------------------------------------------+----------------------------------------------+----------------------------------------------+ - -* Boxes.py is an online box generator - - * https://www.festi.info/boxes.py/index.html - -* Boxes.py is an Inkscape plug-in -* Boxes.py is library to write your own -* Boxes.py is free software licensed under GPL v3+ -* Boxes.py is written in Python and runs with Python 3 - -Boxes.py comes with a growing set of ready-to-use, fully parametrized -generators. See https://florianfesti.github.io/boxes/html/generators.html for the full list. - -+----------------------------------------------+----------------------------------------------+----------------------------------------------+ -| .. image:: static/samples/AngledBox.jpg | .. image:: static/samples/FlexBox2.jpg | .. image:: static/samples/HingeBox.jpg | -+----------------------------------------------+----------------------------------------------+----------------------------------------------+ - -Features --------- - -Boxes.py generates SVG images that can be viewed directly in a web browser but also -postscript and - with pstoedit as external helper - other vector formats -including dxf, plt (aka hpgl) and gcode. - -Of course the library and the generators allow selecting the "thickness" -of the material used and automatically adjusts lengths and width of -joining fingers and other elements. - -The "burn" parameter compensates for the material removed by the laser. This -allows fine tuning the gaps between joins up to the point where plywood -can be press fitted even without any glue. - -Finger Joints are the work horse of the library. They allow 90° edges -and T connections. Their size is scaled up with the material -"thickness" to maintain the same appearance. The library also allows -putting holes and slots for screws (bed bolts) into finger joints, -although this is currently not supported for the included generators. - -Dovetail joints can be used to join pieces in the same plane. - -Flex cuts allows bending and stretching the material in one direction. This -is used for rounded edges and living hinges. - -+----------------------------------------------+----------------------------------------------+----------------------------------------------+ -| .. image:: static/samples/TypeTray.jpg | .. image:: static/samples/BinTray.jpg | .. image:: static/samples/DisplayShelf.jpg | -+----------------------------------------------+----------------------------------------------+----------------------------------------------+ -| .. image:: static/samples/AgricolaInsert.jpg | .. image:: static/samples/HeartBox.jpg | .. image:: static/samples/Atreus21.jpg | -+----------------------------------------------+----------------------------------------------+----------------------------------------------+ - -Documentation -------------- - -Boxes.py comes with Sphinx based documentation for usage, installation -and development. - -The rendered version can be viewed at . diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/Color.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/Color.py deleted file mode 100644 index 884c12b..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/Color.py +++ /dev/null @@ -1,16 +0,0 @@ -class Color: - BLACK = [ 0.0, 0.0, 0.0 ] - BLUE = [ 0.0, 0.0, 1.0 ] - GREEN = [ 0.0, 1.0, 0.0 ] - RED = [ 1.0, 0.0, 0.0 ] - CYAN = [ 0.0, 1.0, 1.0 ] - YELLOW = [ 1.0, 1.0, 0.0 ] - MAGENTA = [ 1.0, 0.0, 1.0 ] - WHITE = [ 1.0, 1.0, 1.0 ] - - # TODO: Make this configurable - OUTER_CUT = BLACK - INNER_CUT = BLUE - ANNOTATIONS = RED - ETCHING = GREEN - ETCHING_DEEP = CYAN diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/__init__.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/__init__.py deleted file mode 100755 index c928017..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/__init__.py +++ /dev/null @@ -1,2988 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from __future__ import annotations - -import argparse -import copy -import gettext -import math -import random -import re -import sys -from argparse import ArgumentParser -from contextlib import contextmanager -from functools import wraps -from shlex import quote -from typing import Any -from xml.sax.saxutils import quoteattr - -import qrcode -from shapely.geometry import * -from shapely.ops import split - -from boxes import edges, formats, gears, parts, pulley -from boxes.Color import * -from boxes.qrcode_factory import BoxesQrCodeFactory -from boxes.vectors import kerf - -### Helpers - -def dist(dx, dy): - """ - Return distance - - :param dx: delta x - :param dy: delay y - """ - return (dx * dx + dy * dy) ** 0.5 - -def restore(func): - """ - Wrapper: Restore coordinates after function - - :param func: function to wrap - """ - - @wraps(func) - def f(self, *args, **kw): - with self.saved_context(): - pt = self.ctx.get_current_point() - func(self, *args, **kw) - self.ctx.move_to(*pt) - - return f - - -def holeCol(func): - """ - Wrapper: color holes differently - - :param func: function to wrap - """ - - @wraps(func) - def f(self, *args, **kw): - if "color" in kw: - color = kw.pop("color") - else: - color = Color.INNER_CUT - - self.ctx.stroke() - with self.saved_context(): - self.set_source_color(color) - func(self, *args, **kw) - self.ctx.stroke() - - return f - - -############################################################################# -### Building blocks -############################################################################# - -class NutHole: - """Draw a hex nut""" - sizes = { - "M1.6": (3.2, 1.3), - "M2": (4, 1.6), - "M2.5": (5, 2.0), - "M3": (5.5, 2.4), - "M4": (7, 3.2), - "M5": (8, 4.7), - "M6": (10, 5.2), - "M8": (13.7, 6.8), - "M10": (16, 8.4), - "M12": (18, 10.8), - "M14": (21, 12.8), - "M16": (24, 14.8), - "M20": (30, 18.0), - "M24": (36, 21.5), - "M30": (46, 25.6), - "M36": (55, 31), - "M42": (65, 34), - "M48": (75, 38), - "M56": (85, 45), - "M64": (95, 51), - } - - def __init__(self, boxes, settings) -> None: - self.boxes = boxes - self.ctx = boxes.ctx - self.settings = settings - - def __getattr__(self, name): - return getattr(self.boxes, name) - - @restore - @holeCol - def __call__(self, size, x=0, y=0, angle=0): - size = self.sizes.get(size, (size,))[0] - side = size / 3 ** 0.5 - self.boxes.moveTo(x, y, angle) - self.boxes.moveTo(-0.5 * side, 0.5 * size, angle) - for i in range(6): - self.boxes.edge(side) - self.boxes.corner(-60) - - -############################################################################## -### Argument types -############################################################################## - -def argparseSections(s): - """ - Parse sections parameter - - :param s: string to parse - """ - - result = [] - - s = re.split(r"\s|:", s) - - try: - for part in s: - m = re.match(r"^(\d+(\.\d+)?)/(\d+)$", part) - if m: - n = int(m.group(3)) - result.extend([float(m.group(1)) / n] * n) - continue - m = re.match(r"^(\d+(\.\d+)?)\*(\d+)$", part) - if m: - n = int(m.group(3)) - result.extend([float(m.group(1))] * n) - continue - result.append(float(part)) - except ValueError: - raise argparse.ArgumentTypeError("Don't understand sections string") - - if not result: - result.append(0.0) - - return result - -class ArgparseEdgeType: - """argparse type to select from a set of edge types""" - - names = edges.getDescriptions() - edges: list[str] = [] - - def __init__(self, edges: str | None = None) -> None: - if edges: - self.edges = list(edges) - - def __call__(self, pattern): - if len(pattern) != 1: - raise ValueError("Edge type can only have one letter.") - if pattern not in self.edges: - raise ValueError("Use one of the following values: " + - ", ".join(edges)) - return pattern - - def html(self, name, default, translate): - options = "\n".join( - """""" % - (e, ' selected="selected"' if e == default else "", - translate("{} {}".format(e, self.names.get(e, "")))) for e in self.edges) - return """\n""".format(name, name, name+"_id", name+"_description", options) - - def inx(self, name, viewname, arg): - return (' \n' % - (name, viewname, quoteattr(arg.help or "")) + - ''.join(' \n'.format( - e, e, self.names.get(e, "")) - for e in self.edges) + - ' \n') - -class BoolArg: - def __call__(self, arg): - if not arg or arg.lower() in ("none", "0", "off", "false"): - return False - return True - - def html(self, name, default, _): - if isinstance(default, (str)): - default = self(default) - return """ -""" % \ - (name, name, name, name+"_id", name+"_description",' checked="checked"' if default else "") - -boolarg = BoolArg() - - -class HexHolesSettings(edges.Settings): - """Settings for hexagonal hole patterns - -Values: - -* absolute - * diameter : 5.0 : diameter of the holes - * distance : 3.0 : distance between the holes - * style : "circle" : currently only supported style - -""" - - absolute_params = { - 'diameter' : 10.0, - 'distance' : 3.0, - 'style' : ('circle', ), - } - - relative_params: dict[str, Any] = {} - -class fillHolesSettings(edges.Settings): - """Settings for Hole filling - -Values: - -* absolute - * fill_pattern : "no fill" : style of hole pattern - * hole_style : "round" : style of holes (does not apply to fill patterns 'vbar' and 'hbar') - * max_random : 1000 : maximum number of random holes - * bar_length : 50 : maximum length of bars - * hole_max_radius : 12.0 : maximum radius of generated holes (in mm) - * hole_min_radius : 4.0 : minimum radius of generated holes (in mm) - * space_between_holes : 4.0 : hole to hole spacing (in mm) - * space_to_border : 4.0 : hole to border spacing (in mm) - -""" - - absolute_params = { - "fill_pattern": ("no fill", "hex", "square", "random", "hbar", "vbar"), - "hole_style": ("round", "triangle", "square", "hexagon", "octagon"), - "max_random": 1000, - "bar_length": 50, - "hole_max_radius": 3.0, - "hole_min_radius": 0.5, - "space_between_holes": 4.0, - "space_to_border": 4.0, - } - -############################################################################## -### Main class -############################################################################## - -class Boxes: - """Main class -- Generator should subclass this """ - - webinterface = True - ui_group = "Misc" - UI = "" - - description: str = "" # Markdown syntax is supported - - def __init__(self) -> None: - self.formats = formats.Formats() - self.ctx = None - description: str = self.__doc__ or "" - if self.description: - description += "\n\n" + self.description - self.argparser = ArgumentParser(description=description) - self.edgesettings: dict[Any, Any] = {} - self.non_default_args: dict[Any, Any] = {} - self.translations = gettext.NullTranslations() - - self.metadata = { - "name" : self.__class__.__name__, - "short_description" : self.__doc__, - "description" : self.description, - "group" : self.ui_group, - "url" : "", - "url_short" : "", - "cli" : "", - "cli_short" : "", - } - - # Dummy attribute for static analytic tools. Will be overwritten by `argparser` at runtime. - self.thickness: float = 0.0 - - self.argparser._action_groups[1].title = self.__class__.__name__ + " Settings" - defaultgroup = self.argparser.add_argument_group( - "Default Settings") - defaultgroup.add_argument( - "--thickness", action="store", type=float, default=3.0, - help="thickness of the material (in mm) [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#thickness)") - defaultgroup.add_argument( - "--output", action="store", type=str, default="box.svg", - help="name of resulting file") - defaultgroup.add_argument( - "--format", action="store", type=str, default="svg", - choices=self.formats.getFormats(), - help="format of resulting file [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#format)") - defaultgroup.add_argument( - "--tabs", action="store", type=float, default=0.0, - help="width of tabs holding the parts in place (in mm)(not supported everywhere) [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#tabs)") - defaultgroup.add_argument( - "--qr_code", action="store", type=boolarg, default=False, - help="Add a QR Code with link or command line to the generated output") - defaultgroup.add_argument( - "--debug", action="store", type=boolarg, default=False, - help="print surrounding boxes for some structures [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#debug)") - defaultgroup.add_argument( - "--labels", action="store", type=boolarg, default=True, - help="label the parts (where available)") - defaultgroup.add_argument( - "--reference", action="store", type=float, default=100, - help="print reference rectangle with given length (in mm)(zero to disable) [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#reference)") - defaultgroup.add_argument( - "--inner_corners", action="store", type=str, default="loop", - choices=["loop", "corner", "backarc"], - help="style for inner corners [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#inner-corners)") - defaultgroup.add_argument( - "--burn", action="store", type=float, default=0.1, - help='burn correction (in mm)(bigger values for tighter fit) [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#burn)') - - @contextmanager - def saved_context(self): - """ - Generator: for saving and restoring contexts. - """ - cr = self.ctx - cr.save() - try: - yield cr - finally: - cr.restore() - - def set_source_color(self, color): - """ - Sets the color of the pen. - """ - self.ctx.set_source_rgb(*color) - - def set_font(self, style, bold=False, italic=False): - """ - Set font style used - :param style: "serif", "sans-serif" or "monospaced" - :param bold: Use bold font - :param italic: Use italic font - """ - self.ctx.set_font(style, bold, italic) - - def open(self): - """ - Prepare for rendering - - Create canvas and edge and other objects - Call this before .render() - """ - if self.ctx is not None: - return - - self.bedBoltSettings = (3, 5.5, 2, 20, 15) # d, d_nut, h_nut, l, l1 - self.surface, self.ctx = self.formats.getSurface(self.format) - - if self.format == 'svg_Ponoko': - self.ctx.set_line_width(0.01) - self.set_source_color(Color.BLUE) - else: - self.ctx.set_line_width(max(2 * self.burn, 0.05)) - self.set_source_color(Color.BLACK) - - self.spacing = 2 * self.burn + 0.5 * self.thickness - self.set_font("sans-serif") - self._buildObjects() - if self.reference and self.format != 'svg_Ponoko': - self.move(self.reference, 10, "up", before=True) - self.ctx.rectangle(0, 0, self.reference, 10) - if self.reference < 80: - self.text(f"{self.reference:.2f}mm, burn:{self.burn:.2f}mm", self.reference + 5, 5, - fontsize=8, align="middle left", color=Color.ANNOTATIONS) - else: - self.text(f"{self.reference:.2f}mm, burn:{self.burn:.2f}mm", self.reference / 2.0, 5, - fontsize=8, align="middle center", color=Color.ANNOTATIONS) - self.move(self.reference, 10, "up") - if self.qr_code: - self.renderQrCode() - self.ctx.stroke() - - def renderQrCode(self): - content = self.metadata['url_short'] or self.metadata["cli_short"] - size = 1.5 - if content: - with self.saved_context(): - self.qrcode(content, box_size=size, move="right") - self.text(text=content, y=6, color=Color.ANNOTATIONS, fontsize=6) - self.qrcode(content, box_size=size, move="up only") - - def buildArgParser(self, *l, **kw): - """ - Add commonly used arguments - - :param l: parameter names - :param kw: parameters with new default values - - Supported parameters are - - * floats: x, y, h, hi - * argparseSections: sx, sy, sh - * ArgparseEdgeType: bottom_edge, top_edge - * boolarg: outside - * str (selection): nema_mount - """ - for arg in l: - kw[arg] = None - for arg, default in kw.items(): - if arg == "x": - if default is None: default = 100.0 - help = "inner width in mm" - if "outside" in kw: - help += " (unless outside selected)" - self.argparser.add_argument( - "--x", action="store", type=float, default=default, - help=help) - elif arg == "y": - if default is None: default = 100.0 - help = "inner depth in mm" - if "outside" in kw: - help += " (unless outside selected)" - self.argparser.add_argument( - "--y", action="store", type=float, default=default, - help=help) - elif arg == "sx": - if default is None: default = "50*3" - self.argparser.add_argument( - "--sx", action="store", type=argparseSections, - default=default, - help="""sections left to right in mm [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#section-parameters)""") - elif arg == "sy": - if default is None: default = "50*3" - self.argparser.add_argument( - "--sy", action="store", type=argparseSections, - default=default, - help="""sections back to front in mm [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#section-parameters)""") - elif arg == "sh": - if default is None: default = "50*3" - self.argparser.add_argument( - "--sh", action="store", type=argparseSections, - default=default, - help="""sections bottom to top in mm [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#section-parameters)""") - elif arg == "h": - if default is None: default = 100.0 - help = "inner height in mm" - if "outside" in kw: - help += " (unless outside selected)" - self.argparser.add_argument( - "--h", action="store", type=float, default=default, - help=help) - elif arg == "hi": - if default is None: default = 0.0 - self.argparser.add_argument( - "--hi", action="store", type=float, default=default, - help="inner height of inner walls in mm (unless outside selected)(leave to zero for same as outer walls)") - elif arg == "hole_dD": - if default is None: default = "3.5:6.5" - self.argparser.add_argument( - "--hole_dD", action="store", type=argparseSections, default=default, - help="mounting hole diameter (shaft:head) in mm [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#mounting-holes)") - elif arg == "bottom_edge": - if default is None: default = "h" - self.argparser.add_argument( - "--bottom_edge", action="store", - type=ArgparseEdgeType("Fhse"), choices=list("Fhse"), - default=default, - help="edge type for bottom edge") - elif arg == "top_edge": - if default is None: default = "e" - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("efFhcESŠikvLtGyY"), choices=list("efFhcESŠikvfLtGyY"), - default=default, help="edge type for top edge") - elif arg == "outside": - if default is None: default = True - self.argparser.add_argument( - "--outside", action="store", type=boolarg, default=default, - help="treat sizes as outside measurements [\U0001F6C8](https://florianfesti.github.io/boxes/html/usermanual.html#outside)") - elif arg == "nema_mount": - if default is None: default = 23 - self.argparser.add_argument( - "--nema_mount", action="store", - type=int, choices=list(sorted(self.nema_sizes.keys())), - default=default, help="NEMA size of motor") - else: - raise ValueError("No default for argument", arg) - - def addSettingsArgs(self, settings, prefix=None, **defaults): - prefix = prefix or settings.__name__[:-len("Settings")] - settings.parserArguments(self.argparser, prefix, **defaults) - self.edgesettings[prefix] = {} - - - def parseArgs(self, args=None): - """ - Parse command line parameters - - :param args: (Default value = None) parameters, None for using sys.argv - """ - if args is None: - args = sys.argv[1:] - - def cliquote(s): - s = s.replace('\r', '') - s = s.replace('\n', "\\n") - return quote(s) - - self.metadata["cli"] = "boxes " + self.__class__.__name__ + " " + " ".join(cliquote(arg) for arg in args) - - for key, value in vars(self.argparser.parse_args(args=args)).items(): - default = self.argparser.get_default(key) - - # treat edge settings separately - for setting in self.edgesettings: - if key.startswith(setting + '_'): - self.edgesettings[setting][key[len(setting)+1:]] = value - continue - setattr(self, key, value) - if (value != default): - self.non_default_args[key] = value - - # Change file ending to format if not given explicitly - format = getattr(self, "format", "svg") - if getattr(self, 'output', None) == 'box.svg': - self.output = 'box.' + format.split("_")[0] - - self.metadata["cli_short"] = "boxes " + self.__class__.__name__ + " " + " ".join(cliquote(arg) for arg in args if (arg.split("=")[0][2:] in self.non_default_args)) - - def addPart(self, part, name=None): - """ - Add Edge or other part instance to this one and add it as attribute - - :param part: Callable - :param name: (Default value = None) attribute name (__name__ as default) - """ - if name is None: - name = part.__class__.__name__ - name = name[0].lower() + name[1:] - # if not hasattr(self, name): - if isinstance(part, edges.BaseEdge): - self.edges[part.char] = part - else: - setattr(self, name, part) - - def addParts(self, parts): - for part in parts: - self.addPart(part) - - def _buildObjects(self): - """Add default edges and parts""" - self.edges = {} - self.addPart(edges.Edge(self, None)) - self.addPart(edges.OutSetEdge(self, None)) - edges.GripSettings(self.thickness).edgeObjects(self) - - # Finger joints - # Share settings object - s = edges.FingerJointSettings(self.thickness, True, - **self.edgesettings.get("FingerJoint", {})) - s.edgeObjects(self) - self.addPart(edges.FingerHoles(self, s), name="fingerHolesAt") - # Stackable - edges.StackableSettings(self.thickness, True, - **self.edgesettings.get("Stackable", {})).edgeObjects(self) - # Dove tail joints - edges.DoveTailSettings(self.thickness, True, - **self.edgesettings.get("DoveTail", {})).edgeObjects(self) - # Flex - s = edges.FlexSettings(self.thickness, True, - **self.edgesettings.get("Flex", {})) - self.addPart(edges.FlexEdge(self, s)) - # Clickable - edges.ClickSettings(self.thickness, True, - **self.edgesettings.get("Click", {})).edgeObjects(self) - # Hinges - edges.HingeSettings(self.thickness, True, - **self.edgesettings.get("Hinge", {})).edgeObjects(self) - edges.ChestHingeSettings(self.thickness, True, - **self.edgesettings.get("ChestHinge", {})).edgeObjects(self) - edges.CabinetHingeSettings(self.thickness, True, - **self.edgesettings.get("CabinetHinge", {})).edgeObjects(self) - # Sliding Lid - edges.SlideOnLidSettings(self.thickness, True, - **self.edgesettings.get("SlideOnLid", {})).edgeObjects(self) - # Rounded Triangle Edge - edges.RoundedTriangleEdgeSettings(self.thickness, True, - **self.edgesettings.get("RoundedTriangleEdge", {})).edgeObjects(self) - # Grooved Edge - edges.GroovedSettings(self.thickness, True, - **self.edgesettings.get("Grooved", {})).edgeObjects(self) - # Mounting Edge - edges.MountingSettings(self.thickness, True, - **self.edgesettings.get("Mounting", {})).edgeObjects(self) - # Handle Edge - edges.HandleEdgeSettings(self.thickness, True, - **self.edgesettings.get("HandleEdge", {})).edgeObjects(self) - # HexHoles - self.hexHolesSettings = HexHolesSettings(self.thickness, True, - **self.edgesettings.get("HexHoles", {})) - # Lids - from . import lids - self.lidSettings = lids.LidSettings(self.thickness, True, - **self.edgesettings.get("Lid", {})) - self.lid = lids.Lid(self, self.lidSettings) - - # Nuts - self.addPart(NutHole(self, None)) - # Gears - self.addPart(gears.Gears(self)) - s = edges.GearSettings(self.thickness, True, - **self.edgesettings.get("Gear", {})) - self.addPart(edges.RackEdge(self, s)) - self.addPart(pulley.Pulley(self)) - self.addPart(parts.Parts(self)) - - def adjustSize(self, l, e1=True, e2=True): - # Char to edge object - e1 = self.edges.get(e1, e1) - e2 = self.edges.get(e2, e2) - - try: - total = sum(l) - walls = (len(l) - 1) * self.thickness - except TypeError: - total = l - walls = 0 - - if isinstance(e1, edges.BaseEdge): - walls += e1.startwidth() + e1.margin() - elif e1: - walls += self.thickness - - if isinstance(e2, edges.BaseEdge): - walls += e2.startwidth() + e2.margin() - elif e2: - walls += self.thickness - - try: - if total > 0.0: - factor = (total - walls) / total - else: - factor = 1.0 - return [s * factor for s in l] - except TypeError: - return l - walls - - def render(self): - """Implement this method in your subclass. - - You will typically need to call .parseArgs() before calling this one - """ - # Change settings and create new Edges and part classes here - raise NotImplementedError - - def cc(self, callback, number, x=0.0, y=None, a=0.0): - """Call callback from edge of a part - - :param callback: callback (callable or list of callables) - :param number: number of the callback - :param x: (Default value = 0.0) x position to be call on - :param y: (Default value = None) y position to be called on (default does burn correction) - """ - if y is None: - y = self.burn - - if hasattr(callback, '__getitem__'): - try: - callback = callback[number] - number = None - except (KeyError, IndexError): - pass - - if callback and callable(callback): - with self.saved_context(): - self.moveTo(x, y, a) - if number is None: - callback() - else: - callback(number) - self.ctx.move_to(0, 0) - - def getEntry(self, param, idx): - """ - Get entry from list or items itself - - :param param: list or item - :param idx: index in list - """ - if isinstance(param, list): - if len(param) > idx: - return param[idx] - else: - return None - else: - return param - - def close(self): - """Finish rendering - - Flush canvas to disk and convert output to requested format if needed. - Call after .render()""" - if self.ctx is None: - return - - self.ctx.stroke() - self.ctx = None - - self.surface.set_metadata(self.metadata) - - self.surface.flush() - data = self.surface.finish(self.inner_corners) - - data = self.formats.convert(data, self.format) - return data - - ############################################################ - ### Turtle graphics commands - ############################################################ - - def corner(self, degrees, radius=0, tabs=0): - """ - Draw a corner - - This is what does the burn corrections - - :param degrees: angle - :param radius: (Default value = 0) - """ - - try: - degrees, radius = degrees - except: - pass - - rad = degrees * math.pi / 180 - - if tabs and self.tabs: - if degrees > 0: - r_ = radius + self.burn - tabrad = self.tabs / max(r_, 0.01) - else: - r_ = radius - self.burn - tabrad = -self.tabs / max(r_, 0.01) - - length = abs(r_ * rad) - tabs = min(tabs, int(length // (tabs*3*self.tabs))) - if tabs and self.tabs: - l = (length - tabs * self.tabs) / tabs - lang = math.degrees(l / r_) - if degrees < 0: - lang = -lang - #print(degrees, radius, l, lang, tabs, math.degrees(tabrad)) - self.corner(lang/2., radius) - for i in range(tabs-1): - self.moveArc(math.degrees(tabrad), r_) - self.corner(lang, radius) - if tabs: - self.moveArc(math.degrees(tabrad), r_) - self.corner(lang/2., radius) - return - - if ((radius > 0.5* self.burn and abs(degrees) > 36) or - (abs(degrees) > 100)): - steps = int(abs(degrees)/ 36.) + 1 - for i in range(steps): - self.corner(float(degrees)/steps, radius) - return - - if degrees > 0: - self.ctx.arc(0, radius + self.burn, radius + self.burn, - -0.5 * math.pi, rad - 0.5 * math.pi) - elif radius > self.burn: - self.ctx.arc_negative(0, -(radius - self.burn), radius - self.burn, - 0.5 * math.pi, rad + 0.5 * math.pi) - else: # not rounded inner corner - self.ctx.arc_negative(0, self.burn - radius, self.burn - radius, - -0.5 * math.pi, -0.5 * math.pi + rad) - - self._continueDirection(rad) - - def edge(self, length, tabs=0): - """ - Simple line - :param length: length in mm - """ - self.ctx.move_to(0, 0) - if tabs and self.tabs: - if self.tabs > length: - self.ctx.move_to(length, 0) - else: - tabs = min(tabs, max(1, int(length // (tabs*3*self.tabs)))) - l = (length - tabs * self.tabs) / tabs - self.ctx.line_to(0.5*l, 0) - for i in range(tabs-1): - self.ctx.move_to((i+0.5)*l+self.tabs, 0) - self.ctx.line_to((i+0.5)*l+self.tabs+l, 0) - if tabs == 1: - self.ctx.move_to((tabs-0.5)*l+self.tabs, 0) - else: - self.ctx.move_to((tabs-0.5)*l+2*self.tabs, 0) - - self.ctx.line_to(length, 0) - else: - self.ctx.line_to(length, 0) - self.ctx.translate(*self.ctx.get_current_point()) - - def step(self, out): - """ - Create a parallel step perpendicular to the current direction - Positive values move to the outside of the part - """ - if out > 1E-5: - self.corner(-90) - self.edge(out) - self.corner(90) - elif out < -1E-5: - self.corner(90) - self.edge(-out) - self.corner(-90) - - def curveTo(self, x1, y1, x2, y2, x3, y3): - """control point 1, control point 2, end point - - :param x1: - :param y1: - :param x2: - :param y2: - :param x3: - :param y3: - """ - self.ctx.curve_to(x1, y1, x2, y2, x3, y3) - dx = x3 - x2 - dy = y3 - y2 - rad = math.atan2(dy, dx) - self._continueDirection(rad) - - def polyline(self, *args): - """ - Draw multiple connected lines - - :param args: Alternating length in mm and angle in degrees. - - lengths may be a tuple (length, #tabs) - angles may be tuple (angle, radius) - """ - for i, arg in enumerate(args): - if i % 2: - if isinstance(arg, tuple): - self.corner(*arg) - else: - self.corner(arg) - else: - if isinstance(arg, tuple): - self.edge(*arg) - else: - self.edge(arg) - - def bedBoltHole(self, length, bedBoltSettings=None, tabs=0): - """ - Draw an edge with slot for a bed bolt - - :param length: length of the edge in mm - :param bedBoltSettings: (Default value = None) Dimensions of the slot - """ - d, d_nut, h_nut, l, l1 = bedBoltSettings or self.bedBoltSettings - self.edge((length - d) / 2.0, tabs=tabs//2) - self.corner(90) - self.edge(l1) - self.corner(90) - self.edge((d_nut - d) / 2.0) - self.corner(-90) - self.edge(h_nut) - self.corner(-90) - self.edge((d_nut - d) / 2.0) - self.corner(90) - self.edge(l - l1 - h_nut) - self.corner(-90) - self.edge(d) - self.corner(-90) - self.edge(l - l1 - h_nut) - self.corner(90) - self.edge((d_nut - d) / 2.0) - self.corner(-90) - self.edge(h_nut) - self.corner(-90) - self.edge((d_nut - d) / 2.0) - self.corner(90) - self.edge(l1) - self.corner(90) - self.edge((length - d) / 2.0, tabs=tabs-(tabs//2)) - - def edgeCorner(self, edge1, edge2, angle=90): - """Make a corner between two Edges. Take width of edges into account""" - edge1 = self.edges.get(edge1, edge1) - edge2 = self.edges.get(edge2, edge2) - - self.edge(edge2.startwidth() * math.tan(math.radians(angle/2.))) - self.corner(angle) - self.edge(edge1.endwidth() * math.tan(math.radians(angle/2.))) - - def regularPolygon(self, corners=3, radius=None, h=None, side=None): - """Give measures of a regular polygon - - :param corners: number of corners of the polygon - :param radius: distance center to one of the corners - :param h: distance center to one of the sides (height of sector) - :param side: length of one side - :return: (radius, h, side) - """ - if radius: - side = 2 * math.sin(math.radians(180.0/corners)) * radius - h = radius * math.cos(math.radians(180.0/corners)) - elif h: - side = 2 * math.tan(math.radians(180.0/corners)) * h - radius = ((side/2.)**2+h**2)**0.5 - elif side: - h = 0.5 * side * math.tan(math.radians(90-180./corners)) - radius = ((side/2.)**2+h**2)**0.5 - - return radius, h, side - - @restore - def regularPolygonAt(self, x, y, corners, angle=0, r=None, h=None, side=None): - """Draw regular polygon""" - self.moveTo(x, y, angle) - r, h, side = self.regularPolygon(corners, r, h, side) - self.moveTo(-side/2.0, -h-self.burn) - for i in range(corners): - self.edge(side) - self.corner(360./corners) - - def regularPolygonWall(self, corners=3, r=None, h=None, side=None, - edges='e', hole=None, callback=None, move=None): - """Create regular polygon as a wall - - :param corners: number of corners of the polygon - :param r: radius distance center to one of the corners - :param h: distance center to one of the sides (height of sector) - :param side: length of one side - :param edges: (Default value = "e", may be string/list of length corners) - :param hole: diameter of central hole (Default value = 0) - :param callback: (Default value = None, middle=0, then sides=1..) - :param move: (Default value = None) - """ - r, h, side = self.regularPolygon(corners, r, h, side) - - t = self.thickness - - if not hasattr(edges, "__getitem__") or len(edges) == 1: - edges = [edges] * corners - edges = [self.edges.get(e, e) for e in edges] - edges += edges # append for wrapping around - - if corners % 2: - th = r + h + edges[0].spacing() + ( - max(edges[corners//2].spacing(), - edges[corners//2+1].spacing()) / - math.sin(math.radians(90-180/corners))) - else: - th = 2*h + edges[0].spacing() + edges[corners//2].spacing() - - tw = 0 - for i in range(corners): - ang = (180+360*i)/corners - tw = max(tw, 2*abs(math.sin(math.radians(ang))* - (r + max(edges[i].spacing(), edges[i+1].spacing())/ - math.sin(math.radians(90-180/corners))))) - - if self.move(tw, th, move, before=True): - return - - self.moveTo(0.5*tw-0.5*side, edges[0].margin()) - - - if hole: - self.hole(side/2., h+edges[0].startwidth() + self.burn, hole/2.) - self.cc(callback, 0, side/2., h+edges[0].startwidth() + self.burn) - for i in range(corners): - self.cc(callback, i+1, 0, edges[i].startwidth() + self.burn) - edges[i](side) - self.edgeCorner(edges[i], edges[i+1], 360.0/corners) - - self.move(tw, th, move) - - def grip(self, length, depth): - """Corrugated edge useful as a gipping area - - :param length: length - :param depth: depth of the grooves - """ - grooves = max(int(length // (depth * 2.0)) + 1, 1) - depth = length / grooves / 4.0 - for groove in range(grooves): - self.corner(90, depth) - self.corner(-180, depth) - self.corner(90, depth) - - def _latchHole(self, length): - """ - :param length: - """ - self.edge(1.1 * self.thickness) - self.corner(-90) - self.edge(length / 2.0 + 0.2 * self.thickness) - self.corner(-90) - self.edge(1.1 * self.thickness) - - def _latchGrip(self, length, extra_length=0.0): - """ - :param length: - """ - self.corner(90, self.thickness / 4.0) - self.grip(length / 2.0 - self.thickness / 2.0 - 0.2 * self.thickness + extra_length, self.thickness / 2.0) - self.corner(90, self.thickness / 4.0) - - def latch(self, length, positive=True, reverse=False, extra_length=0.0): - """Latch to fix a flex box door to the box - - :param length: length in mm - :param positive: (Default value = True) False: Door side; True: Box side - :param reverse: (Default value = False) True when running away from the latch - """ - t = self.thickness - if positive: - poly = [0, -90, t, 90, length / 2.0, 90, t, -90, length / 2.] - if reverse: - poly = list(reversed(poly)) - self.polyline(*poly) - else: - if reverse: - self._latchGrip(length, extra_length) - else: - self.corner(90) - self._latchHole(length) - if not reverse: - self._latchGrip(length, extra_length) - else: - self.corner(90) - - def handle(self, x, h, hl, r=30): - """Creates an Edge with a handle - - :param x: width in mm - :param h: height in mm - :param hl: height if th grip hole - :param r: (Default value = 30) radius of the corners - """ - d = (x - hl - 2 * r) / 2.0 - - # Hole - with self.saved_context(): - self.moveTo(d + 2 * r, 0) - self.edge(hl - 2 * r) - self.corner(-90, r) - self.edge(h - 3 * r) - self.corner(-90, r) - self.edge(hl - 2 * r) - self.corner(-90, r) - self.edge(h - 3 * r) - self.corner(-90, r) - - self.moveTo(0, 0) - - self.curveTo(d, 0, d, 0, d, -h + r) - self.curveTo(r, 0, r, 0, r, r) - self.edge(hl) - self.curveTo(r, 0, r, 0, r, r) - self.curveTo(h - r, 0, h - r, 0, h - r, -d) - - ### Navigation - - def moveTo(self, x, y=0.0, degrees=0): - """ - Move coordinate system to given point - - :param x: - :param y: (Default value = 0.0) - :param degrees: (Default value = 0) - """ - self.ctx.move_to(0, 0) - self.ctx.translate(x, y) - self.ctx.rotate(degrees * math.pi / 180.0) - self.ctx.move_to(0, 0) - - def moveArc(self, angle, r=0.0): - """ - :param angle: - :param r: (Default value = 0.0) - """ - if r < 0: - r = -r - angle = -angle - - rad = math.radians(angle) - if angle > 0: - self.moveTo(r*math.sin(rad), - r*(1-math.cos(rad)), angle) - else: - self.moveTo(r*math.sin(-rad), - -r*(1-math.cos(rad)), angle) - - def _continueDirection(self, angle=0): - """ - Set coordinate system to current position (end point) - - :param angle: (Default value = 0) heading - """ - self.ctx.translate(*self.ctx.get_current_point()) - self.ctx.rotate(angle) - - def move(self, x, y, where, before=False, label=""): - """Intended to be used by parts - where can be combinations of "up" or "down", "left" or "right", "only", - "mirror" and "rotated" - when "only" is included the move is only done when before is True - "mirror" will flip the part along the y-axis - "rotated" draws the parts rotated 90 counter clockwise - The function returns whether actual drawing of the part - should be omitted. - - :param x: width of part - :param y: height of part - :param where: which direction to move - :param before: (Default value = False) called before or after part being drawn - """ - if not where: - where = "" - - terms = where.split() - dontdraw = before and "only" in terms - - x += self.spacing - y += self.spacing - - if "rotated" in terms: - x, y = y, x - - moves = { - "up": (0, y, False), - "down": (0, -y, True), - "left": (-x, 0, True), - "right": (x, 0, False), - "only": (0, 0, None), - "mirror": (0, 0, None), - "rotated": (0, 0, None), - } - - if not before: - # restore position - self.ctx.restore() - if self.labels and label: - self.text(label, x/2, y/2, align="middle center", color=Color.ANNOTATIONS, fontsize=4) - self.ctx.stroke() - - for term in terms: - if not term in moves: - raise ValueError("Unknown direction: '%s'" % term) - mx, my, movebeforeprint = moves[term] - if movebeforeprint and before: - self.moveTo(mx, my) - elif (not movebeforeprint and not before) or dontdraw: - self.moveTo(mx, my) - if not dontdraw: - if before: - # paint debug rectangle - if self.debug: - with self.saved_context(): - self.set_source_color(Color.ANNOTATIONS) - self.ctx.rectangle(0, 0, x, y) - # save position - self.ctx.save() - if "rotated" in terms: - self.moveTo(x, 0, 90) - x, y = y, x # change back for "mirror" - if "mirror" in terms: - self.moveTo(x, 0) - self.ctx.scale(-1, 1) - self.moveTo(self.spacing / 2.0, self.spacing / 2.0) - self.ctx.new_part() - - return dontdraw - - @restore - def circle(self, x, y, r): - """ - Draw a round disc - - :param x: position - :param y: position - :param r: radius - """ - r += self.burn - self.moveTo(x + r, y) - a = 0 - n = 10 - da = 2 * math.pi / n - for i in range(n): - self.ctx.arc(-r, 0, r, a, a+da) - a += da - self.ctx.stroke() - - @restore - @holeCol - def regularPolygonHole(self, x, y, r=0.0, d=0.0, n=6, a=0.0, tabs=0, corner_radius=0.0): - """ - Draw a hole in shape of an n-edged regular polygon - - :param x: position - :param y: position - :param r: radius - :param n: number of edges - :param a: rotation angle - """ - - if not r: - r = d / 2.0 - - if n == 0: - self.hole(x, y, r=r, tabs=tabs) - return - - if r < self.burn: - r = self.burn + 1E-9 - r_ = r - self.burn - - if corner_radius < self.burn: - corner_radius = self.burn - cr_ = corner_radius - self.burn - - side_length = 2 * r_ * math.sin(math.pi / n) - apothem = r_ * math.cos(math.pi / n) - # the corner chord: - s = math.sqrt(2 * math.pow(cr_, 2) * (1 - math.cos(2 * math.pi / n))) - # the missing portion of the rounded corner: - b = math.sin(math.pi / n) / math.sin(2 * math.pi / n) * s - # the flat portion of the side: - flat_side_length = side_length - 2 * b - - self.moveTo(x, y, a) - self.moveTo(r_, 0, 90+180/n) - self.moveTo(b, 0, 0) - for _ in range(n): - self.edge(flat_side_length) - self.corner(360/n, cr_) - - @restore - @holeCol - def hole(self, x, y, r=0.0, d=0.0, tabs=0): - """ - Draw a round hole - - :param x: position - :param y: position - :param r: radius - """ - - if not r: - r = d / 2.0 - if r < self.burn: - r = self.burn + 1E-9 - r_ = r - self.burn - self.moveTo(x + r_, y, -90) - self.corner(-360, r, tabs) - - @restore - @holeCol - def rectangularHole(self, x, y, dx, dy, r=0, center_x=True, center_y=True): - """ - Draw a rectangular hole - - :param x: position - :param y: position - :param dx: width - :param dy: height - :param r: (Default value = 0) radius of the corners - :param center_x: (Default value = True) if True, x position is the center, else the start - :param center_y: (Default value = True) if True, y position is the center, else the start - """ - r = min(r, dx/2., dy/2.) - x_start = x if center_x else x + dx / 2.0 - y_start = y - dy / 2.0 if center_y else y - self.moveTo(x_start, y_start + self.burn, 180) - self.edge(dx / 2.0 - r) # start with an edge to allow easier change of inner corners - for d in (dy, dx, dy, dx / 2.0 + r): - self.corner(-90, r) - self.edge(d - 2 * r) - - @restore - @holeCol - def dHole(self, x, y, r=None, d=None, w=None, rel_w=0.75, angle=0): - """ - Draw a hole for a shaft with flat edge - D shaped hole - - :param x: center position - :param y: center position - :param r: radius (overrides d) - :param d: diameter - :param w: width measured against flat side in mm - :param rel_w: width in percent - :param angle: orientation (rotation) of the flat side - """ - - if r is None: - r = d / 2.0 - if w is None: - w = 2.0 * r * rel_w - w -= r - if r <= 0.0: - return - if abs(w) > r: - return self.hole(x, y, r) - - a = math.degrees(math.acos(w / r)) - self.moveTo(x, y, angle-a) - self.moveTo(r-self.burn, 0, -90) - self.corner(-360+2*a, r) - self.corner(-a) - self.edge(2*r*math.sin(math.radians(a))) - - @restore - @holeCol - def flatHole(self, x, y, r=None, d=None, w=None, rel_w=0.75, angle=0): - """ - Draw a hole for a shaft with two opposed flat edges - ( ) shaped hole - - :param x: center position - :param y: center position - :param r: radius (overrides d) - :param d: diameter - :param w: width measured against flat side in mm - :param rel_w: width in percent - :param angle: orientation (rotation) of the flat sides - """ - - if r is None: - r = d / 2.0 - if w is None: - w = r * rel_w - else: - w = w / 2.0 - - if r < 0.0: - return - if abs(w) > r: - return self.hole(x, y, r) - - a = math.degrees(math.acos(w / r)) - self.moveTo(x, y, angle-a) - self.moveTo(r-self.burn, 0, -90) - for i in range(2): - self.corner(-180+2*a, r) - self.corner(-a) - self.edge(2*r*math.sin(math.radians(a))) - self.corner(-a) - - @restore - @holeCol - def mountingHole(self, x, y, d_shaft, d_head=0.0, angle=0, tabs=0): - """ - Draw a pear shaped mounting hole for sliding over a screw head. Total height = 1.5* d_shaft + d_head - - :param x: position - :param y: position - :param d_shaft: diameter of the screw shaft - :param d_head: diameter of the screw head - :param angle: rotation angle of the hole - """ - - if d_shaft < (2 * self.burn): - return # no hole if diameter is smaller then the capabilities of the machine - - if not d_head or d_head < (2 * self.burn): # if no head diameter is given - self.hole(x, y ,d=d_shaft, tabs=tabs) # only a round hole is generated - return - - rs = d_shaft / 2 - rh = d_head / 2 - - self.moveTo(x, y, angle) - self.moveTo(0, rs - self.burn, 0) - self.corner(-180, rs, tabs) - self.edge(2 * rs,tabs) - a = math.degrees(math.asin(rs / rh)) - self.corner(90 - a, 0, tabs) - self.corner(-360 + 2 * a, rh, tabs) - self.corner(90 - a, 0, tabs) - self.edge(2 * rs, tabs) - - @restore - def text(self, text, x=0, y=0, angle=0, align="", fontsize=10, color=[0.0, 0.0, 0.0], font="Arial"): - """ - Draw text - - :param text: text to render - :param x: (Default value = 0) - :param y: (Default value = 0) - :param angle: (Default value = 0) - :param align: (Default value = "") string with combinations of (top|middle|bottom) and (left|center|right) separated by a space - """ - self.moveTo(x, y, angle) - text = text.split("\n") - - lines = len(text) - height = lines * fontsize + (lines - 1) * 0.4 * fontsize - align = align.split() - halign = "left" - moves = { - "top": -height, - "middle": -0.5 * height, - "bottom": 0, - "left": "left", - "center": "middle", - "right": "end", - } - for a in align: - if a in moves: - if isinstance(moves[a], str): - halign = moves[a] - else: - self.moveTo(0, moves[a]) - else: - raise ValueError("Unknown alignment: %s" % align) - - for line in reversed(text): - self.ctx.show_text(line, fs=fontsize, align=halign, rgb=color, font=font) - self.moveTo(0, 1.4 * fontsize) - - tx_sizes = { - 1 : 0.61, - 2 : 0.70, - 3 : 0.82, - 4 : 0.96, - 5 : 1.06, - 6 : 1.27, - 7 : 1.49, - 8 : 1.75, - 9 : 1.87, - 10 : 2.05, - 15 : 2.40, - 20 : 2.85, - 25 : 3.25, - 30 : 4.05, - 40 : 4.85, - 45 : 5.64, - 50 : 6.45, - 55 : 8.05, - 60 : 9.60, - 70 : 11.20, - 80 : 12.80, - 90 : 14.40, - 100 : 16.00, - } - - @restore - @holeCol - def TX(self, size, x=0, y=0, angle=0): - """Draw a star pattern - - :param size: 1 to 100 - :param x: (Default value = 0) - :param y: (Default value = 0) - :param angle: (Default value = 0) - """ - self.moveTo(x, y, angle) - - size = self.tx_sizes.get(size, 0) - ri = 0.5 * size * math.tan(math.radians(30)) - ro = ri * (2**0.5-1) - - self.moveTo(size * 0.5 - self.burn, 0, -90) - for i in range(6): - self.corner(45, ri) - self.corner(-150, ro) - self.corner(45, ri) - - nema_sizes = { - # motor,flange, holes, screws - 8: (20.3, 16, 15.4, 3), - 11: (28.2, 22, 23, 4), - 14: (35.2, 22, 26, 4), - 16: (39.2, 22, 31, 4), - 17: (42.2, 22, 31, 4), - 23: (56.4, 38.1, 47.1, 5.2), - 24: (60, 36, 49.8, 5.1), - 34: (86.3, 73, 69.8, 6.6), - 42: (110, 55.5, 89, 8.5), - } - - @restore - def NEMA(self, size, x=0, y=0, angle=0, screwholes=None): - """Draw holes for mounting a NEMA stepper motor - - :param size: Nominal size in tenths of inches - :param x: (Default value = 0) - :param y: (Default value = 0) - :param angle: (Default value = 0) - :param screwholes: - """ - width, flange, holedistance, diameter = self.nema_sizes[size] - if screwholes: - diameter = screwholes - self.moveTo(x, y, angle) - if self.debug: - self.rectangularHole(0, 0, width, width) - self.hole(0, 0, 0.5 * flange) - for x in (-1, 1): - for y in (-1, 1): - self.hole(x * 0.5 * holedistance, - y * 0.5 * holedistance, - 0.5 * diameter) - - def drawPoints(self, lines, kerfdir=1, close=True): - - if not lines: - return - - if kerfdir != 0: - lines = kerf(lines, self.burn*kerfdir, closed=close) - - self.ctx.save() - self.ctx.move_to(*lines[0]) - - for x, y in lines[1:]: - self.ctx.line_to(x, y) - - if close: - self.ctx.line_to(*lines[0]) - self.ctx.restore() - - def qrcode(self, content, box_size=1.0, color=Color.ETCHING, move=None): - q = qrcode.QRCode(image_factory=BoxesQrCodeFactory, box_size=box_size*10) - q.add_data(content) - m = q.get_matrix() - tw, th = len(m) * box_size, len(m[0]) * box_size - if self.move(tw, th, move, True): - return - - self.set_source_color(color) - q.make_image(ctx=self.ctx) - - self.move(tw, th, move) - - @restore - def showBorderPoly(self,border,color=Color.ANNOTATIONS): - """ - draw border polygon (for debugging only) - - :param border: array with coordinate [(x0,y0), (x1,y1),...] of the border polygon - :param color: - """ - self.set_source_color(color) - self.ctx.save() - self.ctx.move_to(*border[0]) - - for x, y in border[1:]: - self.ctx.line_to(x, y) - - self.ctx.line_to(*border[0]) - self.ctx.restore() - - i = 0 - for x, y in border: - i += 1 - self.hole(x, y, 0.5, color=color) - self.text(str(i), x, y, fontsize=2, color=color) - - @restore - @holeCol - def fillHoles(self, pattern, border, max_radius, hspace=3, bspace=0, min_radius=0.5, style="round", bar_length=50, max_random=1000): - """ - fill a polygon defined by its outline with holes - - :param pattern: defines the hole pattern - currently "random", "hex", "square" "hbar" or "vbar" are supported - :param border: array with coordinate [(x0,y0), (x1,y1),...] of the border polygon - :param max_radius: maximum hole radius - :param hspace: space between holes - :param bspace: space to border - :param min_radius: minimum hole radius - :param style: defines hole style - currently one of "round", "triangle", "square", "hexagon" or "octagon" - :param bar_length: maximum bar length - :param max_random: maximum number of random holes - """ - if pattern not in ["random", "hex", "square", "hbar", "vbar"]: - return - - a = 0 - if style == "round": - n = 0 - elif style == "triangle": - n = 3 - a = 60 - elif style == "square": - n = 4 - elif style == "hexagon": - n = 6 - a = 30 - elif style == "octagon": - n = 8 - a = 22.5 - else: - raise ValueError("fillHoles - unknown hole style: %s)" % style) - -# note to myself: ^y x> - - if self.debug: - self.showBorderPoly(border) - - borderPoly = Polygon(border) - min_x, min_y, max_x, max_y = borderPoly.bounds - - if pattern == "vbar": - border = [(max_y - y + min_y, x) for x, y in border] - borderPoly = Polygon(border) - min_x, min_y, max_x, max_y = borderPoly.bounds - self.moveTo(0, max_x + min_x, -90) - pattern = "hbar" - if self.debug: - self.showBorderPoly(border, color=Color.MAGENTA) - - row = 0 - i = 0 - - # calc the next smaller radius to fit an 'optimum' number of circles - # for x direction - nx = math.ceil((max_x - min_x - 2 * bspace + hspace) / (2 * max_radius + hspace)) - max_radius_x = (max_x - min_x - 2 * bspace - (nx - 1) * hspace) / nx / 2 - - # for y direction - if pattern == "hex": - ny = math.ceil((max_y - min_y - 2 * bspace - 2 * max_radius) / (math.sqrt(3) / 2 * (2 * max_radius + hspace))) - max_radius_y = (max_y - min_y - 2 * bspace - math.sqrt(3) / 2 * ny * hspace) / (math.sqrt(3) * ny + 2 ) - else: - ny = math.ceil((max_y - min_y - 2 * bspace + hspace) / (2 * max_radius + hspace)) - max_radius_y = (max_y - min_y - 2 * bspace - (ny - 1) * hspace) / ny / 2 - - if pattern == "random": - grid = {} - misses = 0 # in a row - while i < max_random and misses < 20: - i += 1 - misses += 1 - # random new point - x = random.randrange(math.floor(min_x + bspace), math.ceil(max_x - bspace)) # randomness takes longer to compute - y = random.randrange(math.floor(min_y + bspace), math.ceil(max_y - bspace)) # but generates a new pattern for each run - pt = Point(x, y).buffer(min_radius + bspace) - # check if point is within border - if borderPoly.contains(pt): - pt1 = Point(x, y) - grid_x = int(x//(2*max_radius+hspace)) - grid_y = int(y//(2*max_radius+hspace)) - # compute distance between hole and border - bdist = borderPoly.exterior.distance(pt1) - bspace - # compute minimum distance to all other holes - hdist = max_radius - try: # learned from https://medium.com/techtofreedom/5-ways-to-break-out-of-nested-loops-in-python-4c505d34ace7 - for gx in (-1, 0, 1): - for gy in (-1, 0, 1): - for pt2 in grid.get((grid_x+gx, grid_y+gy), []): - pt3 = Point(pt2.x, pt2.y) - hdist = min(hdist, pt1.distance(pt3) - pt2.z - hspace) - if hdist < min_radius: - hdist = 0 - raise StopIteration - except StopIteration: - pass - # find maximum radius depending on distances - r = min(bdist, hdist) - # if too small, dismiss cycle - if r < min_radius: - continue - # if too large, limit to max size - if r > max_radius: - r = max_radius - # store in grid with radius as z value - grid.setdefault((grid_x, grid_y), []).append( - Point(x, y, r)) - misses = 0 - # and finally paint the hole - self.regularPolygonHole(x, y, r=r, n=n, a=a) - # rinse and repeat - - elif pattern in ("square", "hex"): - # use 'optimum' hole size - max_radius = min(max_radius_x, max_radius_y) - - # check if at least one line fits (we do horizontal filling) - if (max_y - min_y) < (2 * max_radius + 2 * bspace): - return - - # make cutPolys a little wider to avoid - # overlapping with lines to be cut - outerCutPoly = borderPoly.buffer(-1 * (bspace - 0.000001), - join_style=2) - outerTestPoly = borderPoly.buffer(-1 * (bspace - 0.01), - join_style=2) - # shrink original polygon to get place for full size polygons - innerCutPoly = borderPoly.buffer(-1 * (bspace + max_radius - 0.0001), join_style=2) - innerTestPoly = borderPoly.buffer(-1 * (bspace + max_radius - 0.001), join_style=2) - - # get left and right boundaries of cut polygon - x_cpl, y_cpl, x_cpr, y_cpr = outerCutPoly.bounds - - if self.debug: - self.showBorderPoly(list(outerCutPoly.exterior.coords)) - self.showBorderPoly(list(innerCutPoly.exterior.coords)) - - # set startpoint - y = min_y + bspace + max_radius_y - - while y < (max_y - bspace - max_radius_y): - if pattern == "square" or row % 2 == 0: - xs = min_x + bspace + max_radius_x - else: - xs = min_x + max_radius_x * 2 + hspace / 2 + bspace - - # create line segments cut by the polygons - line_complete = LineString([(x_cpl, y), (max_x + 1, y)]) - # cut accurate - outer_line_split = split(line_complete, outerCutPoly) - line_complete = LineString([(x_cpl, y), (max_x + 1, y)]) - inner_line_split = split(line_complete, innerCutPoly) - inner_line_index = 0 - - if self.debug and False: - for line in inner_line_split.geoms: - self.hole(line.bounds[0], line.bounds[1], 1.1) - self.hole(line.bounds[2], line.bounds[3], .9) - - # process each line - for line_this in outer_line_split.geoms: - - if self.debug and False: # enable to debug missing lines - x_start, y_start, x_end, y_end = line_this.bounds - with self.saved_context(): - self.moveTo(x_start, y_start ,0) - self.hole(0, 0, 0.5) - self.edge(x_end - x_start) - with self.saved_context(): - self.moveTo(x_start, y_start ,0) - self.text(str(outerTestPoly.contains(line_this)), 0, 0, fontsize=2, color=Color.ANNOTATIONS) - with self.saved_context(): - self.moveTo(x_end, y_end ,0) - self.hole(0, 0, 0.5) - - if not outerTestPoly.contains(line_this): - continue - x_start, y_start , x_end, y_end = line_this.bounds - #initialize walking x coordinate - xw = (math.ceil((x_start - xs) / (2 * max_radius_x + hspace)) * (2 * max_radius_x + hspace)) + xs - - # look up matching inner line - while (inner_line_index < len(inner_line_split) and - (inner_line_split.geoms[inner_line_index].bounds[2] < xw - or not innerTestPoly.contains(inner_line_split.geoms[inner_line_index]))): - inner_line_index += 1 - - # and process line - while not xw > x_end: - # are we in inner polygon already? - if (len(inner_line_split) > inner_line_index and - xw > inner_line_split.geoms[inner_line_index].bounds[0]): - # place inner, full size polygons - while xw < inner_line_split.geoms[inner_line_index].bounds[2]: - self.regularPolygonHole(xw, y, r=max_radius, n=n, a=a) - xw += (2 * max_radius_x + hspace) - # forward to next inner line - while (inner_line_index < len(inner_line_split) and - (inner_line_split.geoms[inner_line_index].bounds[0] < xw - or not innerTestPoly.contains(inner_line_split.geoms[inner_line_index]))): - inner_line_index += 1 - if xw > x_end: - break - - # Check distance to border to size the polygon - pt = Point(xw, y) - r = min(borderPoly.exterior.distance(pt) - bspace, - max_radius) - # if too small, dismiss - if r >= min_radius: - self.regularPolygonHole(xw, y, r=r, n=n, a=a) - xw += (2 * max_radius_x + hspace) - - row += 1 - if pattern == "square": - y += 2 * max_radius_y + hspace - 0.0001 - else: - y += (math.sqrt(3) / 2 * (2 * max_radius_y + hspace)) - 0.0001 - - elif pattern == "hbar": - # 'optimum' hole size to be used - max_radius = max_radius_y - # check if at least one bar fits - if (max_y - min_y) < (2 * max_radius + 2 * bspace): - return - - #shrink original polygon - shrinkPoly = borderPoly.buffer(-1 * (bspace + max_radius - 0.01), join_style=2) - cutPoly = borderPoly.buffer(-1 * (bspace + max_radius - 0.000001), join_style=2) - - if self.debug: - self.showBorderPoly(list(shrinkPoly.exterior.coords)) - - segment_length = [bar_length / 2, bar_length] - segment_max = 1 - segment_toggle = False - - # set startpoint - y = min_y + bspace + max_radius - # and calc step width - step_y = 2 * max_radius_y + hspace - 0.0001 - - while y < (max_y - bspace - max_radius): - # toggle segment length each new line - if segment_toggle: - segment_max = 0 - segment_toggle ^= 1 - - # create line from left to right and cut according to shrunk polygon - line_complete = LineString([(min_x - 1, y), (max_x + 1, y)]) - line_split = split(line_complete, cutPoly) - - # process each line - for line_this in line_split.geoms: - - if self.debug and False: # enable to debug missing lines - x_start, y_start , x_end, y_end = line_this.bounds - with self.saved_context(): - self.moveTo(x_start, y_start ,0) - self.hole(0, 0, 0.5) - self.edge(x_end - x_start) - with self.saved_context(): - self.moveTo(x_start, y_start ,0) - self.text(str(shrinkPoly.contains(line_this)), 0, 0, fontsize=2, color=Color.ANNOTATIONS) - with self.saved_context(): - self.moveTo(x_end, y_end ,0) - self.hole(0, 0, 0.5) - - if shrinkPoly.contains(line_this): - # long segment are cut down further - if line_this.length > segment_length[segment_max]: - line_working = line_this - length = line_working.length - while length > 0: - x_start, y_start , xw_end, yw_end = line_working.bounds - # calculate point with required distance from start point - p = line_working.interpolate(segment_length[segment_max]) - # and use its coordinates as endpoint for this segment - x_end = p.x - y_end = p.y - # draw segment - self.set_source_color(Color.INNER_CUT) - with self.saved_context(): - self.moveTo(x_start, y_start + max_radius,0) - self.edge(x_end - x_start) - self.corner(-180, max_radius) - self.edge(x_end - x_start) - self.corner(-180, max_radius) - - if self.debug and False: # enable to debug cutting lines - self.set_source_color(Color.ANNOTATIONS) - with self.saved_context(): - self.moveTo(x_start, y_start, 0) - self.edge(x_end - x_start) - - s = "long - y: " + str(round(y, 1)) + " xs: " + str(round(x_start, 1)) + " xe: " + str(round(x_end, 1)) + " l: " + str(round(length, 1)) + " max: " + str(round(segment_length[segment_max], 1)) - with self.saved_context(): - self.text(s, x_start, y_start, fontsize=2, color=Color.ANNOTATIONS) - - # subtract length of segmant from total segment length - length -= (x_end - x_start + hspace + 2 * max_radius) - # create remaining line to work with - line_working = LineString([(x_end + hspace + 2 * max_radius, y_end), (xw_end, yw_end)]) - # next segment shall be long - segment_max = 1 - else: - # short segment can be drawn instantly - x_start, y_start , x_end, y_end = line_this.bounds - self.set_source_color(Color.INNER_CUT) - with self.saved_context(): - self.moveTo(x_start, y_start + max_radius, 0) - self.edge(x_end - x_start) - self.corner(-180, max_radius) - self.edge(x_end - x_start) - self.corner(-180, max_radius) - - if self.debug and False: # enable to debug short lines - self.set_source_color(Color.ANNOTATIONS) - with self.saved_context(): - self.moveTo(x_start, y_start, 0) - self.edge(x_end - x_start) - - s = "short - y: " + str(round(y, 1)) + " xs: " + str(round(x_start, 1)) + " xe: " + str(round(x_end, 1)) + " l: " + str(round(line_this.length, 1)) + " max: " + str(round(segment_length[segment_max], 1)) - with self.saved_context(): - self.text(s, x_start, y_start, fontsize=2, color=Color.ANNOTATIONS) - - segment_max = 1 - # short segment shall be skipped if a short segment shall start the line - if segment_toggle: - segment_max = 0 - y += step_y - else: - raise ValueError("fillHoles - unknown hole pattern: %s)" % pattern) - - def hexHolesRectangle(self, x, y, settings=None, skip=None): - """Fills a rectangle with holes in a hex pattern. - - Settings have: - r : radius of holes - b : space between holes - style : what types of holes (not yet implemented) - - :param x: width - :param y: height - :param settings: (Default value = None) - :param skip: (Default value = None) function to check if hole should be present - gets x, y, r, b, posx, posy - """ - - if settings is None: - settings = self.hexHolesSettings - r, b, style = settings.diameter/2, settings.distance, settings.style - - w = r + b / 2.0 - dist = w * math.cos(math.pi / 6.0) - - # how many half circles do fit - cx = int((x - 2 * r) // (w)) + 2 - cy = int((y - 2 * r) // (dist)) + 2 - - # what's left on the sides - lx = (x - (2 * r + (cx - 2) * w)) / 2.0 - ly = (y - (2 * r + ((cy // 2) * 2) * dist - 2 * dist)) / 2.0 - - for i in range(cy // 2): - for j in range((cx - (i % 2)) // 2): - px = 2 * j * w + r + lx - py = i * 2 * dist + r + ly - if i % 2: - px += w - if skip and skip(x, y, r, b, px, py): - continue - self.hole(px, py, r=r) - - def __skipcircle(self, x, y, r, b, posx, posy): - cx, cy = x / 2.0, y / 2.0 - return (dist(posx - cx, posy - cy) > (cx - r)) - - def hexHolesCircle(self, d, settings=None): - """ - Fill circle with holes in a hex pattern - - :param d: diameter of the circle - :param settings: (Default value = None) - """ - d2 = d / 2.0 - self.hexHolesRectangle(d, d, settings=settings, skip=self.__skipcircle) - - def hexHolesPlate(self, x, y, rc, settings=None): - """ - Fill a plate with holes in a hex pattern - - :param x: width - :param y: height - :param rc: radius of the corners - :param settings: (Default value = None) - """ - - def skip(x, y, r, b, posx, posy): - """ - :param x: - :param y: - :param r: - :param b: - :param posx: - :param posy: - """ - posx = abs(posx - (x / 2.0)) - posy = abs(posy - (y / 2.0)) - - wx = 0.5 * x - rc - r - wy = 0.5 * y - rc - r - - if (posx <= wx) or (posy <= wx): - return 0 - return dist(posx - wx, posy - wy) > rc - - self.hexHolesRectangle(x, y, settings, skip=skip) - - def hexHolesHex(self, h, settings=None, grow=None): - """ - Fill a hexagon with holes in a hex pattern - - :param h: height - :param settings: (Default value = None) - :param grow: (Default value = None) - """ - if settings is None: - settings = self.hexHolesSettings - r, b, style = settings.diameter/2, settings.distance, settings.style - - self.ctx.rectangle(0, 0, h, h) - w = r + b / 2.0 - dist = w * math.cos(math.pi / 6.0) - cy = 2 * int((h - 4 * dist) // (4 * w)) + 1 - - leftover = h - 2 * r - (cy - 1) * 2 * r - if grow == 'space ': - b += leftover / (cy - 1) / 2 - - # recalculate with adjusted values - w = r + b / 2.0 - dist = w * math.cos(math.pi / 6.0) - - self.moveTo(h / 2.0 - (cy // 2) * 2 * w, h / 2.0) - for j in range(cy): - self.hole(2 * j * w, 0, r) - for i in range(1, cy / 2 + 1): - for j in range(cy - i): - self.hole(j * 2 * w + i * w, i * 2 * dist, r) - self.hole(j * 2 * w + i * w, -i * 2 * dist, r) - - def flex2D(self, x, y, width=1): - """ - Fill a rectangle with a pattern allowing bending in both axis - - :param x: width - :param y: height - :param width: width between the lines of the pattern in multiples of thickness - """ - width *= self.thickness - cx = int(x // (5 * width)) - cy = int(y // (5 * width)) - - if cx == 0 or cy == 0: - return - - wx = x / 5. / cx - wy = y / 5. / cy - - armx = (4 * wx, 90, 4 * wy, 90, 2 * wx, 90, 2 * wy) - army = (4 * wy, 90, 4 * wx, 90, 2 * wy, 90, 2 * wx) - for i in range(cx): - for j in range(cy): - if (i + j) % 2: - with self.saved_context(): - self.moveTo((5 * i) * wx, (5 * j) * wy) - self.polyline(*armx) - with self.saved_context(): - self.moveTo((5 * i + 5) * wx, (5 * j + 5) * wy, -180) - self.polyline(*armx) - else: - with self.saved_context(): - self.moveTo((5 * i + 5) * wx, (5 * j) * wy, 90) - self.polyline(*army) - with self.saved_context(): - self.moveTo((5 * i) * wx, (5 * j + 5) * wy, -90) - self.polyline(*army) - self.ctx.stroke() - - @restore - def fingerHoleRectangle(self, dx, dy, x=0., y=0., angle=0., outside=False): - """ - Place finger holes for four walls - attaching a box on this plane - - :param dx: size in x direction - :param dy: size in y direction - :param x: x position of the center - :param y: y position of the center - :param angle: angle in which the rectangle is placed - :param outside: measure size from the outside of the walls - not the inside - """ - self.moveTo(x, y, angle) - d = 0.5*self.thickness - if outside: - d = -d - - self.fingerHolesAt(dx/2+d, -dy/2, dy, 90) - self.fingerHolesAt(-dx/2-d, -dy/2, dy, 90) - self.fingerHolesAt(-dx/2, -dy/2-d, dx, 0) - self.fingerHolesAt(-dx/2, dy/2+d, dx, 0) - - ################################################## - ### parts - ################################################## - - def _splitWall(self, pieces, side): - """helper for roundedPlate and surroundingWall - figures out what sides to split - """ - return [ - (False, False, False, False, True), - (True, False, False, False, True), - (True, False, True, False, True), - (True, True, True, False, True), - (True, True, True, True, True), - ][pieces][side] - - def roundedPlate(self, x, y, r, edge="f", callback=None, - holesMargin=None, holesSettings=None, - bedBolts=None, bedBoltSettings=None, - wallpieces=1, - extend_corners=True, - move=None): - """Plate with rounded corner fitting to .surroundingWall() - - For the callbacks the sides are counted depending on wallpieces - - :param x: width - :param y: height - :param r: radius of the corners - :param edge: - :param callback: (Default value = None) - :param holesMargin: (Default value = None) set to get hex holes - :param holesSettings: (Default value = None) - :param bedBolts: (Default value = None) - :param bedBoltSettings: (Default value = None) - :param wallpieces: (Default value = 1) # of separate surrounding walls - :param extend_corners: (Default value = True) have corners outset with the edges - :param move: (Default value = None) - """ - corner_holes = True - - t = self.thickness - edge = self.edges.get(edge, edge) - overallwidth = x + 2 * edge.spacing() - overallheight = y + 2 * edge.spacing() - - if self.move(overallwidth, overallheight, move, before=True): - return - - lx = x - 2*r - ly = y - 2*r - - self.moveTo(edge.spacing(), - edge.margin()) - self.moveTo(r, 0) - - if wallpieces > 4: - wallpieces = 4 - - wallcount = 0 - for nr, l in enumerate((lx, ly, lx, ly)): - if self._splitWall(wallpieces, nr): - for i in range(2): - self.cc(callback, wallcount, y=edge.startwidth()+self.burn) - edge(l / 2.0 , - bedBolts=self.getEntry(bedBolts, wallcount), - bedBoltSettings=self.getEntry(bedBoltSettings, wallcount)) - wallcount += 1 - else: - self.cc(callback, wallcount, y=edge.startwidth()+self.burn) - edge(l, - bedBolts=self.getEntry(bedBolts, wallcount), - bedBoltSettings=self.getEntry(bedBoltSettings, wallcount)) - wallcount += 1 - if extend_corners: - if corner_holes: - with self.saved_context(): - self.moveTo(0, edge.startwidth()) - self.polyline(0, (90, r), 0, -90, t, -90, 0, - (-90, r+t), 0, -90, t, -90, 0,) - self.ctx.stroke() - self.corner(90, r + edge.startwidth()) - else: - self.step(-edge.endwidth()) - self.corner(90, r) - self.step(edge.startwidth()) - - self.ctx.restore() - self.ctx.save() - - self.moveTo(edge.margin(), - edge.margin()) - - if holesMargin is not None: - self.moveTo(holesMargin, holesMargin) - if r > holesMargin: - r -= holesMargin - else: - r = 0 - self.hexHolesPlate(x - 2 * holesMargin, y - 2 * holesMargin, r, - settings=holesSettings) - - self.move(overallwidth, overallheight, move) - - def surroundingWallPiece(self, cbnr, x, y, r, pieces=1): - """ - Return the geometry of a pices of surroundingWall with the given - callback number. - :param cbnr: number of the callback corresponding to this part of the wall - :param x: width of matching roundedPlate - :param y: height of matching roundedPlate - :param r: corner radius of matching roundedPlate - :param pieces: (Default value = 1) number of separate pieces - :return: (left, length, right) left and right are Booleans that are True if the start or end of the wall is on that side. - """ - if pieces<=2 and (y - 2 * r) < 1E-3: - # remove zero length y sides - sides = (x/2-r, x - 2*r, x - 2*r) - if pieces > 0: # hack to get the right splits - pieces += 1 - else: - sides = (x/2-r, y - 2*r, x - 2*r, y - 2*r, x - 2*r) - - wallcount = 0 - for nr, l in enumerate(sides): - if self._splitWall(pieces, nr) and nr > 0: - if wallcount == cbnr: - return (False, l/2, True) - wallcount += 1 - if wallcount == cbnr: - return (True, l/2, False) - wallcount += 1 - else: - if wallcount == cbnr: - return (False, l, False) - wallcount += 1 - return (False, 0.0, False) - - def surroundingWall(self, x, y, r, h, - bottom='e', top='e', - left="D", right="d", - pieces=1, - extend_corners=True, - callback=None, - move=None): - """ - Wall(s) with flex filing around a roundedPlate() - - For the callbacks the sides are counted depending on pieces - - :param x: width of matching roundedPlate - :param y: height of matching roundedPlate - :param r: corner radius of matching roundedPlate - :param h: inner height of the wall (without edges) - :param bottom: (Default value = 'e') Edge type - :param top: (Default value = 'e') Edge type - :param left: (Default value = 'D') left edge(s) - :param right: (Default value = 'd') right edge(s) - :param pieces: (Default value = 1) number of separate pieces - :param callback: (Default value = None) - :param move: (Default value = None) - """ - t = self.thickness - c4 = (r + self.burn) * math.pi * 0.5 # circumference of quarter circle - c4 = c4 / self.edges["X"].settings.stretch - - top = self.edges.get(top, top) - bottom = self.edges.get(bottom, bottom) - left = self.edges.get(left, left) - right = self.edges.get(right, right) - - # XXX assumes startwidth == endwidth - if extend_corners: - topwidth = t - bottomwidth = t - else: - topwidth = top.startwidth() - bottomwidth = bottom.startwidth() - - overallwidth = 2*x + 2*y - 8*r + 4*c4 + (self.edges["d"].spacing() + self.edges["D"].spacing() + self.spacing) * pieces - overallheight = h + max(t, top.spacing()) + max(t, bottom.spacing()) - - if self.move(overallwidth, overallheight, move, before=True): - return - - self.moveTo(left.spacing(), bottom.margin()) - - wallcount = 0 - tops = [] # edges needed on the top for this wall segment - - if pieces<=2 and (y - 2 * r) < 1E-3: - # remove zero length y sides - c4 *= 2 - sides = (x/2-r, x - 2*r, x - 2*r) - if pieces > 0: # hack to get the right splits - pieces += 1 - else: - sides = (x/2-r, y - 2*r, x - 2*r, y - 2*r, x - 2*r) - - for nr, l in enumerate(sides): - if self._splitWall(pieces, nr) and nr > 0: - self.cc(callback, wallcount, y=bottomwidth + self.burn) - wallcount += 1 - bottom(l / 2.) - tops.append(l / 2.) - - # complete wall segment - with self.saved_context(): - self.edgeCorner(bottom, right, 90) - right(h) - self.edgeCorner(right, top, 90) - for n, d in enumerate(reversed(tops)): - if n % 2: # flex - self.step(topwidth-top.endwidth()) - self.edge(d) - self.step(top.startwidth()-topwidth) - else: - top(d) - self.edgeCorner(top, left, 90) - left(h) - self.edgeCorner(left, bottom, 90) - - if nr == len(sides) - 1: - break - # start new wall segment - tops = [] - self.moveTo(right.margin() + left.margin() + self.spacing) - self.cc(callback, wallcount, y=bottomwidth + self.burn) - wallcount += 1 - bottom(l / 2.) - tops.append(l / 2.) - else: - self.cc(callback, wallcount, y=bottomwidth + self.burn) - wallcount += 1 - bottom(l) - tops.append(l) - self.step(bottomwidth-bottom.endwidth()) - self.edges["X"](c4, h + topwidth + bottomwidth) - self.step(bottom.startwidth()-bottomwidth) - tops.append(c4) - - self.move(overallwidth, overallheight, move) - - def rectangularWall(self, x, y, edges="eeee", - ignore_widths=[], - holesMargin=None, holesSettings=None, - bedBolts=None, bedBoltSettings=None, - callback=None, - move=None, - label=""): - """ - Rectangular wall for all kind of box like objects - - :param x: width - :param y: height - :param edges: (Default value = "eeee") bottom, right, top, left - :param ignore_widths: list of edge_widths added to adjacent edge - :param holesMargin: (Default value = None) - :param holesSettings: (Default value = None) - :param bedBolts: (Default value = None) - :param bedBoltSettings: (Default value = None) - :param callback: (Default value = None) - :param move: (Default value = None) - :param label: rendered to identify parts, it is not meant to be cut or etched (Default value = "") - """ - if len(edges) != 4: - raise ValueError("four edges required") - edges = [self.edges.get(e, e) for e in edges] - edges += edges # append for wrapping around - overallwidth = x + edges[-1].spacing() + edges[1].spacing() - overallheight = y + edges[0].spacing() + edges[2].spacing() - - if self.move(overallwidth, overallheight, move, before=True): - return - - if 7 not in ignore_widths: - self.moveTo(edges[-1].spacing()) - self.moveTo(0, edges[0].margin()) - for i, l in enumerate((x, y, x, y)): - self.cc(callback, i, y=edges[i].startwidth() + self.burn) - e1, e2 = edges[i], edges[i + 1] - if (2*i-1 in ignore_widths or - 2*i-1+8 in ignore_widths): - l += edges[i-1].endwidth() - if 2*i in ignore_widths: - l += edges[i+1].startwidth() - e2 = self.edges["e"] - if 2*i+1 in ignore_widths: - e1 = self.edges["e"] - - edges[i](l, - bedBolts=self.getEntry(bedBolts, i), - bedBoltSettings=self.getEntry(bedBoltSettings, i)) - self.edgeCorner(e1, e2, 90) - - if holesMargin is not None: - self.moveTo(holesMargin, - holesMargin + edges[0].startwidth()) - self.hexHolesRectangle(x - 2 * holesMargin, y - 2 * holesMargin, settings=holesSettings) - - self.move(overallwidth, overallheight, move, label=label) - - def flangedWall(self, x, y, edges="FFFF", flanges=None, r=0.0, - callback=None, move=None, label=""): - """Rectangular wall with flanges extending the regular size - - This is similar to the rectangularWall but it may extend to either - side. Sides with flanges may only have e, E, or F edges - the later - being replaced with fingerHoles. - - :param x: width - :param y: height - :param edges: (Default value = "FFFF") bottom, right, top, left - :param flanges: (Default value = None) list of width of the flanges - :param r: radius of the corners of the flange - :param callback: (Default value = None) - :param move: (Default value = None) - :param label: rendered to identify parts, it is not meant to be cut or etched (Default value = "") - """ - - t = self.thickness - - if not flanges: - flanges = [0.0] * 4 - - while len(flanges) < 4: - flanges.append(0.0) - - edges = [self.edges.get(e, e) for e in edges] - # double to allow looping around - edges = edges + edges - flanges = flanges + flanges - - tw = x + edges[1].spacing() + flanges[1] + edges[3].spacing() + flanges[3] - th = y + edges[0].spacing() + flanges[0] + edges[2].spacing() + flanges[2] - - if self.move(tw, th, move, True): - return - - rl = min(r, max(flanges[-1], flanges[0])) - self.moveTo(rl + edges[-1].margin(), edges[0].margin()) - - for i in range(4): - l = y if i % 2 else x - - rl = min(r, max(flanges[i-1], flanges[i])) - rr = min(r, max(flanges[i], flanges[i+1])) - self.cc(callback, i, x=-rl) - if flanges[i]: - if edges[i] is self.edges["F"] or edges[i] is self.edges["h"]: - self.fingerHolesAt(flanges[i-1]+edges[i-1].endwidth()-rl, 0.5*t+flanges[i], l, - angle=0) - self.edge(l+flanges[i-1]+flanges[i+1]+edges[i-1].endwidth()+edges[i+1].startwidth()-rl-rr) - else: - self.edge(flanges[i-1]+edges[i-1].endwidth()-rl) - edges[i](l) - self.edge(flanges[i+1]+edges[i+1].startwidth()-rr) - self.corner(90, rr) - self.move(tw, th, move, label=label) - - def rectangularTriangle(self, x, y, edges="eee", r=0.0, num=1, - bedBolts=None, bedBoltSettings=None, - callback=None, - move=None, - label=""): - """ - Rectangular triangular wall - - :param x: width - :param y: height - :param edges: (Default value = "eee") bottom, right[, diagonal] - :param r: radius towards the hypotenuse - :param num: (Default value = 1) number of triangles - :param bedBolts: (Default value = None) - :param bedBoltSettings: (Default value = None) - :param callback: (Default value = None) - :param move: (Default value = None) - :param label: rendered to identify parts, it is not meant to be cut or etched (Default value = "") - """ - edges = [self.edges.get(e, e) for e in edges] - if len(edges) == 2: - edges.append(self.edges["e"]) - if len(edges) != 3: - raise ValueError("two or three edges required") - - r = min(r, x, y) - a = math.atan2(y-r, float(x-r)) - alpha = math.degrees(a) - if a > 0: - width = x + (edges[-1].spacing()+self.spacing)/math.sin(a) + edges[1].spacing() + self.spacing - else: - width = x + (edges[-1].spacing()+self.spacing) + edges[1].spacing() + self.spacing - height = y + edges[0].spacing() + edges[2].spacing() * math.cos(a) + 2* self.spacing + self.spacing - if num > 1: - width = 2*width - x + r - self.spacing - dx = width - x - edges[1].spacing() - self.spacing / 2 - dy = edges[0].margin() + self.spacing / 2 - - overallwidth = width * (num // 2 + num % 2) - self.spacing - overallheight = height - self.spacing - - if self.move(overallwidth, overallheight, move, before=True): - return - - if self.debug: - self.rectangularHole(width/2., height/2., width, height) - - self.moveTo(dx - self.spacing / 2, dy - self.spacing / 2) - - for n in range(num): - for i, l in enumerate((x, y)): - self.cc(callback, i, y=edges[i].startwidth() + self.burn) - edges[i](l, - bedBolts=self.getEntry(bedBolts, i), - bedBoltSettings=self.getEntry(bedBoltSettings, i)) - if i==0: - self.edgeCorner(edges[i], edges[i + 1], 90) - self.edgeCorner(edges[i], "e", 90) - - self.corner(alpha, r) - self.cc(callback, 2) - self.step(edges[2].startwidth()) - edges[2](((x-r)**2+(y-r)**2)**0.5) - self.step(-edges[2].endwidth()) - self.corner(90-alpha, r) - self.edge(edges[0].startwidth()) - self.corner(90) - self.ctx.stroke() - - self.moveTo(width-2*dx, height - 2*dy, 180) - if n % 2: - self.moveTo(width) - - self.move(overallwidth, overallheight, move, label=label) - - def trapezoidWall(self, w, h0, h1, edges="eeee", - callback=None, move=None, - label=""): - """ - Rectangular trapezoidal wall - - :param w: width - :param h0: left height - :param h1: right height - :param edges: (Default value = "eee") bottom, right, left - :param callback: (Default value = None) - :param move: (Default value = None) - :param label: rendered to identify parts, it is not meant to be cut or etched (Default value = "") - """ - - edges = [self.edges.get(e, e) for e in edges] - - overallwidth = w + edges[-1].spacing() + edges[1].spacing() - overallheight = max(h0, h1) + edges[0].spacing() - - if self.move(overallwidth, overallheight, move, before=True): - return - - a = math.degrees(math.atan((h1-h0)/w)) - l = ((h0-h1)**2+w**2)**0.5 - - self.moveTo(edges[-1].spacing(), edges[0].margin()) - self.cc(callback, 0, y=edges[0].startwidth()) - edges[0](w) - self.edgeCorner(edges[0], edges[1], 90) - self.cc(callback, 1, y=edges[1].startwidth()) - edges[1](h1) - self.edgeCorner(edges[1], self.edges["e"], 90) - self.corner(a) - self.cc(callback, 2) - edges[2](l) - self.corner(-a) - self.edgeCorner(self.edges["e"], edges[-1], 90) - self.cc(callback, 3, y=edges[-1].startwidth()) - edges[3](h0) - self.edgeCorner(edges[-1], edges[0], 90) - - self.move(overallwidth, overallheight, move, label=label) - - def trapezoidSideWall(self, w, h0, h1, edges="eeee", - radius=0.0, callback=None, move=None, - label=""): - """ - Rectangular trapezoidal wall - - :param w: width - :param h0: left height - :param h1: right height - :param edges: (Default value = "eeee") bottom, right, left - :param radius: (Default value = 0.0) radius of upper corners - :param callback: (Default value = None) - :param move: (Default value = None) - :param label: rendered to identify parts, it is not meant to be cut or etched (Default value = "") - """ - - edges = [self.edges.get(e, e) for e in edges] - - overallwidth = w + edges[-1].spacing() + edges[1].spacing() - overallheight = max(h0, h1) + edges[0].spacing() - - if self.move(overallwidth, overallheight, move, before=True): - return - - r = min(radius, abs(h0-h1)) - ws = w-r - if h0 > h1: - ws += edges[1].endwidth() - else: - ws += edges[3].startwidth() - hs = abs(h1-h0) - r - a = math.degrees(math.atan(hs/ws)) - l = (ws**2+hs**2)**0.5 - - self.moveTo(edges[-1].spacing(), edges[0].margin()) - self.cc(callback, 0, y=edges[0].startwidth()) - edges[0](w) - self.edgeCorner(edges[0], edges[1], 90) - self.cc(callback, 1, y=edges[1].startwidth()) - edges[1](h1) - - if h0 > h1: - self.polyline(0, (90-a, r)) - self.cc(callback, 2) - edges[2](l) - self.polyline(0, (a, r), edges[3].startwidth(), 90) - else: - self.polyline(0, 90, edges[1].endwidth(), (a, r)) - self.cc(callback, 2) - edges[2](l) - self.polyline(0, (90-a, r)) - self.cc(callback, 3, y=edges[-1].startwidth()) - edges[3](h0) - self.edgeCorner(edges[-1], edges[0], 90) - - self.move(overallwidth, overallheight, move, label=label) - - ### polygonWall and friends - - def _polygonWallExtend(self, borders, edges, close=False): - posx, posy = 0, 0 - ext = [ 0.0 ] * 4 - angle = 0 - - def checkpoint(ext, x, y): - ext[0] = min(ext[0], x) - ext[1] = min(ext[1], y) - ext[2] = max(ext[2], x) - ext[3] = max(ext[3], y) - - # trace edge margins - nborders = [] - for i, val in enumerate(borders): - if i % 2: - nborders.append(val) - else: - edge = edges[(i//2)%len(edges)] - margin = edge.margin() - try: - l = val[0] - except TypeError: - l = val - if margin: - nborders.extend([0.0, -90, margin, 90, l, 90, margin, -90, 0.0]) - else: - nborders.append(val) - - borders = nborders - for i in range(len(borders)): - if i % 2: - try: - a, r = borders[i] - except TypeError: - angle = (angle + borders[i]) % 360 - continue - if a > 0: - centerx = posx + r * math.cos(math.radians(angle+90)) - centery = posy + r * math.sin(math.radians(angle+90)) - else: - centerx = posx + r * math.cos(math.radians(angle-90)) - centery = posy + r * math.sin(math.radians(angle-90)) - - for direction in (0, 90, 180, 270): - if (a > 0 and - angle <= direction and (angle + a) % 360 >= direction): - direction -= 90 - elif (a < 0 and - angle >= direction and (angle + a) % 360 <= direction): - direction -= 90 - else: - continue - checkpoint(ext, centerx + r * math.cos(math.radians(direction)), centery + r * math.sin(math.radians(direction))) - #print("%4s %4s %4s %f %f" % (angle, direction+90, angle+a, centerx + r * math.cos(math.radians(direction)), centery + r * math.sin(math.radians(direction)))) - angle = (angle + a) % 360 - if a > 0: - posx = centerx + r * math.cos(math.radians(angle-90)) - posy = centery + r * math.sin(math.radians(angle-90)) - else: - posx = centerx + r * math.cos(math.radians(angle+90)) - posy = centery + r * math.sin(math.radians(angle+90)) - else: - posx += borders[i] * math.cos(math.radians(angle)) - posy += borders[i] * math.sin(math.radians(angle)) - checkpoint(ext, posx, posy) - - return ext - - def _closePolygon(self, borders): - posx, posy = 0, 0 - angle = 0.0 - - if borders and borders[-1] is not None: - return borders - - borders = borders[:-1] - - for i in range(len(borders)): - if i % 2: - try: - a, r = borders[i] - except TypeError: - angle = (angle + borders[i]) % 360 - continue - if a > 0: - centerx = posx + r * math.cos(math.radians(angle+90)) - centery = posy + r * math.sin(math.radians(angle+90)) - else: - centerx = posx + r * math.cos(math.radians(angle-90)) - centery = posy + r * math.sin(math.radians(angle-90)) - - angle = (angle + a) % 360 - if a > 0: - posx = centerx + r * math.cos(math.radians(angle-90)) - posy = centery + r * math.sin(math.radians(angle-90)) - else: - posx = centerx + r * math.cos(math.radians(angle+90)) - posy = centery + r * math.sin(math.radians(angle+90)) - else: - posx += borders[i] * math.cos(math.radians(angle)) - posy += borders[i] * math.sin(math.radians(angle)) - if len(borders) % 2 == 0: - borders.append(0.0) - - a = math.degrees(math.atan2(-posy, -posx)) - #print(a, angle, a - angle) - borders.append((a - angle + 360) % 360) - borders.append((posx**2 + posy**2)**.5) - borders.append(-a) - #print(borders) - return borders - - def polygonWall(self, borders, edge="f", turtle=False, - correct_corners=True, - callback=None, move=None, label=""): - """ - Polygon wall for all kind of multi-edged objects - - :param borders: array of distance and angles to draw - :param edge: (Default value = "f") Edges to apply. If the array of borders contains more segments that edges, the edge will wrap. Only edge types without start and end width supported for now. - :param turtle: (Default value = False) - :param correct_corners: (Default value = True) - :param callback: (Default value = None) - :param move: (Default value = None) - :param label: rendered to identify parts, it is not meant to be cut or etched (Default value = "") - - borders is alternating between length of the edge and angle of the corner. For now neither tabs nor radii are supported. None at the end closes the polygon. - """ - try: - edges = [self.edges.get(e, e) for e in edge] - except TypeError: - edges = [self.edges.get(edge, edge)] - - t = self.thickness # XXX edge.margin() - - borders = self._closePolygon(borders) - - minx, miny, maxx, maxy = self._polygonWallExtend(borders, edges) - - tw, th = maxx - minx, maxy - miny - - if not turtle: - if self.move(tw, th, move, True): - return - - self.moveTo(-minx, -miny) - - length_correction = 0. - for i in range(0, len(borders), 2): - self.cc(callback, i // 2) - self.edge(length_correction) - l = borders[i] - length_correction - next_angle = borders[i+1] - - if (correct_corners and - isinstance(next_angle, (int, float)) and next_angle < 0): - length_correction = t * math.tan(math.radians(-next_angle / 2)) - else: - length_correction = 0.0 - l -= length_correction - edge = edges[(i//2)%len(edges)] - edge(l) - self.edge(length_correction) - self.corner(next_angle, tabs=1) - - if not turtle: - self.move(tw, th, move, label=label) - - @restore - def polygonWalls(self, borders, h, bottom="F", top="F", symmetrical=True): - if not borders: - return - - borders = self._closePolygon(borders) - bottom = self.edges.get(bottom, bottom) - top = self.edges.get(top, top) - t = self.thickness # XXX edge.margin() - - leftsettings = copy.deepcopy(self.edges["f"].settings) - lf, lF, lh = leftsettings.edgeObjects(self, add=False) - rightsettings = copy.deepcopy(self.edges["f"].settings) - rf, rF, rh = rightsettings.edgeObjects(self, add=False) - - length_correction = 0. - angle = borders[-1] - i = 0 - part_cnt = 0 - - self.moveTo(0, bottom.margin()) - while i < len(borders): - if symmetrical: - if part_cnt % 2: - left, right = lf, rf - else: - # last part of an uneven lot - if (part_cnt == (len(borders)//2)-1): - left, right = lF, rf - else: - left, right = lF, rF - else: - left, right = lf, rF - - top_lengths = [] - top_edges = [] - - self.moveTo(left.spacing() + self.spacing, 0) - l = borders[i] - length_correction - leftsettings.setValues(self.thickness, angle=angle) - angle = borders[i+1] - - while isinstance(angle, (tuple, list)): - bottom(l) - angle, radius = angle - lr = abs(math.radians(angle) * radius) - self.edges["X"](lr, h + 2*t) # XXX - top_lengths.append(l) - top_lengths.append(lr) - top_edges.append(top) - top_edges.append("E") - - i += 2 - l = borders[i] - angle = borders[i+1] - - rightsettings.setValues(self.thickness, angle=angle) - if angle < 0: - length_correction = t * math.tan(math.radians(-angle / 2)) - else: - length_correction = 0.0 - l -= length_correction - - bottom(l) - - top_lengths.append(l) - top_edges.append(top) - with self.saved_context(): - self.edgeCorner(bottom, right, 90) - right(h) - self.edgeCorner(right, top, 90) - - top_edges.reverse() - top_lengths.reverse() - edges.CompoundEdge(self, top_edges, top_lengths)(sum(top_lengths)) - self.edgeCorner(top, left, 90) - left(h) - self.edgeCorner(left, bottom, 90) - self.ctx.stroke() - - self.moveTo(right.spacing() + self.spacing) - part_cnt += 1 - i += 2 - - - ################################################## - ### Place Parts - ################################################## - - def partsMatrix(self, n, width, move, part, *l, **kw): - """place many of the same part - - :param n: number of parts - :param width: number of parts in a row (0 for same as n) - :param move: (Default value = "") - :param part: callable that draws a part and knows move param - :param l: params for part - :param kw: keyword params for part - """ - if n <= 0: - return - - if not width: - width = n - - rows = n//width + (1 if n % width else 0) - - if not move: - move = "" - move = move.split() - - #move down / left before - for m in move: - if m == "left": - kw["move"] = "left only" - for i in range(width): - part(*l, **kw) - if m == "down": - kw["move"] = "down only" - for i in range(rows): - part(*l, **kw) - # draw matrix - for i in range(rows): - with self.saved_context(): - for j in range(width): - if "only" in move: - break - if width*i+j >= n: - break - kw["move"] = "right" - part(*l, **kw) - kw["move"] = "up only" - part(*l, **kw) - - # Move back down - if "up" not in move: - kw["move"] = "down only" - for i in range(rows): - part(*l, **kw) - - # Move right - if "right" in move: - kw["move"] = "right only" - for i in range(width): - part(*l, **kw) - - def mirrorX(self, f, offset=0.0): - """Wrap a function to draw mirrored at the y axis - - :param f: function to wrap - :param offset: (default value = 0.0) axis to mirror at - """ - def r(): - self.moveTo(offset, 0) - with self.saved_context(): - self.ctx.scale(-1, 1) - f() - return r - - def mirrorY(self, f, offset=0.0): - """Wrap a function to draw mirrored at the x axis - - :param f: function to wrap - :param offset: (default value = 0.0) axis to mirror at - """ - def r(): - self.moveTo(0, offset) - with self.saved_context(): - self.ctx.scale(1, -1) - f() - return r diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/drawing.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/drawing.py deleted file mode 100644 index 3645772..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/drawing.py +++ /dev/null @@ -1,1051 +0,0 @@ -from __future__ import annotations - -import codecs -import datetime -import io -import math -from typing import Any -from xml.etree import ElementTree as ET - -from affine import Affine - -from boxes.extents import Extents - -EPS = 1e-4 -PADDING = 10 - -RANDOMIZE_COLORS = False # enable to ease check for continuity of paths - - -def reorder_attributes(root) -> None: - """ - Source: https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.remove - """ - for el in root.iter(): - attrib = el.attrib - if len(attrib) > 1: - # adjust attribute order, e.g. by sorting - attribs = sorted(attrib.items()) - attrib.clear() - attrib.update(attribs) - - -def points_equal(x1, y1, x2, y2): - return abs(x1 - x2) < EPS and abs(y1 - y2) < EPS - - -def pdiff(p1, p2): - x1, y1 = p1 - x2, y2 = p2 - return (x1 - x2, y1 - y2) - - -class Surface: - - scale = 1.0 - invert_y = False - - def __init__(self) -> None: - self.parts: list[Any] = [] - self._p = self.new_part("default") - self.count = 0 - - def set_metadata(self, metadata): - self.metadata = metadata - - def flush(self): - pass - - def finish(self): - pass - - def _adjust_coordinates(self): - extents = self.extents() - extents.xmin -= PADDING - extents.ymin -= PADDING - extents.xmax += PADDING - extents.ymax += PADDING - - m = Affine.translation(-extents.xmin, -extents.ymin) - if self.invert_y: - m = Affine.scale(self.scale, -self.scale) * m - m = Affine.translation(0, self.scale*extents.height) * m - else: - m = Affine.scale(self.scale, self.scale) * m - - self.transform(self.scale, m, self.invert_y) - - return Extents(0, 0, extents.width * self.scale, extents.height * self.scale) - - def render(self, renderer): - renderer.init(**self.args) - for p in self.parts: - p.render(renderer) - renderer.finish() - - def transform(self, f, m, invert_y=False): - for p in self.parts: - p.transform(f, m, invert_y) - - def new_part(self, name="part"): - if self.parts and len(self.parts[-1].pathes) == 0: - return self._p - p = Part(name) - self.parts.append(p) - self._p = p - return p - - def append(self, *path): - self.count += 1 - if self.count > 100000: - raise ValueError("Too many lines") - self._p.append(*path) - - def stroke(self, **params): - return self._p.stroke(**params) - - def move_to(self, *xy): - self._p.move_to(*xy) - - def extents(self): - if not self.parts: - return Extents() - return sum([p.extents() for p in self.parts]) - - -class Part: - def __init__(self, name) -> None: - self.pathes: list[Any] = [] - self.path: list[Any] = [] - - def extents(self): - if not self.pathes: - return Extents() - return sum([p.extents() for p in self.pathes]) - - def transform(self, f, m, invert_y=False): - assert(not self.path) - for p in self.pathes: - p.transform(f, m, invert_y) - - def append(self, *path): - self.path.append(list(path)) - - def stroke(self, **params): - if len(self.path) == 0: - return - # search for path ending at new start coordinates to append this path to - xy0 = self.path[0][1:3] - if (not points_equal(*xy0, *self.path[-1][1:3]) and - not self.path[0][0] == "T"): - for p in reversed(self.pathes): - xy1 = p.path[-1][1:3] - if points_equal(*xy0, *xy1) and p.params == params: - p.path.extend(self.path[1:]) - self.path = [] - return p - p = Path(self.path, params) - self.pathes.append(p) - self.path = [] - return p - - def move_to(self, *xy): - if len(self.path) == 0: - self.path.append(["M", *xy]) - elif self.path[-1][0] == "M": - self.path[-1] = ["M", *xy] - else: - xy0 = self.path[-1][1:3] - if not points_equal(*xy0, *xy): - self.path.append(["M", *xy]) - - -class Path: - def __init__(self, path, params) -> None: - self.path = path - self.params = params - - def __repr__(self) -> str: - l = len(self.path) - # x1,y1 = self.path[0][1:3] - if l>0: - x2, y2 = self.path[-1][1:3] - return f"Path[{l}] to ({x2:.2f},{y2:.2f})" - return f"empty Path" - - def extents(self): - e = Extents() - for p in self.path: - e.add(*p[1:3]) - if p[0] == 'T': - m, text, params = p[3:] - h = params['fs'] - l = len(text) * h * 0.7 - align = params.get('align', 'left') - start, end = { - 'left' : (0, 1), - 'middle' : (-0.5, 0.5), - 'end' : (-1, 0), - }[align] - for x in (start*l, end*l): - for y in (0, h): - x_, y_ = m * (x, y) - e.add(x_, y_) - return e - - def transform(self, f, m, invert_y=False): - self.params["lw"] *= f - for c in self.path: - C = c[0] - c[1], c[2] = m * (c[1], c[2]) - if C == 'C': - c[3], c[4] = m * (c[3], c[4]) - c[5], c[6] = m * (c[5], c[6]) - if C == "T": - c[3] = m * c[3] - if invert_y: - c[3] *= Affine.scale(1, -1) - - def faster_edges(self, inner_corners): - if inner_corners == "backarc": - return - - for (i, p) in enumerate(self.path): - if p[0] == "C" and i > 1 and i < len(self.path) - 1: - if self.path[i - 1][0] == "L" and self.path[i + 1][0] == "L": - p11 = self.path[i - 2][1:3] - p12 = self.path[i - 1][1:3] - p21 = p[1:3] - p22 = self.path[i + 1][1:3] - if (((p12[0]-p21[0])**2 + (p12[1]-p21[1])**2) > - self.params["lw"]**2): - continue - lines_intersect, x, y = line_intersection((p11, p12), (p21, p22)) - if lines_intersect: - self.path[i - 1] = ("L", x, y) - if inner_corners == "loop": - self.path[i] = ("C", x, y, *p12, *p21) - else: - self.path[i] = ("L", x, y) - # filter duplicates - if len(self.path) > 1: # no need to find duplicates if only one element in path - self.path = [p for n, p in enumerate(self.path) if p != self.path[n-1]] - -class Context: - def __init__(self, surface, *al, **ad) -> None: - self._renderer = self._dwg = surface - - self._bounds = Extents() - self._padding = PADDING - - self._stack: list[Any] = [] - self._m = Affine.translation(0, 0) - self._xy = (0, 0) - self._mxy = self._m * self._xy - self._lw = 0 - self._rgb = (0, 0, 0) - self._ff = "sans-serif" - self._fs = 10 - self._last_path = None - - def _update_bounds_(self, mx, my): - self._bounds.update(mx, my) - - def save(self): - self._stack.append( - (self._m, self._xy, self._lw, self._rgb, self._mxy, self._last_path) - ) - self._xy = (0, 0) - - def restore(self): - ( - self._m, - self._xy, - self._lw, - self._rgb, - self._mxy, - self._last_path, - ) = self._stack.pop() - - ## transformations - - def translate(self, x, y): - self._m *= Affine.translation(x, y) - self._xy = (0, 0) - - def scale(self, sx, sy): - self._m *= Affine.scale(sx, sy) - - def rotate(self, r): - self._m *= Affine.rotation(180 * r / math.pi) - - def set_line_width(self, lw): - self._lw = lw - - def set_source_rgb(self, r, g, b): - self._rgb = (r, g, b) - - ## path methods - - def _line_to(self, x, y): - self._add_move() - x1, y1 = self._mxy - self._xy = x, y - x2, y2 = self._mxy = self._m * self._xy - if not points_equal(x1, y1, x2, y2): - self._dwg.append("L", x2, y2) - - def _add_move(self): - self._dwg.move_to(*self._mxy) - - def move_to(self, x, y): - self._xy = (x, y) - self._mxy = self._m * self._xy - - def line_to(self, x, y): - self._line_to(x, y) - - def _arc(self, xc, yc, radius, angle1, angle2, direction): - if abs(angle1 - angle2) < EPS or radius < EPS: - return - x1, y1 = radius * math.cos(angle1) + xc, radius * math.sin(angle1) + yc - x4, y4 = radius * math.cos(angle2) + xc, radius * math.sin(angle2) + yc - - # XXX direction seems not needed for small arcs - ax = x1 - xc - ay = y1 - yc - bx = x4 - xc - by = y4 - yc - q1 = ax * ax + ay * ay - q2 = q1 + ax * bx + ay * by - k2 = 4/3 * ((2 * q1 * q2)**0.5 - q2) / (ax * by - ay * bx) - - x2 = xc + ax - k2 * ay - y2 = yc + ay + k2 * ax - x3 = xc + bx + k2 * by - y3 = yc + by - k2 * bx - - mx1, my1 = self._m * (x1, y1) - mx2, my2 = self._m * (x2, y2) - mx3, my3 = self._m * (x3, y3) - mx4, my4 = self._m * (x4, y4) - mxc, myc = self._m * (xc, yc) - - self._add_move() - self._dwg.append("C", mx4, my4, mx2, my2, mx3, my3) - self._xy = (x4, y4) - self._mxy = (mx4, my4) - - def arc(self, xc, yc, radius, angle1, angle2): - self._arc(xc, yc, radius, angle1, angle2, 1) - - def arc_negative(self, xc, yc, radius, angle1, angle2): - self._arc(xc, yc, radius, angle1, angle2, -1) - - def curve_to(self, x1, y1, x2, y2, x3, y3): - # mx0,my0 = self._m*self._xy - mx1, my1 = self._m * (x1, y1) - mx2, my2 = self._m * (x2, y2) - mx3, my3 = self._m * (x3, y3) - self._add_move() - self._dwg.append("C", mx3, my3, mx1, my1, mx2, my2) # destination first! - self._xy = (x3, y3) - self._mxy = (mx3, my3) - - def stroke(self): - # print('stroke stack-level=',len(self._stack),'lastpath=',self._last_path,) - self._last_path = self._dwg.stroke(rgb=self._rgb, lw=self._lw) - self._xy = (0, 0) - - def fill(self): - self._xy = (0, 0) - raise NotImplementedError() - - def set_font(self, style, bold=False, italic=False): - if style not in ("serif", "sans-serif", "monospaced"): - raise ValueError("Unknown font style") - self._ff = (style, bold, italic) - - def set_font_size(self, fs): - self._fs = fs - - def show_text(self, text, **args): - params = {"ff": self._ff, "fs": self._fs, "lw": self._lw, "rgb": self._rgb} - params.update(args) - mx0, my0 = self._m * self._xy - m = self._m - self._dwg.append("T", mx0, my0, m, text, params) - - def text_extents(self, text): - fs = self._fs - # XXX ugly hack! Fix Boxes.text() ! - return (0, 0, 0.6 * fs * len(text), 0.65 * fs, fs * 0.1, 0) - - def rectangle(self, x, y, width, height): - - # todo: better check for empty path? - self.stroke() - - self.move_to(x, y) - self.line_to(x + width, y) - self.line_to(x + width, y + height) - self.line_to(x, y + height) - self.line_to(x, y) - self.stroke() - - def get_current_point(self): - return self._xy - - def flush(self): - pass - # todo: check, if needed - # self.stroke() - - ## additional methods - def new_part(self): - self._dwg.new_part() - - -class SVGSurface(Surface): - - invert_y = True - - fonts = { - 'serif' : 'TimesNewRoman, "Times New Roman", Times, Baskerville, Georgia, serif', - 'sans-serif' : '"Helvetica Neue", Helvetica, Arial, sans-serif', - 'monospaced' : '"Courier New", Courier, "Lucida Sans Typewriter"' - } - - def _addTag(self, parent, tag, text, first=False): - if first: - t = ET.Element(tag) - else: - t = ET.SubElement(parent, tag) - t.text = text - t.tail = '\n' - if first: - parent.insert(0, t) - return t - - def _add_metadata(self, root): - md = self.metadata - - # Add Inkscape style rdf meta data - root.set("xmlns:dc", "http://purl.org/dc/elements/1.1/") - root.set("xmlns:cc", "http://creativecommons.org/ns#") - root.set("xmlns:rdf","http://www.w3.org/1999/02/22-rdf-syntax-ns#") - - title = "{group} - {name}".format(**md) - date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - m = self._addTag(root, "metadata", '\n', True) - r = ET.SubElement(m, 'rdf:RDF') - w = ET.SubElement(r, 'cc:Work') - w.text = '\n' - - self._addTag(w, 'dc:title', title) - self._addTag(w, 'dc:date', date) - - if "url" in md and md["url"]: - self._addTag(w, 'dc:source', md["url"]) - self._addTag(w, 'dc:source', md["url_short"]) - else: - self._addTag(w, 'dc:source', md["cli"]) - - desc = md["short_description"] or "" - if "description" in md and md["description"]: - desc += "\n\n" + md["description"] - desc += "\n\nCreated with Boxes.py (https://festi.info/boxes.py)\n" - desc += "Command line: %s\n" % md["cli"] - desc += "Command line short: %s\n" % md["cli_short"] - if md["url"]: - desc += "Url: %s\n" % md["url"] - desc += "Url short: %s\n" % md["url_short"] - desc += "SettingsUrl: %s\n" % md["url"].replace("&render=1", "") - desc += "SettingsUrl short: %s\n" % md["url_short"].replace("&render=1", "") - self._addTag(w, 'dc:description', desc) - - # title - self._addTag(root, "title", md["name"], True) - - # Add XML comment - txt = """ -{name} - {short_description} -""".format(**md) - if md["description"]: - txt += """ - -{description} - -""".format(**md) - txt += """ -Created with Boxes.py (https://festi.info/boxes.py) -Creation date: {date} -""".format(date=date, **md) - - txt += "Command line (remove spaces between dashes): %s\n" % md["cli_short"] - - if md["url"]: - txt += "Url: %s\n" % md["url"] - txt += "Url short: %s\n" % md["url_short"] - txt += "SettingsUrl: %s\n" % md["url"].replace("&render=1", "") - txt += "SettingsUrl short: %s\n" % md["url_short"].replace("&render=1", "") - m = ET.Comment(txt.replace("--", "- -").replace("--", "- -")) # ---- - m.tail = '\n' - root.insert(0, m) - - def finish(self, inner_corners="loop"): - extents = self._adjust_coordinates() - w = extents.width * self.scale - h = extents.height * self.scale - - - nsmap = { - "dc": "http://purl.org/dc/elements/1.1/", - "cc": "http://creativecommons.org/ns#", - "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - "svg": "http://www.w3.org/2000/svg", - "xlink": "http://www.w3.org/1999/xlink", - "inkscape": "http://www.inkscape.org/namespaces/inkscape", - } - ET.register_namespace("", "http://www.w3.org/2000/svg") - ET.register_namespace("xlink", "http://www.w3.org/1999/xlink") - svg = ET.Element('svg', width=f"{w:.2f}mm", height=f"{h:.2f}mm", - viewBox=f"0.0 0.0 {w:.2f} {h:.2f}", - xmlns="http://www.w3.org/2000/svg") - for name, value in nsmap.items(): - svg.set(f"xmlns:{name}", value) - svg.text = "\n" - tree = ET.ElementTree(svg) - - self._add_metadata(svg) - - for i, part in enumerate(self.parts): - if not part.pathes: - continue - g = ET.SubElement(svg, "g", id=f"p-{i}", - style="fill:none;stroke-linecap:round;stroke-linejoin:round;") - g.text = "\n " - g.tail = "\n" - for j, path in enumerate(part.pathes): - p = [] - x, y = 0, 0 - start = None - last = None - path.faster_edges(inner_corners) - for c in path.path: - x0, y0 = x, y - C, x, y = c[0:3] - if C == "M": - if start and points_equal(start[1], start[2], - last[1], last[2]): - p.append("Z") - start = c - p.append(f"M {x:.3f} {y:.3f}") - elif C == "L": - if abs(x - x0) < EPS: - p.append(f"V {y:.3f}") - elif abs(y - y0) < EPS: - p.append(f"H {x:.3f}") - else: - p.append(f"L {x:.3f} {y:.3f}") - elif C == "C": - x1, y1, x2, y2 = c[3:] - p.append( - f"C {x1:.3f} {y1:.3f} {x2:.3f} {y2:.3f} {x:.3f} {y:.3f}" - ) - elif C == "T": - m, text, params = c[3:] - m = m * Affine.translation(0, -params['fs']) - tm = " ".join(f"{m[i]:.3f}" for i in (0, 3, 1, 4, 2, 5)) - font, bold, italic = params['ff'] - fontweight = ("normal", "bold")[bool(bold)] - fontstyle = ("normal", "italic")[bool(italic)] - - style = f"font-family: {font} ; font-weight: {fontweight}; font-style: {fontstyle}; fill: {rgb_to_svg_color(*params['rgb'])}" - t = ET.SubElement(g, "text", - #x=f"{x:.3f}", y=f"{y:.3f}", - transform=f"matrix( {tm} )", - style=style) - t.text = text - t.set("font-size", f"{params['fs']}px") - t.set("text-anchor", params.get('align', 'left')) - t.set("dominant-baseline", 'hanging') - else: - print("Unknown", c) - - last = c - - if start and start is not last and \ - points_equal(start[1], start[2], last[1], last[2]): - p.append("Z") - color = ( - random_svg_color() - if RANDOMIZE_COLORS - else rgb_to_svg_color(*path.params["rgb"]) - ) - if p and p[-1][0] == "M": - p.pop() - if p: # might be empty if only contains text - t = ET.SubElement(g, "path", d=" ".join(p), stroke=color) - t.set("stroke-width", f'{path.params["lw"]:.2f}') - t.tail = "\n " - t.tail = "\n" - reorder_attributes(tree) - f = io.BytesIO() - tree.write(f, encoding="utf-8", xml_declaration=True, method="xml") - f.seek(0) - return f - -class PSSurface(Surface): - - scale = 72 / 25.4 # 72 dpi - - fonts = { - ('serif', False, False) : 'Times-Roman', - ('serif', False, True) : 'Times-Italic', - ('serif', True, False) : 'Times-Bold', - ('serif', True, True) : 'Times-BoldItalic', - ('sans-serif', False, False) : 'Helvetica', - ('sans-serif', False, True) : 'Helvetica-Oblique', - ('sans-serif', True, False) : 'Helvetica-Bold', - ('sans-serif', True, True) : 'Helvetica-BoldOblique', - ('monospaced', False, False) : 'Courier', - ('monospaced', False, True) : 'Courier-Oblique', - ('monospaced', True, False) : 'Courier-Bold', - ('monospaced', True, True) : 'Courier-BoldOblique', - } - - def _metadata(self): - md = self.metadata - - desc = "" - desc += "%%Title: Boxes.py - {group} - {name}\n".format(**md) - desc += f'%%CreationDate: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}\n' - desc += f'%%Keywords: boxes.py, laser, laser cutter\n' - desc += f'%%Creator: {md.get("url") or md["cli"]}\n' - desc += "%%CreatedBy: Boxes.py (https://festi.info/boxes.py)\n" - for line in (md["short_description"] or "").split("\n"): - desc += "%% %s\n" % line - desc += "%\n" - if "description" in md and md["description"]: - desc += "%\n" - for line in md["description"].split("\n"): - desc += "%% %s\n" % line - desc += "%\n" - - desc += "%% Command line: %s\n" % md["cli"] - desc += "%% Command line short: %s\n" % md["cli_short"] - if md["url"]: - desc += f'%%Url: {md["url"]}\n' - desc += f'%%Url short: {md["url_short"]}\n' - desc += f'%%SettingsUrl: {md["url"].replace("&render=1", "")}\n' - desc += f'%%SettingsUrl short: {md["url_short"].replace("&render=1", "")}\n' - return desc - - def finish(self, inner_corners="loop"): - - extents = self._adjust_coordinates() - w = extents.width - h = extents.height - - data = io.BytesIO() - f = codecs.getwriter('utf-8')(data) - - f.write(f"""%!PS-Adobe-2.0 EPSF-2.0 -%%BoundingBox: 0 0 {w:.0f} {h:.0f} -{self._metadata()} -%%EndComments - -1 setlinecap -1 setlinejoin -0.0 0.0 0.0 setrgbcolor -""") - f.write(""" -/ReEncode { % inFont outFont encoding | - - /MyEncoding exch def - exch findfont - dup length dict - begin - {def} forall - /Encoding MyEncoding def - currentdict - end - definefont -} def - -""") - for font in self.fonts.values(): - f.write(f"/{font} /{font}-Latin1 ISOLatin1Encoding ReEncode\n") - # f.write(f"%%DocumentMedia: \d+x\d+mm ((\d+) (\d+)) 0 \(" - # dwg['width']=f'{w:.2f}mm' - # dwg['height']=f'{h:.2f}mm' - - for i, part in enumerate(self.parts): - if not part.pathes: - continue - for j, path in enumerate(part.pathes): - p = [] - x, y = 0, 0 - path.faster_edges(inner_corners) - - for c in path.path: - x0, y0 = x, y - C, x, y = c[0:3] - if C == "M": - p.append(f"{x:.3f} {y:.3f} moveto") - elif C == "L": - p.append(f"{x:.3f} {y:.3f} lineto") - elif C == "C": - x1, y1, x2, y2 = c[3:] - p.append( - f"{x1:.3f} {y1:.3f} {x2:.3f} {y2:.3f} {x:.3f} {y:.3f} curveto" - ) - elif C == "T": - m, text, params = c[3:] - tm = " ".join(f"{m[i]:.3f}" for i in (0, 3, 1, 4, 2, 5)) - text = text.replace("(", r"\(").replace(")", r"\)") - color = " ".join(f"{c:.2f}" for c in params["rgb"]) - align = params.get('align', 'left') - f.write(f"/{self.fonts[params['ff']]}-Latin1 findfont\n") - f.write(f"{params['fs']} scalefont\n") - f.write("setfont\n") - #f.write(f"currentfont /Encoding ISOLatin1Encoding put\n") - f.write(f"{color} setrgbcolor\n") - f.write("matrix currentmatrix") # save current matrix - f.write(f"[ {tm} ] concat\n") - if align == "left": - f.write(f"0.0\n") - else: - f.write(f"({text}) stringwidth pop ") - if align == "middle": - f.write(f"-0.5 mul\n") - else: # end - f.write(f"neg\n") - # offset y by descender - f.write("currentfont dup /FontBBox get 1 get \n") - f.write("exch /FontMatrix get 3 get mul neg moveto \n") - - f.write(f"({text}) show\n") # text created by dup above - f.write("setmatrix\n\n") # restore matrix - else: - print("Unknown", c) - color = ( - random_svg_color() - if RANDOMIZE_COLORS - else rgb_to_svg_color(*path.params["rgb"]) - ) - if p: # todo: might be empty since text is not implemented yet - color = " ".join(f"{c:.2f}" for c in path.params["rgb"]) - f.write("newpath\n") - f.write("\n".join(p)) - f.write("\n") - f.write(f"{path.params['lw']} setlinewidth\n") - f.write(f"{color} setrgbcolor\n") - f.write("stroke\n\n") - f.write( - """ -showpage -%%Trailer -%%EOF -""" - ) - data.seek(0) - return data - -class LBRN2Surface(Surface): - - - invert_y = False - dbg = False - - fonts = { - 'serif' : 'Times New Roman', - 'sans-serif' : 'Arial', - 'monospaced' : 'Courier New' - } - - lbrn2_colors=[ - 0, # Colors.OUTER_CUT (BLACK) --> Lightburn C00 (black) - 1, # Colors.INNER_CUT (BLUE) --> Lightburn C01 (blue) - 3, # Colors.ETCHING (GREEN) --> Lightburn C02 (green) - 6, # Colors.ETCHING_DEEP (CYAN) --> Lightburn C06 (cyan) - 30, # Colors.ANNOTATIONS (RED) --> Lightburn T1 - 7, # Colors.OUTER_CUT (MAGENTA) --> Lightburn C07 (magenta) - 4, # Colors.OUTER_CUT (YELLOW) --> Lightburn C04 (yellow) - 8, # Colors.OUTER_CUT (WHITE) --> Lightburn C08 (grey) - ] - - def finish(self, inner_corners="loop"): - if self.dbg: print("LBRN2 save") - extents = self._adjust_coordinates() - w = extents.width * self.scale - h = extents.height * self.scale - - svg = ET.Element('LightBurnProject', AppVersion="1.0.06", FormatVersion="1", MaterialHeight="0", MirrorX="False", MirrorY="False") - svg.text = "\n" - num = 0 - txtOffset = {} - - tree = ET.ElementTree(svg) - if self.dbg: print ("8", num) - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="3") # green layer (ETCHING) - name = ET.SubElement(cs, "name", Value="Etch") - priority = ET.SubElement(cs, "priority", Value="0") # is cut first - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="6") # cyan layer (ETCHING_DEEP) - name = ET.SubElement(cs, "name", Value="Deep Etch") - priority = ET.SubElement(cs, "priority", Value="1") # is cut second - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="7") # magenta layer (MAGENTA) - name = ET.SubElement(cs, "name", Value="C07") - priority = ET.SubElement(cs, "priority", Value="2") # is cut third - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="4") # yellow layer (YELLOW) - name = ET.SubElement(cs, "name", Value="C04") - priority = ET.SubElement(cs, "priority", Value="3") # is cut third - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="8") # grey layer (WHITE) - name = ET.SubElement(cs, "name", Value="C08") - priority = ET.SubElement(cs, "priority", Value="4") # is cut fourth - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="1") # blue layer (INNER_CUT) - name = ET.SubElement(cs, "name", Value="Inner Cut") - priority = ET.SubElement(cs, "priority", Value="5") # is cut fifth - - cs = ET.SubElement(svg, "CutSetting", Type="Cut") - index = ET.SubElement(cs, "index", Value="0") # black layer (OUTER_CUT) - name = ET.SubElement(cs, "name", Value="Outer Cut") - priority = ET.SubElement(cs, "priority", Value="6") # is cut sixth - - cs = ET.SubElement(svg, "CutSetting", Type="Tool") - index = ET.SubElement(cs, "index", Value="30") # T1 layer (ANNOTATIONS) - name = ET.SubElement(cs, "name", Value="T1") # tool layer do not support names - priority = ET.SubElement(cs, "priority", Value="7") # is not cut at all - - for i, part in enumerate(self.parts): - if self.dbg: print ("7", num) - if not part.pathes: - continue - gp = ET.SubElement(svg, "Shape", Type="Group") - gp.text = "\n " - gp.tail = "\n" - children = ET.SubElement(gp, "Children") - children.text = "\n " - children.tail = "\n" - - for j, path in enumerate(part.pathes): - myColor = self.lbrn2_colors[4*int(path.params["rgb"][0])+2*int(path.params["rgb"][1])+int(path.params["rgb"][2])] - - p = [] - x, y = 0, 0 - C = "" - start = None - last = None - path.faster_edges(inner_corners) - num = 0 - cnt = 1 - end = len(path.path) - 1 - if self.dbg: - for c in path.path: - print ("6",num, c) - num += 1 - num = 0 - - c = path.path[num] - C, x, y = c[0:3] - if self.dbg: - print("end:", end) - while num < end or (C == "T" and num <= end): # len(path.path): - if self.dbg: - print("0", num) - c = path.path[num] - if self.dbg: print("first: ", num, c) - - C, x, y = c[0:3] - if C == "M": - if self.dbg: print ("1", num) - sh = ET.SubElement(children, "Shape", Type="Path", CutIndex=str(myColor)) - sh.text = "\n " - sh.tail = "\n" - vl = ET.SubElement(sh, "VertList") - vl.text = f"V{x:.3f} {y:.3f}c0x1c1x1" - vl.tail = "\n" - pl = ET.SubElement(sh, "PrimList") - pl.text = ""#f"L{cnt} {cnt+1}" - pl.tail = "\n" - start = c - x0, y0 = x, y - # do something with M - done = False - bspline = False - while done == False and num < end: # len(path.path): - num += 1 - c = path.path[num] - if self.dbg: print ("next: ",num, c) - C, x, y = c[0:3] - if C == "M": - if start and points_equal(start[1], start[2], x, y): - pl.text = "LineClosed" - start = c - cnt = 1 - if self.dbg: print ("next, because M") - done = True - elif C == "T": - if self.dbg: print ("next, because T") - done = True - else: - if C == "L": - vl.text+=(f"V{x:.3f} {y:.3f}c0x1c1x1") - pl.text += f"L{cnt-1} {cnt}" - cnt +=1 - elif C == "C": - x1, y1, x2, y2 = c[3:] - if self.dbg: print ("C: ",x0, y0, x1, y1, x, y, x2, y2) - vl.text+=(f"V{x0:.3f} {y0:.3f}c0x{(x1):.3f}c0y{(y1):.3f}c1x1V{x:.3f} {y:.3f}c0x1c1x{(x2):.3f}c1y{(y2):.3f}") - pl.text += f"L{cnt-1} {cnt}B{cnt} {cnt+1}" - cnt +=2 - bspline = True - else: - print("unknown", c) - if done == False: - x0, y0 = x, y - - if start and points_equal(start[1], start[2], x0, y0): - if bspline == False: - pl.text = "LineClosed" - start = c - if self.dbg: print ("2", num) - elif C == "T": - cnt = 1 - #C = "" - if self.dbg: print ("3", num) - m, text, params = c[3:] - m = m * Affine.translation(0, params['fs']) - if self.dbg: print ("T: ",x, y, c) - num += 1 - font, bold, italic = params['ff'] - if params.get('font', 'Arial')=='Arial': - f = self.fonts[font] - else: - f = params.get('font', 'Arial') - fontColor = self.lbrn2_colors[4*int(params["rgb"][0])+2*int(params["rgb"][1])+int(params["rgb"][2])] - - #alignment can be left|middle|end - if params.get('align', 'left')=='middle': - hor = '1' - else: - if params.get('align', 'left')=='end': - hor = '2' - else: - hor = '0' - ver = 1 # vertical is always bottom, text is shifted in box class - - pos = text.find('%') - offs = 0 - if pos >- 1: - if self.dbg: print ("p: ", pos, text[pos+1:pos+3]) - texttype = '2' - if self.dbg: print("l ", len(text[pos+1:pos+3])) - if text[pos+1:pos+2].isnumeric(): - if self.dbg: print ("t0", text[pos+1:pos+3]) - if text[pos+1:pos+3].isnumeric() and len(text[pos+1:pos+3]) == 2: - if self.dbg: print ("t1") - if text[pos:pos+3] in txtOffset: - if self.dbg: print ("t2") - offs = txtOffset[text[pos:pos+3]] + 1 - else: - if self.dbg: print ("t3") - offs = 0 - txtOffset[text[pos:pos+3]] = offs - else: - if self.dbg: print ("t4") - if text[pos:pos+2] in txtOffset: - if self.dbg: print ("t5") - offs = txtOffset[text[pos:pos+2]] + 1 - else: - offs = 0 - if self.dbg: print ("t6") - txtOffset[text[pos:pos+2]] = offs - else: - if self.dbg: print ("t7") - texttype = '0' - else: - texttype = '0' - if self.dbg: print ("t8") - if self.dbg: print ("o: ", text, txtOffset, offs) - - if not text: - if self.dbg: print ("T: text with empty string - ",x, y, c) - else: - sh = ET.SubElement(children, "Shape", Type="Text", CutIndex=str(fontColor), Font=f"{f}", H=f"{(params['fs']*1.75*0.6086434):.3f}", Str=f"{text}", Bold=f"{'1' if bold else '0'}", Italic=f"{'1' if italic else '0'}", Ah=f"{str(hor)}", Av=f"{str(ver)}", Eval=f"{texttype}", VariableOffset=f"{str(offs)}") # 1mm = 1.75 Lightburn H units - sh.text = "\n " - sh.tail = "\n" - xf = ET.SubElement(sh, "XForm") - xf.text = " ".join(f"{m[i]:.3f}" for i in (0, 3, 1, 4, 2, 5)) - xf.tail = "\n" - else: - if self.dbg: print ("4", num) - print ("next, because not M") - num += 1 - - url = self.metadata["url"].replace("&render=1", "") # remove render argument to get web form again - - pl = ET.SubElement(svg, "Notes", ShowOnLoad="1", Notes="File created by Boxes.py script, programmed by Florian Festi.\nLightburn output by Klaus Steinhammer.\n\nURL with settings:\n" + str(url)) - pl.text = "" - pl.tail = "\n" - - if self.dbg: print ("5", num) - f = io.BytesIO() - tree.write(f, encoding="utf-8", xml_declaration=True, method="xml") - f.seek(0) - return f - -from random import random - - -def random_svg_color(): - r, g, b = random(), random(), random() - return f"rgb({r*255:.0f},{g*255:.0f},{b*255:.0f})" - - -def rgb_to_svg_color(r, g, b): - return f"rgb({r*255:.0f},{g*255:.0f},{b*255:.0f})" - - -def line_intersection(line1, line2): - - xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0]) - ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1]) - - def det(a, b): - return a[0] * b[1] - a[1] * b[0] - - div = det(xdiff, ydiff) - if div == 0: - # todo: deal with parallel line intersection / overlay - return False, None, None - - d = (det(*line1), det(*line2)) - x = det(d, xdiff) / div - y = det(d, ydiff) / div - - on_segments = ( - (x + EPS >= min(line1[0][0], line1[1][0])), - (x + EPS >= min(line2[0][0], line2[1][0])), - (x - EPS <= max(line1[0][0], line1[1][0])), - (x - EPS <= max(line2[0][0], line2[1][0])), - (y + EPS >= min(line1[0][1], line1[1][1])), - (y + EPS >= min(line2[0][1], line2[1][1])), - (y - EPS <= max(line1[0][1], line1[1][1])), - (y - EPS <= max(line2[0][1], line2[1][1])), - ) - - return min(on_segments), x, y diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/edges.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/edges.py deleted file mode 100644 index 18f6643..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/edges.py +++ /dev/null @@ -1,2666 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from __future__ import annotations - -import argparse -import inspect -import math -import re -from abc import ABC, abstractmethod -from typing import Any - -from boxes import gears - - -def argparseSections(s: str) -> list[float]: - """ - Parse sections parameter - - :param s: string to parse - """ - - result: list[float] = [] - - parse = re.split(r"\s|:", s) - - try: - for part in parse: - m = re.match(r"^(\d+(\.\d+)?)/(\d+)$", part) - if m: - n = int(m.group(3)) - result.extend([float(m.group(1)) / n] * n) - continue - m = re.match(r"^(\d+(\.\d+)?)\*(\d+)$", part) - if m: - n = int(m.group(3)) - result.extend([float(m.group(1))] * n) - continue - result.append(float(part)) - except ValueError: - raise argparse.ArgumentTypeError("Don't understand sections string") - - if not result: - result.append(0.0) - - return result - - -def getDescriptions() -> dict: - d = {edge.char: edge.description for edge in globals().values() - if inspect.isclass(edge) and issubclass(edge, BaseEdge) - and edge.char} - d['j'] = d['i'] + " (other end)" - d['J'] = d['I'] + " (other end)" - d['k'] = d['i'] + " (both ends)" - d['K'] = d['I'] + " (both ends)" - d['O'] = d['o'] + ' (other end)' - d['P'] = d['p'] + ' (other end)' - d['U'] = d['u'] + ' top side' - d['v'] = d['u'] + ' for 90° lid' - d['V'] = d['u'] + ' 90° lid' - return d - - -class BoltPolicy(ABC): - """Abstract class - - Distributes (bed) bolts on a number of segments - (fingers of a finger joint) - """ - - def drawbolt(self, pos) -> bool: - """Add a bolt to this segment? - - :param pos: number of the finger - """ - return False - - def numFingers(self, numFingers: int) -> int: - """Return next smaller, possible number of fingers - - :param numFingers: number of fingers to aim for - """ - return numFingers - - def _even(self, numFingers: int) -> int: - """ - Return same or next smaller even number - - :param numFingers: - """ - return (numFingers // 2) * 2 - - def _odd(self, numFingers: int) -> int: - """ - Return same or next smaller odd number - - :param numFingers: - """ - if numFingers % 2: - return numFingers - return numFingers - 1 - - -class Bolts(BoltPolicy): - """Distribute a fixed number of bolts evenly""" - - def __init__(self, bolts: int = 1) -> None: - self.bolts = bolts - - def numFingers(self, numFingers: int) -> int: - if self.bolts % 2: - self.fingers = self._even(numFingers) - else: - self.fingers = numFingers - - return self.fingers - - def drawBolt(self, pos): - """ - Return if this finger needs a bolt - - :param pos: number of this finger - """ - if pos > self.fingers // 2: - pos = self.fingers - pos - - if pos == 0: - return False - - if pos == self.fingers // 2 and not (self.bolts % 2): - return False - - return (math.floor((float(pos) * (self.bolts + 1) / self.fingers) - 0.01) != - math.floor((float(pos + 1) * (self.bolts + 1) / self.fingers) - 0.01)) - - -############################################################################# -### Settings -############################################################################# - -class Settings: - """Generic Settings class - - Used by different other classes to store measurements and details. - Supports absolute values and settings that grow with the thickness - of the material used. - - Overload the absolute_params and relative_params class attributes with - the supported keys and default values. The values are available via - attribute access. - """ - absolute_params: dict[str, Any] = {} # TODO find better typing. - relative_params: dict[str, Any] = {} # TODO find better typing. - - @classmethod - def parserArguments(cls, parser, prefix=None, **defaults): - prefix = prefix or cls.__name__[:-len("Settings")] - - lines = cls.__doc__.split("\n") - - # Parse doc string - descriptions = {} - r = re.compile(r"^ +\* +(\S+) +: .* : +(.*)") - for l in lines: - m = r.search(l) - if m: - descriptions[m.group(1)] = m.group(2) - - group = parser.add_argument_group(lines[0] or lines[1]) - group.prefix = prefix - for name, default in (sorted(cls.absolute_params.items()) + - sorted(cls.relative_params.items())): - # Handle choices - choices = None - if isinstance(default, tuple): - choices = default - t = type(default[0]) - for val in default: - if (type(val) is not t or - type(val) not in (bool, int, float, str)): - raise ValueError("Type not supported: %r", val) - default = default[0] - - # Overwrite default - if name in defaults: - default = type(default)(defaults[name]) - - if type(default) not in (bool, int, float, str): - raise ValueError("Type not supported: %r", default) - if type(default) is bool: - from boxes import BoolArg - t = BoolArg() - else: - t = type(default) - - group.add_argument(f"--{prefix}_{name}", - type=t, - action="store", default=default, - choices=choices, - help=descriptions.get(name)) - - def __init__(self, thickness, relative: bool = True, **kw) -> None: - self.values = {} - for name, value in self.absolute_params.items(): - if isinstance(value, tuple): - value = value[0] - if type(value) not in (bool, int, float, str): - raise ValueError("Type not supported: %r", value) - self.values[name] = value - - self.thickness = thickness - factor = 1.0 - if relative: - factor = thickness - for name, value in self.relative_params.items(): - self.values[name] = value * factor - self.setValues(thickness, relative, **kw) - - def edgeObjects(self, boxes, chars: str = "", add: bool = True): - """ - Generate Edge objects using this kind of settings - - :param boxes: Boxes object - :param chars: sequence of chars to be used by Edge objects - :param add: add the resulting Edge objects to the Boxes object's edges - """ - edges: list[Any] = [] - return self._edgeObjects(edges, boxes, chars, add) - - def _edgeObjects(self, edges, boxes, chars: str, add: bool): - for i, edge in enumerate(edges): - try: - char = chars[i] - edge.char = char - except IndexError: - pass - except TypeError: - pass - if add: - boxes.addParts(edges) - return edges - - def setValues(self, thickness, relative: bool = True, **kw): - """ - Set values - - :param thickness: thickness of the material used - :param relative: Do scale by thickness (Default value = True) - :param kw: parameters to set - """ - factor = 1.0 - if relative: - factor = thickness - for name, value in kw.items(): - if name in self.absolute_params: - self.values[name] = value - elif name in self.relative_params: - self.values[name] = value * factor - else: - raise ValueError(f"Unknown parameter for {self.__class__.__name__}: {name}") - self.checkValues() - - def checkValues(self) -> None: - """ - Check if all values are in the right range. Raise ValueError if needed. - """ - pass - - def __getattr__(self, name): - if "values" in self.__dict__ and name in self.values: - return self.values[name] - raise AttributeError - - -############################################################################# -### Edges -############################################################################# - - -class BaseEdge(ABC): - """Abstract base class for all Edges""" - char: str | None = None - description: str = "Abstract Edge Class" - - def __init__(self, boxes, settings) -> None: - self.boxes = boxes - self.ctx = boxes.ctx - self.settings = settings - - def __getattr__(self, name): - """Hack for using unalter code form Boxes class""" - return getattr(self.boxes, name) - - @abstractmethod - def __call__(self, length, **kw): - pass - - def startwidth(self) -> float: - """Amount of space the beginning of the edge is set below the inner space of the part """ - return 0.0 - - def endwidth(self) -> float: - return self.startwidth() - - def margin(self) -> float: - """Space needed right of the starting point""" - return 0.0 - - def spacing(self) -> float: - """Space the edge needs outside of the inner space of the part""" - return self.startwidth() + self.margin() - - def startAngle(self) -> float: - """Not yet supported""" - return 0.0 - - def endAngle(self) -> float: - """Not yet supported""" - return 0.0 - - -class Edge(BaseEdge): - """Straight edge""" - char = 'e' - description = "Straight Edge" - positive = False - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - """Draw edge of length mm""" - if bedBolts: - # distribute the bolts equidistantly - interval_length = length / bedBolts.bolts - if self.positive: - d = (bedBoltSettings or self.bedBoltSettings)[0] - for i in range(bedBolts.bolts): - self.hole(0.5 * interval_length, - 0.5 * self.thickness, 0.5 * d) - self.edge(interval_length, tabs= - (i == 0 or i == bedBolts.bolts - 1)) - else: - for i in range(bedBolts.bolts): - self.bedBoltHole(interval_length, bedBoltSettings, tabs= - (i == 0 or i == bedBolts.bolts - 1)) - else: - self.edge(length, tabs=2) - - -class OutSetEdge(Edge): - """Straight edge out set by one thickness""" - char = 'E' - description = "Straight Edge (outset by thickness)" - positive = True - - def startwidth(self) -> float: - return self.settings if self.settings is not None else self.boxes.thickness - - -############################################################################# -#### MountingEdge -############################################################################# - -class MountingSettings(Settings): - """Settings for Mounting Edge -Values: -* absolute_params - - * style : "straight edge, within" : edge style - * side : "back" : side of box (not all valid configurations make sense...) - * num : 2 : number of mounting holes (integer) - * margin : 0.125 : minimum space left and right without holes (fraction of the edge length) - * d_shaft : 3.0 : shaft diameter of mounting screw (in mm) - * d_head : 6.5 : head diameter of mounting screw (in mm) -""" - - PARAM_IN = "straight edge, within" - PARAM_EXT = "straight edge, extended" - PARAM_TAB = "mounting tab" - - PARAM_LEFT = "left" - PARAM_BACK = "back" - PARAM_RIGHT = "right" - PARAM_FRONT = "front" - - absolute_params = { - "style": (PARAM_IN, PARAM_EXT, PARAM_TAB), - "side": (PARAM_BACK, PARAM_LEFT, PARAM_RIGHT, PARAM_FRONT), - "num": 2, - "margin": 0.125, - "d_shaft": 3.0, - "d_head": 6.5 - } - - def edgeObjects(self, boxes, chars: str = "G", add: bool = True): - edges = [MountingEdge(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -class MountingEdge(BaseEdge): - description = """Edge with pear shaped mounting holes""" # for slide-on mounting using flat-head screws""" - char = 'G' - - def margin(self) -> float: - if self.settings.style == MountingSettings.PARAM_TAB: - return 2.75 * self.boxes.thickness + self.settings.d_head - return 0.0 - - def startwidth(self) -> float: - if self.settings.style == MountingSettings.PARAM_EXT: - return 2.5 * self.boxes.thickness + self.settings.d_head - return 0.0 - - def __call__(self, length, **kw): - if length == 0.0: - return - - def check_bounds(val, mn, mx, name): - if not mn <= val <= mx: - raise ValueError(f"MountingEdge: {name} needs to be in [{mn}, {mx}] but is {val}") - - style = self.settings.style - margin = self.settings.margin - num = self.settings.num - ds = self.settings.d_shaft - dh = self.settings.d_head - if dh > 0: - width = 3 * self.thickness + dh - else: - width = ds - - if num != int(num): - raise ValueError(f"MountingEdge: num needs to be an integer number") - - check_bounds(margin, 0, 0.5, "margin") - if not dh == 0: - if not dh > ds: - raise ValueError(f"MountingEdge: d_shaft needs to be in 0 or > {ds}, but is {dh}") - - # Check how many holes fit - count = max(1, int(num)) - if count > 1: - margin_ = length * margin - gap = (length - 2 * margin_ - width * count) / (count - 1) - if gap < width: - count = int(((length - 2 * margin + width) / (2 * width)) - 0.5) - if count < 1: - self.edge(length) - return - if count < 2: - margin_ = (length - width) / 2 - gap = 0 - else: - gap = (length - 2 * margin_ - width * count) / (count - 1) - else: - margin_ = (length - width) / 2 - gap = 0 - - if style == MountingSettings.PARAM_TAB: - - # The edge until the first groove - self.edge(margin_, tabs=1) - - for i in range(count): - if i > 0: - self.edge(gap) - self.corner(-90, self.thickness / 2) - self.edge(dh + 1.5 * ds - self.thickness / 4 - dh / 2) - self.corner(90, self.thickness + dh / 2) - self.corner(-90) - self.corner(90) - self.mountingHole(0, self.thickness * 1.25 + ds / 2, ds, dh, -90) - self.corner(90, self.thickness + dh / 2) - self.edge(dh + 1.5 * ds - self.thickness / 4 - dh / 2) - self.corner(-90, self.thickness / 2) - - # The edge until the end - self.edge(margin_, tabs=1) - else: - x = margin_ - for i in range(count): - x += width / 2 - self.mountingHole(x, ds / 2 + self.thickness * 1.5, ds, dh, -90) - x += width / 2 - x += gap - self.edge(length) - - -############################################################################# -#### GroovedEdge -############################################################################# - -class GroovedSettings(Settings): - """Settings for Grooved Edge -Values: - -* absolute_params - - * style : "arc" : the style of grooves - * tri_angle : 30 : the angle of triangular cuts - * arc_angle : 120 : the angle of arc cuts - * width : 0.2 : the width of each groove (fraction of the edge length) - * gap : 0.1 : the gap between grooves (fraction of the edge length) - * margin : 0.3 : minimum space left and right without grooves (fraction of the edge length) - * inverse : False : invert the groove directions - * interleave : False : alternate the direction of grooves -""" - - PARAM_ARC = "arc" - PARAM_FLAT = "flat" - PARAM_SOFTARC = "softarc" - PARAM_TRIANGLE = "triangle" - - absolute_params = { - "style": (PARAM_ARC, PARAM_FLAT, PARAM_TRIANGLE, PARAM_SOFTARC), - "tri_angle": 30, - "arc_angle": 120, - "width": 0.2, - "gap": 0.1, - "margin": 0.3, - "inverse": False, - "interleave": False, - } - - def edgeObjects(self, boxes, chars: str = "zZ", add: bool = True): - edges = [GroovedEdge(boxes, self), - GroovedEdgeCounterPart(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -class GroovedEdgeBase(BaseEdge): - def is_inverse(self) -> bool: - return self.settings.inverse != self.inverse - - def groove_arc(self, width, angle: float = 90.0, inv: float = -1.0) -> None: - side_length = width / math.sin(math.radians(angle)) / 2 - self.corner(inv * -angle) - self.corner(inv * angle, side_length) - self.corner(inv * angle, side_length) - self.corner(inv * -angle) - - def groove_soft_arc(self, width, angle: float = 60.0, inv: float = -1.0) -> None: - side_length = width / math.sin(math.radians(angle)) / 4 - self.corner(inv * -angle, side_length) - self.corner(inv * angle, side_length) - self.corner(inv * angle, side_length) - self.corner(inv * -angle, side_length) - - def groove_triangle(self, width, angle: float = 45.0, inv: float = -1.0) -> None: - side_length = width / math.cos(math.radians(angle)) / 2 - self.corner(inv * -angle) - self.edge(side_length) - self.corner(inv * 2 * angle) - self.edge(side_length) - self.corner(inv * -angle) - - def __call__(self, length, **kw): - if length == 0.0: - return - - def check_bounds(val, mn, mx, name): - if not mn <= val <= mx: - raise ValueError(f"{name} needs to be in [{mn}, {mx}] but is {val}") - - style = self.settings.style - width = self.settings.width - margin = self.settings.margin - gap = self.settings.gap - interleave = self.settings.interleave - - check_bounds(width, 0, 1, "width") - check_bounds(margin, 0, 0.5, "margin") - check_bounds(gap, 0, 1, "gap") - - # Check how many grooves fit - count = max(0, int((1 - 2 * margin + gap) / (width + gap))) - inside_width = max(0, count * (width + gap) - gap) - margin = (1 - inside_width) / 2 - - # Convert to actual length - margin = length * margin - gap = length * gap - width = length * width - - # Determine the initial inversion - inv = 1 if self.is_inverse() else -1 - if interleave and self.inverse and count % 2 == 0: - inv = -inv - - # The edge until the first groove - self.edge(margin, tabs=1) - - # Grooves - for i in range(count): - if i > 0: - self.edge(gap) - if interleave: - inv = -inv - if style == GroovedSettings.PARAM_FLAT: - self.edge(width) - elif style == GroovedSettings.PARAM_ARC: - angle = self.settings.arc_angle / 2 - self.groove_arc(width, angle, inv) - elif style == GroovedSettings.PARAM_SOFTARC: - angle = self.settings.arc_angle / 2 - self.groove_soft_arc(width, angle, inv) - elif style == GroovedSettings.PARAM_TRIANGLE: - angle = self.settings.tri_angle - self.groove_triangle(width, angle, inv) - else: - raise ValueError("Unknown GroovedEdge style: %s)" % style) - - # The final edge - self.edge(margin, tabs=1) - - -class GroovedEdge(GroovedEdgeBase): - description = """Edge with grooves""" - char = 'z' - inverse = False - - -class GroovedEdgeCounterPart(GroovedEdgeBase): - description = """Edge with grooves (opposing side)""" - char = 'Z' - inverse = True - - -############################################################################# -#### Gripping Edge -############################################################################# - -class GripSettings(Settings): - """Settings for GrippingEdge -Values: - -* absolute_params - - * style : "wave" : "wave" or "bumps" - * outset : True : extend outward the straight edge - -* relative (in multiples of thickness) - - * depth : 0.3 : depth of the grooves - -""" - - absolute_params = { - "style": ("wave", "bumps"), - "outset": True, - } - - relative_params = { - "depth": 0.3, - } - - def edgeObjects(self, boxes, chars: str = "g", add: bool = True): - edges = [GrippingEdge(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -class GrippingEdge(BaseEdge): - description = """Corrugated edge useful as an gipping area""" - char = 'g' - - def wave(self, length) -> None: - depth = self.settings.depth - grooves = int(length // (depth * 2.0)) + 1 - depth = length / grooves / 4.0 - - o = 1 if self.settings.outset else -1 - for groove in range(grooves): - self.corner(o * -90, depth) - self.corner(o * 180, depth) - self.corner(o * -90, depth) - - def bumps(self, length) -> None: - depth = self.settings.depth - grooves = int(length // (depth * 2.0)) + 1 - depth = length / grooves / 2.0 - o = 1 if self.settings.outset else -1 - - if self.settings.outset: - self.corner(-90) - else: - self.corner(90) - self.edge(depth) - self.corner(-180) - - for groove in range(grooves): - self.corner(180, depth) - self.corner(-180, 0) - - if self.settings.outset: - self.corner(90) - else: - self.edge(depth) - self.corner(90) - - def margin(self) -> float: - if self.settings.outset: - return self.settings.depth - return 0.0 - - def __call__(self, length, **kw): - if length == 0.0: - return - getattr(self, self.settings.style)(length) - - -class CompoundEdge(BaseEdge): - """Edge composed of multiple different Edges""" - description = "Compound Edge" - - def __init__(self, boxes, types, lengths) -> None: - super().__init__(boxes, None) - - self.types = [self.edges.get(edge, edge) for edge in types] - self.lengths = lengths - self.length = sum(lengths) - - def startwidth(self) -> float: - return self.types[0].startwidth() - - def endwidth(self) -> float: - return self.types[-1].endwidth() - - def margin(self) -> float: - return max(e.margin() + e.startwidth() for e in self.types) - self.types[0].startwidth() - - def __call__(self, length, **kw): - if length and abs(length - self.length) > 1E-5: - raise ValueError("Wrong length for CompoundEdge") - lastwidth = self.types[0].startwidth() - - for e, l in zip(self.types, self.lengths): - self.step(e.startwidth() - lastwidth) - e(l) - lastwidth = e.endwidth() - - -############################################################################# -#### Slots -############################################################################# - -class Slot(BaseEdge): - """Edge with a slot to slide another piece through """ - - description = "Slot" - - def __init__(self, boxes, depth) -> None: - super().__init__(boxes, None) - - self.depth = depth - - def __call__(self, length, **kw): - if self.depth: - self.boxes.corner(90) - self.boxes.edge(self.depth) - self.boxes.corner(-90) - self.boxes.edge(length) - self.boxes.corner(-90) - self.boxes.edge(self.depth) - self.boxes.corner(90) - else: - self.boxes.edge(self.length) - - -class SlottedEdge(BaseEdge): - """Edge with multiple slots""" - description = "Straight Edge with slots" - - def __init__(self, boxes, sections, edge: str = "e", slots: int = 0) -> None: - super().__init__(boxes, Settings(boxes.thickness)) - - self.edge = self.edges.get(edge, edge) - self.sections = sections - self.slots = slots - - def startwidth(self) -> float: - return self.edge.startwidth() - - def endwidth(self) -> float: - return self.edge.endwidth() - - def margin(self) -> float: - return self.edge.margin() - - def __call__(self, length, **kw): - - for l in self.sections[:-1]: - self.edge(l) - - if self.slots: - Slot(self.boxes, self.slots)(self.settings.thickness) - else: - self.boxes.edge(self.settings.thickness) - - self.edge(self.sections[-1]) - - -############################################################################# -#### Finger Joints -############################################################################# - -class FingerJointSettings(Settings): - """Settings for Finger Joints - -Values: - -* absolute - * style : "rectangular" : style of the fingers - * surroundingspaces : 2.0 : space at the start and end in multiple of normal spaces - * angle: 90 : Angle of the walls meeting - -* relative (in multiples of thickness) - - * space : 2.0 : space between fingers (multiples of thickness) - * finger : 2.0 : width of the fingers (multiples of thickness) - * width : 1.0 : width of finger holes (multiples of thickness) - * edge_width : 1.0 : space below holes of FingerHoleEdge (multiples of thickness) - * play : 0.0 : extra space to allow finger move in and out (multiples of thickness) - * extra_length : 0.0 : extra material to grind away burn marks (multiples of thickness) - * bottom_lip : 0.0 : height of the bottom lips sticking out (multiples of thickness) FingerHoleEdge only! -""" - - absolute_params = { - "style": ("rectangular", "springs", "barbs", "snap"), - "surroundingspaces": 2.0, - "angle": 90.0, - } - - relative_params = { - "space": 2.0, - "finger": 2.0, - "width": 1.0, - "edge_width": 1.0, - "play": 0.0, - "extra_length": 0.0, - "bottom_lip": 0.0, - } - - def checkValues(self) -> None: - if abs(self.space + self.finger) < 0.1: - raise ValueError("FingerJointSettings: space + finger must not be close to zero") - - def edgeObjects(self, boxes, chars: str = "fFh", add: bool = True): - edges = [FingerJointEdge(boxes, self), - FingerJointEdgeCounterPart(boxes, self), - FingerHoleEdge(boxes, self), - ] - return self._edgeObjects(edges, boxes, chars, add) - - -class FingerJointBase(ABC): - """Abstract base class for finger joint.""" - - def calcFingers(self, length: float, bedBolts) -> tuple[int, float]: - space, finger = self.settings.space, self.settings.finger # type: ignore - fingers = int((length - (self.settings.surroundingspaces - 1) * space) // (space + finger)) # type: ignore - # shrink surrounding space up to half a thickness each side - if fingers == 0 and length > finger + 1.0 * self.settings.thickness: # type: ignore - fingers = 1 - if not finger: - fingers = 0 - if bedBolts: - fingers = bedBolts.numFingers(fingers) - leftover = length - fingers * (space + finger) + space - - if fingers <= 0: - fingers = 0 - leftover = length - - return fingers, leftover - - def fingerLength(self, angle: float) -> tuple[float, float]: - # sharp corners - if angle >= 90 or angle <= -90: - return self.settings.thickness + self.settings.extra_length, 0.0 # type: ignore - - # inner blunt corners - if angle < 0: - return (math.sin(math.radians(-angle)) * self.settings.thickness + self.settings.extra_length), 0 # type: ignore - - # 0 to 90 (blunt corners) - a = 90 - (180 - angle) / 2.0 - fingerlength = self.settings.thickness * math.tan(math.radians(a)) # type: ignore - b = 90 - 2 * a - spacerecess = -math.sin(math.radians(b)) * fingerlength - return fingerlength + self.settings.extra_length, spacerecess # type: ignore - - -class FingerJointEdge(BaseEdge, FingerJointBase): - """Finger joint edge """ - char = 'f' - description = "Finger Joint" - positive = True - - def draw_finger(self, f, h, style, positive: bool = True, firsthalf: bool = True) -> None: - t = self.settings.thickness - - if positive: - if style == "springs": - self.polyline( - 0, -90, 0.8 * h, (90, 0.2 * h), - 0.1 * h, 90, 0.9 * h, -180, 0.9 * h, 90, - f - 0.6 * h, - 90, 0.9 * h, -180, 0.9 * h, 90, 0.1 * h, - (90, 0.2 * h), 0.8 * h, -90) - elif style == "barbs": - n = int((h - 0.1 * t) // (0.3 * t)) - a = math.degrees(math.atan(0.5)) - l = 5 ** 0.5 - poly = [h - n * 0.3 * t] + \ - ([-45, 0.1 * 2 ** 0.5 * t, 45 + a, l * 0.1 * t, -a, 0] * n) - self.polyline( - 0, -90, *poly, 90, f, 90, *reversed(poly), -90 - ) - elif style == "snap" and f > 1.9 * t: - a12 = math.degrees(math.atan(0.5)) - l12 = t / math.cos(math.radians(a12)) - d = 4 * t - d2 = d + 1 * t - a = math.degrees(math.atan((0.5 * t) / (h + d2))) - l = (h + d2) / math.cos(math.radians(a)) - poly = [0, 90, d, -180, d + h, -90, 0.5 * t, 90 + a12, l12, 90 - a12, - 0.5 * t, 90 - a, l, +a, 0, (-180, 0.1 * t), h + d2, 90, f - 1.7 * t, 90 - a12, l12, a12, h, -90, 0] - if firsthalf: - poly = list(reversed(poly)) - self.polyline(*poly) - else: - self.polyline(0, -90, h, 90, f, 90, h, -90) - else: - self.polyline(0, 90, h, -90, f, -90, h, 90) - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - - positive = self.positive - t = self.settings.thickness - - s, f = self.settings.space, self.settings.finger - thickness = self.settings.thickness - style = self.settings.style - play = self.settings.play - - fingers, leftover = self.calcFingers(length, bedBolts) - - # not enough space for normal fingers - use small rectangular one - if (fingers == 0 and f and - leftover > 0.75 * thickness and leftover > 4 * play): - fingers = 1 - f = leftover = leftover / 2.0 - bedBolts = None - style = "rectangular" - - if not positive: - f += play - s -= play - leftover -= play - - self.edge(leftover / 2.0, tabs=1) - - l1, l2 = self.fingerLength(self.settings.angle) - h = l1 - l2 - - d = (bedBoltSettings or self.bedBoltSettings)[0] - - for i in range(fingers): - if i != 0: - if not positive and bedBolts and bedBolts.drawBolt(i): - self.hole(0.5 * s, - 0.5 * self.settings.thickness, 0.5 * d) - - if positive and bedBolts and bedBolts.drawBolt(i): - self.bedBoltHole(s, bedBoltSettings) - else: - self.edge(s) - self.draw_finger(f, h, style, - positive, i < fingers // 2) - - self.edge(leftover / 2.0, tabs=1) - - def margin(self) -> float: - """ """ - widths = self.fingerLength(self.settings.angle) - if self.positive: - if self.settings.style == "snap": - return widths[0] - widths[1] + self.settings.thickness - return widths[0] - widths[1] - return 0.0 - - def startwidth(self) -> float: - widths = self.fingerLength(self.settings.angle) - return widths[self.positive] - - -class FingerJointEdgeCounterPart(FingerJointEdge): - """Finger joint edge - other side""" - char = 'F' - description = "Finger Joint (opposing side)" - positive = False - - -class FingerHoles(FingerJointBase): - """Hole matching a finger joint edge""" - - def __init__(self, boxes, settings) -> None: - self.boxes = boxes - self.ctx = boxes.ctx - self.settings = settings - - def __call__(self, x, y, length, angle=90, bedBolts=None, bedBoltSettings=None): - """ - Draw holes for a matching finger joint edge - - :param x: position - :param y: position - :param length: length of matching edge - :param angle: (Default value = 90) - :param bedBolts: (Default value = None) - :param bedBoltSettings: (Default value = None) - """ - with self.boxes.saved_context(): - self.boxes.moveTo(x, y, angle) - s, f = self.settings.space, self.settings.finger - p = self.settings.play - b = self.boxes.burn - fingers, leftover = self.calcFingers(length, bedBolts) - - # not enough space for normal fingers - use small rectangular one - if (fingers == 0 and f and - leftover > 0.75 * self.settings.thickness and leftover > 4 * p): - fingers = 1 - f = leftover = leftover / 2.0 - bedBolts = None - - if self.boxes.debug: - self.ctx.rectangle(b, -self.settings.width / 2 + b, - length - 2 * b, self.settings.width - 2 * b) - for i in range(fingers): - pos = leftover / 2.0 + i * (s + f) - - if bedBolts and bedBolts.drawBolt(i): - d = (bedBoltSettings or self.boxes.bedBoltSettings)[0] - self.boxes.hole(pos - 0.5 * s, 0, d * 0.5) - - self.boxes.rectangularHole(pos + 0.5 * f, 0, - f + p, self.settings.width + p) - - -class FingerHoleEdge(BaseEdge): - """Edge with holes for a parallel finger joint""" - char = 'h' - description = "Edge (parallel Finger Joint Holes)" - - def __init__(self, boxes, fingerHoles=None, **kw) -> None: - settings = None - if isinstance(fingerHoles, Settings): - settings = fingerHoles - fingerHoles = FingerHoles(boxes, settings) - super().__init__(boxes, settings, **kw) - - self.fingerHoles = fingerHoles or boxes.fingerHolesAt - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - dist = self.fingerHoles.settings.edge_width - with self.saved_context(): - self.fingerHoles( - 0, self.burn + dist + self.settings.thickness / 2, length, 0, - bedBolts=bedBolts, bedBoltSettings=bedBoltSettings) - if self.settings.bottom_lip: - h = self.settings.bottom_lip + \ - self.fingerHoles.settings.edge_width - sp = self.boxes.spacing - self.moveTo(-sp / 2, -h - sp) - self.rectangularWall(length - 1.05 * self.boxes.thickness, h) - self.edge(length, tabs=2) - - def startwidth(self) -> float: - """ """ - return self.fingerHoles.settings.edge_width + self.settings.thickness - - def margin(self) -> float: - if self.settings.bottom_lip: - return self.settings.bottom_lip + self.fingerHoles.settings.edge_width + self.boxes.spacing - return 0.0 - - -class CrossingFingerHoleEdge(Edge): - """Edge with holes for finger joints 90° above""" - - description = "Edge (orthogonal Finger Joint Holes)" - char = '|' - - def __init__(self, boxes, height, fingerHoles=None, outset: float = 0.0, **kw) -> None: - super().__init__(boxes, None, **kw) - - self.fingerHoles = fingerHoles or boxes.fingerHolesAt - self.height = height - self.outset = outset - - def __call__(self, length, **kw): - self.fingerHoles(length / 2.0, self.outset + self.burn, self.height) - super().__call__(length) - - def startwidth(self) -> float: - return self.outset - - -############################################################################# -#### Stackable Joints -############################################################################# - -class StackableSettings(Settings): - """Settings for Stackable Edges - -Values: - -* absolute_params - - * angle : 60 : inside angle of the feet - -* relative (in multiples of thickness) - - * height : 2.0 : height of the feet (multiples of thickness) - * width : 4.0 : width of the feet (multiples of thickness) - * holedistance : 1.0 : distance from finger holes to bottom edge (multiples of thickness) - * bottom_stabilizers : 0.0 : height of strips to be glued to the inside of bottom edges (multiples of thickness) - -""" - - absolute_params = { - "angle": 60, - } - - relative_params = { - "height": 2.0, - "width": 4.0, - "holedistance": 1.0, - "bottom_stabilizers": 0.0, - } - - def checkValues(self) -> None: - if self.angle < 20: - raise ValueError("StackableSettings: 'angle' is too small. Use value >= 20") - if self.angle > 260: - raise ValueError("StackableSettings: 'angle' is too big. Use value < 260") - - def edgeObjects(self, boxes, chars: str = "sSšŠ", add: bool = True, fingersettings=None): - fingersettings = fingersettings or boxes.edges["f"].settings - edges = [StackableEdge(boxes, self, fingersettings), - StackableEdgeTop(boxes, self, fingersettings), - StackableFeet(boxes, self, fingersettings), - StackableHoleEdgeTop(boxes, self, fingersettings), - ] - return self._edgeObjects(edges, boxes, chars, add) - - -class StackableBaseEdge(BaseEdge): - """Edge for having stackable Boxes. The Edge creates feet on the bottom - and has matching recesses on the top corners.""" - - char = "s" - description = "Abstract Stackable class" - bottom = True - - def __init__(self, boxes, settings, fingerjointsettings) -> None: - super().__init__(boxes, settings) - - self.fingerjointsettings = fingerjointsettings - - def __call__(self, length, **kw): - s = self.settings - r = s.height / 2.0 / (1 - math.cos(math.radians(s.angle))) - l = r * math.sin(math.radians(s.angle)) - p = 1 if self.bottom else -1 - - if self.bottom and s.bottom_stabilizers: - with self.saved_context(): - sp = self.boxes.spacing - self.moveTo(-sp / 2, -s.height - sp) - self.rectangularWall(length - 1.05 * self.boxes.thickness, - s.bottom_stabilizers) - - self.boxes.edge(s.width, tabs=1) - self.boxes.corner(p * s.angle, r) - self.boxes.corner(-p * s.angle, r) - self.boxes.edge(length - 2 * s.width - 4 * l) - self.boxes.corner(-p * s.angle, r) - self.boxes.corner(p * s.angle, r) - self.boxes.edge(s.width, tabs=1) - - def _height(self): - return self.settings.height + self.settings.holedistance + self.settings.thickness - - def startwidth(self) -> float: - return self._height() if self.bottom else 0 - - def margin(self) -> float: - if self.bottom: - if self.settings.bottom_stabilizers: - return self.settings.bottom_stabilizers + self.boxes.spacing - else: - return 0 - else: - return self.settings.height - - -class StackableEdge(StackableBaseEdge): - """Edge for having stackable Boxes. The Edge creates feet on the bottom - and has matching recesses on the top corners.""" - - char = "s" - description = "Stackable (bottom, finger joint holes)" - - def __call__(self, length, **kw): - s = self.settings - self.boxes.fingerHolesAt( - 0, - s.height + s.holedistance + 0.5 * self.boxes.thickness, - length, 0) - super().__call__(length, **kw) - - -class StackableEdgeTop(StackableBaseEdge): - char = "S" - description = "Stackable (top)" - bottom = False - - -class StackableFeet(StackableBaseEdge): - char = "š" - description = "Stackable feet (bottom)" - - def _height(self): - return self.settings.height - - -class StackableHoleEdgeTop(StackableBaseEdge): - char = "Š" - description = "Stackable edge with finger holes (top)" - bottom = False - - def startwidth(self) -> float: - return self.settings.thickness + self.settings.holedistance - - def __call__(self, length, **kw): - s = self.settings - self.boxes.fingerHolesAt( - 0, - s.holedistance + 0.5 * self.boxes.thickness, - length, 0) - super().__call__(length, **kw) - - -############################################################################# -#### Hinges -############################################################################# - -class HingeSettings(Settings): - """Settings for Hinges and HingePins -Values: - -* absolute_params - - * style : "outset" : "outset" or "flush" - * outset : False : have lid overlap at the sides (similar to OutSetEdge) - * pinwidth : 1.0 : set to lower value to get disks surrounding the pins - * grip_percentage" : 0 : percentage of the lid that should get grips - -* relative (in multiples of thickness) - - * hingestrength : 1 : thickness of the arc holding the pin in place (multiples of thickness) - * axle : 2 : diameter of the pin hole (multiples of thickness) - * grip_length : 0 : fixed length of the grips on he lids (multiples of thickness) - -""" - absolute_params = { - "style": ("outset", "flush"), - "outset": False, - "pinwidth": 0.5, - "grip_percentage": 0, - } - - relative_params = { - "hingestrength": 1, # 1.5-0.5*2**0.5, - "axle": 2.0, - "grip_length": 0, - } - - def checkValues(self) -> None: - if self.axle / self.thickness < 0.1: - raise ValueError("HingeSettings: 'axle' need to be at least 0.1 strong") - - def edgeObjects(self, boxes, chars: str = "iIjJkK", add: bool = True): - edges = [ - Hinge(boxes, self, 1), - HingePin(boxes, self, 1), - Hinge(boxes, self, 2), - HingePin(boxes, self, 2), - Hinge(boxes, self, 3), - HingePin(boxes, self, 3), - ] - return self._edgeObjects(edges, boxes, chars, add) - - -class Hinge(BaseEdge): - char = 'i' - description = "Straight edge with hinge eye" - - def __init__(self, boxes, settings=None, layout: int = 1) -> None: - super().__init__(boxes, settings) - - if not (0 < layout <= 3): - raise ValueError("layout must be 1, 2 or 3 (got %i)" % layout) - - self.layout = layout - self.char = "eijk"[layout] - self.description = self.description + ('', ' (start)', ' (end)', ' (both ends)')[layout] - - def margin(self) -> float: - t: float = self.settings.thickness - if self.settings.style == "outset": - r = 0.5 * self.settings.axle - alpha = math.degrees(math.asin(0.5 * t / r)) - pos = math.cos(math.radians(alpha)) * r - return 1.5 * t + pos - else: # flush - return 0.5 * t + 0.5 * self.settings.axle + self.settings.hingestrength - - def outset(self, _reversed: bool = False) -> None: - t: float = self.settings.thickness - r = 0.5 * self.settings.axle - alpha = math.degrees(math.asin(0.5 * t / r)) - pinl = (self.settings.axle ** 2 - self.settings.thickness ** 2) ** 0.5 * self.settings.pinwidth - pos = math.cos(math.radians(alpha)) * r - hinge = ( - 0., - 90. - alpha, 0., - (-360., r), 0., - 90. + alpha, - t, - 90., - 0.5 * t, - (180., t + pos), 0., - (-90., 0.5 * t), 0. - ) - - if _reversed: - hinge = reversed(hinge) # type: ignore - self.polyline(*hinge) - self.boxes.rectangularHole(-pos, -0.5 * t, pinl, self.settings.thickness) - else: - self.boxes.rectangularHole(pos, -0.5 * t, pinl, self.settings.thickness) - self.polyline(*hinge) - - def outsetlen(self) -> float: - t = self.settings.thickness - r = 0.5 * self.settings.axle - alpha = math.degrees(math.asin(0.5 * t / r)) - pos = math.cos(math.radians(alpha)) * r - - return 2.0 * pos + 1.5 * t - - def flush(self, _reversed: bool = False) -> None: - t = self.settings.thickness - - hinge = ( - 0., -90., - 0.5 * t, - (180., 0.5 * self.settings.axle + self.settings.hingestrength), 0., - (-90., 0.5 * t), 0. - ) - pos = 0.5 * self.settings.axle + self.settings.hingestrength - pinl = (self.settings.axle ** 2 - self.settings.thickness ** 2) ** 0.5 * self.settings.pinwidth - - if _reversed: - hinge = reversed(hinge) # type: ignore - self.hole(0.5 * t + pos, -0.5 * t, 0.5 * self.settings.axle) - self.boxes.rectangularHole(0.5 * t + pos, -0.5 * t, pinl, self.settings.thickness) - else: - self.hole(pos, -0.5 * t, 0.5 * self.settings.axle) - self.boxes.rectangularHole(pos, -0.5 * t, pinl, self.settings.thickness) - - self.polyline(*hinge) - - def flushlen(self) -> float: - return self.settings.axle + 2.0 * self.settings.hingestrength + 0.5 * self.settings.thickness - - def __call__(self, l, **kw): - hlen = getattr(self, self.settings.style + 'len', self.outsetlen)() - - if self.layout & 1: - getattr(self, self.settings.style, self.outset)() - - self.edge(l - (self.layout & 1) * hlen - bool(self.layout & 2) * hlen, - tabs=2) - - if self.layout & 2: - getattr(self, self.settings.style, self.outset)(True) - - -class HingePin(BaseEdge): - char = 'I' - description = "Edge with hinge pin" - - def __init__(self, boxes, settings=None, layout: int = 1) -> None: - super().__init__(boxes, settings) - - if not (0 < layout <= 3): - raise ValueError("layout must be 1, 2 or 3 (got %i)" % layout) - - self.layout = layout - self.char = "EIJK"[layout] - self.description = self.description + ('', ' (start)', ' (end)', ' (both ends)')[layout] - - def startwidth(self) -> float: - if self.layout & 1: - return 0.0 - return self.settings.outset * self.boxes.thickness - - def endwidth(self) -> float: - if self.layout & 2: - return 0.0 - return self.settings.outset * self.boxes.thickness - - def margin(self) -> float: - return self.settings.thickness - - def outset(self, _reversed: bool = False) -> None: - t: float = self.settings.thickness - r = 0.5 * self.settings.axle - alpha = math.degrees(math.asin(0.5 * t / r)) - pos = math.cos(math.radians(alpha)) * r - pinl = (self.settings.axle ** 2 - self.settings.thickness ** 2) ** 0.5 * self.settings.pinwidth - pin = (pos - 0.5 * pinl, -90., - t, 90., - pinl, - 90., - t, - -90.) - - if self.settings.outset: - pin += ( # type: ignore - pos - 0.5 * pinl + 1.5 * t, - -90., - t, - 90., - 0., - ) - else: - pin += (pos - 0.5 * pinl,) # type: ignore - - if _reversed: - pin = reversed(pin) # type: ignore - - self.polyline(*pin) - - def outsetlen(self): - t = self.settings.thickness - r = 0.5 * self.settings.axle - alpha = math.degrees(math.asin(0.5 * t / r)) - pos = math.cos(math.radians(alpha)) * r - - if self.settings.outset: - return 2 * pos + 1.5 * self.settings.thickness - return 2 * pos - - def flush(self, _reversed: bool = False) -> None: - t: float = self.settings.thickness - pinl = (self.settings.axle ** 2 - t ** 2) ** 0.5 * self.settings.pinwidth - d = (self.settings.axle - pinl) / 2.0 - pin = (self.settings.hingestrength + d, -90., - t, 90., - pinl, - 90., - t, - -90., d) - - if self.settings.outset: - pin += ( # type: ignore - 0., - self.settings.hingestrength + 0.5 * t, - -90., - t, - 90., - 0., - ) - - if _reversed: - pin = reversed(pin) # type: ignore - - self.polyline(*pin) - - def flushlen(self): - l = self.settings.hingestrength + self.settings.axle - - if self.settings.outset: - l += self.settings.hingestrength + 0.5 * self.settings.thickness - - return l - - def __call__(self, l, **kw): - plen = getattr(self, self.settings.style + 'len', self.outsetlen)() - glen = l * self.settings.grip_percentage / 100 + \ - self.settings.grip_length - - if not self.settings.outset: - glen = 0.0 - - glen = min(glen, l - plen) - - if self.layout & 1 and self.layout & 2: - getattr(self, self.settings.style, self.outset)() - self.edge(l - 2 * plen, tabs=2) - getattr(self, self.settings.style, self.outset)(True) - elif self.layout & 1: - getattr(self, self.settings.style, self.outset)() - self.edge(l - plen - glen, tabs=2) - self.edges['g'](glen) - else: - self.edges['g'](glen) - self.edge(l - plen - glen, tabs=2) - getattr(self, self.settings.style, self.outset)(True) - - -############################################################################# -#### Chest Hinge -############################################################################# - -class ChestHingeSettings(Settings): - """Settings for Chest Hinges -Values: - -* relative (in multiples of thickness) - - * pin_height : 2.0 : radius of the disc rotating in the hinge (multiples of thickness) - * hinge_strength : 1.0 : thickness of the arc holding the pin in place (multiples of thickness) - -* absolute - - * finger_joints_on_box : False : whether to include finger joints on the edge with the box - * finger_joints_on_lid : False : whether to include finger joints on the edge with the lid -""" - - relative_params = { - "pin_height": 2.0, - "hinge_strength": 1.0, - "play": 0.1, - } - - absolute_params = { - "finger_joints_on_box": False, - "finger_joints_on_lid": False, - } - - def checkValues(self) -> None: - if self.pin_height / self.thickness < 1.2: - raise ValueError("ChestHingeSettings: 'pin_height' must be >= 1.2") - - def pinheight(self): - return ((0.9 * self.pin_height) ** 2 - self.thickness ** 2) ** 0.5 - - def edgeObjects(self, boxes, chars: str = "oOpPqQ", add: bool = True): - edges = [ - ChestHinge(boxes, self), - ChestHinge(boxes, self, True), - ChestHingeTop(boxes, self), - ChestHingeTop(boxes, self, True), - ChestHingePin(boxes, self), - ChestHingeFront(boxes, self), - ] - return self._edgeObjects(edges, boxes, chars, add) - - -class ChestHinge(BaseEdge): - description = "Edge with chest hinge" - - char = "o" - - def __init__(self, boxes, settings=None, reversed: bool = False) -> None: - super().__init__(boxes, settings) - - self.reversed = reversed - self.char = "oO"[reversed] - self.description = self.description + (' (start)', ' (end)')[reversed] - - def __call__(self, l, **kw): - t = self.settings.thickness - p = self.settings.pin_height - s = self.settings.hinge_strength - pinh = self.settings.pinheight() - if self.reversed: - self.hole(l + t, 0, p, tabs=4) - self.rectangularHole(l + 0.5 * t, -0.5 * pinh, t, pinh) - else: - self.hole(-t, -s - p, p, tabs=4) - self.rectangularHole(-0.5 * t, -s - p - 0.5 * pinh, t, pinh) - - if self.settings.finger_joints_on_box: - final_segment = t - s - draw_rest_of_edge = lambda: self.edges["F"](l - p) - else: - final_segment = l + t - p - s - draw_rest_of_edge = lambda: None - - poly = (0, -180, t, (270, p + s), 0, -90, final_segment) - - if self.reversed: - draw_rest_of_edge() - self.polyline(*reversed(poly)) - else: - self.polyline(*poly) - draw_rest_of_edge() - - def margin(self) -> float: - if self.reversed: - return 0.0 - return 1 * (self.settings.pin_height + self.settings.hinge_strength) - - def startwidth(self) -> float: - if self.reversed: - return self.settings.pin_height + self.settings.hinge_strength - return 0.0 - - def endwidth(self) -> float: - if self.reversed: - return 0.0 - return self.settings.pin_height + self.settings.hinge_strength - - -class ChestHingeTop(ChestHinge): - """Edge above a chest hinge""" - - char = "p" - - def __init__(self, boxes, settings=None, reversed: bool = False) -> None: - super().__init__(boxes, settings) - - self.reversed = reversed - self.char = "oO"[reversed] - self.description = self.description + (' (start)', ' (end)')[reversed] - - def __call__(self, l, **kw): - t = self.settings.thickness - p = self.settings.pin_height - s = self.settings.hinge_strength - play = self.settings.play - - if self.settings.finger_joints_on_lid: - final_segment = t - s - play - draw_rest_of_edge = lambda: self.edges["F"](l - p) - else: - final_segment = l + t - p - s - play - draw_rest_of_edge = lambda: None - - poly = (0, -180, t, -180, 0, (-90, p + s + play), 0, 90, final_segment) - - if self.reversed: - draw_rest_of_edge() - self.polyline(*reversed(poly)) - else: - self.polyline(*poly) - draw_rest_of_edge() - - def startwidth(self) -> float: - if self.reversed: - return self.settings.play + self.settings.pin_height + self.settings.hinge_strength - return 0.0 - - def endwidth(self) -> float: - if self.reversed: - return 0.0 - return self.settings.play + self.settings.pin_height + self.settings.hinge_strength - - def margin(self) -> float: - if self.reversed: - return 0.0 - return 1 * (self.settings.play + self.settings.pin_height + self.settings.hinge_strength) - - -class ChestHingePin(BaseEdge): - description = "Edge with pins for an chest hinge" - - char = "q" - - def __call__(self, l, **kw): - t = self.settings.thickness - p = self.settings.pin_height - s = self.settings.hinge_strength - pinh = self.settings.pinheight() - - if self.settings.finger_joints_on_lid: - middle_segment = [0] - draw_rest_of_edge = lambda: (self.edge(t), self.edges["F"](l), self.edge(t)) - else: - middle_segment = [l + 2 * t, ] - draw_rest_of_edge = lambda: None - - poly = [0, -90, s + p - pinh, -90, t, 90, pinh, 90, ] - self.polyline(*poly) - draw_rest_of_edge() - self.polyline(*(middle_segment + list(reversed(poly)))) - - def margin(self) -> float: - return (self.settings.pin_height + self.settings.hinge_strength) - - -class ChestHingeFront(Edge): - description = "Edge opposing a chest hinge" - - char = "Q" - - def startwidth(self) -> float: - return self.settings.pin_height + self.settings.hinge_strength - - -############################################################################# -#### Cabinet Hinge -############################################################################# - -class CabinetHingeSettings(Settings): - """Settings for Cabinet Hinges -Values: - -* absolute_params - - * bore : 3.2 : diameter of the pin hole in mm - * eyes_per_hinge : 5 : pieces per hinge - * hinges : 2 : number of hinges per edge - * style : inside : style of hinge used - -* relative (in multiples of thickness) - - * eye : 1.5 : radius of the eye (multiples of thickness) - * play : 0.05 : space between eyes (multiples of thickness) - * spacing : 2.0 : minimum space around the hinge (multiples of thickness) -""" - absolute_params = { - "bore": 3.2, - "eyes_per_hinge": 5, - "hinges": 2, - "style": ("inside", "outside"), - } - - relative_params = { - "eye": 1.5, - "play": 0.05, - "spacing": 2.0, - } - - def edgeObjects(self, boxes, chars: str = "uUvV", add: bool = True): - edges = [CabinetHingeEdge(boxes, self), - CabinetHingeEdge(boxes, self, top=True), - CabinetHingeEdge(boxes, self, angled=True), - CabinetHingeEdge(boxes, self, top=True, angled=True), - ] - for e, c in zip(edges, chars): - e.char = c - return self._edgeObjects(edges, boxes, chars, add) - - -class CabinetHingeEdge(BaseEdge): - """Edge with cabinet hinges""" - - char = "u" - description = "Edge with cabinet hinges" - - def __init__(self, boxes, settings=None, top: bool = False, angled: bool = False) -> None: - super().__init__(boxes, settings) - self.top = top - self.angled = angled - self.char = "uUvV"[bool(top) + 2 * bool(angled)] - - def startwidth(self) -> float: - return self.settings.thickness if self.top and self.angled else 0.0 - - def __poly(self): - n = self.settings.eyes_per_hinge - p = self.settings.play - e = self.settings.eye - t = self.settings.thickness - spacing = self.settings.spacing - - if self.settings.style == "outside" and self.angled: - e = t - elif self.angled and not self.top: - # move hinge up to leave space for lid - e -= t - - if self.top: - # start with space - poly = [spacing, 90, e + p] - else: - # start with hinge eye - poly = [spacing + p, 90, e + p, 0] - for i in range(n): - if (i % 2) ^ self.top: - # space - if i == 0: - poly += [-90, t + 2 * p, 90] - else: - poly += [90, t + 2 * p, 90] - else: - # hinge eye - poly += [t - p, -90, t, -90, t - p] - - if (n % 2) ^ self.top: - # stopped with hinge eye - poly += [0, e + p, 90, p + spacing] - else: - # stopped with space - poly[-1:] = [-90, e + p, 90, 0 + spacing] - - width = (t + p) * n + p + 2 * spacing - - return poly, width - - def __call__(self, l, **kw): - n = self.settings.eyes_per_hinge - p = self.settings.play - e = self.settings.eye - t = self.settings.thickness - hn = self.settings.hinges - - poly, width = self.__poly() - - if self.settings.style == "outside" and self.angled: - e = t - elif self.angled and not self.top: - # move hinge up to leave space for lid - e -= t - - hn = min(hn, int(l // width)) - - if hn == 1: - self.edge((l - width) / 2, tabs=2) - - for j in range(hn): - for i in range(n): - if not (i % 2) ^ self.top: - self.rectangularHole(self.settings.spacing + 0.5 * t + p + i * (t + p), e + 2.5 * t, t, t) - self.polyline(*poly) - if j < (hn - 1): - self.edge((l - hn * width) / (hn - 1), tabs=2) - - if hn == 1: - self.edge((l - width) / 2, tabs=2) - - def parts(self, move=None) -> None: - e, b = self.settings.eye, self.settings.bore - t = self.settings.thickness - - n = self.settings.eyes_per_hinge * self.settings.hinges - pairs = n // 2 + 2 * (n % 2) - - if self.settings.style == "outside": - th = 2 * e + 4 * t - tw = n * (max(3 * t, 2 * e) + self.boxes.spacing) - else: - th = 4 * e + 3 * t + self.boxes.spacing - tw = max(e, 2 * t) * pairs - - if self.move(tw, th, move, True, label="hinges"): - return - - if self.settings.style == "outside": - ax = max(t / 2, e - t) - self.moveTo(t + ax) - for i in range(n): - if self.angled: - if i > n // 2: - l = 4 * t + ax - else: - l = 5 * t + ax - else: - l = 3 * t + e - self.hole(0, e, b / 2.0) - da = math.asin((t - ax) / e) - dad = math.degrees(da) - dy = e * (1 - math.cos(da)) - self.polyline(0, (180 - dad, e), 0, (-90 + dad), dy + l - e, (90, t)) - self.polyline(0, 90, t, -90, t, 90, t, 90, t, -90, t, -90, t, - 90, t, 90, (ax + t) - e, -90, l - 3 * t, (90, e)) - self.moveTo(2 * max(e, 1.5 * t) + self.boxes.spacing) - - self.move(tw, th, move, label="hinges") - return - - if e <= 2 * t: - if self.angled: - corner = [2 * e - t, (90, 2 * t - e), 0, -90, t, (90, e)] - else: - corner = [2 * e, (90, 2 * t)] - else: - a = math.asin(2 * t / e) - ang = math.degrees(a) - corner = [e * (1 - math.cos(a)) + 2 * t, -90 + ang, 0, (180 - ang, e)] - self.moveTo(max(e, 2 * t)) - for i in range(n): - self.hole(0, e, b / 2.0) - self.polyline(*[0, (180, e), 0, -90, t, 90, t, -90, t, -90, t, 90, t, 90, t, (90, t)] + corner) - self.moveTo(self.boxes.spacing, 4 * e + 3 * t + self.boxes.spacing, 180) - if i % 2: - self.moveTo(2 * max(e, 2 * t) + 2 * self.boxes.spacing) - - self.move(th, tw, move, label="hinges") - - -############################################################################# -#### Slide-on lid -############################################################################# - -class SlideOnLidSettings(FingerJointSettings): - """Settings for Slide-on Lids - -Note that edge_width below also determines how much the sides extend above the lid. - -Values: - -* absolute_params - - * second_pin : True : additional pin for better positioning - * spring : "both" : position(s) of the extra locking springs in the lid - * hole_width : 0 : width of the "finger hole" in mm - """ - __doc__ += FingerJointSettings.__doc__ or "" - - absolute_params = FingerJointSettings.absolute_params.copy() - relative_params = FingerJointSettings.relative_params.copy() - - relative_params.update({ - "play": 0.05, - "finger": 3.0, - "space": 2.0, - }) - - absolute_params.update({ - "second_pin": True, - "spring": ("both", "none", "left", "right"), - "hole_width": 0 - }) - - def edgeObjects(self, boxes, chars=None, add: bool = True): - edges = [LidEdge(boxes, self), - LidHoleEdge(boxes, self), - LidRight(boxes, self), - LidLeft(boxes, self), - LidSideRight(boxes, self), - LidSideLeft(boxes, self), - ] - return self._edgeObjects(edges, boxes, chars, add) - - -class LidEdge(FingerJointEdge): - char = "l" - description = "Edge for slide on lid (back)" - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - hole_width = self.settings.hole_width - if hole_width > 0: - super().__call__((length - hole_width) / 2) - GroovedEdgeBase.groove_arc(self, hole_width) - super().__call__((length - hole_width) / 2) - else: - super().__call__(length) - - -class LidHoleEdge(FingerHoleEdge): - char = "L" - description = "Edge for slide on lid (box back)" - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw) -> None: - hole_width = self.settings.hole_width - if hole_width > 0: - super().__call__((length - hole_width) / 2) - self.edge(hole_width) - super().__call__((length - hole_width) / 2) - else: - super().__call__(length) - - -class LidRight(BaseEdge): - char = "n" - description = "Edge for slide on lid (right)" - rightside = True - - def __call__(self, length, **kw): - t = self.boxes.thickness - - if self.rightside: - spring = self.settings.spring in ("right", "both") - else: - spring = self.settings.spring in ("left", "both") - - if spring: - l = min(6 * t, length - 2 * t) - a = 30 - sqt = 0.4 * t / math.cos(math.radians(a)) - sw = 0.5 * t - p = [0, 90, 1.5 * t + sw, -90, l, (-180, 0.25 * t), l - 0.2 * t, 90, sw, 90 - a, sqt, 2 * a, sqt, -a, length - t] - else: - p = [t, 90, t, -90, length - t] - - pin = self.settings.second_pin - - if pin: - pinl = 2 * t - p[-1:] = [length - 2 * t - pinl, -90, t, 90, pinl, 90, t, -90, t] - - if not self.rightside: - p = list(reversed(p)) - self.polyline(*p) - - def startwidth(self) -> float: - if self.rightside: # or self.settings.second_pin: - return self.boxes.thickness - return 0.0 - - def endwidth(self) -> float: - if not self.rightside: # or self.settings.second_pin: - return self.boxes.thickness - return 0.0 - - def margin(self) -> float: - if not self.rightside: # and not self.settings.second_pin: - return self.boxes.thickness - return 0.0 - - -class LidLeft(LidRight): - char = "m" - description = "Edge for slide on lid (left)" - rightside = False - - -class LidSideRight(BaseEdge): - char = "N" - description = "Edge for slide on lid (box right)" - - rightside = True - - def __call__(self, length, **kw): - t = self.boxes.thickness - s = self.settings.play - pin = self.settings.second_pin - edge_width = self.settings.edge_width - r = edge_width / 3 - - if self.rightside: - spring = self.settings.spring in ("right", "both") - else: - spring = self.settings.spring in ("left", "both") - - if spring: - p = [s, -90, t + s, -90, t + s, 90, edge_width - s / 2, 90, length + t] - else: - p = [t + s, -90, t + s, -90, 2 * t + s, 90, edge_width - s / 2, 90, length + t] - - if pin: - pinl = 2 * t - p[-1:] = [p[-1] - 1.5 * t - 2 * pinl - r, (90, r), edge_width + t + s / 2 - r, -90, 2 * pinl + s + 0.5 * t, -90, t + s, -90, - pinl - r, (90, r), edge_width - s / 2 - 2 * r, (90, r), pinl + t - s - r] - - holex = 0.6 * t - holey = -0.5 * t + self.burn - s / 2 - if self.rightside: - p = list(reversed(p)) - holex = length - holex - holey = edge_width + 0.5 * t + self.burn - - if spring: - self.rectangularHole(holex, holey, 0.4 * t, t + 2 * s) - self.polyline(*p) - - def startwidth(self) -> float: - return self.boxes.thickness + self.settings.edge_width if self.rightside else -self.settings.play / 2 - - def endwidth(self) -> float: - return self.boxes.thickness + self.settings.edge_width if not self.rightside else -self.settings.play / 2 - - def margin(self) -> float: - return self.boxes.thickness + self.settings.edge_width + self.settings.play / 2 if not self.rightside else 0.0 - - -class LidSideLeft(LidSideRight): - char = "M" - description = "Edge for slide on lid (box left)" - rightside = False - - -############################################################################# -#### Click Joints -############################################################################# - -class ClickSettings(Settings): - """Settings for Click-on Lids -Values: - -* absolute_params - - * angle : 5.0 : angle of the hooks bending outward - -* relative (in multiples of thickness) - - * depth : 3.0 : length of the hooks (multiples of thickness) - * bottom_radius : 0.1 : radius at the bottom (multiples of thickness) -""" - - absolute_params = { - "angle": 5.0, - } - - relative_params = { - "depth": 3.0, - "bottom_radius": 0.1, - } - - def edgeObjects(self, boxes, chars: str = "cC", add: bool = True): - edges = [ClickConnector(boxes, self), - ClickEdge(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -class ClickConnector(BaseEdge): - char = "c" - description = "Click on (bottom side)" - - def hook(self, reverse: bool = False) -> None: - t = self.settings.thickness - a = self.settings.angle - d = self.settings.depth - r = self.settings.bottom_radius - c = math.cos(math.radians(a)) - s = math.sin(math.radians(a)) - - p1 = (0, 90 - a, c * d) - p2 = ( - d + t, - -90, - t * 0.5, - 135, - t * 2 ** 0.5, - 135, - d + 2 * t + s * 0.5 * t) - p3 = (c * d - s * c * 0.2 * t, -a, 0) - - if not reverse: - self.polyline(*p1) - self.corner(-180, r) - self.polyline(*p2) - self.corner(-180 + 2 * a, r) - self.polyline(*p3) - else: - self.polyline(*reversed(p3)) - self.corner(-180 + 2 * a, r) - self.polyline(*reversed(p2)) - self.corner(-180, r) - self.polyline(*reversed(p1)) - - def hookWidth(self): - t = self.settings.thickness - a = self.settings.angle - d = self.settings.depth - r = self.settings.bottom_radius - c = math.cos(math.radians(a)) - s = math.sin(math.radians(a)) - - return 2 * s * d * c + 0.5 * c * t + c * 4 * r - - def hookOffset(self): - a = self.settings.angle - d = self.settings.depth - r = self.settings.bottom_radius - c = math.cos(math.radians(a)) - s = math.sin(math.radians(a)) - - return s * d * c + 2 * r - - def finger(self, length) -> None: - t = self.settings.thickness - self.polyline( - 2 * t, - 90, - length, - 90, - 2 * t, - ) - - def __call__(self, length, **kw): - t = self.settings.thickness - self.edge(4 * t) - self.hook() - self.finger(2 * t) - self.hook(reverse=True) - - self.edge(length - 2 * (6 * t + 2 * self.hookWidth()), tabs=2) - - self.hook() - self.finger(2 * t) - self.hook(reverse=True) - self.edge(4 * t) - - def margin(self) -> float: - return 2 * self.settings.thickness - - -class ClickEdge(ClickConnector): - char = "C" - description = "Click on (top)" - - def startwidth(self) -> float: - return self.boxes.thickness - - def margin(self) -> float: - return 0.0 - - def __call__(self, length, **kw): - t = self.settings.thickness - o = self.hookOffset() - w = self.hookWidth() - p1 = ( - 4 * t + o, - 90, - t, - -90, - 2 * (t + w - o), - -90, - t, - 90, - 0) - self.polyline(*p1) - self.edge(length - 2 * (6 * t + 2 * w) + 2 * o, tabs=2) - self.polyline(*reversed(p1)) - - -############################################################################# -#### Dove Tail Joints -############################################################################# - -class DoveTailSettings(Settings): - """Settings for Dove Tail Joints - -Values: - -* absolute - - * angle : 50 : how much should fingers widen (-80 to 80) - -* relative (in multiples of thickness) - - * size : 3 : from one middle of a dove tail to another (multiples of thickness) - * depth : 1.5 : how far the dove tails stick out of/into the edge (multiples of thickness) - * radius : 0.2 : radius used on all four corners (multiples of thickness) - -""" - absolute_params = { - "angle": 50, - } - - relative_params = { - "size": 3, - "depth": 1.5, - "radius": 0.2, - } - - def edgeObjects(self, boxes, chars: str = "dD", add: bool = True): - edges = [DoveTailJoint(boxes, self), - DoveTailJointCounterPart(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -class DoveTailJoint(BaseEdge): - """Edge with dove tail joints """ - - char = 'd' - description = "Dove Tail Joint" - positive = True - - def __call__(self, length, **kw): - s = self.settings - radius = max(s.radius, self.boxes.burn) # no smaller than burn - positive = self.positive - a = s.angle + 90 - alpha = 0.5 * math.pi - math.pi * s.angle / 180.0 - - l1 = radius / math.tan(alpha / 2.0) - diffx = 0.5 * s.depth / math.tan(alpha) - l2 = 0.5 * s.depth / math.sin(alpha) - - sections = int((length) // (s.size * 2)) - leftover = length - sections * s.size * 2 - - if sections == 0: - self.edge(length) - return - - p = 1 if positive else -1 - - self.edge((s.size + leftover) / 2.0 + diffx - l1, tabs=1) - - for i in range(sections): - self.corner(-1 * p * a, radius) - self.edge(2 * (l2 - l1)) - self.corner(p * a, radius) - self.edge(2 * (diffx - l1) + s.size) - self.corner(p * a, radius) - self.edge(2 * (l2 - l1)) - self.corner(-1 * p * a, radius) - - if i < sections - 1: # all but the last - self.edge(2 * (diffx - l1) + s.size) - - self.edge((s.size + leftover) / 2.0 + diffx - l1, tabs=1) - - def margin(self) -> float: - """ """ - return self.settings.depth - - -class DoveTailJointCounterPart(DoveTailJoint): - """Edge for other side of dove joints """ - char = 'D' - description = "Dove Tail Joint (opposing side)" - - positive = False - - def margin(self) -> float: - return 0.0 - - -class FlexSettings(Settings): - """Settings for Flex - -Values: - -* absolute - - * stretch : 1.05 : Hint of how much the flex part should be shortened - -* relative (in multiples of thickness) - - * distance : 0.5 : width of the pattern perpendicular to the cuts (multiples of thickness) - * connection : 1.0 : width of the gaps in the cuts (multiples of thickness) - * width : 5.0 : width of the pattern in direction of the cuts (multiples of thickness) - -""" - relative_params = { - "distance": 0.5, - "connection": 1.0, - "width": 5.0, - } - - absolute_params = { - "stretch": 1.05, - } - - def checkValues(self) -> None: - if self.distance < 0.01: - raise ValueError("Flex Settings: distance parameter must be > 0.01mm") - if self.width < 0.1: - raise ValueError("Flex Settings: width parameter must be > 0.1mm") - - -class FlexEdge(BaseEdge): - """Edge with flex cuts - use straight edge for the opposing side""" - char = 'X' - description = "Flex cut" - - def __call__(self, x, h, **kw): - dist = self.settings.distance - connection = self.settings.connection - width = self.settings.width - - burn = self.boxes.burn - h += 2 * burn - lines = int(x // dist) - leftover = x - lines * dist - sections = max(int((h - connection) // width), 1) - sheight = ((h - connection) / sections) - connection - - self.ctx.stroke() - for i in range(1, lines): - pos = i * dist + leftover / 2 - - if i % 2: - self.ctx.move_to(pos, 0) - self.ctx.line_to(pos, connection + sheight) - - for j in range((sections - 1) // 2): - self.ctx.move_to(pos, (2 * j + 1) * sheight + (2 * j + 2) * connection) - self.ctx.line_to(pos, (2 * j + 3) * (sheight + connection)) - - if not sections % 2: - self.ctx.move_to(pos, h - sheight - connection) - self.ctx.line_to(pos, h) - else: - if sections % 2: - self.ctx.move_to(pos, h) - self.ctx.line_to(pos, h - connection - sheight) - - for j in range((sections - 1) // 2): - self.ctx.move_to( - pos, h - ((2 * j + 1) * sheight + (2 * j + 2) * connection)) - self.ctx.line_to( - pos, h - (2 * j + 3) * (sheight + connection)) - - else: - for j in range(sections // 2): - self.ctx.move_to(pos, - h - connection - 2 * j * (sheight + connection)) - self.ctx.line_to(pos, h - 2 * (j + 1) * (sheight + connection)) - - self.ctx.stroke() - self.ctx.move_to(0, 0) - self.ctx.line_to(x, 0) - self.ctx.translate(*self.ctx.get_current_point()) - - -class GearSettings(Settings): - """Settings for rack (and pinion) edge -Values: -* absolute_params - - * dimension : 3.0 : modulus of the gear (in mm) - * angle : 20.0 : pressure angle - * profile_shift : 20.0 : Profile shift - * clearance : 0.0 : clearance -""" - - absolute_params = { - "dimension": 3.0, - "angle": 20.0, - "profile_shift": 20.0, - "clearance": 0.0, - } - - relative_params: dict[str, Any] = {} - - -class RackEdge(BaseEdge): - char = "R" - - description = "Rack (and pinion) Edge" - - def __init__(self, boxes, settings) -> None: - super().__init__(boxes, settings) - self.gear = gears.Gears(boxes) - - def __call__(self, length, **kw): - params = self.settings.values.copy() - params["draw_rack"] = True - params["rack_base_height"] = -1E-36 - params["rack_teeth_length"] = int(length // (params["dimension"] * math.pi)) - params["rack_base_tab"] = (length - (params["rack_teeth_length"]) * params["dimension"] * math.pi) / 2.0 - s_tmp = self.boxes.spacing - self.boxes.spacing = 0 - self.moveTo(length, 0, 180) - self.gear(move="", **params) - self.moveTo(0, 0, 180) - self.boxes.spacing = s_tmp - - def margin(self) -> float: - return self.settings.dimension * 1.1 - - -class RoundedTriangleEdgeSettings(Settings): - """Settings for RoundedTriangleEdge -Values: - -* absolute_params - - * height : 150. : height above the wall - * radius : 30. : radius of top corner - * r_hole : 0. : radius of hole - -* relative (in multiples of thickness) - - * outset : 0 : extend the triangle along the length of the edge (multiples of thickness) - -""" - - absolute_params = { - "height": 50., - "radius": 30., - "r_hole": 2., - } - - relative_params = { - "outset": 0., - } - - def edgeObjects(self, boxes, chars: str = "t", add: bool = True): - edges = [RoundedTriangleEdge(boxes, self), - RoundedTriangleFingerHolesEdge(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -class RoundedTriangleEdge(Edge): - """Makes an 'edge' with a rounded triangular bumpout and - optional hole""" - description = "Triangle for handle" - char = "t" - - def __call__(self, length, **kw): - length += 2 * self.settings.outset - r = self.settings.radius - if r > length / 2: - r = length / 2 - if length - 2 * r < self.settings.height: # avoid division by zero - angle = 90 - math.degrees(math.atan( - (length - 2 * r) / (2 * self.settings.height))) - l = self.settings.height / math.cos(math.radians(90 - angle)) - else: - angle = math.degrees(math.atan( - 2 * self.settings.height / (length - 2 * r))) - l = 0.5 * (length - 2 * r) / math.cos(math.radians(angle)) - if self.settings.outset: - self.polyline(0, -180, self.settings.outset, 90) - else: - self.corner(-90) - if self.settings.r_hole: - self.hole(self.settings.height, length / 2., self.settings.r_hole) - self.corner(90 - angle, r, tabs=1) - self.edge(l, tabs=1) - self.corner(2 * angle, r, tabs=1) - self.edge(l, tabs=1) - self.corner(90 - angle, r, tabs=1) - if self.settings.outset: - self.polyline(0, 90, self.settings.outset, -180) - else: - self.corner(-90) - - def margin(self) -> float: - return self.settings.height + self.settings.radius - - -class RoundedTriangleFingerHolesEdge(RoundedTriangleEdge): - char = "T" - - def startwidth(self) -> float: - return self.settings.thickness - - def __call__(self, length, **kw): - self.fingerHolesAt(0, 0.5 * self.settings.thickness, length, 0) - super().__call__(length, **kw) - - -class HandleEdgeSettings(Settings): - """Settings for HandleEdge -Values: - -* absolute_params - - * height : 20. : height above the wall in mm - * radius : 10. : radius of corners in mm - * hole_width : "40:40" : width of hole(s) in percentage of maximum hole width (width of edge - (n+1) * material thickness) - * hole_height : 75. : height of hole(s) in percentage of maximum hole height (handle height - 2 * material thickness) - * on_sides : True, : added to side panels if checked, to front and back otherwise (only used with top_edge parameter) - -* relative - - * outset : 1. : extend the handle along the length of the edge (multiples of thickness) - -""" - - absolute_params = { - "height": 20., - "radius": 10., - "hole_width": "40:40", - "hole_height": 75., - "on_sides": True, - } - - relative_params = { - "outset": 1., - } - - def edgeObjects(self, boxes, chars: str = "yY", add: bool = True): - edges = [HandleEdge(boxes, self), - HandleHoleEdge(boxes, self)] - return self._edgeObjects(edges, boxes, chars, add) - - -# inspiration came from https://www.thingiverse.com/thing:327393 - -class HandleEdge(Edge): - """Extends an 'edge' by adding a rounded bumpout with optional holes""" - description = "Handle for e.g. a drawer" - char = "y" - extra_height = 0.0 - - def __call__(self, length, **kw): - length += 2 * self.settings.outset - extra_height = self.extra_height * self.settings.thickness - - r = self.settings.radius - if r > length / 2: - r = length / 2 - if r > self.settings.height: - r = self.settings.height - - widths = argparseSections(self.settings.hole_width) - - if self.settings.outset: - self.polyline(0, -180, self.settings.outset, 90) - else: - self.corner(-90) - - if self.settings.hole_height and sum(widths) > 0: - if sum(widths) < 100: - slot_offset = ((1 - sum(widths) / 100) * (length - (len(widths) + 1) * self.thickness)) / (len(widths) * 2) - else: - slot_offset = 0 - - slot_height = (self.settings.height - 2 * self.thickness) * self.settings.hole_height / 100 - slot_x = self.thickness + slot_offset - - for w in widths: - if sum(widths) > 100: - slotwidth = w / sum(widths) * (length - (len(widths) + 1) * self.thickness) - else: - slotwidth = w / 100 * (length - (len(widths) + 1) * self.thickness) - slot_x += slotwidth / 2 - with self.saved_context(): - self.moveTo((self.settings.height / 2) + extra_height, slot_x, 0) - self.rectangularHole(0, 0, slot_height, slotwidth, slot_height / 2, True, True) - slot_x += slotwidth / 2 + slot_offset + self.thickness + slot_offset - - self.edge(self.settings.height - r + extra_height, tabs=1) - self.corner(90, r, tabs=1) - self.edge(length - 2 * r, tabs=1) - self.corner(90, r, tabs=1) - self.edge(self.settings.height - r + extra_height, tabs=1) - - if self.settings.outset: - self.polyline(0, 90, self.settings.outset, -180) - else: - self.corner(-90) - - def margin(self) -> float: - return self.settings.height - - -class HandleHoleEdge(HandleEdge): - """Extends an 'edge' by adding a rounded bumpout with optional holes and holes for parallel finger joint""" - description = "Handle with holes for parallel finger joint" - char = "Y" - extra_height = 1.0 - - def __call__(self, length, **kw): - self.fingerHolesAt(0, -0.5 * self.settings.thickness, length, 0) - super().__call__(length, **kw) - - def margin(self) -> float: - return self.settings.height + self.extra_height * self.settings.thickness diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/extents.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/extents.py deleted file mode 100644 index b2ab4a6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/extents.py +++ /dev/null @@ -1,43 +0,0 @@ -class Extents: - __slots__ = "xmin ymin xmax ymax".split() - - def __init__(self, xmin: float = float('inf'), ymin: float = float('inf'), xmax: float = float('-inf'), ymax: float = float('-inf')) -> None: - self.xmin = xmin - self.ymin = ymin - self.xmax = xmax - self.ymax = ymax - - def add(self, x: float, y: float) -> None: - self.xmin = min(self.xmin, x) - self.xmax = max(self.xmax, x) - self.ymin = min(self.ymin, y) - self.ymax = max(self.ymax, y) - - def extend(self, l) -> None: - for x, y in l: - self.add(x, y) - - def __add__(self, extent): - # todo: why can this happen? - if extent == 0: - return Extents(self.xmin, self.ymin, self.xmax, self.ymax) - return Extents( - min(self.xmin, extent.xmin), min(self.ymin, extent.ymin), - max(self.xmax, extent.xmax), max(self.ymax, extent.ymax) - ) - - def __radd__(self, extent): - if extent == 0: - return Extents(self.xmin, self.ymin, self.xmax, self.ymax) - return self.__add__(extent) - - @property - def width(self) -> float: - return self.xmax - self.xmin - - @property - def height(self) -> float: - return self.ymax - self.ymin - - def __repr__(self) -> str: - return f'Extents ({self.xmin},{self.ymin})-({self.xmax},{self.ymax})' diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/formats.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/formats.py deleted file mode 100644 index b49f196..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/formats.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import os -import shutil -import subprocess -import tempfile - -from boxes.drawing import Context, LBRN2Surface, PSSurface, SVGSurface - - -class Formats: - - pstoedit_candidates = ["/usr/bin/pstoedit", "pstoedit", "pstoedit.exe"] - ps2pdf_candidates = ["/usr/bin/ps2pdf", "ps2pdf", "ps2pdf.exe"] - - _BASE_FORMATS = ['svg', 'svg_Ponoko', 'ps', 'lbrn2'] - - formats = { - "svg": None, - "svg_Ponoko": None, - "ps": None, - "lbrn2": None, - "dxf": "{pstoedit} -flat 0.1 -f dxf:-mm {input} {output}", - "gcode": "{pstoedit} -f gcode {input} {output}", - "plt": "{pstoedit} -f hpgl {input} {output}", - # "ai": "{pstoedit} -f ps2ai", - "pdf": "{ps2pdf} -dEPSCrop {input} {output}", - } - - http_headers = { - "svg": [('Content-type', 'image/svg+xml; charset=utf-8')], - "svg_Ponoko": [('Content-type', 'image/svg+xml; charset=utf-8')], - "ps": [('Content-type', 'application/postscript')], - "lbrn2": [('Content-type', 'application/lbrn2')], - "dxf": [('Content-type', 'image/vnd.dxf')], - "plt": [('Content-type', ' application/vnd.hp-hpgl')], - "gcode": [('Content-type', 'text/plain; charset=utf-8')], - - # "" : [('Content-type', '')], - } - - def __init__(self) -> None: - for cmd in self.pstoedit_candidates: - self.pstoedit = shutil.which(cmd) - if self.pstoedit: - break - for cmd in self.ps2pdf_candidates: - self.ps2pdf = shutil.which(cmd) - if self.ps2pdf: - break - - def getFormats(self): - if self.pstoedit: - return sorted(self.formats.keys()) - return self._BASE_FORMATS - - def getSurface(self, fmt): - if fmt in ("svg", "svg_Ponoko"): - surface = SVGSurface() - elif fmt == "lbrn2": - surface = LBRN2Surface() - else: - surface = PSSurface() - - ctx = Context(surface) - return surface, ctx - - def convert(self, data, fmt): - - if fmt not in self._BASE_FORMATS: - fd, tmpfile = tempfile.mkstemp() - os.write(fd, data.getvalue()) - os.close(fd) - fd2, outfile = tempfile.mkstemp() - - cmd = self.formats[fmt].format( - pstoedit=self.pstoedit, - ps2pdf=self.ps2pdf, - input=tmpfile, - output=outfile).split() - - result = subprocess.run(cmd) - os.unlink(tmpfile) - if result.returncode: - # XXX show stderr output - raise ValueError("Conversion failed. pstoedit returned %i\n\n %s" % (result.returncode, result.stderr)) - data = open(outfile, 'rb') - os.unlink(outfile) - os.close(fd2) - - return data diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/gears.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/gears.py deleted file mode 100644 index 55c5f20..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/gears.py +++ /dev/null @@ -1,709 +0,0 @@ -# Copyright (C) 2007 Aaron Spike (aaron @ ekips.org) -# Copyright (C) 2007 Tavmjong Bah (tavmjong @ free.fr) -# Copyright (C) https://cnc-club.ru/forum/viewtopic.php?f=33&t=434&p=2594#p2500 -# Copyright (C) 2014 Jürgen Weigert (juewei@fabmail.org) -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# 2014-03-20 jw@suse.de 0.2 Option --accuracy=0 for automatic added. -# 2014-03-21 sent upstream: https://bugs.launchpad.net/inkscape/+bug/1295641 -# 2014-03-21 jw@suse.de 0.3 Fixed center of rotation for gears with odd number of teeth. -# 2014-04-04 juewei 0.7 Revamped calc_unit_factor(). -# 2014-04-05 juewei 0.7a Correctly positioned rack gear. -# The geometry above the meshing line is wrong. -# 2014-04-06 juewei 0.7b Undercut detection added. Reference: -# https://web.archive.org/web/20140801105942/https://nptel.ac.in/courses/IIT-MADRAS/Machine_Design_II/pdf/2_2.pdf -# Manually merged https://github.com/jnweiger/inkscape-gears-dev/pull/15 -# 2014-04-07 juewei 0.7c Manually merged https://github.com/jnweiger/inkscape-gears-dev/pull/17 -# 2014-04-09 juewei 0.8 Fixed https://github.com/jnweiger/inkscape-gears-dev/issues/19 -# Ring gears are ready for production now. Thanks neon22 for driving this. -# Profile shift implemented (Advanced Tab), fixing -# https://github.com/jnweiger/inkscape-gears-dev/issues/9 -# 2015-05-29 juewei 0.9 ported to inkscape 0.91 -# AttributeError: 'module' object inkex has no attribute 'uutounit -# Fixed https://github.com/jnweiger/inkscape-gears-dev - -from math import acos, asin, ceil, cos, degrees, pi, radians, sin, sqrt, tan -from os import devnull # for debugging - -two_pi = 2 * pi -import argparse - -from boxes.vectors import vdiff, vlength - -__version__ = '0.9' - -def linspace(a,b,n): - """ return list of linear interp of a to b in n steps - - if a and b are ints - you'll get an int result. - - n must be an integer - """ - return [a+x*(b-a)/(n-1) for x in range(0,n)] - -def involute_intersect_angle(Rb, R): - Rb, R = float(Rb), float(R) - return (sqrt(R**2 - Rb**2) / (Rb)) - (acos(Rb / R)) - -def point_on_circle(radius, angle): - """ return xy coord of the point at distance radius from origin at angle """ - x = radius * cos(angle) - y = radius * sin(angle) - return (x, y) - -### Undercut support functions -def undercut_min_teeth(pitch_angle, k=1.0): - """ - computes the minimum tooth count for a - spur gear so that no undercut with the given pitch_angle (in deg) - and an addendum = k * metric_module, where 0 < k < 1 - - Note: - The return value should be rounded upwards for perfect safety. E.g. - min_teeth = int(math.ceil(undercut_min_teeth(20.0))) # 18, not 17 - """ - x = max(sin(radians(pitch_angle)), 0.01) - return 2*k /(x*x) - -def undercut_max_k(teeth, pitch_angle=20.0): - """ computes the maximum k value for a given teeth count and pitch_angle - so that no undercut occurs. - """ - x = max(sin(radians(pitch_angle)), 0.01) - return 0.5 * teeth * x * x - -def undercut_min_angle(teeth, k=1.0): - """ computes the minimum pitch angle, to that the given teeth count (and - profile shift) cause no undercut. - """ - return degrees(asin(min(0.856, sqrt(2.0*k/teeth)))) # max 59.9 deg - - -def have_undercut(teeth, pitch_angle=20.0, k=1.0): - """ returns true if the specified number of teeth would - cause an undercut. - """ - return (teeth < undercut_min_teeth(pitch_angle, k)) - - -## gather all basic gear calculations in one place -def gear_calculations(num_teeth, circular_pitch, pressure_angle, clearance=0, ring_gear=False, profile_shift=0.): - """ Put base calcs for spur/ring gears in one place. - - negative profile shifting helps against undercut. - """ - diametral_pitch = pi / circular_pitch - pitch_diameter = num_teeth / diametral_pitch - pitch_radius = pitch_diameter / 2.0 - addendum = 1 / diametral_pitch - dedendum = addendum - dedendum *= 1+profile_shift - addendum *= 1-profile_shift - - if ring_gear: - addendum = addendum + clearance # our method - else: - dedendum = dedendum + clearance # our method - - base_radius = pitch_diameter * cos(radians(pressure_angle)) / 2.0 - outer_radius = pitch_radius + addendum - root_radius = pitch_radius - dedendum - - # Tooth thickness: Tooth width along pitch circle. - tooth_thickness = ( pi * pitch_diameter ) / ( 2.0 * num_teeth ) - - return (pitch_radius, base_radius, - addendum, dedendum, outer_radius, root_radius, - tooth_thickness - ) - - -def generate_rack_points(tooth_count, pitch, addendum, pressure_angle, - base_height, tab_length, clearance=0, draw_guides=False): - """ Return path (suitable for svg) of the Rack gear. - - rack gear uses straight sides - - - involute on a circle of infinite radius is a simple linear ramp - - - the meshing circle touches at y = 0, - - the highest elevation of the teeth is at y = +addendum - - the lowest elevation of the teeth is at y = -addendum-clearance - - the base_height extends downwards from the lowest elevation. - - we generate this middle tooth exactly centered on the y=0 line. - (one extra tooth on the right hand side, if number of teeth is even) - """ - spacing = 0.5 * pitch # rolling one pitch distance on the spur gear pitch_diameter. - - # roughly center rack in drawing, exact position is so that it meshes - # nicely with the spur gear. - # -0.5*spacing has a gap in the center. - # +0.5*spacing has a tooth in the center. - - if tab_length <= 0.0: - tab_length = 1E-8 - - tas = tan(radians(pressure_angle)) * addendum - tasc = tan(radians(pressure_angle)) * (addendum+clearance) - base_top = addendum+clearance - base_bot = addendum+clearance+base_height - - x_lhs = -pitch * 0.5*tooth_count - tab_length - # Start with base tab on LHS - points = [] # make list of points - points.append((x_lhs, base_bot)) - points.append((x_lhs, base_top)) - x = x_lhs + tab_length+tasc - - # An involute on a circle of infinite radius is a simple linear ramp. - # We need to add curve at bottom and use clearance. - for i in range(tooth_count): - # move along path, generating the next 'tooth' - # pitch line is at y=0. the left edge hits the pitch line at x - points.append((x-tasc, base_top)) - points.append((x+tas, -addendum)) - points.append((x+spacing-tas, -addendum)) - points.append((x+spacing+tasc, base_top)) - x += pitch - - # add base on RHS - x_rhs = x - tasc + tab_length - points.append((x_rhs, base_top)) - points.append((x_rhs, base_bot)) - # We don't close the path here. Caller does it. - # points.append((x_lhs, base_bot)) - - # Draw line representing the pitch circle of infinite diameter - guide_path = None - p = [] - if draw_guides: - p.append( (x_lhs + 0.5 * tab_length, 0) ) - p.append( (x_rhs - 0.5 * tab_length, 0) ) - - return (points, p) - - -def generate_spur_points(teeth, base_radius, pitch_radius, outer_radius, root_radius, accuracy_involute, accuracy_circular): - """ given a set of core gear params - - generate the svg path for the gear - """ - half_thick_angle = two_pi / (4.0 * teeth ) #?? = pi / (2.0 * teeth) - pitch_to_base_angle = involute_intersect_angle( base_radius, pitch_radius ) - pitch_to_outer_angle = involute_intersect_angle( base_radius, outer_radius ) - pitch_to_base_angle - - start_involute_radius = max(base_radius, root_radius) - radii = linspace(start_involute_radius, outer_radius, accuracy_involute) - angles = [involute_intersect_angle(base_radius, r) for r in radii] - - centers = [(x * two_pi / float( teeth) ) for x in range( teeth ) ] - points = [] - - for c in centers: - # Angles - pitch1 = c - half_thick_angle - base1 = pitch1 - pitch_to_base_angle - offsetangles1 = [ base1 + x for x in angles] - points1 = [ point_on_circle( radii[i], offsetangles1[i]) for i in range(0,len(radii)) ] - - pitch2 = c + half_thick_angle - base2 = pitch2 + pitch_to_base_angle - offsetangles2 = [ base2 - x for x in angles] - points2 = [ point_on_circle( radii[i], offsetangles2[i]) for i in range(0,len(radii)) ] - - points_on_outer_radius = [ point_on_circle(outer_radius, x) for x in linspace(offsetangles1[-1], offsetangles2[-1], accuracy_circular) ] - - if root_radius > base_radius: - pitch_to_root_angle = pitch_to_base_angle - involute_intersect_angle(base_radius, root_radius ) - root1 = pitch1 - pitch_to_root_angle - root2 = pitch2 + pitch_to_root_angle - points_on_root = [point_on_circle (root_radius, x) for x in linspace(root2, root1+(two_pi/float(teeth)), accuracy_circular) ] - p_tmp = points1 + points_on_outer_radius[1:-1] + points2[::-1] + points_on_root[1:-1] # [::-1] reverses list; [1:-1] removes first and last element - else: - points_on_root = [point_on_circle (root_radius, x) for x in linspace(base2, base1+(two_pi/float(teeth)), accuracy_circular) ] - p_tmp = points1 + points_on_outer_radius[1:-1] + points2[::-1] + points_on_root # [::-1] reverses list - - points.extend( p_tmp ) - - return (points) - -def inkbool(val): - return val not in ("False", False, "0", 0, "None", None) - -class OptionParser(argparse.ArgumentParser): - - types = { - "int" : int, - "float" : float, - "string" : str, - "inkbool" : inkbool, - } - - def add_option(self, short, long_, **kw): - kw["type"] = self.types[kw["type"]] - names = [] - if short: - names.append("-" + short.replace("-", "_")[1:]) - if long_: - names.append("--" + long_.replace("-", "_")[2:]) - self.add_argument(*names, **kw) - -class Gears(): - - def __init__(self, boxes, **kw) -> None: - # an alternate way to get debug info: - # could use inkex.debug(string) instead... - #try: - # self.tty = open("/dev/tty", 'w') - #except: - # self.tty = open(devnull, 'w') # '/dev/null' for POSIX, 'nul' for Windows. - # # print >>self.tty, "gears-dev " + __version__ - - self.boxes = boxes - self.OptionParser = OptionParser() - self.OptionParser.add_option("-t", "--teeth", - action="store", type="int", - dest="teeth", default=24, - help="Number of teeth") - - self.OptionParser.add_option("-s", "--system", - action="store", type="string", - dest="system", default='MM', - help="Select system: 'CP' (Cyclic Pitch (default)), 'DP' (Diametral Pitch), 'MM' (Metric Module)") - - self.OptionParser.add_option("-d", "--dimension", - action="store", type="float", - dest="dimension", default=1.0, - help="Tooth size, depending on system (which defaults to CP)") - - - self.OptionParser.add_option("-a", "--angle", - action="store", type="float", - dest="angle", default=20.0, - help="Pressure Angle (common values: 14.5, 20, 25 degrees)") - - self.OptionParser.add_option("-p", "--profile-shift", - action="store", type="float", - dest="profile_shift", default=20.0, - help="Profile shift [in percent of the module]. Negative values help against undercut") - - self.OptionParser.add_option("-u", "--units", - action="store", type="string", - dest="units", default='mm', - help="Units this dialog is using") - - self.OptionParser.add_option("-A", "--accuracy", - action="store", type="int", - dest="accuracy", default=0, - help="Accuracy of involute: automatic: 5..20 (default), best: 20(default), medium 10, low: 5; good accuracy is important with a low tooth count") - # Clearance: Radial distance between top of tooth on one gear to bottom of gap on another. - self.OptionParser.add_option("", "--clearance", - action="store", type="float", - dest="clearance", default=0.0, - help="Clearance between bottom of gap of this gear and top of tooth of another") - - self.OptionParser.add_option("", "--annotation", - action="store", type="inkbool", - dest="annotation", default=False, - help="Draw annotation text") - - self.OptionParser.add_option("-i", "--internal-ring", - action="store", type="inkbool", - dest="internal_ring", default=False, - help="Ring (or Internal) gear style (default: normal spur gear)") - - self.OptionParser.add_option("", "--mount-hole", - action="store", type="float", - dest="mount_hole", default=0., - help="Mount hole diameter") - - self.OptionParser.add_option("", "--mount-diameter", - action="store", type="float", - dest="mount_diameter", default=15, - help="Mount support diameter") - - self.OptionParser.add_option("", "--spoke-count", - action="store", type="int", - dest="spoke_count", default=3, - help="Spokes count") - - self.OptionParser.add_option("", "--spoke-width", - action="store", type="float", - dest="spoke_width", default=5, - help="Spoke width") - - self.OptionParser.add_option("", "--holes-rounding", - action="store", type="float", - dest="holes_rounding", default=5, - help="Holes rounding") - - self.OptionParser.add_option("", "--active-tab", - action="store", type="string", - dest="active_tab", default='', - help="Active tab. Not used now.") - - self.OptionParser.add_option("-x", "--centercross", - action="store", type="inkbool", - dest="centercross", default=False, - help="Draw cross in center") - - self.OptionParser.add_option("-c", "--pitchcircle", - action="store", type="inkbool", - dest="pitchcircle", default=False, - help="Draw pitch circle (for mating)") - - self.OptionParser.add_option("-r", "--draw-rack", - action="store", type="inkbool", - dest="drawrack", default=False, - help="Draw rack gear instead of spur gear") - - self.OptionParser.add_option("", "--rack-teeth-length", - action="store", type="int", - dest="teeth_length", default=12, - help="Length (in teeth) of rack") - - self.OptionParser.add_option("", "--rack-base-height", - action="store", type="float", - dest="base_height", default=8, - help="Height of base of rack") - - self.OptionParser.add_option("", "--rack-base-tab", - action="store", type="float", - dest="base_tab", default=14, - help="Length of tabs on ends of rack") - - self.OptionParser.add_option("", "--undercut-alert", - action="store", type="inkbool", - dest="undercut_alert", default=False, - help="Let the user confirm a warning dialog if undercut occurs. This dialog also shows helpful hints against undercut") - - def calc_circular_pitch(self): - """We use math based on circular pitch.""" - dimension = self.options.dimension - if self.options.system == 'CP': # circular pitch - circular_pitch = dimension * 25.4 - elif self.options.system == 'DP': # diametral pitch - circular_pitch = pi * 25.4 / dimension - elif self.options.system == 'MM': # module (metric) - circular_pitch = pi * dimension - else: - raise ValueError("unknown system '%s', try CP, DP, MM" % self.options.system) - - # circular_pitch defines the size in mm - return circular_pitch - - def generate_spokes(self, root_radius, spoke_width, spokes, mount_radius, mount_hole, - unit_factor, unit_label): - """ given a set of constraints - - generate the svg path for the gear spokes - - lies between mount_radius (inner hole) and root_radius (bottom of the teeth) - - spoke width also defines the spacing at the root_radius - - mount_radius is adjusted so that spokes fit if there is room - - if no room (collision) then spokes not drawn - """ - - if not spokes: - return [] - - # Spokes - collision = False # assume we draw spokes - messages = [] # messages to send back about changes. - spoke_holes = [] - r_outer = root_radius - spoke_width - - try: - spoke_count = spokes - spokes = [i*2*pi/spokes for i in range(spoke_count)] - except TypeError: - spoke_count = len(spokes) - spokes = [radians(a) for a in spokes] - spokes.append(spokes[0]+two_pi) - - # checks for collision with spokes - # check for mount hole collision with inner spokes - if mount_radius <= mount_hole/2: - adj_factor = (r_outer - mount_hole/2) / 5 - - if adj_factor < 0.1: - # not enough reasonable room - collision = True - else: - mount_radius = mount_hole/2 + adj_factor # small fix - messages.append(f"Mount support too small. Auto increased to {mount_radius/unit_factor*2:2.2f}{unit_label}.") - - # then check to see if cross-over on spoke width - for i in range(spoke_count): - angle = spokes[i]-spokes[i-1] - - if spoke_width >= angle * mount_radius: - adj_factor = 1.2 # wrong value. its probably one of the points distances calculated below - mount_radius += adj_factor - messages.append(f"Too many spokes. Increased Mount support by {adj_factor/unit_factor:2.3f}{unit_label}") - - # check for collision with outer rim - if r_outer <= mount_radius: - # not enough room to draw spokes so cancel - collision = True - if collision: # don't draw spokes if no room. - messages.append("Not enough room for Spokes. Decrease Spoke width.") - else: # draw spokes - - for i in range(spoke_count): - self.boxes.ctx.save() - start_a, end_a = spokes[i], spokes[i+1] - # inner circle around mount - asin_factor = spoke_width/mount_radius/2 - # check if need to clamp radius - asin_factor = max(-1.0, min(1.0, asin_factor)) # no longer needed - resized above - a = asin(asin_factor) - - # is inner circle too small - asin_factor = spoke_width/r_outer/2 - # check if need to clamp radius - asin_factor = max(-1.0, min(1.0, asin_factor)) # no longer needed - resized above - a2 = asin(asin_factor) - l = vlength(vdiff(point_on_circle(mount_radius, start_a + a), - point_on_circle(r_outer, start_a + a2))) - self.boxes.moveTo(*point_on_circle(mount_radius, start_a + a), degrees=degrees(start_a)) - self.boxes.polyline( - l, - +90+degrees(a2), 0, - (degrees(end_a-start_a-2*a2), r_outer), 0, - +90+degrees(a2), - l, 90-degrees(a), 0, - (-degrees(end_a-start_a-2*a), mount_radius), - 0, 90+degrees(a2), 0 - ) - - self.boxes.ctx.restore() - - return messages - - def sizes(self, **kw): - self.options = self.OptionParser.parse_args([f"--{name}={value}" for name, value in kw.items()]) - # Pitch (circular pitch): Length of the arc from one tooth to the next) - # Pitch diameter: Diameter of pitch circle. - pitch = self.calc_circular_pitch() - - if self.options.drawrack: - base_height = self.options.base_height * unit_factor - tab_width = self.options.base_tab * unit_factor - tooth_count = self.options.teeth_length - width = tooth_count * pitch + 2*tab_width - height = base_height+ 2* addendum - return 0, width, height - - teeth = self.options.teeth - # Angle of tangent to tooth at circular pitch wrt radial line. - angle = self.options.angle - # Clearance: Radial distance between top of tooth on one gear to - # bottom of gap on another. - clearance = self.options.clearance # * unit_factor - # Replace section below with this call to get the combined gear_calculations() above - (pitch_radius, base_radius, addendum, dedendum, - outer_radius, root_radius, tooth) = gear_calculations(teeth, pitch, angle, clearance, self.options.internal_ring, self.options.profile_shift*0.01) - if self.options.internal_ring: - outer_radius += self.options.spoke_width - return pitch_radius, 2*outer_radius, 2*outer_radius - - def gearCarrier(self, r, spoke_width, positions, mount_radius, mount_hole, circle=True, callback=None, move=None): - width = 2*r+spoke_width - - if self.boxes.move(width, width, move, before=True): - return - - try: - positions = [i*360/positions for i in range(positions)] - except TypeError: - pass - - self.boxes.ctx.save() - self.boxes.moveTo(width/2.0, width/2.0) - if callback: - self.boxes.cc(callback, None) - self.generate_spokes(r+0.5*spoke_width, spoke_width, positions, mount_radius, mount_hole, 1, "") - self.boxes.hole(0, 0, mount_hole) - - for angle in positions: - self.boxes.ctx.save() - self.boxes.moveTo(0, 0, angle) - self.boxes.hole(r, 0, mount_hole) - self.boxes.ctx.restore() - - self.boxes.moveTo(r+0.5*spoke_width+self.boxes.burn, 0, 90) - self.boxes.corner(360, r+0.5*spoke_width) - - self.boxes.ctx.restore() - self.boxes.move(width, width, move) - - def __call__(self, teeth_only=False, move="", callback=None, **kw): - """ Calculate Gear factors from inputs. - - Make list of radii, angles, and centers for each tooth and - iterate through them - - Turn on other visual features e.g. cross, rack, annotations, etc - """ - self.options = self.OptionParser.parse_args([f"--{name}={value}" for name, value in kw.items()]) - - warnings = [] # list of extra messages to be shown in annotations - # calculate unit factor for units defined in dialog. - unit_factor = 1 - # User defined options - teeth = self.options.teeth - # Angle of tangent to tooth at circular pitch wrt radial line. - angle = self.options.angle - # Clearance: Radial distance between top of tooth on one gear to - # bottom of gap on another. - clearance = self.options.clearance * unit_factor - mount_hole = self.options.mount_hole * unit_factor - # for spokes - mount_radius = self.options.mount_diameter * 0.5 * unit_factor - spoke_count = self.options.spoke_count - spoke_width = self.options.spoke_width * unit_factor - holes_rounding = self.options.holes_rounding * unit_factor # unused - # visible guide lines - centercross = self.options.centercross # draw center or not (boolean) - pitchcircle = self.options.pitchcircle # draw pitch circle or not (boolean) - - # Accuracy of teeth curves - accuracy_involute = 20 # Number of points of the involute curve - accuracy_circular = 9 # Number of points on circular parts - if self.options.accuracy is not None: - if self.options.accuracy == 0: - # automatic - if teeth < 10: accuracy_involute = 20 - elif teeth < 30: accuracy_involute = 12 - else: accuracy_involute = 6 - else: - accuracy_involute = self.options.accuracy - - accuracy_circular = max(3, int(accuracy_involute/2) - 1) # never less than three - # print >>self.tty, "accuracy_circular=%s accuracy_involute=%s" % (accuracy_circular, accuracy_involute) - # Pitch (circular pitch): Length of the arc from one tooth to the next) - # Pitch diameter: Diameter of pitch circle. - pitch = self.calc_circular_pitch() - # Replace section below with this call to get the combined gear_calculations() above - (pitch_radius, base_radius, addendum, dedendum, - outer_radius, root_radius, tooth) = gear_calculations(teeth, pitch, angle, clearance, self.options.internal_ring, self.options.profile_shift*0.01) - - b = self.boxes.burn - # Add Rack (instead) - if self.options.drawrack: - base_height = self.options.base_height * unit_factor - tab_width = self.options.base_tab * unit_factor - tooth_count = self.options.teeth_length - (points, guide_points) = generate_rack_points(tooth_count, pitch, addendum, angle, - base_height, tab_width, clearance, pitchcircle) - width = tooth_count * pitch + 2 * tab_width - height = base_height + 2 * addendum - if self.boxes.move(width, height, move, before=True): - return - - self.boxes.cc(callback, None) - self.boxes.moveTo(width/2.0, base_height+addendum, -180) - if base_height < 0: - points = points[1:-1] - self.boxes.drawPoints(points, close=base_height >= 0) - self.boxes.drawPoints(guide_points, kerfdir=0) - self.boxes.move(width, height, move) - - return - - # Move only - width = height = 2 * outer_radius - if self.options.internal_ring: - width = height = width + 2 * self.options.spoke_width - - if not teeth_only and self.boxes.move(width, height, move, before=True): - return - - # Detect Undercut of teeth -## undercut = int(ceil(undercut_min_teeth( angle ))) -## needs_undercut = teeth < undercut #? no longer needed ? - if have_undercut(teeth, angle, 1.0): - min_teeth = int(ceil(undercut_min_teeth(angle, 1.0))) - min_angle = undercut_min_angle(teeth, 1.0) + .1 - max_k = undercut_max_k(teeth, angle) - msg = "Undercut Warning: This gear (%d teeth) will not work well.\nTry tooth count of %d or more,\nor a pressure angle of %.1f [deg] or more,\nor try a profile shift of %d %%.\nOr other decent combinations." % (teeth, min_teeth, min_angle, int(100.*max_k)-100.) - # alas annotation cannot handle the degree symbol. Also it ignore newlines. - # so split and make a list - warnings.extend(msg.split("\n")) - - # All base calcs done. Start building gear - points = generate_spur_points(teeth, base_radius, pitch_radius, outer_radius, root_radius, accuracy_involute, accuracy_circular) - - if not teeth_only: - self.boxes.moveTo(width/2, height/2) - self.boxes.cc(callback, None, 0, 0) - self.boxes.drawPoints(points) - # Spokes - if not teeth_only and not self.options.internal_ring: # only draw internals if spur gear - msg = self.generate_spokes(root_radius, spoke_width, spoke_count, mount_radius, mount_hole, - unit_factor, self.options.units) - warnings.extend(msg) - - # Draw mount hole - # A : rx,ry x-axis-rotation, large-arch-flag, sweepflag x,y - r = mount_hole / 2 - self.boxes.hole(0, 0, r) - elif not teeth_only: - # its a ring gear - # which only has an outer ring where width = spoke width - r = outer_radius + spoke_width + self.boxes.burn - self.boxes.ctx.save() - self.boxes.moveTo(r, 0) - self.boxes.ctx.arc(-r, 0, r, 0, 2*pi) - self.boxes.ctx.restore() - - # Add center - if centercross: - cs = pitch / 3.0 # centercross length - self.boxes.ctx.save() - self.boxes.ctx.move_to(-cs, 0) - self.boxes.ctx.line_to(+cs, 0) - self.boxes.ctx.move_to(0, -cs) - self.boxes.ctx.line_to(0, +cs) - self.boxes.ctx.restore() - - # Add pitch circle (for mating) - if pitchcircle: - self.boxes.hole(0, 0, pitch_radius) - - # Add Annotations (above) - if self.options.annotation: - outer_dia = outer_radius * 2 - - if self.options.internal_ring: - outer_dia += 2 * spoke_width - - notes = [] - notes.extend(warnings) - #notes.append('Document (%s) scale conversion = %2.4f' % (self.document.getroot().find(inkex.addNS('namedview', 'sodipodi')).get(inkex.addNS('document-units', 'inkscape')), unit_factor)) - notes.extend(['Teeth: %d CP: %2.4f(%s) ' % (teeth, pitch / unit_factor, self.options.units), - f'DP: {25.4 * pi / pitch:2.3f} Module: {pitch:2.4f}(mm)', - 'Pressure Angle: %2.2f degrees' % (angle), - f'Pitch diameter: {pitch_radius * 2 / unit_factor:2.3f} {self.options.units}', - f'Outer diameter: {outer_dia / unit_factor:2.3f} {self.options.units}', - f'Base diameter: {base_radius * 2 / unit_factor:2.3f} {self.options.units}'#, - #'Addendum: %2.4f %s' % (addendum / unit_factor, self.options.units), - #'Dedendum: %2.4f %s' % (dedendum / unit_factor, self.options.units) - ]) - # text height relative to gear size. - # ranges from 10 to 22 over outer radius size 60 to 360 - text_height = max(10, min(10+(outer_dia-60)/24, 22)) - # position above - y = - outer_radius - (len(notes)+1) * text_height * 1.2 - - for note in notes: - self.boxes.text(note, -outer_radius, y) - y += text_height * 1.2 - - if not teeth_only: - self.boxes.move(width, height, move) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/__init__.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/__init__.py deleted file mode 100644 index 89de2fd..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/__init__.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -import importlib -import inspect -import os -import pkgutil -from types import ModuleType -from typing import Any - -import boxes - -ui_groups_by_name = {} - - -class UIGroup: - - def __init__(self, name: str, title: str | None = None, description: str = "", image: str = "") -> None: - self.name = name - self.title = title or name - self.description = description - self._image = image - self.generators: list[Any] = [] - # register - ui_groups_by_name[name] = self - - def add(self, box) -> None: - self.generators.append(box) - self.generators.sort(key=lambda b: getattr(b, '__name__', None) or b.__class__.__name__) - - @property - def thumbnail(self) -> str: - return self._image and f"{self._image}-thumb.jpg" - - @property - def image(self) -> str: - return self._image and f"{self._image}.jpg" - - -ui_groups: list[UIGroup] = [ - UIGroup("Box", "Boxes", image="UniversalBox"), - UIGroup("FlexBox", "Boxes with flex", image="RoundedBox"), - UIGroup("Tray", "Trays and Drawer Inserts", image="TypeTray"), - UIGroup("Shelf", "Shelves", image="DisplayShelf"), - UIGroup("WallMounted", image="WallTypeTray"), - UIGroup("Holes", "Hole patterns", image=""), - UIGroup("Part", "Parts and Samples", image="BurnTest"), - UIGroup("Misc", image="TrafficLight"), - UIGroup("Unstable", description="Generators are still untested or need manual adjustment to be useful."), -] - - -def getAllBoxGenerators() -> dict[str, type[boxes.Boxes]]: - generators = {} - path = __path__ - if "BOXES_GENERATOR_PATH" in os.environ: - path.extend(os.environ.get("BOXES_GENERATOR_PATH", "").split(":")) - for importer, modname, ispkg in pkgutil.walk_packages(path=path, prefix=__name__ + '.'): - module = importlib.import_module(modname) - if module.__name__.split('.')[-1].startswith("_"): - continue - for k, v in module.__dict__.items(): - if v is boxes.Boxes: - continue - if inspect.isclass(v) and issubclass(v, boxes.Boxes) and v.__name__[0] != '_': - generators[modname + '.' + v.__name__] = v - return generators - - -def getAllGeneratorModules() -> dict[str, ModuleType]: - generators = {} - path = __path__ - if "BOXES_GENERATOR_PATH" in os.environ: - path.extend(os.environ.get("BOXES_GENERATOR_PATH", "").split(":")) - for importer, modname, ispkg in pkgutil.walk_packages( - path=path, - prefix=__name__ + '.', - onerror=lambda x: None): - module = importlib.import_module(modname) - generators[modname.split('.')[-1]] = module - return generators diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/_swtemplate.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/_swtemplate.py deleted file mode 100644 index a185bfe..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/_swtemplate.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# mypy: ignore-errors - -from boxes import * - - -class SlatwallXXX(Boxes): # Change class name! - """DESCRIPTION""" - - ui_group = "SlatWall" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.SlatWallSettings) - - # remove cli params you do not need - self.buildArgParser(x=100, sx="3*50", y=100, sy="3*50", h=100, hi=0) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--XX", action="store", type=float, default=0.5, - help="DESCRIPTION") - - def render(self): - # Add slat wall edges - s = edges.SlatWallSettings(self.thickness, True, - **self.edgesettings.get("SlatWall", {})) - s.edgeObjects(self) - self.slatWallHolesAt = edges.SlatWallHoles(self, s) - - # render your parts here diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/_template.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/_template.py deleted file mode 100644 index a99cb19..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/_template.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BOX(Boxes): # Change class name! - """DESCRIPTION""" - - ui_group = "Unstable" # see ./__init__.py for names - - def __init__(self) -> None: - Boxes.__init__(self) - - # Uncomment the settings for the edge types you use - # use keyword args to set default values - # self.addSettingsArgs(edges.FingerJointSettings, finger=1.0,space=1.0) - # self.addSettingsArgs(edges.DoveTailSettings) - # self.addSettingsArgs(edges.StackableSettings) - # self.addSettingsArgs(edges.HingeSettings) - # self.addSettingsArgs(edges.SlideOnLidSettings) - # self.addSettingsArgs(edges.ClickSettings) - # self.addSettingsArgs(edges.FlexSettings) - # self.addSettingsArgs(edges.HandleEdgeSettings) - # self.addSettingsArgs(edges.RoundedTriangleEdgeSettings) - # self.addSettingsArgs(edges.MountingSettings) - - # remove cli params you do not need - self.buildArgParser(x=100, sx="3*50", y=100, sy="3*50", h=100, hi=0) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--XX", action="store", type=float, default=0.5, - help="DESCRIPTION") - - - def render(self): - # adjust to the variables you want in the local scope - x, y, h = self.x, self.y, self.h - t = self.thickness - - # Create new Edges here if needed E.g.: - s = edges.FingerJointSettings(self.thickness, relative=False, - space = 10, finger=10, - width=self.thickness) - p = edges.FingerJointEdge(self, s) - p.char = "a" # 'a', 'A', 'b' and 'B' is reserved for being used within generators - self.addPart(p) - - # render your parts here diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/abox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/abox.py deleted file mode 100644 index 4e32ea5..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/abox.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.lids import LidSettings - - -class ABox(Boxes): - """A simple Box""" - - description = "This box is kept simple on purpose. If you need more features have a look at the UniversalBox." - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(LidSettings) - self.buildArgParser("x", "y", "h", "outside", "bottom_edge") - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - - t1, t2, t3, t4 = "eeee" - b = self.edges.get(self.bottom_edge, self.edges["F"]) - sideedge = "F" # if self.vertical_edges == "finger joints" else "h" - - if self.outside: - self.x = x = self.adjustSize(x, sideedge, sideedge) - self.y = y = self.adjustSize(y) - self.h = h = self.adjustSize(h, b, t1) - - with self.saved_context(): - self.rectangularWall(x, h, [b, sideedge, t1, sideedge], - ignore_widths=[1, 6], move="up") - self.rectangularWall(x, h, [b, sideedge, t3, sideedge], - ignore_widths=[1, 6], move="up") - - if self.bottom_edge != "e": - self.rectangularWall(x, y, "ffff", move="up") - self.lid(x, y) - - self.rectangularWall(x, h, [b, sideedge, t3, sideedge], - ignore_widths=[1, 6], move="right only") - self.rectangularWall(y, h, [b, "f", t2, "f"], - ignore_widths=[1, 6], move="up") - self.rectangularWall(y, h, [b, "f", t4, "f"], - ignore_widths=[1, 6], move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/agricolainsert.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/agricolainsert.py deleted file mode 100644 index 3b1a8a6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/agricolainsert.py +++ /dev/null @@ -1,931 +0,0 @@ -# Copyright (C) 2020 Guillaume Collic -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math -from functools import partial - -from boxes import Boxes, edges - -from .dividertray import DividerSlotsEdge, SlotDescriptionsGenerator - - -class AgricolaInsert(Boxes): - """ - Agricola Revised Edition game box insert, including some expansions. - """ - - ui_group = "Misc" - - description = """ -This insert was designed with 3 mm plywood in mind, and should work fine with -materials around this thickness. - -This is an insert for the [Agricola Revised Edition](https://boardgamegeek.com/boardgame/200680/agricola-revised-edition) -board game. It is specifically designed around the [Farmers Of The Moor expansion](https://boardgamegeek.com/boardgameexpansion/257344/agricola-farmers-moor), -and should also store the [5-6 players expansion](https://boardgamegeek.com/boardgameexpansion/210625/agricola-expansion-5-and-6-players) -(not tested, but I tried to take everything into account for it, please inform -us if you tested it). - -It can be stored inside the original game box, including the 2 expansions, -with the lid slightly raised. - -The parts of a given element are mostly generated next to each other vertically. -It should be straightforward to match them. - -Here are the different elements, from left to right in the generated file. - -#### Card tray - -The cards are all kept in a tray, with paper dividers to sort them easily. When -the tray is not full of cards, wood dividers slides in slots in order to keep -the cards from falling into the empty space. - -There should be enough space for the main game, Farmers Of The Moor, and the 5-6 -player expansion, but not much more than that. - -To keep a lower profile, the cards are at a slight angle, and the paper dividers -tabs are horizontal instead of vertical. -A small wall keeps the card against one side while the tabs protrude on the -other side, above the small wall. - -The wall with the big hole is the sloped one. It goes between the two -"comb-like" walls first, with its two small holes at the bottom. Then there is a -low-height long wall with a sloped edge which should go from the sloped wall to -the other side. You can finish the tray with the last wall at the end. - -#### Upper level trays - -4 trays with movable walls are used to store resources. They were designed to -store them in this order: - -* Stone / Vegetable / Pig / Cow -* Reed / Grain / Sheep -* Wood / Clay -* Food / Fire - -The wall would probably be better if fixed instead of movable, but I would like -to test with the 5-6 player expansion to be sure their positions are correct -with it too. - -The little feet of the movable wall should be glued. The triangles are put -horizontally, with their bases towards the sides. - -#### Lower level tray - -The lower level tray is used to store the horses. - -#### Room/Field tiles - -Two boxes are generated to store the room/field tiles. One for the wood/field, -the other for the clay/stone. They are stored with the main opening upside, but -I prefer to use them during play with this face on the side. - -#### Moor/Forest and miscellaneous tiles - -A box is generated to store the Moor/Forest tiles, and some other tiles such as -the "multiple resources" cardboard tokens. - -The Moor/Forest tiles are at the same height as the Room/Field, and the upper -level trays are directly on them. The horse box and player box are slightly -lower. This Moor/Forest box have a lowered corner (the one for the miscellaneous -tiles). Two cardboard pieces can be stored between the smaller boxes and the -upper level trays (as seen on the picture). - -Be sure to match the pieces so that the walls with smaller heights are next to -each other. - -#### Players bit boxes - -Each player has its own box where the bits of his color are stored. -The cardboard bed from Farmers Of The Moor is central to this box. - -* The fences are stored inside the bed -* The bed is placed in the box, with holes to keep it there (and to take less - height) -* The stables are stored in the two corners -* The five farmers are stored between the bed and the three walls, alternatively - head up and head down. - -During assembly, the small bars are put in the middle holes. The two bigger -holes at the ends are used for the bed feet. The bar keeps the bed from -protruding underneath. - -""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1.0) - - def render(self): - player_box_height = 34.5 - player_box_inner_width = 50.5 - bigger_box_inner_height = 36.7 - row_width = 37.2 - tray_inner_height = 17 - box_width = 218 - card_tray_height = ( - self.thickness * 2 + tray_inner_height + bigger_box_inner_height - ) - card_tray_width = ( - 305.35 - player_box_inner_width * 2 - row_width * 2 - 9 * self.thickness - ) - - self.render_card_divider_tray(card_tray_height, box_width, card_tray_width) - self.render_upper_token_trays(tray_inner_height, box_width) - wood_room_box_width = 39.8 - self.render_room_box(wood_room_box_width, bigger_box_inner_height, row_width) - stone_room_box_width = 26.7 - self.render_room_box(stone_room_box_width, bigger_box_inner_height, row_width) - moor_box_length = 84.6 - self.render_moor_box( - bigger_box_inner_height, player_box_height, row_width, moor_box_length - ) - horse_box_margin = 0.5 - horse_box_length = ( - box_width - - wood_room_box_width - - stone_room_box_width - - moor_box_length - - 6 * self.thickness - - horse_box_margin - ) - self.render_horse_box(player_box_height, row_width, horse_box_length) - for _ in range(6): - self.render_player_box(player_box_height, player_box_inner_width) - - def render_card_divider_tray( - self, card_tray_height, card_tray_length, card_tray_width - ): - """ - The whole tray which contains the cards, including its dividers. - Cards are at an angle, to save height. - """ - self.ctx.save() - - tray_inner_length = card_tray_length - self.thickness - margin_for_score_sheet = 0 # 3 if you want more space for score sheet - sleeved_cards_width = 62 + margin_for_score_sheet - - rad = math.acos(card_tray_height / sleeved_cards_width) - angle = math.degrees(rad) - cos = math.cos(rad) - tan = math.tan(rad) - sin = math.sin(rad) - - slots_number = 19 - slot_depth = 30 - slot_descriptions = SlotDescriptionsGenerator().generate_all_same_angles( - [tray_inner_length / slots_number for _ in range(slots_number)], - self.thickness, - 0.2, - slot_depth, - card_tray_height, - angle, - ) - slot_descriptions.adjust_to_target_length(tray_inner_length) - - sloped_wall_height = sleeved_cards_width - self.thickness * (tan + 1 / tan) - sloped_wall_posx_at_y0 = ( - tray_inner_length - sloped_wall_height * tan - cos * self.thickness - ) - sloped_wall_posx = sloped_wall_posx_at_y0 + cos * self.thickness / 2 - sloped_wall_posy = sin * self.thickness / 2 - - dse = DividerSlotsEdge(self, slot_descriptions.descriptions) - for _ in range(2): - self.rectangularWall( - tray_inner_length, - card_tray_height, - ["e", "e", dse, "f"], - move="up", - callback=[ - partial( - lambda: self.fingerHolesAt( - sloped_wall_posx, - sloped_wall_posy, - sloped_wall_height, - angle=90 - angle, - ) - ) - ], - ) - - # generate spacer - spacer_height = card_tray_height / 2 - spacer_spacing = card_tray_width-99.8 - spacer_upper_width = sloped_wall_posx_at_y0 + spacer_height * tan - self.trapezoidWall( - spacer_height, - spacer_upper_width, - sloped_wall_posx_at_y0, - "fefe", - move="up rotated", - ) - - self.rectangularWall( - card_tray_width, - card_tray_height, - "eFeF", - move="up", - callback=[ - partial( - lambda: self.fingerHolesAt( - spacer_spacing - self.thickness / 2, 0, spacer_height - ) - ) - ], - ) - self.rectangularWall( - card_tray_width, - sloped_wall_height, - "efef", - move="up", - callback=[ - partial( - self.generate_card_tray_sloped_wall_holes, - card_tray_width, - sloped_wall_height, - spacer_height, - spacer_spacing, - rad, - ) - ], - ) - - self.ctx.restore() - self.rectangularWall(card_tray_length, 0, "FFFF", move="right only") - self.ctx.save() - - divider_height = sleeved_cards_width - self.thickness * tan - self.generate_divider( - card_tray_width, divider_height, slot_depth, spacer_spacing, "up" - ) - self.explain( - [ - "Wood divider", - "Hard separation to keep the card", - "from slipping in empty space left.", - "Takes more space, but won't move.", - "Duplicate as much as you want", - "(I use 2).", - ] - ) - - self.ctx.restore() - self.rectangularWall(card_tray_width, 0, "ffff", move="right only") - self.ctx.save() - - self.generate_paper_divider( - card_tray_width, sleeved_cards_width, slot_depth, spacer_spacing, "up" - ) - self.explain( - [ - "Paper divider", - "Soft separation to search easily", - "the card group you need", - "(by expansion, number of player,", - "etc.).", - "Duplicate as much as you want", - "(I use 7).", - ] - ) - self.ctx.restore() - self.rectangularWall(card_tray_width, 0, "ffff", move="right only") - - def explain(self, strings): - self.text( - str.join( - "\n", - strings, - ), - fontsize=7, - align="bottom left", - ) - - def generate_sloped_wall_holes(self, side_wall_length, rad, sloped_wall_height): - cos = math.cos(rad) - tan = math.tan(rad) - sin = math.sin(rad) - posx_at_y0 = side_wall_length - sloped_wall_height * tan - posx = posx_at_y0 - cos * self.thickness / 2 - posy = sin * self.thickness / 2 - self.fingerHolesAt(posx, posy, sloped_wall_height, angle=90 - math.degrees(rad)) - - def generate_card_tray_sloped_wall_holes( - self, side_wall_length, sloped_wall_height, spacer_height, spacer_spacing, rad - ): - # Spacer finger holes - self.fingerHolesAt( - side_wall_length - (spacer_spacing - self.thickness / 2), - # the sloped wall doesn't exactly touch the bottom of the spacer - -self.thickness * math.tan(rad), - spacer_height / math.cos(rad), - ) - - # Big hole to access "lost" space behind sloped wall - radius = 5 - padding = 8 - total_loss = 2 * radius + 2 * padding - self.moveTo(radius + padding, padding) - self.polyline( - side_wall_length - total_loss, - (90, radius), - sloped_wall_height - total_loss, - (90, radius), - side_wall_length - total_loss, - (90, radius), - sloped_wall_height - total_loss, - (90, radius), - ) - - def generate_paper_divider(self, width, height, slot_depth, spacer_spacing, move): - """ - A card separation made of paper, which moves freely in the card tray. - Takes less space and easy to manipulate, but won't block cards in place. - """ - if self.move(width, height, move, True): - return - - margin = 0.5 - actual_width = width - margin - self.polyline( - actual_width - spacer_spacing, - 90, - height - slot_depth, - -90, - spacer_spacing, - 90, - slot_depth, - 90, - actual_width, - 90, - height, - 90, - ) - - # Move for next piece - self.move(width, height, move) - - def generate_divider(self, width, height, slot_depth, spacer_spacing, move): - """ - A card separation made of wood which slides in the side slots. - Can be useful to do hard separations, but takes more space and - less movable than the paper ones. - """ - total_width = width + 2 * self.thickness - - if self.move(total_width, height, move, True): - return - - radius = 16 - padding = 20 - divider_notch_depth = 35 - - self.polyline( - self.thickness + spacer_spacing + padding - radius, - (90, radius), - divider_notch_depth - radius - radius, - (-90, radius), - width - 2 * radius - 2 * padding - spacer_spacing, - (-90, radius), - divider_notch_depth - radius - radius, - (90, radius), - self.thickness + padding - radius, - 90, - slot_depth, - 90, - self.thickness, - -90, - height - slot_depth, - 90, - width - spacer_spacing, - 90, - height - slot_depth, - -90, - self.thickness + spacer_spacing, - 90, - slot_depth, - ) - - # Move for next piece - self.move(total_width, height, move) - - def render_horse_box(self, player_box_height, row_width, width): - """ - Box for the horses on lower level. Same height as player boxes. - """ - length = 2 * row_width + 3 * self.thickness - self.render_simple_tray(width, length, player_box_height) - - def render_moor_box( - self, bigger_box_inner_height, player_box_height, row_width, length - ): - """ - Box for the moor/forest tiles, and the cardboard tokens with multiple - units of resources. - A corner is lowered (the one for the tokens) at the same height as player boxes - to store 2 levels of small boards there. - """ - self.ctx.save() - height = bigger_box_inner_height - lowered_height = player_box_height - self.thickness - lowered_corner_height = height - lowered_height - corner_length = 53.5 - - self.rectangularWall( - length, - 2 * row_width + self.thickness, - "FfFf", - move="up", - callback=[ - partial( - lambda: self.fingerHolesAt( - 0, row_width + 0.5 * self.thickness, length, 0 - ) - ) - ], - ) - - for i in range(2): - self.rectangularWall( - length, - lowered_height, - [ - "f", - "f", - MoorBoxSideEdge( - self, corner_length, lowered_corner_height, i % 2 == 0 - ), - "f", - ], - move="up", - ) - self.rectangularWall(length, height / 2, "ffef", move="up") - - for i in range(2): - self.rectangularWall( - 2 * row_width + self.thickness, - lowered_height, - [ - "F", - "F", - MoorBoxHoleEdge(self, height, lowered_corner_height, i % 2 == 0), - "F", - ], - move="up", - callback=[ - partial(self.generate_side_finger_holes, row_width, height / 2) - ], - ) - - self.ctx.restore() - self.rectangularWall(length, 0, "FFFF", move="right only") - - def generate_side_finger_holes(self, row_width, height): - self.fingerHolesAt(row_width + 0.5 * self.thickness, 0, height) - - def render_room_box(self, width, height, row_width): - """ - A box in which storing room/field tiles. - """ - border_height = 12 - room_box_length = row_width * 2 + self.thickness - - self.ctx.save() - - self.rectangularWall( - room_box_length, - height, - "eFfF", - move="up", - callback=[partial(self.generate_side_finger_holes, row_width, height)], - ) - - self.rectangularWall( - room_box_length, - width, - "FFfF", - move="up", - callback=[partial(self.generate_side_finger_holes, row_width, width)], - ) - - self.rectangularWall( - room_box_length, - border_height, - "FFeF", - move="up", - callback=[ - partial(self.generate_side_finger_holes, row_width, border_height) - ], - ) - - for _ in range(3): - self.trapezoidWall(width, height, border_height, "ffef", move="up") - - self.ctx.restore() - - self.rectangularWall(room_box_length, 0, "FFFF", move="right only") - - def render_player_box(self, player_box_height, player_box_inner_width): - """ - A box in which storing all the bits of a single player, - including (and designed for) the cardboard bed from Farmers Of The Moor. - """ - self.ctx.save() - bed_inner_height = player_box_height - self.thickness - bed_inner_length = 66.75 - bed_inner_width = player_box_inner_width - cardboard_bed_foot_height = 6.5 - cardboard_bed_hole_margin = 5 - cardboard_bed_hole_length = 12 - bed_head_length = 20 - bed_foot_height = 18 - support_length = 38 - - bed_edge = Bed2SidesEdge( - self, bed_inner_length, bed_head_length, bed_foot_height - ) - noop_edge = NoopEdge(self) - self.ctx.save() - optim_180_x = ( - bed_inner_length + self.thickness + bed_head_length + 2 * self.spacing - ) - optim_180_y = 2 * bed_foot_height - player_box_height + 2 * self.spacing - for _ in range(2): - self.rectangularWall( - bed_inner_length, - bed_inner_height, - ["F", bed_edge, noop_edge, "F"], - move="up", - ) - self.moveTo(optim_180_x, optim_180_y, -180) - self.ctx.restore() - self.moveTo(0, bed_inner_height + self.thickness + self.spacing + optim_180_y) - - self.rectangularWall( - bed_inner_length, - bed_inner_width, - "feff", - move="up", - callback=[ - partial( - self.generate_bed_holes, - bed_inner_width, - cardboard_bed_hole_margin, - cardboard_bed_hole_length, - support_length, - ) - ], - ) - - self.ctx.save() - self.rectangularWall( - bed_inner_width, - bed_inner_height, - ["F", "f", BedHeadEdge(self, bed_inner_height - 15), "f"], - move="right", - ) - for _ in range(2): - self.rectangularWall( - cardboard_bed_foot_height - self.thickness, - support_length, - "efee", - move="right", - ) - self.ctx.restore() - self.rectangularWall( - bed_inner_width, - bed_inner_height, - "Ffef", - move="up only", - ) - - self.ctx.restore() - self.rectangularWall( - bed_inner_length + bed_head_length + self.spacing - self.thickness, - 0, - "FFFF", - move="right only", - ) - - def generate_bed_holes(self, width, margin, hole_length, support_length): - support_start = margin + hole_length - - bed_width = 29.5 - bed_space_to_wall = (width - bed_width) / 2 - bed_feet_width = 3 - - posy_1 = bed_space_to_wall - posy_2 = width - bed_space_to_wall - - for y, direction in [(posy_1, 1), (posy_2, -1)]: - bed_feet_middle_y = y + direction * bed_feet_width / 2 - support_middle_y = y + direction * self.thickness / 2 - self.rectangularHole( - margin, - bed_feet_middle_y, - hole_length, - bed_feet_width, - center_x=False, - ) - self.fingerHolesAt(support_start, support_middle_y, support_length, angle=0) - self.rectangularHole( - support_start + support_length, - bed_feet_middle_y, - hole_length, - bed_feet_width, - center_x=False, - ) - - def render_upper_token_trays(self, tray_inner_height, box_width): - """ - Upper level : multiple trays for each resource - (beside horses which are on the lower level) - """ - tray_height = tray_inner_height + self.thickness - upper_level_width = 196 - upper_level_length = box_width - row_width = upper_level_width / 3 - - # Stone / Vegetable / Pig / Cow - self.render_simple_tray(row_width, upper_level_length, tray_height, 3) - # Reed / Grain / Sheep - self.render_simple_tray(row_width, upper_level_length * 2 / 3, tray_height, 2) - # Wood / Clay - self.render_simple_tray(row_width, upper_level_length * 2 / 3, tray_height, 1) - # Food / Fire - self.render_simple_tray(upper_level_length / 3, row_width * 2, tray_height, 1) - - def render_simple_tray(self, outer_width, outer_length, outer_height, dividers=0): - """ - One of the upper level trays, with movable dividers. - """ - width = outer_width - 2 * self.thickness - length = outer_length - 2 * self.thickness - height = outer_height - self.thickness - self.ctx.save() - self.rectangularWall(width, length, "FFFF", move="up") - for _ in range(2): - self.rectangularWall(width, height, "ffef", move="up") - self.ctx.restore() - self.rectangularWall(width, length, "FFFF", move="right only") - for _ in range(2): - self.rectangularWall(height, length, "FfFe", move="right") - - if dividers: - self.ctx.save() - for _ in range(dividers): - self.render_simple_tray_divider(width, height, "up") - self.ctx.restore() - self.render_simple_tray_divider(width, height, "right only") - - def render_simple_tray_divider(self, width, height, move): - """ - Simple movable divider. A wall with small feet for a little more stability. - """ - - if self.move(height, width, move, True): - return - - t = self.thickness - self.polyline( - height - t, - 90, - t, - -90, - t, - 90, - width - 2 * t, - 90, - t, - -90, - t, - 90, - height - t, - 90, - width, - 90, - ) - - self.move(height, width, move) - - self.render_simple_tray_divider_feet(width, height, move) - - def render_simple_tray_divider_feet(self, width, height, move): - sqr2 = math.sqrt(2) - t = self.thickness - divider_foot_width = 2 * t - full_width = t + 2 * divider_foot_width - move_length = self.spacing + full_width / sqr2 - move_width = self.spacing + max(full_width, height) - - if self.move(move_width, move_length, move, True): - return - - self.ctx.save() - self.polyline( - sqr2 * divider_foot_width, - 135, - t, - -90, - t, - -90, - t, - 135, - sqr2 * divider_foot_width, - 135, - full_width, - 135, - ) - self.ctx.restore() - - self.moveTo(-self.burn / sqr2, self.burn * (1 + 1 / sqr2), 45) - self.moveTo(full_width) - - self.polyline( - 0, - 135, - sqr2 * divider_foot_width, - 135, - t, - -90, - t, - -90, - t, - 135, - sqr2 * divider_foot_width, - 135, - ) - - self.move(move_width, move_length, move) - - -class MoorBoxSideEdge(edges.BaseEdge): - """ - Edge for the sides of the moor tiles box - """ - - def __init__(self, boxes, corner_length, corner_height, lower_corner) -> None: - super().__init__(boxes, None) - self.corner_height = corner_height - self.lower_corner = lower_corner - self.corner_length = corner_length - - def __call__(self, length, **kw): - radius = self.corner_height / 2 - if self.lower_corner: - self.polyline( - length - self.corner_height - self.corner_length, - (90, radius), - 0, - (-90, radius), - self.corner_length, - ) - else: - self.polyline(length) - - def startwidth(self) -> float: - return self.corner_height - - def endwidth(self) -> float: - return 0.0 if self.lower_corner else self.corner_height - - -class MoorBoxHoleEdge(edges.BaseEdge): - """ - Edge which does the notches for the moor tiles box - """ - - def __init__(self, boxes, height, corner_height, lower_corner) -> None: - super().__init__(boxes, None) - self.height = height - self.corner_height = corner_height - self.lower_corner = lower_corner - - def __call__(self, length, **kw): - one_side_width = (length - self.thickness) / 2 - notch_width = 20 - radius = 6 - upper_edge = (one_side_width - notch_width - 2 * radius) / 2 - hole_start = 10 - lowered_hole_start = 2 - hole_depth = self.height - 2 * radius - lower_edge = notch_width - 2 * radius - - one_side_polyline = lambda margin1, margin2: [ - upper_edge, - (90, radius), - hole_depth - margin1, - (-90, radius), - lower_edge, - (-90, radius), - hole_depth - margin2, - (90, radius), - upper_edge, - ] - - normal_side_polyline = one_side_polyline(hole_start, hole_start) - corner_side_polyline = one_side_polyline( - lowered_hole_start, lowered_hole_start + self.corner_height - ) - - full_polyline = ( - normal_side_polyline - + [0, self.thickness, 0] - + (corner_side_polyline if self.lower_corner else normal_side_polyline) - ) - self.polyline(*full_polyline) - - def startwidth(self) -> float: - return self.corner_height - - def endwidth(self) -> float: - return 0.0 if self.lower_corner else self.corner_height - - -class BedHeadEdge(edges.BaseEdge): - """ - Edge which does the head side of the Agricola player box - """ - - def __init__(self, boxes, hole_depth) -> None: - super().__init__(boxes, None) - self.hole_depth = hole_depth - - def __call__(self, length, **kw): - hole_length = 16 - upper_corner = 10 - lower_corner = 6 - depth = self.hole_depth - upper_corner - lower_corner - upper_edge = (length - hole_length - 2 * upper_corner) / 2 - lower_edge = hole_length - 2 * lower_corner - - self.polyline( - upper_edge, - (90, upper_corner), - depth, - (-90, lower_corner), - lower_edge, - (-90, lower_corner), - depth, - (90, upper_corner), - upper_edge, - ) - - -class Bed2SidesEdge(edges.BaseEdge): - """ - Edge which does a bed like shape, skipping the next corner. - The next edge should be a NoopEdge - """ - - def __init__(self, boxes, bed_length, full_head_length, full_foot_height) -> None: - super().__init__(boxes, None) - self.bed_length = bed_length - self.full_head_length = full_head_length - self.full_foot_height = full_foot_height - - def __call__(self, bed_height, **kw): - foot_corner = 6 - middle_corner = 3 - head_corner = 10 - foot_height = self.full_foot_height - self.thickness - foot_corner - head_length = self.full_head_length - head_corner - self.thickness - corners = foot_corner + middle_corner + head_corner - head_height = bed_height - foot_height - corners - middle_length = self.bed_length - head_length - corners - - self.polyline( - foot_height, - (90, foot_corner), - middle_length, - (-90, middle_corner), - head_height, - (90, head_corner), - head_length, - ) - - -class NoopEdge(edges.BaseEdge): - """ - Edge which does nothing, not even turn or move. - """ - - def __init__(self, boxes) -> None: - super().__init__(boxes, None) - - def __call__(self, length, **kw): - # cancel turn - self.corner(-90) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/airpurifier.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/airpurifier.py deleted file mode 100644 index c308c7b..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/airpurifier.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class AirPurifier(Boxes): - """Housing for the Nukit Open Air Purifier""" - - ui_group = "Misc" - - description = """See [Nukit Open Air Purifier](https://github.com/opennukit/Nukit-Open-Air-Purifier/) -""" - - fan_holes = { - 40.: 32.5, - 60.: 50, - 80.: 71.5, - 92.: 82.5, - 120.: 105, - 140.: 125, - } - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.DoveTailSettings, size=2.0, depth=1) - - self.buildArgParser(x=498., y=496.) - - self.argparser.add_argument( - "--filter_height", action="store", type=float, default=46.77, - help="height of the filter along the flow direction (in mm)") - self.argparser.add_argument( - "--rim", action="store", type=float, default=30., - help="rim around the filter holing it in place (in mm)") - self.argparser.add_argument( - "--fan_diameter", action="store", type=float, default=140., - choices=list(self.fan_holes.keys()), - help="diameter of the fans (in mm)") - self.argparser.add_argument( - "--filters", action="store", type=int, default=2, - choices=(1, 2), - help="Filters on both sides or only one") - self.argparser.add_argument( - "--split_frames", action="store", type=BoolArg(), default=True, - help="Split frame pieces into four thin rectangles to save material") - self.argparser.add_argument( - "--fans_left", action="store", type=int, default=-1, - help="number of fans on the left side (-1 for maximal number)") - self.argparser.add_argument( - "--fans_right", action="store", type=int, default=-1, - help="number of fans on the right side (-1 for maximal number)") - self.argparser.add_argument( - "--fans_top", action="store", type=int, default=0, - help="number of fans on the top side (-1 for maximal number)") - self.argparser.add_argument( - "--fans_bottom", action="store", type=int, default=0, - help="number of fans on the bottom side (-1 for maximal number)") - self.argparser.add_argument( - "--screw_holes", action="store", type=float, default=5., - help="diameter of the holes for screwing in the fans (in mm)") - - def fanCB(self, n, h, l, fingerHoles=True, split_frames=False): - fh = self.filter_height - t = self.thickness - r = self.rim - - def cb(): - if fingerHoles: - heights = [fh + t/2] - if self.filters > 1: - heights.append(h - fh - t/2) - for h_ in heights: - if split_frames: - self.fingerHolesAt(0, h_, r, 0) - self.fingerHolesAt(r, h_, l-2*r, 0) - self.fingerHolesAt(l-r, h_, r, 0) - else: - self.fingerHolesAt(0, h_, l, 0) - - max_n = int((l-20) // (self.fan_diameter + 10)) - if n == -1: - n_ = max_n - else: - n_ = min(max_n, n) - - if n_ == 0: - return - w = (l-20) / n_ - x = 10 + w / 2 - delta = self.fan_holes[self.fan_diameter] / 2 - if self.filters==2: - posy = h / 2 - else: - posy = (h + t + fh) / 2 - - for i in range(n_): - posx = x+i*w - self.hole(posx, posy, d=self.fan_diameter-4) - for dx in [-delta, delta]: - for dy in [-delta, delta]: - self.hole(posx + dx, posy + dy, d=self.screw_holes) - - return cb - - def render(self): - x, y, d = self.x, self.y, self.fan_diameter - t = self.thickness - r = self.rim - - y = self.y = y - t # shorten by one thickness as we use the wall space - - fh = self.filter_height - h = d + 2 + self.filters * (fh + t) - - - self.rectangularWall(x, d, "ffff", callback=[ - self.fanCB(self.fans_top, d, x, False)], label="top", move="up") - self.rectangularWall(x, h, "ffff", callback=[ - self.fanCB(self.fans_bottom, h, x)], label="bottom", move="up") - - be = te = edges.CompoundEdge(self, "fff", (r, y - 2*r, r)) \ - if self.split_frames else "f" - - if self.filters==2: - le = edges.CompoundEdge(self, "EFE", (fh + t, d+2, fh + t)) - else: - le = edges.CompoundEdge(self, "FE", (d+2, fh + t)) - te = "f" - - for fans in (self.fans_left, self.fans_right): - self.rectangularWall( - y, h, [be, "h", te, le], - callback=[self.fanCB(fans, h, y, split_frames=self.split_frames)], - move="up") - - - if self.split_frames: - e = edges.CompoundEdge(self, "DeD", (r, x - 2*r, r)) - for _ in range(self.filters): - self.rectangularWall(x, r, ["E", "h", e, "h"], move="up") - self.rectangularWall(y - 2*r, r, "hded", move="up") - self.rectangularWall(y - 2*r, r, "hded", move="up") - self.rectangularWall(x, r, [e, "h", "h", "h"], move="up") - - self.rectangularWall(x, r, ["F", "f", e, "f"], move="up") - self.rectangularWall(y - 2*r, r, "fded", move="up") - self.rectangularWall(y - 2*r, r, "fded", move="up") - self.rectangularWall(x, r, [e, "f", "f", "f"], move="up") - else: - for _ in range(self.filters): - self.rectangularWall(x, y, "Ffff", callback=[ - lambda:self.rectangularHole(x/2, y/2, x - r, y - r, r=10)], move="up") - self.rectangularWall(x, y, "Ehhh", callback=[ - lambda:self.rectangularHole(x/2, y/2, x - r, y - r, r=10)], move="up") - if self.filters==1: - self.rectangularWall(x, y, "hhhh", move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/alledges.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/alledges.py deleted file mode 100644 index 6f31f92..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/alledges.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class AllEdges(Boxes): - """Showing all edge types""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.StackableSettings) - self.addSettingsArgs(edges.HingeSettings) - self.addSettingsArgs(edges.SlideOnLidSettings) - self.addSettingsArgs(edges.ClickSettings) - self.addSettingsArgs(edges.FlexSettings) - self.addSettingsArgs(edges.HandleEdgeSettings) - - self.buildArgParser(x=100) - - def render(self): - x = self.x - t = self.thickness - - chars = list(self.edges.keys()) - chars.sort(key=lambda c: c.lower() + (c if c.isupper() else '')) - chars.reverse() - - self.moveTo(0, 10*t) - - for c in chars: - with self.saved_context(): - self.move(0, 0, "", True) - self.moveTo(x, 0, 90) - self.edge(t+self.edges[c].startwidth()) - self.corner(90) - self.edges[c](x, h=4*t) - self.corner(90) - self.edge(t+self.edges[c].endwidth()) - self.move(0, 0, "") - - self.moveTo(0, 3*t + self.edges[c].spacing()) - self.text(f"{c} - {self.edges[c].description}") - self.moveTo(0, 12*t) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/angledbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/angledbox.py deleted file mode 100644 index 35e86f2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/angledbox.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class AngledBox(Boxes): - """Box with both ends cornered""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h", "outside", "bottom_edge") - self.argparser.add_argument( - "--n", action="store", type=int, default=5, - help="number of walls at one side (1+)") - self.argparser.add_argument( - "--top", action="store", type=str, default="none", - choices=["none", "angled hole", "angled lid", "angled lid2"], - help="style of the top and lid") - - def floor(self, x, y, n, edge='e', hole=None, move=None, callback=None, label=""): - r, h, side = self.regularPolygon(2*n+2, h=y/2.0) - t = self.thickness - - if n % 2: - lx = x - 2 * h + side - else: - lx = x - 2 * r + side - - edge = self.edges.get(edge, edge) - - tx = x + 2 * edge.spacing() - ty = y + 2 * edge.spacing() - - if self.move(tx, ty, move, before=True): - return - - self.moveTo((tx-lx)/2., edge.margin()) - - if hole: - with self.saved_context(): - hr, hh, hside = self.regularPolygon(2*n+2, h=y/2.0-t) - dx = side - hside - hlx = lx - dx - - self.moveTo(dx/2.0, t+edge.spacing()) - for i, l in enumerate(([hlx] + ([hside] * n))* 2): - self.edge(l) - self.corner(360.0/(2*n + 2)) - - for i, l in enumerate(([lx] + ([side] * n))* 2): - self.cc(callback, i, 0, edge.startwidth() + self.burn) - edge(l) - self.edgeCorner(edge, edge, 360.0/(2*n + 2)) - - self.move(tx, ty, move, label=label) - - def render(self): - - x, y, h, n = self.x, self.y, self.h, self.n - b = self.bottom_edge - - if n < 1: - n = self.n = 1 - - if x < y: - x, y = y, x - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - if self.top == "none": - h = self.adjustSize(h, False) - elif "lid" in self.top and self.top != "angled lid": - h = self.adjustSize(h) - self.thickness - else: - h = self.adjustSize(h) - - t = self.thickness - - r, hp, side = self.regularPolygon(2*n+2, h=y/2.0) - - if n % 2: - lx = x - 2 * hp + side - else: - lx = x - 2 * r + side - - fingerJointSettings = copy.deepcopy(self.edges["f"].settings) - fingerJointSettings.setValues(self.thickness, angle=360./(2 * (n+1))) - fingerJointSettings.edgeObjects(self, chars="gGH") - - with self.saved_context(): - if b != "e": - self.floor(x, y , n, edge='f', move="right", label="Bottom") - if self.top == "angled lid": - self.floor(x, y, n, edge='e', move="right", label="Lower Lid") - self.floor(x, y, n, edge='E', move="right", label="Upper Lid") - elif self.top in ("angled hole", "angled lid2"): - self.floor(x, y, n, edge='F', move="right", hole=True, label="Top Rim and Lid") - if self.top == "angled lid2": - self.floor(x, y, n, edge='E', move="right", label="Upper Lid") - self.floor(x, y , n, edge='F', move="up only") - - fingers = self.top in ("angled lid2", "angled hole") - - cnt = 0 - for j in range(2): - cnt += 1 - if j == 0 or n % 2: - self.rectangularWall(lx, h, move="right", - edges=b+"GfG" if fingers else b+"GeG", - label=f"wall {cnt}") - else: - self.rectangularWall(lx, h, move="right", - edges=b+"gfg" if fingers else b+"geg", - label=f"wall {cnt}") - for i in range(n): - cnt += 1 - if (i+j*((n+1)%2)) % 2: # reverse for second half if even n - self.rectangularWall(side, h, move="right", - edges=b+"GfG" if fingers else b+"GeG", - label=f"wall {cnt}") - else: - self.rectangularWall(side, h, move="right", - edges=b+"gfg" if fingers else b+"geg", - label=f"wall {cnt}") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/angledcutjig.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/angledcutjig.py deleted file mode 100644 index 08e5ebf..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/angledcutjig.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class AngledCutJig(Boxes): # Change class name! - """Jig for making angled cuts in a laser cutter""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1.) - - # remove cli params you do not need - self.buildArgParser(x=50, y=100) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--angle", action="store", type=float, default=45., - help="Angle of the cut") - - def bottomCB(self): - t = self.thickness - self.fingerHolesAt(10-t, 4.5*t, 20, 0) - self.fingerHolesAt(30+t, 4.5*t, self.x, 0) - self.fingerHolesAt(10-t, self.y-4.5*t, 20, 0) - self.fingerHolesAt(30+t, self.y-4.5*t, self.x, 0) - - def render(self): - # adjust to the variables you want in the local scope - x, y = self.x, self.y - t = self.thickness - - th = x * math.tan(math.radians(90-self.angle)) - l = (x**2 + th**2)**0.5 - th2 = 20 * math.tan(math.radians(self.angle)) - l2 = (20**2 + th2**2)**0.5 - - self.rectangularWall(30+x+2*t, y, callback=[self.bottomCB], move="right") - self.rectangularWall(l, y, callback=[ - lambda:self.fingerHolesAt(0, 4.5*t, l, 0), None, - lambda:self.fingerHolesAt(0, 4.5*t, l, 0), None], - move="right") - self.rectangularWall(l2, y, callback=[ - lambda:self.fingerHolesAt(0, 4.5*t, l2, 0), None, - lambda:self.fingerHolesAt(0, 4.5*t, l2, 0), None], - move="right") - - self.rectangularTriangle(x, th, "fef", num=2, move="up") - self.rectangularTriangle(20, th2, "fef", num=2, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/arcade.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/arcade.py deleted file mode 100644 index 37c6008..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/arcade.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Arcade(Boxes): - """Desktop Arcade Machine""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--width", action="store", type=float, default=450.0, - help="inner width of the console") - self.argparser.add_argument( - "--monitor_height", action="store", type=float, default=350.0, - help="inner width of the console") - self.argparser.add_argument( - "--keyboard_depth", action="store", type=float, default=150.0, - help="inner width of the console") - - def side(self, move=None): - # TODO: Add callbacks - - y, h = self.y, self.h - t = self.thickness - r = 10 - d_30 = 2* r * math.tan(math.radians(15)) - - tw, th = y+2*r+(self.front+t) * math.sin(math.radians(15)), h+2*r+(self.topback+t)/2**0.5 - if self.move(tw, th, move, True): - return - - self.moveTo(r+(self.front+t) * math.sin(math.radians(15)), 0) - - with self.saved_context(): - self.moveTo(0, r) - self.polyline(y, 90, h, 45, self.topback+t, 90, self.top+2*t, 90, 100, -90, self.monitor_height, -30, self.keyboard_depth+2*t, 90, self.front+t, 75) - - self.fingerHolesAt(10, r+t/2, self.bottom, 0) - self.polyline(y, (90, r)) - self.fingerHolesAt(0.5*t, r+t/2, self.back, 0) - self.fingerHolesAt(h-40-40, r+t/2, self.back, 0) - - self.polyline(h, (45, r)) - self.fingerHolesAt(0, r+t/2, self.topback, 0) - self.fingerHolesAt(self.topback+t/2, r+t, self.top, 90) - self.fingerHolesAt(self.topback, self.top+r+1.5*t, self.speaker, -180) - self.polyline(self.topback+t, (90, r), self.top+2*t, (90, r), 100-2*r, (-90, r), self.monitor_height-2*r-d_30, (-30, r)) - self.fingerHolesAt(-d_30+t, r+.5*t, self.keyboard_depth, 0) - self.fingerHolesAt(-d_30+0.5*t, r+t, self.keyback, 90) - self.fingerHolesAt(self.keyboard_depth-d_30+1.5*t, r+t, self.front, 90) - self.polyline(self.keyboard_depth-d_30+2*t, (90, r), self.front+t, (75, r)) - - self.move(tw, th, move) - - def keyboard(self): - # Add holes for the joystick and buttons here - pass - - def speakers(self): - self.hole(self.width/4., 50, 40) - self.hole(self.width*3/4., 50, 40) - - def render(self): - width = self.width - t = self.thickness - - self.back = 40 - self.front = 120 - self.keyback = 50 - self.speaker = 150 - self.top = 100 - self.topback = 200 - y, h = self.y, self.h = 540, 450 - y = self.y = ((self.topback+self.top+3*t-100+self.monitor_height) / 2**0.5 - + (self.keyboard_depth+2*t)*math.cos(math.radians(15)) - - (self.front+t) * math.sin(math.radians(15))) - h = self.h = ((self.monitor_height-self.topback+self.top+1*t+100) / 2**0.5 + - + (self.keyboard_depth+2*t)*math.sin(math.radians(15)) - + (self.front+t) * math.cos(math.radians(15))) - - self.bottom = y-40-0.5*t - self.backwall = h-40 - - # Floor - self.rectangularWall(width, self.bottom, "efff", move="up") - # Back - self.rectangularWall(width, self.back, "Ffef", move="up") - self.rectangularWall(width, self.backwall, move="up") - self.rectangularWall(width, self.back, "efef", move="up") - - # Front bottom - self.rectangularWall(width, self.front, "efff", move="up") - self.rectangularWall(width, self.keyboard_depth, "FfFf", callback=[self.keyboard], move="up") - self.rectangularWall(width, self.keyback, "ffef", move="up") - # Top - self.rectangularWall(width, self.speaker, "efff", callback=[None, None, self.speakers], move="up") - self.rectangularWall(width, self.top, "FfFf", move="up") - self.rectangularWall(width, self.topback, "ffef", move="up") - # Sides - self.side(move="up") - self.side(move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/atreus21.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/atreus21.py deleted file mode 100644 index eee3b5a..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/atreus21.py +++ /dev/null @@ -1,117 +0,0 @@ -"""Generator for a split atreus keyboard.""" - -from boxes import Boxes, restore - -from .keyboard import Keyboard - - -class Atreus21(Boxes, Keyboard): - """Generator for a split atreus keyboard.""" - ui_group = 'Misc' - btn_size = 15.6 - half_btn = btn_size / 2 - border = 6 - - def __init__(self) -> None: - super().__init__() - self.add_common_keyboard_parameters( - # By default, columns from Atreus 21 - default_columns_definition=f'4@3/4@6/4@11/4@5/4@0/1@{self.btn_size * 0.5}' - ) - - def render(self): - """Renders the keyboard.""" - - self.moveTo(10, 30) - case_x, case_y = self._case_x_y() - - margin = 2 * self.border + 1 - - for reverse in [False, True]: - # keyholder - self.outer() - self.half(reverse=reverse) - self.holes() - self.moveTo(case_x + margin) - - # support - self.outer() - self.half(self.support, reverse=reverse) - self.holes() - self.moveTo(-case_x - margin, case_y + margin) - - # hotplug - self.outer() - self.half(self.hotplug, reverse=reverse) - self.holes() - self.moveTo(case_x + margin) - - # border - self.outer() - self.rim() - self.holes() - self.moveTo(-case_x - margin, case_y + margin) - - def holes(self, diameter=3, margin=1.5): - case_x, case_y = self._case_x_y() - for x in [-margin, case_x + margin]: - for y in [-margin, case_y + margin]: - self.hole(x, y, d=diameter) - - def micro(self): - x = 17.9 - y = 33 - b = self.border - case_x, case_y = self._case_x_y() - self.rectangularHole( - x * -.5 + case_x + b * .5, - y * -.5 + case_y + b * .5, - x, y - ) - - @restore - def rim(self): - x, y = self._case_x_y() - self.moveTo(x * .5, y * .5) - self.rectangularHole(0, 0, x, y, 5) - - @restore - def outer(self): - x, y = self._case_x_y() - b = self.border - self.moveTo(0, -b) - corner = [90, b] - self.polyline(*([x, corner, y, corner] * 2)) - - @restore - def half(self, hole_cb=None, reverse=False): - if hole_cb is None: - hole_cb = self.key - self.moveTo(self.half_btn, self.half_btn) - self.apply_callback_on_columns( - hole_cb, - self.columns_definition, - reverse=reverse, - ) - - def support(self): - self.configured_plate_cutout(support=True) - - def hotplug(self): - self.pcb_holes( - with_hotswap=self.hotswap_enable, - with_pcb_mount=self.pcb_mount_enable, - with_diode=self.diode_enable, - with_led=self.led_enable, - ) - - def key(self): - self.configured_plate_cutout() - - # get case sizes - def _case_x_y(self): - spacing = Keyboard.STANDARD_KEY_SPACING - margin = spacing - self.btn_size - x = len(self.columns_definition) * spacing - margin - y = max(offset + keys * spacing for (offset, keys) in self.columns_definition) - margin - return x, y diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/basedbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/basedbox.py deleted file mode 100644 index 065a5f7..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/basedbox.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BasedBox(Boxes): - """Fully closed box on a base""" - - ui_group = "Box" - - description = """This box is more of a building block than a finished item. -Use a vector graphics program (like Inkscape) to add holes or adjust the base -plate. The width of the "brim" can also be adjusted with the **edge_width** - parameter in the **Finger Joints Settings**. - -See ClosedBox for variant without a base. -""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h", "outside") - - def render(self): - - x, y, h = self.x, self.y, self.h - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - - t = self.thickness - - self.rectangularWall(x, h, "fFFF", move="right", label="Wall 1") - self.rectangularWall(y, h, "ffFf", move="up", label="Wall 2") - self.rectangularWall(y, h, "ffFf", label="Wall 4") - self.rectangularWall(x, h, "fFFF", move="left up", label="Wall 3") - - self.rectangularWall(x, y, "ffff", move="right", label="Top") - self.rectangularWall(x, y, "hhhh", label="Base") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bayonetbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bayonetbox.py deleted file mode 100644 index 136178e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bayonetbox.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BayonetBox(Boxes): - """Round box made from layers with twist on top""" - - description = """Glue together - all outside rings to the bottom, all inside rings to the top.""" - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.argparser.add_argument( - "--diameter", action="store", type=float, default=50., - help="Diameter of the box in mm") - self.argparser.add_argument( - "--lugs", action="store", type=int, default=10, - help="number of locking lugs") - self.argparser.add_argument( - "--alignment_pins", action="store", type=float, default=1.0, - help="diameter of the alignment pins") - self.buildArgParser("outside") - - def alignmentHoles(self, inner=False, outer=False): - d = self.diameter - r = d / 2 - t = self.thickness - p = 0.05*t - l = self.lugs - - a = 180 / l - with self.saved_context(): - for i in range(3): - if outer: - self.hole(r-t/2, 0, d=self.alignment_pins) - if inner: - self.hole(r-2*t-p, 0, d=self.alignment_pins) - self.moveTo(0, 0, 360/3) - - def lowerLayer(self, asPart=False, move=None): - d = self.diameter - r = d / 2 - t = self.thickness - p = 0.05*t - l = self.lugs - - a = 180 / l - - if asPart: - if self.move(d, d, move, True): - return - self.moveTo(d/2, d/2) - - self.alignmentHoles(inner=True) - self.hole(0, 0, r=d/2 - 2.5*t) - self.moveTo(d/2 - 1.5*t, 0, -90) - - for i in range(l): - self.polyline(0, (-4/3*a, r-1.5*t), 0, 90, 0.5*t, -90, 0, (-2/3*a, r-t), 0, -90, 0.5*t, 90) - - if asPart: - self.move(d, d, move) - - def lowerCB(self): - d = self.diameter - r = d / 2 - t = self.thickness - p = 0.05*t - l = self.lugs - - a = 180 / l - - self.alignmentHoles(outer=True) - with self.saved_context(): - self.lowerLayer() - - self.moveTo(d/2 - 1.5*t+p, 0, -90) - for i in range(l): - self.polyline(0, (-2/3*a, r-1.5*t+p), 0, 90, 0.5*t, -90, 0, (-4/3*a, r-t+p), 0, -90, 0.5*t, 90) - - - def upperCB(self): - d = self.diameter - r = d / 2 - t = self.thickness - p = 0.05*t - l = self.lugs - - a = 180 / l - - self.hole(0, 0, r=d/2 - 2.5*t) - self.hole(0, 0, r=d/2 - 1.5*t) - self.alignmentHoles(inner=True, outer=True) - self.moveTo(d/2 - 1.5*t, 0, -90) - - for i in range(l): - self.polyline(0, (-1.3*a, r-1.5*t+p), 0, 90, 0.5*t, -90, 0, (-0.7*a, r-t+p), 0, -90, 0.5*t, 90) - - - def render(self): - d = self.diameter - t = self.thickness - p = 0.05*t - - if not self.outside: - self.diameter = d = d - 3*t - - - self.parts.disc(d, callback=lambda: self.alignmentHoles(outer=True), move="right") - self.parts.disc(d, callback=lambda: (self.alignmentHoles(outer=True), self.hole(0, 0, d/2-1.5*t)), move="right") - self.parts.disc(d, callback=self.lowerCB, move="right") - self.parts.disc(d, callback=self.upperCB, move="right") - self.parts.disc(d, callback=lambda : self.alignmentHoles(inner=True),move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bintray.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bintray.py deleted file mode 100644 index f872be3..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bintray.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BinFrontEdge(edges.BaseEdge): - char = "B" - def __call__(self, length, **kw): - f = self.settings.front - a1 = math.degrees(math.atan(f/(1-f))) - a2 = 45 + a1 - self.corner(-a1) - for i, l in enumerate(self.settings.sy): - self.edges["e"](l* (f**2+(1-f)**2)**0.5) - self.corner(a2) - self.edges["f"](l*f*2**0.5) - if i < len(self.settings.sy)-1: - if self.char == "B": - self.polyline(0, 45, 0.5*self.settings.hi, - -90, self.thickness, -90, 0.5*self.settings.hi, 90-a1) - else: - self.polyline(0, -45, self.thickness, -a1) - else: - self.corner(-45) - - def margin(self) -> float: - return max(self.settings.sy) * self.settings.front - -class BinFrontSideEdge(BinFrontEdge): - char = 'b' - -class BinTray(Boxes): - """A Type tray variant to be used up right with sloped walls in front""" - - ui_group = "Shelf" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("sx", "sy", "h", "outside", "hole_dD") - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0.5) - self.argparser.add_argument( - "--front", action="store", type=float, default=0.4, - help="fraction of bin height covered with slope") - - def xSlots(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - posy = 0 - for y in self.sy: - self.fingerHolesAt(posx, posy, y) - posy += y + self.thickness - - def ySlots(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - posx = 0 - for x in self.sx: - self.fingerHolesAt(posy, posx, x) - posx += x + self.thickness - - def addMount(self): - ds = self.hole_dD[0] - - if len(self.hole_dD) < 2: # if no head diameter is given - dh = 0 # only a round hole is generated - y = max (self.thickness * 1.25, self.thickness * 1.0 + ds) # and we assume that a typical screw head diameter is twice the shaft diameter - else: - dh = self.hole_dD[1] # use given head diameter - y = max (self.thickness * 1.25, self.thickness * 1.0 + dh / 2) # and offset the hole to have enough space for the head - - dx = sum(self.sx) + self.thickness * (len(self.sx) - 1) - x1 = dx * 0.125 - x2 = dx * 0.875 - - self.mountingHole(x1, y, ds, dh, -90) - self.mountingHole(x2, y, ds, dh, -90) - - def xHoles(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, self.hi) - - def frontHoles(self, i): - def CB(): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, self.sy[i]*self.front*2**0.5) - return CB - - def yHoles(self): - posy = -0.5 * self.thickness - for y in reversed(self.sy[1:]): - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.hi) - - def render(self): - if self.outside: - self.sx = self.adjustSize(self.sx) - self.sy = self.adjustSize(self.sy) - self.h = self.adjustSize(self.h, e2=False) - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - y = sum(self.sy) + self.thickness * (len(self.sy) - 1) - - h = self.h - hi = self.hi = h - t = self.thickness - self.front = min(self.front, 0.999) - - self.addPart(BinFrontEdge(self, self)) - self.addPart(BinFrontSideEdge(self, self)) - - angledsettings = copy.deepcopy(self.edges["f"].settings) - angledsettings.setValues(self.thickness, True, angle=45) - angledsettings.edgeObjects(self, chars="gGH") - - # outer walls - e = ["F", "f", edges.SlottedEdge(self, self.sx[::-1], "G"), "f"] - - self.rectangularWall(x, h, e, callback=[self.xHoles], move="right", label="bottom") - self.rectangularWall(y, h, "FFbF", callback=[self.yHoles, ], move="up", label="left") - self.rectangularWall(y, h, "FFbF", callback=[self.yHoles, ], label="right") - self.rectangularWall(x, h, "Ffef", callback=[self.xHoles, ], move="left", label="top") - self.rectangularWall(y, h, "FFBF", move="up only") - - # floor - self.rectangularWall(x, y, "ffff", callback=[self.xSlots, self.ySlots, self.addMount], move="right", label="back") - # Inner walls - for i in range(len(self.sx) - 1): - e = [edges.SlottedEdge(self, self.sy, "f"), "f", "B", "f"] - self.rectangularWall(y, hi, e, move="up", label="inner vertical " + str(i+1)) - - for i in range(len(self.sy) - 1): - e = [edges.SlottedEdge(self, self.sx, "f", slots=0.5 * hi), "f", - edges.SlottedEdge(self, self.sx[::-1], "G"), "f"] - self.rectangularWall(x, hi, e, move="up", label="inner horizontal " + str(i+1)) - - # Front walls - for i in range(len(self.sy)): - e = [edges.SlottedEdge(self, self.sx, "g"), "F", "e", "F"] - self.rectangularWall(x, self.sy[i]*self.front*2**0.5, e, callback=[self.frontHoles(i)], move="up", label="retainer " + str(i+1)) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/birdhouse.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/birdhouse.py deleted file mode 100644 index e363822..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/birdhouse.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2013-2022 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BirdHouse(Boxes): - """Simple Bird House""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=10.0,space=10.0) - self.buildArgParser(x=200, y=200, h=200) - self.argparser.add_argument( - "--roof_overhang", action="store", type=float, default=0.4, - help="overhang as fraction of the roof length") - - def side(self, x, h, edges="hfeffef", callback=None, move=None): - angles = (90, 0, 45, 90, 45, 0, 90) - roof = 2**0.5 * x / 2 - t = self.thickness - lengths = (x, h, t, roof, roof, t, h) - - edges = [self.edges.get(e, e) for e in edges] - edges.append(edges[0]) # wrap around - - tw = x + edges[1].spacing() + edges[-2].spacing() - th = h + x/2 + t + edges[0].spacing() + max(edges[3].spacing(), edges[4].spacing()) - - if self.move(tw, th, move, True): - return - - self.moveTo(edges[-2].spacing()) - for i in range(7): - self.cc(callback, i, y=self.burn+edges[i].startwidth()) - edges[i](lengths[i]) - self.edgeCorner(edges[i], edges[i+1], angles[i]) - - self.move(tw, th, move) - - def roof(self, x, h, overhang, edges="eefe", move=None): - t = self.thickness - edges = [self.edges.get(e, e) for e in edges] - - tw = x + 2*t + 2*overhang + edges[1].spacing() + edges[3].spacing() - th = h + 2*t + overhang + edges[0].spacing() + edges[2].spacing() - - if self.move(tw, th, move, True): - return - - self.moveTo(overhang + edges[3].spacing(), edges[0].margin()) - edges[0](x + 2*t) - self.corner(90, overhang) - edges[1](h + 2*t) - self.edgeCorner(edges[1], edges[2]) - self.fingerHolesAt(overhang + 0.5*t, edges[2].startwidth(), h, 90) - self.fingerHolesAt(x + overhang + 1.5*t, edges[2].startwidth(), h, 90) - edges[2](x + 2*t + 2*overhang) - self.edgeCorner(edges[2], edges[3]) - edges[3](h + 2*t) - self.corner(90, overhang) - - self.move(tw, th, move) - - def side_hole(self, width): - self.rectangularHole(width/2, self.h/2, - 0.75*width, 0.75*self.h, - r=self.thickness) - - def render(self): - x, y, h = self.x, self.y, self.h - - roof = 2**0.5 * x / 2 - overhang = roof * self.roof_overhang - - cbx = [lambda: self.side_hole(x)] - cby = [lambda: self.side_hole(y)] - - self.side(x, h, callback=cbx, move="right") - self.side(x, h, callback=cbx, move="right") - self.rectangularWall(y, h, "hFeF", callback=cby, move="right") - self.rectangularWall(y, h, "hFeF", callback=cby, move="right") - self.rectangularWall(x, y, "ffff", move="right") - self.edges["h"].settings.setValues(self.thickness, relative=False, edge_width=overhang) - self.roof(y, roof, overhang, "eefe", move="right") - self.roof(y, roof, overhang, "eeFe", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bottlestack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bottlestack.py deleted file mode 100644 index fb96e6f..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bottlestack.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (C) 2013-2020 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BottleStack(Boxes): - """Stack bottles in a fridge""" - - description = """When rendered with the "double" option the parts with the double slots get connected the shorter beams in the asymmetrical slots. - -Without the "double" option the stand is a bit more narrow. -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.argparser.add_argument( - "--diameter", action="store", type=float, default=80, - help="diameter of the bottles in mm") - self.argparser.add_argument( - "--number", action="store", type=int, default=3, - help="number of bottles to hold in the bottom row") - self.argparser.add_argument( - "--depth", action="store", type=float, default=80, - help="depth of the stand along the base of the bottles") - self.argparser.add_argument( - "--double", action="store", type=boolarg, default=True, - help="two pieces that can be combined to up to double the width") - - - - def front(self, h_sides, offset=0, move=None): - t = self.thickness - a = 60 - nr = self.number - r1 = self.diameter / 2.0 # bottle - r2 = r1 / math.cos(math.radians(90-a)) - r1 # in between - if self.double: - r3 = 1.5*t # upper corners - else: - r3 = .5*t - h = (r1+r2) * (1-math.cos(math.radians(a))) - h_extra = 1*t - h_s = h_sides - t - p = 0.05*t # play - - tw, th = nr * r1 * 2 + 2*r3, h + 2*t - - - if self.move(tw, th, move, True): - return - - open_sides = r3 <= 0.5*t - - if offset == 0: - slot = [0, 90, h_s, -90, t, -90, h_s, 90] - if open_sides: - self.moveTo(0, h_s) - self.polyline(r3-0.5*t) - self.polyline(*slot[4:]) - else: - self.polyline(r3-0.5*t) - self.polyline(*slot) - for i in range(nr-open_sides): - self.polyline(2*r1-t) - self.polyline(*slot) - if open_sides: - self.polyline(2*r1-t) - self.polyline(*slot[:-3]) - self.polyline(r3-0.5*t) - else: - self.polyline(r3-0.5*t) - else: - slot = [0, 90, h_s, -90, t, -90, h_s, 90] - h_s += t - slot2 = [0, 90, h_s, -90, t+2*p, -90, h_s, 90] - if open_sides: - self.moveTo(0, h_s) - self.polyline(t+p, -90, h_s, 90) - else: - self.polyline(r3-0.5*t-p) - self.polyline(*slot2) - self.polyline(t-p) - self.polyline(*slot) - self.polyline(2*r1-5*t) - self.polyline(*slot) - self.polyline(t-p) - self.polyline(*slot2) - for i in range(1, nr-open_sides): - self.polyline(2*r1-3*t-p) - self.polyline(*slot) - self.polyline(t-p) - self.polyline(*slot2) - if open_sides: - self.polyline(2*r1-3*t-p) - self.polyline(*slot) - self.polyline(t-p) - self.polyline(0, 90, h_s, -90, t+p) - else: - self.polyline(r3-0.5*t-p) - - if open_sides: - h_extra -= h_s - - self.polyline(0, 90, h_extra+h-r3, (90, r3)) - - for i in range(nr): - self.polyline(0, (a, r2), 0, (-2*a, r1), 0, (a, r2)) - self.polyline(0, (90, r3), h_extra+h-r3, 90) - - self.move(tw, th, move) - - def side(self, l, h, short=False, move=None): - t = self.thickness - short = bool(short) - - tw, th = l + 2*t - 4*t*short, h - - if self.move(tw, th, move, True): - return - - self.moveTo(t, 0) - - self.polyline(l-3*t*short) - if short: - end = [90, h-t, 90, t, -90, t, 90] - else: - end = [(90, t), h-2*t, (90, t), 0, 90, t, -90, t, -90, t, 90] - self.polyline(0, *end) - self.polyline(l-2*t- 3*t*short) - self.polyline(0, *reversed(end)) - - self.move(tw, th, move) - - def render(self): - t = self.thickness - d = self.depth - nr = self.number - h_sides = 2*t - pieces = 2 if self.double else 1 - - for offset in range(pieces): - self.front(h_sides, offset, move="up") - self.front(h_sides, offset, move="up") - - for short in range(pieces): - for i in range(nr+1): - self.side(d, h_sides, short, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bottletag.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bottletag.py deleted file mode 100644 index 5d6a704..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/bottletag.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BottleTag(Boxes): - """Paper slip over bottle tag""" - - ui_group = "Misc" # see ./__init__.py for names - - def __init__(self) -> None: - Boxes.__init__(self) - - self.buildArgParser() - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--width", action="store", type=float, default=72, - help="width of neck tag") - self.argparser.add_argument( - "--height", action="store", type=float, default=98, - help="height of neck tag") - self.argparser.add_argument( - "--min_diameter", action="store", type=float, default=24, - help="inner diameter of bottle neck hole") - self.argparser.add_argument( - "--max_diameter", action="store", type=float, default=50, - help="outer diameter of bottle neck hole") - self.argparser.add_argument( - "--radius", action="store", type=float, default=15, - help="corner radius of bottom tag") - self.argparser.add_argument( - "--segment_width", action="store", type=int, default=3, - help="inner segment width") - - def render(self): - # adjust to the variables you want in the local scope - width = self.width - height = self.height - r_min = self.min_diameter / 2 - r_max = self.max_diameter / 2 - r = self.radius - segment_width = self.segment_width - - # tag outline - self.moveTo(r) - self.edge(width - r - r) - self.corner(90, r) - self.edge(height - width / 2.0 - r) - self.corner(180, width / 2) - self.edge(height - width / 2.0 - r) - self.corner(90, r) - - # move to centre of hole and cut the inner circle - self.moveTo(width / 2 - r, height - width / 2) - with self.saved_context(): - self.moveTo(0, -r_min) - self.corner(360, r_min) - - # draw the radial lines approx 2mm apart on r_min - seg_angle = math.degrees(segment_width / r_min) - # for neatness, we want an integral number of cuts - num = math.floor(360 / seg_angle) - for i in range(num): - with self.saved_context(): - self.moveTo(0, 0, i * 360.0 / num) - self.moveTo(r_min) - self.edge(r_max - r_min) - # Add some right angle components to reduce tearing - with self.saved_context(): - self.moveTo(0, 0, 90) - self.edge(0.5) - with self.saved_context(): - self.moveTo(0, 0, -90) - self.edge(0.5) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/breadbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/breadbox.py deleted file mode 100644 index 492f02c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/breadbox.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright (C) 2013-2022 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class BreadBox(Boxes): - """A BreadBox with a gliding door""" - - ui_group = "FlexBox" - - description = """Beware of the rolling shutter effect! Use wax on sliding surfaces. -""" - - def side(self, l, h, r, move=None): - t = self.thickness - - if self.move(l+2*t, h+2*t, move, True): - return - - self.moveTo(t, t) - - self.ctx.save() - - n = self.n - a = 90. / n - ls = 2*math.sin(math.radians(a/2)) * (r-2.5*t) - - self.fingerHolesAt(2*t, 0, h-r, 90) - self.moveTo(2.5*t, h-r, 90-a/2) - for i in range(n): - self.fingerHolesAt(0, 0.5*t, ls, 0) - self.moveTo(ls, 0, -a) - self.moveTo(0, 0, a/2) - self.fingerHolesAt(0, 0.5*t, l / 2 - r, 0) - self.ctx.restore() - - self.edges["f"](l) - self.polyline(t, 90, h-r, (90, r+t), l/2-r, 90, t, -90, 0,) - self.edges["f"](l/2) - self.polyline(0, 90) - self.edges["f"](h) - - self.move(l+2*t, h+2*t, move) - - def cornerRadius(self, r, two=False, move=None): - s = self.spacing - if self.move(r, r+s, move, True): - return - for i in range(2 if two else 1): - self.polyline(r, 90, r, 180, 0, (-90, r), 0 ,-180) - self.moveTo(r, r+s, 180) - self.move(r, r+s, move) - - def rails(self, l, h, r, move=None): - t = self.thickness - s = self.spacing - tw, th = l/2+2.5*t+3*s, h+1.5*t+3*s - - if self.move(tw, th, move, True): - return - - self.moveTo(2.5*t+s, 0) - self.polyline(l/2-r, (90, r+t), h-r, 90, t, 90, h-r, (-90, r), l/2-r, 90, t, 90) - self.moveTo(-t-s, t+s) - self.polyline(l/2-r, (90, r+t), h-r, 90, t, 90, h-r, (-90, r), l/2-r, 90, t, 90) - self.moveTo(+t-s, t+s) - self.polyline(l/2-r, (90, r-1.5*t), h-r, 90, t, 90, h-r, (-90, r-2.5*t), l/2-r, 90, t, 90) - self.moveTo(-t-s, t+s) - self.polyline(l/2-r, (90, r-1.5*t), h-r, 90, t, 90, h-r, (-90, r-2.5*t), l/2-r, 90, t, 90) - - self.move(tw, th, move) - - def door(self, l, h, move=None): - t = self.thickness - if self.move(l, h, move, True): - return - self.fingerHolesAt(t, t, h-2*t) - self.edge(2*t) - self.edges["X"](l-2*t, h) - self.polyline(0, 90, h, 90, l, 90, h, 90) - self.move(l, h, move) - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0.5) - self.addSettingsArgs(edges.FlexSettings, distance=.75, connection=2.) - - self.buildArgParser(x=150, y=100, h=100) - self.argparser.add_argument( - "--radius", action="store", type=float, default=40.0, - help="radius of the corners") - - def render(self): - x, y, h, r = self.x, self.y, self.h, self.radius - self.n = n = 3 - - if not r: - self.radius = r = h / 2 - self.radius = r = min(r, h/2) - - t = self.thickness - self.ctx.save() - self.side(x, h, r, move="right") - self.side(x, h, r, move="right") - self.rectangularWall(y, h, "fFfF", move="right") - - self.ctx.restore() - self.side(x, h, r, move="up only") - - self.rectangularWall(x, y, "FEFF", move="right") - self.rectangularWall(x/2, y, "FeFF", move="right") - - self.door(x/2 + h - 2*r + 0.5*math.pi*r + 2*t, y-0.2*t, move="right") - - self.rectangularWall(2*t, y-2.2*t, edges="eeef", move="right") - - - a = 90. / n - ls = 2*math.sin(math.radians(a/2)) * (r-2.5*t) - - edges.FingerJointSettings(t, angle=a).edgeObjects(self, chars="aA") - edges.FingerJointSettings(t, angle=a/2).edgeObjects(self, chars="bB") - - - self.rectangularWall(h-r, y, "fbfe", move="right") - - self.rectangularWall(ls, y, "fafB", move="right") - - for i in range(n-2): - self.rectangularWall(ls, y, "fafA", move="right") - - self.rectangularWall(ls, y, "fbfA", move="right") - self.rectangularWall(x/2 - r, y, "fefB", move="right") - - self.rails(x, h, r, move="right mirror") - self.cornerRadius(r, two=True, move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/burntest.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/burntest.py deleted file mode 100644 index b291f3d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/burntest.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# Copyright (C) 2024 Seth Fischer -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from datetime import date - -from boxes import * - - -class BurnTest(Boxes): - """Test different burn values""" - - description = """This generator will make shapes that you can use to select -optimal value for burn parameter for other generators. After burning try to -attach sides with the same value and use best fitting one on real projects. -In this generator set burn in the Default Settings to the lowest value -to be tested. To get an idea cut a rectangle with known nominal size and -measure the shrinkage due to the width of the laser cut. Now you can -measure the burn value that you should use in other generators. It is half -the difference of the overall size as shrinkage is occurring on both -sides. You can use the reference rectangle as it is rendered without burn -correction. - -See also LBeam that can serve as compact BurnTest and FlexTest for testing flex settings. -""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser(x=100) - self.argparser.add_argument( - "--step", - action="store", - type=float, - default=0.01, - help="increases in burn value between the sides", - ) - self.argparser.add_argument( - "--pairs", - action="store", - type=int, - default=2, - help="number of pairs (each testing four burn values)", - ) - self.argparser.add_argument( - "--date", - action="store", - type=boolarg, - default=False, - help="add current date etching to each piece", - ) - self.argparser.add_argument( - "--id", - action="store", - type=str, - default="", - help="add identifier etching to each piece", - ) - - def render(self): - font = { - "fontsize": 12.5 * self.x / 100 if self.x < 81 else 10, - "align": "center", - "color": Color.ETCHING, - } - font_meta = font.copy() - font_meta["fontsize"] = font["fontsize"] * 0.75 - - today = date.today().strftime("%Y-%m-%d") - - x, s = self.x, self.step - t = self.thickness - - self.moveTo(t, t) - - for cnt in range(self.pairs): - for i in range(4): - self.text("%.3fmm" % self.burn, x / 2, t, **font) - if self.date and i == 3: - self.text(today, x / 2, 20, **font_meta) - if self.id and i == 1: - self.text(self.id, x / 2, 20, **font_meta) - self.edges["f"](x) - self.corner(90) - self.burn += s - - self.burn -= 4 * s - self.moveTo(x + 2 * t + self.spacing, -t) - - for i in range(4): - self.text("%.3fmm" % self.burn, x / 2, t, **font) - if self.date and i == 3: - self.text(today, x / 2, 20, **font_meta) - if self.id and i == 1: - self.text(self.id, x / 2, 20, **font_meta) - self.edges["F"](x) - self.polyline(t, 90, t) - self.burn += s - - self.moveTo(x + 2 * t + self.spacing, t) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/can_storage.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/can_storage.py deleted file mode 100644 index 1c19aa1..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/can_storage.py +++ /dev/null @@ -1,365 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FrontEdge(edges.BaseEdge): - char = "a" - - def __call__(self, length, **kw): - x = math.ceil( ((self.canDiameter * 0.5 + 2 * self.thickness) * math.sin(math.radians(self.chuteAngle))) / self.thickness) - if self.top_edge != "e": - self.corner(90, self.thickness) - self.edge(0.5 * self.canDiameter) - self.corner(-90, 0.25 * self.canDiameter) - else: - self.moveTo(-self.burn, self.canDiameter + self.thickness, -90) - self.corner(90, 0.25 * self.canDiameter) - self.edge(self.thickness) - - self.edge(0.5 * self.canDiameter - self.thickness) - self.corner(-90, 0.25 * self.canDiameter) - self.edge(0.5 * self.canDiameter) - self.corner(90, self.thickness) - self.edge(x * self.thickness ) - self.corner(90, self.thickness) - self.edge(0.5 * self.canDiameter) - self.corner(-90, 0.25 * self.canDiameter) - self.edge(0.5 * self.canDiameter - (1 + x) * self.thickness + self.top_chute_height + self.bottom_chute_height - self.barrier_height) - self.corner(-90, 0.25 * self.canDiameter) - self.edge(0.5 * self.canDiameter) - self.corner(90, self.thickness) - self.edge(self.barrier_height) - self.edge(self.thickness) - -class TopChuteEdge(edges.BaseEdge): - char = "b" - - def __call__(self, length, **kw): - self.edge(0.2 * length - self.thickness) - self.corner(90, self.thickness) - self.edge(1.5*self.canDiameter - 2 * self.thickness) - self.corner(-90, self.thickness) - self.edge(0.6 * length - 2 * self.thickness) - self.corner(-90, self.thickness) - self.edge(1.5*self.canDiameter - 2 * self.thickness) - self.corner(90, self.thickness) - self.edge(0.2 * length - self.thickness) - -class BarrierEdge(edges.BaseEdge): - char = "A" - - def __call__(self, length, **kw): - self.edge(0.2*length) - self.corner(90,self.thickness/2) - self.corner(-90,self.thickness/2) - self.edge(0.6*length-2*self.thickness) - self.corner(-90,self.thickness/2) - self.corner(90,self.thickness/2) - self.edge(0.2*length) - - def startwidth(self) -> float: - return self.boxes.thickness - -class CanStorage(Boxes): - """Storage box for round containers""" - - description = """ -for AA batteries: - -![CanStorage for AA batteries](static/samples/CanStorageAA.jpg) - -for canned tomatoes: -""" - - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=2.0, space=2.0, surroundingspaces=0.0) - self.addSettingsArgs(edges.StackableSettings) - self.addSettingsArgs(fillHolesSettings) - - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("efhŠ"), choices=list("efhŠ"), - default="Š", help="edge type for top edge") - self.argparser.add_argument( - "--bottom_edge", action="store", - type=ArgparseEdgeType("eEš"), choices=list("eEš"), - default="š", help="edge type for bottom edge") - - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--canDiameter", action="store", type=float, default=75, - help="outer diameter of the cans to be stored (in mm)") - self.argparser.add_argument( - "--canHeight", action="store", type=float, default=110, - help="height of the cans to be stored (in mm)") - self.argparser.add_argument( - "--canNum", action="store", type=int, default=12, - help="number of cans to be stored") - self.argparser.add_argument( - "--chuteAngle", action="store", type=float, default=5.0, - help="slope angle of the chutes") - - def DrawPusher(self, dbg = False): - with self.saved_context(): - if dbg == False: - self.moveTo(0,self.thickness) - self.edge(0.25*self.pusherA) - self.corner(-90) - self.edge(self.thickness) - self.corner(90) - self.edge(0.5*self.pusherA) - self.corner(90) - self.edge(self.thickness) - self.corner(-90) - self.edge(0.25*self.pusherA) - - self.corner(90-self.chuteAngle) - - self.edge(0.25*self.pusherB) - self.corner(-90) - self.edge(self.thickness) - self.corner(90) - self.edge(0.5*self.pusherB) - self.corner(90) - self.edge(self.thickness) - self.corner(-90) - self.edge(0.25*self.pusherB) - - self.corner(90+self.pusherAngle+self.chuteAngle) - self.edge(self.pusherC) - - def cb_top_chute(self, nr): - if nr == 0: - # fill with holes - border = [ - (0, 0), - (self.top_chute_depth, 0), - (self.top_chute_depth, 0.2 * self.width - self.thickness), - (self.top_chute_depth - self.thickness, 0.2 * self.width), - (self.top_chute_depth - 1.5*self.canDiameter, 0.2 * self.width), - (self.top_chute_depth - 1.5*self.canDiameter, 0.8 * self.width), - (self.top_chute_depth - self.thickness, 0.8 * self.width), - (self.top_chute_depth, 0.8 * self.width + self.thickness), - (self.top_chute_depth, self.width), - (0, self.width), - ] - - if self.fillHoles_fill_pattern != "no fill": - self.fillHoles( - pattern="hbar", - border=border, - max_radius = min(2*self.thickness, self.fillHoles_hole_max_radius) if self.fillHoles_fill_pattern in ["hbar", "vbar"] else min(2*self.thickness, self.width/30), - hspace=min(2*self.thickness, self.fillHoles_space_between_holes) if self.fillHoles_fill_pattern in ["hbar", "vbar"] else min(2*self.thickness, self.width/20), - bspace=min(2*self.thickness, self.fillHoles_space_to_border) if self.fillHoles_fill_pattern in ["hbar", "vbar"] else min(2*self.thickness, self.width/20), - bar_length=self.fillHoles_bar_length, - max_random=self.fillHoles_max_random, - ) - - def cb_top(self, nr): - if nr == 0: - # fill with holes - border = [ - (0, 0), - (self.depth, 0), - (self.depth, self.width), - (0, self.width), - ] - - if self.fillHoles_fill_pattern != "no fill": - self.fillHoles( - pattern="hbar", - border=border, - max_radius = min(2*self.thickness, self.fillHoles_hole_max_radius) if self.fillHoles_fill_pattern in ["hbar", "vbar"] else min(2*self.thickness, self.width/30), - hspace=min(2*self.thickness, self.fillHoles_space_between_holes) if self.fillHoles_fill_pattern in ["hbar", "vbar"] else min(2*self.thickness, self.width/20), - bspace=min(2*self.thickness, self.fillHoles_space_to_border) if self.fillHoles_fill_pattern in ["hbar", "vbar"] else min(2*self.thickness, self.width/20), - bar_length=self.fillHoles_bar_length, - max_random=self.fillHoles_max_random, - ) - - def cb_bottom_chute(self, nr): - if nr == 1: - # holes for pusher - self.rectangularHole(self.width*0.85-0.5*self.thickness, 0.25*self.pusherA, self.thickness, 0.5*self.pusherA, center_x=False, center_y=False) - self.rectangularHole(self.width*0.5 -0.5*self.thickness, 0.25*self.pusherA, self.thickness, 0.5*self.pusherA, center_x=False, center_y=False) - self.rectangularHole(self.width*0.15-0.5*self.thickness, 0.25*self.pusherA, self.thickness, 0.5*self.pusherA, center_x=False, center_y=False) - - - def cb_back(self, nr): - if nr == 1: - # holes for pusher - self.rectangularHole(self.width*0.85-0.5*self.thickness, self.thickness + self.depth * math.tan(math.radians(self.chuteAngle)) + 0.25*self.pusherB, self.thickness, 0.5*self.pusherB + self.thickness, center_x=False, center_y=False) - self.rectangularHole(self.width*0.5 -0.5*self.thickness, self.thickness + self.depth * math.tan(math.radians(self.chuteAngle)) + 0.25*self.pusherB, self.thickness, 0.5*self.pusherB + self.thickness, center_x=False, center_y=False) - self.rectangularHole(self.width*0.15-0.5*self.thickness, self.thickness + self.depth * math.tan(math.radians(self.chuteAngle)) + 0.25*self.pusherB, self.thickness, 0.5*self.pusherB + self.thickness, center_x=False, center_y=False) - - - def cb_sides(self, nr): - if nr == 0: - # for debugging only - if self.debug: - # draw orientation points - self.hole(0, 0, 1, color=Color.ANNOTATIONS) - self.hole(0, self.thickness, 1, color=Color.ANNOTATIONS) - self.hole(0, self.thickness + self.canDiameter, 1, color=Color.ANNOTATIONS) - self.hole(0, self.thickness + self.canDiameter + self.bottom_chute_height, 1, color=Color.ANNOTATIONS) - self.hole(0, self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + self.thickness, 1, color=Color.ANNOTATIONS) - self.hole(0, self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + self.thickness + self.canDiameter, 1, color=Color.ANNOTATIONS) - self.hole(0, self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + self.thickness + self.canDiameter + 1.0 * self.thickness, 1, color=Color.ANNOTATIONS) - with self.saved_context(): - # draw cans, bottom row - self.moveTo(0, self.thickness, self.chuteAngle) - self.rectangularHole(2*self.thickness, 0, math.ceil(self.canNum / 2) * self.canDiameter, self.canDiameter, center_x=False, center_y=False, color=Color.ANNOTATIONS) - for i in range(math.ceil(self.canNum / 2)-1): - self.hole(2*self.thickness+(0.5 + i) * self.canDiameter, self.canDiameter / 2, self.canDiameter / 2, color=Color.ANNOTATIONS) - i+=1 - self.hole(2*self.thickness+(0.5 + i) * self.canDiameter, self.canDiameter*0.8 , self.canDiameter / 2, color=Color.ANNOTATIONS) - - with self.saved_context(): - # draw pusher - self.moveTo(self.depth-self.pusherA, self.thickness + (self.depth-self.pusherA) * math.tan(math.radians(self.chuteAngle))) - self.moveTo(0,0,self.chuteAngle) - self.DrawPusher(True) - - with self.saved_context(): - # draw cans, top row - self.moveTo(0, self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + 0.5 * self.thickness, -self.chuteAngle) - self.rectangularHole(0, 0.5 * self.thickness, math.ceil(self.canNum / 2) * self.canDiameter, self.canDiameter, center_x=False, center_y=False, color=Color.ANNOTATIONS) - for i in range(math.ceil(self.canNum / 2)): - self.hole((0.5 + i) * self.canDiameter, self.canDiameter / 2 + 0.5 * self.thickness, self.canDiameter / 2, color=Color.ANNOTATIONS) - with self.saved_context(): - # draw barrier - self.moveTo(1.5 * self.thickness, 1.1 * self.thickness + self.burn + math.sin(math.radians(self.chuteAngle)) * 2 * self.thickness, 90) - self.rectangularHole(0, 0, self.barrier_height, self.thickness, center_x=False, center_y=True, color=Color.ANNOTATIONS) - - # bottom chute - with self.saved_context(): - self.moveTo(0, 0.5 * self.thickness, self.chuteAngle) - self.fingerHolesAt(0, 0, self.depth / math.cos(math.radians(self.chuteAngle)), 0) - # top chute - with self.saved_context(): - self.moveTo(0, self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + 0.5 * self.thickness, -self.chuteAngle) - self.fingerHolesAt(0, 0, self.top_chute_depth, 0) - # front barrier - with self.saved_context(): - self.moveTo(1.5 * self.thickness, 1.1 * self.thickness + self.burn + math.sin(math.radians(self.chuteAngle)) * 2 * self.thickness, 90) - self.fingerHolesAt(0, 0, self.barrier_height, 0) - # fill with holes - border = [ - (2*self.thickness, 0.5*self.thickness + 2*self.thickness * math.tan(math.radians(self.chuteAngle)) + 0.5*self.thickness/math.cos(math.radians(self.chuteAngle))), - (self.depth, self.thickness + self.depth * math.tan(math.radians(self.chuteAngle))), - (self.depth, self.height), - (self.thickness + 0.75 * self.canDiameter, self.height), - (self.thickness + 0.75 * self.canDiameter, 0.5*self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + self.thickness - (self.thickness + 0.75 * self.canDiameter) * math.tan(math.radians(self.chuteAngle)) + 0.5*self.thickness/math.cos(math.radians(self.chuteAngle))), - (self.top_chute_depth * math.cos(math.radians(self.chuteAngle)), self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + self.thickness - (self.top_chute_depth) * math.sin(math.radians(self.chuteAngle))), - (self.top_chute_depth * math.cos(math.radians(self.chuteAngle)), self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height - (self.top_chute_depth) * math.sin(math.radians(self.chuteAngle))), - (self.thickness + 0.75 * self.canDiameter, 1.5*self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height - (self.thickness + 0.75 * self.canDiameter) * math.tan(math.radians(self.chuteAngle)) - 0.5*self.thickness/math.cos(math.radians(self.chuteAngle))), - (self.thickness + 0.75 * self.canDiameter, 2*self.thickness + self.barrier_height ), - (2*self.thickness, 2*self.thickness + self.barrier_height), - ] - - self.fillHoles( - pattern=self.fillHoles_fill_pattern, - border=border, - max_radius=self.fillHoles_hole_max_radius, - hspace=self.fillHoles_space_between_holes, - bspace=self.fillHoles_space_to_border, - min_radius=self.fillHoles_hole_min_radius, - style=self.fillHoles_hole_style, - bar_length=self.fillHoles_bar_length, - max_random=self.fillHoles_max_random, - ) - - def render(self): - self.chuteAngle = self.chuteAngle - - self.pusherAngle = 30 # angle of pusher - self.pusherA = 0.75 * self.canDiameter # length of pusher - self.pusherB = self.pusherA / math.sin(math.radians(180 - (90+self.chuteAngle) - self.pusherAngle)) * math.sin(math.radians(self.pusherAngle)) - self.pusherC = self.pusherA / math.sin(math.radians(180 - (90+self.chuteAngle) - self.pusherAngle)) * math.sin(math.radians(90+self.chuteAngle)) - - self.addPart(FrontEdge(self, self)) - self.addPart(TopChuteEdge(self, self)) - self.addPart(BarrierEdge(self, self)) - - if self.canDiameter < 8 * self.thickness: - self.edges["f"].settings.setValues(self.thickness, True, finger=1.0) - self.edges["f"].settings.setValues(self.thickness, True, space=1.0) - self.edges["f"].settings.setValues(self.thickness, True, surroundingspaces=0.0) - - if self.canDiameter < 4 * self.thickness: - raise ValueError("Can diameter has to be at least 4 times the material thickness!") - - if self.canNum < 4: - raise ValueError("4 cans is the minimum!") - - self.depth = self.canDiameter * (math.ceil(self.canNum / 2) + 0.1) + self.thickness - self.top_chute_height = max(self.depth * math.sin(math.radians(self.chuteAngle)), 0.1 * self.canDiameter) - self.top_chute_depth = (self.depth - 1.1 * self.canDiameter) / math.cos(math.radians(self.chuteAngle)) - self.bottom_chute_height = max((self.depth - 1.1 * self.canDiameter) * math.sin(math.radians(self.chuteAngle)), 0.1 * self.canDiameter) - self.bottom_chute_depth = self.depth / math.cos(math.radians(self.chuteAngle)) - self.barrier_height = min( - 0.25 * self.canDiameter, - self.bottom_chute_height + self.top_chute_height - self.thickness) - - if (self.top_chute_depth + self.bottom_chute_height - self.thickness) < (self.barrier_height + self.canDiameter * 0.1): - self.bottom_chute_height = self.barrier_height + self.canDiameter * 0.1 + self.thickness - self.top_chute_depth - - self.height = self.thickness + self.canDiameter + self.bottom_chute_height + self.top_chute_height + 0.5 * self.thickness + self.canDiameter + 1.5 * self.thickness # measurements from bottom to top - self.width = 0.01 * self.canHeight + self.canHeight + 0.01 * self.canHeight - edgs = self.bottom_edge + "h" + self.top_edge + "a" - - # render your parts here - self.rectangularWall(self.depth, self.height, edges=edgs, callback=self.cb_sides, move="up", label="right") - self.rectangularWall(self.depth, self.height, edges=edgs, callback=self.cb_sides, move="up mirror", label="left") - - self.rectangularWall(self.bottom_chute_depth, self.width, "fefe", callback=self.cb_bottom_chute, move="up", label="bottom chute") - self.rectangularWall(self.top_chute_depth, self.width, "fbfe", callback=self.cb_top_chute, move="up", label="top chute") - - self.rectangularWall(self.barrier_height, self.width, "fAfe", move="right", label="barrier") - self.rectangularWall(self.height, self.width, "fefe", callback=self.cb_back, move="up", label="back") - self.rectangularWall(self.barrier_height, self.width, "fefe", move="left only", label="invisible") - - if self.top_edge != "e": - self.rectangularWall(self.depth, self.width, "fefe", callback=self.cb_top, move="up", label="top") - - pusherH = self.pusherB * math.cos(math.radians(self.chuteAngle)) + self.thickness - pusherV = self.pusherC * math.cos(math.radians(self.chuteAngle)) + self.thickness - - self.move(pusherV, pusherH, where ="right", before=True, label="Pusher") - self.DrawPusher() - self.move(pusherV, pusherH, where ="right", before=False, label="Pusher") - self.move(pusherV, pusherH, where ="right", before=True, label="Pusher") - self.DrawPusher() - self.move(pusherV, pusherH, where ="right", before=False, label="Pusher") - self.move(pusherV, pusherH, where ="up", before=True, label="Pusher") - self.DrawPusher() - self.text("Glue the Pusher pieces into slots on bottom\nand back plates to prevent stuck cans.", pusherV+3,0, fontsize=4, color=Color.ANNOTATIONS) - self.move(pusherV, pusherH, where ="up", before=False, label="Pusher") - - self.move(pusherV, pusherH, where ="left only", before=True, label="Pusher") - self.move(pusherV, pusherH, where ="left only", before=True, label="Pusher") - - if self.bottom_edge == "š": - self.rectangularWall(self.edges["š"].settings.width+3*self.thickness, self.edges["š"].settings.height-4*self.burn, "eeee", move="right", label="Stabilizer 1") - self.rectangularWall(self.edges["š"].settings.width+3*self.thickness, self.edges["š"].settings.height-4*self.burn, "eeee", move="right", label="Stabilizer 2") - self.rectangularWall(self.edges["š"].settings.width+5*self.thickness, self.edges["š"].settings.height-4*self.burn, "eeee", move="right", label="Stabilizer 3") - self.rectangularWall(self.edges["š"].settings.width+5*self.thickness, self.edges["š"].settings.height-4*self.burn, "eeee", move="right", label="Stabilizer 4") - self.text("Glue a stabilizer on the inside of each bottom\nside stacking foot for lateral stabilization.",3 ,0 , fontsize=4, color=Color.ANNOTATIONS) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/carbonfilter.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/carbonfilter.py deleted file mode 100644 index ebf2c8c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/carbonfilter.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (C) 2013-2023 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class CarbonFilter(Boxes): - """Compact filter for activated char coal pellets""" - - description = """The filter does not include the top rim. You need some rectangular wooden strip about 2-3cm in size to glue around. The x and y are without this rim and should be about 5 cm smaller that the nominal size. - -The following sizes are currently hard coded: - -* Height of rails on top: 50mm -* Borders on top: 40mm -* Char coal width (horizontal): 40mm -* Bottom width: 40 + 20 + 40 mm - -For assembly it is important that all bottom plates are the same way up. This allows the ribs of adjacent pockets to pass beside each other. - -There are three type of ribs: - -* Those with staight tops go in the middle of the bottom plates -* Those pointier angle go at the outer sides and meet with the side bars -* The less pointy go at all other sides of the bottom plates that will end up on the inside - -The last two types of ribs do not have finger joints on the outside but still need to be glued to the top beam of the adjacent pocket or the left or right side bar. -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser(x=550, y=550, h=250) - self.argparser.add_argument( - "--pockets", action="store", type=int, default=3, - help="number of V shaped filter pockets") - self.argparser.add_argument( - "--ribs", action="store", type=int, default=12, - help="number of ribs to hold the bottom and the mesh") - - def sideCB(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - p = self.pockets - - posx = t - w = self.w - a = self.a - - self.fingerHolesAt(t/2, h, 50, -90) - self.fingerHolesAt(x-t/2, h, 50, -90) - - for i in range(p): - self.fingerHolesAt(posx + t/2, h, 50, -90+a) - self.fingerHolesAt(posx + 40 + t/2, h, 50, -90+a) - self.fingerHolesAt(posx + w - t/2, h, 50, -90-a) - self.fingerHolesAt(posx + w - 40 - t/2, h, 50, -90-a) - - self.fingerHolesAt(posx + w/2 -50 + t, 3.5*t, 100 - 2*t, 0) - - posx += w - - def bottomCB(self): - t = self.thickness - for i in range(self.ribs): - self.fingerHolesAt((i+1) * self.y / (self.ribs + 1) - 1.5 * t, - 0, 4*t, 90) - self.fingerHolesAt((i+1) * self.y / (self.ribs + 1) - 1.5 * t, - 40 - t, 20, 90) - - def topRailCB(self): - t = self.thickness - for i in range(self.ribs): - self.fingerHolesAt((i+1) * self.y / (self.ribs + 1) - 1.5 * t, - 0, 30, 90) - - def innerRibs(self, n, move=None): - - x, y, h = self.x, self.y, self.h - t = self.thickness - a = self.a - a_ = math.radians(a) - - l = (h-4*t) / math.cos(a_) - 0.5 * t * math.sin(a_) - - tw = n * (20 + self.spacing) + l * math.sin(a_) - th = h-3*t - 20 * math.cos(a_) + self.spacing - - if self.move(tw, th, move, True): - return - - self.moveTo(0, t) - - for i in range(n): - self.edges["f"](20) - self.polyline(0, 90-a, l - 50, 90, t, -90) - self.edges["f"](30) - self.polyline(0, 90 + a, 20-t, 90 - a, l-20 + t * math.sin(a_), - 90+a) - - self.moveTo(20 + self.spacing) - self.ctx.stroke() - - self.move(tw, th, move, label="Inner ribs") - - def sideHolders(self, n, move=None): - - x, y, h = self.x, self.y, self.h - t = self.thickness - a = self.a - a_ = math.radians(a) - - l = (h-4*t) / math.cos(a_) - 0.5 * t * math.sin(a_) - 50 - - tw = n * (10 + self.spacing) + l * math.sin(a_) - th = h - 4*t - 50 - - if self.move(tw, th, move, True): - return - - for i in range(n): - self.polyline(10, 90-a, l, 90+a, 10, 90-a, l, 90+a) - self.ctx.stroke() - self.moveTo(10+self.spacing) - - self.move(tw, th, move, label="Inner ribs") - - def topStabilizers(self, n, move=None): - t = self.thickness - - l = 2* (self.h-60) * math.sin(math.radians(self.a)) - 20 - tw = n * (6*t + self.spacing) - th = l + 4*t - - if self.move(tw, th, move, True): - return - - self.moveTo(t) - for i in range(n): - for j in range(2): - self.polyline(0, 90, 2*t, -90, t, -90, 2*t, 90, 3*t, (90, t), - l+2*t, (90, t)) - self.ctx.stroke() - self.moveTo(6*t + self.spacing) - - self.move(tw, th, move, label="Inner ribs") - - def outerRibs(self, n, n_edge, move=None): - - x, y, h = self.x, self.y, self.h - t = self.thickness - a = self.a - a_ = math.radians(a) - - l = (h-4*t) / math.cos(a_) + 0.5 * t * math.sin(a_) - - dl = (20 - t) * (math.tan(math.pi/2 - 2*a_) + math.sin(a_)) - dll = (20 - t) * (1 / math.sin(2*a_)) - - dl2 = (20 - t) * (math.tan(math.pi/2 - a_) + math.sin(a_)) - dll2 = (20 - t) * (1 / math.sin(a_)) - - tw = (n // 2) * (40 + t) + l * math.sin(a_) - th = h + 5*t - - if self.move(tw, th, move, True): - return - - self.moveTo(2*t) - - for i in range(n): - self.polyline(0*t + 20, (90, 2*t), 2*t, -a) - if i < n_edge: - self.polyline(l - dl2 - t * math.sin(a_), a, - dll2, 180 - a, 20) - else: - self.polyline(l - dl - t * math.sin(a_), 2*a, - dll, 180 - 2*a, 20) - self.edges["f"](30) - self.polyline(0, -90, t, 90, l - 50, a, t, -90) - self.edges["f"](4*t) - self.polyline(0, 90, 1*t, (90, 2*t)) - - self.moveTo(t + 40)# + self.spacing) - if i + 1 == n // 2: - self.moveTo(2*t+0.7*self.spacing, h + 5*t, 180) - self.ctx.stroke() - - self.move(tw, th, move, label="Outer ribs") - - def render(self): - # adjust to the variables you want in the local scope - x, y, h = self.x, self.y, self.h - - self.y = y = self.adjustSize(y) - - t = self.thickness - - self.w = (x - 2*t) / self.pockets - self.a = math.degrees(math.atan((self.w - 100) / 2 / (h - 4*t))) - - # sides - for i in range(2): - self.rectangularWall(x, h, callback=[self.sideCB], move="up") - for i in range(2): - self.rectangularWall(y, 50, "efef", label="Sides", move="up") - - # top rails - for i in range(self.pockets * 4): - self.rectangularWall(y, 50, "efef", - callback=[self.topRailCB], - label="Top rails", move="up") - - # bottoms - w = 100 - 2*t - for i in range(self.pockets): - self.rectangularWall( - y, w, "efef", - callback=[self.bottomCB, None, self.bottomCB], - label="bottom plate", move="up") - - self.innerRibs(self.pockets * self.ribs * 2, move="up") - self.outerRibs(self.pockets * self.ribs * 2, self.ribs * 2, move="up") - self.sideHolders(self.pockets * 8, move="up") - self.topStabilizers(min(3, self.ribs) *self.pockets) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/cardbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/cardbox.py deleted file mode 100644 index 377b9b9..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/cardbox.py +++ /dev/null @@ -1,250 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# Copyright (C) 2018 jens persson -# Copyright (C) 2023 Manuel Lohoff -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import BoolArg, Boxes, edges - - -class InsetEdgeSettings(edges.Settings): - """Settings for InsetEdge""" - absolute_params = { - "thickness": 0, - } - - -class InsetEdge(edges.BaseEdge): - """An edge with space to slide in a lid""" - def __call__(self, length, **kw): - t = self.settings.thickness - self.corner(90) - self.edge(t, tabs=2) - self.corner(-90) - self.edge(length, tabs=2) - self.corner(-90) - self.edge(t, tabs=2) - self.corner(90) - - -class FingerHoleEdgeSettings(edges.Settings): - """Settings for FingerHoleEdge""" - absolute_params = { - "wallheight": 0, - "fingerholedepth": 0, - } - - -class FingerHoleEdge(edges.BaseEdge): - """An edge with room to get your fingers around cards""" - def __call__(self, length, **kw): - depth = self.settings.fingerholedepth-10 - self.edge(length/2-10, tabs=2) - self.corner(90) - self.edge(depth, tabs=2) - self.corner(-180, 10) - self.edge(depth, tabs=2) - self.corner(90) - self.edge(length/2-10, tabs=2) - - -class CardBox(Boxes): - """Box for storage of playing cards, with versatile options""" - ui_group = "Box" - - description = """ -### Description -Versatile Box for Storage of playing cards. Multiple different styles of storage are supported, e.g. a flat storage or a trading card deck box style storage. See images for ideas. - -#### Building instructions -Place inner walls on floor first (if any). Then add the outer walls. Glue the two walls without finger joins to the inside of the side walls. Make sure there is no squeeze out on top, as this is going to form the rail for the lid. - -Add the top of the rails to the sides (front open) or to the back and front (right side open) and the grip rail to the lid. -Details of the lid and rails -![Details](static/samples/CardBox-detail.jpg) -Whole box (early version still missing grip rail on the lid): -""" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser(y=68, h=92, outside=False, sx="65*4") - self.argparser.add_argument( - "--openingdirection", action="store", type=str, default="front", - choices=['front', 'right'], - help="Direction in which the lid slides open. Lid length > Lid width recommended.") - self.argparser.add_argument( - "--fingerhole", action="store", type=str, default="regular", - choices=['regular', 'deep', 'custom'], - help="Depth of cutout to grab the cards") - self.argparser.add_argument( - "--fingerhole_depth", action="store", type=float, default=20, - help="Depth of cutout if fingerhole is set to 'custom'. Disabled otherwise.") - self.argparser.add_argument( - "--add_lidtopper", action="store", type=BoolArg(), default=False, - help="Add an additional lid topper for optical reasons and customisation" - ) - - @property - def fingerholedepth(self): - if self.fingerhole == 'custom': - return self.fingerhole_depth - elif self.fingerhole == 'regular': - a = self.h/4 - if a < 35: - return a - else: - return 35 - elif self.fingerhole == 'deep': - return self.h-self.thickness-10 - - #inner dimensions of surrounding box (disregarding inlays) - @property - def boxhight(self): - if self.outside: - return self.h - 3 * self.thickness - return self.h - @property - def boxwidth(self): - return (len(self.sx) + 1) * self.thickness + sum(self.sx) - @property - def boxdepth(self): - if self.outside: - return self.y - 2 * self.thickness - if self.openingdirection == 'right': - return self.y + 2 * self.thickness - return self.y - - def divider_bottom(self): - t = self.thickness - sx = self.sx - y = self.boxdepth - - pos = 0.5 * t - for i in sx[:-1]: - pos += i + t - self.fingerHolesAt(pos, 0, y, 90) - - def divider_back_and_front(self): - t = self.thickness - sx = self.sx - y = self.boxhight - - pos = 0.5 * t - for i in sx[:-1]: - pos += i + t - self.fingerHolesAt(pos, 0, y, 90) - - def render(self): - t = self.thickness - - h = self.boxhight - x = self.boxwidth - y = self.boxdepth - sx = self.sx - - s = InsetEdgeSettings(thickness=t) - p = InsetEdge(self, s) - p.char = "a" - self.addPart(p) - - s = FingerHoleEdgeSettings(thickness=t, wallheight=h, fingerholedepth=self.fingerholedepth) - p = FingerHoleEdge(self, s) - p.char = "A" - self.addPart(p) - - if self.openingdirection == 'right': - with self.saved_context(): - self.rectangularWall(x, y-t*.2, "eFee", move="right", label="Lid") - self.rectangularWall(x, y, "ffff", callback=[self.divider_bottom], - move="right", label="Bottom") - self.rectangularWall(x, y, "eEEE", move="up only") - self.rectangularWall(x, t, "feee", move="up", label="Lip Front") - self.rectangularWall(x, t, "eefe", move="up", label="Lip Back") - - with self.saved_context(): - self.rectangularWall(x, h+t, "FfFf", - callback=[self.divider_back_and_front], - move="right", - label="Back") - self.rectangularWall(x, h+t, "FfFf", - callback=[self.divider_back_and_front], - move="right", - label="Front") - self.rectangularWall(x, h+t, "EEEE", move="up only") - - with self.saved_context(): - self.rectangularWall(y, h+t, "FFEF", move="right", label="Outer Side Left") - self.rectangularWall(y, h+t, "FFaF", move="right", label="Outer Side Right") - self.rectangularWall(y, h+t, "fFfF", move="up only") - - with self.saved_context(): - self.rectangularWall(y, h, "Aeee", move="right", label="Inner Side Left") - self.rectangularWall(y, h, "Aeee", move="right", label="Inner Side Right") - self.rectangularWall(y, h, "eAee", move="up only") - - with self.saved_context(): - self.rectangularWall(y-t*.2, t, "fEeE", move="right", label="Lid Lip") - self.rectangularWall(y, t*2, "efee", move="up only") - - for i in range(len(sx) - 1): - self.rectangularWall(h, y, "fAff", move="right", label="Divider") - - for c in sx: - self.rectangularWall(c, h, "eeee", move="right", label="Front inlay") - self.rectangularWall(c, h, "eeee", move="right", label="Back inlay") - - if self.add_lidtopper: - self.rectangularWall(x, y - 2*t, "eeee", move="right", label="Lid topper") - - elif self.openingdirection == 'front': - with self.saved_context(): - self.rectangularWall(x - t * .2, y, "eeFe", move="right", label="Lid") - self.rectangularWall(x, y, "ffff", callback=[self.divider_bottom], - move="right", label="Bottom") - self.rectangularWall(x, y, "eEEE", move="up only") - self.rectangularWall(x - t * .2, t, "fEeE", move="up", label="Lid Lip") - - with self.saved_context(): - self.rectangularWall(x, h + t, "FFEF", - callback=[self.divider_back_and_front], - move="right", - label="Back") - self.rectangularWall(x, h + t, "FFaF", - callback=[self.divider_back_and_front], - move="right", - label="Front") - self.rectangularWall(x, h + t, "EEEE", move="up only") - - with self.saved_context(): - self.rectangularWall(y, h + t, "FfFf", move="right", label="Outer Side Left") - self.rectangularWall(y, h + t, "FfFf", move="right", label="Outer Side Right") - self.rectangularWall(y, h + t, "fFfF", move="up only") - - with self.saved_context(): - self.rectangularWall(y, h, "Aeee", move="right", label="Inner Side Left") - self.rectangularWall(y, h, "Aeee", move="right", label="Inner Side Right") - self.rectangularWall(y, h, "eAee", move="up only") - - with self.saved_context(): - self.rectangularWall(y, t, "eefe", move="right", label="Lip Left") - self.rectangularWall(y, t, "feee", move="right", label="Lip Right") - self.rectangularWall(y, t * 2, "efee", move="up only") - - for i in range(len(sx) - 1): - self.rectangularWall(h, y, "fAff", move="right", label="Divider") - - if self.add_lidtopper: - self.rectangularWall(x, y - 2 * t, "eeee", move="right", label="Lid topper (optional)") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/cardholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/cardholder.py deleted file mode 100644 index bcefe39..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/cardholder.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (C) 2013-2021 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class CardHolder(Boxes): - """Shelf for holding (multiple) piles of playing cards / notes""" - - ui_group = "Shelf" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.StackableSettings) - self.addSettingsArgs(edges.GroovedSettings) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1.0) - - self.buildArgParser(sx="68*3", y=100, h=40, outside=False) - self.argparser.add_argument( - "--angle", action="store", type=float, default=7.5, - help="backward angle of floor") - self.argparser.add_argument( - "--stackable", action="store", type=boolarg, default=True, - help="make holders stackable") - - def side(self): - t = self.thickness - a = math.radians(self.angle) - - pos_y = self.y - abs(0.5 * t * math.sin(a)) - pos_h = t - math.cos(a) * 0.5 * t - self.fingerHolesAt(pos_y, pos_h, self.y, 180-self.angle) - - def fingerHoleCB(self, length, posy=0.0): - def CB(): - t = self.thickness - px = -0.5 * t - for x in self.sx[:-1]: - px += x + t - self.fingerHolesAt(px, posy, length, 90) - return CB - - def middleWall(self, move=None): - y, h = self.y , self.h - a = self.angle - t = self.thickness - tw = y + t - th = h - - if self.move(tw, th, move, True): - return - - self.moveTo(t, t, a) - - self.edges["f"](y) - self.polyline(0, 90-a, h-t-y*math.sin(math.radians(a)), 90, - y*math.cos(math.radians(a)), 90) - self.edges["f"](h-t) - - self.move(tw, th, move) - - def render(self): - sx, y = self.sx, self.y - t = self.thickness - - bottom = "š" if self.stackable else "e" - top = "S" if self.stackable else "e" - - if self.outside: - self.sx = sx = self.adjustSize(sx) - h = self.h = self.adjustSize(self.h, bottom, top) - else: - h = self.h = self.h + t + y * math.sin(math.radians(self.angle)) - self.x = x = sum(sx) + t * (len(sx) - 1) - - self.rectangularWall(y, h, [bottom, "F", top, "e"], - ignore_widths=[1, 6], - callback=[self.side], move="up") - self.rectangularWall(y, h, [bottom, "F", top, "e"], - ignore_widths=[1, 6], - callback=[self.side], move="up mirror") - - nx = len(sx) - f_lengths = [] - for val in self.sx: - f_lengths.append(val) - f_lengths.append(t) - f_lengths = f_lengths[:-1] - - frontedge = edges.CompoundEdge( - self, "e".join("z" * nx), f_lengths) - - self.rectangularWall(x, y, [frontedge, "f", "e", "f"], - callback=[self.fingerHoleCB(y)], move="up") - self.rectangularWall(x, h, bottom + "f" + top + "f", - ignore_widths=[1, 6], - callback=[self.fingerHoleCB(h-t, t)], move="up") - for i in range(nx-1): - self.middleWall(move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/castle.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/castle.py deleted file mode 100644 index 61d40db..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/castle.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Castle(Boxes): - """Castle tower with two walls""" - - description = """This was done as a table decoration. May be at some point in the future someone will create a proper castle -with towers and gates and walls that can be attached in multiple configurations.""" - ui_group = "Unstable" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - - def render(self, t_x=70, t_h=250, w1_x=300, w1_h=120, w2_x=100, w2_h=120): - s = edges.FingerJointSettings(10.0, relative=True, - space=1, finger=1, - width=self.thickness) - - s.edgeObjects(self, "pPQ") - - self.moveTo(0, 0) - self.rectangularWall(t_x, t_h, edges="efPf", move="right", callback=[lambda: self.fingerHolesAt(t_x * 0.5, 0, w1_h, 90), ]) - self.rectangularWall(t_x, t_h, edges="efPf", move="right") - self.rectangularWall(t_x, t_h, edges="eFPF", move="right", callback=[lambda: self.fingerHolesAt(t_x * 0.5, 0, w2_h, 90), ]) - self.rectangularWall(t_x, t_h, edges="eFPF", move="right") - - self.rectangularWall(w1_x, w1_h, "efpe", move="right") - self.rectangularWall(w2_x, w2_h, "efpe", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/closedbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/closedbox.py deleted file mode 100644 index 95dd6bc..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/closedbox.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class ClosedBox(Boxes): - """Fully closed box""" - - ui_group = "Box" - - description = """This box is more of a building block than a finished item. -Use a vector graphics program (like Inkscape) to add holes or adjust the base -plate. - -See BasedBox for variant with a base.""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h", "outside") - - def render(self): - - x, y, h = self.x, self.y, self.h - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - - t = self.thickness - - d2 = edges.Bolts(2) - d3 = edges.Bolts(3) - - d2 = d3 = None - - self.rectangularWall(x, h, "FFFF", bedBolts=[d2] * 4, move="right", label="Wall 1") - self.rectangularWall(y, h, "FfFf", bedBolts=[d3, d2, d3, d2], move="up", label="Wall 2") - self.rectangularWall(y, h, "FfFf", bedBolts=[d3, d2, d3, d2], label="Wall 4") - self.rectangularWall(x, h, "FFFF", bedBolts=[d2] *4, move="left up", label="Wall 3") - - self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="right", label="Top") - self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], label="Bottom") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coffeecapsulesholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coffeecapsulesholder.py deleted file mode 100644 index b9b5617..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coffeecapsulesholder.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (C) 2021 Guillaume Collic -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math - -from boxes import Boxes, boolarg - - -class CoffeeCapsuleHolder(Boxes): - """ - Coffee capsule holder - """ - - ui_group = "Misc" - - description = """ - You can store your coffee capsule near your espresso machine with this. It works both vertically, or upside down under a shelf. -""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.argparser.add_argument( - "--columns", - type=int, - default=4, - help="Number of columns of capsules.", - ) - self.argparser.add_argument( - "--rows", - type=int, - default=5, - help="Number of capsules by columns.", - ) - self.argparser.add_argument( - "--backplate", - type=boolarg, - default=True, - help="True if a backplate should be generated.", - ) - - def render(self): - self.lid_size = 37 - self.lid_size_with_margin = 39 - self.body_size = 30 - self.column_spacing = 5 - self.corner_radius = 3 - self.screw_margin = 6 - self.outer_margin = 7 - # Add space for the opening. A full row is not necessary for it. - self.rows = self.rows + 0.6 - - self.render_plate(screw_hole=7, hole_renderer=self.render_front_hole) - self.render_plate(hole_renderer=self.render_middle_hole) - if self.backplate: - self.render_plate() - - def render_plate(self, screw_hole=3.5, hole_renderer=None, move="right"): - width = ( - self.columns * (self.lid_size_with_margin + self.column_spacing) - - self.column_spacing - + 2 * self.outer_margin - ) - height = self.rows * self.lid_size + 2 * self.outer_margin - - if self.move(width, height, move, True): - return - - with self.saved_context(): - self.moveTo(self.corner_radius) - self.polyline( - width - 2 * self.corner_radius, - (90, self.corner_radius), - height - 2 * self.corner_radius, - (90, self.corner_radius), - width - 2 * self.corner_radius, - (90, self.corner_radius), - height - 2 * self.corner_radius, - (90, self.corner_radius), - ) - - if hole_renderer: - for col in range(self.columns): - with self.saved_context(): - self.moveTo( - self.outer_margin + col * (self.lid_size_with_margin + self.column_spacing) - self.burn, - self.outer_margin + (self.rows - 0.5) * self.lid_size + self.burn, - -90, - ) - hole_renderer() - - if screw_hole: - for x in [self.screw_margin, width - self.screw_margin]: - for y in [self.screw_margin, height - self.screw_margin]: - self.hole(x, y + self.burn, d=screw_hole) - - self.move(width, height, move) - - def render_front_hole(self): - radians = math.acos(self.body_size / self.lid_size_with_margin) - height_difference = (self.lid_size / 2) * math.sin(radians) - degrees = math.degrees(radians) - half = [ - 0, - (degrees, self.lid_size_with_margin / 2), - 0, - -degrees, - (self.rows - 1) * self.lid_size - height_difference, - ] - path = ( - half - + [(180, self.body_size / 2)] - + list(reversed(half)) - + [(180, self.lid_size_with_margin / 2)] - ) - self.polyline(*path) - - def render_middle_hole(self): - half = [(self.rows - 1) * self.lid_size, (180, self.lid_size_with_margin / 2)] - path = half * 2 - self.polyline(*path) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coinbanksafe.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coinbanksafe.py deleted file mode 100644 index 8124689..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coinbanksafe.py +++ /dev/null @@ -1,223 +0,0 @@ -# Copyright (C) 2024 Oliver Jensen -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class CoinBankSafe(Boxes): - """A piggy-bank designed to look like a safe.""" - - description =''' -Make sure not to discard the circle cutouts from the lid, base, and door. They are all needed. - -![Closed](static/samples/CoinBankSafe-closed.jpg) - -![Open](static/samples/CoinBankSafe-open.jpg) - -Assemble the locking pins like this: wiggle-disc, number-disc, doorhole-disc, spacer-disc, D-disc. -Glue the first three in place, but do not glue the last two. -Leaving them unglued will allow you change the code, and to remove the pin from the door. - -![Pins](static/samples/CoinBankSafe-pins.jpg) - -''' - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h") - self.argparser.add_argument( - "--slotlength", action="store", type=float, default=30, - help="Length of the coin slot in mm") - self.argparser.add_argument( - "--slotwidth", action="store", type=float, default=4, - help="Width of the coin slot in mm") - self.argparser.add_argument( - "--handlelength", action="store", type=float, default=8, - help="Length of handle in multiples of thickness") - self.argparser.add_argument( - "--handleclearance", action="store", type=float, default=1.5, - help="Clearance of handle in multiples of thickness") - - def drawNumbers(self, radius, cover): - fontsize = 0.8 * (radius - cover) - for num in range(8): - angle = num*45 - x = (cover + fontsize *0.4) * math.sin(math.radians(angle)) - y = (cover + fontsize *0.4) * math.cos(math.radians(angle)) - self.text(str(num+1), align="center middle", fontsize=fontsize, angle=-angle, color=[1,0,0], - y=y, x=x) - - def lockPin(self, layers, move=None): - t = self.thickness - cutout_width = t/3 - barb_length = t - base_length = layers * t - base_width = t - total_length = base_length + barb_length - total_width = base_width + cutout_width * 0.5 - cutout_angle = math.degrees(math.atan(cutout_width / base_length)) - cutout_length = math.sqrt(cutout_width**2 + base_length**2) - - #self.rectangularWall(5*t, t) - - if self.move(total_length, total_width, move, True): - return - - self.edge(total_length) - self.corner(90) - self.edge(base_width * 1/3) - self.corner(90) - self.edge(base_length) - self.corner(180+cutout_angle, 0) - self.edge(cutout_length) - self.corner(90-cutout_angle) - self.edge(cutout_width * 1.5) - self.corner(90) - self.edge(barb_length) - self.corner(90) - self.corner(-90, cutout_width * 0.5) - self.edge(base_length - cutout_width * 0.5) - self.corner(90) - self.edge(t) - self.corner(90) - - self.move(total_length, total_width, move) - - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - - slot_length = self.slotlength - slot_width = self.slotwidth - - handle_length = self.handlelength * t - handle_clearance = self.handleclearance * t - - # lock parameters - big_radius = 2.25 * t - small_radius = 1.4 * t - doorhole_radius = 1.25 * t - spacing = 1 - - # side walls - with self.saved_context(): - self.rectangularWall(x, h, "seFf", move="mirror right") - self.rectangularWall(y, h, "sFFF", move="right") - - # wall with holes for the locking bar - self.rectangularWall( - x, h, "sfFe", ignore_widths=[3,4,7,8], - callback=[lambda: self.fingerHolesAt(2.75*t, 0, h, 90)], - move="mirror right") - - # locking bar - self.moveTo(0, self.edges['s'].spacing() + t) - self.rectangularWall(1.33*t, h, "eeef", move="right") - # door - door_clearance = .1 * t # amount to shave off of the door width so it can open - before_hinge = 1.25 * t - door_clearance - after_hinge = y - 2.25 * t - door_clearance - self.moveTo(self.spacing/2, -t) - self.polyline( - after_hinge, -90, t, 90, t, 90, t, -90, before_hinge, 90, - h, 90, - before_hinge, -90, t, 90, t, 90, t, -90, after_hinge, 90, - h, 90) - num_dials = 3 - space_under_dials = 6*big_radius - space_not_under_dials = h - space_under_dials - dial_spacing = space_not_under_dials / (num_dials + 1) - if dial_spacing < 1 : - min_height = 6*big_radius + 4 - raise ValueError(f"With thickness {t}, h must be at least {min_height} to fit the dials.") - - for pos_y in (h/2, - h/2 - (2*big_radius + dial_spacing), - h/2 + (2*big_radius + dial_spacing)): - self.hole(3*t - door_clearance, pos_y, doorhole_radius) - self.rectangularHole(3*t - door_clearance, pos_y, t, t) - self.rectangularHole(y/2 - door_clearance, h/2, t, handle_length / 2) - - self.rectangularWall(x, h, "seff", move="up only") - - # top - self.rectangularWall( - y, x, "efff", callback=[ - lambda: self.rectangularHole(y/2, x/2, slot_length, slot_width), - lambda: (self.hole(1.75*t, 1.75*t, 1.15*t), - self.rectangularHole(1.75*t, 1.75*t, t, t))], - label="top", move="right") - - # bottom - self.rectangularWall( - y, x, "efff", callback=[ - lambda: (self.hole(1.75*t, 1.75*t, 1.15*t), - self.rectangularHole(1.75*t, 1.75*t, t, t))], - label="bottom", move="right") - - def holeCB(): - self.rectangularHole(0, 0, t, t) - self.moveTo(0, 0, 45) - self.rectangularHole(0, 0, t, t) - - # locks - with self.saved_context(): - self.partsMatrix(3, 1, "right", self.parts.disc, 2*big_radius, - callback=lambda: (self.drawNumbers(big_radius, small_radius), self.rectangularHole(0, 0, t, t))) - self.partsMatrix(3, 1, "right", self.parts.disc, 2*big_radius, - dwidth=0.8,callback=holeCB) - self.partsMatrix( - 3, 1, "right", self.parts.disc, 2*small_radius, - callback=lambda:self.rectangularHole(0, 0, t, t)) - self.partsMatrix( - 3, 1, "right", self.parts.wavyKnob, 2*small_radius, - callback=lambda:self.rectangularHole(0, 0, t, t)) - - self.partsMatrix(3, 1, "up only", self.parts.disc, 2*big_radius) - - # lock pins - with self.saved_context(): - self.lockPin(5, move="up") - self.lockPin(5, move="up") - self.lockPin(5, move="up") - self.lockPin(5, move="right only") - - # handle - self.moveTo(0) - handle_curve_radius = 0.2 * t - self.moveTo(t * 2.5) - self.polyline( - 0, - (90, handle_curve_radius), - handle_length - 2 * handle_curve_radius, - (90, handle_curve_radius), - handle_clearance - handle_curve_radius, - 90, - handle_length / 4, - -90, - t, - 90, - handle_length / 2, - 90, - t, - -90, - handle_length / 4, - 90, - handle_clearance - handle_curve_radius, - ) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coindisplay.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coindisplay.py deleted file mode 100644 index b98190d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/coindisplay.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class CoinHolderSideEdge(edges.BaseEdge): - char = "B" - def __call__(self, length, **kw): - a_l = self.coin_plate - a_l2 = self.settings.coin_plate * math.sin(self.settings.angle) - a = math.degrees(self.settings.angle) - - print(a, a_l, a_l2) - self.corner(-a) - # Draw the angled edge, but set the thickness to two temporarily - # as two pieces will go on top of another - self.edges["F"].settings.thickness = self.thickness * 2 - self.edges["F"](a_l) - self.edges["F"].settings.thickness = self.thickness - - self.polyline(0, 90+a, a_l2, -90) - - def margin(self) -> float: - return self.settings.coin_plate_x - -class CoinDisplay(Boxes): - """A showcase for a single coin""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--coin_d", action="store", type=float, default=20.0, - help="The diameter of the coin in mm") - self.argparser.add_argument( - "--coin_plate", action="store", type=float, default=50.0, - help="The size of the coin plate") - self.argparser.add_argument( - "--coin_showcase_h", action="store", type=float, default=50.0, - help="The height of the coin showcase piece") - self.argparser.add_argument( - "--angle", action="store", type=float, default=30, - help="The angle that the coin will tilt as") - - def bottomHoles(self): - """ - Function that puts two finger holes at the bottom cube plate for the coin holder - """ - self.fingerHolesAt(self.x/2 - self.thickness - self.thickness/2 - (self.coin_plate/2), self.y/2+self.coin_plate_x/2-self.thickness, self.coin_plate_x, -90) - self.fingerHolesAt(self.x/2 - self.thickness + self.thickness/2 + (self.coin_plate/2), self.y/2+self.coin_plate_x/2-self.thickness, self.coin_plate_x, -90) - - self.fingerHolesAt(self.x/2-self.coin_plate/2-self.thickness, self.y/2-self.coin_plate_x/2-self.thickness*1.5, self.coin_plate, 0) - - def coinCutout(self): - """ - Function that puts a circular hole in the coin holder piece - """ - self.hole(self.coin_plate/2, self.coin_plate/2, self.coin_d/2) - - def render(self): - - x, y, h = self.x, self.y, self.h - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - - t = self.thickness - - d2 = edges.Bolts(2) - d3 = edges.Bolts(3) - - d2 = d3 = None - - self.addPart(CoinHolderSideEdge(self, self)) - - self.angle = math.radians(self.angle) - self.coin_plate_x = self.coin_plate * math.cos(self.angle) - - self.rectangularWall(x, h, "FFFF", bedBolts=[d2] * 4, move="right", label="Wall 1") - self.rectangularWall(y, h, "FfFf", bedBolts=[d3, d2, d3, d2], move="up", label="Wall 2") - self.rectangularWall(y, h, "FfFf", bedBolts=[d3, d2, d3, d2], label="Wall 4") - self.rectangularWall(x, h, "FFFF", bedBolts=[d2] *4, move="left up", label="Wall 3") - - self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="right", label="Top") - self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="right", label="Bottom", callback=[self.bottomHoles]) - - # Draw the coin holder side holsers - e = ["f", "f", "B", "e"] - self.rectangularWall(self.coin_plate_x, self.coin_showcase_h, e, move="right", label="CoinSide1") - self.rectangularWall(self.coin_plate_x, self.coin_showcase_h, e, move="right", label="CoinSide2") - - self.rectangularWall(self.coin_plate, self.coin_plate, "efef", move="left down", label="Coin Plate Base") - self.rectangularWall(self.coin_plate, self.coin_plate, "efef", move="down", label="Coin Plate", callback=[self.coinCutout]) - - self.rectangularWall(self.coin_plate, self.coin_showcase_h, "fFeF", move="down", label="CoinSide3") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/concaveknob.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/concaveknob.py deleted file mode 100644 index 19cbe8d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/concaveknob.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class ConcaveKnob(Boxes): - """Round knob serrated outside for better gripping""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--diameter", action="store", type=float, default=50., - help="Diameter of the knob (mm)") - self.argparser.add_argument( - "--serrations", action="store", type=int, default=3, - help="Number of serrations") - self.argparser.add_argument( - "--rounded", action="store", type=float, default=.2, - help="Amount of circumference used for non convex parts") - self.argparser.add_argument( - "--angle", action="store", type=float, default=70., - help="Angle between convex and concave parts") - self.argparser.add_argument( - "--bolthole", action="store", type=float, default=6., - help="Diameter of the bolt hole (mm)") - self.argparser.add_argument( - "--dhole", action="store", type=float, default=1., - help="D-Flat in fraction of the diameter") - self.argparser.add_argument( - "--hexhead", action="store", type=float, default=10., - help="Width of the hex bolt head (mm)") - - def render(self): - t = self.thickness - self.parts.concaveKnob(self.diameter, self.serrations, - self.rounded, self.angle, - callback=lambda:self.dHole(0, 0, - d=self.bolthole, - rel_w=self.dhole), - move="right") - self.parts.concaveKnob(self.diameter, self.serrations, - self.rounded, self.angle, - callback=lambda: self.nutHole(self.hexhead), - move="right") - self.parts.concaveKnob(self.diameter, self.serrations, - self.rounded, self.angle) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/console.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/console.py deleted file mode 100644 index 09105ee..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/console.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Console(Boxes): - """Console with slanted panel""" - - ui_group = "Box" - - description = """ - -Console Arcade Stick - -![Front](static/samples/ConsoleArcadeStickFront.jpg) -![Back](static/samples/ConsoleArcadeStickBack.jpg) -![Inside](static/samples/ConsoleArcadeStickInside.jpg) - -Keyboard enclosure: -""" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=.5) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=100, y=100, h=100, outside=False) - self.argparser.add_argument( - "--front_height", action="store", type=float, default=30, - help="height of the front below the panel (in mm)") - self.argparser.add_argument( - "--angle", action="store", type=float, default=50, - help="angle of the front panel (90°=upright)") - - def render(self): - x, y, h, hf = self.x, self.y, self.h, self.front_height - t = self.thickness - - if self.outside: - self.x = x = self.adjustSize(x) - self.y = y = self.adjustSize(y) - self.h = h = self.adjustSize(h) - - panel = min((h-hf)/math.cos(math.radians(90-self.angle)), - y/math.cos(math.radians(self.angle))) - top = y - panel * math.cos(math.radians(self.angle)) - h = hf + panel * math.sin(math.radians(self.angle)) - - if top>0.1*t: - borders = [y, 90, hf, 90-self.angle, panel, self.angle, top, - 90, h, 90] - else: - borders = [y, 90, hf, 90-self.angle, panel, self.angle+90, h, 90] - - if hf < 0.01*t: - borders[1:4] = [180-self.angle] - - self.polygonWall(borders, move="right") - self.polygonWall(borders, move="right") - self.polygonWalls(borders, x) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/console2.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/console2.py deleted file mode 100644 index 300a85c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/console2.py +++ /dev/null @@ -1,302 +0,0 @@ -# Copyright (C) 2013-2020 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Console2(Boxes): - """Console with slanted panel and service hatches""" - - ui_group = "Box" - - description = """ -This box is designed as a housing for electronic projects. It has hatches that can be re-opened with simple tools. It intentionally cannot be opened with bare hands - if build with thin enough material. - -#### Caution -There is a chance that the latches of the back wall or the back wall itself interfere with the front panel or it's mounting frame/lips. The generator does not check for this. So depending on the variant chosen you might need to make the box deeper (increase y parameter) or the panel angle steeper (increase angle parameter) until there is enough room. - -It's also possible that the frame of the panel interferes with the floor if the hi parameter is too small. - -#### Assembly instructions -The main body is easy to assemble by starting with the floor and then adding the four walls and (if present) the top piece. - -If the back wall is removable you need to add the lips and latches. The U-shaped clamps holding the latches in place need to be clued in place without also gluing the latches themselves. Make sure the springs on the latches point inwards and the angled ends point to the side walls as shown here: - -![Back wall details](static/samples/Console2-backwall-detail.jpg) - -If the panel is removable you need to add the springs with the tabs to the side lips. This photo shows the variant which has the panel glued to the frame: - -![Back wall details](static/samples/Console2-panel-detail.jpg) - -If space is tight you may consider not gluing the cross pieces in place and remove them after the glue-up. This may prevent the latches of the back wall and the panel from interfering with each other. - -The variant using finger joints only has the two side lips without the cross bars. - -#### Re-Opening - -The latches at the back wall lock in place when closed. To open them they need to be pressed in and can then be moved aside. - -To remove the panel you have to press in the four tabs at the side. It is easiest to push them in and then pull the panel up a little bit so the tabs stay in. -""" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=.5) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=100, y=100, h=100, bottom_edge="s", - outside=False) - self.argparser.add_argument( - "--front_height", action="store", type=float, default=30, - help="height of the front below the panel (in mm)") - self.argparser.add_argument( - "--angle", action="store", type=float, default=50, - help="angle of the front panel (90°=upright)") - self.argparser.add_argument( - "--removable_backwall", action="store", type=boolarg, default=True, - help="have latches at the backwall") - self.argparser.add_argument( - "--removable_panel", action="store", type=boolarg, default=True, - help="The panel is held by tabs and can be removed") - self.argparser.add_argument( - "--glued_panel", action="store", type=boolarg, default=True, - help="the panel is glued and not held by finger joints") - - def borders(self): - x, y, h, fh = self.x, self.y, self.h, self.front_height - t = self.thickness - - panel = min((h-fh)/math.cos(math.radians(90-self.angle)), - y/math.cos(math.radians(self.angle))) - top = y - panel * math.cos(math.radians(self.angle)) - h = fh + panel * math.sin(math.radians(self.angle)) - - if top>0.1*t: - borders = [y, 90, fh, 90-self.angle, panel, self.angle, top, - 90, h, 90] - else: - borders = [y, 90, fh, 90-self.angle, panel, self.angle+90, h, 90] - return borders - - def latch(self, move=None): - t = self.thickness - s = 0.1 * t - - tw, th = 8*t, 3*t - - if self.move(tw, th, move, True): - return - - self.moveTo(0, 1.2*t) - self.polyline(t, -90, .2*t, 90, 2*t, -90, t, 90, t, 90, t, -90, 3*t, - 90, t, -90, t, 90, t, 90, 2*t, 90, 0.5*t, - -94, 4.9*t, 94, .5*t, 86, 4.9*t, -176, 5*t, - -90, 1.0*t, 90, t, 90, 1.8*t, 90) - - self.move(tw, th, move) - - def latch_clamp(self, move=None): - t = self.thickness - s = 0.1 * t - - tw, th = 4*t, 4*t - - if self.move(tw, th, move, True): - return - - self.moveTo(0.5*t) - self.polyline(t-0.5*s, 90, 2.5*t+.5*s, -90, t+s, -90, 2.5*t+.5*s, 90, t-0.5*s, 90, - t, -90, 0.5*t, 90, 2*t, 45, 2**.5*t, 45, 2*t, 45, 2**.5*t, 45, 2*t, 90, 0.5*t, -90, t, 90) - - self.move(tw, th, move) - - @restore - @holeCol - def latch_hole(self, posx): - t = self.thickness - s = 0.1 * t - - self.moveTo(posx, 2*t, 180) - - path = [1.5*t, -90, t, -90, t-0.5*s, 90] - path = path + [2*t] + list(reversed(path)) - path = path[:-1] + [3*t] + list(reversed(path[:-1])) - - self.polyline(*path) - - def panel_side(self, l, move=None): - t = self.thickness - s = 0.1 * t - - tw, th = l, 3*t - - if not self.glued_panel: - th += t - - if self.move(tw, th, move, True): - return - - self.rectangularHole(3*t, 1.5*t, 3*t, 1.05*t) - self.rectangularHole(l-3*t, 1.5*t, 3*t, 1.05*t) - self.rectangularHole(l/2, 1.5*t, 2*t, t) - if self.glued_panel: - self.polyline(*([l, 90, t, 90, t, -90, t, -90, t, 90, t, 90]*2)) - else: - self.polyline(l, 90, 3*t, 90) - self.edges["f"](l) - self.polyline(0, 90, 3*t, 90) - self.move(tw, th, move) - - def panel_lock(self, l, move=None): - t = self.thickness - - l -= 4*t - tw, th = l, 2.5*t - - if self.move(tw, th, move, True): - return - - end = [l/2-3*t, -90, 1.5*t, (90, .5*t), t, (90, .5*t), - t, 90, .5*t, -90, 0.5*t, -90, 0, (90, .5*t), 0, 90,] - - self.moveTo(l/2-t, 2*t, -90) - self.polyline(*([t, 90, 2*t, 90, t, -90] + end + [l] + - list(reversed(end)))) - self.move(tw, th, move) - - def panel_cross_beam(self, l, move=None): - t = self.thickness - - tw, th = l+2*t, 3*t - - if self.move(tw, th, move, True): - return - - self.moveTo(t, 0) - self.polyline(*([l, 90, t, -90, t, 90, t, 90, t, -90, t, 90]*2)) - - self.move(tw, th, move) - - def side(self, borders, bottom="s", move=None, label=""): - - t = self.thickness - bottom = self.edges.get(bottom, bottom) - - tw = borders[0] + 2* self.edges["f"].spacing() - th = borders[-2] + bottom.spacing() + self.edges["f"].spacing() - if self.move(tw, th, move, True): - return - - d1 = t * math.cos(math.radians(self.angle)) - d2 = t * math.sin(math.radians(self.angle)) - - self.moveTo(t, 0) - bottom(borders[0]) - self.corner(90) - self.edges["f"](borders[2]+bottom.endwidth()-d1) - self.edge(d1) - self.corner(borders[3]) - if self.removable_panel: - self.rectangularHole(3*t, 1.5*t, 2.5*t, 1.05*t) - if not self.removable_panel and not self.glued_panel: - self.edges["f"](borders[4]) - else: - self.edge(borders[4]) - if self.removable_panel: - self.rectangularHole(-3*t, 1.5*t, 2.5*t, 1.05*t) - if len(borders) == 10: - self.corner(borders[5]) - self.edge(d2) - self.edges["f"](borders[6]-d2) - self.corner(borders[-3]) - if self.removable_backwall: - self.rectangularHole(self.latchpos, 1.55*t, 1.1*t, 1.1*t) - self.edge(borders[-2]-t) - self.edges["f"](t+bottom.startwidth()) - else: - self.edges["f"](borders[-2]+bottom.startwidth()) - self.corner(borders[-1]) - - self.move(tw, th, move, label=label) - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - bottom = self.edges.get(self.bottom_edge) - - if self.outside: - self.x = x = self.adjustSize(x) - self.y = y = self.adjustSize(y) - self.h = h = self.adjustSize(h, bottom) - - d1 = t * math.cos(math.radians(self.angle)) - d2 = t * math.sin(math.radians(self.angle)) - - self.latchpos = latchpos = 6*t - - borders = self.borders() - self.side(borders, bottom, move="right", label="Left Side") - self.side(borders, bottom, move="right", label="Right Side") - - self.rectangularWall(borders[0], x, "ffff", move="right", label="Floor") - self.rectangularWall( - borders[2]-d1, x, ("F", "e", "F", bottom), ignore_widths=[7, 4], - move="right", label="Front") - - if self.glued_panel: - self.rectangularWall(borders[4], x, "EEEE", move="right", label="Panel") - elif self.removable_panel: - self.rectangularWall(borders[4], x-2*t, "hEhE", move="right", label="Panel") - else: - self.rectangularWall(borders[4], x, "FEFE", move="right", label="Panel") - - if len(borders) == 10: - self.rectangularWall(borders[6]-d2, x, "FEFe", move="right", label="Top") - - if self.removable_backwall: - self.rectangularWall( - borders[-2]-1.05*t, x, "EeEe", - callback=[ - lambda:self.latch_hole(latchpos), - lambda: self.fingerHolesAt(.5*t, 0, borders[-2]-4.05*t-latchpos), - lambda:self.latch_hole(borders[-2]-1.2*t-latchpos), - lambda: self.fingerHolesAt(.5*t, 3.05*t+latchpos, borders[-2]-4.05*t-latchpos)], - move="right", - label="Back Wall") - self.rectangularWall(2*t, borders[-2]-4.05*t-latchpos, "EeEf", move="right", label="Guide") - self.rectangularWall(2*t, borders[-2]-4.05*t-latchpos, "EeEf", move="right", label="Guide") - self.rectangularWall(t, x, ("F", bottom, "F", "e"), - ignore_widths=[0, 3], move="right", label="Bottom Back") - else: - self.rectangularWall(borders[-2], x, ("F", bottom, "F", "e"), - ignore_widths=[0, 3], move="right", label="Back Wall") - - # hardware for panel - if self.removable_panel: - if self.glued_panel: - self.panel_cross_beam(x-2.05*t, "rotated right") - self.panel_cross_beam(x-2.05*t, "rotated right") - - self.panel_lock(borders[4], "up") - self.panel_lock(borders[4], "up") - self.panel_side(borders[4], "up") - self.panel_side(borders[4], "up") - - # hardware for back wall - if self.removable_backwall: - self.latch(move="up") - self.latch(move="up") - self.partsMatrix(4, 2, "up", self.latch_clamp) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/desksign.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/desksign.py deleted file mode 100644 index 44c4395..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/desksign.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Desksign(Boxes): - """Simple diagonal plate with stands to show name or message.""" - - description = """Text to be engraved can be generated by inputting the label and fontsize fields. - height represents the area that can be used for writing text, does not match the actual - height when standing. Generated text is put in the center. Currently only a single - line of text is supported.""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.StackableSettings, width=2.0) # used for feet - - self.argparser.add_argument( - "--width", action="store", type=float, default=150, - help="plate width in mm (excluding holes)") - self.argparser.add_argument( - "--height", action="store", type=float, default=80, - help="plate height in mm") - self.argparser.add_argument( - "--angle", action="store", type=float, default=60, - help="plate angle in degrees (90 is vertical)") - self.argparser.add_argument( - "--label", action="store", type=str, default="", - help="optional text to engrave (leave blank to omit)") - self.argparser.add_argument( - "--fontsize", action="store", type=float, default=20, - help="height of text") - self.argparser.add_argument( - "--feet", action="store", type=boolarg, default=False, - help="add raised feet") - self.argparser.add_argument( - "--mirror", action="store", type=boolarg, default=True, - help="mirrors one of the stand so the same side of the material can be placed on the outside") - - def render(self): - width = self.width - height = self.height - angle = self.angle - feet = self.feet - mirror = self.mirror - t = self.thickness - - if not (0 < angle and angle < 90): - raise ValueError("angle has to between 0 and 90 degrees") - - base = math.cos(math.radians(angle)) * height - h = math.sin(math.radians(angle)) * height - - label = self.label - fontsize = self.fontsize - - if label and fontsize: - self.rectangularWall(width, height, "eheh", move="right", callback=[ - lambda: self.text("%s" % label, width/2, (height-fontsize)/2, - fontsize = fontsize, align="center", color=Color.ETCHING)]) # add text - else: - self.rectangularWall(width, height, "eheh", move="right") # front - - # stands at back/side - edge = "šef" if feet else "eef" - if mirror: - self.rectangularTriangle(base, h, edge, num=1, move="right") - self.rectangularTriangle(base, h, edge, num=1, move="mirror right") - else: - self.rectangularTriangle(base, h, edge, num=2, move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dicebox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dicebox.py deleted file mode 100644 index e646011..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dicebox.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (C) 2022 Erik Snider (SniderThanYou@gmail.com) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class DiceBox(Boxes): - """Box with lid and integraded hinge for storing dice""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs( - edges.FingerJointSettings, - surroundingspaces=2.0) - self.addSettingsArgs( - edges.ChestHingeSettings, - finger_joints_on_box=True, - finger_joints_on_lid=True) - self.buildArgParser( - x=100, - y=100, - h=18, - outside=True) - self.argparser.add_argument( - "--lidheight", action="store", type=float, default=18, - help="height of lid in mm") - self.argparser.add_argument( - "--hex_hole_corner_radius", action="store", type=float, default=5, - help="The corner radius of the hexagonal dice holes, in mm") - self.argparser.add_argument( - "--magnet_diameter", action="store", type=float, default=6, - help="The diameter of magnets for holding the box closed, in mm") - - def diceCB(self): - t = self.thickness - xi = self.x - 2 * t - yi = self.y - 2 * t - xc = xi / 2 - yc = yi / 2 - cr = self.hex_hole_corner_radius - - # -4*t because there are four gaps across: - # 2 between the outer holes and the finger joints - # 2 between the outer holes and the center hole - # /6 because there are 6 apothems across, 2 for each hexagon - apothem = (min(xi, yi) - 4 * t) / 6 - r = apothem * 2 / math.sqrt(3) - - # dice - centers = [[xc, yc]] # start with one in the center - polar_r = 2 * apothem + t # the full width of a hexagon, plus a gap of t width - for i in range(6): - theta = i * math.pi / 3 # 60 degrees each step - centers.append( - [ - xc + polar_r * math.cos(theta), - yc + polar_r * math.sin(theta), - ] - ) - for center in centers: - self.regularPolygonHole(x=center[0], y=center[1], n=6, r=r, corner_radius=cr, a=30) - - # magnets - d = self.magnet_diameter - mo = t + d/2 - self.hole(mo, mo, d=d) - self.hole(xi-mo, mo, d=d) - - def render(self): - x, y, h, hl = self.x, self.y, self.h, self.lidheight - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - hl = self.adjustSize(hl) - - t = self.thickness - - hy = self.edges["O"].startwidth() - hy2 = self.edges["P"].startwidth() - - e1 = edges.CompoundEdge(self, "eF", (hy-t, h-hy+t)) - e2 = edges.CompoundEdge(self, "Fe", (h-hy+t, hy-t)) - e_back = ("F", e1, "F", e2) - - p = self.edges["o"].settings.pin_height - e_inner_1 = edges.CompoundEdge(self, "fe", (y-p, p)) - e_inner_2 = edges.CompoundEdge(self, "ef", (p, y-p)) - e_inner_topbot = ("f", e_inner_1, "f", e_inner_2) - - self.ctx.save() - - self.rectangularWall(x, y, e_inner_topbot, move="up", callback=[self.diceCB]) - self.rectangularWall(x, y, e_inner_topbot, move="up", callback=[self.diceCB]) - self.rectangularWall(x, h, "FFFF", ignore_widths=[1,2,5,6], move="up") - self.rectangularWall(x, h, e_back, move="up") - self.rectangularWall(x, hl, "FFFF", ignore_widths=[1,2,5,6], move="up") - self.rectangularWall(x, hl-hy2+t, "FFqF", move="up") - - self.ctx.restore() - self.rectangularWall(x, y, "ffff", move="right only") - - self.rectangularWall(y, x, "ffff", move="up") - self.rectangularWall(y, x, "ffff", move="up") - self.rectangularWall(y, hl-hy2+t, "Ffpf", ignore_widths=[5,6], move="up") - self.rectangularWall(y, h-hy+t, "OfFf", ignore_widths=[5,6], move="up") - self.rectangularWall(y, h-hy+t, "Ffof", ignore_widths=[5,6], move="up") - self.rectangularWall(y, hl-hy2+t, "PfFf", ignore_widths=[5,6], move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dinrailbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dinrailbox.py deleted file mode 100644 index ed9b2b3..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dinrailbox.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright (C) 2013-2020 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class DinRailEdge(edges.FingerHoleEdge): - - def __init__(self, boxes, settings, width=35.0, offset=0.0) -> None: - super().__init__(boxes, settings) - self.width = width - self.offset = offset - - def startwidth(self) -> float: - return 8 + self.settings.thickness - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - with self.saved_context(): - self.fingerHoles( - 0, self.burn + 8 + self.settings.thickness / 2, length, 0, - bedBolts=bedBolts, bedBoltSettings=bedBoltSettings) - - w = self.width - o = self.offset - l = length - self.polyline((l-w)/2-o, 45, 2.75*2**.5, 90, 2.75*2**.5, -45, .5, -90, - w+0.25, - -90, 1, 30, 5*2*3**-.5, 60, (l-w)/2+o-3.25) - - -class DinRailBox(Boxes): - """Box for DIN rail used in electrical junction boxes""" - - ui_group = "WallMounted" - - def latch(self, l, move=None): - - t = self.thickness - tw = l+3+6+t - th = 8 - - if self.move(tw, th, move, True): - return - - self.moveTo(tw, th, 180) - self.polyline(2, 90, 0, (-180, 1.5), 0, 90, l+1.2*t, 90, - 3, -90, 1, 30, 2*2*3**-.5, 90, 4.5*2*3**-.5, 60, - 4+1.25, 90, 4.5, -90, t+4, -90, 2, 90, l-.8*t-9, 90, 2, -90, 5+t, 90, 4, 90) - - self.move(tw, th, move) - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=.8) - - self.buildArgParser(x=70, y=90, h=60) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--rail_width", action="store", type=float, default=35., - help="width of the rail (typically 35 or 15mm)") - self.argparser.add_argument( - "--rail_offset", action="store", type=float, default=0., - help="offset of the rail from the middle of the box (in mm)") - - def spring(self): - t = self.thickness - l = min(self.x/2-1.5*t, 50) - self.moveTo(self.x/2-l, -6-t, 0) - self.polyline(l+0.525*t, 90 , 6, 90 , 1.1*t, 90, 3, -90, l-0.525*t, - 180, l-0.525*t, -90, 1+0.1*t, 90, t-0.5, -90, 2) - - def lid_lip(self, l, move=None): - t = self.thickness - tw, th = l+2, t+8 - - if self.move(tw, th, move, True): - return - self.moveTo(1, t) - self.edges["f"](l) - - poly = [0, 90, 6, -60, 0, (120, 2*3**-.5), 0, 30, 2, 90, 5, - (-180, .5), 5, 90] - self.polyline(*(poly+[l-2*3]+list(reversed(poly)))) - - self.move(tw, th, move) - - def lid_holes(self): - t = self.thickness - self.rectangularHole(0.55*t, 7, 1.1*t, 1.6) - self.rectangularHole(self.x-0.55*t, 7, 1.1*t, 1.6) - - def render(self): - # adjust to the variables you want in the local scope - x, y, h = self.x, self.y, self.h - w = self.rail_width - o = self.rail_offset - t = self.thickness - - self.rectangularWall(x, y, "EEEE", callback=[ - lambda:self.fingerHolesAt(.55*t, .05*t, y-.1*t, 90), None, - lambda:self.fingerHolesAt(.55*t, .05*t, y-.1*t, 90), None], - move="right", label="Lid") - - self.lid_lip(y-.1*t, move="rotated right") - self.lid_lip(y-.1*t, move="rotated right") - - self.rectangularWall(x, y, "ffff", - callback=[ - lambda:self.fingerHolesAt(0, (y-w)/2-0.5*t+o-9, x, 0)], - move="right", label="Back") - - # Change h edge to 8mm! - self.edges["f"].settings.setValues(t, False, edge_width=8) - dr = DinRailEdge(self, self.edges["f"].settings, w, o) - - self.rectangularWall(y, h, [dr, "F", "e", "F"], - ignore_widths=[1, 6], move="rotated right", - label="Left Side upsidedown") - self.rectangularWall(y, h, [dr, "F", "e", "F"], - ignore_widths=[1, 6], move="rotated mirror right", - label="Right Side") - self.rectangularWall(x, h, ["h", "f", "e", "f"], - ignore_widths=[1, 6], callback=[ - self.spring, None, self.lid_holes], - move="up", - label="Bottom") - self.rectangularWall(x, h, ["h", "f", "e", "f"], - callback=[None, None, self.lid_holes], - ignore_widths=[1, 6], move="up", - label="Top") - - - self.rectangularWall(x, 8, "feee", callback=[ - lambda:self.rectangularHole(x/2, 2.05-0.5*t, t, t+4.1)], move="up") - self.latch((y-w)/2+o, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/discrack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/discrack.py deleted file mode 100644 index f40adc1..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/discrack.py +++ /dev/null @@ -1,266 +0,0 @@ -# Copyright (C) 2019 chrysn -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from math import cos, pi, sin, sqrt - -from boxes import * - - -def offset_radius_in_square(squareside, angle, outset): - """From the centre of a square, rotate by an angle relative to the - vertical, move away from the center (down if angle = 0), and then in a - right angle until the border of the square. Return the length of that last - segment. - - Note that for consistency with other boxes.py methods, angle is given in - degree. - - >>> # Without rotation, it's always half the square length - >>> offset_radius_in_square(20, 0, 0) - 10.0 - >>> offset_radius_in_square(20, 0, 5) - 10.0 - >>> # Without offset, it's half square length divided by cos(angle) -- at - >>> # least before it hits the next wall - >>> offset_radius_in_square(20, 15, 0) # doctest:+ELLIPSIS - 10.35276... - >>> offset_radius_in_square(20, 45, 0) # doctest:+ELLIPSIS - 14.1421... - >>> # Positive angles make the segment initially shorter... - >>> offset_radius_in_square(20, 5, 10) < 10 - True - >>> # ... while negative angles make it longer. - >>> offset_radius_in_square(20, -5, 10) > 10 - True - """ - - if angle <= -90: - return offset_radius_in_square(squareside, angle + 180, outset) - if angle > 90: - return offset_radius_in_square(squareside, angle - 180, outset) - - angle = angle / 180 * pi - - step_right = outset * sin(angle) - step_down = outset * cos(angle) - - try: - len_right = (squareside / 2 - step_right) / cos(angle) - except ZeroDivisionError: - return squareside / 2 - - if angle == 0: - return len_right - if angle > 0: - len_up = (squareside / 2 + step_down) / sin(angle) - - return min(len_up, len_right) - else: # angle < 0 - len_down = - (squareside / 2 - step_down) / sin(angle) - - return min(len_down, len_right) - -class DiscRack(Boxes): - """A rack for storing disk-shaped objects vertically next to each other""" - - ui_group = "Shelf" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.buildArgParser(sx="20*10") - self.argparser.add_argument( - "--disc_diameter", action="store", type=float, default=150.0, - help="Disc diameter in mm") - self.argparser.add_argument( - "--disc_thickness", action="store", type=float, default=5.0, - help="Thickness of the discs in mm") - - self.argparser.add_argument( - "--lower_factor", action="store", type=float, default=0.75, - help="Position of the lower rack grids along the radius") - self.argparser.add_argument( - "--rear_factor", action="store", type=float, default=0.75, - help="Position of the rear rack grids along the radius") - - self.argparser.add_argument( - "--disc_outset", action="store", type=float, default=3.0, - help="Additional space kept between the disks and the outbox of the rack") - - # These can be parameterized, but the default value of pulling them up - # to the box front is good enough for so many cases it'd only clutter - # the user interface. - # - # The parameters can be resurfaced when there is something like rare or - # advanced settings. - ''' - self.argparser.add_argument( - "--lower_outset", action="store", type=float, default=0.0, - help="Space in front of the disk slits (0: automatic)") - self.argparser.add_argument( - "--rear_outset", action="store", type=float, default=0.0, - help="Space above the disk slits (0: automatic)") - ''' - - self.argparser.add_argument( - "--angle", action="store", type=float, default=18, - help="Backwards slant of the rack") - self.addSettingsArgs(edges.FingerJointSettings) - - def parseArgs(self, *args, **kwargs): - Boxes.parseArgs(self, *args, **kwargs) - self.lower_outset = self.rear_outset = 0 - - self.calculate() - - def calculate(self): - self.outer = self.disc_diameter + 2 * self.disc_outset - - r = self.disc_diameter / 2 - - # distance between radius line and front (or rear) end of the slit - self.lower_halfslit = r * sqrt(1 - self.lower_factor**2) - self.rear_halfslit = r * sqrt(1 - self.rear_factor**2) - - if True: # self.lower_outset == 0: # when lower_outset parameter is re-enabled - toplim = offset_radius_in_square(self.outer, self.angle, r * self.lower_factor) - # With typical positive angles, the lower surface of board will be limiting - bottomlim = offset_radius_in_square(self.outer, self.angle, r * self.lower_factor + self.thickness) - self.lower_outset = min(toplim, bottomlim) - self.lower_halfslit - - if True: # self.rear_outset == 0: # when rear_outset parameter is re-enabled - # With typical positive angles, the upper surface of board will be limiting - toplim = offset_radius_in_square(self.outer, -self.angle, r * self.rear_factor) - bottomlim = offset_radius_in_square(self.outer, -self.angle, r * self.rear_factor + self.thickness) - self.rear_outset = min(toplim, bottomlim) - self.rear_halfslit - - # front outset, space to radius, space to rear part, plus nothing as fingers extend out - self.lower_size = self.lower_outset + \ - self.lower_halfslit + \ - r * self.rear_factor - - self.rear_size = r * self.lower_factor + \ - self.rear_halfslit + \ - self.rear_outset - - self.warn_on_demand() - - def warn_on_demand(self): - warnings = [] - - # Are the discs supported on the outer ends? - - def word_thickness(length): - if length > 0: - return f"very thin ({length:.2g} mm at a thickness of {self.thickness:.2g} mm)" - if length < 0: - return "absent" - - if self.rear_outset < self.thickness: - warnings.append("Rear upper constraint is %s. Consider increasing the disc outset parameter, or move the angle away from 45°." % word_thickness(self.rear_outset)) - - if self.lower_outset < self.thickness: - warnings.append("Lower front constraint is %s. Consider increasing the disc outset parameter, or move the angle away from 45°." % word_thickness(self.lower_outset)) - - # Are the discs supported where the grids meet? - - r = self.disc_diameter / 2 - inner_lowerdistance = r * self.rear_factor - self.lower_halfslit - inner_reardistance = r * self.lower_factor - self.rear_halfslit - - if inner_lowerdistance < 0 or inner_reardistance < 0: - warnings.append("Corner is inside the disc radios, discs would not be supported. Consider increasing the factor parameters.") - - # Won't the type-H edge on the rear side make the whole contraption - # wiggle? - - max_slitlengthplush = offset_radius_in_square( - self.outer, self.angle, r * self.rear_factor + self.thickness) - slitlengthplush = self.rear_halfslit + self.thickness * ( 1 + - self.edgesettings['FingerJoint']['edge_width']) - - if slitlengthplush > max_slitlengthplush: - warnings.append("Joint would protrude from lower box edge. Consider increasing the the disc outset parameter, or move the angle away from 45°.") - - # Can the discs be removed at all? - # Does not need explicit checking, for Thales' theorem tells us that at - # the point where there is barely support in the corner, three contact - # points on the circle form just a semicircle and the discs can be - # inserted/removed. When we keep the other contact points and move the - # slits away from the corner, the disc gets smaller and thus will fit - # through the opening that is as wide as the diameter of the largest - # possible circle. - - # Act on warnings - - if warnings: - self.argparser.error("\n".join(warnings)) - - def sidewall_holes(self): - r = self.disc_diameter / 2 - - self.moveTo(self.outer/2, self.outer/2, -self.angle) - # can now move down to paint horizontal lower part, or right to paint - # vertical rear part - with self.saved_context(): - self.moveTo( - r * self.rear_factor, - -r * self.lower_factor - self.thickness/2, - 90) - self.fingerHolesAt(0, 0, self.lower_size) - with self.saved_context(): - self.moveTo( - r * self.rear_factor + self.thickness/2, - -r * self.lower_factor, - 0) - self.fingerHolesAt(0, 0, self.rear_size) - - if self.debug: - self.circle(0, 0, self.disc_diameter / 2) - - def _draw_slits(self, inset, halfslit): - total_x = 0 - - for x in self.sx: - center_x = total_x + x / 2 - - total_x += x - self.rectangularHole(inset, center_x, 2 * halfslit, self.disc_thickness) - if self.debug: - self.ctx.rectangle(inset - halfslit, center_x - x/2, 2 * halfslit, x) - - def lower_holes(self): - r = self.disc_diameter / 2 - inset = self.lower_outset + self.lower_halfslit - - self._draw_slits(inset, self.lower_halfslit) - - def rear_holes(self): - r = self.disc_diameter / 2 - inset = r * self.lower_factor - - self._draw_slits(inset, self.rear_halfslit) - - def render(self): - o = self.outer - - self.lower_factor = min(self.lower_factor, 0.99) - self.rear_factor = min(self.rear_factor, 0.99) - - self.rectangularWall(o, o, "eeee", move="right", callback=[self.sidewall_holes]) - self.rectangularWall(o, o, "eeee", move="right mirror", callback=[self.sidewall_holes]) - - self.rectangularWall(self.lower_size, sum(self.sx), "fffe", move="right", callback=[self.lower_holes]) - self.rectangularWall(self.rear_size, sum(self.sx), "fefh", move="right", callback=[self.rear_holes]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dispenser.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dispenser.py deleted file mode 100644 index c624b04..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dispenser.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FrontEdge(edges.BaseEdge): - """An edge with room to get your fingers around cards""" - def __call__(self, length, **kw): - depth = self.settings.y * 2 / 3 - t = self.settings.thickness - r = min(depth-t, length/4) - self.edge(length/4-t, tabs=2) - self.corner(90, t) - self.edge(depth-t-r, tabs=2) - self.corner(-90, r) - self.edge(length/2 - 2*r) - self.corner(-90, r) - self.edge(depth-t-r, tabs=2) - self.corner(90, t) - self.edge(length/4-t, tabs=2) - - -class Dispenser(Boxes): - """Dispenser for stackable (flat) items of same size""" - - description = """Set *bottomheight* to 0 for a wall mounting variant. -Please add mounting holes yourself.""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=100, y=100, h=100) - - self.argparser.add_argument( - "--slotheight", action="store", type=float, default=10.0, - help="height of the dispenser slot / items (in mm)") - self.argparser.add_argument( - "--bottomheight", action="store", type=float, default=0.0, - help="height underneath the dispenser (in mm)") - self.argparser.add_argument( - "--sideedges", action="store", type=ArgparseEdgeType("Fh"), - choices=list("Fh"), default="F", - help="edges used for holding the front panels and back") - - - def render(self): - x, y, h, hs = self.x, self.y, self.h, self.slotheight - hb = self.bottomheight - t = self.thickness - - se = self.sideedges - fe = FrontEdge(self, self) - - hb = max(0, hb-self.edges["š"].spacing()) - th = h + (hb+t if hb else 0.0) - hh = hb + 0.5*t - - with self.saved_context(): - self.rectangularWall(x, y, [fe, "f", "f", "f"], - label="Floor", move="right") - self.rectangularWall(x, y, "eeee", label="Lid bottom", move="right") - self.rectangularWall(x, y, "EEEE", label="Lid top", move="right") - - - self.rectangularWall(x, y, "ffff", move="up only") - - if hb: - frontedge = edges.CompoundEdge(self, "Ef", (hb+t+hs, h-hs)) - self.rectangularWall( - y, th, ("š", frontedge, "e", "f"), ignore_widths=[6], - callback=[lambda:self.fingerHolesAt(0, hh, y, 0)], - label="Left wall", move="right mirror") - self.rectangularWall( - x, th, ["š", se, "e", se], ignore_widths=[1, 6], - callback=[lambda:self.fingerHolesAt(0, hh, x, 0)], - label="Back wall", move="right") - self.rectangularWall( - y, th, ("š", frontedge, "e", "f"), ignore_widths=[6], - callback=[lambda:self.fingerHolesAt(0, hh, y, 0)], - label="Right wall", move="right") - - else: - frontedge = edges.CompoundEdge(self, "Ef", (hs, h-hs)) - self.rectangularWall( - y, th, ("h", frontedge, "e", "f"), - label="Left wall", ignore_widths=[6], move="right mirror") - self.rectangularWall( - x, th, ["h", se, "e", se], ignore_widths=[1, 6], - label="Back wall", move="right") - self.rectangularWall( - y, th, ("h", frontedge, "e", "f"), - label="Right wall", ignore_widths=[6], move="right") - - self.rectangularWall(x/3, h-hs, "eee" + se, - label="Left front", move="right") - self.rectangularWall(x/3, h-hs, "eee" + se, - label="Right front", move="mirror right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/display.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/display.py deleted file mode 100644 index 3f4e429..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/display.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Display(Boxes): - """Display for flyers or leaflets""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.buildArgParser(x=150., h=200.0) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--radius", action="store", type=float, default=5., - help="radius of the corners in mm") - self.argparser.add_argument( - "--angle", action="store", type=float, default=0., - help="greater zero for top wider as bottom") - - - def render(self): - # adjust to the variables you want in the local scope - x, h, r = self.x, self.h, self.radius - a = self.angle - t = self.thickness - - self.roundedPlate(0.7*x, x, r, "e", extend_corners=False, move="up") - - oh = 1.2*h-2*r - if a > 0: - self.moveTo(math.sin(math.radians(a))*oh) - self.rectangularHole(x/2, h*0.2, 0.7*x+0.1*t, 1.3*t) - self.moveTo(r) - self.polyline(x-2*r, (90-a, r), oh, (90+a, r), - x-2*r+2*math.sin(math.radians(a))*oh, - (90+a, r), oh, (90-a, r)) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/displaycase.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/displaycase.py deleted file mode 100644 index 5ec363d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/displaycase.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# Copyright (C) 2018 Alexander Bulimov -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class DisplayCase(Boxes): - """Fully closed box intended to be cut from transparent acrylics and to serve as a display case.""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--overhang", - action="store", - type=float, - default=2, - help="overhang for joints in mm", - ) - - def render(self): - - x, y, h = self.x, self.y, self.h - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - - t = self.thickness - - d2 = edges.Bolts(2) - d3 = edges.Bolts(3) - - d2 = d3 = None - - self.rectangularWall(x, h, "ffff", bedBolts=[d2] * 4, move="right", label="Wall 1") - self.rectangularWall(y, h, "fFfF", bedBolts=[d3, d2, d3, d2], move="up", label="Wall 2") - self.rectangularWall(y, h, "fFfF", bedBolts=[d3, d2, d3, d2], label="Wall 4") - self.rectangularWall(x, h, "ffff", bedBolts=[d2] * 4, move="left up", label="Wall 3") - - self.flangedWall(x, y, "FFFF", flanges=[self.overhang] * 4, move="right", label="Top") - self.flangedWall(x, y, "FFFF", flanges=[self.overhang] * 4, label="Bottom") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/displayshelf.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/displayshelf.py deleted file mode 100644 index 5a9eeba..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/displayshelf.py +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class DisplayShelf(Boxes): - """Shelf with slanted floors""" - - ui_group = "Shelf" - - # arguments/properties - num: int - x: float - y: float - h: float - angle: float - thickness: float - radians: float - sl: float - front_wall_height: float - include_back: bool - slope_top: bool - outside: bool - divider_wall_height: float - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - self.buildArgParser(sx="400", y=100, h=300, outside=True) - self.argparser.add_argument( - "--num", action="store", type=int, default=3, - help="number of shelves") - self.argparser.add_argument( - "--front_wall_height", action="store", type=float, default=20.0, - help="height of front walls") - self.argparser.add_argument( - "--angle", action="store", type=float, default=30.0, - help="angle of floors (negative values for slanting backwards)") - self.argparser.add_argument( - "--include_back", action="store", type=boolarg, default=False, - help="Include panel on the back of the shelf") - self.argparser.add_argument( - "--slope_top", action="store", type=boolarg, default=False, - help="Slope the sides and the top by front wall height") - self.argparser.add_argument( - "--divider_wall_height", action="store", type=float, default=20.0, - help="height of divider walls") - - def generate_finger_holes(self): - t = self.thickness - a = self.radians - hs = (self.sl + t) * math.sin(a) + math.cos(a) * t - for i in range(self.num): - pos_x = abs(0.5 * t * math.sin(a)) - pos_y = hs - math.cos(a) * 0.5 * t + i * (self.h - abs(hs)) / (self.num - 0.5) - if a < 0: - pos_y += -math.sin(a) * self.sl - self.fingerHolesAt(pos_x, pos_y, self.sl, -self.angle) - pos_x += math.cos(-a) * (self.sl + 0.5 * t) + math.sin(a) * 0.5 * t - pos_y += math.sin(-a) * (self.sl + 0.5 * t) + math.cos(a) * 0.5 * t - self.fingerHolesAt(pos_x, pos_y, self.front_wall_height, 90 - self.angle) - - def generate_sloped_sides(self, width, height): - top_segment_height = height / self.num - a = self.radians - - # Maximum size to cut out - vertical_cut = top_segment_height - self.front_wall_height - hypotenuse = vertical_cut / math.sin(a) - horizontal_cut = math.sqrt((hypotenuse ** 2) - (vertical_cut ** 2)) - - if horizontal_cut > width: - # Shrink the cut to keep the full height - horizontal_cut = width - 1 # keep a 1mm edge on the top - vertical_cut = horizontal_cut * math.tan(a) - hypotenuse = math.sqrt((horizontal_cut ** 2) + (vertical_cut ** 2)) - - top = width - horizontal_cut - front = height - vertical_cut - - borders = [width, 90, front, 90 - self.angle, hypotenuse, self.angle, top, 90, height, 90] - edges = 'eeeef' if self.include_back else 'e' - self.polygonWall(borders, edge=edges, callback=[self.generate_finger_holes], move="up", label="left side") - self.polygonWall(borders, edge=edges, callback=[self.generate_finger_holes], move="up", label="right side") - - def generate_rectangular_sides(self, width, height): - edges = "eeee" - if self.include_back: - edges = "eeef" - self.rectangularWall(width, height, edges, callback=[self.generate_finger_holes], move="up", label="left side") - self.rectangularWall(width, height, edges, callback=[self.generate_finger_holes], move="up", label="right side") - - def generate_shelve_finger_holes(self): - t = self.thickness - pos_x = -0.5 * t - for x in self.sx[:-1]: - pos_x += x + t - self.fingerHolesAt(pos_x, 0, self.sl, 90) - - def generate_front_lip_finger_holes(self): - t = self.thickness - height = self.front_wall_height - if self.divider_wall_height < height: - height = self.divider_wall_height - pos_x = -0.5 * t - for x in self.sx[:-1]: - pos_x += x + t - self.fingerHolesAt(pos_x, 0, height, 90) - - def generate_shelves(self): - if self.front_wall_height: - for i in range(self.num): - self.rectangularWall( - self.x, - self.sl, - "ffef", - callback=[self.generate_shelve_finger_holes], - move="up", - label=f"shelf {i + 1}" - ) - self.rectangularWall( - self.x, - self.front_wall_height, - "Ffef", - callback=[self.generate_front_lip_finger_holes], - move="up", - label=f"front lip {i + 1}" - ) - else: - for i in range(self.num): - self.rectangularWall( - self.x, - self.sl, - "Efef", - callback=[self.generate_shelve_finger_holes], - move="up", - label=f"shelf {i + 1}" - ) - - def generate_dividers(self): - edges_ = "feee" - if self.front_wall_height: - edges_ = "ffee" - if self.divider_wall_height > self.front_wall_height: - edges_ = [ - "f", - edges.CompoundEdge(self, "fe", [self.front_wall_height, self.divider_wall_height - self.front_wall_height]), - "e", - "e" - ] - - for i in range(self.num): - for j in range(len(self.sx) -1): - self.rectangularWall(self.sl, self.divider_wall_height, edges_, move="up", label=f"divider {j + 1} for shelf {i + 1}") - - def render(self): - # adjust to the variables you want in the local scope - sx, y, h = self.sx, self.y, self.h - front = self.front_wall_height - thickness = self.thickness - - if self.outside: - self.sx = sx = self.adjustSize(sx) - if self.include_back: - self.y = y = self.adjustSize(y, False) - - self.x = x = sum(sx) + thickness * (len(sx) - 1) - self.radians = a = math.radians(self.angle) - self.sl = (y - (thickness * (math.cos(a) + abs(math.sin(a)))) - max(0, math.sin(a) * front)) / math.cos(a) - - # render your parts here - if self.slope_top: - self.generate_sloped_sides(y, h) - else: - self.generate_rectangular_sides(y, h) - - self.generate_shelves() - self.generate_dividers() - - if self.include_back: - self.rectangularWall(x, h, "eFeF", label="back wall", move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dividertray.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dividertray.py deleted file mode 100644 index e3d28ec..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/dividertray.py +++ /dev/null @@ -1,640 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from __future__ import annotations - -import math -from functools import partial - -from boxes import Boxes, boolarg, edges, lids - - -class NotchSettings(edges.Settings): - """Settings for Notches on the Dividers""" - - absolute_params = { - "upper_radius": 1, - "lower_radius": 8, - "depth": 15, - } - - -class SlotSettings(edges.Settings): - """Settings for Divider Slots - - Values: - - * absolute - * depth : 20 : depth of the slot in mm - * angle : 0 : angle at which slots are generated, in degrees. 0° is vertical. - * radius : 2 : radius of the slot entrance in mm - * extra_slack : 0.2 : extra slack (in addition to thickness and kerf) to help insert dividers in mm""" - - absolute_params = { - "depth": 20, - "angle": 0, - "radius": 2, - "extra_slack": 0.2, - } - - -class DividerSettings(edges.Settings): - """Settings for Dividers - Values: - - * absolute_params - - * bottom_margin : 0 : margin between box's bottom and divider's in mm - - * relative (in multiples of thickness) - - * play : 0.05 : play to avoid them clamping onto the walls (in multiples of thickness) - """ - - absolute_params = { - "bottom_margin": 0, - } - relative_params = { - "play": 0.05, - } - - -class DividerTray(Boxes): - """Divider tray - rows and dividers""" - - description = """ -Adding '0:' at the start of the sy parameter adds a slot at the very back. Adding ':0' at the end of sy adds a slot meeting the bottom at the very front. This is especially useful if slot angle is set above zero. - -There are 4 different sets of dividers rendered: - -* With asymmetric tabs so the tabs fit on top of each other -* With tabs of half wall thickness that can go side by side -* With tabs of a full wall thickness -* One single divider spanning across all columns - -You will likely need to cut each of the dividers you want multiple times. -""" - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.HandleEdgeSettings) - self.addSettingsArgs(lids.LidSettings) - self.buildArgParser("sx", "sy", "h", "outside") - self.addSettingsArgs(SlotSettings) - self.addSettingsArgs(NotchSettings) - self.addSettingsArgs(DividerSettings) - self.argparser.add_argument( - "--notches_in_wall", - type=boolarg, - default=True, - help="generate the same notches on the walls that are on the dividers", - ) - self.argparser.add_argument( - "--left_wall", - type=boolarg, - default=True, - help="generate wall on the left side", - ) - self.argparser.add_argument( - "--right_wall", - type=boolarg, - default=True, - help="generate wall on the right side", - ) - self.argparser.add_argument( - "--bottom", type=boolarg, default=False, help="generate wall on the bottom", - ) - self.argparser.add_argument( - "--handle", type=boolarg, default=False, help="add handle to the bottom", - ) - - def render(self): - - side_walls_number = len(self.sx) - 1 + sum([self.left_wall, self.right_wall]) - if side_walls_number == 0: - raise ValueError("You need at least one side wall to generate this tray") - - # We need to adjust height before slot generation - if self.outside: - if self.bottom: - self.h -= self.thickness - else: - # If the parameter 'h' is the inner height of the content itself, - # then the actual tray height needs to be adjusted with the angle - self.h = self.h * math.cos(math.radians(self.Slot_angle)) - - slot_descriptions = SlotDescriptionsGenerator().generate_all_same_angles( - self.sy, - self.thickness, - self.Slot_extra_slack, - self.Slot_depth, - self.h, - self.Slot_angle, - self.Slot_radius, - ) - - # If measures are outside, we need to readjust slots afterwards - if self.outside: - self.sx = self.adjustSize(self.sx, self.left_wall, self.right_wall) - side_wall_target_length = sum(self.sy) - 2 * self.thickness - slot_descriptions.adjust_to_target_length(side_wall_target_length) - - self.ctx.save() - - # Facing walls (outer) with finger holes to support side walls - facing_wall_length = sum(self.sx) + self.thickness * (len(self.sx) - 1) - side_edge = lambda with_wall: "F" if with_wall else "e" - bottom_edge = lambda with_wall, with_handle: ("f" if with_handle else "F") if with_wall else "e" - upper_edge = ( - DividerNotchesEdge( - self, - list(reversed(self.sx)), - ) - if self.notches_in_wall - else "e" - ) - for _ in range(2): - self.rectangularWall( - facing_wall_length, - self.h, - [ - bottom_edge(self.bottom, _ and self.handle), - side_edge(self.right_wall), - upper_edge, - side_edge(self.left_wall), - ], - callback=[partial(self.generate_finger_holes, self.h)], - move="up", label = "Front" if _ else "Back", - ) - - # Side walls (outer & inner) with slots to support dividers - side_wall_length = slot_descriptions.total_length() - for _ in range(side_walls_number): - if _ < side_walls_number - (len(self.sx) - 1): - be = "F" if self.bottom else "e" - else: - be = "f" if self.bottom else "e" - se = DividerSlotsEdge(self, slot_descriptions.descriptions) - self.rectangularWall( - side_wall_length, self.h, [be, "f", se, "f"], move="up", label="Sidepiece " + str(_ + 1) - ) - - self.lid(facing_wall_length, side_wall_length) - - # Switch to right side of the file - self.ctx.restore() - self.rectangularWall( - max(facing_wall_length, side_wall_length), self.h, "ffff", move="right only", label="invisible" - ) - - # Bottom piece. - if self.bottom: - self.rectangularWall( - facing_wall_length, - side_wall_length, - [ - "f", - "f" if self.right_wall else "e", - "Y" if self.handle else "f", - "f" if self.left_wall else "e", - ], - callback=[partial(self.generate_finger_holes, side_wall_length)], - move="up", label="Bottom", - ) - - # Dividers - divider_height = ( - # h, with angle adjustment - self.h / math.cos(math.radians(self.Slot_angle)) - # removing what exceeds in the width of the divider - - self.thickness * math.tan(math.radians(self.Slot_angle)) - # with margin - - self.Divider_bottom_margin - ) - self.generate_divider( - self.sx, divider_height, "up", - first_tab_width=self.thickness if self.left_wall else 0, - second_tab_width=self.thickness if self.right_wall else 0 - ) - for tabs, asymmetric_tabs in [(self.thickness, None), - (self.thickness / 2, None), - (self.thickness, 0.5),]: - with self.saved_context(): - for i, length in enumerate(self.sx): - self.generate_divider( - [length], - divider_height, - "right", - first_tab_width=tabs if self.left_wall or i>0 else 0, - second_tab_width=tabs if self.right_wall or i<(len(self.sx) - 1) else 0, - asymmetric_tabs=asymmetric_tabs, - ) - if asymmetric_tabs: - self.moveTo(-tabs, self.spacing) - self.generate_divider(self.sx, divider_height, "up only") - - if self.debug: - debug_info = ["Debug"] - debug_info.append(f"Slot_edge_outer_length:{slot_descriptions.total_length() + 2 * self.thickness:.2f}") - debug_info.append( - "Slot_edge_inner_lengths:{}".format( - str.join( - "|", - [ - f"{e.useful_length():.2f}" - for e in slot_descriptions.get_straight_edges() - ], - ) - ) - ) - debug_info.append(f"Face_edge_outer_length:{facing_wall_length + self.thickness * sum([self.left_wall, self.right_wall]):.2f}") - debug_info.append("Face_edge_inner_lengths:{}".format(str.join("|", [f"{e:.2f}" for e in self.sx]))) - debug_info.append(f"Tray_height:{self.h:.2f}") - debug_info.append(f"Content_height:{self.h / math.cos(math.radians(self.Slot_angle)):.2f}") - self.text(str.join("\n", debug_info), x=5, y=5, align="bottom left") - - def generate_finger_holes(self, length): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, length) - - def generate_divider( - self, widths, height, move, - first_tab_width=0, second_tab_width=0, - asymmetric_tabs=None): - total_width = sum(widths) + (len(widths)-1) * self.thickness + first_tab_width + second_tab_width - - if self.move(total_width, height, move, True): - return - - play = self.Divider_play - left_tab_height = right_tab_height = self.Slot_depth - if asymmetric_tabs: - left_tab_height = left_tab_height * asymmetric_tabs - play - right_tab_height = right_tab_height * (1 - asymmetric_tabs) - - # Upper: first tab width - if asymmetric_tabs: - self.moveTo(first_tab_width - play) - else: - self.edge(first_tab_width - play) - # Upper edge with a finger notch - for nr, width in enumerate(widths): - if nr > 0: - self.edge(self.thickness) - DividerNotchesEdge( - self, - [width], - )(width) - - self.polyline( - # Upper: second tab width if needed - second_tab_width - play, - # First side, with tab depth only if there is 2 walls - 90, - left_tab_height, - 90, - second_tab_width, - -90, - height - left_tab_height, - 90, - ) - # Lower edge - for width in reversed(widths[1:]): - self.polyline( - width - 2 * play, - 90, - height - self.Slot_depth, - -90, - self.thickness + 2 * play, - -90, - height - self.Slot_depth, - 90, - ) - - self.polyline( - # Second side tab - widths[0] - 2 * play, - 90, - height - self.Slot_depth, - -90, - first_tab_width, - 90, - right_tab_height, - 90 - ) - if asymmetric_tabs: - self.polyline( - first_tab_width - play, - -90, - self.Slot_depth-right_tab_height, - 90 - ) - - # Move for next piece - self.move(total_width, height, move, label="Divider") - - -class SlottedEdgeDescriptions: - def __init__(self) -> None: - self.descriptions: list[str] = [] - - def add(self, description: str) -> None: - self.descriptions.append(description) - - def get_straight_edges(self): - return [x for x in self.descriptions if isinstance(x, StraightEdgeDescription)] - - def get_last_edge(self): - return self.descriptions[-1] - - def adjust_to_target_length(self, target_length): - actual_length = sum([d.tracing_length() for d in self.descriptions]) - compensation = actual_length - target_length - - compensation_ratio = compensation / sum( - [d.asked_length for d in self.get_straight_edges()] - ) - - for edge in self.get_straight_edges(): - edge.outside_ratio = 1 - compensation_ratio - - def total_length(self): - return sum([x.tracing_length() for x in self.descriptions]) - - -class StraightEdgeDescription: - def __init__( - self, - asked_length, - round_edge_compensation=0, - outside_ratio=1, - angle_compensation=0, - ) -> None: - self.asked_length = asked_length - self.round_edge_compensation = round_edge_compensation - self.outside_ratio = outside_ratio - self.angle_compensation = angle_compensation - - def __repr__(self) -> str: - return f"StraightEdgeDescription({self.asked_length}, round_edge_compensation={self.round_edge_compensation}, angle_compensation={self.angle_compensation}, outside_ratio={self.outside_ratio})" - - def tracing_length(self): - """ - How much length should take tracing this straight edge - """ - return ( - (self.asked_length * self.outside_ratio) - - self.round_edge_compensation - + self.angle_compensation - ) - - def useful_length(self): - """ - Part of the length which might be used by the content of the tray - """ - return self.asked_length * self.outside_ratio - - -class Memoizer(dict): - def __init__(self, computation) -> None: - self.computation = computation - - def __missing__(self, key): - res = self[key] = self.computation(key) - return res - - -class SlotDescription: - _div_by_cos_cache = Memoizer(lambda a: 1 / math.cos(math.radians(a))) - _tan_cache = Memoizer(lambda a: math.tan(math.radians(a))) - - def __init__( - self, width, depth=20, angle=0, radius=0, start_radius=None, end_radius=None - ) -> None: - self.depth = depth - self.width = width - self.start_radius = radius if start_radius is None else start_radius - self.end_radius = radius if end_radius is None else end_radius - self.angle = angle - - def __repr__(self) -> str: - return f"SlotDescription({self.width}, depth={self.depth}, angle={self.angle}, start_radius={self.start_radius}, end_radius={self.end_radius})" - - def _div_by_cos(self): - return SlotDescription._div_by_cos_cache[self.angle] - - def _tan(self): - return SlotDescription._tan_cache[self.angle] - - def angle_corrected_width(self): - """ - returns how much width is the slot when measured horizontally, since the angle makes it bigger. - It's the same as the slot entrance width when radius is 0°. - """ - return self.width * self._div_by_cos() - - def round_edge_start_correction(self): - """ - returns by how much we need to stop tracing our straight lines at the start of the slot - in order to do a curve line instead - """ - return self.start_radius * (self._div_by_cos() - self._tan()) - - def round_edge_end_correction(self): - """ - returns by how much we need to stop tracing our straight lines at the end of the slot - in order to do a curve line instead - """ - return self.end_radius * (self._div_by_cos() + self._tan()) - - def _depth_angle_correction(self): - """ - The angle makes one side of the slot deeper than the other. - """ - extra_depth = self.width * self._tan() - return extra_depth - - def corrected_start_depth(self): - """ - Returns the depth of the straight part of the slot starting side - """ - extra_depth = self._depth_angle_correction() - return self.depth + max(0, extra_depth) - self.round_edge_start_correction() - - def corrected_end_depth(self): - """ - Returns the depth of the straight part of the slot ending side - """ - extra_depth = self._depth_angle_correction() - return self.depth + max(0, -extra_depth) - self.round_edge_end_correction() - - def tracing_length(self): - """ - How much length this slot takes on an edge - """ - return ( - self.round_edge_start_correction() - + self.angle_corrected_width() - + self.round_edge_end_correction() - ) - - -class SlotDescriptionsGenerator: - def generate_all_same_angles( - self, sections, thickness, extra_slack, depth, height, angle, radius=2, - ): - width = thickness + extra_slack - - descriptions = SlottedEdgeDescriptions() - - # Special case: if first slot start at 0, then radius is 0 - first_correction = 0 - current_section = 0 - if sections[0] == 0: - slot = SlotDescription( - width, depth=depth, angle=angle, start_radius=0, end_radius=radius, - ) - descriptions.add(slot) - first_correction = slot.round_edge_end_correction() - current_section += 1 - - first_length = sections[current_section] - current_section += 1 - descriptions.add( - StraightEdgeDescription( - first_length, round_edge_compensation=first_correction - ) - ) - - for l in sections[current_section:]: - slot = SlotDescription(width, depth=depth, angle=angle, radius=radius,) - - # Fix previous edge length - previous_edge = descriptions.get_last_edge() - previous_edge.round_edge_compensation += slot.round_edge_start_correction() - - # Add this slot - descriptions.add(slot) - - # Add the straight edge after this slot - descriptions.add( - StraightEdgeDescription(l, slot.round_edge_end_correction()) - ) - - # We need to add extra space for the divider (or the actual content) - # to slide all the way down to the bottom of the tray in spite of walls - end_length = height * math.tan(math.radians(angle)) - descriptions.get_last_edge().angle_compensation += end_length - - return descriptions - - -class DividerNotchesEdge(edges.BaseEdge): - """Edge with multiple notches for easier access to dividers""" - - description = "Edge with multiple notches for easier access to dividers" - - def __init__(self, boxes, sx) -> None: - - super().__init__(boxes, None) - - self.sx = sx - - def __call__(self, _, **kw): - first = True - for width in self.sx: - if first: - first = False - else: - self.edge(self.thickness) - self.edge_with_notch(width) - - def edge_with_notch(self, width): - # width (with notch if possible) - upper_third = ( - width - 2 * self.Notch_upper_radius - 2 * self.Notch_lower_radius - ) / 3 - if upper_third > 0: - straightHeight = ( - self.Notch_depth - self.Notch_upper_radius - self.Notch_lower_radius - ) - self.polyline( - upper_third, - (90, self.Notch_upper_radius), - straightHeight, - (-90, self.Notch_lower_radius), - upper_third, - (-90, self.Notch_lower_radius), - straightHeight, - (90, self.Notch_upper_radius), - upper_third, - ) - else: - # if there isn't enough room for the radius, we don't use it - self.edge(width) - - -class DividerSlotsEdge(edges.BaseEdge): - """Edge with multiple angled rounded slots for dividers""" - - description = "Edge with multiple angled rounded slots for dividers" - - def __init__(self, boxes, descriptions) -> None: - - super().__init__(boxes, None) - - self.descriptions = descriptions - - def __call__(self, length, **kw): - - self.ctx.save() - - for description in self.descriptions: - if isinstance(description, SlotDescription): - self.do_slot(description) - elif isinstance(description, StraightEdgeDescription): - self.do_straight_edge(description) - - # rounding errors might accumulate : - # restore context and redo the move straight - self.ctx.restore() - self.moveTo(length) - - def do_straight_edge(self, straight_edge): - self.edge(straight_edge.tracing_length()) - - def do_slot(self, slot): - self.ctx.save() - - self.polyline( - 0, - (90 - slot.angle, slot.start_radius), - slot.corrected_start_depth(), - -90, - slot.width, - -90, - slot.corrected_end_depth(), - (90 + slot.angle, slot.end_radius), - ) - - # rounding errors might accumulate : - # restore context and redo the move straight - self.ctx.restore() - self.moveTo(slot.tracing_length()) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/doubleflexdoorbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/doubleflexdoorbox.py deleted file mode 100644 index 8eb3a60..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/doubleflexdoorbox.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math - -import boxes - - -class DoubleFlexDoorBox(boxes.Boxes): - """Box with two part lid with living hinges and round corners""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - boxes.Boxes.__init__(self) - self.addSettingsArgs(boxes.edges.FingerJointSettings) - self.addSettingsArgs(boxes.edges.FlexSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--radius", action="store", type=float, default=15, - help="Radius of the latch in mm") - self.argparser.add_argument( - "--latchsize", action="store", type=float, default=8, - help="size of latch in multiples of thickness") - - def flexBoxSide(self, x, y, r, callback=None, move=None): - t = self.thickness - ll = (x - 2*r) / 2 - self.latchsize - - if self.move(x+2*t, y+2*t, move, True): - return - - self.moveTo(t+r, t) - - for i, l in zip(range(2), (x, y)): - self.cc(callback, i) - self.edges["f"](l - 2 * r) - self.corner(90, r) - - self.cc(callback, 2) - self.edge(ll) - self.latch(self.latchsize) - self.latch(self.latchsize, reverse=True) - self.edge(ll) - - self.corner(90, r) - self.cc(callback, 3) - self.edges["f"](y - 2 * r) - self.corner(90, r) - - self.move(x+2*t, y+2*t, move) - - def surroundingWall(self, x, y, h, r, move=None): - t = self.thickness - c4 = math.pi * r * 0.5 - - tw = 2*x + 2*y - 8*r + 4*c4 - th = h + 2.5*t - - if self.move(tw, th, move, True): - return - - self.moveTo(0, 0.25*t, -90) - - self.latch(self.latchsize, False, True) - self.edge((x-2*r)/2 - self.latchsize, False) - if y - 2 * r < t: - self.edges["X"](2 * c4 + y - 2 * r, h + 2 * t) - else: - self.edges["X"](c4, h + 2 * t) - self.edges["F"](y - 2 * r, False) - self.edges["X"](c4, h + 2 * t) - self.edges["F"](x - 2 * r, False) - if y - 2 * r < t: - self.edges["X"](2 * c4 + y - 2 * r, h + 2 * t) - else: - self.edges["X"](c4, h + 2 * t) - self.edges["F"](y - 2 * r) - self.edges["X"](c4, h + 2 * t) - self.edge((x-2*r)/2 - self.latchsize, False) - self.latch(self.latchsize, False) - self.edge(h + 2 * t) - self.latch(self.latchsize, False, True) - self.edge((x-2*r)/2 - self.latchsize, False) - self.edge(c4) - self.edges["F"](y - 2 * r) - self.edge(c4) - self.edges["F"](x - 2 * r, False) - self.edge(c4) - self.edges["F"](y - 2 * r, False) - self.edge(c4) - self.edge((x-2*r)/2 - self.latchsize) - self.latch(self.latchsize, False, False) - self.edge(h + 2 * t) - - self.move(tw, th, move) - - def render(self): - - if self.outside: - self.x = self.adjustSize(self.x) - self.y = self.adjustSize(self.y) - self.h = self.adjustSize(self.h) - - t = self.thickness - self.latchsize *= t - x, y, h = self.x, self.y, self.h - r = self.radius or min(x - 2*self.latchsize, y) / 2.0 - r = min(r, y / 2.0) - self.radius = r = min(r, max(0, (x - 2*self.latchsize) / 2.0)) - - - # swap y and h for more consistent axis names - self.surroundingWall(x, h, y, r, move="up") - self.flexBoxSide(x, h, r, move="right") - self.flexBoxSide(x, h, r, move="mirror") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/drillbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/drillbox.py deleted file mode 100644 index 7306d60..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/drillbox.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import ArgparseEdgeType, Boxes, Color, edges -from boxes.lids import LidSettings, _TopEdge - - -class DrillBox(_TopEdge): - """A parametrized box for drills""" - - description = """![Multiple DrillBoxes](static/samples/DrillBoxes.jpg) """ - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, - space=3, finger=3, surroundingspaces=1) - self.addSettingsArgs(edges.RoundedTriangleEdgeSettings, outset=1) - self.addSettingsArgs(edges.StackableSettings) - self.addSettingsArgs(edges.MountingSettings) - self.addSettingsArgs(LidSettings) - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("eStG"), choices=list("eStG"), - default="e", help="edge type for top edge") - self.buildArgParser(sx="25*3", sy="60*4", sh="5:25:10", - bottom_edge="h") - self.argparser.add_argument( - "--holes", - action="store", - type=int, - default=3, - help="Number of holes for each size", - ) - self.argparser.add_argument( - "--firsthole", - action="store", - type=float, - default=1.0, - help="Smallest hole", - ) - self.argparser.add_argument( - "--holeincrement", - action="store", - type=float, - default=.5, - help="increment between holes", - ) - - def sideholes(self, l): - t = self.thickness - h = -0.5 * t - for d in self.sh[:-1]: - h += d + t - self.fingerHolesAt(0, h, l, angle=0) - - - def drillholes(self, description=False): - y = 0 - d = self.firsthole - for dy in self.sy: - x = 0 - for dx in self.sx: - iy = dy / self.holes - for k in range(self.holes): - self.hole(x + dx / 2, y + (k + 0.5) * iy, d=d + 0.05) - if description: - self.rectangularHole(x + dx / 2, y + dy / 2, dx - 2, dy - 2, color=Color.ETCHING) - self.text( - "%.1f" % d, - x + 2, - y + 2, - 270, - align="right", - fontsize=6, - color=Color.ETCHING, - ) - # TODO: make the fontsize dynamic to make the text fit in all cases - d += self.holeincrement - x += dx - y += dy - - def render(self): - x = sum(self.sx) - y = sum(self.sy) - - h = sum(self.sh) + self.thickness * (len(self.sh)-1) - b = self.bottom_edge - t1, t2, t3, t4 = self.topEdges(self.top_edge) - - self.rectangularWall( - x, h, [b, "f", t1, "F"], - ignore_widths=[1, 6], - callback=[lambda: self.sideholes(x)], move="right") - self.rectangularWall( - y, h, [b, "f", t2, "F"], callback=[lambda: self.sideholes(y)], - ignore_widths=[1, 6], - move="up") - self.rectangularWall( - y, h, [b, "f", t3, "F"], callback=[lambda: self.sideholes(y)], - ignore_widths=[1, 6]) - self.rectangularWall( - x, h, [b, "f", t4, "F"], - ignore_widths=[1, 6], - callback=[lambda: self.sideholes(x)], move="left up") - if b != "e": - self.rectangularWall(x, y, "ffff", move="right") - for d in self.sh[:-2]: - self.rectangularWall( - x, y, "ffff", callback=[self.drillholes], move="right") - self.rectangularWall( - x, y, "ffff", - callback=[lambda: self.drillholes(description=True)], - move="right") - self.lid(x, y, self.top_edge) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/drillstand.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/drillstand.py deleted file mode 100644 index 53ecc16..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/drillstand.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import boxes -from boxes import * - - -class DrillStand(Boxes): - """Box for drills with each compartment of a different height""" - - description = """Note: `sh` gives the height of the rows front to back. It though should have the same number of entries as `sy`. These heights are the one on the left side and increase throughout the row. To have each compartment a bit higher than the previous one the steps in `sh` should be a bit bigger than `extra_height`. - -Assembly: - -![Parts](static/samples/DrillStand-drawing.png) - -Start with putting the slots of the inner walls together. Be especially careful with adding the bottom. It is always asymmetrical and flush with the right/lower side while being a little short on the left/higher side to not protrude into the side wall. - -| | | -| ---- | ---- | -| ![Assembly inner walls](static/samples/DrillStand-assembly-1.jpg) | ![Assembly bottom](static/samples/DrillStand-assembly-2.jpg) | -| Then add the front and the back wall. | Add the very left and right walls last. | -| ![Assembly front and back](static/samples/DrillStand-assembly-3.jpg) | ![Assembly side walls](static/samples/DrillStand-assembly-4.jpg) | -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.StackableSettings, height=1.0, width=3) - self.addSettingsArgs(edges.FingerJointSettings) - - self.buildArgParser(sx="25*6", sy="10:20:30", sh="25:40:60") - self.argparser.add_argument( - "--extra_height", action="store", type=float, default=15.0, - help="height difference left to right") - - def yWall(self, nr, move=None): - t = self.thickness - x, sx, y, sy, sh = self.x, self.sx, self.y, self.sy, self.sh - eh = self.extra_height * (sum(sx[:nr])+ nr*t - t)/x - - tw, th = sum(sy) + t * len(sy) + t, max(sh) + eh - - if self.move(tw, th, move, True): - return - - self.moveTo(t) - self.polyline(y, 90) - self.edges["f"](sh[-1]+eh) - self.corner(90) - for i in range(len(sy)-1, 0, -1): - s1 = max(sh[i]-sh[i-1], 0) + 4*t - s2 = max(sh[i-1]-sh[i], 0) + 4*t - - self.polyline(sy[i], 90, s1, -90, t, -90, s2, 90) - self.polyline(sy[0], 90) - self.edges["f"](sh[0] + eh) - self.corner(90) - - self.move(tw, th, move) - - def sideWall(self, extra_height=0.0, foot_height=0.0, edges="šFf", move=None): - t = self.thickness - x, sx, y, sy, sh = self.x, self.sx, self.y, self.sy, self.sh - eh = extra_height - fh = foot_height - - edges = [self.edges.get(e, e) for e in edges] - - tw = sum(sy) + t * len(sy) + t - th = max(sh) + eh + fh + edges[0].spacing() - - if self.move(tw, th, move, True): - return - - self.moveTo(edges[0].margin()) - - edges[0](y+2*t) - self.edgeCorner(edges[0], "e") - self.edge(fh) - self.step(edges[1].startwidth() - t) - edges[1](sh[-1]+eh) - self.edgeCorner(edges[1], "e") - for i in range(len(sy)-1, 0, -1): - self.edge(sy[i]) - if sh[i] > sh[i-1]: - self.fingerHolesAt(0.5*t, self.burn, sh[i]+eh, 90) - self.polyline(t, 90, sh[i] - sh[i-1], -90) - else: - self.polyline(0, -90, sh[i-1] - sh[i], 90, t) - self.fingerHolesAt(-0.5*t, self.burn, sh[i-1]+eh) - self.polyline(sy[0]) - self.edgeCorner("e", edges[2]) - edges[2](sh[0]+eh) - self.step(t - edges[2].endwidth()) - self.polyline(fh) - self.edgeCorner("e", edges[0]) - - self.move(tw, th, move) - - def xWall(self, nr, move=None): - t = self.thickness - x, sx, y, sy, sh = self.x, self.sx, self.y, self.sy, self.sh - eh = self.extra_height - - tw, th = x + 2*t, sh[nr] + eh + t - - a = math.degrees(math.atan(eh / x)) - fa = 1 / math.cos(math.radians(a)) - - if self.move(tw, th, move, True): - return - - - self.moveTo(t, eh+t, -a) - - for i in range(len(sx)-1): - self.edges["f"](fa*sx[i]) - h = min(sh[nr - 1], sh[nr]) - s1 = h - 3.95*t + self.extra_height * (sum(sx[:i+1]) + i*t)/x - s2 = h - 3.95*t + self.extra_height * (sum(sx[:i+1]) + i*t + t)/x - - self.polyline(0, 90+a, s1, -90, t, -90, s2, 90-a) - self.edges["f"](fa*sx[-1]) - self.polyline(0, 90+a) - self.edges["f"](sh[nr]+eh) - self.polyline(0, 90, x, 90) - self.edges["f"](sh[nr]) - self.polyline(0, 90+a) - - self.move(tw, th, move) - - def xOutsideWall(self, h, edges="fFeF", move=None): - t = self.thickness - x, sx, y, sy, sh = self.x, self.sx, self.y, self.sy, self.sh - - edges = [self.edges.get(e, e) for e in edges] - eh = self.extra_height - - tw = x + edges[1].spacing() + edges[3].spacing() - th = h + eh + edges[0].spacing() + edges[2].spacing() - - a = math.degrees(math.atan(eh / x)) - fa = 1 / math.cos(math.radians(a)) - - if self.move(tw, th, move, True): - return - - - self.moveTo(edges[3].spacing(), eh+edges[0].margin(), -a) - - self.edge(t*math.tan(math.radians(a))) - if isinstance(edges[0], boxes.edges.FingerHoleEdge): - with self.saved_context(): - self.moveTo(0, 0, a) - self.fingerHolesAt( - 0, 1.5*t, x*fa - t*math.tan(math.radians(a)), -a) - self.edge(x*fa - t*math.tan(math.radians(a))) - elif isinstance(edges[0], boxes.edges.FingerJointEdge): - edges[0](x*fa - t*math.tan(math.radians(a))) - else: - raise ValueError("Only edges h and f supported: ") - self.corner(a) - self.edgeCorner(edges[0], "e", 90) - self.corner(-90) - self.edgeCorner("e", edges[1], 90) - edges[1](eh+h) - self.edgeCorner(edges[1], edges[2], 90) - edges[2](x) - self.edgeCorner(edges[2], edges[3], 90) - edges[3](h) - self.edgeCorner(edges[3], "e", 90) - self.corner(-90) - self.edgeCorner("e", edges[0], 90) - - self.moveTo(0, self.burn+edges[0].startwidth(), 0) - - for i in range(1, len(sx)): - posx = sum(sx[:i]) + i*t - 0.5 * t - length = h + self.extra_height * (sum(sx[:i]) + i*t - t)/x - self.fingerHolesAt(posx, h, length, -90) - - self.move(tw, th, move) - - def bottomCB(self): - t = self.thickness - x, sx, y, sy, sh = self.x, self.sx, self.y, self.sy, self.sh - eh = self.extra_height - - a = math.degrees(math.atan(eh / x)) - fa = 1 / math.cos(math.radians(a)) - - posy = -0.5 * t - for i in range(len(sy)-1): - posy += sy[i] + t - posx = -t * math.tan(math.radians(a)) # left side is clipped - for j in range(len(sx)): - self.fingerHolesAt(posx, posy, fa*sx[j], 0) - posx += fa*sx[j] + fa*t - - def render(self): - t = self.thickness - sx, sy, sh = self.sx, self.sy, self.sh - self.x = x = sum(sx) + len(sx)*t - t - self.y = y = sum(sy) + len(sy)*t - t - - bottom_angle = math.atan(self.extra_height / x) # radians - - self.xOutsideWall(sh[0], "hFeF", move="up") - for i in range(1, len(sy)): - self.xWall(i, move="up") - self.xOutsideWall(sh[-1], "hfef", move="up") - - self.rectangularWall(x/math.cos(bottom_angle)-t*math.tan(bottom_angle), y, "fefe", callback=[self.bottomCB], move="up") - - self.sideWall(foot_height=self.extra_height+2*t, move="right") - for i in range(1, len(sx)): - self.yWall(i, move="right") - self.sideWall(self.extra_height, 2*t, move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/edges.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/edges.py deleted file mode 100644 index 663873d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/edges.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Edges(Boxes): - """Print all registered Edge types""" - - webinterface = False - - def __init__(self) -> None: - Boxes.__init__(self) - - def render(self): - self.ctx = None - self._buildObjects() - chars = self.edges.keys() - for c in sorted(chars, key=lambda x:(x.lower(), x.isupper())): - print("%s %s - %s" %(c, self.edges[c].__class__.__name__, - self.edges[c].__doc__)) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/electronicsbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/electronicsbox.py deleted file mode 100644 index ad4f327..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/electronicsbox.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class ElectronicsBox(Boxes): - """Closed box with screw on top and mounting holes""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--triangle", action="store", type=float, default=25., - help="Sides of the triangles holding the lid in mm") - self.argparser.add_argument( - "--d1", action="store", type=float, default=2., - help="Diameter of the inner lid screw holes in mm") - self.argparser.add_argument( - "--d2", action="store", type=float, default=3., - help="Diameter of the lid screw holes in mm") - self.argparser.add_argument( - "--d3", action="store", type=float, default=3., - help="Diameter of the mounting screw holes in mm") - self.argparser.add_argument( - "--outsidemounts", action="store", type=boolarg, default=True, - help="Add external mounting points") - self.argparser.add_argument( - "--holedist", action="store", type=float, default=7., - help="Distance of the screw holes from the wall in mm") - - def wallxCB(self): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, self.triangle, 0) - self.fingerHolesAt(self.x, self.h-1.5*t, self.triangle, 180) - - def wallyCB(self): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, self.triangle, 0) - self.fingerHolesAt(self.y, self.h-1.5*t, self.triangle, 180) - - def render(self): - - t = self.thickness - self.h = h = self.h + 2*t # compensate for lid - x, y, h = self.x, self.y, self.h - d1, d2, d3 =self.d1, self.d2, self.d3 - hd = self.holedist - tr = self.triangle - trh = tr / 3. - - if self.outside: - self.x = x = self.adjustSize(x) - self.y = y = self.adjustSize(y) - self.h = h = h - 3*t - - self.rectangularWall(x, h, "fFeF", callback=[self.wallxCB], - move="right", label="Wall 1") - self.rectangularWall(y, h, "ffef", callback=[self.wallyCB], - move="up", label="Wall 2") - self.rectangularWall(y, h, "ffef", callback=[self.wallyCB], - label="Wall 4") - self.rectangularWall(x, h, "fFeF", callback=[self.wallxCB], - move="left up", label="Wall 3") - - if not self.outsidemounts: - self.rectangularWall(x, y, "FFFF", callback=[ - lambda:self.hole(hd, hd, d=d3)] *4, move="right", - label="Bottom") - else: - self.flangedWall(x, y, edges="FFFF", - flanges=[0.0, 2*hd, 0., 2*hd], r=hd, - callback=[ - lambda:self.hole(hd, hd, d=d3)] * 4, move='up', - label="Bottom") - self.rectangularWall(x, y, callback=[ - lambda:self.hole(trh, trh, d=d2)] * 4, move='up', label="Top") - - self.rectangularTriangle(tr, tr, "ffe", num=4, - callback=[None, lambda: self.hole(trh, trh, d=d1)]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/eurorackskiff.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/eurorackskiff.py deleted file mode 100644 index c5490b6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/eurorackskiff.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class EuroRackSkiff(Boxes): - """3U Height case with adjustable width and height and included rails""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("h") - self.argparser.add_argument( - "--hp", action="store", type=int, default=84, - help="Width of the case in HP") - - - def wallxCB(self, x): - t = self.thickness - - def wallyCB(self, y): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, y, 0) - - def railHoles(self): - for i in range(0, self.hp): - self.hole(i*5.08 + 2.54, 3, d=3.0) - - def render(self): - - t = self.thickness - h = self.h - y = self.hp * 5.08 - x = 128.5 - - - self.rectangularWall(y, 6, "feee", callback=[self.railHoles] , move="up") - self.rectangularWall(y, 6, "feee", callback=[self.railHoles] , move="up") - self.rectangularWall(x, h, "fFeF", callback=[lambda: self.wallxCB(x)], - move="right") - self.rectangularWall(y, h, "ffef", callback=[lambda: self.wallyCB(y)], move="up") - self.rectangularWall(y, h, "ffef", callback=[lambda: self.wallyCB(y)]) - self.rectangularWall(x, h, "fFeF", callback=[lambda: self.wallxCB(x)], - move="left up") - self.rectangularWall(x, y, "FFFF", callback=[], move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/fanhole.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/fanhole.py deleted file mode 100644 index e8ede93..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/fanhole.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FanHole(Boxes): - """Hole pattern for mounting a fan""" - - ui_group = "Holes" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.argparser.add_argument( - "--diameter", action="store", type=float, default=80, - help="diameter of the fan hole") - self.argparser.add_argument( - "--mounting_holes", action="store", type=float, default=3, - help="diameter of the fan mounting holes") - self.argparser.add_argument( - "--mounting_holes_inset", action="store", type=float, default=5, - help="distance of the fan mounting holes from the outside") - self.argparser.add_argument( - "--arms", action="store", type=int, default=10, - help="number of arms") - self.argparser.add_argument( - "--inner_disc", action="store", type=float, default=.2, - help="relative size of the inner disc") - self.argparser.add_argument( - "--style", action="store", type=str, default="CW Swirl", - choices=["CW Swirl", "CCW Swirl", "Hole"], - help="Style of the fan hole") - - - def arc(self, d, a): - r = abs(1/math.cos(math.radians(90-a/2))*d/2) - self.corner(-a/2) - self.corner(a, r) - self.corner(-a/2) - - def swirl(self, r, ri_rel=.1, n=20): - - d = 2*r - #r = d/2 - ri = ri_rel * r - - ai = 90 - ao = 360/n * 0.8 - # angle going in - a1 = math.degrees(math.atan( - ri*math.sin(math.radians(ai)) / - (r - ri*math.cos(math.radians(ai))))) - d1= (ri*math.sin(math.radians(ai))**2 + - (r - ri*math.cos(math.radians(ai)))**2)**.5 - d2= (ri*math.sin(math.radians(ai-ao))**2 + - (r - ri*math.cos(math.radians(ai-ao)))**2)**.5 - - # angle coming out - a_i2 = math.degrees(math.atan( - (r*math.sin(math.radians(ao)) - ri*math.sin(math.radians(ai))) / - (r*math.cos(math.radians(ao)) - ri*math.cos(math.radians(ai))))) - a3 = a1 + a_i2 - a2 = 90 + a_i2 - ao - - self.moveTo(0, -r, 180) - - for i in range(n): - with self.saved_context(): - self.corner(-ao, r) - self.corner(-a2) - self.arc(d2, -90) - self.corner(-180+a3) - self.arc(d1, 85) - self.corner(-90-a1) - - self.moveArc(-360./n, r) - - def render(self): - r_h = self.mounting_holes / 2 - d = self.diameter - inset = self.mounting_holes_inset - - for px in (inset, d-inset): - for py in (inset, d-inset): - self.hole(px, py, r_h) - self.moveTo(d/2, d/2) - print(self.style) - if self.style == "CW Swirl": - self.ctx.scale(-1, 1) - self.swirl(d/2, self.inner_disc, self.arms) - elif self.style == "CCW Swirl": - self.swirl(d/2, self.inner_disc, self.arms) - else: #Hole - self.hole(0, 0, d=d) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/filamentspool.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/filamentspool.py deleted file mode 100644 index 848c5aa..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/filamentspool.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.generators.bayonetbox import BayonetBox - - -class FilamentSpool(BayonetBox): - """A two part spool for 3D printing filament""" - - description = """ -Use small nails to properly align the pieces of the bayonet latch. Glue the parts of the bayonet latch before assembling the "axle". The inner parts go at the side and the outer parts at the inside of the axle. -![opened spool](static/samples/FilamentSpool-2.jpg)""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - self.buildArgParser(h=48) - self.argparser.add_argument( - "--outer_diameter", action="store", type=float, default=200.0, - help="diameter of the flanges") - self.argparser.add_argument( - "--inner_diameter", action="store", type=float, default=100.0, - help="diameter of the center part") - self.argparser.add_argument( - "--axle_diameter", action="store", type=float, default=50.0, - help="diameter of the axle hole") - self.argparser.add_argument( - "--sides", action="store", type=int, default=8, - help="number of pieces for the center part") - self.argparser.add_argument( - "--alignment_pins", action="store", type=float, default=1.0, - help="diameter of the alignment pins") - - - def leftsideCB(self): - self.hole(0, 0, d=self.axle_diameter) - r, h, side = self.regularPolygon(self.sides, radius=self.inner_diameter/2) - for i in range(self.sides): - self.fingerHolesAt(-side/2, h+0.5*self.thickness, side, 0) - self.moveTo(0, 0, 360/self.sides) - self.outerHolesCB() - - def outerHolesCB(self): - t = self.thickness - for i in range(6): - for j in range(2): - self.rectangularHole( - 0, self.outer_diameter / 2 - 7.0, - self.outer_diameter * math.pi / 360 * 8, 5, r=2.5) - self.moveTo(0, 0, 10) - self.moveTo(0, 0, 360 / 6 - 20) - self.rectangularHole( - (self.outer_diameter + self.inner_diameter) / 4, 0, - (self.outer_diameter - self.inner_diameter) / 2 - 4*t, t, r=t/2) - - - def render(self): - t = self.thickness - - self.inner_diameter -= 2 * t - r, h, side = self.regularPolygon(self.sides, radius=self.inner_diameter/2) - self.diameter = 2*h - self.lugs = self.sides - - self.parts.disc( - self.outer_diameter, callback=self.leftsideCB, move="right") - self.parts.disc( - self.outer_diameter, hole=self.axle_diameter, - callback=lambda:(self.alignmentHoles(True), - self.outerHolesCB()), - move="right") - self.regularPolygonWall( - self.sides, r=self.inner_diameter/2, edges="f", - callback=[self.upperCB], move="right") - self.parts.disc(self.diameter, callback=self.lowerCB, move="right") - - for i in range(self.sides): - self.rectangularWall( - side, self.h - t, "feFe", - callback=[lambda:self.hole(side/2, self.h-2*t, r=t)], - move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/filltest.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/filltest.py deleted file mode 100644 index 8fd29a3..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/filltest.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import time - -from boxes import * - - -class FillTest(Boxes): # Change class name! - """Piece for testing different settings for hole filling""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(fillHolesSettings, fill_pattern="hex") - - self.buildArgParser(x=320, y=220) - - - def xHoles(self): -# border = [(5, 10), (245, 10), (225, 150), (235, 150), (255, 10), (290, 10), (270, 190), (45, 190), (45, 50), (35, 50), (35, 190), (5, 190)] - - x, y = self.x, self.y - - border = [ - ( 5/320*x, 10/220*y), - (245/320*x, 10/220*y), - (225/320*x, 150/220*y), - (235/320*x, 150/220*y), - (255/320*x, 10/220*y), - (290/320*x, 10/220*y), - (270/320*x, 190/220*y), - ( 45/320*x, 190/220*y), - ( 45/320*x, 50/220*y), - ( 35/320*x, 50/220*y), - ( 35/320*x, 190/220*y), - ( 5/320*x, 190/220*y), - ] - - - self.showBorderPoly(border) - self.text("Area to be filled", x/2, 190/220*y, align="bottom center", color=Color.ANNOTATIONS) - - start_time = time.time() - self.fillHoles( - pattern=self.fillHoles_fill_pattern, - border=border, - max_radius=self.fillHoles_hole_max_radius, - hspace=self.fillHoles_space_between_holes, - bspace=self.fillHoles_space_to_border, - min_radius=self.fillHoles_hole_min_radius, - style=self.fillHoles_hole_style, - bar_length=self.fillHoles_bar_length, - max_random=self.fillHoles_max_random - ) - end_time = time.time() - -# print('fillHoles - Execution time:', (end_time-start_time)*1000, 'ms ', self.fillHoles_fill_pattern) - - def render(self): - self.rectangularWall(self.x, self.y, "eeee", callback=[self.xHoles, None, None, None],) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbook.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbook.py deleted file mode 100644 index 4f4d183..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbook.py +++ /dev/null @@ -1,313 +0,0 @@ -# Copyright (C) 2024 Oliver Jensen -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FlexBook(Boxes): - """Box with living hinge styled after a book.""" - - ui_group = "FlexBox" - - description = """ -If you have an enclosure, arrange the living hinge to be as close to your extractor fan as possible. - -![Open](static/samples/FlexBook-2.jpg)""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser(x=75.0, y=35.0, h=125.0) - self.argparser.add_argument( - "--latchsize", action="store", type=float, default=8, - help="size of latch in multiples of thickness") - self.argparser.add_argument( - "--recess_wall", action="store", type=boolarg, default=False, - help="Whether to recess the inner wall for easier object removal") - - - def flexBookSide(self, h, x, r, callback=None, move=None): - t = self.thickness - - tw, th = h+t, x+2*t+r - if self.move(tw, th, move, True): - return - - self.fingerHolesAt(0, x+1.5*t, h, 0) - - self.edges["F"](h) - self.corner(90, 0) - self.edges["e"](t) - self.edges["f"](x + t) - self.corner(180, r) - self.edges["e"](x + 2*t) - self.corner(90) - - self.move(tw, th, move) - - - def flexBookRecessedWall(self, h, y, include_recess, callback=None, move=None): - t = self.thickness - - tw, th = h, y+2*t - - if self.move(tw, th, move, True): - return - - # TODO: figure out math for gentler angles - cutout_radius = min(h/4, y/8) - cutout_angle = 90 - cutout_predist = y * 0.2 - cutout_angle_dist = h/2 - 2 * cutout_radius - cutout_base_dist = y - (y * .4) - 4 * cutout_radius - - self.moveTo(0, t) - - self.edges["f"](h) - self.corner(90,) - self.edges["e"](y) - self.corner(90) - self.edges["f"](h) - self.corner(90) - if include_recess: - self.polyline( - cutout_predist, - (cutout_angle, cutout_radius), - cutout_angle_dist, - (-cutout_angle, cutout_radius), - cutout_base_dist, - (-cutout_angle, cutout_radius), - cutout_angle_dist, - (cutout_angle, cutout_radius), - cutout_predist) - else : - self.edges["e"](y) - self.corner(90) - - self.move(tw, th, move) - - - def flexBookLatchWall(self, h, y, latchSize, callback=None, move=None): - t = self.thickness - - if self.recess_wall: - x_adjust = 0 - else: - x_adjust = 3 * t - - tw, th = h+t+x_adjust, y+2*t - - if self.move(tw, th, move, True): - return - - self.moveTo(x_adjust, t) - - self.edges["f"](h) - self.corner(90) - self.edges["f"](y) - self.corner(90) - self.edges["f"](h) - self.corner(90) - - self.rectangularHole(y/2, -1.5*t, latchSize - 2*t, t) - - self.polyline( - (y-latchSize) / 2, - -90, - 2.5*t, - (90, t/2), - latchSize - t, - (90, t/2), - 2.5*t, - -90, - (y-latchSize) / 2, - 90 - ) - - self.move(tw, th, move) - - def flexBookCover(self, move=None): - x, y = self.x, self.y - latchSize = self.latchsize - c4 = self.c4 - t = self.thickness - - tw = 2*x + 6*t + 2*c4 + t - th = y + 4*t - - if self.move(tw, th, move, True): - return - - self.moveTo(2*t, 0) - - self.edges["h"](x+t) - self.edges["X"](2*c4 + t, y + 4*t) # extra thickness here to make it fit - self.edges["e"](x+t) - self.corner(90, 2*t) - self.edges["e"](y/2) - - self.rectangularHole(0, 1.5*t, latchSize, t) - self.rectangularHole((latchSize+7*t)/2, 3.5*t, t, t) - self.rectangularHole(-(latchSize+7*t)/2, 3.5*t, t, t) - - self.edges["e"](y/2) - self.corner(90, 2*t) - self.edges["e"](x+t + 2*c4 + t) # corresponding extra thickness - self.edges["h"](x+t) - self.corner(90, 2*t) - self.edges["h"](y) - self.corner(90, 2*t) - - if False: - # debug lines - self.moveTo(0, 2*t) - self.edges["e"](x+t + 2*c4 + x+t + t) - self.corner(90) - self.edges["e"](y) - self.corner(90) - self.edges["e"](x+t + 2*c4 + x+t + t) - self.corner(90) - self.edges["e"](y) - self.corner(90) - - self.edges["e"](x) - self.corner(90) - self.edges["e"](y) - self.corner(90) - self.edges["e"](x) - self.corner(90) - self.edges["e"](y) - self.corner(90) - - self.move(tw, th, move) - - def flexBookLatchBracket(self, isCover, move=None): - t = self.thickness - round = t/3 - - tw, th = 5*t, 5.5*t - if self.move(tw, th, move, True): - return - - if isCover: - self.edge(5*t) - else: - self.edge(t) - self.corner(90) - self.edge(2*t - round) - self.corner(-90, round) - self.edge(1.5*t - round) - self.rectangularHole(0, 1.5 * t, t, t) - self.edge(1.5*t - round) - self.corner(-90, round) - self.edge(2*t - round) - self.corner(90) - self.edge(t) - - self.corner(90) - self.edge(3*t) - self.corner(180, 2.5 * t) - self.edge(3*t) - - if not isCover: - # anchor pin - self.moveTo(-1.5*t, 1.25*t) - self.ctx.stroke() - self.rectangularWall(t, 2*t) - - self.move(tw, th, move) - - def flexBookLatchPin(self, move=None): - t = self.thickness - l = self.latchsize - - tw, th = l + 4*t, 5*t - - if self.move(tw, th, move, True): - return - - round = t/3 - - self.moveTo(2*t, 0) - - self.polyline( - l, - 90, - 2*t, - -90, - 2*t - round, - (90, round), - 2*t - 2*round, - (90, round), - 3*t - round, - -90, - t - round, - (90, round), - l - 2*t - 2*round, - (90, round), - t - round, - -90, - 3*t - round, - (90, round), - 2*t - 2*round, - (90, round), - 2*t - round, - -90, - 2*t, - 90) - self.move(tw, th, move) - - - - - def render(self): - - # I found it easier to conceptualize swapping y and h - y = self.h - self.h = self.y - self.y = y - t = self.thickness - - self.radius = self.h / 2 - self.c4 = c4 = math.pi * self.radius * 0.5 - - self.latchsize *= self.thickness - - self.flexBookCover(move="up") - self.flexBookRecessedWall(self.h, self.y, self.recess_wall, move="mirror right") - self.flexBookLatchWall(self.h, self.y, self.latchsize, move="right") - - with self.saved_context(): - self.flexBookSide(self.h, self.x, self.radius, move="right") - self.flexBookSide(self.h, self.x, self.radius, move="mirror right") - self.flexBookSide(self.h, self.x, self.radius, move="up only") - - with self.saved_context(): - self.flexBookLatchBracket(False, move="up") - self.flexBookLatchBracket(False, move="up") - self.flexBookLatchBracket(False, move="right only") - - with self.saved_context(): - self.flexBookLatchBracket(True, move="up") - self.flexBookLatchBracket(True, move="up") - self.flexBookLatchBracket(False, move="right only") - - l = self.latchsize - self.rectangularWall( - 4*t, l, - callback=[lambda: self.rectangularHole(2*t, l/2, 2.5*t, .8*l, r=2*t)], - move="right") - self.flexBookLatchPin(move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox.py deleted file mode 100644 index e385f5c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math - -import boxes - - -class FlexBox(boxes.Boxes): - """Box with living hinge and round corners""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - boxes.Boxes.__init__(self) - self.addSettingsArgs(boxes.edges.FingerJointSettings) - self.addSettingsArgs(boxes.edges.FlexSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--radius", action="store", type=float, default=15, - help="Radius of the latch in mm") - self.argparser.add_argument( - "--latchsize", action="store", type=float, default=8, - help="size of latch in multiples of thickness") - - def flexBoxSide(self, x, y, r, callback=None, move=None): - t = self.thickness - - if self.move(x+2*t, y+t, move, True): - return - - self.moveTo(t+r, t) - - for i, l in zip(range(2), (x, y)): - self.cc(callback, i) - self.edges["f"](l - 2 * r) - self.corner(90, r) - - self.cc(callback, 2) - self.edge(x - 2 * r) - self.corner(90, r) - self.cc(callback, 3) - self.latch(self.latchsize) - self.cc(callback, 4) - self.edges["f"](y - 2 * r - self.latchsize) - self.corner(90, r) - - self.move(x+2*t, y+t, move) - - def surroundingWall(self, move=None): - x, y, h, r = self.x, self.y, self.h, self.radius - t = self.thickness - c4 = math.pi * r * 0.5 - - tw = 2*x + 2*y - 8*r + 4*c4 - th = h + 2.5*t - - if self.move(tw, th, move, True): - return - - self.moveTo(0, 0.25*t) - - self.edges["F"](y - 2 * r - self.latchsize, False) - if x - 2 * r < t: - self.edges["X"](2 * c4 + x - 2 * r, h + 2 * t) - else: - self.edges["X"](c4, h + 2 * t) - self.edges["F"](x - 2 * r, False) - self.edges["X"](c4, h + 2 * t) - self.edges["F"](y - 2 * r, False) - if x - 2 * r < t: - self.edges["X"](2 * c4 + x - 2 * r, h + 2 * t) - else: - self.edges["X"](c4, h + 2 * t) - self.edge(x - 2 * r) - self.edges["X"](c4, h + 2 * t) - self.latch(self.latchsize, False) - self.edge(h + 2 * t) - self.latch(self.latchsize, False, True) - self.edge(c4) - self.edge(x - 2 * r) - self.edge(c4) - self.edges["F"](y - 2 * r, False) - self.edge(c4) - self.edges["F"](x - 2 * r, False) - self.edge(c4) - self.edges["F"](y - 2 * r - self.latchsize, False) - self.corner(90) - self.edge(h + 2 * t) - self.corner(90) - - self.move(tw, th, move) - - def render(self): - - if self.outside: - self.x = self.adjustSize(self.x) - self.y = self.adjustSize(self.y) - self.h = self.adjustSize(self.h) - - x, y, h = self.x, self.y, self.h - self.latchsize *= self.thickness - r = self.radius or min(x, y - self.latchsize) / 2.0 - r = min(r, x / 2.0) - self.radius = r = min(r, max(0, (y - self.latchsize) / 2.0)) - - - self.surroundingWall(move="up") - self.flexBoxSide(self.x, self.y, self.radius, move="right") - self.flexBoxSide(self.x, self.y, self.radius, move="mirror") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox2.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox2.py deleted file mode 100644 index 8729888..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox2.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FlexBox2(Boxes): - """Box with living hinge and top corners rounded""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--radius", action="store", type=float, default=15, - help="Radius of the corners in mm") - self.argparser.add_argument( - "--latchsize", action="store", type=float, default=8, - help="size of latch in multiples of thickness") - - def flexBoxSide(self, y, h, r, callback=None, move=None): - t = self.thickness - if self.move(y+2*t, h+t, move, True): - return - - self.moveTo(t, t) - self.cc(callback, 0) - self.edges["f"](y) - self.corner(90, 0) - self.cc(callback, 1) - self.edges["f"](h - r) - self.corner(90, r) - self.cc(callback, 2) - self.edge(y - 2 * r) - self.corner(90, r) - self.cc(callback, 3) - self.latch(self.latchsize) - self.cc(callback, 4) - self.edges["f"](h - r - self.latchsize) - self.corner(90) - - self.move(y+2*t, h+t, move) - - def surroundingWall(self, move=None): - y, h, x, r = self.y, self.h, self.x, self.radius - t = self.thickness - - tw = y + h - 3*r + 2*self.c4 + self.latchsize + t - th = x + 2.5*t - - if self.move(tw, th, move, True): - return - - self.moveTo(t, .25*t) - self.edges["F"](h - r, False) - - if (y - 2 * r < t): - self.edges["X"](2 * self.c4 + y - 2 * r, x + 2 * t) - else: - self.edges["X"](self.c4, x + 2 * t) - self.edge(y - 2 * r) - self.edges["X"](self.c4, x + 2 * t) - - self.latch(self.latchsize, False) - self.edge(x + 2 * t) - self.latch(self.latchsize, False, True) - self.edge(self.c4) - self.edge(y - 2 * r) - self.edge(self.c4) - self.edges["F"](h - r) - self.corner(90) - self.edge(t) - self.edges["f"](x) - self.edge(t) - self.corner(90) - - self.move(tw, th, move) - - def render(self): - - if self.outside: - self.y = self.adjustSize(self.y) - self.h = self.adjustSize(self.h) - self.x = self.adjustSize(self.x) - - self.latchsize *= self.thickness - self.radius = self.radius or min(self.y / 2.0, self.h - self.latchsize) - self.radius = min(self.radius, self.y / 2.0) - self.radius = min(self.radius, max(0, self.h - self.latchsize)) - self.c4 = c4 = math.pi * self.radius * 0.5 - - - self.moveTo(2 * self.thickness, self.thickness) - - with self.saved_context(): - self.surroundingWall(move="right") - self.rectangularWall(self.y, self.x, edges="FFFF") - - self.surroundingWall(move="up only") - - self.flexBoxSide(self.y, self.h, self.radius, move="right") - self.flexBoxSide(self.y, self.h, self.radius, move= "mirror right") - self.rectangularWall(self.x, self.h - self.radius - self.latchsize, edges="fFeF") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox3.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox3.py deleted file mode 100644 index 97b143e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox3.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FlexBox3(Boxes): - """Box with living hinge""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser("x", "y", "outside") - self.argparser.add_argument( - "--z", action="store", type=float, default=100.0, - help="height of the box") - self.argparser.add_argument( - "--h", action="store", type=float, default=10.0, - help="height of the lid") - self.argparser.add_argument( - "--radius", action="store", type=float, default=10.0, - help="radius of the lids living hinge") - self.argparser.add_argument( - "--c", action="store", type=float, default=1.0, - dest="d", help="clearance of the lid") - - def flexBoxSide(self, x, y, r, callback=None, move=None): - t = self.thickness - if self.move(x+2*t, y+t, move, True): - return - - self.moveTo(t, t) - self.cc(callback, 0) - self.edges["f"](x) - self.corner(90, 0) - self.cc(callback, 1) - self.edges["f"](y - r) - self.corner(90, r) - self.cc(callback, 2) - self.edge(x - r) - self.corner(90, 0) - self.cc(callback, 3) - self.edges["f"](y) - self.corner(90) - - self.move(x+2*t, y+t, move) - - def surroundingWall(self, move=None): - x, y, z, r, d = self.x, self.y, self.z, self.radius, self.d - t = self.thickness - - tw = x + y - 2*r + self.c4 + 2*t + t - th = z + 4*t + 2*d - - if self.move(tw, th, move, True): - return - - self.moveTo(t, d + t) - - self.edges["F"](y - r, False) - self.edges["X"](self.c4, z + 2 * t) - self.corner(-90) - self.edge(d) - self.corner(90) - self.edges["f"](x - r + t) - self.corner(90) - self.edges["f"](z + 2 * t + 2 * d) - self.corner(90) - self.edges["f"](x - r + t) - self.corner(90) - self.edge(d) - self.corner(-90) - self.edge(self.c4) - self.edges["F"](y - r) - self.corner(90) - self.edge(t) - self.edges["f"](z) - self.edge(t) - self.corner(90) - - self.move(tw, th, move) - - def lidSide(self, move=None): - x, y, z, r, d, h = self.x, self.y, self.z, self.radius, self.d, self.h - t = self.thickness - r2 = r + t if r + t <= h + t else h + t - - if r < h: - r2 = r + t - base_l = x + 2 * t - if self.move(h+t, base_l+t, move, True): - return - - self.edge(h + self.thickness - r2) - self.corner(90, r2) - self.edge(r - r2 + 1 * t) - else: - a = math.acos((r-h)/(r+t)) - ang = math.degrees(a) - base_l = x + (r+t) * math.sin(a) - r + t - if self.move(h+t, base_l+t, move, True): - return - - self.corner(90-ang) - self.corner(ang, r+t) - - self.edges["F"](x - r + t) - self.edgeCorner("F", "f") - self.edges["g"](h) - self.edgeCorner("f", "e") - self.edge(base_l) - self.corner(90) - - self.move(h+t, base_l+t, move) - - def render(self): - if self.outside: - self.x = self.adjustSize(self.x) - self.y = self.adjustSize(self.y) - self.z = self.adjustSize(self.z) - - x, y, z, d, h = self.x, self.y, self.z, self.d, self.h - r = self.radius = self.radius or min(x, y) / 2.0 - thickness = self.thickness - - self.c4 = c4 = math.pi * r * 0.5 * 0.95 - self.latchsize = 8 * thickness - - width = 2 * x + y - 2 * r + c4 + 14 * thickness + 3 * h # lock - height = y + z + 8 * thickness - - - s = edges.FingerJointSettings(self.thickness, finger=1., - space=1., surroundingspaces=1) - s.edgeObjects(self, "gGH") - - with self.saved_context(): - self.surroundingWall(move="right") - self.rectangularWall(x, z, edges="FFFF", move="right") - self.rectangularWall(h, z + 2 * (d + self.thickness), edges="GeGF", move="right") - self.lidSide(move="right") - self.lidSide(move="mirror right") - - self.surroundingWall(move="up only") - - self.flexBoxSide(x, y, r, move="right") - self.flexBoxSide(x, y, r, move="mirror right") - self.rectangularWall(z, y, edges="fFeF") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox4.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox4.py deleted file mode 100644 index 433ee88..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox4.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FlexBox4(Boxes): - """Box with living hinge and left corners rounded""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--radius", action="store", type=float, default=15, - help="Radius of the corners in mm") - self.argparser.add_argument( - "--latchsize", action="store", type=float, default=8, - help="size of latch in multiples of thickness") - - def flexBoxSide(self, x, y, r, callback=None, move=None): - t = self.thickness - - if self.move(x+2*t, y+t, move, True): - return - - self.moveTo(t, t) - - self.cc(callback, 0) - self.edges["f"](x) - self.corner(90, 0) - self.cc(callback, 1) - self.edges["f"](y - r) - self.corner(90, r) - self.cc(callback, 2) - self.edge(x - 2 * r) - self.corner(90, r) - self.cc(callback, 3) - self.edges["e"](y - r - self.latchsize) - self.cc(callback, 4) - self.latch(self.latchsize) - self.corner(90) - - self.move(x+2*t, y+t, move) - - def surroundingWall(self, move=None): - x, y, h, r = self.x, self.y, self.h, self.radius - c4 = self.c4 - - t = self.thickness - - tw, th = 2*c4 + 2*y + x - 4*r + 2*t, h + 2.5*t - - if self.move(tw, th, move, True): - return - - self.moveTo(t, 0.25*t) - - self.edges["F"](y - r, False) - if (x - 2 * r < self.thickness): - self.edges["X"](2 * c4 + x - 2 * r, h + 2 * self.thickness) - else: - self.edges["X"](c4, h + 2 * self.thickness) - self.edge(x - 2 * r) - self.edges["X"](c4, h + 2 * self.thickness) - - self.edge(y - r - self.latchsize) - self.latch(self.latchsize, False, extra_length=t) - self.edge(h + 2 * self.thickness) - self.latch(self.latchsize, False, True, extra_length=t) - self.edge(y - r - self.latchsize) - self.edge(c4) - self.edge(x - 2 * r) - self.edge(c4) - self.edges["F"](y - r) - self.corner(90) - self.edge(self.thickness) - self.edges["f"](h) - self.edge(self.thickness) - self.corner(90) - - self.move(tw, th, move) - - def render(self): - if self.outside: - self.x = self.adjustSize(self.x) - self.y = self.adjustSize(self.y) - self.h = self.adjustSize(self.h) - - self.latchsize *= self.thickness - self.radius = self.radius or min(self.x / 2.0, self.y - self.latchsize) - self.radius = min(self.radius, self.x / 2.0) - self.radius = min(self.radius, max(0, self.y - self.latchsize)) - self.c4 = c4 = math.pi * self.radius * 0.5 - - - self.surroundingWall(move="up") - self.flexBoxSide(self.x, self.y, self.radius, move="right") - self.flexBoxSide(self.x, self.y, self.radius, move="mirror right") - self.rectangularWall(self.x, self.h, edges="FeFF") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox5.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox5.py deleted file mode 100644 index f9faf94..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flexbox5.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math - -import boxes - - -class FlexBox5(boxes.Boxes): - """Box with living hinge and round corners""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - boxes.Boxes.__init__(self) - self.addSettingsArgs(boxes.edges.FingerJointSettings) - self.addSettingsArgs(boxes.edges.FlexSettings) - self.buildArgParser("x", "h", "outside") - self.argparser.add_argument( - "--top_diameter", action="store", type=float, default=60, - help="diameter at the top") - self.argparser.add_argument( - "--bottom_diameter", action="store", type=float, default=60, - help="diameter at the bottom") - self.argparser.add_argument( - "--latchsize", action="store", type=float, default=8, - help="size of latch in multiples of thickness") - - def flexBoxSide(self, callback=None, move=None): - t = self.thickness - - r1, r2 = self.top_diameter/2., self.bottom_diameter/2 - a = self.a - l = self.l - - tw , th = l+r1+r2, 2*max(r1, r2)+2*t - - if self.move(tw, th, move, True): - return - - self.moveTo(r2, t) - - self.cc(callback, 0) - self.edges["f"](l) - self.corner(180+2*a, r1) - self.cc(callback, 1) - self.latch(self.latchsize) - self.cc(callback, 2) - self.edges["f"](l - self.latchsize) - self.corner(180-2*a, r2) - - self.move(tw, th, move) - - def surroundingWall(self, move=None): - t = self.thickness - - r1, r2 = self.top_diameter/2., self.bottom_diameter/2 - h = self.h - a = self.a - l = self.l - - - c1 = math.radians(180+2*a) * r1 - c2 = math.radians(180-2*a) * r2 - - tw = 2*l + c1 + c2 - th = h + 2.5*t - - if self.move(tw, th, move, True): - return - - self.moveTo(0, 0.25*t) - - self.edges["F"](l - self.latchsize, False) - self.edges["X"](c2, h + 2 * t) - self.edges["F"](l, False) - self.edges["X"](c1, h + 2 * t) - self.latch(self.latchsize, False) - self.edge(h + 2 * t) - self.latch(self.latchsize, False, True) - self.edge(c1) - self.edges["F"](l, False) - self.edge(c2) - self.edges["F"](l - self.latchsize, False) - self.corner(90) - self.edge(h + 2 * t) - self.corner(90) - - self.move(tw, th, move) - - def render(self): - - if self.outside: - self.x = self.adjustSize(self.x) - self.h = self.adjustSize(self.h) - self.top_diameter = self.adjustSize(self.top_diameter) - self.bottom_diameter = self.adjustSize(self.bottom_diameter) - - t = self.thickness - self.latchsize *= self.thickness - d_t, d_b = self.top_diameter, self.bottom_diameter - self.x = max(self.x, self.latchsize + 2*t + (d_t + d_b)/2) - - d_c = self.x - d_t/2. - d_b/2. - self.a = math.degrees(math.asin((d_t-d_b)/2 / d_c)) - self.l = d_c * math.cos(math.radians(self.a)) - - self.surroundingWall(move="up") - self.flexBoxSide(move="right") - self.flexBoxSide(move="mirror") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flextest.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flextest.py deleted file mode 100644 index 4e1a718..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flextest.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FlexTest(Boxes): - """Piece for testing different flex settings""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser("x", "y") - - def render(self): - x, y = self.x, self.y - - self.moveTo(5, 5) - self.edge(10) - self.edges["X"](x, y) - self.edge(10) - self.corner(90) - self.edge(y) - self.corner(90) - self.edge(x + 20) - self.corner(90) - self.edge(y) - self.corner(90) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flextest2.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flextest2.py deleted file mode 100644 index 033c049..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/flextest2.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FlexTest2(Boxes): - """Piece for testing 2D flex settings""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("x", "y") - self.argparser.add_argument( - "--fw", action="store", type=float, default=1, - help="distance of flex cuts in multiples of thickness") - - def render(self): - x, y = self.x, self.y - - self.rectangularWall(x, y, callback=[lambda: self.flex2D(x, y, self.fw)]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/folder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/folder.py deleted file mode 100644 index 020e482..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/folder.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Folder(Boxes): - """Book cover with flex for the spine""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser("x", "y", "h") - self.argparser.add_argument( - "--r", action="store", type=float, default=10.0, - help="radius of the corners") - self.argparser.set_defaults(h=20) - - def render(self): - x, y, r, h = self.x, self.y, self.r, self.h - c2 = math.pi * h - self.moveTo(r + self.thickness, self.thickness) - self.edge(x - r) - self.edges["X"](c2, y) - self.edge(x - r) - self.corner(90, r) - self.edge(y - 2 * r) - self.corner(90, r) - self.edge(2 * x - 2 * r + c2) - self.corner(90, r) - self.edge(y - 2 * r) - self.corner(90, r) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/frontpanel.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/frontpanel.py deleted file mode 100644 index 4b7d58e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/frontpanel.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import io -import shlex - -from boxes import * - - -def str_to_bool(s: str) -> bool: - return s.lower() in ('true', '1', 't', 'y', 'yes', 'yeah', 'yup', 'certainly', 'uh-huh') - - -class FrontPanel(Boxes): - """Mounting Holes and cutouts for all your holy needs.""" - - description = f""" - - - - -This will help you create font (and side and top) panels for your -boxes that are pre-configured for all the bits and bobs you'd like to -install - - The layout can create several types of holes including rectangles, - circles and mounting holes. The default shows an example layout with all - currently supported objects. - -#### -`rect x y w h [cr=0] [cx=True] [cy=True]` - - x: x position - y: y position - w: width - h: height - cr: optional, Corner radius, default=0 - cx: optional, Center x. the x position denotes the center of the rectangle. - accepts t, T, 1, or other true-like values. - cy: optional, Center y. the y position denotes the center of the rectangle. - -#### outline -`rect w h` - - w: width - h: height - -`outline` has a special meaning: You can create multiple panel outlines with one command. -This has the effect of making it easy to manage all the holes on all the sides of -your boxes. - -#### circle -`circle x y r` - - x: x position - y: y position - r: radius - -#### mountinghole -mountinghole x y d_shaft [d_head=0] [angle=0] - - x: x position - y: y position - d_shaft: diameter of the shaft part of the mounting hole - d_head: optional. diameter of the head - angle: optional. angle of the mounting hole - -#### text -`text x y size "some text" [angle=0] [align=bottom|left]` - - x: x position - y: y position - size: size, in mm - text: text to render. This *must* be in quotation marks - angle: angle (in degrees) - align: string with combinations of (top|middle|bottom) and (left|center|right), - separated by '|'. Default is 'bottom|left' - - - -#### nema -`nema x y size [screwhole_size=0]` - - x: x position (center of shaft) - y: y position (center of shaft) - size: nema size. One of [{', '.join([f'{x}' for x in Boxes.nema_sizes])}] - screw: screw size, in mm. Optional. Default=0, which means the default size - - """ - - ui_group = "Holes" - - def __init__(self) -> None: - Boxes.__init__(self) - self.argparser.add_argument( - "--layout", action="store", type=str, - default=""" -outline 100 100 -rect 50 60 80 30 3 True False -text 50 91 7 "Super Front Panel With Buttons!" 0 bottom|center -circle 10 45 3.5 -circle 30 45 3.5 -circle 50 45 3.5 -circle 70 45 3.5 -circle 90 45 3.5 -text 10 40 3 "BTN_1" 0 top|center -text 35 45 3 "BTN_2" 90 top|center -text 50 50 3 "BTN_3" 180 top|center -text 65 45 3 "BTN_4" 270 top|center -text 90 45 3 "5" 0 middle|center -mountinghole 5 85 3 6 90 -mountinghole 95 85 3 6 90 - -# Start another panel, 30x50 -outline 30 50 -rect 15 25 15 15 1 True True -text 15 25 3 "__Fun!" 0 bottom|left -text 15 25 3 "__Fun!" 45 bottom|left -text 15 25 3 "__Fun!" 90 bottom|left -text 15 25 3 "__Fun!" 135 bottom|left -text 15 25 3 "__Fun!" 180 bottom|left -text 15 25 3 "__Fun!" 225 bottom|left -text 15 25 3 "__Fun!" 270 bottom|left - -text 3 10 2 "Another panel, for fun" 0 top|left - - -# Let's create another panel with a nema motor on it -outline 40 40 -nema 20 20 17 -""") - - def applyOffset(self, x, y): - return (x+self.offset[0], y+self.offset[1]) - - def drawRect(self, x, y, w, h, r=0, center_x="True", center_y="True") -> None: - x, y, w, h, r = (float(i) for i in [x, y, w, h, r]) - x, y = self.applyOffset(x, y) - center_x = str_to_bool(center_x) - center_y = str_to_bool(center_y) - self.rectangularHole(x, y, w, h, r, center_x, center_y) - - def drawCircle(self, x, y, r) -> None: - x, y, r = (float(i) for i in [x, y, r]) - x, y = self.applyOffset(x, y) - self.hole(x, y, r) - - def drawMountingHole(self, x, y, d_shaft, d_head=0.0, angle=0) -> None: - x, y, d_shaft, d_head, angle = (float(i) for i in [x, y, d_shaft, d_head, angle]) - x, y = self.applyOffset(x, y) - self.mountingHole(x, y, d_shaft, d_head, angle) - - def drawOutline(self, w, h): - w, h = (float(i) for i in [w, h]) - if self.outline is not None: - self.offset = self.applyOffset(self.outline[0]+10, 0) - self.outline = (w, h) # store away for next time - x = 0 - y = 0 - x, y = self.applyOffset(x, y) - border = [(x, y), (x+w, y), (x+w, y+h), (x, y+h), (x, y)] - self.showBorderPoly( border ) - - def drawText(self, x, y, size, text, angle=0, align='bottom|left'): - x, y, size, angle = (float(i) for i in [x, y, size, angle]) - x, y = self.applyOffset(x, y) - align = align.replace("|", " ") - self.text(text=text, x=x, y=y, fontsize=size, angle=angle, align=align) - - def drawNema(self, x, y, size, screwhole_size=0): - x, y, size, screwhole_size = (float(i) for i in [x, y, size, screwhole_size]) - if size in self.nema_sizes: - x, y = self.applyOffset(x, y) - self.NEMA(size, x, y, screwholes=screwhole_size) - - def parse_layout(self, layout): - f = io.StringIO(layout) - line = 0 - objects = { - 'outline': self.drawOutline, - 'rect': self.drawRect, - 'circle': self.drawCircle, - 'mountinghole': self.drawMountingHole, - 'text': self.drawText, - 'nema': self.drawNema, - } - - for l in f.readlines(): - line += 1 - l = re.sub('#.*$', '', l) # remove comments - l = l.strip() - la = shlex.split(l, comments=True, posix=True) - if len(la) > 0 and la[0].lower() in objects: - objects[la[0]](*la[1:]) - - def render(self): - self.offset = (0.0, 0.0) - self.outline = None # No outline yet - self.parse_layout(self.layout) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/frontpanel_test.json b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/frontpanel_test.json deleted file mode 100644 index 892bf74..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/frontpanel_test.json +++ /dev/null @@ -1,3 +0,0 @@ -outline 60 60 -squre 10 20 25 34 -circle 10 20 40 diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gear.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gear.py deleted file mode 100644 index f4fdad5..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gear.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Gears(Boxes): - """Gears""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.argparser.add_argument( - "--teeth1", action="store", type=int, default=12, - help="number of teeth") - self.argparser.add_argument( - "--shaft1", action="store", type=float, default=6., - help="diameter of the shaft 1") - self.argparser.add_argument( - "--dpercentage1", action="store", type=float, default=75, - help="percent of the D section of shaft 1 (100 for round shaft)") - - self.argparser.add_argument( - "--teeth2", action="store", type=int, default=32, - help="number of teeth in the other size of gears") - self.argparser.add_argument( - "--shaft2", action="store", type=float, default=0.0, - help="diameter of the shaft2 (zero for same as shaft 1)") - self.argparser.add_argument( - "--dpercentage2", action="store", type=float, default=0, - help="percent of the D section of shaft 1 (0 for same as shaft 1)") - - self.argparser.add_argument( - "--modulus", action="store", type=float, default=2, - help="size of teeth (diameter / #teeth) in mm") - self.argparser.add_argument( - "--pressure_angle", action="store", type=float, default=20, - help="angle of the teeth touching (in degrees)") - self.argparser.add_argument( - "--profile_shift", action="store", type=float, default=20, - help="in percent of the modulus") - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - - self.teeth1 = max(2, self.teeth1) - self.teeth2 = max(2, self.teeth2) - - if not self.shaft2: - self.shaft2 = self.shaft1 - if not self.dpercentage2: - self.dpercentage2 = self.dpercentage1 - - self.gears(teeth=self.teeth2, dimension=self.modulus, - angle=self.pressure_angle, profile_shift=self.profile_shift, - callback=lambda:self.dHole(0, 0, d=self.shaft2, - rel_w=self.dpercentage2/100.), - move="up") - r2, d2, d2 = self.gears.sizes( - teeth=self.teeth2, dimension=self.modulus, - angle=self.pressure_angle, profile_shift=self.profile_shift) - - self.gears(teeth=self.teeth1, dimension=self.modulus, - angle=self.pressure_angle, profile_shift=self.profile_shift, - callback=lambda:self.dHole(0, 0, d=self.shaft1, - rel_w=self.dpercentage1/100.), - move="up") - r1, d1, d1 = self.gears.sizes( - teeth=self.teeth1, dimension=self.modulus, - angle=self.pressure_angle, profile_shift=self.profile_shift) - r = max(self.shaft1, self.shaft2)/2 - self.hole(t+r, t+r, self.shaft1/2) - self.hole(t+r+r1+r2, t+r, self.shaft2/2) - self.moveTo(0, 2*r+t) - - self.text(f"Pitch radius 1: {r1:.1f}mm\n" - f"Outer diameter 1: {d1:.1f}mm\n" - f"Pitch radius 2: {r2:.1f}mm\n" - f"Outer diameter 2: {d2:.1f}mm\n" - f"Axis distance: {r1 + r2:.1f}mm\n", - align="bottom left") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gearbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gearbox.py deleted file mode 100644 index e93e286..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gearbox.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class GearBox(Boxes): - """Gearbox with multiple identical stages""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--teeth1", action="store", type=int, default=8, - help="number of teeth on ingoing shaft") - self.argparser.add_argument( - "--teeth2", action="store", type=int, default=20, - help="number of teeth on outgoing shaft") - self.argparser.add_argument( - "--modulus", action="store", type=float, default=3, - help="modulus of the teeth in mm") - self.argparser.add_argument( - "--shaft", action="store", type=float, default=6., - help="diameter of the shaft") - self.argparser.add_argument( - "--stages", action="store", type=int, default=4, - help="number of stages in the gear reduction") - - def render(self): - - if self.teeth2 < self.teeth1: - self.teeth2, self.teeth1 = self.teeth1, self.teeth2 - - pitch1, size1, xxx = self.gears.sizes(teeth=self.teeth1, dimension=self.modulus) - pitch2, size2, xxx = self.gears.sizes(teeth=self.teeth2, dimension=self.modulus) - - t = self.thickness - x = 1.1 * t * self.stages - - if self.stages == 1: - y = size1 + size2 - y1 = y / 2 - (pitch1 + pitch2) + pitch1 - y2 = y / 2 + (pitch1 + pitch2) - pitch2 - else: - y = 2 * size2 - y1 = y / 2 - (pitch1 + pitch2) / 2 - y2 = y / 2 + (pitch1 + pitch2) / 2 - - h = max(size1, size2) + t - - b = "F" - t = "e" # prepare for close box - mh = self.shaft - - def sideCB(): - self.hole(y1, h / 2, mh / 2) - self.hole(y2, h / 2, mh / 2) - - self.moveTo(self.thickness, self.thickness) - self.rectangularWall(y, h, [b, "f", t, "f"], callback=[sideCB], move="right") - self.rectangularWall(x, h, [b, "F", t, "F"], move="up") - self.rectangularWall(x, h, [b, "F", t, "F"]) - self.rectangularWall(y, h, [b, "f", t, "f"], callback=[sideCB], move="left") - self.rectangularWall(x, h, [b, "F", t, "F"], move="up only") - - self.rectangularWall(x, y, "ffff", move="up") - - profile_shift = 20 - pressure_angle = 20 - - for i in range(self.stages - 1): - self.gears(teeth=self.teeth2, dimension=self.modulus, angle=pressure_angle, - mount_hole=mh, profile_shift=profile_shift, move="up") - - self.gears(teeth=self.teeth2, dimension=self.modulus, angle=pressure_angle, - mount_hole=mh, profile_shift=profile_shift, move="right") - - for i in range(self.stages): - self.gears(teeth=self.teeth1, dimension=self.modulus, angle=pressure_angle, - mount_hole=mh, profile_shift=profile_shift, move="down") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gridfinitybase.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gridfinitybase.py deleted file mode 100644 index 66f2603..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gridfinitybase.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import lids - - -class GridfinityBase(Boxes): - """A parameterized Gridfinity base""" - - description = """This is a configurable gridfinity base. This - design is based on - Zach Freedman's Gridfinity system""" - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, space=4, finger=4) - self.addSettingsArgs(lids.LidSettings) - self.argparser.add_argument("--x", type=int, default=3, help="number of grids in X direction") - self.argparser.add_argument("--y", type=int, default=2, help="number of grids in Y direction") - self.argparser.add_argument("--h", type=float, default=7*3, help="height of sidewalls of the tray (mm)") - self.argparser.add_argument("--m", type=float, default=0.5, help="Extra margin around the gridfinity base to allow it to drop into the carrier (mm)") - self.argparser.add_argument( - "--bottom_edge", action="store", - type=ArgparseEdgeType("Fhse"), choices=list("Fhse"), - default='F', - help="edge type for bottom edge") - self.argparser.add_argument("--pitch", type=int, default=42, help="The Gridfinity pitch, in mm. Should always be 42.") - self.argparser.add_argument("--opening", type=int, default=38, help="The cutout for each grid opening. Typical is 38.") - - def generate_grid(self): - pitch = self.pitch - nx, ny = self.x, self.y - opening = self.opening - for col in range(nx): - for row in range(ny): - lx = col*pitch+pitch/2 - ly = row*pitch+pitch/2 - self.rectangularHole(lx, ly, opening, opening) - - def create_base_plate(self): - pitch = self.pitch - nx, ny = self.x, self.y - opening = self.opening - self.rectangularWall(nx*pitch, ny*pitch, move="up", callback=[self.generate_grid]) - - def create_tray(self): - pitch = self.pitch - nx, ny = self.x, self.y - margin = self.m - x, y, h = nx*pitch, ny*pitch, self.h - t = self.thickness - x += 2*margin - y += 2*margin - t1, t2, t3, t4 = "eeee" - b = self.edges.get(self.bottom_edge, self.edges["F"]) - sideedge = "F" # if self.vertical_edges == "finger joints" else "h" - - self.rectangularWall(x, h, [b, sideedge, t1, sideedge], - ignore_widths=[1, 6], move="right") - self.rectangularWall(y, h, [b, "f", t2, "f"], - ignore_widths=[1, 6], move="up") - self.rectangularWall(y, h, [b, "f", t4, "f"], - ignore_widths=[1, 6], move="") - self.rectangularWall(x, h, [b, sideedge, t3, sideedge], - ignore_widths=[1, 6], move="left up") - - if self.bottom_edge != "e": - self.rectangularWall(x, y, "ffff", move="up") - - def render(self): - self.create_base_plate() - self.create_tray() - self.lid(self.x*self.pitch + 2*self.m, - self.y*self.pitch + 2*self.m) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gridfinitytraylayout.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gridfinitytraylayout.py deleted file mode 100644 index 04c2058..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/gridfinitytraylayout.py +++ /dev/null @@ -1,116 +0,0 @@ -import boxes -from boxes import Boxes, lids, restore -from boxes.Color import Color -from boxes.generators.traylayout import TrayLayout - - -class GridfinityTrayLayout(TrayLayout): - """A Gridfinity Tray Generator based on TrayLayout""" - - description = """ -This is a general purpose gridfinity tray generator. You can create -somewhat arbitrarily shaped trays, or just do nothing for simple grid -shaped trays. - -The dimensions are automatically calculated to fit perfectly into a -gridfinity grid (like the GridfinityBase, or any other Gridfinity -based base). - -Edit the layout text graphics to adjust your tray. -You can replace the hyphens and vertical bars representing the walls -with a space character to remove the walls. You can replace the space -characters representing the floor by a "X" to remove the floor for -this compartment. -""" - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(boxes.edges.FingerJointSettings) - self.addSettingsArgs(lids.LidSettings) - self.buildArgParser(h=50) - self.outside = True # We're *always* outside for gridfinity - self.pitch = 42.0 # gridfinity pitch is defined as 42. - self.opening = 38 - self.opening_margin = 2 - self.argparser.add_argument("--hi", type=float, default=0, help="inner height of inner walls in mm (leave to zero for same as outer walls)") - self.argparser.add_argument("--nx", type=int, default=3, help="number of gridfinity grids in X direction") - self.argparser.add_argument("--ny", type=int, default=2, help="number of gridfinity grids in Y direction") - self.argparser.add_argument("--countx", type=int, default=5, help="split x into this many grid sections. 0 means same as --nx") - self.argparser.add_argument("--county", type=int, default=3, help="split y into this many grid sections. 0 means same as --ny") - self.argparser.add_argument("--margin", type=float, default=0.75, help="Leave this much total margin on the outside, in mm") - self.argparser.add_argument("--layout", type=str, help="You can hand edit this before generating", default="\n"); - - def generate_layout(self): - layout = '' - countx = self.countx - county = self.county - if countx == 0: - countx = self.nx - if county == 0: - county = self.ny - - stepx = self.x / countx - stepy = self.y / county - for i in range(countx): - line = ' |' * i + f" ,> {stepx}mm\n" - layout += line - for i in range(county): - layout += "+-" * countx + f"+\n" - layout += "| " * countx + f"|{stepy}mm\n" - layout += "+-" * countx + "+\n" - return layout - - @restore - def rectangularEtching(self, x, y, dx, dy, r=0, center_x=True, center_y=True): - """ - Draw a rectangular hole - - :param x: position - :param y: position - :param dx: width - :param dy: height - :param r: (Default value = 0) radius of the corners - :param center_x: (Default value = True) if True, x position is the center, else the start - :param center_y: (Default value = True) if True, y position is the center, else the start - """ - r = min(r, dx/2., dy/2.) - x_start = x if center_x else x + dx / 2.0 - y_start = y - dy / 2.0 if center_y else y - self.moveTo(x_start, y_start, 180) - self.edge(dx / 2.0 - r) # start with an edge to allow easier change of inner corners - for d in (dy, dx, dy, dx / 2.0 + r): - self.corner(-90, r) - self.edge(d - 2 * r) - - def baseplate_etching(self): - x = -self.thickness - self.margin / 2 - y = -self.thickness - self.margin / 2 - o = self.opening - p = self.pitch - m = self.opening_margin - self.ctx.stroke() - with self.saved_context(): - for xx in [0, self.nx-1]: - for yy in [0, self.ny-1]: - self.set_source_color(Color.ETCHING) - self.rectangularEtching(x+p/2+xx*p, y+p/2+yy*p, o-m, o-m) - self.ctx.stroke() - - def render(self): - # Create a layout - self.x = self.pitch * self.nx - self.margin - self.y = self.pitch * self.ny - self.margin - self.outer_x = self.x - self.outer_y = self.y - - self.prepare() - self.walls() - with self.saved_context(): - self.base_plate(callback=[self.baseplate_etching], - move="mirror right") - foot = self.opening - self.opening_margin - for i in range(min(self.nx * self.ny, 4)): - self.rectangularWall(foot, foot, move="right") - self.base_plate(callback=[self.baseplate_etching], - move="up only") - self.lid(sum(self.x) + (len(self.x)-1) * self.thickness, - sum(self.y) + (len(self.y)-1) * self.thickness) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/halfbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/halfbox.py deleted file mode 100644 index b5184ed..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/halfbox.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class HalfBox(Boxes): - """Configurable half of a box which can be: a bookend, a hanging shelf, an angle clamping jig, ...""" - - description = """This can be used to create: - -* a hanging shelf: -![HalfBox as hanging shelf](static/samples/HalfBox_Shelf_usage.jpg) - -* an angle clamping jig: -![HalfBox as an angle clamping jig](static/samples/HalfBox_AngleJig_usage.jpg) - -* a bookend: -![HalfBox as a bookend](static/samples/HalfBox_Bookend_usage.jpg) - -and many more... - -""" - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=2.0,space=2.0) - self.addSettingsArgs(edges.MountingSettings) - self.buildArgParser(x=100, sy="50:50", h=100) - - self.argparser.add_argument("--Clamping", action="store", type=boolarg, default=False, help="add clamping holes") - self.argparser.add_argument("--ClampingSize", action="store", type=float, default=25.0, help="diameter of clamping holes") - self.argparser.add_argument("--Mounting", action="store", type=boolarg, default=False, help="add mounting holes") - self.argparser.add_argument("--Sturdy", action="store", type=boolarg, default=False, help="create sturdy construction (e.g. shelf, clamping jig, ...)") - - def polygonWallExt(self, borders, edge="f", turtle=False, callback=None, move=None): - # extended polygon wall. - # same as polygonWall, but with extended border parameters - # each border dataset consists of - # length - # turn angle - # radius of turn (without radius correction) - # edge type - - for i in range(0, len(borders), 4): - self.cc(callback, i) - length = borders[i] - next_angle = borders[i+1] - next_radius = borders[i+2] - next_edge = borders[i+3] - - e = self.edges.get(next_edge, next_edge) - if i == 0: - self.moveTo(0,e.margin(),0) - e(length) - if self.debug: - self.hole(0, 0, 1, color=Color.ANNOTATIONS) - self.corner(next_angle, tabs=0, radius=next_radius) - - def xHoles(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.x) - - def hHoles(self): - posy = -0.5 * self.thickness - for y in reversed(self.sy[1:]): - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.h) - - def render(self): - # adjust to the variables you want in the local scope - - x, h = self.x, self.h - d = self.ClampingSize - t = self.thickness - - # triangle with sides: x (horizontal), h (upwards) and l - # angles: 90° between x & h - # b between h & l - # c between l & x - - l = math.sqrt(x * x + h * h) - b = math.degrees(math.asin(x / l)) - c = math.degrees(math.asin(h / l)) - if x > h: - if 90 + b + c < 179: - b = 180 - b - else: - if 90 + b + c < 179: - c = 180 - c - - # small triangle top: 2*t, h1, l1 - h1 = (2*t)/x*h - l1 = (2*t)/x*l - - # small triangle left: x2, 2*t, l2 - x2 = (2*t)/h*x - l2 = (2*t)/h*l - - # render your parts here - - if self.Sturdy: - width = sum(self.sy) + (len(self.sy) - 1) * t - self.rectangularWall(x, width, "fffe", callback=[None, self.xHoles, None, None], move="right", label="bottom") - self.rectangularWall(h, width, "fGfF" if self.Mounting else "fefF", callback=[None, None, None, self.hHoles], move="up", label="back") - self.rectangularWall(x, width, "fffe", callback=[None, self.xHoles, None, None], move="left only", label="invisible") - - for i in range(2): - self.move(x+x2+2*t + self.edges["f"].margin(), h+h1+2*t + self.edges["f"].margin(), "right", True, label="side " + str(i)) - self.polygonWallExt(borders=[x2, 0, 0, "e", x, 0, 0, "h",2*t, 90, 0, "e", 2*t, 0, 0, "e", h, 0, 0, "h",h1, 180-b, 0, "e", l+l1+l2, 180-c, 0, "e"]) - if self.Clamping: - self.hole(0, 0, 1, color=Color.ANNOTATIONS) - self.rectangularHole(x/2+x2,2*t+d/2,dx=d,dy=d,r=d/8) - self.rectangularHole((x+x2+2*t)-2*t-d/2,h/2+2*t,dx=d,dy=d,r=d/8) - self.move(x+x2+2*t + self.edges["f"].margin(), h+h1+2*t + self.edges["f"].margin(), "right", False, label="side " + str(i)) - - if len(self.sy) > 1: - for i in range(len(self.sy) - 1): - self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", True, label="support " + str(i)) - self.polygonWallExt(borders=[x, 90, 0, "f", h, 180-b, 0, "f", l, 180-c, 0, "e"]) - if self.Clamping: - self.rectangularHole(x/2,d/2-t/2,dx=d,dy=d+t,r=d/8) - self.rectangularHole(x-d/2+t/2,h/2,dx=d+t,dy=d,r=d/8) - self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", False, label="support " + str(i)) - else: - self.sy.insert(0,0) - self.sy.append(0) - width = sum(self.sy) + (len(self.sy) - 1) * t - self.rectangularWall(x, width, "efee", callback=[None, self.xHoles, None, None], move="right", label="bottom") - self.rectangularWall(h, width, "eGeF" if self.Mounting else "eeeF", callback=[None, None, None, self.hHoles], move="up", label="side") - self.rectangularWall(x, width, "efee", callback=[None, self.xHoles, None, None], move="left only", label="invisible") - - for i in range(len(self.sy) - 1): - self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", True, label="support " + str(i)) - self.polygonWallExt(borders=[x, 90, 0, "f", h, 180-b, 0, "f", l, 180-c, 0, "e"]) - if self.Clamping: - self.rectangularHole(x/2,d/2,dx=d,dy=d,r=d/8) - self.rectangularHole(x-d/2,h/2,dx=d,dy=d,r=d/8) - self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", False, label="support " + str(i)) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/heart.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/heart.py deleted file mode 100644 index 191e070..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/heart.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class HeartBox(Boxes): - """Box in the form of a heart""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=1.0,space=1.0) - self.addSettingsArgs(edges.FlexSettings) - self.buildArgParser(x=150, h=50) - self.argparser.add_argument( - "--top", action="store", type=str, default="closed", - choices=["closed", "hole", "lid",], - help="style of the top and lid") - - def CB(self): - x = self.x - t = self.thickness - - l = 2/3. * x - t - r = l/2. - t - d = 2 *t - - if self.top == "closed": - return - - for i in range(2): - self.moveTo(t, t) - self.polyline((l, 2), (180, r), (d, 1), -90, - (d, 1), (180, r), (l, 2), 90) - l -= t - r -= t - d += t - if self.top == "hole": - return - - def render(self): - x, h = self.x, self.h - t = self.thickness - - l = 2/3. * x - r = l/2. - 0.5*t - - borders = [l, (180, r), t, -90, t, (180, r), l, 90] - self.polygonWalls(borders, h) - self.rectangularWall(0, h, "FFFF", move="up only") - self.polygonWall(borders, callback=[self.CB], move="right") - self.polygonWall(borders, move="mirror right") - if self.top == "lid": - self.polygonWall([l+t, (180, r+t), 0, -90, 0, (180, r+t), l+t, 90], 'e') diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/hingebox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/hingebox.py deleted file mode 100644 index d25dda4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/hingebox.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class HingeBox(Boxes): - """Box with lid attached by cabinet hinges""" - - description = """Needs (metal) pins as hinge axles. Pieces of nails will -do fine. They need to be cut to length as they are captured as soon as the -hinges are assembled. - -Assemble the box and the lid separately. Then insert the axle into the hinges. -Then attach the hinges on the inside of the box and then connect them to lid. -""" - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.CabinetHingeSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--lidheight", action="store", type=float, default=20.0, - help="height of lid in mm") - self.argparser.add_argument( - "--splitlid", action="store", type=float, default=0.0, - help="split the lid in y direction (mm)") - - def render(self): - - x, y, h, hl = self.x, self.y, self.h, self.lidheight - s = self.splitlid - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - s = self.adjustSize(s, None) # reduce by half of the walls - - if s > x or s < 0.0: s = 0.0 - t = self.thickness - - # bottom walls - if s: - self.rectangularWall(x, h, "FFuF", move="right") - else: - self.rectangularWall(x, h, "FFeF", move="right") - self.rectangularWall(y, h, "Ffef", move="up") - self.rectangularWall(y, h, "Ffef") - self.rectangularWall(x, h, "FFuF", move="left up") - - # lid - self.rectangularWall(x, hl, "UFFF", move="right") - if s: - self.rectangularWall(s, hl, "eeFf", move="right") - self.rectangularWall(y-s, hl, "efFe", move="up") - self.rectangularWall(y-s, hl, "eeFf") - self.rectangularWall(s, hl, "efFe", move="left") - self.rectangularWall(x, hl, "UFFF", move="left up") - else: - self.rectangularWall(y, hl, "efFf", move="up") - self.rectangularWall(y, hl, "efFf") - self.rectangularWall(x, hl, "eFFF", move="left up") - - self.rectangularWall(x, y, "ffff", move="right only") - self.rectangularWall(x, y, "ffff") - if s: - self.rectangularWall(x, s, "ffef", move="left up") - self.rectangularWall(x, y-s, "efff", move="up") - else: - self.rectangularWall(x, y, "ffff", move="left up") - self.edges['u'].parts(move="up") - if s: - self.edges['u'].parts(move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/holepattern.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/holepattern.py deleted file mode 100644 index ac79544..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/holepattern.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (C) 2013-2022 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class HolePattern(Boxes): - """Generate hole patterns in different simple shapes""" - - ui_group = "Holes" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(fillHolesSettings, fill_pattern="hex") - - self.buildArgParser("x", "y") - self.argparser.add_argument( - "--shape", action="store", type=str, default="rectangle", - choices=["rectangle", "ellipse", "oval", "hexagon", "octagon"], - help="Shape of the hole pattern") - - def render(self): - x, y = self.x, self.y - - if self.shape == "ellipse": - border = [(x * (.5+math.sin(math.radians(a))/2), - y * (.5+math.cos(math.radians(a))/2)) - for a in range(0, 360, 18)] - elif self.shape == "oval": - r = min(x, y) / 2 - dx = max(x-y, 0) - dy = max(y-x, 0) - border = [(r * (.5+math.cos(math.radians(a))/2) + - (dx if q in [0, 3] else 0), - r * (.5+math.sin(math.radians(a))/2) + - (dy if q in [1, 2] else 0)) - for q in range(4) - for a in range(90*q, 90*q+91, 18)] - elif self.shape == "hexagon": - dx = min(y / (3**.5) / 2, x / 2) - border = [(dx, 0), (x-dx, 0), (x, .5*y), - (x-dx, y), (dx, y), (0, .5*y)] - elif self.shape == "octagon": - d = (2**.5/(2+2*2**.5)) - d2 = 1 -d - border = [(d*x, 0), (d2*x, 0), (x, d*y), (x, d2*y), - (d2*x, y), (d*x, y), (0, d2*y), (0, d*y)] - else: # "rectangle" - border = [(0, 0), (x, 0), (x, y), (0, y)] - - self.fillHoles( - pattern=self.fillHoles_fill_pattern, - border=border, - max_radius=self.fillHoles_hole_max_radius, - hspace=self.fillHoles_space_between_holes, - bspace=self.fillHoles_space_to_border, - min_radius=self.fillHoles_hole_min_radius, - style=self.fillHoles_hole_style, - bar_length=self.fillHoles_bar_length, - max_random=self.fillHoles_max_random - ) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/hooks.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/hooks.py deleted file mode 100644 index 393c16a..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/hooks.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Hook(Boxes): - """A hook with a rectangular mouth to mount at the wall""" - - ui_group = "Misc" # see ./__init__.py for names - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0.5) - self.argparser.add_argument("--width", action="store", - type=float, default=40., - help="width of the hook (back plate is a bit wider)") - self.argparser.add_argument("--height", action="store", - type=float, default=40., - help="inner height of the hook") - self.argparser.add_argument("--depth", action="store", - type=float, default=40., - help="inner depth of the hook") - self.argparser.add_argument("--strength", action="store", - type=float, default=20., - help="width of the hook from the side") - self.argparser.add_argument("--angle", action="store", - type=float, default=45., - help="angle of the support underneath") - - def render(self): - - self.angle = min(self.angle, 80) - t = self.thickness - w = self.width - 2*t # inner width - d, h, s = self.depth, self.height, self.strength - - self.rectangularWall(w + 4*t, self.height_back, 'Eeee', callback=self.back_callback, move='right') - self.sidewall(d, h, s, self.angle, move='right') - self.sidewall(d, h, s, self.angle, move='right') - self.rectangularWall(d, w, 'FFFf', move='right') - self.rectangularWall(h - t, w, 'FFFf', move='right', callback=[ - lambda: self.hole((h - t)/2, w/2, d=17)]) - self.rectangularWall(s-t, w, 'FeFf', move='right') - - - - def back_callback(self, n): - if n != 0: - return - - t = self.thickness - h = self.h_a + self.strength - - self.fingerHolesAt(1.5*t, 0, h) - self.fingerHolesAt(self.width + .5*t, 0, h) - self.fingerHolesAt(2*t, h + t/2, self.width - 2*t, 0) - - x_h = self.width/2 + t - - y1 = h + self.height/2 - y2 = self.strength/2 - y3 = (y1 + y2) / 2 - - self.hole(x_h, y1, d=3) - self.hole(x_h, y2, d=3) - self.hole(x_h, y3, d=3) - - - @property - def height_back(self): - - return self.strength + self.height + self.h_a - - @property - def h_a(self): - return self.depth * math.tan(math.radians(self.angle)) - - def sidewall(self, depth, height, strength, angle=60., move=None): - - t = self.thickness - - h_a = depth * math.tan(math.radians(angle)) - l_a = depth / math.cos(math.radians(angle)) - - f_edge = self.edges['f'] - - x_total = depth + strength + f_edge.margin() - y_total = strength + height + h_a - - if self.move(x_total, y_total, move, before=True): - return - - - self.moveTo(f_edge.margin()) - self.polyline(strength, angle, l_a, 90-angle, height+strength, 90) - - f_edge(strength - t) - self.corner(90) - f_edge(height - t) - - self.polyline(t, -90, t) - - f_edge(depth) - self.corner(90) - f_edge(h_a + strength) - self.corner(90) - - self.move(x_total, y_total, move) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/integratedhingebox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/integratedhingebox.py deleted file mode 100644 index 4288bc5..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/integratedhingebox.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class IntegratedHingeBox(Boxes): - """Box with lid and integraded hinge""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.ChestHingeSettings) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--lidheight", action="store", type=float, default=20.0, - help="height of lid in mm") - - - def render(self): - - x, y, h, hl = self.x, self.y, self.h, self.lidheight - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - - t = self.thickness - - hy = self.edges["O"].startwidth() - hy2 = self.edges["P"].startwidth() - - e1 = edges.CompoundEdge(self, "Fe", (h-hy, hy)) - e2 = edges.CompoundEdge(self, "eF", (hy, h-hy)) - e_back = ("F", e1, "e", e2) - - self.rectangularWall(y, h-hy, "FfOf", ignore_widths=[2], move="up") - self.rectangularWall(y, hl-hy2, "pfFf", ignore_widths=[1], move="up") - self.rectangularWall(y, h-hy, "Ffof", ignore_widths=[5], move="up") - self.rectangularWall(y, hl-hy2, "PfFf", ignore_widths=[6], move="up") - self.rectangularWall(x, h, "FFeF", move="up") - self.rectangularWall(x, h, e_back, move="up") - self.rectangularWall(x, hl, "FFeF", move="up") - self.rectangularWall(x, hl-hy2, "FFqF", move="up") - - self.rectangularWall(y, x, "ffff", move="up") - self.rectangularWall(y, x, "ffff") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/jigsaw.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/jigsaw.py deleted file mode 100644 index f47a7ff..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/jigsaw.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class JigsawPuzzle(Boxes): # change class name here and below - """Fractal jigsaw puzzle. Still alpha.""" - - webinterface = False # Change to make visible in web interface - - def __init__(self) -> None: - Boxes.__init__(self) - self.count = 0 - self.argparser.add_argument( - "--size", action="store", type=float, default=100, - help="size of the puzzle in mm") - self.argparser.add_argument( - "--depth", action="store", type=int, default=5, - help="depth of the recursion/level of detail") - - def peano(self, level): - if level == 0: - self.edge(self.size / self.depth) - return - - self.peano(self, level - 1) - self.corner() - - def edge(self, l): - self.count += 1 - Boxes.edge(self, l) - # if (self.count % 2**5) == 0: #level == 3 and parity>0: - # self.corner(-360, 0.25*self.size/2**self.depth) - - def hilbert(self, level, parity=1): - if level == 0: - return - # rotate and draw first subcurve with opposite parity to big curve - self.corner(parity * 90) - self.hilbert(level - 1, -parity) - - # interface to and draw second subcurve with same parity as big curve - self.edge(self.size / 2 ** self.depth) - self.corner(parity * -90) - self.hilbert(level - 1, parity) - - # third subcurve - self.edge(self.size / 2 ** self.depth) - self.hilbert(level - 1, parity) - - # if level == 3: self.corner(-360, 0.4*self.size/2**self.depth) - # fourth subcurve - self.corner(parity * -90) - self.edge(self.size / 2 ** self.depth) - self.hilbert(level - 1, -parity) - # a final turn is needed to make the turtle - # end up facing outward from the large square - self.corner(parity * 90) - # if level == 3 and parity>0: # and random.random() < 100*0.5**(self.depth-2): - # self.corner(-360, 0.4*self.size/2**self.depth) - # with self.savedcontext(): - # self.corner(parity*-90) - # self.edge(self.size/2**self.depth) - - def render(self): - size = self.size - t = self.thickness - self.burn = 0.0 - self.moveTo(10, 10) - self.hilbert(self.depth) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/jointpanel.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/jointpanel.py deleted file mode 100644 index be6e5e6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/jointpanel.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class JointPanel(Boxes): - """Create pieces larger than your laser cutter by joining them with Dove Tails""" - - description = """This can be used to just create a big panel in a smaller laser cutter. But the actual use is to split large parts into multiple smaller pieces. Copy the outline onto the sheet and then use the pieces to cut it into multiple parts that each can fit your laser cutter. Note that each piece must be cut with the sheet surrounding it to ensure the burn correction (aka kerf) is correct. Depending on your vector graphics software you may need to duplicate your part multiple times and then generate the intersection between one copy and each rectangular part. - -The Boxes.py drawings assume that the laser is cutting in the center of the line and the width of the line represents the material that is cut away. Make sure your changes work the same way and you do not cutting away the kerf. - -Small dove tails make it easier to fit parts in without problems. Lookout for pieces cut loose where the dove tails meet the edge of the parts. Move your part if necessary to avoid dove tails or details of your part colliding in a weird way. - -For plywood this method works well with a very stiff press fit. Aim for needing a hammer to join the pieces together. This way they will feel like they have been welder together. - -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs( - edges.DoveTailSettings, size=1, depth=.5, radius=.1) - self.buildArgParser(sx="400/2", sy="400/3") - self.argparser.add_argument( - "--separate", action="store", type=boolarg, default=False, - help="draw pieces apart so they can be cut to form a large sheet") - - def render(self): - sx, sy = self.sx, self.sy - t = self.thickness - - for ny, y in enumerate(sy): - t0 = "e" if ny == 0 else "d" - t2 = "e" if ny == len(sy) - 1 else "D" - with self.saved_context(): - for nx, x in enumerate(sx): - t1 = "e" if nx == len(sx) - 1 else "d" - t3 = "e" if nx == 0 else "D" - self.rectangularWall(x, y, [t0, t1, t2, t3]) - if self.separate: - self.rectangularWall(x, y, [t0, t1, t2, t3], - move="right only") - else: - self.moveTo(x) - if self.separate: - self.rectangularWall(x, y, [t0, t1, t2, t3], - move="up only") - else: - self.moveTo(0, y - self.edges["d"].spacing() if ny == 0 else y) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keyboard.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keyboard.py deleted file mode 100644 index f19bd12..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keyboard.py +++ /dev/null @@ -1,284 +0,0 @@ -# Copyright (C) 2021 Guillaume Collic -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import argparse -import re - -from boxes import boolarg - - -class Keyboard: - """ - Code to manage Cherry MX compatible switches and Kailh hotswap socket. - - Reference : - * https://www.cherrymx.de/en/dev.html - * https://cdn.sparkfun.com/datasheets/Components/Switches/MX%20Series.pdf - * https://www.kailhswitch.com/uploads/201815927/PG151101S11.pdf - """ - - STANDARD_KEY_SPACING = 19.05 - SWITCH_CASE_SIZE = 15.6 - FRAME_CUTOUT = 14 - - def __init__(self) -> None: - pass - - def add_common_keyboard_parameters( - self, - add_hotswap_parameter=True, - add_pcb_mount_parameter=True, - add_led_parameter=True, - add_diode_parameter=True, - add_cutout_type_parameter=True, - default_columns_definition=None, - ): - if add_hotswap_parameter: - self.argparser.add_argument( - "--hotswap_enable", - action="store", - type=boolarg, - default=True, - help=("enlarge switches holes for hotswap pcb sockets"), - ) - if add_pcb_mount_parameter: - self.argparser.add_argument( - "--pcb_mount_enable", - action="store", - type=boolarg, - default=True, - help=("adds holes for pcb mount switches"), - ) - if add_led_parameter: - self.argparser.add_argument( - "--led_enable", - action="store", - type=boolarg, - default=False, - help=("adds pin holes under switches for leds"), - ) - if add_diode_parameter: - self.argparser.add_argument( - "--diode_enable", - action="store", - type=boolarg, - default=False, - help=("adds pin holes under switches for diodes"), - ) - if add_cutout_type_parameter: - self.argparser.add_argument( - "--cutout_type", - action="store", - type=str, - default="castle", - help=( - "Shape of the plate cutout: 'castle' allows for modding, and 'simple' is a tighter and simpler square" - ), - ) - if default_columns_definition: - self.argparser.add_argument( - "--columns_definition", - type=self.argparseColumnsDefinition, - default=default_columns_definition, - help=( - "Each column is separated by '/', and is in the form 'nb_rows @ offset x repeat_count'. " - "Nb_rows is the number of rows for this column. " - "The offset is in mm and optional. " - "Repeat_count is optional and repeats this column multiple times. " - "Spaces are not important." - "For example '3x2 / 4@11' means we want 3 columns, the two first with " - "3 rows without offset, and the last with 4 rows starting at 11mm high." - ), - ) - - def argparseColumnsDefinition(self, s): - """ - Parse columns definition parameter - - :param s: string to parse - - Each column is separated by '/', and is in the form 'nb_rows @ offset x repeat_count'. - Nb_rows is the number of rows for this column. - The offset is in mm and optional. - Repeat_count is optional and repeats this column multiple times. - Spaces are not important. - For example '3x2 / 4@11' means we want 3 columns, the two first with - 3 rows without offset, and the last with 4 rows starting at 11mm high - """ - result = [] - try: - for column_string in s.split("/"): - m = re.match(r"^\s*(\d+)\s*@?\s*(\d*\.?\d*)(?:\s*x\s*(\d+))?\s*$", column_string) - keys_count = int(m.group(1)) - offset = float(m.group(2)) if m.group(2) else 0 - n = int(m.group(3)) if m.group(3) else 1 - result.extend([(offset, keys_count)]*n) - except: - raise argparse.ArgumentTypeError("Don't understand columns definition string") - - return result - - def pcb_holes( - self, with_hotswap=True, with_pcb_mount=True, with_led=False, with_diode=False - ): - grid_unit = 1.27 - main_hole_size = 4 - pcb_mount_size = 1.7 - led_hole_size = 1 - if with_hotswap: - pin_hole_size = 2.9 - else: - pin_hole_size = 1.5 - - def grid_hole(x, y, d): - self.hole(grid_unit * x, grid_unit * y, d=d) - - # main hole - grid_hole(0, 0, main_hole_size) - - # switch pins - grid_hole(-3, 2, pin_hole_size) - grid_hole(2, 4, pin_hole_size) - - if with_pcb_mount: - grid_hole(-4, 0, pcb_mount_size) - grid_hole(4, 0, pcb_mount_size) - - if with_led: - grid_hole(-1, -4, led_hole_size) - grid_hole(1, -4, led_hole_size) - - if with_diode: - grid_hole(-3, -4, led_hole_size) - grid_hole(3, -4, led_hole_size) - - def apply_callback_on_columns(self, cb, columns_definition, spacing=None, reverse=False): - if spacing is None: - spacing = self.STANDARD_KEY_SPACING - if reverse: - columns_definition = list(reversed(columns_definition)) - - for offset, nb_keys in columns_definition: - self.moveTo(0, offset) - for _ in range(nb_keys): - cb() - self.moveTo(0, spacing) - self.moveTo(spacing, -nb_keys * spacing) - self.moveTo(0, -offset) - - total_width = len(columns_definition) * spacing - self.moveTo(-1 * total_width) - - def outer_hole(self, radius=2, centered=True): - """ - Draws a rounded square big enough to go around a whole switch (15.6mm) - """ - half_size = Keyboard.SWITCH_CASE_SIZE / 2 - if centered: - self.moveTo(-half_size, -half_size) - - # draw clock wise to work with burn correction - straight_edge = Keyboard.SWITCH_CASE_SIZE - 2 * radius - polyline = [straight_edge, (-90, radius)] * 4 - self.moveTo(self.burn, radius, 90) - self.polyline(*polyline) - self.moveTo(0, 0, 270) - self.moveTo(0, -radius) - self.moveTo(-self.burn) - - if centered: - self.moveTo(half_size, half_size) - - def castle_shaped_plate_cutout(self, centered=True): - """ - This cutout shaped like a castle enables switch modding and rotation. - More information (type 4) on https://geekhack.org/index.php?topic=59837.0 - """ - half_size = Keyboard.SWITCH_CASE_SIZE / 2 - if centered: - self.moveTo(-half_size, -half_size) - - # draw clock wise to work with burn correction - btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505] - btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]] - btn = [*btn_full_side, -90] * 4 - - self.moveTo(self.burn+0.81, 0.81, 90) - self.polyline(*btn) - self.moveTo(0, 0, 270) - self.moveTo(-self.burn-0.81, -0.81) - - if centered: - self.moveTo(half_size, half_size) - - def configured_plate_cutout(self, support=False): - """ - Choose which cutout to use based on configured type. - - support: if true, not the main cutout, but one to glue against the first - 1.5mm cutout to strengthen it, without the clipping part. - """ - if self.cutout_type.lower() == "castle": - if support: - self.outer_hole() - else: - self.castle_shaped_plate_cutout() - else: - self.simple_plate_cutout(with_notch=support) - - def simple_plate_cutout(self, radius=0.2, with_notch=False): - """ - A simple plate cutout, a 14mm rectangle, as specified in this reference sheet - https://cdn.sparkfun.com/datasheets/Components/Switches/MX%20Series.pdf - - With_notch should be used for a secondary lower plate, strengthening the first one. - A notch is added to let the hooks grasp the main upper plate. - - Current position should be switch center. - - Radius should be lower or equal to 0.3 mm - """ - size = Keyboard.FRAME_CUTOUT - half_size = size / 2 - - if with_notch: - notch_length = 5 - notch_depth = 1 - straight_part = 0.5 * (size - 2 * radius - 2 * notch_depth - notch_length) - - self.moveTo(-half_size + self.burn, 0, 90) - polyline_quarter = [ - half_size - radius, - (-90, radius), - straight_part, - (90, notch_depth / 2), - 0, - (-90, notch_depth / 2), - notch_length / 2, - ] - polyline = ( - polyline_quarter - + [0] - + list(reversed(polyline_quarter)) - + [0] - + polyline_quarter - + [0] - + list(reversed(polyline_quarter)) - ) - self.polyline(*polyline) - self.moveTo(0, 0, -90) - self.moveTo(half_size - self.burn) - else: - self.rectangularHole(0, 0, size, size, r=radius) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keyholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keyholder.py deleted file mode 100644 index fef6eda..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keyholder.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class HangerEdge(edges.BaseEdge): - char = "H" - - def margin(self) -> float: - return self.hook_height * 0.7 - - def __call__(self, l, **kw): - # Radius of the bottom part of the hook - radius_outside = self.hook_height * 0.5 - radius_inside = radius_outside - self.hook_thickness - - # Make corners less sharp - radius_burr = 1.5 - - hookInnerHeight = self.hook_height * 0.7 - hookLength = self.hook_height * 0.7 - - # Correct orientation - self.polyline(0, -90) - - # Line bottom - self.edge(hookLength - radius_outside) - - # Outer corner - self.corner(90, radius_outside) - - # Line right - self.edge(hookInnerHeight - radius_outside - self.hook_thickness / 2) - - # Semicircle at top - self.corner(180, self.hook_thickness / 2) - - # Line left-ish - self.edge( - hookInnerHeight - - self.hook_thickness - - self.hook_thickness / 2 - - radius_inside - ) - - # Inner corner - self.corner(-90, radius_inside) - - # Line bottom - self.edge(hookLength - self.hook_thickness - 2 * radius_burr - radius_inside) - self.corner(-90, radius_burr) - - # Line top - self.edge(self.hook_height - self.hook_thickness - 2 * radius_burr) - self.corner(90, radius_burr) - - # Correct orientation - self.polyline(0, -90) - - -class KeyHolder(Boxes): - """Wall organizer with hooks for keys or similar small items""" - - description = """Example for a KeyHolder with a slightly larger backplate and 8 hooks. This uses 6mm plywood for extra stability. - -Closeup: - -![KeyHolder-2](static/samples/KeyHolder-2.jpg) - -Full picture: -""" - - ui_group = "WallMounted" - - def __init__(self) -> None: - Boxes.__init__(self) - self.argparser.add_argument( - "--num_hooks", action="store", type=int, default=7, help="Number of hooks" - ) - self.argparser.add_argument( - "--hook_distance", - action="store", - type=float, - default=20, - help="Distance between hooks", - ) - self.argparser.add_argument( - "--hook_thickness", - action="store", - type=float, - default=5, - help="Thickness of hook", - ) - self.argparser.add_argument( - "--hook_height", - action="store", - type=float, - default=20, - help="Height of back part of hook", - ) - - # Padding around the hooks to define the size of the back plate - self.argparser.add_argument( - "--padding_top", - action="store", - type=float, - default=10, - help="Padding above hooks", - ) - self.argparser.add_argument( - "--padding_left_right", - action="store", - type=float, - default=5, - help="Padding left/right from hooks", - ) - self.argparser.add_argument( - "--padding_bot", - action="store", - type=float, - default=30, - help="Padding below hooks", - ) - - self.argparser.add_argument( - "--mounting", - action="store", - type=boolarg, - default=False, - help="Add mounting holes", - ) - - self.addSettingsArgs( - edges.FingerJointSettings, surroundingspaces=0.0, finger=1.0, space=1.0 - ) - self.addSettingsArgs(edges.MountingSettings) - - def yHoles(self): - """ - Holes for hooks to attach to - """ - posx = 0.5 * self.thickness - posx += self.padding_left_right - for _ in range(self.num_hooks): - self.fingerHolesAt(posx, self.padding_bot, self.hook_height) - posx += self.hook_distance + self.thickness - - def render(self): - self.addPart(HangerEdge(self, 1)) - - # Total height and width of the backplate - h = self.hook_height + self.padding_bot + self.padding_top - w = ( - (self.padding_left_right * 2) - + self.num_hooks * self.thickness - + (self.num_hooks - 1) * self.hook_distance - ) - - # Back plate - self.rectangularWall( - w, - h, - "eeGe" if self.mounting else "eeee", - callback=[self.yHoles, None, None, None], - move="up", - ) - - # Hooks - for _ in range(self.num_hooks): - self.rectangularWall( - self.hook_thickness, self.hook_height, "eHef", move="right" - ) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keypad.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keypad.py deleted file mode 100644 index 1696356..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/keypad.py +++ /dev/null @@ -1,140 +0,0 @@ -"""Generator for keypads with mechanical switches.""" - -from copy import deepcopy - -from boxes import Boxes, boolarg -from boxes.edges import FingerJointSettings - -from .keyboard import Keyboard - - -class Keypad(Boxes, Keyboard): - """Generator for keypads with mechanical switches.""" - - description = "Note that top layers use a different material thickness according to the top1_thickness and top2_thickness (if enabled)." - - ui_group = 'Box' - btn_size = 15.6 - space_between_btn = 4 - box_padding = 10 - triangle = 25.0 - - def __init__(self) -> None: - super().__init__() - self.argparser.add_argument( - '--h', action='store', type=int, default=30, - help='height of the box' - ) - self.argparser.add_argument( - '--top1_thickness', action='store', type=float, default=1.5, - help=('thickness of the button hold layer, cherry like switches ' - 'need 1.5mm or smaller to snap in') - ) - self.argparser.add_argument( - '--top2_enable', action='store', type=boolarg, default=False, - help=('enables another top layer that can hold CPG151101S11 ' - 'hotswap sockets') - ) - self.argparser.add_argument( - '--top2_thickness', action='store', type=float, default=1.5, - help=('thickness of the hotplug layer, CPG151101S11 hotswap ' - 'sockets need 1.2mm to 1.5mm') - ) - - # Add parameter common with other keyboard projects - self.add_common_keyboard_parameters( - # Hotswap already depends on top2_enable setting, a second parameter - # for it would be useless - add_hotswap_parameter=False, - # By default, 3 columns of 4 rows - default_columns_definition="4x3" - ) - - self.addSettingsArgs(FingerJointSettings, surroundingspaces=1) - - def _get_x_y(self): - """Gets the keypad's size based on the number of buttons.""" - spacing = self.btn_size + self.space_between_btn - border = 2*self.box_padding - self.space_between_btn - x = len(self.columns_definition) * spacing + border - y = max(offset + keys * spacing for (offset, keys) in self.columns_definition) + border - return x, y - - def render(self): - """Renders the keypad.""" - # deeper edge for top to add multiple layers - deep_edge = deepcopy(self.edges['f'].settings) - deep_edge.thickness = self.thickness + self.top1_thickness - if self.top2_enable: - deep_edge.thickness += self.top2_thickness - deep_edge.edgeObjects(self, 'gGH', True) - - d1, d2 = 2., 3. - x, y = self._get_x_y() - h = self.h - - # box sides - self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="right") - self.rectangularWall(y, h, "GfEf", callback=[self.wally_cb], move="up") - self.rectangularWall(y, h, "GfEf", callback=[self.wally_cb]) - self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="left up") - - # keypad lids - self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.support_hole), move="right") - self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.key_hole), move="up") - if self.top2_enable: - self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.hotplug)) - - # screwable - tr = self.triangle - trh = tr / 3 - self.rectangularWall( - x, y, - callback=[lambda: self.hole(trh, trh, d=d2)] * 4, - move='left up' - ) - self.rectangularTriangle( - tr, tr, "ffe", num=4, - callback=[None, lambda: self.hole(trh, trh, d=d1)] - ) - - def to_grid_callback(self, inner_callback): - def callback(): - # move to first key center - key_margin = self.box_padding + self.btn_size / 2 - self.moveTo(key_margin, key_margin) - self.apply_callback_on_columns( - inner_callback, self.columns_definition, self.btn_size + self.space_between_btn - ) - - return [callback] - - def hotplug(self): - """Callback for the key stabilizers.""" - self.pcb_holes( - with_pcb_mount=self.pcb_mount_enable, - with_diode=self.diode_enable, - with_led=self.led_enable, - ) - - def support_hole(self): - self.configured_plate_cutout(support=True) - - def key_hole(self): - self.configured_plate_cutout() - - # stolen form electronics-box - def wallx_cb(self): - """Callback for triangle holes on x-side.""" - x, _ = self._get_x_y() - t = self.thickness - self.fingerHolesAt(0, self.h - 1.5 * t, self.triangle, 0) - self.fingerHolesAt(x, self.h - 1.5 * t, self.triangle, 180) - - # stolen form electronics-box - def wally_cb(self): - """Callback for triangle holes on y-side.""" - _, y = self._get_x_y() - t = self.thickness - self.fingerHolesAt(0, self.h - 1.5 * t, self.triangle, 0) - self.fingerHolesAt(y, self.h - 1.5 * t, self.triangle, 180) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/lamp.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/lamp.py deleted file mode 100644 index 03ad9ad..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/lamp.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - -""" -22x7.5x7cm -D=23cm, d=21cm -d = 8" D = 9" -""" - - -class RoundedTriangleSettings(edges.Settings): - absolute_params = { - "angle": 60, - "radius": 30, - "r_hole": 0.0, - } - - -class RoundedTriangle(edges.Edge): - char = "t" - - def __call__(self, length, **kw): - angle = self.settings.angle - r = self.settings.radius - - if self.settings.r_hole: - x = 0.5 * (length - 2 * r) * math.tan(math.radians(angle)) - y = 0.5 * (length) - self.hole(x, y, self.settings.r_hole) - - l = 0.5 * (length - 2 * r) / math.cos(math.radians(angle)) - self.corner(90 - angle, r) - self.edge(l) - self.corner(2 * angle, r) - self.edge(l) - self.corner(90 - angle, r) - - def startAngle(self) -> float: - return 90.0 - - def endAngle(self) -> float: - return 90.0 - - -class Lamp(Boxes): - webinterface = False - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser(x=220, y=75, h=70) - self.argparser.add_argument( - "--radius", action="store", type=float, default="105", - help="radius of the lamp") - self.argparser.add_argument( - "--width", action="store", type=float, default="10", - help="width of the ring") - - def side(self, y, h): - return - self.edges["f"](y) - self.corner(90) - self.edges["f"](h) - self.roundedTriangle(y, 75, 25) - self.edges["f"](h) - self.corner(90) - - def render(self): - """ - r : radius of lamp - w : width of surrounding ring - x : length box - y : width box - h : height box - """ - - - # self.edges["f"].settings = (5, 5) # XXX - - x, y, h = self.x, self.y, self.h - r, w = self.radius, self.width - - s = RoundedTriangleSettings(self.thickness, angle=72, r_hole=2) - self.addPart(RoundedTriangle(self, s)) - - self.flexSettings = (3, 5.0, 20.0) - - self.edges["f"].settings.setValues(self.thickness, finger=5, space=5, relative=False) - d = 2 * (r + w) - - self.roundedPlate(d, d, r, move="right", callback=[ - lambda: self.hole(w, r + w, r), ]) - - # dist = ((2**0.5)*r-r) / (2**0.5) + 4 - # pos = (w-dist, dist) - self.roundedPlate(d, d, r, holesMargin=w / 2.0) # , callback=[ - # lambda: self.hole(pos[0], pos[1], 7),]) - self.roundedPlate(d, d, r, move="only left up") - - hole = lambda: self.hole(w, 70, 2) - self.surroundingWall(d, d, r, 120, top='h', bottom='h', callback=[ - None, hole, None, hole], move="up") - - with self.saved_context(): - self.rectangularWall(x, y, edges="fFfF", holesMargin=5, move="right") - self.rectangularWall(x, y, edges="fFfF", holesMargin=5, move="right") - # sides - self.rectangularWall(y, h, "fftf", move="right") - self.rectangularWall(y, h, "fftf") - - self.rectangularWall(x, y, edges="fFfF", holesMargin=5, - move="up only") - - self.rectangularWall(x, h, edges='hFFF', holesMargin=5, move="right") - self.rectangularWall(x, h, edges='hFFF', holesMargin=5) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laptopstand.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laptopstand.py deleted file mode 100644 index f977970..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laptopstand.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from math import * - -from boxes import * - - -class LaptopStand(Boxes): # Change class name! - """A simple X shaped frame to support a laptop on a given angle""" - - ui_group = "Misc" # see ./__init__.py for names - - def __init__(self) -> None: - Boxes.__init__(self) - - self.argparser.add_argument( - "--l_depth", - action="store", - type=float, - default=250, - help="laptop depth - front to back (mm)", - ) - self.argparser.add_argument( - "--l_thickness", - action="store", - type=float, - default=10, - help="laptop thickness (mm)", - ) - self.argparser.add_argument( - "--angle", - action="store", - type=float, - default=15, - help="desired tilt of keyboard (deg)", - ) - self.argparser.add_argument( - "--ground_offset", - action="store", - type=float, - default=10, - help="desired height between bottom of laptop and ground at lowest point (front of laptop stand)", - ) - self.argparser.add_argument( - "--nub_size", - action="store", - type=float, - default=10, - help="desired thickness of the supporting edge", - ) - - def render(self): - calcs = self.perform_calculations() - - self.laptopstand_triangles(calcs, move="up") - - def perform_calculations(self): - # a - angle_rads_a = math.radians(self.angle) - - # h - height = self.l_depth * math.sin(angle_rads_a) - - # y - base = sqrt(2) * self.l_depth * math.cos(angle_rads_a) - - # z - hyp = self.l_depth * sqrt(math.pow(math.cos(angle_rads_a), 2) + 1) - - # b - angle_rads_b = math.atan(math.tan(angle_rads_a) / math.sqrt(2)) - - # g - base_extra = ( - 1 - / math.cos(angle_rads_b) - * (self.nub_size - self.ground_offset * math.sin(angle_rads_b)) - ) - - # x - lip_outer = ( - self.ground_offset / math.cos(angle_rads_b) - + self.l_thickness - - self.nub_size * math.tan(angle_rads_b) - ) - - bottom_slot_depth = (height / 4) + (self.ground_offset / 2) - - top_slot_depth_big = ( - height / 4 + self.ground_offset / 2 + (self.thickness * height) / (2 * base) - ) - - top_slot_depth_small = ( - height / 4 + self.ground_offset / 2 - (self.thickness * height) / (2 * base) - ) - - half_hyp = (hyp * (base - self.thickness)) / (2 * base) - - return dict( - height=height, - base=base, - hyp=hyp, - angle=math.degrees(angle_rads_b), - base_extra=base_extra, - lip_outer=lip_outer, - bottom_slot_depth=bottom_slot_depth, - top_slot_depth_small=top_slot_depth_small, - top_slot_depth_big=top_slot_depth_big, - half_hyp=half_hyp, - ) - - def laptopstand_triangles(self, calcs, move=None): - tw = calcs["base"] + self.spacing + 2 * (calcs["base_extra"] + math.sin(math.radians(calcs["angle"]))*(calcs["lip_outer"]+1)) - th = calcs["height"] + 2 * self.ground_offset + self.spacing - - if self.move(tw, th, move, True): - return - self.moveTo(calcs["base_extra"]+self.spacing + math.sin(math.radians(calcs["angle"]))*(calcs["lip_outer"]+1)) - self.draw_triangle(calcs, top=False) - self.moveTo(calcs["base"] - self.spacing, - th, 180) - self.draw_triangle(calcs, top=True) - - self.move(tw, th, move) - - @restore - def draw_triangle(self, calcs, top): - # Rear end - self.moveTo(0, calcs["height"] + self.ground_offset, -90) - - self.edge(calcs["height"] + self.ground_offset) - self.corner(90) - - foot_length = 10 + self.nub_size - - base_length_without_feet = ( - calcs["base"] - foot_length * 2 - 7 # -7 to account for extra width gained by 45deg angles - ) - - if top: - # Bottom without slot - self.polyline( - foot_length, 45, - 5, -45, - base_length_without_feet, -45, - 5, 45, - foot_length + calcs["base_extra"], 0, - ) - else: - # Bottom with slot - self.polyline( - foot_length, 45, - 5, -45, - (base_length_without_feet - self.thickness) / 2, 90, - calcs["bottom_slot_depth"] - 3.5, -90, - self.thickness, -90, - calcs["bottom_slot_depth"] - 3.5, 90, - (base_length_without_feet - self.thickness) / 2, -45, - 5, 45, - foot_length + calcs["base_extra"], 0, - ) - - # End nub - self.corner(90 - calcs["angle"]) - self.edge(calcs["lip_outer"]) - self.corner(90, 1) - self.edge(self.nub_size - 2) - self.corner(90, 1) - self.edge(self.l_thickness) - self.corner(-90) - - if top: - # Top with slot - self.edge(calcs["half_hyp"]) - self.corner(90 + calcs["angle"]) - self.edge(calcs["top_slot_depth_small"]) - self.corner(-90) - self.edge(self.thickness) - self.corner(-90) - self.edge(calcs["top_slot_depth_big"]) - self.corner(90 - calcs["angle"]) - self.edge(calcs["half_hyp"]) - else: - # Top without slot - self.edge(calcs["hyp"]) - - self.corner(90 + calcs["angle"]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laserclamp.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laserclamp.py deleted file mode 100644 index 5370a4e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laserclamp.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class LaserClamp(Boxes): - """A clamp to hold down material to a knife table""" - - description = """You need a tension spring of the proper length to make the clamp work. -Increase extraheight to get more space for the spring and to make the -sliding mechanism less likely to bind. You may need to add some wax on the -parts sliding on each other to reduce friction. -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0) - self.argparser.add_argument( - "--minheight", action="store", type=float, default=25., - help="minimal clamping height in mm") - self.argparser.add_argument( - "--maxheight", action="store", type=float, default=50., - help="maximal clamping height in mm") - self.argparser.add_argument( - "--extraheight", action="store", type=float, default=0., - help="extra height to make operation smoother in mm") - - def topPart(self, l, move=None): - t = self. thickness - - tw, th = 12*t, l+4*t - - if self.move(tw, th, move, True): - return - - self.moveTo(8*t, 0) - self.rectangularHole(t, 2*t+l/2, 1.05*t, l) - self.polyline(2*t, (90, t), l+1.5*t, (-90, 0.5*t), - 2*t, -90, 0, (180, 0.5*t), 0, - (90, 1.5*t), 9*t, - (180, 4*t), 2*t, (-90, t)) - self.hole(-5*t, -3*t, 2.5*t) - self.polyline(l-5.5*t, (90, t)) - self.move(tw, th, move) - - def bottomPart(self, h_min, h_extra, move=None): - t = self. thickness - - tw, th = 14*t, h_min+4*t - - if self.move(tw, th, move, True): - return - - ls = t/2*(2**.5) - self.moveTo(2*t, 0) - self.fingerHolesAt(3*t, 2*t, h_min+h_extra, 90) - if h_extra: - self.polyline(4*t, (90,t), h_extra-2*t, (-90, t)) - else: - self.polyline(6*t) - self.polyline(4*t, (90, 2*t), 3*t, 135, 2*ls, 45, 1*t, -90, 6*t, -90) - - self.polyline(h_min, (90, t), 2*t, (90, t), - h_min+h_extra-0*t, (-90, t), t, (180, t), - 0, 90, 0, (-180, 0.5*t), 0 , 90) - - self.move(tw, th, move) - - def render(self): - t = self. thickness - h_max, h_min, h_extra = self.maxheight, self.minheight,self.extraheight - - if h_extra and h_extra < 2*t: - h_extra = 2*t - - self.topPart(h_max+h_extra, move="right") - self.bottomPart(h_min, h_extra, move="right") - self.roundedPlate(4*t, h_min+h_extra+4*t, edge="e", r=t, - extend_corners=False, move="right", - callback=[lambda: self.fingerHolesAt(1*t, 2*t, h_min+h_extra)]) - self.rectangularWall(1.1*t, h_min+h_extra, "efef") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laserholdfast.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laserholdfast.py deleted file mode 100644 index cd293a6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/laserholdfast.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class LaserHoldfast(Boxes): - """A holdfast for honey comb tables of laser cutters""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.buildArgParser(x=25, h=40) - self.argparser.add_argument( - "--hookheight", action="store", type=float, default=5.0, - help="height of the top hook") - self.argparser.add_argument( - "--shaftwidth", action="store", type=float, default=5.0, - help="width of the shaft") - - def render(self): - # adjust to the variables you want in the local scope - x, hh, h, sw = self.x, self.hookheight, self.h, self.shaftwidth - t = self.thickness - - a = 30 - r = x/math.radians(a) - - self.polyline(hh+h, (180, sw/2), h, -90+a/2, 0, (-a, r), 0, (180, hh/2), 0, (a, r+hh), 0 , -a/2, sw-math.sin(math.radians(a/2))*hh , 90) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/lbeam.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/lbeam.py deleted file mode 100644 index d360b3e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/lbeam.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class LBeam(Boxes): - """Simple L-Beam: two pieces joined with a right angle""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("x", "y", "h", "outside") - self.addSettingsArgs(edges.FingerJointSettings) - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - - if self.outside: - x = self.adjustSize(x, False) - y = self.adjustSize(y, False) - - - - self.rectangularWall(x, h, "eFee", move="right") - self.rectangularWall(y, h, "eeef") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/magazinefile.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/magazinefile.py deleted file mode 100644 index 7716901..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/magazinefile.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.lids import _TopEdge - - -class MagazineFile(Boxes): - """Open magazine file""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser(x=100, y=200, h=300, hi=0, outside=False) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.MountingSettings, margin=0, num=1) - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("eG"), choices=list("eG"), - default="e", help="edge type for top edge") - - def side(self, w, h, hi, top_edge): - r = min(h - hi, w) / 2.0 - - if (h - hi) > w: - r = w / 2.0 - lx = 0 - ly = (h - hi) - w - else: - r = (h - hi) / 2.0 - lx = (w - 2 * r) / 2.0 - ly = 0 - - top_edge = self.edges.get(top_edge, top_edge) - - e_w = self.edges["F"].startwidth() - self.moveTo(3, 3) - self.edge(e_w) - self.edges["F"](w) - self.edge(e_w) - self.corner(90) - self.edge(e_w) - self.edges["F"](hi) - self.corner(90) - self.edge(e_w) - top_edge(lx) - self.corner(-90, r) - self.edge(ly) - self.corner(90, r) - top_edge(lx) - self.edge(e_w) - self.corner(90) - self.edges["F"](h) - self.edge(e_w) - self.corner(90) - - def render(self): - - if self.outside: - self.x = self.adjustSize(self.x) - self.y = self.adjustSize(self.y) - self.h = self.adjustSize(self.h, e2=False) - - x, y, h, = self.x, self.y, self.h - self.hi = hi = self.hi or (h / 2.0) - t = self.thickness - t1, t2, t3, t4 = _TopEdge.topEdges(self, self.top_edge) - - - with self.saved_context(): - self.rectangularWall(x, h, ["F", "f", t2, "f"], move="up") - self.rectangularWall(x, hi, "Ffef", move="up") - self.rectangularWall(x, y, "ffff") - - self.rectangularWall(x, h, "Ffef", move="right only") - self.side(y, h, hi, t1) - self.moveTo(y + 15, h + hi + 15, 180) - self.side(y, h, hi, t3) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/makitapowersupply.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/makitapowersupply.py deleted file mode 100644 index 949ce06..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/makitapowersupply.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class MakitaPowerSupply(Boxes): - """Bench power supply powered with Maktia 18V battery or laptop power supply""" - - description = """ -Vitamins: DSP5005 (or similar) power supply, two banana sockets, two 4.8mm flat terminals with flat soldering tag - -To allow powering by laptop power supply: flip switch, Lenovo round socket (or adjust right hole for different socket) -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - self.argparser.add_argument("--banana_socket_diameter", action="store", - type=float, default=8.0, - help="diameter of the banana socket mounting holes") - - self.argparser.add_argument("--flipswitch_diameter", action="store", - type=float, default=6.3, - help="diameter of the flipswitch mounting hole") - - - def side(self, l, h=14, move=None): - t = self.thickness - tw, th = h+t, l - - if self.move(tw, th, move, True): - return - - self.moveTo(t, 0) - self.polyline(h, 90, l-h/3**0.5, 60, h*2/3**0.5, 120) - self.edges["f"](l) - - self.move(tw, th, move) - - def side2(self, l, h=14, move=None): - t = self.thickness - tw, th = h, l-10 - - if self.move(tw, th, move, True): - return - - if h > 14: - self.polyline(h, 90, l-12, 90, h-14, 90, 50-12, -90, 8, -90) - else: - self.polyline(h, 90, l-50, 90, h-6, -90) - self.polyline(11, 90, 1, -90, 27, (90, 1), - 3, (90, 1), l-12, 90) - - self.move(tw, th, move) - - - def bottom(self): - t = self.thickness - m = self.x / 2 - - self.fingerHolesAt(m-30.5-0.5*t, 10, self.l) - self.fingerHolesAt(m+30.5+0.5*t, 10, self.l) - - self.rectangularHole(m-19, 10+34, 0.8, 6.25) - self.rectangularHole(m+19, 10+34, 0.8, 6.25) - - self.rectangularHole(m, 7.5, 35, 5) - - def front(self): - d_b = self.banana_socket_diameter - d_f = self.flipswitch_diameter - - self.hole(10, self.h/2, d=d_b) - self.hole(30, self.h/2, d=d_b) - self.hole(50, self.h/2, d=d_f) - - self.rectangularHole(76, 6.4, 12.4, 12.4) - - def back(self): - n = int((self.h-2*self.thickness) // 8) - offs = (self.h - n*8.0) / 2 + 4 - for i in range(n): - self.rectangularHole(self.x/2, i*8+offs, self.x-20, 5, r=2.5) - - def regulatorCB(self): - self.rectangularHole(21, 9.5, 35, 5) - self.rectangularHole(5, 33+12, 10, 10) - self.rectangularHole(42-5, 33+12, 10, 10) - - for x in [3.5, 38.5]: - for y in [3.5, 65]: - self.hole(x, y, 1.0) - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - - l = self.l = 64 - hm = 15.5 - - self.x, self.y, self.h = x, y, h = 85, 75, 35 - - self.rectangularWall(x, h, "FFFF", callback=[self.front], move="right") - self.rectangularWall(y, h, "FfFf", move="up") - self.rectangularWall(y, h, "FfFf") - self.rectangularWall(x, h, "FFFF", callback=[self.back], move="left up") - - self.rectangularWall(x, y, "ffff", callback=[self.bottom], move="right") - self.rectangularWall(x, y, "ffff", callback=[ - lambda: self.rectangularHole(x/2, y-20-5, 76, 40)], move="") - self.rectangularWall(x, y, "ffff", move="left up only") - - self.side(l, hm, move="right") - self.side(l, hm, move="right mirror") - self.side2(l, hm, move="right") - self.side2(l, hm, move="right mirror") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/microrack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/microrack.py deleted file mode 100644 index 92cd3f4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/microrack.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (C) 2019 Gabriel Morell -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import Boxes, boolarg, edges - - -class SBCMicroRack(Boxes): - """Stackable rackable racks for SBC Pi-Style Computers""" - - webinterface = True - ui_group = "Shelf" # see ./__init__.py for names - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=56, y=85) - - # count - self.argparser.add_argument( - "--sbcs", action="store", type=int, default=5, - help="how many slots for sbcs", - ) - - # spaces - self.argparser.add_argument( - "--clearance_x", action="store", type=int, default=3, - help="clearance for the board in the box (x) in mm" - ) - self.argparser.add_argument( - "--clearance_y", action="store", type=int, default=3, - help="clearance for the board in the box (y) in mm" - ) - self.argparser.add_argument( - "--clearance_z", action="store", type=int, default=28, - help="SBC Clearance in mm", - ) - - # mounting holes - self.argparser.add_argument( - "--hole_dist_edge", action="store", type=float, default=3.5, - help="hole distance from edge in mm" - ) - self.argparser.add_argument( - "--hole_grid_dimension_x", action="store", type=int, default=58, - help="width of x hole area" - ) - self.argparser.add_argument( - "--hole_grid_dimension_y", action="store", type=int, default=49, - help="width of y hole area" - ) - self.argparser.add_argument( - "--hole_diameter", action="store", type=float, default=2.75, - help="hole diameters" - ) - - # i/o holes - self.argparser.add_argument( - "--netusb_z", action="store", type=int, default=18, - help="height of the net/usb hole mm" - ) - self.argparser.add_argument( - "--netusb_x", action="store", type=int, default=53, - help="width of the net/usb hole in mm" - ) - - # features - self.argparser.add_argument( - "--stable", action='store', type=boolarg, default=False, - help="draw some holes to put a 1/4\" dowel through at the base and top" - ) - self.argparser.add_argument( - "--switch", action='store', type=boolarg, default=False, - help="adds an additional vertical segment to hold the switch in place, works best w/ --stable" - ) - # TODO flesh this idea out better - #self.argparser.add_argument( - # "--fan", action='store', type=int, default=0, required=False, - # help="ensure that the x width is at least this much and as well, draw a snug holder for a fan someplace" - # ) - - - def paint_mounting_holes(self): - cy = self.clearance_y - cx = self.clearance_x - - h2r = self.hole_diameter - hde = self.hole_dist_edge - hgdx = self.hole_grid_dimension_x - hgdy = self.hole_grid_dimension_y - - self.hole( - h2r + cx + hde / 2, - h2r + cy + hde / 2, - h2r / 2 - ) - - self.hole( - h2r + cx + hgdx + hde / 2, - h2r + cy + hde / 2, - h2r / 2 - ) - - self.hole( - h2r + cx + hde / 2, - h2r + cy + hgdy + hde / 2, - h2r / 2 - ) - - self.hole( - h2r + cx + hgdx + hde / 2, - h2r + cy + hgdy + hde / 2, - h2r / 2 - ) - - def paint_stable_features(self): - if self.stable: - self.hole( - 10, 10, d=6.5 - ) - - def paint_netusb_holes(self): - t = self.thickness - x = self.x - w = x + self.hole_dist_edge * 2 - height_per = self.clearance_z + t - usb_height = self.netusb_z - usb_width = self.netusb_x - for i in range(self.sbcs): - self.rectangularHole(w/2, (height_per)*i+15 , usb_width, usb_height, r=1) - - def paint_finger_holes(self): - t = self.thickness - height_per = self.clearance_z + t - for i in range(self.sbcs): - self.fingerHolesAt((height_per) * i + +height_per/2 + 1.5, self.hole_dist_edge, self.x, 90) - - def render(self): - # adjust to the variables you want in the local scope - x, y = self.x, self.y - t = self.thickness - - height_per = self.clearance_z + t - height_total = self.sbcs * height_per - - # render your parts here - - with self.saved_context(): - self.rectangularWall(height_total + height_per/2, - x + self.hole_dist_edge * 2, - "eseS", - callback=[self.paint_finger_holes, - self.paint_netusb_holes], - move="up") - - self.rectangularWall(height_total + height_per/2, - x + self.hole_dist_edge * 2, - "eseS", - callback=[self.paint_finger_holes, - self.paint_stable_features], - move="up") - - if self.switch: - self.rectangularWall(height_total + height_per / 2, - x + self.hole_dist_edge * 2, - "eseS", - callback=[self.paint_stable_features], - move="up") - - self.rectangularWall(height_total + height_per/2, - x + self.hole_dist_edge * 2, - "eseS", - move="right only") - - self.rectangularWall(y + self.hole_dist_edge * 2, - x + self.hole_dist_edge * 2, - "efef", - move="up") - - for i in range(self.sbcs): - self.rectangularWall(y + self.hole_dist_edge * 2, - x + self.hole_dist_edge * 2, - "efef", - callback=[self.paint_mounting_holes], - move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/nemamount.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/nemamount.py deleted file mode 100644 index 6ccc4d2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/nemamount.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class NemaMount(Boxes): - """Mounting bracket for a Nema motor""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--size", action="store", type=int, default=8, - choices=list(sorted(self.nema_sizes.keys())), - help="Nema size of the motor") - - def render(self): - motor, flange, holes, screws = self.nema_sizes.get( - self.size, self.nema_sizes[8]) - t = self.thickness - - x = y = h = motor + 2*t - - - self.rectangularWall(x, y, "ffef", callback=[ - lambda: self.NEMA(self.size, x/2, y/2)], move="right") - self.rectangularTriangle(x, h, "fFe", num=2, move="right") - self.rectangularWall(x, h, "FFeF", callback=[ - - lambda:self.rectangularHole((x-holes)/2, y/2, screws, holes, - screws/2), - None, - lambda:self.rectangularHole((x-holes)/2, y/2, screws, holes, - screws/2)], - move="right") - self.moveTo(t, 0) - self.fingerHolesAt(0.5*t, t, x, 90) - self.fingerHolesAt(1.5*t+x, t, x, 90) - self.fingerHolesAt(t, 0.5*t, x, 0) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/nemapattern.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/nemapattern.py deleted file mode 100644 index 0976f66..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/nemapattern.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class NemaPattern(Boxes): - """Mounting holes for a Nema motor""" - - ui_group = "Holes" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--size", action="store", type=int, default=8, - choices=list(sorted(self.nema_sizes.keys())), - help="Nema size of the motor") - self.argparser.add_argument( - "--screwholes", action="store", type=float, default=0.0, - help="Size of the screw holes in mm - 0 for default size") - - def render(self): - motor, flange, holes, screws = self.nema_sizes.get( - self.size, self.nema_sizes[8]) - - self.NEMA(self.size, motor/2, motor/2, screwholes=self.screwholes) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/notesholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/notesholder.py deleted file mode 100644 index 90c6161..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/notesholder.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.edges import CompoundEdge, Edge - - -class USlotEdge(Edge): - - def __init__(self, boxes, settings, edge="f"): - super().__init__(boxes, settings) - self.e = edge - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - l = length - o = self.settings - d = length * (1-o/100) / 2 - r = min(3*self.thickness, (l-2*d)/2) - self.edges[self.e](d) - self.step(-self.edges[self.e].endwidth()) - self.polyline(0, 90, 0, (-90, r), l-2*d-2*r, (-90, r), 0, 90) - self.step(self.edges[self.e].startwidth()) - self.edges[self.e](d) - - def margin(self) -> float: - return self.edges[self.e].margin() - - def startwidth(self): - return self.edges[self.e].startwidth() - -class HalfStackableEdge(edges.StackableEdge): - - char = 'H' - - def __call__(self, length, **kw): - s = self.settings - r = s.height / 2.0 / (1 - math.cos(math.radians(s.angle))) - l = r * math.sin(math.radians(s.angle)) - p = 1 if self.bottom else -1 - - if self.bottom: - self.boxes.fingerHolesAt(0, s.height + self.settings.holedistance + 0.5 * self.boxes.thickness, - length, 0) - - self.boxes.edge(s.width, tabs=1) - self.boxes.corner(p * s.angle, r) - self.boxes.corner(-p * s.angle, r) - self.boxes.edge(length - 1 * s.width - 2 * l) - - def endwidth(self) -> float: - return self.settings.holedistance + self.settings.thickness - -class NotesHolder(Boxes): - """Box for holding a stack of paper, coasters etc""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1) - self.addSettingsArgs(edges.StackableSettings) - self.buildArgParser(sx="78*1", y=78, h=35) - self.argparser.add_argument( - "--bottom_edge", action="store", - type=ArgparseEdgeType("Fhsfe"), choices=list("Fhsfe"), - default="s", - help="edge type for bottom edge") - self.argparser.add_argument( - "--opening", action="store", type=float, default=40, - help="percent of front (or back) that's open") - self.argparser.add_argument( - "--back_openings", action="store", type=boolarg, default=False, - help="have openings on the back side, too") - - def fingerHoleCB(self, lengths, height, posy=0.0): - def CB(): - t = self.thickness - px = -0.5 * t - for x in lengths[:-1]: - px += x + t - self.fingerHolesAt(px, posy, height, 90) - return CB - - def render(self): - sx, y, h = self.sx, self.y, self.h - t = self.thickness - - x = sum(sx) + (len(sx) - 1) * t - - o = max(0, min(self.opening, 100)) - sides = x * (1-o/100) / 2 - - b = self.edges.get(self.bottom_edge, self.edges["F"]) - if self.bottom_edge == "s": - b2 = HalfStackableEdge(self, self.edges["s"].settings, - self.edges["f"].settings) - b3 = self.edges["h"] - else: - b2 = b - b3 = b - - b4 = Edge(self, None) - b4.startwidth = lambda: b3.startwidth() - - - for side in range(2): - with self.saved_context(): - self.rectangularWall(y, h, [b, "F", "e", "F"], - ignore_widths=[1, 6], move="right") - # front walls - if self.opening == 0.0 or (side and not self.back_openings): - self.rectangularWall(x, h, [b, "f", "e", "f"], - ignore_widths=[1, 6], move="right") - else: - self.rectangularWall(sx[0] * (1-o/100) / 2, h, - [b2, "e", "e", "f"], - ignore_widths=[1, 6], move="right") - for ix in range(len(sx)-1): - left = sx[ix] * (1-o/100) / 2 - right = sx[ix+1] * (1-o/100) / 2 - h_e = t - bottom_edge = CompoundEdge( - self, [b3, b4, b3], [left, t, right]) - self.rectangularWall( - left+right+t, h, - [bottom_edge, "e", "e", "e"], - callback=[lambda: self.fingerHolesAt(left+t/2, 0, h, 90)], - move="right") - - self.rectangularWall(sx[-1] * (1-o/100) / 2, h, - [b2, "e", "e", "f"], - ignore_widths=[1, 6], - move="right mirror") - - self.rectangularWall(x, h, [b, "F", "e", "F"], - ignore_widths=[1, 6], move="up only") - # hack to have it reversed in second go and then back to normal - sx = list(reversed(sx)) - - # bottom - if self.bottom_edge != "e": - outer_edge = "h" if self.bottom_edge == "f" else "f" - font_edge = back_edge = outer_edge - u_edge = USlotEdge(self, o, outer_edge) - outer_width = self.edges[outer_edge].startwidth() - if self.opening > 0.0: - front_edge = CompoundEdge( - self, - ([u_edge, edges.OutSetEdge(self, outer_width)]*len(sx))[:-1], - ([l for x in sx for l in (x, t)])[:-1]) - if self.opening > 0.0 and self.back_openings: - back_edge = CompoundEdge( - self, - ([u_edge, edges.OutSetEdge(self, outer_width)]*len(sx))[:-1], - ([l for x in reversed(sx) for l in (x, t)])[:-1]) - - self.rectangularWall( - x, y, - [front_edge, outer_edge, back_edge, outer_edge], - callback=[self.fingerHoleCB(sx, y)], - move="up") - # innner walls - for i in range(len(sx)-1): - self.rectangularWall( - y, h, ("e" if self.bottom_edge=="e" else "f") + "fef", - move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/openbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/openbox.py deleted file mode 100644 index 5fd0c72..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/openbox.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class OpenBox(Boxes): - """Box with top and front open""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--edgetype", action="store", - type=ArgparseEdgeType("Fh"), choices=list("Fh"), - default="F", - help="edge type") - self.addSettingsArgs(edges.FingerJointSettings) - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y, False) - h = self.adjustSize(h, False) - - e = self.edgetype - self.rectangularWall(x, h, [e, e, "e", e], move="right") - self.rectangularWall(y, h, [e, "e", "e", "f"], move="up") - self.rectangularWall(y, h, [e, "e", "e", "f"]) - self.rectangularWall(x, y, "efff", move="left") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/organpipe.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/organpipe.py deleted file mode 100644 index 39e1e2d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/organpipe.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# Based on pipecalc by Christian F. Coors -# https://github.com/ccoors/pipecalc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from math import * - -from boxes import * - -pitches = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#' ,'b'] - -pressure_units = { 'Pa' : 1.0, - 'mBar' : 100., - 'mmHg' : 133.322, - 'mmH2O' : 9.80665, -} - -class OrganPipe(Boxes): # Change class name! - """Rectangular organ pipe based on pipecalc""" - - ui_group = "Unstable" # see ./__init__.py for names - - def getFrequency(self, pitch, octave, base_freq=440): - steps = pitches.index(pitch) + (octave-4)*12 - 9 - return base_freq * 2**(steps/12.) - - def getRadius(self, pitch, octave, intonation): - steps = pitches.index(pitch) + (octave-2)*12 + intonation - return 0.5 * 0.15555 * 0.957458**steps - - def getAirSpeed(self, wind_pressure, air_density=1.2): - return (2.0 * (wind_pressure / air_density))**.5 - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=3.0, space=3.0, - surroundingspaces=1.0) - - """ - air_temperature: f64, -""" - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--pitch", action="store", type=str, default="c", - choices=pitches, - help="pitch") - self.argparser.add_argument( - "--octave", action="store", type=int, default=2, - help="Octave in International Pitch Notation (2 == C)") - self.argparser.add_argument( - "--intonation", action="store", type=float, default=2.0, - help="Intonation Number. 2 for max. efficiency, 3 max.") - self.argparser.add_argument( - "--mouthratio", action="store", type=float, default=0.25, - help="mouth to circumference ratio (0.1 to 0.45). Determines the width to depth ratio") - self.argparser.add_argument( - "--cutup", action="store", type=float, default=0.3, - help="Cutup to mouth ratio") - self.argparser.add_argument( - "--mensur", action="store", type=int, default=0, - help="Distance in halftones in the Normalmensur by Töpfer") - self.argparser.add_argument( - "--windpressure", action="store", type=float, default=588.4, - help="uses unit selected below") - self.argparser.add_argument( - "--windpressure_units", action="store", type=str, default='Pa', - choices=pressure_units.keys(), - help="in Pa") - self.argparser.add_argument( - "--stopped", action="store", type=boolarg, default=False, - help="pipe is closed at the top") - - - def render(self): - t = self.thickness - f = self.getFrequency(self.pitch, self.octave, 440) - - self.windpressure *= pressure_units.get(self.windpressure_units, 1.0) - - speed_of_sound = 343.6 # XXX util::speed_of_sound(self.air_temperature); // in m/s - air_density = 1.2 - air_speed = self.getAirSpeed(self.windpressure, air_density) - - i = self.intonation - radius = self.getRadius(self.pitch, self.octave, i) * 1000 - cross_section = pi * radius**2 - circumference = pi * radius * 2.0 - mouth_width = circumference * self.mouthratio - mouth_height = mouth_width * self.cutup - mouth_area = mouth_height * mouth_width - pipe_depth = cross_section / mouth_width - base_length = max(mouth_width, pipe_depth) - - jet_thickness = (f**2 * i**2 * (.01 * mouth_height)**3) / air_speed**2 - sound_power = (0.001 * pi * (air_density / speed_of_sound) * f**2 - * (1.7 * (jet_thickness * speed_of_sound * f * mouth_area * mouth_area**.5)**.5)**2) - - air_consumption_rate = air_speed * mouth_width * jet_thickness * 1E6 - - wavelength = speed_of_sound / f * 1000 - - if self.stopped: - theoretical_resonator_length = wavelength / 4.0 - resonator_length = (-0.73 * (f * cross_section *1E-6 - 0.342466 * speed_of_sound * mouth_area**.5 * 1E-3) - / (f * mouth_area**.5 * 1E-3)) - else: - theoretical_resonator_length = wavelength / 2.0 - resonator_length = (-0.73 * (f * cross_section * 1E-6 + 0.465753 * f * mouth_area**.5 * cross_section**.5 * 1E-6 - 0.684932 * speed_of_sound * mouth_area**.5 * 1E-3) - / (f * mouth_area**.5 * 1E-3)) * 1E3 - air_hole_diameter = 2.0 * ((mouth_width * jet_thickness * 10.0)**.5 / pi) - - total_length = resonator_length + base_length - - - e = ["f", "e", - edges.CompoundEdge(self, "fef", (resonator_length - mouth_height - 10*t, mouth_height + 10*t, base_length)), "f"] - - self.rectangularWall(total_length, pipe_depth, e, callback=[ - lambda: self.fingerHolesAt(base_length-0.5*t, 0, pipe_depth-jet_thickness)], - move="up") - self.rectangularWall(total_length, pipe_depth, e, callback=[ - lambda: self.fingerHolesAt(base_length-0.5*t, 0, pipe_depth-jet_thickness)], - move="up") - self.rectangularWall(total_length, mouth_width, "FeFF", callback=[ - lambda: self.fingerHolesAt(base_length-0.5*t, 0, mouth_width)], - move="up") - e = [edges.CompoundEdge(self, "EF", (t*10, resonator_length - mouth_height - t*10)), 'e', - edges.CompoundEdge(self, "FE", (resonator_length - mouth_height - t*10, t*10)), 'e'] - self.rectangularWall(resonator_length - mouth_height, mouth_width, e, move="up") - self.rectangularWall(base_length, mouth_width, "FeFF", move="right") - self.rectangularWall(mouth_width, pipe_depth, "fFfF", callback=[ - lambda:self.hole(mouth_width/2, pipe_depth/2, d=air_hole_diameter)], move="right") - self.rectangularWall(mouth_width, pipe_depth - jet_thickness, "ffef", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottobody.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottobody.py deleted file mode 100644 index 4b15c85..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottobody.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -try: - from gettext import gettext as _ -except ImportError: - def _(message: str) -> str: - return message - -from boxes import * - - -class OttoBody(Boxes): - """Otto LC - a laser cut chassis for Otto DIY - body""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.ChestHingeSettings) - - - def bottomCB(self): - self.hole(6, self.y/2, 6) - self.hole(6, self.y/2-6, 3) - self.hole(self.x-6, self.y/2, 6) - self.hole(self.x-6, self.y/2-6, 3) - - #self.rectangularHole(20, self.y/2, 4, 30, 1.5) - #self.rectangularHole(self.x-20, self.y/2, 4, 30, 1.5) - self.rectangularHole(self.x/2, self.y/2, 10, 5, 1.5) - - # switch - self.rectangularHole(self.x-7, self.y-2.8, 7, 4) - - self.moveTo(0, self.y-12) - self.hexHolesCircle(12, HexHolesSettings( - self, diameter=2, distance=2, style='circle')) - - def leftBottomCB(self): - self.hole(7, self.y-7, 6) - - self.hole(6, self.y/2+9, 0.9) - self.rectangularHole(6, self.y/2-5.5, 12, 23) - self.hole(6, self.y/2-20, 0.9) - - def rightBottomCB(self): - self.hole(7, self.y-5, 2) - - self.hole(8, self.y/2+9, 0.9) - self.rectangularHole(8, self.y/2-5.5, 12, 23) - self.hole(8, self.y/2-20, 0.9) - - def eyeCB(self): - self.hole(self.x/2+13,self.hl/2, 8) - self.hole(self.x/2-13,self.hl/2, 8) - - def frontCB(self): - t = self.thickness - self.rectangularHole(0.5*t, 2+t, t, 2.5) - self.rectangularHole(self.x-0.5*t, 2+t, t, 2.5) - - def IOCB(self): - self.rectangularHole(26, 18, 12, 10) - # self.rectangularHole(42.2, 10.2, 9.5, 11.5) - - def buttonCB(self): - px, py = 7.5, 7.5 - - self.rectangularHole(px, py-2.25, 5.2, 2.5) - self.rectangularHole(px, py+2.25, 5.2, 2.5) - - def PCB_Clip(self, x , y, move=None): - - if self.move(x+4, y, move, True): - return - self.moveTo(1.5) - self.polyline(x-1.5, 90, (y, 2), 90, x, 85, (y-2-4, 2), -30, 2, 120, 1, -90, 2, (180, 1.), y-7, -175, y-5) - - self.move(x+4, y, move) - - def PCB_Clamp(self, w, s, h, move=None): - t = self. thickness - f = 2**0.5 - - if self.move(w+4, h+8+t, move, True): - return - self.polyline(w, 90, s, -90, 1, (90, 1), (h-s-1, 2), 90, w-2, 90, - h-8, (-180, 1), h-8+3*t, 135, f*(4), 90, f*2, -45, - (h+t, 2)) - self.move(w+4, h+8+t, move) - - def render(self): - - self.x = x = 60. - self.y = y = 60. - self.h = h = 35. - self.hl = hl = 30. - - t = self.thickness - - hx = self.edges["O"].startwidth() - hx2 = self.edges["P"].startwidth() - - e1 = edges.CompoundEdge(self, "Fe", (h-hx, hx)) - e2 = edges.CompoundEdge(self, "eF", (hx, h-hx)) - e_back = ("F", e1, "e", e2) - - # sides - self.moveTo(hx) - self.rectangularWall(x, h-hx, "FfOf", ignore_widths=[2], move="up", label=_("Left bottom side")) - self.rectangularWall(x, hl-hx2, "pfFf", ignore_widths=[1], move="up", label=_("Left top side")) - self.moveTo(-hx) - self.rectangularWall(x, h-hx, "Ffof", ignore_widths=[5], callback=[ - lambda: self.rectangularHole(y-7.5, h-4-7.5, 6.2, 7.)], - move="up", label=_("Right bottom side")) - self.rectangularWall(x, hl-hx2, "PfFf", ignore_widths=[6], - callback=[None, None, self.IOCB], move="up", - label=_("Right top side")) - - # lower walls - self.rectangularWall(y, h, "FFeF", callback=[ - None, None, self.frontCB], move="up", - label=_("Lower front")) - self.rectangularWall(y, h, e_back, move="up", - label=_("Lower back")) - - # upper walls - self.rectangularWall(y, hl, "FFeF", callback=[self.eyeCB], move="up", label=_("Upper front")) - self.rectangularWall(y, hl-hx2, "FFqF", move="up", label=_("Upper back")) - - # top - self.rectangularWall(x, y, "ffff", move="up", label=_("Top")) - # bottom - self.rectangularWall(x, y, "ffff", callback=[self.bottomCB], move="up", label=_("Bottom")) - # PCB mounts - with self.saved_context(): - self.PCB_Clamp(y-53.5, 4.5, hl, move="right") - self.PCB_Clamp(y-50, 4.5, hl, move="right") - self.PCB_Clip(3.5, hl, move="right") - self.rectangularWall(15, 15, callback=[self.buttonCB]) - self.PCB_Clamp(y-53.5, 4.5, hl, move="up only") - # servo mounts - self.moveTo(0, 50) - self.rectangularWall(y, 14, callback=[None, None, None, - self.leftBottomCB], move="up", - label=_("Servo mount")) - self.rectangularWall(y-5.6, 14, callback=[ - None, None, None, self.rightBottomCB], move="up", - label=_("Servo mount")) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottolegs.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottolegs.py deleted file mode 100644 index 8ab0650..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottolegs.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import edges - - -class LegEdge(edges.BaseEdge): - - def __call__(self, l, **kw): - d0 = (l - 12.0) /2 - self.hole(l/2, 6, 3.0) - self.polyline(d0, 90, 0, (-180, 6), 0, 90, d0) - -class OttoLegs(Boxes): - """Otto LC - a laser cut chassis for Otto DIY - legs""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=1.0, space=1.0, - surroundingspaces=1.0) - self.argparser.add_argument( - "--anklebolt1", action="store", type=float, default=3.0, - help="diameter for hole for ankle bolts - foot side") - self.argparser.add_argument( - "--anklebolt2", action="store", type=float, default=2.6, - help="diameter for hole for ankle bolts - leg side") - self.argparser.add_argument( - "--length", action="store", type=float, default=34.0, - help="length of legs (34mm min)") - - def foot(self, x, y, ly, l, r=5., move=None): - if self.move(x, y, move, True): - return - - t = self.thickness - w = ly + 5.5 + 2 * t - self.fingerHolesAt(x/2 - w/2, 0, l, 90) - self.fingerHolesAt(x/2 + w/2, 0, l, 90) - self.moveTo(r, 0) - - for l in (x, y, x, y): - self.polyline((l - 2*r, 2), 45, r*2**0.5, 45) - - self.move(x, y, move) - - def ankles(self, x, h, edge="f", callback=None, move=None): - - f = 0.5 - tw = x - th = 2 * h + self.thickness - - if self.move(tw, th, move, True): - return - - self.moveTo(0, self.thickness) - for i in range(2): - self.cc(callback, 0) - self.edges[edge](x) - self.polyline(0, 90) - self.cc(callback, 1) - self.polyline((h, 2), 90, (f*x, 1), 45, ((2**0.5)*(1-f)*x, 1), 45, - (h-(1-f)*x, 1), 90) - self.moveTo(tw, th, 180) - self.ctx.stroke() - self.move(tw, th, move) - - def ankle1(self): - # from vertical edge - self.hole(15, 10, 3.45) # 3.45 for servo arm, 2.3 for knob - - def servoring(self, move=""): - if self.move(20, 20, move, True): - return - self.moveTo(10, 10, 90) - self.moveTo(3.45, 0, -90) - self.polyline(0, (-264, 3.45), 0, 36, 6.55, 108, 0, (330, 9.0, 4), 0, 108, 6.55) - self.move(20, 20, move) - - - def ankle2(self): - # from vertical edge - self.hole(15, 10, self.anklebolt1/2) - - def servoHole(self): - self.hole(6, 6, 11.6/2) - self.hole(6, 12, 5.5/2) - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - - ws = 25 - lx, ly, lh = 12.4, 23.5, max(self.length, ws+6+t) - - self.ctx.save() - # Legs - - c1 = edges.CompoundEdge(self, "FE", (ly-7.0, 7.0)) - c2 = edges.CompoundEdge(self, "EF", (7.0, lh-7.0)) - e = [c1, c2, "F", "F"] - - for i in range(2): - # front - self.rectangularWall(lx, lh-7., [LegEdge(self, None), "f", "F", "f"], callback=[None, lambda:self.fingerHolesAt(ws-7., 0, lx)], move="right") - # back - self.rectangularWall(lx, lh, "FfFf", callback=[ - lambda:self.hole(lx/2, 7, self.anklebolt2/2)], move="right") - # sides - self.rectangularWall(ly, lh, e, callback=[None, - lambda:self.fingerHolesAt(ws, 7.0, ly-7.0-3.0)], move="right") - self.rectangularWall(ly, lh, e, callback=[ - lambda:self.rectangularHole(ly/2, ws+3+0.5*t, 12, 6, 3), - lambda:self.fingerHolesAt(ws, 7.0, ly-7.0-3.0)], move="right") - - # top - self.partsMatrix(2, 1, "right", self.rectangularWall, ly, lx, "ffff", - callback=[None, lambda: self.hole(lx/2, ly/2, 2.3)]) - self.partsMatrix(2, 1, "right", self.rectangularWall, lx, ly, "eeee", callback=[lambda: self.hole(lx/2, ly/2, 1.5)]) - # hold servo at the front - self.partsMatrix(2, 1, "right", self.rectangularWall, 4.6, lx, "efee") - # bottom - self.partsMatrix(2, 1, "right", self.rectangularWall, lx, ly-7.0, "efff") - # hold servo inside - self.partsMatrix(2, 1, "right", self.rectangularWall, lx, ly-7.0-3.0, "efef") - - self.ctx.restore() - self.rectangularWall(lx, lh, "ffff", move="up only") - - # feet - self.foot(60, 40, ly, 30, move="right") - self.foot(60, 40, ly, 30, move="right") - self.ankles(30, 25, callback=[None, self.ankle1], move="right") - self.ankles(30, 25, callback=[None, self.ankle2], move="right") - self.partsMatrix(2, 2, "right", self.servoring) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottosoles.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottosoles.py deleted file mode 100644 index 20e6608..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ottosoles.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class OttoSoles(Boxes): - """Foam soles for the OttO bot""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.buildArgParser(x=58., y=38.) - self.argparser.add_argument( - "--width", action="store", type=float, default=4., - help="width of sole stripe") - self.argparser.add_argument( - "--chamfer", action="store", type=float, default=5., - help="chamfer at the corners") - self.argparser.add_argument( - "--num", action="store", type=int, default=2, - help="number of soles") - - - def render(self): - x, y = self.x, self.y - c = self.chamfer - c2 = c * 2**0.5 - w = min(self.width, c2 / 2. / math.tan(math.radians(22.5))) - w = self.width - w2 = w * 2**0.5 - c2 / 2 - d = w * math.tan(math.radians(22.5)) - - - self.edges["d"].settings.setValues(w, size=0.4, depth=0.3, - radius=0.05) - - self.moveTo(0, y, -90) - - for i in range(self.num*2): - if c2 >= 2 * d: - self.polyline((c2, 1), 45, (y-2*c, 1), 45, c2/2., 90) - self.edges["d"](w) - self.polyline(0, 90, c2/2-d, -45, (y-2*c-2*d, 1), -45, - (c2-2*d, 1), -45, - (x-2*c-2*d, 1), -45, c2/2-d, 90) - self.edges["D"](w) - self.polyline(0, 90, c2/2., 45, (x-2*c, 1), 45) - self.moveTo(0, w + c2/2. + 2*2**0.5*self.burn) - else: - self.polyline((c2, 1), 45, (y-2*c, 1), 45, c2/2., 90) - self.edges["d"](w2) - self.polyline(0, 45, (y-2*w, 1), -90, (x-2*w, 1), 45) - self.edges["D"](w2) - self.polyline(0, 90, c2/2., 45, (x-2*c, 3), 45) - self.moveTo(0, w * 2**0.5 + 2*2**0.5*self.burn) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/paintbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/paintbox.py deleted file mode 100644 index 3020d39..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/paintbox.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import Boxes, boolarg, edges - - -class PaintStorage(Boxes): - """Stackable storage for hobby paint or other things""" - - webinterface = True - ui_group = "Shelf" # see ./__init__.py for names - - canheight: int - candiameter: int - minspace: int - additional_bottom: int - additional_top: int - hexpattern: bool - drawer: bool - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=100, y=300) - - self.argparser.add_argument( - "--canheight", action="store", type=int, default=50, - help="Height of the paintcans") - self.argparser.add_argument( - "--candiameter", action="store", type=int, default=30, - help="Diameter of the paintcans") - self.argparser.add_argument( - "--minspace", action="store", type=int, default=10, - help="Minimum space between the paintcans") - self.argparser.add_argument( - "--additional_bottom", action="store", type=boolarg, default=False, - help="Additional bottom/floor with holes the paintcans go through") - self.argparser.add_argument( - "--additional_top", action="store", type=boolarg, default=False, - help="Additional top/floor with holes the paintcans go through") - self.argparser.add_argument( - "--hexpattern", action="store", type=boolarg, default=False, - help="Use hexagonal arrangement for the holes instead of orthogonal") - self.argparser.add_argument( - "--drawer", action="store", type=boolarg, default=False, - help="Create a stackable drawer instead") - - def paintholes(self): - """Place holes for the paintcans evenly""" - - if self.hexpattern: - self.moveTo(self.minspace / 2, self.minspace / 2) - settings = self.hexHolesSettings - settings.diameter = self.candiameter - settings.distance = self.minspace - settings.style = 'circle' - self.hexHolesRectangle(self.y - 1 * self.minspace, - self.x - 1 * self.minspace, - settings) - return - n_x = int(self.x / (self.candiameter + self.minspace)) - n_y = int(self.y / (self.candiameter + self.minspace)) - - if n_x <= 0 or n_y <= 0: - return - - spacing_x = (self.x - n_x * self.candiameter) / n_x - spacing_y = (self.y - n_y * self.candiameter) / n_y - for i in range(n_y): - for j in range(n_x): - self.hole(i * (self.candiameter + spacing_y) + (self.candiameter + spacing_y) / 2, - j * (self.candiameter + spacing_x) + (self.candiameter + spacing_x) / 2, - self.candiameter / 2) - - def sidesCb(self): - x, y = self.x, self.y - t = self.thickness - - stack = self.edges['s'].settings - h = self.canheight - stack.height - stack.holedistance + t - hx = 1 / 2. * x - hh = h / 4. - hr = min(hx, hh) / 2 - - if not self.drawer: - self.rectangularHole(h / 3, (x / 2.0) - t, hh, hx, r=hr) - self.fingerHolesAt(((self.canheight/3)*2)-t*2, -t, x, 90) - - if self.additional_bottom: - self.fingerHolesAt((self.canheight / 6) - (t / 2), -t, x, 90) - if self.additional_top: - self.fingerHolesAt(self.canheight - ((self.canheight / 6) + t), -t, x, 90) - else: - self.rectangularHole(h / 3, (x / 2.0) - t, hh, hx, r=hr) - - def render(self): - # adjust to the variables you want in the local scope - x, y = self.x, self.y - t = self.thickness - - stack = self.edges['s'].settings - h = self.canheight - stack.height - stack.holedistance + t - - wall_callbacks = [self.sidesCb] - if not self.drawer: - wall_keys = "EsES" - bottom_keys = "EfEf" - else: - wall_keys = "FsFS" - bottom_keys = "FfFf" - - # Walls - self.rectangularWall( - h, x - 2 * t, wall_keys, - ignore_widths=[1, 2, 5, 6], - callback=wall_callbacks, move="up", - ) - self.rectangularWall( - h, x - 2 * t, wall_keys, - ignore_widths=[1, 2, 5, 6], - callback=wall_callbacks, move="right" - ) - - # Plates - self.rectangularWall( - 0.8 * stack.height + stack.holedistance, x, "eeee", move="" - ) - self.rectangularWall( - 0.8 * stack.height + stack.holedistance, x, "eeee", move="down right" - ) - - # Bottom - self.rectangularWall( - y, x - 2 * t, bottom_keys, ignore_widths=[1, 2, 5, 6], move="up" - ) - - if not self.drawer: - # Top - self.rectangularWall(y, x, "efef", callback=[self.paintholes], move="up") - if self.additional_bottom: - self.rectangularWall(y, x, "efef", callback=[self.paintholes], move="up") - if self.additional_top: - self.rectangularWall(y, x, "efef", callback=[self.paintholes], move="up") - else: - # Sides - self.rectangularWall(y, h, "efff", move="up") - self.rectangularWall(y, h, "efff", move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/paperbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/paperbox.py deleted file mode 100644 index a5ea36c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/paperbox.py +++ /dev/null @@ -1,276 +0,0 @@ -# Copyright (C) 2020 Guillaume Collic -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math - -from boxes import Boxes - - -class PaperBox(Boxes): - """ - Box made of paper, with lid. - """ - - ui_group = "Misc" - - description = """ -This box is made of paper. - -There is marks in the "outside leftover paper" to help see where to fold -(cutting with tabs helps use them). The cut is very precise, and could be too tight if misaligned when glued. A plywood box (such as a simple TypeTray) of the same size is a great guide during folding and gluing. Just fold the box against it. Accurate quick and easy. - -A paper creaser (or bone folder) is also useful. -""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("x", "y", "h") - - self.argparser.add_argument( - "--design", - action="store", - type=str, - default="automatic", - choices=("automatic", "widebox", "tuckbox"), - help="different design for paper consumption optimization. The tuckbox also has locking cut for its lid.", - ) - - self.argparser.add_argument( - "--lid_height", - type=float, - default=15, - help="Height of the lid (part which goes inside the box)", - ) - self.argparser.add_argument( - "--lid_radius", - type=float, - default=7, - help="Angle, in radius, of the round corner of the lid", - ) - self.argparser.add_argument( - "--lid_sides", - type=float, - default=20, - help="Width of the two sides upon which goes the lid", - ) - self.argparser.add_argument( - "--margin", - type=float, - default=0, - help="Margin for the glued sides", - ) - self.argparser.add_argument( - "--mark_length", - type=float, - default=1.5, - help="Length of the folding outside mark", - ) - self.argparser.add_argument( - "--tab_angle_rad", - type=float, - default=math.atan(2 / 25), - help="Angle (in radian) of the sides which are to be glued inside the box", - ) - - self.argparser.add_argument( - "--finger_hole_diameter", - type=float, - default=15, - help="Diameter of the hole to help catch the lid", - ) - - def render(self): - if self.design == "automatic": - self.design = "tuckbox" if self.h > self.y else "widebox" - - path = ( - self.tuckbox(self.x, self.y, self.h) - if self.design == "tuckbox" - else self.widebox(self.x, self.y, self.h) - ) - - self.polyline(*path) - - def tuckbox(self, width, length, height): - lid_cut_length = min(10, length / 2, width / 5) - half_side = ( - self.mark(self.mark_length) - + [ - 0, - 90, - ] - + self.ear_description(length, lid_cut_length) - + [ - 0, - -90, - length, - 0, - ] - + self.lid_cut(lid_cut_length) - + self.lid_tab(width - 2 * self.thickness) - + [0] - + self.lid_cut(lid_cut_length, reverse=True) - + [ - length, - -90, - ] - + self.ear_description(length, lid_cut_length, reverse=True) - + self.mark(self.mark_length) - ) - return ( - [height, 0] - + half_side - + self.side_with_finger_hole(width, self.finger_hole_diameter) - + self.mark(self.mark_length) - + [ - 0, - 90, - ] - + self.tab_description(length - self.margin - self.thickness, height) - + [ - 0, - 90, - ] - + self.mark(self.mark_length) - + [width] - + list(reversed(half_side)) - ) - - def widebox(self, width, length, height): - half_side = ( - self.mark(self.mark_length) - + [ - 0, - 90, - ] - + self.tab_description(length / 2 - self.margin, height) - + [ - 0, - -90, - height, - 0, - ] - + self.mark(self.mark_length) - + [ - 0, - 90, - ] - + self.tab_description(self.lid_sides, length) - + [ - 0, - 90, - ] - + self.mark(self.mark_length) - + [ - height, - -90, - ] - + self.tab_description(length / 2 - self.margin, height) - + [ - length, - 0, - ] - + self.mark(self.mark_length) - ) - return ( - self.side_with_finger_hole(width, self.finger_hole_diameter) - + half_side - + self.lid_tab(width) - + list(reversed(half_side)) - ) - - def lid_tab(self, width): - return [ - self.lid_height - self.lid_radius, - (90, self.lid_radius), - width - 2 * self.lid_radius, - (90, self.lid_radius), - self.lid_height - self.lid_radius, - ] - - def mark(self, length): - if length == 0: - return [] - return [ - 0, - -90, - length, - 180, - length, - -90, - ] - - def lid_cut(self, length, reverse=False): - path = [ - 90, - length + self.thickness, - -180, - length, - 90, - ] - - return [0] + (list(reversed(path)) if reverse else path) - - def side_with_finger_hole(self, width, finger_hole_diameter): - half_width = (width - finger_hole_diameter) / 2 - - return [ - half_width, - 90, - 0, - (-180, finger_hole_diameter / 2), - 0, - 90, - half_width, - 0, - ] - - def tab_description(self, height, width): - deg = math.degrees(self.tab_angle_rad) - side = height / math.cos(self.tab_angle_rad) - end_width = width - 2 * height * math.tan(self.tab_angle_rad) - return [ - 0, - deg - 90, - side, - 90 - deg, - end_width, - 90 - deg, - side, - deg - 90, - ] - - def ear_description(self, length, lid_cut_length, reverse=False): - ear_depth = max(lid_cut_length, self.lid_height) - radius = min(self.lid_radius, ear_depth - lid_cut_length) - start_margin = self.thickness - end_margin = 2 * self.burn - path = [ - start_margin, - -90, - lid_cut_length, - 90, - 0, - (-90, radius), - 0, - 90, - length - radius - start_margin - end_margin, - 90, - ear_depth, - -90, - end_margin, - ] - - return (list(reversed(path)) if reverse else path) + [0] diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/phoneholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/phoneholder.py deleted file mode 100644 index 3160224..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/phoneholder.py +++ /dev/null @@ -1,305 +0,0 @@ -# Copyright (C) 2021 Guillaume Collic -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import math -from functools import partial - -from boxes import Boxes, edges - - -class PhoneHolder(Boxes): - """ - Smartphone desk holder - """ - - ui_group = "Misc" - - description = """ - This phone stand holds your phone between two tabs, with access to its - bottom, in order to connect a charger, headphones, and also not to obstruct - the mic. - - Default values are currently based on Galaxy S7. -""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.argparser.add_argument( - "--phone_height", - type=float, - default=142, - help="Height of the phone.", - ) - self.argparser.add_argument( - "--phone_width", - type=float, - default=73, - help="Width of the phone.", - ) - self.argparser.add_argument( - "--phone_depth", - type=float, - default=11, - help=( - "Depth of the phone. Used by the bottom support holding the " - "phone, and the side tabs depth as well. Should be at least " - "your material thickness for assembly reasons." - ), - ) - self.argparser.add_argument( - "--angle", - type=float, - default=25, - help="angle at which the phone stands, in degrees. 0° is vertical.", - ) - self.argparser.add_argument( - "--bottom_margin", - type=float, - default=30, - help="Height of the support below the phone", - ) - self.argparser.add_argument( - "--tab_size", - type=float, - default=76, - help="Length of the tabs holding the phone", - ) - self.argparser.add_argument( - "--bottom_support_spacing", - type=float, - default=16, - help=( - "Spacing between the two bottom support. Choose a value big " - "enough for the charging cable, without getting in the way of " - "other ports." - ), - ) - - self.addSettingsArgs(edges.FingerJointSettings) - - def render(self): - self.h = self.phone_height + self.bottom_margin - tab_start = self.bottom_margin - tab_length = self.tab_size - tab_depth = self.phone_depth - support_depth = self.phone_depth - support_spacing = self.bottom_support_spacing - rad = math.radians(self.angle) - self.stand_depth = self.h * math.sin(rad) - self.stand_height = self.h * math.cos(rad) - - self.render_front_plate(tab_start, tab_length, support_spacing, move="right") - - self.render_back_plate(move="right") - - self.render_side_plate(tab_start, tab_length, tab_depth, move="right") - - for move in ["right mirror", "right"]: - self.render_bottom_support(tab_start, support_depth, tab_length, move=move) - - def render_front_plate( - self, - tab_start, - tab_length, - support_spacing, - support_fingers_length=None, - move="right", - ): - if not support_fingers_length: - support_fingers_length = tab_length - - be = BottomEdge(self, tab_start, support_spacing) - se1 = SideEdge(self, tab_start, tab_length) - se2 = SideEdge(self, tab_start, tab_length, reverse=True) - self.rectangularWall( - self.phone_width, - self.h, - [be, se1, "e", se2], - move=move, - callback=[ - partial( - lambda: self.front_plate_holes( - tab_start, support_fingers_length, support_spacing - ) - ) - ], - ) - - def render_back_plate( - self, - move="right", - ): - be = BottomEdge(self, 0, 0) - self.rectangularWall( - self.phone_width, - self.stand_height, - [be, "F", "e", "F"], - move=move, - ) - - def front_plate_holes( - self, support_start_height, support_fingers_length, support_spacing - ): - margin = (self.phone_width - support_spacing - self.thickness) / 2 - self.fingerHolesAt( - margin, - support_start_height, - support_fingers_length, - ) - self.fingerHolesAt( - self.phone_width - margin, - support_start_height, - support_fingers_length, - ) - - def render_side_plate(self, tab_start, tab_length, tab_depth, move): - te = TabbedEdge(self, tab_start, tab_length, tab_depth, reverse=True) - self.rectangularTriangle( - self.stand_depth, - self.stand_height, - ["e", "f", te], - move=move, - num=2, - ) - - def render_bottom_support( - self, support_start_height, support_depth, support_fingers_length, move="right" - ): - full_height = support_start_height + support_fingers_length - rad = math.radians(self.angle) - floor_length = full_height * math.sin(rad) - angled_height = full_height * math.cos(rad) - bottom_radius = min(support_start_height, 3 * self.thickness + support_depth) - smaller_radius = 0.5 - support_hook_height = 5 - full_width = floor_length + (support_depth + 3 * self.thickness) * math.cos(rad) - if self.move(full_width, angled_height, move, True): - return - - self.polyline( - floor_length, - self.angle, - 3 * self.thickness + support_depth - bottom_radius, - (90, bottom_radius), - support_hook_height + support_start_height - bottom_radius, - (180, self.thickness), - support_hook_height - smaller_radius, - (-90, smaller_radius), - self.thickness + support_depth - smaller_radius, - -90, - ) - self.edges["f"](support_fingers_length) - self.polyline( - 0, - 180 - self.angle, - angled_height, - 90, - ) - # Move for next piece - self.move(full_width, angled_height, move) - - -class BottomEdge(edges.BaseEdge): - def __init__(self, boxes, support_start_height, support_spacing) -> None: - super().__init__(boxes, None) - self.support_start_height = support_start_height - self.support_spacing = support_spacing - - def __call__(self, length, **kw): - cable_hole_radius = 2.5 - self.support_spacing = max(self.support_spacing, 2 * cable_hole_radius) - side = (length - self.support_spacing - 2 * self.thickness) / 2 - - half = [ - side, - 90, - self.support_start_height, - -90, - self.thickness, - -90, - self.support_start_height, - 90, - self.support_spacing / 2 - cable_hole_radius, - 90, - 2 * cable_hole_radius, - ] - path = half + [(-180, cable_hole_radius)] + list(reversed(half)) - self.polyline(*path) - - -class SideEdge(edges.BaseEdge): - def __init__(self, boxes, tab_start, tab_length, reverse=False) -> None: - super().__init__(boxes, None) - self.tab_start = tab_start - self.tab_length = tab_length - self.reverse = reverse - - def __call__(self, length, **kw): - tab_start = self.tab_start - tab_end = length - self.tab_start - self.tab_length - - if self.reverse: - tab_start, tab_end = tab_end, tab_start - - self.edges["F"](tab_start) - self.polyline( - 0, - 90, - self.thickness, - -90, - ) - self.edges["f"](self.tab_length) - self.polyline(0, -90, self.thickness, 90) - self.edges["F"](tab_end) - - def startwidth(self) -> float: - return self.boxes.thickness - - -class TabbedEdge(edges.BaseEdge): - def __init__(self, boxes, tab_start, tab_length, tab_depth, reverse=False) -> None: - super().__init__(boxes, None) - self.tab_start = tab_start - self.tab_length = tab_length - self.tab_depth = tab_depth - self.reverse = reverse - - def __call__(self, length, **kw): - tab_start = self.tab_start - tab_end = length - self.tab_start - self.tab_length - - if self.reverse: - tab_start, tab_end = tab_end, tab_start - - self.edges["f"](tab_start) - - self.ctx.save() - self.fingerHolesAt(0, -self.thickness / 2, self.tab_length, 0) - self.ctx.restore() - - self.polyline( - 0, - -90, - self.thickness, - (90, self.tab_depth), - self.tab_length - 2 * self.tab_depth, - (90, self.tab_depth), - self.thickness, - -90, - ) - self.edges["f"](tab_end) - - def margin(self) -> float: - return self.tab_depth + self.thickness diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/piratechest.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/piratechest.py deleted file mode 100644 index c3da958..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/piratechest.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class PirateChest(Boxes): - """Box with polygon lid with chest hinges.""" - - description = """Do not assemble sides before attaching the lid! - Hinge of the lid has to be placed first because it is impossible - to get it in position without removing the side wall. The lid can - be a bit tricky to assemble. Keep track of how the parts fit together. - Part with label "lid back" is placed in the hinges""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, finger=1.0,space=1.0) - self.addSettingsArgs(edges.HingeSettings) - - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--n", action="store", type=int, default=5, - help="number of sides on the lid. n ≥ 3") - - - def render(self): - # adjust to the variables you want in the local scope - x, y, h = self.x, self.y, self.h - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h, "f", False) - t = self.thickness - n = self.n - - if (n < 3): - raise ValueError("number of sides on the lid must be greater or equal to 3 (got %i)" % n) - - hy = self.edges["O"].startwidth() - h -= hy - if (h < 0): - raise ValueError("box to low to allow for hinge (%i)" % h) - - # create edge for non 90 degree joints in the lid - fingerJointSettings = copy.deepcopy(self.edges["f"].settings) - fingerJointSettings.setValues(self.thickness, angle=180./(n-1)) - fingerJointSettings.edgeObjects(self, chars="gGH") - - # render all parts - self.ctx.save() - - self.rectangularWall(x, y, "FFFF", move="up", label="Bottom") - frontlid, toplids, backlid = self.topside(y, n = n, move="only", bottom='P') - - self.rectangularWall(x, backlid, "qFgF", move="up", label="lid back") - for _ in range(n-2): - self.rectangularWall(x, toplids, "GFgF", move="up", label="lid top") - self.rectangularWall(x, frontlid, "GFeF", move="up", label="lid front") - - self.ctx.restore() - self.rectangularWall(x, y, "FFFF", move="right only") - - with self.saved_context(): - self.rectangularWall(x, h, "fFQF", ignore_widths=[2, 5], move="right", label="front") - self.rectangularWall(y, h, "ffof", ignore_widths=[5], move="right", label="right") - self.rectangularWall(0, h, "eeep", move="right only") - self.rectangularWall(x, h, "fFoF", move="up only") - self.rectangularWall(x, 0, "Peee", move="up only") - - e1 = edges.CompoundEdge(self, "Fe", (h, hy)) - e2 = edges.CompoundEdge(self, "eF", (hy, h)) - e_back = ("f", e1, "e", e2) - - with self.saved_context(): - self.rectangularWall(x, h+hy, e_back, move="right", label="back") # extend back to correct height - self.rectangularWall(0, h, "ePee", move="right only") - self.rectangularWall(y, h, "ffOf", ignore_widths=[2], move="right", label="left") - self.rectangularWall(x, h, "fFOF", move="up only") - self.rectangularWall(x, 0, "peee", move="up only") - - self.topside(y, n = n, move="right", bottom='p', label="lid left") - self.topside(y, n = n, move="right", bottom='P', label="lid right") - - - def topside(self, y, n, bottom, move=None, label=""): - radius, hp, side = self.regularPolygon((n - 1) * 2, h=y/2.0) - - tx = y + 2 * self.edges.get('f').spacing() - lidheight = hp if n % 2 else radius - ty = lidheight + self.edges.get('f').spacing() + self.edges.get(bottom).spacing() - - if self.move(tx, ty, move, before=True): - return side/2 + self.edges.get(bottom).spacing(), side, side/2 - - self.moveTo(self.edges.get('f').margin(), self.edges.get(bottom).margin()) - - self.edges.get(bottom)(y) - - self.corner(90) - if bottom == 'p': - self.edges.get('f')(side/2 + self.edges.get(bottom).spacing()) - else: - self.edges.get('f')(side/2) - - self.corner(180 / (n - 1)) - for _ in range(n-2): - self.edges.get('f')(side) - self.corner(180 / (n - 1)) - - if bottom == 'P': - self.edges.get('f')(side/2 + self.edges.get(bottom).spacing()) - else: - self.edges.get('f')(side/2) - - self.corner(90) - - self.move(tx, ty, move, label=label) - - return side/2 + self.edges.get(bottom).spacing(), side, side/2 diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/pizzashovel.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/pizzashovel.py deleted file mode 100644 index 8038c61..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/pizzashovel.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class PizzaShovel(Boxes): - """Pizza shovel with conveyor belt action""" - - description = """ -You need (permanent) baking paper to create the conveyor. With that you can pick up and put down the pizza by moving the handle attached to the belt. - """ - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.HandleEdgeSettings, outset=0.0, height=40, hole_width="30:30:30") - self.buildArgParser(x=382, y=400) - self.argparser.add_argument( - "--grip_length", action="store", type=float, default=250.0, - help="Length of the grip. Zero for holes for a screw-in handle") - self.argparser.add_argument( - "--grip_height", action="store", type=float, default=30.0, - help="Height of the grip. Distance between the cross beams.") - self.argparser.add_argument( - "--top_holes", action="store", type=float, default=3.0, - help="Diameter of the screw holes in the bottom of the pusher - where the screws pass through") - self.argparser.add_argument( - "--bottom_holes", action="store", type=float, default=2.0, - help="Diameter of the screw holes in the bottom of the pusher - where the screws hold") - self.argparser.add_argument( - "--grip_holes", action="store", type=float, default=3.0, - help="Diameter of the screw holes for zero griplength") - - def holesCB(self, d): - def cb(): - for i in range(5): - self.hole((self.x-3)/5 * (i+0.5), 20, d=d) - return cb - - def gripCB(self, top): - - def cb(): - t = self.thickness - if self.grip_length: - for d in (-t, +t): - self.fingerHolesAt(self.x/2 + d, 0, 40, 90) - else: - for y in ((10, 30) if top else (15, 35, 60)): - self.hole(self.x/2, y, d=self.grip_holes) - return cb - - def render(self): - x, y, h = self.x, self.y, self.grip_height - grip = self.grip_length - t = self.thickness - - ce = edges.CompoundEdge(self, "fe", [y/2, y/2]) - ec = edges.CompoundEdge(self, "ef", [y/2, y/2]) - - self.rectangularWall(x, y, ["e", ce, "e", ec], move="up") - self.rectangularWall(x, 40, "efef", callback=[self.gripCB(top=True)], move="up") - self.rectangularWall(x, 80, "efef", callback=[self.gripCB(top=False)], move="up") - for i in range(2): - a = math.atan((h+2*t) / (y/2 - 30)) - l = (y/2 - 30) / math.cos(a) - a = math.degrees(a) - self.polygonWall((y/2+40, (90, t), h+2*t, (90, t), 70, a, l, -a, 0, (180, t)), "e", - callback=[lambda: (self.fingerHolesAt(0, 1.5*t, y/2, 0), - self.fingerHolesAt(y/2+t, 1.5*t, 40, 0)), - None, - lambda: self.fingerHolesAt(-t, 1.5*t, 80, 0)], - move="up") - - self.rectangularWall(x-3, 40, "eeee", callback=[self.holesCB(self.bottom_holes)], move="up") - self.rectangularWall(x-3, 40, "yeee", callback=[self.holesCB(self.top_holes)], move="up") - - if grip: - ce1 = edges.CompoundEdge(self, "fe", (40, grip-h/2)) - ce2 = edges.CompoundEdge(self, "ef", (grip-h/2, 40)) - self.flangedWall(40+grip-h/2, h, [ce1, "e", ce2, "e"], flanges=[0, h/2], r=h/2, move="up") - self.flangedWall(40+grip-h/2, h, "eeee", flanges=[0, h/2], r=h/2, move="up") - self.flangedWall(40+grip-h/2, h, [ce1, "e", ce2, "e"], flanges=[0, h/2], r=h/2, move="up") - self.flangedWall(30+grip-h/2, h-2*t, "eeee", flanges=[0, h/2-t], r=h/2-t, move="up") - self.flangedWall(30+grip-h/2, h-2*t, "eeee", flanges=[0, h/2-t], r=h/2-t, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/planetary.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/planetary.py deleted file mode 100644 index eb92c3f..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/planetary.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Planetary(Boxes): - """Planetary Gear with possibly multiple identical stages""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - self.argparser.add_argument( - "--sunteeth", action="store", type=int, default=8, - help="number of teeth on sun gear") - self.argparser.add_argument( - "--planetteeth", action="store", type=int, default=20, - help="number of teeth on planets") - self.argparser.add_argument( - "--maxplanets", action="store", type=int, default=0, - help="limit the number of planets (0 for as much as fit)") - self.argparser.add_argument( - "--deltateeth", action="store", type=int, default=0, - help="enable secondary ring with given delta to the ring gear") - self.argparser.add_argument( - "--modulus", action="store", type=float, default=3, - help="modulus of the theeth in mm") - self.argparser.add_argument( - "--shaft", action="store", type=float, default=6., - help="diameter of the shaft") - # self.argparser.add_argument( - # "--stages", action="store", type=int, default=4, - # help="number of stages in the gear reduction") - - def render(self): - - ringteeth = self.sunteeth + 2 * self.planetteeth - spoke_width = 3 * self.shaft - - pitch1, size1, xxx = self.gears.sizes(teeth=self.sunteeth, - dimension=self.modulus) - pitch2, size2, xxx = self.gears.sizes(teeth=self.planetteeth, - dimension=self.modulus) - pitch3, size3, xxx = self.gears.sizes( - teeth=ringteeth, internal_ring=True, spoke_width=spoke_width, - dimension=self.modulus) - - t = self.thickness - planets = int(math.pi / (math.asin(float(self.planetteeth + 2) / (self.planetteeth + self.sunteeth)))) - - if self.maxplanets: - planets = min(self.maxplanets, planets) - - # Make sure the teeth mash - ta = self.sunteeth + ringteeth - # There are sunteeth+ringteeth mashing positions for the planets - if ta % planets: - planetpositions = [round(i * ta / planets) * 360 / ta for i in range(planets)] - else: - planetpositions = planets - - # XXX make configurable? - profile_shift = 20 - pressure_angle = 20 - self.parts.disc(size3, callback=lambda: self.hole(0, 0, self.shaft / 2), move="up") - self.gears(teeth=ringteeth, dimension=self.modulus, - angle=pressure_angle, internal_ring=True, - spoke_width=spoke_width, mount_hole=self.shaft, - profile_shift=profile_shift, move="up") - self.gears.gearCarrier(pitch1 + pitch2, spoke_width, planetpositions, - 2 * spoke_width, self.shaft / 2, move="up") - self.gears(teeth=self.sunteeth, dimension=self.modulus, - angle=pressure_angle, - mount_hole=self.shaft, profile_shift=profile_shift, move="up") - numplanets = planets - - if self.deltateeth: - numplanets += planets - deltamodulus = self.modulus * ringteeth / (ringteeth - self.deltateeth) - self.gears(teeth=ringteeth - self.deltateeth, dimension=deltamodulus, - angle=pressure_angle, internal_ring=True, - spoke_width=spoke_width, mount_hole=self.shaft, - profile_shift=profile_shift, move="up") - - for i in range(numplanets): - self.gears(teeth=self.planetteeth, dimension=self.modulus, - angle=pressure_angle, - mount_hole=self.shaft, profile_shift=profile_shift, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/planetary2.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/planetary2.py deleted file mode 100644 index c6c5928..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/planetary2.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Planetary2(Boxes): - """Balanced force Difference Planetary Gear (not yet working properly)""" - - ui_group = "Unstable" - - description = """Still has issues. The middle planetary gears set must not have a mashing sun gear as it can't be a proper gear set.""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("nema_mount") - self.argparser.add_argument( - "--profile", action="store", type=str, default="GT2_2mm", - choices=pulley.Pulley.getProfiles(), - help="profile of the teeth/belt") - self.argparser.add_argument( - "--sunteeth", action="store", type=int, default=20, - help="number of teeth on sun gear") - self.argparser.add_argument( - "--planetteeth", action="store", type=int, default=20, - help="number of teeth on planets") - self.argparser.add_argument( - "--maxplanets", action="store", type=int, default=0, - help="limit the number of planets (0 for as much as fit)") - self.argparser.add_argument( - "--deltateeth", action="store", type=int, default=1, - help="enable secondary ring with given delta to the ring gear") - self.argparser.add_argument( - "--modulus", action="store", type=float, default=1.0, - help="modulus of the teeth in mm") - self.argparser.add_argument( - "--shaft", action="store", type=float, default=6., - help="diameter of the shaft") - self.argparser.add_argument( - "--screw1", action="store", type=float, default=2.4, - help="diameter of lower part of the screw hole") - self.argparser.add_argument( - "--screw2", action="store", type=float, default=4., - help="diameter of upper part of the screw hole") - self.argparser.add_argument( - "--pinsize", action="store", type=float, default=3.1, - help="diameter of alignment pins") - # self.argparser.add_argument( - # "--stages", action="store", type=int, default=4, - # help="number of stages in the gear reduction") - - def pins(self, r, rh, nr=0, angle=0.0): - self.moveTo(0, 0, angle) - - if nr < 8: - ang = 20 + 10 * nr - else: - ang = 15 + 10 * (nr-8) - - ang = 180 - ang - for a in (0, ang, -ang): - self.moveTo(0, 0, a) - self.hole(r, 0, rh) - self.moveTo(0, 0, -a) - - - def render(self): - - ringteeth = self.sunteeth + 2 * self.planetteeth - t = self.thickness - spoke_width = 4 * t - pinsize = self.pinsize / 2. - - pitch1, size1, xxx = self.gears.sizes(teeth=self.sunteeth, - dimension=self.modulus) - pitch2, size2, xxx = self.gears.sizes(teeth=self.planetteeth, - dimension=self.modulus) - pitch3, size3, xxx = self.gears.sizes( - teeth=ringteeth, internal_ring=True, spoke_width=spoke_width, - dimension=self.modulus) - - planets = int(math.pi / (math.asin(float(self.planetteeth + 2) / (self.planetteeth + self.sunteeth)))) - - if self.maxplanets: - planets = min(self.maxplanets, planets) - - # Make sure the teeth mash - ta = self.sunteeth + ringteeth - # There are sunteeth+ringteeth mashing positions for the planets - planetpositions = [round(i * ta / planets) * 360 / ta for i in range(planets)] - secondary_offsets = [((pos % (360. / (ringteeth - self.deltateeth))) - - (pos % (360. / ringteeth)) * ringteeth / self.planetteeth) - for pos in planetpositions] - - ratio = (1 + (ringteeth / self.sunteeth)) * (-ringteeth/self.deltateeth) - # XXX make configurable? - profile_shift = 20 - pressure_angle = 20 - - screw = self.screw1 / 2 - - # output - # XXX simple guess - belt = self.profile - pulleyteeth = int((size3-2*t) * math.pi / pulley.Pulley.spacing[belt][1]) - numplanets = planets - - deltamodulus = self.modulus * ringteeth / (ringteeth - self.deltateeth) - - def holes(r): - def h(): - self.hole(2*t, 2*t, r) - self.hole(size3-2*t, 2*t, r) - self.hole(2*t, size3-2*t, r) - self.hole(size3-2*t, size3-2*t, r) - return h - - def planets(): - self.moveTo(size3/2, size3/2) - for angle in planetpositions: - angle += 180 # compensate for 3 position in callback - self.moveTo(0, 0, angle) - self.hole((pitch1+pitch2), 0, size2/2) - self.moveTo(0, 0, -angle) - - # Base - self.rectangularWall(size3, size3, callback=[ - lambda: self.NEMA(self.nema_mount, size3 / 2, size3 / 2), - holes(screw), planets], - move="up") - - def gear(): - self.moveTo(size3 / 2, size3 / 2) - self.gears(teeth=ringteeth, dimension=self.modulus, - angle=pressure_angle, internal_ring=True, - spoke_width=spoke_width, teeth_only=True, - profile_shift=profile_shift, move="up") - - # Lower primary ring gear - self.rectangularWall(size3, size3, callback=[gear, holes(screw)], move="up") - tl = 0.5*size3*(2**0.5-1)*2**0.5 - screw = self.screw2 / 2 - self.rectangularTriangle(tl, tl, num=8, callback=[ - None, lambda:self.hole(2*t, 2*t, screw)], move='up') - - # Secondary ring gears - def ring(): - self.gears(teeth=ringteeth - self.deltateeth, - dimension=deltamodulus, - angle=pressure_angle, internal_ring=True, - spoke_width=spoke_width, teeth_only=True, - profile_shift=profile_shift) - for i in range(3): - self.hole((size3-6*t)/2+0.5*pinsize, 0, pinsize) - self.moveTo(0, 0, 120) - - self.pulley(pulleyteeth, belt, callback=ring, move="up") - self.pulley(pulleyteeth, belt, callback=ring, move="up") - - # Upper primary ring gear - self.rectangularWall(size3, size3, callback=[gear, holes(screw)], move="up") - # top cover plate - self.rectangularWall(size3, size3, callback=[holes(screw)], move="up") - - # Sun gear - def sunpins(): - self.hole(0.5*self.shaft+1.5*pinsize ,0, pinsize) - self.hole(-0.5*self.shaft-1.5*pinsize ,0, pinsize) - self.partsMatrix(4, 4, 'up', self.gears, teeth=self.sunteeth, - dimension=self.modulus, callback=sunpins, - angle=pressure_angle, mount_hole=self.shaft, - profile_shift=profile_shift) - - # Planets - for i in range(numplanets): - with self.saved_context(): - self.gears(teeth=self.planetteeth, dimension=self.modulus, - angle=pressure_angle, - callback=lambda:self.pins(0.25*size2, pinsize, i), - profile_shift=profile_shift, move="right") - for j in range(2): - self.gears(teeth=self.planetteeth, dimension=self.modulus, - angle=pressure_angle, - callback=lambda:self.pins(0.25*size2, pinsize, i, - secondary_offsets[i]), - profile_shift=profile_shift, move="right") - self.gears(teeth=self.planetteeth, dimension=self.modulus, - angle=pressure_angle, - callback=lambda:self.pins(0.25*size2, pinsize, i), - profile_shift=profile_shift, move="right") - - self.gears(teeth=self.planetteeth, dimension=self.modulus, - angle=pressure_angle, - profile_shift=profile_shift, move="up only") - - self.text("1:%.1f" % abs(ratio)) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/platonic.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/platonic.py deleted file mode 100644 index 56fd0d0..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/platonic.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (C) 2020 Norbert Szulc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.edges import FingerJointEdge - - -class UnevenFingerJointEdge(FingerJointEdge): - """Uneven finger joint edge """ - char = 'u' - description = "Uneven Finger Joint" - positive = True - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - # copied from original - - positive = self.positive - - s, f, thickness = self.settings.space, self.settings.finger, self.settings.thickness - - p = 1 if positive else -1 - - fingers, leftover = self.calcFingers(length, bedBolts) - - if not positive: - play = self.settings.play - f += play - s -= play - leftover -= play - - shift = (f + s) / 2 # we shift all fingers to make them un even - if (leftover < shift): - leftover = shift - - self.edge((leftover + shift)/2, tabs=1) # Whole point of this class - - l1,l2 = self.fingerLength(self.settings.angle) - h = l1-l2 - - d = (bedBoltSettings or self.bedBoltSettings)[0] - - for i in range(fingers): - if i != 0: - if not positive and bedBolts and bedBolts.drawBolt(i): - self.hole(0.5 * s, - 0.5 * self.settings.thickness, 0.5 * d) - - if positive and bedBolts and bedBolts.drawBolt(i): - self.bedBoltHole(s, bedBoltSettings) - else: - self.edge(s) - - if positive and self.settings.style == "springs": - self.polyline( - 0, -90 * p, 0.8*h, (90 * p, 0.2*h), - 0.1 * h, 90, 0.9*h, -180, 0.9*h, 90, - f - 0.6*h, - 90, 0.9*h, -180, 0.9*h, 90, 0.1*h, - (90 * p, 0.2 *h), 0.8*h, -90 * p) - else: - self.polyline(0, -90 * p, h, 90 * p, f, 90 * p, h, -90 * p) - - self.edge((leftover - shift)/2, tabs=1) # Whole point of this class - -# Unstable -class UnevenFingerJointEdgeCounterPart(UnevenFingerJointEdge): - """Uneven finger joint edge - other side""" - char = 'U' - description = "Uneven Finger Joint (opposing side)" - positive = False - -class Platonic(Boxes): - """Platonic solids generator""" - - ui_group = "Unstable" # see ./__init__.py for names - description = """![Icosahedron](static/samples/Platonic-Icosahedron.jpg) -""" - - SOLIDS = { - "tetrahedron": (4, 3), - "cube": (6, 4), - "octahedron": (8, 3), - "dodecahedron": (12, 5), - "icosahedro": (20, 3), - } - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0) - - self.buildArgParser(x=60, outside=True) # x should be treated as edge length, TODO: change that - self.argparser.add_argument( - "--type", action="store", type=str, default=list(self.SOLIDS)[0], - choices=list(self.SOLIDS), - help="type of platonic solid") - - - def render(self): - # adjust to the variables you want in the local scope - e = self.x - t = self.thickness - faces, corners = self.SOLIDS[self.type] - - u = UnevenFingerJointEdge(self, self.edges["f"].settings) - self.addPart(u) - - uc = UnevenFingerJointEdgeCounterPart(self, self.edges["f"].settings) - self.addPart(uc) - - for _ in range(faces): - self.regularPolygonWall(corners, side=e, edges="u", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/polehook.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/polehook.py deleted file mode 100644 index 3a3c687..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/polehook.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class PoleHook(Boxes): # change class name here and below - """Hook for pole like things to be clamped to another pole""" - - def __init__(self) -> None: - Boxes.__init__(self) - - # Uncomment the settings for the edge types you use - self.addSettingsArgs(edges.FingerJointSettings) - - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--diameter", action="store", type=float, default=50., - help="diameter of the thing to hook") - self.argparser.add_argument( - "--screw", action="store", type=float, default=7.8, - help="diameter of the screw in mm") - self.argparser.add_argument( - "--screwhead", action="store", type=float, default=13., - help="with of the screw head in mm") - self.argparser.add_argument( - "--screwheadheight", action="store", type=float, default=5.5, - help="height of the screw head in mm") - self.argparser.add_argument( - "--pin", action="store", type=float, default=4., - help="diameter of the pin in mm") - - def fork(self, d, w, edge="e", full=True, move=None): - tw = d + 2 * w - th = 2 * d - - if self.move(tw, th, move, True): - return - - e = self.edges.get(edge, edge) - - - self.moveTo(0, e.margin()) - - if e is self.edges["e"]: - self.bedBoltHole(tw) - else: - e(tw, bedBolts=edges.Bolts(1)) - if full: - self.hole(-0.5*w, 2*d, self.pin/2) - self.polyline(0, 90, 2*d, (180, w/2), d, (-180, d/2), - 0.5*d, (180, w/2), 1.5 * d, 90) - else: - self.polyline(0, 90, d, 90, w, 90, 0, (-180, d/2), - 0.5*d, (180, w/2), 1.5 * d, 90) - - self.move(tw, th, move) - - def lock(self, l1, l2, w, move=None): - l1 += w/2 - l2 += w/2 - if self.move(l1, l2, move, True): - return - self.hole(w/2, w/2, self.pin/2) - self.moveTo(w/2, 0) - self.polyline(l2-w, (180, w/2), l2-2*w, (-90, w/2), l1-2*w, (180, w/2), - l1-w, (90, w/2)) - self.move(l1, l2, move) - - def backplate(self): - tw = self.diameter + 2*self.ww - t = self.thickness - b = edges.Bolts(1) - bs = (0.0, ) - self.fingerHolesAt(-tw/2, -2*t, tw, 0, bedBolts=b, bedBoltSettings=bs) - self.fingerHolesAt(-tw/2, 0, tw, 0, bedBolts=b, bedBoltSettings=bs) - self.fingerHolesAt(-tw/2, +2*t, tw, 0, bedBolts=b, bedBoltSettings=bs) - - def clamp(self): - d = self.diameter + 2 * self.ww - self.moveTo(10, -0.5*d, 90) - self.edge(d) - self.moveTo(0, -8, -180) - self.edge(d) - - def render(self): - # adjust to the variables you want in the local scope - d = self.diameter - t = self.thickness - - shh = self.screwheadheight - self.bedBoltSettings = (self.screw, self.screwhead, shh, d/4+shh, d/4) # d, d_nut, h_nut, l, l - self.ww = ww = 4*t - self.fork(d, ww, "f", move="right") - self.fork(d, ww, "f", move="right") - self.fork(d, ww, "f", full=False, move="right") - self.fork(d, ww, full=False, move="right") - self.fork(d, ww, full=False, move="right") - - self.parts.disc(d+2*ww, callback=self.backplate, hole=self.screw, move="right") - self.parts.disc(d+2*ww, hole=self.screw, move="right") - self.parts.disc(d+2*ww, callback=self.clamp, hole=self.screw+0.5*t, move="right") - self.parts.disc(d+2*ww, hole=self.screw+0.5*t, move="right") - self.parts.wavyKnob(50, callback=lambda:self.nutHole(self.screwhead), - move="right") - self.parts.wavyKnob(50, callback=lambda:self.nutHole(self.screwhead), - move="right") - self.parts.wavyKnob(50, hole=self.screw+0.5*t, move="right") - - ll = ((d**2 + (0.5*(d+ww))**2)**0.5) - 0.5 * d - for i in range(3): - self.lock(ll, ll, ww, move="right") - - for i in range(2): - self.parts.disc(ww, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/pulley.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/pulley.py deleted file mode 100644 index e76aabd..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/pulley.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import pulley - - -class Pulley(Boxes): - """Timing belt pulleys for different profiles""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - # remove cli params you do not need - self.buildArgParser(h=6.) - self.argparser.add_argument( - "--profile", action="store", type=str, default="GT2_2mm", - choices=pulley.Pulley.getProfiles(), - help="profile of the teeth/belt") - self.argparser.add_argument( - "--teeth", action="store", type=int, default=20, - help="number of teeth") - self.argparser.add_argument( - "--axle", action="store", type=float, default=5, - help="diameter of the axle") - self.argparser.add_argument( - "--insideout", action="store", type=BoolArg(), default=False, - help="create a ring gear with the belt being pushed against from within") - self.argparser.add_argument( - "--top", action="store", type=float, default=0, - help="overlap of top rim (zero for none)") - - # Add non default cli params if needed (see argparse std lib) - # self.argparser.add_argument( - # "--XX", action="store", type=float, default=0.5, - # help="DESCRIPTION") - - def disk(self, diameter, hole, callback=None, move=""): - w = diameter + 2 * self.spacing - - if self.move(w, w, move, before=True): - return - - self.moveTo(w / 2, w / 2) - self.cc(callback, None, 0.0, 0.0) - - if hole: - self.hole(0, 0, hole / 2.0) - - self.moveTo(diameter / 2 + self.burn, 0, 90) - self.corner(360, diameter / 2) - self.move(w, w, move) - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - - if self.top: - self.disk( - self.pulley.diameter(self.teeth, self.profile) + 2 * self.top, - self.axle, move="right") - - for i in range(int(math.ceil(self.h / self.thickness))): - self.pulley(self.teeth, self.profile, insideout=self.insideout, r_axle=self.axle / 2.0, move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack10box.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack10box.py deleted file mode 100644 index edd864d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack10box.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2018 Sebastian Reichel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes.generators.rack19box import Rack19Box - - -class Rack10Box(Rack19Box): - """Closed box with screw on top for mounting in a 10" rack.""" - - def render(self): - self._render(type=10) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack19box.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack19box.py deleted file mode 100644 index c4a85ae..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack19box.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Rack19Box(Boxes): - """Closed box with screw on top for mounting in a 19" rack.""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0.5) - self.argparser.add_argument( - "--depth", action="store", type=float, default=100., - help="inner depth in mm") - self.argparser.add_argument( - "--height", action="store", type=int, default=2, - choices=list(range(1, 17)), - help="height in rack units") - self.argparser.add_argument( - "--triangle", action="store", type=float, default=25., - help="Sides of the triangles holding the lid in mm") - self.argparser.add_argument( - "--d1", action="store", type=float, default=2., - help="Diameter of the inner lid screw holes in mm") - self.argparser.add_argument( - "--d2", action="store", type=float, default=3., - help="Diameter of the lid screw holes in mm") - - def wallxCB(self): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, self.triangle, 0) - self.fingerHolesAt(self.x, self.h-1.5*t, self.triangle, 180) - - def wallxfCB(self): # front - t = self.thickness - for x in (8.5, self.x+2*17.+2*t-8.5): - for y in (6., self.h-6.+t): - self.rectangularHole(x, y, 10, 6.5, r=3.25) - - self.moveTo(t+17., t) - self.wallxCB() - - def wallyCB(self): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, self.triangle, 0) - self.fingerHolesAt(self.y, self.h-1.5*t, self.triangle, 180) - - - def _render(self, type): - - t = self.thickness - self.h = h = self.height * 44.45 - 0.787 - t - if type == 10: - self.x = 219.0 - 2*t - else: - self.x = 448.0 - 2*t - x = self.x - y = self.y = self.depth - - d1, d2 =self.d1, self.d2 - tr = self.triangle - trh = tr / 3. - - self.rectangularWall(y, h, "ffef", callback=[self.wallyCB], - move="right", label="right") - self.flangedWall(x, h, "FFEF", callback=[self.wallxfCB], r=t, - flanges=[0., 17., -t, 17.], move="up", label="front") - self.rectangularWall(x, h, "fFeF", callback=[self.wallxCB], - label="back") - self.rectangularWall(y, h, "ffef", callback=[self.wallyCB], - move="left up", label="left") - - self.rectangularWall(x, y, "fFFF", move="up", label="bottom") - self.rectangularWall(x, y, callback=[ - lambda:self.hole(trh, trh, d=d2)] * 4, move='right', label="lid") - - self.rectangularTriangle(tr, tr, "ffe", num=4, - callback=[None, lambda: self.hole(trh, trh, d=d1)]) - - - def render(self): - self._render(type=19) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack19halfwidth.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack19halfwidth.py deleted file mode 100644 index 214c384..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rack19halfwidth.py +++ /dev/null @@ -1,96 +0,0 @@ -"""Half 19inch rack unit for musical equipment.""" - -from boxes import Boxes - - -class Rack19HalfWidth(Boxes): - """Half width 19inch rack unit for musical equipment.""" - - ui_group = "Box" - - def __init__(self) -> None: - super().__init__() - self.argparser.add_argument( - '--ru_count', action='store', type=float, default=1, - help='number of rack units') - self.argparser.add_argument( - '--holes', action='store', type=str, default="xxmpwx", - help='mounting patterns: x=xlr, m=midi, p=9v-power, w=6.5mm-wire, space=next row') - self.argparser.add_argument( - '--z', action='store', type=float, default=20, - help='depth of the shorter (rackear) side') - self.argparser.add_argument( - '--deepz', action="store", type=float, default=124, - help='depth of the longer (screwed to another half sized thing) side') - - def render(self): - """Render box.""" - # pylint: disable=invalid-name - t = self.thickness - z = self.z - self.x = x = 223 - (2 * t) - self.y = y = (self.ru_count * 44.45) - 4.45 - (2 * t) - deepz = self.deepz - - # front - self.flangedWall(x, y, "FFFF", callback=[self.util_holes, self.rack_holes], r=t, - flanges=[0, 17, 0, 0], move="up") - - # top&bottom - self.trapezoidWall(x, deepz, z, "fFeF", move="up") - self.trapezoidWall(x, deepz, z, "fFeF", move="up") - - # side - self.rectangularWall(deepz, y, "fffe", move="right") - self.rectangularWall(z, y, "fffe", move="up") - - def rack_holes(self): - """Rackmount holes.""" - t = self.thickness # pylint: disable=invalid-name - self.rectangularHole(6 + t, 10, 10, 6.5, r=3.25) - self.rectangularHole(self.y - 6 + t, 10, 10, 6.5, r=3.25) - - def util_holes(self): - """Add holes.""" - self.moveTo(10, (44.45 - 4.45)/2) - for line in self.holes.split(): - with self.saved_context(): - for hole in line: - self.hole_map.get(hole, lambda _: None)(self) - self.moveTo(0, 44.45) - - def hole_xlr(self): - """Hole for a xlr port.""" - self.moveTo(16) - self.hole(-9.5, 12, 1) - self.hole(0, 0, 11.8) - self.hole(9.5, -12, 1) - self.moveTo(16) - - def hole_midi(self): - """Hole for a midi port.""" - self.moveTo(17) - self.hole(-11.1, 0, 1) - self.hole(0, 0, 7.5) - self.hole(11.1, 0, 1) - self.moveTo(17) - - def hole_power(self): - """Hole for a 9v power port.""" - self.moveTo(11) - self.rectangularHole(0, 0, 9, 11) - self.moveTo(11) - - def hole_wire(self): - """Hole for a wire.""" - self.moveTo(3) - self.hole(0, 0, 3.25) - print('hi') - self.moveTo(3) - - hole_map = { - 'm': hole_midi, - 'p': hole_power, - 'w': hole_wire, - 'x': hole_xlr, - } diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rackbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rackbox.py deleted file mode 100644 index a495f7c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rackbox.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class RackBox(Boxes): - """Closed box with screw on top and mounting holes""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1.2) - self.buildArgParser("x", "y", "h", "outside") - self.argparser.add_argument( - "--triangle", action="store", type=float, default=25., - help="Sides of the triangles holding the lid in mm") - self.argparser.add_argument( - "--d1", action="store", type=float, default=2., - help="Diameter of the inner lid screw holes in mm") - self.argparser.add_argument( - "--d2", action="store", type=float, default=3., - help="Diameter of the lid screw holes in mm") - self.argparser.add_argument( - "--d3", action="store", type=float, default=4., - help="Diameter of the mounting screw holes in mm") - self.argparser.add_argument( - "--holedist", action="store", type=float, default=7., - help="Distance of the screw holes from the wall in mm") - - def wallxCB(self): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, self.triangle, 0) - self.fingerHolesAt(self.x, self.h-1.5*t, self.triangle, 180) - - def wallxfCB(self): # front - t = self.thickness - hd = self.holedist - for x in (hd, self.x+3*hd+2*t): - for y in (hd, self.h-hd+t): - self.hole(x, y, self.d3/2.) - - self.moveTo(t+2*hd, t) - self.wallxCB() - - def wallyCB(self): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, self.triangle, 0) - self.fingerHolesAt(self.y, self.h-1.5*t, self.triangle, 180) - - - def render(self): - - t = self.thickness - self.h = h = self.h + 2*t # compensate for lid - x, y, h = self.x, self.y, self.h - d1, d2, d3 =self.d1, self.d2, self.d3 - hd = self.holedist - tr = self.triangle - trh = tr / 3. - - if self.outside: - self.x = x = self.adjustSize(x) - self.y = y = self.adjustSize(y) - self.h = h = h - 3*t - - self.rectangularWall(x, h, "fFeF", callback=[self.wallxCB], - move="right") - self.rectangularWall(y, h, "ffef", callback=[self.wallyCB], move="up") - self.flangedWall(x, h, "FFeF", callback=[self.wallxfCB], r=t, - flanges=[0., 2*hd, -t, 2*hd]) - self.rectangularWall(y, h, "ffef", callback=[self.wallyCB], - move="left up") - - self.rectangularWall(x, y, "fFFF", move="right") - self.rectangularWall(x, y, callback=[ - lambda:self.hole(trh, trh, d=d2)] * 4, move='up') - - self.rectangularTriangle(tr, tr, "ffe", num=4, - callback=[None, lambda: self.hole(trh, trh, d=d1)]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rectangularWall.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rectangularWall.py deleted file mode 100644 index 97d425c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rectangularWall.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class RectangularWall(Boxes): - """Simple wall with options for different edges""" - - ui_group = "Part" # see ./__init__.py for names - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.CabinetHingeSettings) - self.addSettingsArgs(edges.ClickSettings) - self.addSettingsArgs(edges.DoveTailSettings) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.GearSettings) - self.addSettingsArgs(edges.GripSettings) - self.addSettingsArgs(edges.HingeSettings) - self.addSettingsArgs(edges.ChestHingeSettings) - self.addSettingsArgs(edges.SlideOnLidSettings) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=100, h=100) - - self.argparser.add_argument( - "--bottom_edge", action="store", - type=ArgparseEdgeType("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), choices=list("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), - default="e", help="edge type for bottom edge") - self.argparser.add_argument( - "--right_edge", action="store", - type=ArgparseEdgeType("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), choices=list("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), - default="e", help="edge type for right edge") - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), choices=list("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), - default="e", help="edge type for top edge") - self.argparser.add_argument( - "--left_edge", action="store", - type=ArgparseEdgeType("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), choices=list("cCdDeEfFghiIjJkKlLmMnNoOpPqQRsSšŠuUvV"), - default="e", help="edge type for left edge") - - - def cb(self, nr): - t = self.thickness - if self.edgetypes[nr] == "f": - self.fingerHolesAt(0, -2.5*t, self.h if nr % 2 else self.x, 0) - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - - self.edgetypes = [self.bottom_edge, self.right_edge, self.top_edge, self.left_edge] - - self.moveTo(3*t, 3*t) - self.rectangularWall(self.x, self.h, self.edgetypes, callback=self.cb) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/regularbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/regularbox.py deleted file mode 100644 index 0bdce89..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/regularbox.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.generators.bayonetbox import BayonetBox - - -class RegularBox(BayonetBox): - """Box with regular polygon as base""" - - description = """For short side walls that don't fit a connecting finger reduce *surroundingspaces* and *finger* in the Finger Joint Settings. - -The lids needs to be glued. For the bayonet lid all outside rings attach to the bottom, all inside rings to the top. -""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1) - self.buildArgParser("h", "outside") - self.argparser.add_argument( - "--radius_bottom", action="store", type=float, default=50.0, - help="inner radius of the box bottom (at the corners)") - self.argparser.add_argument( - "--radius_top", action="store", type=float, default=50.0, - help="inner radius of the box top (at the corners)") - self.argparser.add_argument( - "--n", action="store", type=int, default=5, - help="number of sides") - self.argparser.add_argument( - "--top", action="store", type=str, default="none", - choices=["none", "hole", "angled hole", "angled lid", "angled lid2", "round lid", "bayonet mount", "closed"], - help="style of the top and lid") - self.argparser.add_argument( - "--alignment_pins", action="store", type=float, default=1.0, - help="diameter of the alignment pins for bayonet lid") - self.argparser.add_argument( - "--bottom", action="store", type=str, default="closed", - choices=["none", "closed", "hole", "angled hole", "angled lid", "angled lid2", "round lid"], - help="style of the bottom and bottom lid") - - self.lugs=6 - - def render(self): - - r0, r1, h, n = self.radius_bottom, self.radius_top, self.h, self.n - - if self.outside: - r0 = r0 - self.thickness / math.cos(math.radians(360/(2*n))) - r1 = r1 - self.thickness / math.cos(math.radians(360/(2*n))) - if self.top == "none": - h = self.adjustSize(h, False) - elif "lid" in self.top and self.top != "angled lid": - h = self.adjustSize(h) - self.thickness - else: - h = self.adjustSize(h) - - t = self.thickness - - - r0, sh0, side0 = self.regularPolygon(n, radius=r0) - r1, sh1, side1 = self.regularPolygon(n, radius=r1) - - # length of side edges - #l = (((side0-side1)/2)**2 + (sh0-sh1)**2 + h**2)**0.5 - l = ((r0-r1)**2 + h**2)**.5 - # angles of sides -90° aka half of top angle of the full pyramid sides - a = math.degrees(math.asin((side1-side0)/2/l)) - # angle between sides (in boxes style change of travel) - phi = 180 - 2 * math.degrees( - math.asin(math.cos(math.pi/n) / math.cos(math.radians(a)))) - - fingerJointSettings = copy.deepcopy(self.edges["f"].settings) - fingerJointSettings.setValues(self.thickness, angle=phi) - fingerJointSettings.edgeObjects(self, chars="gGH") - - beta = math.degrees(math.atan((sh1-sh0)/h)) - angle_bottom = 90 + beta - angle_top = 90 - beta - - fingerJointSettings = copy.deepcopy(self.edges["f"].settings) - fingerJointSettings.setValues(self.thickness, angle=angle_bottom) - fingerJointSettings.edgeObjects(self, chars="yYH") - - fingerJointSettings = copy.deepcopy(self.edges["f"].settings) - fingerJointSettings.setValues(self.thickness, angle=angle_top) - fingerJointSettings.edgeObjects(self, chars="zZH") - - - def drawTop(r, sh, top_type, joint_type): - if top_type == "closed": - self.regularPolygonWall(corners=n, r=r, edges=joint_type[1], move="right") - elif top_type == "angled lid": - self.regularPolygonWall(corners=n, r=r, edges='e', move="right") - self.regularPolygonWall(corners=n, r=r, edges='E', move="right") - elif top_type in ("angled hole", "angled lid2"): - self.regularPolygonWall(corners=n, r=r, edges=joint_type[1], move="right", - callback=[lambda:self.regularPolygonAt( - 0, 0, n, h=sh-t)]) - if top_type == "angled lid2": - self.regularPolygonWall(corners=n, r=r, edges='E', move="right") - elif top_type in ("hole", "round lid"): - self.regularPolygonWall(corners=n, r=r, edges=joint_type[1], move="right", - hole=(sh-t)*2) - if top_type == "round lid": - self.parts.disc(sh*2, move="right") - if self.top == "bayonet mount": - self.diameter = 2*sh - self.parts.disc(sh*2-0.1*t, callback=self.lowerCB, - move="right") - self.regularPolygonWall(corners=n, r=r, edges='F', - callback=[self.upperCB], move="right") - self.parts.disc(sh*2, move="right") - - - with self.saved_context(): - drawTop(r0, sh0, self.bottom, "yY") - drawTop(r1, sh1, self.top, "zZ") - - self.regularPolygonWall(corners=n, r=max(r0, r1), edges='F', move="up only") - - fingers_top = self.top in ("closed", "hole", "angled hole", - "round lid", "angled lid2", "bayonet mount") - fingers_bottom = self.bottom in ("closed", "hole", "angled hole", - "round lid", "angled lid2") - - t_ = self.edges["G"].startwidth() - bottom_edge = ('y' if fingers_bottom else 'e') - top_edge = ('z' if fingers_top else 'e') - d_top = max(0, -t_ * math.sin(math.radians(a))) - d_bottom = max(0.0, t_ * math.sin(math.radians(a))) - l -= (d_top + d_bottom) - - if n % 2: - e = bottom_edge + 'ege' + top_edge + 'eeGee' - borders = [side0, 90-a, d_bottom, 0, l, 0, d_top, 90+a, side1, - 90+a, d_top, -90, t_, 90, l, 90, t_, -90, d_bottom, 90-a] - for i in range(n): - self.polygonWall(borders, edge=e, correct_corners=False, - move="right") - else: - borders0 = [side0, 90-a, - d_bottom, -90, t_, 90, l, 90, t_, -90, d_top, - 90+a, side1, 90+a, - d_top, -90, t_, 90, l, 90, t_, -90, d_bottom, 90-a] - e0 = bottom_edge + 'eeGee' + top_edge + 'eeGee' - borders1 = [side0, 90-a, d_bottom, 0, l, 0, d_top, 90+a, side1, - 90+a, d_top, 0, l, 0, d_bottom, 90-a] - e1 = bottom_edge + 'ege' + top_edge + 'ege' - for i in range(n//2): - self.polygonWall(borders0, edge=e0, correct_corners=False, - move="right") - self.polygonWall(borders1, edge=e1, correct_corners=False, - move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/regularstarbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/regularstarbox.py deleted file mode 100644 index 7ba4b2c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/regularstarbox.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class SlotEdge(edges.Edge): - - def __call__(self, length, **kw): - t, n = self.settings.thickness, self.settings.n - r, h = self.settings.radius, self.settings.h - sh = self.settings.sh # distance side to center - - li = 2 * sh * math.tan(math.radians(90/n)) # side inner 2x polygon - ls2 = t / math.tan(math.radians(180/n)) - ls1 = t / math.cos(math.radians(90-(180/n))) - - lo = (length-li-2*ls1)/2 - - li = li - 2*ls2 # correct for overlap of wall - - d = h/2 - - if li > 0: - poly = [lo-1, (90, 1), d+t-1, -90, ls1+ls2, -90, d-t, (90, t)] - self.polyline(*(poly + [li-2*t] + list(reversed(poly)))) - - def startwidth(self) -> float: - return self.settings.thickness - - -class RegularStarBox(Boxes): - """Regular polygon boxes that form a star when closed""" - - ui_group = "Box" - - - description = """![Open box](static/samples/RegularStarBox-2.jpg)""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser("h", "outside") - self.argparser.add_argument( - "--radius", action="store", type=float, default=50.0, - help="inner radius if the box (center to corners)") - self.argparser.add_argument( - "--n", action="store", type=int, default=5, - choices=(3, 4, 5), - help="number of sides") - - def render(self): - - r, h, n = self.radius, self.h, self.n - - if self.outside: - self.r = r = r - self.thickness / math.cos(math.radians(360/(2*n))) - self.h = h = self.adjustSize(h) - - t = self.thickness - - fingerJointSettings = copy.deepcopy(self.edges["f"].settings) - fingerJointSettings.setValues(self.thickness, angle=360./n) - fingerJointSettings.edgeObjects(self, chars="gGH") - - self.edges["e"] = SlotEdge(self, self) - - r, sh, side = self.regularPolygon(n, radius=r) - self.sh = sh - - with self.saved_context(): - self.regularPolygonWall(corners=n, r=r, edges='F', move="right") - self.regularPolygonWall(corners=n, r=r, edges='F', move="right") - - self.regularPolygonWall(corners=n, r=r, edges='F', move="up only") - - for s in range(2): - with self.saved_context(): - if n % 2: - for i in range(n): - self.rectangularWall(side, h, move="right", - edges="fgeG") - else: - for i in range(n//2): - self.rectangularWall(side, h, move="right", - edges="fGeG") - self.rectangularWall(side, h, move="right", - edges="fgeg") - - self.rectangularWall(side, h, move="up only", - edges="fgeG") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/robotarm.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/robotarm.py deleted file mode 100644 index 9f8ac6d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/robotarm.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (C) 2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import robot, servos - - -class RobotArm(Boxes): # change class name here and below - """Segments of servo powered robot arm""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - for i in range(1, 6): - ra = robot.RobotArg(True) - sa = servos.ServoArg() - self.argparser.add_argument( - "--type%i" % i, action="store", type=ra, - default="none", choices=ra.choices(), - help="type of arm segment") - self.argparser.add_argument( - "--servo%ia" % i, action="store", type=sa, default="Servo9g", - choices=sa.choices(), help="type of servo to use") - self.argparser.add_argument( - "--servo%ib" % i, action="store", type=sa, default="Servo9g", - choices=sa.choices(), help="type of servo to use on second side (if different is supported)") - self.argparser.add_argument( - "--length%i" % i, action="store", type=float, default=50., - help="length of segment axle to axle") - - def render(self): - - for i in range(5, 0,-1): - armtype = getattr(self, "type%i" % i) - length = getattr(self, "length%i" % i) - servoA = getattr(self, "servo%ia" % i) - servoB = getattr(self, "servo%ib" % i) - armcls = getattr(robot, armtype, None) - if not armcls: - continue - servoClsA = getattr(servos, servoA) - servoClsB = getattr(servos, servoB) - armcls(self, servoClsA(self), servoClsB(self))(length, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rollholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rollholder.py deleted file mode 100644 index 8581f1d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rollholder.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class RollHolder(Boxes): - """Holder for kitchen rolls or other rolls""" - - description = """Needs a dowel or pipe as axle.""" - - ui_group = "WallMounted" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--width", action="store", type=float, default=275, - help="length of the axle in mm") - self.argparser.add_argument( - "--diameter", action="store", type=float, default=120, - help="maximum diameter of the roll in mm (choose generously)") - self.argparser.add_argument( - "--height", action="store", type=float, default=80, - help="height of mounting plate in mm") - self.argparser.add_argument( - "--axle", action="store", type=float, default=25, - help="diameter of the axle in mm including play") - self.argparser.add_argument( - "--screw_holes", action="store", type=float, default=4, - help="diameter of mounting holes in mm") - self.argparser.add_argument( - "--one_piece", action="store", type=boolarg, default=True, - help="have a continuous back plate instead of two separate holders") - - def side(self, move=None): - d = self.diameter - a = self.axle - h = self.height - t = self.thickness - - tw, th = h, (d + a) / 2 + 4 * t - - if self.move(tw, th, move, True): - return - - self.moveTo(0, t) - self.edges["f"](h) - self.fingerHolesAt(-(a/2+3*t), self.burn, d/2, 90) - self.polyline(0, 90, d/2, (90, a/2 + 3*t)) - - r = a/2 + 3*t - a = math.atan2(float(d/2), (h-a-6*t)) - alpha = math.degrees(a) - - self.corner(alpha, r) - self.edge(((h-2*r)**2+(d/2)**2)**0.5) - self.corner(90-alpha, r) - self.corner(90) - - self.move(tw, th, move) - - def backCB(self): - t = self.thickness - a = self.axle - h = self.height - w = self.width - - plate = w + 2*t + h/2 if self.one_piece else h/2 + t - - self.fingerHolesAt(h/4+t/2-3*t, 0, h, 90) - self.fingerHolesAt(h/4-3*t, h-3*t-a/2, h/4, 180) - - if self.one_piece: - self.fingerHolesAt(h/4+t/2+t-3*t+w, 0, h, 90) - self.fingerHolesAt(h/4+2*t-3*t+w, h-3*t-a/2, h/4, 0) - - for x in (0, plate-6*t): - for y in (3*t, h-3*t): - self.hole(x, y, d=self.screw_holes) - - def rings(self): - a = self.axle - r = a/2 - t = self.thickness - - self.moveTo(0, a+1.5*t, -90) - for i in range(2): - self.polyline(r-1.5*t, (180, r+3*t), 0, (180, 1.5*t), 0, - (-180, r), r-1.5*t, (180, 1.5*t)) - self.moveTo(a-t, a+12*t, 180) - - - def render(self): - t = self.thickness - w = self.width - d = self.diameter - a = self.axle - h = self.height - - self.height = h = max(h, a+10*t) - - self.side(move="right") - self.side(move="right") - - self.rectangularTriangle(h/4, d/2, "ffe", num=2, r=3*t, move="right") - - if self.one_piece: - self.roundedPlate(w+h/2+2*t, h, edge="e", r=3*t, - extend_corners=False, - callback=[self.backCB], move="right") - else: - self.roundedPlate(h/2+t, h, edge="e", r=3*t, - extend_corners=False, - callback=[self.backCB], move="right") - self.roundedPlate(h/2+t, h, edge="e", r=3*t, - extend_corners=False, - callback=[self.backCB], move="right mirror") - - self.rings() diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rotary.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rotary.py deleted file mode 100644 index a19e5d2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/rotary.py +++ /dev/null @@ -1,324 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class MotorEdge(edges.BaseEdge): - # def margin(self) -> float: - # return 30.0 - def __call__(self, l, **kw): - self.polyline( - l - 165, 45, - 25 * 2 ** 0.5, -45, - 60, -45, - 25 * 2 ** 0.5, 45, - 55) - - -class OutsetEdge(edges.OutSetEdge): - def startwidth(self) -> float: - return 20.0 - - -class HangerEdge(edges.BaseEdge): - char = "H" - - def margin(self) -> float: - return 40.0 - - def __call__(self, l, **kw): - self.fingerHolesAt(0, -0.5 * self.thickness, l, angle=0) - w = self.settings - self.polyline(0, -90, - 22 + w, 90, - 70, 135, - 2 ** 0.5 * 12, 45, - 35, -45, - 2 ** 0.5 * 0.5 * w, -90, - 2 ** 0.5 * 0.5 * w, -45, - l - 28, 45, - 2 ** 0.5 * 5, 45, 5, -90) - - -class RollerEdge(edges.BaseEdge): - def margin(self) -> float: - return 20.0 - - def __call__(self, l, **kw): - m = 40 + 100 - self.polyline((l - m) / 2.0, -45, - 2 ** 0.5 * 20, 45, - 100, 45, - 2 ** 0.5 * 20, -45, - (l - m) / 2.0) - - -class RollerEdge2(edges.BaseEdge): - def margin(self) -> float: - return self.thickness - - def __call__(self, l, **kw): - a = 30 - f = 1 / math.cos(math.radians(a)) - self.edges["f"](70) - self.polyline(0, a, f * 25, -a, l - 190, -a, f * 25, a, 0) - self.edges["f"](70) - - -class Rotary(Boxes): - """Rotary Attachment for engraving cylindrical objects in a laser cutter""" - - ui_group = "Unstable" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - self.argparser.add_argument( - "--diameter", action="store", type=float, default=72., - help="outer diameter of the wheels (including O rings)") - self.argparser.add_argument( - "--rubberthickness", action="store", type=float, default=5., - help="diameter of the strings of the O rings") - self.argparser.add_argument( - "--axle", action="store", type=float, default=6., - help="diameter of the axles") - self.argparser.add_argument( - "--knifethickness", action="store", type=float, default=8., - help="thickness of the knives in mm. Use 0 for use with honey comb table.") - self.argparser.add_argument( - "--beamwidth", action="store", type=float, default=32., - help="width of the (aluminium) profile connecting the parts") - self.argparser.add_argument( - "--beamheight", action="store", type=float, default=7.1, - help="height of the (aluminium) profile connecting the parts") - - def mainPlate(self): - # Motor block outer side - t = self.thickness - d = self.diameter - a = self.axle - bw, bh = self.beamwidth, self.beamheight - hh = 0.5 * d + bh + 2 # hole height - self.hole(1.0 * d, hh, a/2.) - #self.hole(1.0 * d, hh, d/2.) - self.hole(2.0 * d + 5, hh, a/2.) - #self.hole(2.0 * d + 5, hh, d/2.) - # Main beam - self.rectangularHole(1.5*d+2.5, 0.5*bh, bw, bh) - - def frontPlate(self): - # Motor block inner side with motor mount - t = self.thickness - d = self.diameter - a = self.axle - bw, bh = self.beamwidth, self.beamheight - hh = 0.5 * d + bh + 2 # hole height - self.hole(1.0 * d, hh, a/2.) - #self.hole(1.0 * d, hh, d/2.) - self.hole(2.0 * d + 5, hh, a/2.) - #self.hole(2.0 * d + 5, hh, d/2.) - # Main beam - self.rectangularHole(1.5 * d+2.5, 0.5 * bh, bw, bh) - # Motor - mx = 2.7 * d + 20 - self.rectangularHole(mx, hh, 36 + 20, 36, r=36 / 2.0) - - for x in (-1, 1): - for y in (-1,1): - self.rectangularHole(mx+x * 25, hh + y * 25, 20, 4, r=2) - - def link(self, x, y, a, middleHole=False, move=None): - t = self.thickness - overallwidth = x + y - overallheight = y - ra = a / 2.0 - - if self.move(overallwidth, overallheight, move, before=True): - return - - self.moveTo(y / 2.0, 0) - self.hole(0, y / 2., ra) - self.hole(x, y / 2., ra) - - if middleHole: - self.hole(x / 2., y / 2., ra) - - self.edge(10) - self.edges["F"](60) - self.polyline(x - 70, (180, y / 2.), x, (180, y / 2.)) - - self.move(overallwidth, overallheight, move) - - def holderBaseCB(self): - bw, bh = self.beamwidth, self.beamheight - self.hole(20, self.hh - 10, self.a / 2) - self.rectangularHole(self.hl - 70, self.hh - 10, 110, self.a, r=self.a / 2) - self.rectangularHole(self.hl / 2, 0.5 * bh, bw, bh) - - def holderTopCB(self): - self.fingerHolesAt(0, 30 - 0.5 * self.thickness, self.hl, 0) - d = self.diameter / 2.0 + 1 - # XXX - y = -0.5 * self.diameter + self.th + self.hh - self.beamheight - 2. - self.hole(self.hl / 2 + d, y, self.axle / 2.0) - self.hole(self.hl / 2 - d, y, self.axle / 2.0) - self.hole(self.hl / 2 + d, y, self.diameter / 2.0) - self.hole(self.hl / 2 - d, y, self.diameter / 2.0) - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - d = self.diameter - a = self.a = self.axle - bw, bh = self.beamwidth, self.beamheight - - # self.spacing = 0.1 * t - - # Change settings of default edges if needed. E.g.: - self.edges["f"].settings.setValues(self.thickness, space=2, finger=2, - surroundingspaces=1) - if self.knifethickness: - self.addPart(HangerEdge(self, self.knifethickness)) - else: - self.edges["H"] = self.edges["F"] - - # Holder - hw = self.hw = 70. - hh = self.hh = 35. + bh - hl = self.hl = 240 - # Base - self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB, None, - lambda: self.rectangularHole(hl / 2 + 50, hh - t / 2 - 1, - 60, t + 2)], move="up") - self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB], move="up") - self.rectangularWall(hl, hw, edges="ffff", callback=[lambda: self.hole(hl / 2 - 16 - 20, 25, 5)], move="up") - - with self.saved_context(): - self.rectangularWall(hw, hh, edges="hFeF", callback=[ - lambda: self.hole(hw / 2, hh - 20, 4)],move="right") - self.rectangularWall(hw, hh, edges="hFeF", move="right") - # Top - th = self.th = 30 - # sides - - self.rectangularWall(hw + 20, th, edges="fFeF", move="right", - callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)]) - self.rectangularWall(hw + 20, th, edges="fFeF", move="right", - callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)]) - - self.rectangularWall(hw, hh, edges="hFeF", move="up only") - outset = OutsetEdge(self, None) - roller2 = RollerEdge2(self, None) - self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[ - lambda: self.hole(20, 15, a / 2), None, lambda: self.rectangularHole(50, th - 15, 70, a, r=a / 2)], - move="up") - self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[ - lambda: self.hole(20, 15, a / 2), None, lambda: self.rectangularHole(50, th - 15 - t, 70, a, r=a / 2)], - move="up") - self.rectangularWall(hl, th, edges=[roller2, "f", RollerEdge(self, None), "f"], callback=[ - self.holderTopCB], move="up") - self.rectangularWall(hl, 20 - t, edges="feee", move="up") - tl = 70 - self.rectangularWall(tl, hw + 20, edges="FeFF", move="right", - callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)]) - self.rectangularWall(tl, hw + 20, edges="FeFF", move="", - callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)]) - self.rectangularWall(tl, hw + 20, edges="FeFF", move="left up only", - callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)]) - - # Links - self.link(hl - 40, 25, a, True, move="up") - self.link(hl - 40, 25, a, True, move="up") - self.link(hl - 40, 25, a, True, move="up") - self.link(hl - 40, 25, a, True, move="up") - - with self.saved_context(): - self.rectangularWall(hw - 2 * t - 2, 60, edges="efef", move="right") - self.rectangularWall(hw - 4 * t - 4, 60, edges="efef", move="right") - # Spindle auxiliaries - self.parts.wavyKnob(50, callback=lambda: self.nutHole("M8"), move="right") - self.parts.wavyKnob(50, callback=lambda: self.nutHole("M8"), move="right") - - self.rectangularWall(hw - 2 * t - 4, 60, edges="efef", move="up only") - - with self.saved_context(): - slot = edges.SlottedEdge(self, [(30 - t) / 2, (30 - t) / 2], slots=15) - self.rectangularWall(30, 30, edges=["e", "e", slot, "e"], - callback=[lambda: self.hole(7, 23, self.axle / 2)], move="right") - self.rectangularWall(30, 30, edges=["e", "e", slot, "e"], - callback=[lambda: self.hole(7, 23, self.axle / 2)], move="right") - leftover = (hw - 6 * t - 6 - 20) / 2.0 - slot = edges.SlottedEdge(self, [leftover, 20, leftover], slots=15) - self.rectangularWall(hw - 4 * t - 6, 30, edges=[slot, "e", "e", "e"], - callback=[lambda: self.hole((hw - 4 * t - 6) / 2., 15, 4)], move="right") - for i in range(3): - self.rectangularWall(20, 30, - callback=[lambda: self.nutHole("M8", 10, 15)], move="right") - self.rectangularWall(20, 30, - callback=[lambda: self.hole(10, 15, 4)], move="right") - - self.rectangularWall(30, 30, move="up only") - - self.h = h = bh + 2 + 1.0 * d # height of outer pieces - # Other side - if self.knifethickness: - ow = 10 - self.rectangularWall(3.6 * d, h, edges="hfFf", callback=[ - lambda:self.rectangularHole(1.8 * d, 0.5 * bh, bw, bh)], - move="up") - self.rectangularWall(3.6 * d, h, edges="hfFf", callback=[ - lambda:self.rectangularHole(1.8 * d, 0.5 * bh, bw, bh)], - move="up") - self.rectangularWall(3.6 * d, ow, edges="ffff", move="up") - self.rectangularWall(3.6 * d, ow, edges="ffff", move="up") - with self.saved_context(): - self.rectangularWall(ow, h, edges="hFFH", move="right") - self.rectangularWall(ow, h, edges="hFFH", move="right") - self.rectangularWall(ow, h, edges="hFFH", move="up only") - - # Motor block - mw = 40 - self.rectangularWall(3.6 * d, h, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.mainPlate], move="up") - self.rectangularWall(3.6 * d, h, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.frontPlate], move="up") - self.rectangularWall(3.6 * d, mw, edges="ffff", move="up") - with self.saved_context(): - self.rectangularWall(mw, h, edges="hFeH", move="right") - self.rectangularWall(mw, h, edges="hFeH", move="right") - - self.pulley(88, "GT2_2mm", r_axle=a / 2.0, move="right") - self.pulley(88, "GT2_2mm", r_axle=a / 2.0, move="right") - self.rectangularWall(mw, h, edges="hFeH", move="up only") - self.axle = 19 - - for i in range(3): - self.parts.disc(self.diameter - 2 * self.rubberthickness, - hole=self.axle, move="right") - self.parts.disc(self.diameter - 2 * self.rubberthickness, - hole=self.axle, move="up right") - - for i in range(3): - self.parts.disc(self.diameter - 2 * self.rubberthickness, - hole=self.axle, move="left") - self.parts.disc(self.diameter - 2 * self.rubberthickness, - hole=self.axle, move="left up") - - for i in range(3): - self.parts.disc(self.diameter - 2 * self.rubberthickness + 4, - hole=self.axle, move="right") - self.parts.disc(self.diameter - 2 * self.rubberthickness + 4, - hole=self.axle, move="right up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/roundedbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/roundedbox.py deleted file mode 100644 index 429a8c2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/roundedbox.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import boxes - - -class RoundedBox(boxes.Boxes): - """Box with vertical edges rounded""" - - description = """ -Default: edge_style = f Finger Joint: -![Finger Joint](static/samples/RoundedBox-2.jpg) - -Alternative: edge_style = h Edge (parallel Finger Joint Holes): -![Finger Joint Holes](static/samples/RoundedBox-3.jpg) - -With lid: -""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - boxes.Boxes.__init__(self) - self.addSettingsArgs(boxes.edges.FingerJointSettings) - self.addSettingsArgs(boxes.edges.DoveTailSettings) - self.addSettingsArgs(boxes.edges.FlexSettings) - self.buildArgParser("x", "y", "outside", sh="100.0") - self.argparser.add_argument( - "--radius", action="store", type=float, default=15, - help="Radius of the corners in mm") - self.argparser.add_argument( - "--wallpieces", action="store", type=int, default=1, - choices=[1, 2, 3, 4], help="number of pieces for outer wall") - self.argparser.add_argument( - "--edge_style", action="store", - type=boxes.ArgparseEdgeType("fFh"), choices=list("fFh"), - default="f", - help="edge type for top and bottom edges") - self.argparser.add_argument( - "--top", action="store", type=str, default="none", - choices=["closed", "hole", "lid",], - help="style of the top and lid") - - def hole(self): - t = self.thickness - x, y, r = self.x, self.y, self.radius - - dr = 2*t - if self.edge_style == "h": - dr = t - - if r > dr: - r -= dr - else: - x += dr - 2*r - y += dr - 2*r - self.moveTo(dr-r, 0) - r = 0 - - lx = x - 2*r - 2*dr - ly = y - 2*r - 2*dr - - self.moveTo(0, dr) - for l in (lx, ly, lx, ly): - self.edge(l) - self.corner(90, r) - - def cb(self, nr): - h = 0.5 * self.thickness - - left, l, right = self.surroundingWallPiece(nr, self.x, self.y, self.radius, self.wallpieces) - for dh in self.sh[:-1]: - h += dh - self.fingerHolesAt(0, h, l, 0) - - def render(self): - - x, y, sh, r = self.x, self.y, self.sh, self.radius - - if self.outside: - self.x = x = self.adjustSize(x) - self.y = y = self.adjustSize(y) - self.sh = sh = self.adjustSize(sh) - - r = self.radius = min(r, y / 2.0) - - t = self.thickness - - h = sum(sh) + t * (len(sh) - 1) - es = self.edge_style - - corner_holes = True - if self.edge_style == "f": - pe = "F" - ec = False - elif self.edge_style == "F": - pe = "f" - ec = False - else: # "h" - pe = "f" - corner_holes = True - ec = True - - with self.saved_context(): - self.roundedPlate(x, y, r, es, wallpieces=self.wallpieces, - extend_corners=ec, move="right") - for dh in self.sh[:-1]: - self.roundedPlate(x, y, r, "f", wallpieces=self.wallpieces, - extend_corners=False, move="right") - self.roundedPlate(x, y, r, es, wallpieces=self.wallpieces, - extend_corners=ec, move="right", - callback=[self.hole] if self.top != "closed" else None) - if self.top == "lid": - r_extra = self.edges[self.edge_style].spacing() - self.roundedPlate(x+2*r_extra, - y+2*r_extra, - r+r_extra, - "e", wallpieces=self.wallpieces, - extend_corners=False, move="right") - - self.roundedPlate(x, y, r, es, wallpieces=self.wallpieces, move="up only") - - self.surroundingWall(x, y, r, h, pe, pe, pieces=self.wallpieces, - callback=self.cb) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/royalgame.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/royalgame.py deleted file mode 100644 index a1dfeb7..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/royalgame.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class RoyalGame(Boxes): - """The Royal Game of Ur""" - - ui_group = "Misc" - - description = """Most of the blue lines need to be engraved by cutting with high speed and low power. But there are three blue holes that actually need to be cut: The grip hole in the lid and two tiny rectangles on the top and bottom for the lid to grip into. - -![Lid Details](static/samples/RoyalGame-2.jpg) - -![All pieces](static/samples/RoyalGame-3.jpg) - -""" - - def __init__(self) -> None: - Boxes.__init__(self) - - - self.addSettingsArgs(edges.FingerJointSettings) - self.buildArgParser(x=200) - - def dice(self, size, num=1, move=None): - - s = size - r = s / 20.0 - dr = r * 2 - h = s/2*3**0.5 - t = self.thickness - tw, th = (num + 0.5) * size, size - - if self.move(tw, th, move, True): - return - - self.moveTo(r, 0) - for i in range(2*num): - self.polyline((s-t)/2-dr, 90, h/2-r, -90, t, -90, h/2-r, 90, (s-t)/2-dr, (120, r), s-2*dr, (120, r), s-2*dr, (120, r)) - self.ctx.stroke() - if i % 2: - self.moveTo(.5*s - 2*dr, s, 180) - else: - self.moveTo(1.5*s -2*dr, s, 180) - - self.move(tw, th, move) - - def five(self, x, y, s): - self.hole(x, y, 0.05*s) - self.hole(x, y, 0.12*s) - for dx in (-1, 1): - for dy in (-1, 1): - self.hole(x+dx*.25*s, y+dy*.25*s, 0.05*s) - self.hole(x+dx*.25*s, y+dy*.25*s, 0.12*s) - - @restore - @holeCol - def _castle(self, x, y, s): - l = s/7*2**0.5 - self.moveTo(x-s/2 + s/14, y-s/2, 45) - self.polyline(*([l, -90, l, 90]*3 + [l/2, 90])*4) - - def castle(self, x, y, s): - self._castle(x, y, 0.9*s) - self._castle(x, y, 0.5*s) - self.five(x, y, 0.4*s) - - def castles(self, x, y, s): - for dx in (-1, 1): - for dy in (-1, 1): - self._castle(x+dx*0.25*s, y+dy*0.25*s, 0.4*s) - self.five(x+dx*0.25*s, y+dy*0.25*s, 0.3*s) - - @restore - @holeCol - def rosette(self, x, y, s): - self.moveTo(x, y, 22.5) - with self.saved_context(): - self.moveTo(0.1*s, 0, -30) - for i in range(8): - self.polyline(0, (60, 0.35*s), 0, 120, 0, (60, 0.35*s), 0, - -120, 0, (45, 0.1*s), 0, -120) - self.moveTo(0, 0, -22.5) - self.moveTo(0.175*s, 0) - for i in range(8): - self.polyline(0, (67.5, 0.32*s), 0, 90, 0, (67.5, 0.32*s), 0, -180) - - @holeCol - def eyes(self, x, y, s): - for dx in (-1, 1): - for dy in (-1, 1): - posx = x+dx*0.3*s - posy = y+dy*0.25*s - self.rectangularHole(posx, posy, 0.4*s, 0.5*s) - self.hole(posx, posy, 0.05*s) - with self.saved_context(): - self.moveTo(posx, posy-0.2*s, 60) - self.corner(60, 0.4*s) - self.corner(120) - self.corner(60, 0.4*s) - self.corner(120) - self.moveTo(0, 0, -60) - self.moveTo(0, -0.05*s, 60) - self.corner(60, 0.5*s) - self.corner(120) - self.corner(60, 0.5*s) - - for i in range(4): - self.rectangularHole(x, y + (i-1.5)*s*0.25, 0.12*s, 0.12*s) - - def race(self, x, y, s): - for dx in range(4): - for dy in range(4): - posx = (dx-1.5) * s / 4.5 + x - posy = (dy-1.5) * s / 4.5 + y - self.rectangularHole(posx, posy, s/5, s/5) - if dx in (1, 2) and dy in (0,3): - continue - self.hole(posx, posy, s/20) - - def top(self): - - patterns = [ - [self.castle, self.rosette, None, None, self.eyes, self.five, self.eyes, self.rosette], - [self.five, self.eyes, self.castles, self.five, self.rosette, self.castles, self.five, self.race]] - - s = self.size - for x in range(8): - for y in range(3): - if x in [2, 3] and y != 1: - continue - posx = (0.5+x) * s - posy = (0.5+y) * s - self.rectangularHole(posx, posy, 0.9*s, 0.9*s) - pattern = patterns[y % 2][x] - if pattern: - pattern(posx, posy, 0.9*s) - - def player1(self): - for i in range(3): - self.hole(0, 0, r=self.size * (i+2) / 12) - - def player2(self, x=0, y=0): - s = self.size - self.hole(x, y, 0.07*s) - for dx in (-1, 1): - for dy in (-1, 1): - self.hole(x+dx*.2*s, y+dy*.2*s, 0.07*s) - - def render(self): - - x = self.x - t = self.thickness - self.size = size = x / 8.0 - h = size/2 * 3**0.5 - y = 3 * size - - self.rectangularWall(x, h, "FLFF", move="right") - self.rectangularWall(y, h, "nlmE", callback=[ - lambda:self.hole(y/2, h/2, d=0.6*h)], move="up") - self.rectangularWall(y, h, "FfFf") - self.rectangularWall(x, h, "FeFF", move="left up") - - self.rectangularWall(x, y, "fMff", move="up") - self.rectangularWall(x, y, "fNff", callback=[self.top,], move="up") - - - self.partsMatrix(7, 7, "up", self.parts.disc, 0.8*size, callback=self.player1) - self.partsMatrix(7, 7, "up", self.parts.disc, 0.8*size, callback=self.player2) - - self.dice(size, 4, move="up") - self.dice(size, 4, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sevensegment.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sevensegment.py deleted file mode 100644 index fa4033a..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sevensegment.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class SevenSegmentPattern(Boxes): - """Holepatterns and walls for a seven segment digit""" - - description = """This pattern is indented to be used with a LED stripe that is wound through all segments in an S pattern while the stripe being upright on its side. It can also be used with small pieces of LED stripes connected with short wires for large enough sizes. -""" - - ui_group = "Holes" - - def __init__(self): - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--digit", action="store", type=float, default=100.0, - help="height of the digit (without walls) in mm") - self.argparser.add_argument( - "--h", action="store", type=float, default=20.0, - help="height separation walls in mm") - - @restore - @holeCol - def segment(self, l, w): - w2 = w * 2**0.5 - self.moveTo(0, 0, 45) - self.polyline(w2, -45, l-2*w, -45, w2, -90, w2, -45, - l-2*w, -45, w2, -90) - - @restore - def seven_segments(self, x): - t = self.thickness - l = 0.4 * x - w = 0.05 * x - d = 0.05 * x - width = l + 2*w + d # 0.55 * x - - #self.rectangularHole(width/2, x/2, width, x) - - for px in [w/2 + d/2 , w/2 + l + 1.5*d]: - for py in [w + d/2, w + l + 1.5*d]: - with self.saved_context(): - self.moveTo(px, py, 90) - self.segment(l, w) - for i in range(3): - with self.saved_context(): - self.moveTo(w/2 + d, w + i*(l+d)) - self.segment(l, w) - - def seven_segment_holes(self, x): - t = self.thickness - l = 0.4 * x - w = 0.05 * x - d = 0.05 * x - width = l + 2*w + d - - for i in range(2): - self.fingerHolesAt(t/4*2**.5, x/2+w-t/4*2**.5, - 2**0.5*(width-t) - t/2, -45) - self.fingerHolesAt(t, t, 2**0.5* (.55*x/2 - t) - t/2, 45) - self.fingerHolesAt(width/2 + t/2**.5/2, - width/2 + t/2**.5/2, - 2**0.5*(l/2+d/2) - 1.5*t, 45) - self.fingerHolesAt(-t/2, x/2 + 0.25*t, x/2 - 0.25*t, 90) - self.fingerHolesAt(-t/2, 0, x/2 - 0.25*t, 90) - self.fingerHolesAt(-t, -t/2, l + 2*w + d + 2*t, 0) - self.moveTo(width, x, 180) - - def seven_segment_separators(self, x, h, n=1): - t = self.thickness - l = 0.4 * x - w = 0.05 * x - d = 0.05 * x - width = l + 2*w + d # 0.55 * x - for length in ( - 2**0.5*(width-t) - t/2, - 2**0.5* x/4 - t, - 2**0.5*(l/2+d/2) - 1.5*t, - x/2 - 0.25*t, - x/2 - 0.25*t, - l + 2*w + d + 2*t,): - self.partsMatrix(2*n, 1, "right", - self.rectangularWall, length, h, "feee") - - def render(self): - digit, h = self.digit, self.h - t = self.thickness - - self.seven_segments(digit) - self.moveTo(0.55*digit+self.spacing+t, t) - #self.seven_segments(digit) - self.seven_segment_holes(digit) - self.moveTo(0.55*digit+self.spacing+t, -t) - self.seven_segment_separators(digit, h) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sevensegmentclock.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sevensegmentclock.py deleted file mode 100644 index dcbc183..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sevensegmentclock.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - -from .sevensegment import SevenSegmentPattern - - -class SevenSegmentClock(SevenSegmentPattern): - """Seven segment clock build with LED stripe""" - - description = """You need a LED stripe that is wound through all segments in an S pattern and then continuing to the next digit while the stripe being upright on its side. Selecting *debug* gives a better idea how things fit together. - -Adding a diffuser on top or at the bottom of the segment holes will probably enhance the visuals. Just using paper may be enough. - -There is currently not a lot of space for electronics and this generator is still untested. Good luck! -""" - - ui_group = "Misc" - ui_group = "Unstable" - - def __init__(self): - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.argparser.add_argument( - "--height", action="store", type=float, default=100.0, - help="height of the front panel (with walls if outside is selected) in mm") - self.argparser.add_argument( - "--h", action="store", type=float, default=20.0, - help="depth (with walls if outside is selected) in mm") - self.buildArgParser(outside=False) - - def frontCB(self): - x = self.height - self.hole(1.27*x, 0.4*x, 0.05*x) - self.hole(1.27*x, 0.6*x, 0.05*x) - self.moveTo(0.1*x, 0.1*x) - for i in range(2): - for j in range(2): - self.seven_segments(.8 * x) - #self.seven_holes(.8 * x) - self.moveTo(.6 * x) - self.moveTo(0.1 * x) - - def backCB(self): - x = self.height - self.moveTo(0.1*x, 0.1*x) - for i in range(2): - for j in range(2): - self.seven_segment_holes(.8 * x) - self.moveTo(.6 * x) - self.moveTo(0.1 * x) - - - def render(self): - height, h = self.height, self.h - - if self.outside: - height = self.height = self.adjustSize(height) - h = self.h = self.adjustSize(h) - - t = self.thickness - y = (3*0.60 + 0.1 + 0.2) * height + 0.55 * 0.8 * height - - self.rectangularWall(height, h, "FFFF", move="right") - self.rectangularWall(y, h, "FfFf", move="up") - self.rectangularWall(y, h, "FfFf") - self.rectangularWall(height, h, "FFFF", move="left up") - - with self.saved_context(): - self.rectangularWall(y, height, "ffff", callback=[self.frontCB], move="right") - self.rectangularWall(y, height, "ffff", callback=[self.backCB], move="right") - self.rectangularWall(y, height, "ffff", move="up only") - self.seven_segment_separators(0.8*height, h, 4) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shadowbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shadowbox.py deleted file mode 100644 index e985c88..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shadowbox.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (C) 2024 Oliver Jensen -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Shadowbox(Boxes): - """The frame and spacers necessary to display a shadowbox / lightbox.""" - - description = """ -The frame needed to build a shadowbox from paper cutouts. -The cutout used in the photographs can be downloaded [here](https://3axis.co/laser-cut-my-neighbor-totoro-3d-lightbox-lamp-cdr-file/eoxldrxo/). - -See the diagram below for dimensions. - -![diagram](static/samples/Shadowbox-diagram.jpg) - -![backlit](static/samples/Shadowbox-backlit.jpg) -""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.DoveTailSettings, angle=10, depth=1.5, radius=0.1, size=1) - self.buildArgParser(x=200, y=260) - self.argparser.add_argument( - "--layers", action="store", type=int, default=7, - help="the number of paper layers; don't forget the back (blank) layer!") - self.argparser.add_argument( - "--framewidth", action="store", type=float, default=10, - help="the width of the paper layer frames") - self.argparser.add_argument( - "--frameheight", action="store", type=float, default=10, - help="the height of the paper layer frames") - self.argparser.add_argument( - "--extraheight", action="store", type=float, default=20, - help="cumulative height of your paper layers, play between frames, the LED strip, battery/wiring, anything else you want to fit in the case") - self.argparser.add_argument( - "--casejoinery", action="store", type=boolarg, default=True, - help="whether or not to join sides to front plate (disable if doing manual joins on fancy wood)") - - def render(self): - x, y = self.x, self.y - t = self.thickness - extraheight = self.extraheight - frameheight = self.frameheight - framewidth = self.framewidth - casejoinery = self.casejoinery - layers = self.layers - height = layers * t + extraheight - - # inner frames horizontal bars - for _ in range(2*layers): - self.polygonWall([ - x, 90, - frameheight, 90, - framewidth, 0, x - framewidth*2, 0, framewidth, 90, - frameheight, 90], - "eeDeDe", move="up") - - # inner frames vertical bars - for _ in range(2*layers): - self.rectangularWall(y - frameheight*2, framewidth, "eded", move="up") - - # faceplate - hypotenuse = math.sqrt((frameheight+t)**2 + (framewidth+t)**2) - angle = math.degrees(math.acos((framewidth+t) / hypotenuse)) - edgetypes = 'eFeeee' if casejoinery else 'eeeeee' - - vframe_poly = [ - t, 0, y, 0, t, 90+angle, - hypotenuse, 90-angle, - y - frameheight*2, 90-angle, - hypotenuse, 90+angle] - hframe_poly = [ - t, 0, x, 0, t, 90+angle, - hypotenuse, 90-angle, - x - framewidth*2, 90-angle, - hypotenuse, 90+angle] - - self.polygonWall(vframe_poly, edgetypes, move="up") - self.polygonWall(vframe_poly, edgetypes, move="up") - - angle = 90 - angle - self.polygonWall(hframe_poly, edgetypes, move="up") - self.polygonWall(hframe_poly, edgetypes, move="up") - - # case sides - if casejoinery: - top_edge = 'f' - else: - top_edge = 'e' - self.rectangularWall(x, height, f"ef{top_edge}f", move="up") - self.rectangularWall(x, height, f"ef{top_edge}f", move="up") - self.rectangularWall(y, height, f"eF{top_edge}F", move="up") - self.rectangularWall(y, height, f"eF{top_edge}F", move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shoe.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shoe.py deleted file mode 100644 index db79656..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shoe.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Shoe(Boxes): - """Shoe shaped box""" - - description = """Shoe shaped box with flat sides and rounded top. - Works best if flex if under slight compression. - Make sure that the following conditions are met: - y > tophole + r + fronttop; - height > frontheight.""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.FlexSettings) - - self.argparser.add_argument( - "--width", action="store", type=float, default=65, - help="width of the shoe") - self.argparser.add_argument( - "--length", action="store", type=float, default=175, - help="length front to back") - self.argparser.add_argument( - "--height", action="store", type=float, default=100, - help="height at the back of the shoe") - self.argparser.add_argument( - "--frontheight", action="store", type=float, default=35, - help="height at the front of the shoe") - self.argparser.add_argument( - "--fronttop", action="store", type=float, default=20, - help="length of the flat part at the front of the shoe") - self.argparser.add_argument( - "--tophole", action="store", type=float, default=75, - help="length of the opening at the top") - self.argparser.add_argument( - "--radius", action="store", type=float, default=30, - help="radius of the bend") - - - def render(self): - x, y, h = self.width, self.length, self.height - t = self.thickness - - hf = self.frontheight - yg = self.tophole - tf = self.fronttop - r=self.radius - - if (hf > h): - # Give an error because the result will be wrong with possible unconnected paths - raise ValueError("Height at front of shoe must be less than height at back of shoe.") - - stretch = (self.edges["X"].settings.stretch) - - self.ctx.save() - self.rectangularWall(y, x, "FFFF", move="up", label="Bottom") - lf,a=self.shoeside(y,h,hf,yg,tf,r, move="up", label="Side") - self.shoeside(y,h,hf,yg,tf,r, move="mirror up", label="Side") - self.ctx.restore() - self.rectangularWall(y, x, "FFFF", move="right only") - self.rectangularWall(x, h, "ffef", move="up", label="Back") - self.rectangularWall(x, hf, "ffff", move="up", label="front") - dr = a*(r-t)/stretch - self.shoelip(x, tf, dr, lf, label="top") - - - def shoelip(self, x, tf, dr, lf, move=None, label=""): - - w = self.edges["F"].spacing() - - th = tf + dr + lf + self.edges["F"].spacing() + self.edges["e"].spacing() - tw = x + 2*w - if self.move(tw, th, move, True, label=label): - return - - self.moveTo(self.edges["F"].spacing(), self.edges["e"].spacing()) - - self.edges["F"](x) - self.edgeCorner("F", "F") - self.edges["F"](tf) - self.edges["X"](dr, h=x+2*w) - self.edges["F"](lf) - self.edgeCorner("F", "e") - self.edges["e"](x) - self.edgeCorner("e", "F") - self.edges["F"](lf) - self.edges["E"](dr) - self.edges["F"](tf) - self.edgeCorner("F", "F") - - self.move(tw, th, move, label=label) - - def shoeside(self, y, h, hf, yg, tf, r, move=None, label=""): - import math - - tx = y + 2 * self.edges.get('F').spacing() - ty = h + self.edges.get('f').spacing() + self.edges.get("e").spacing() - - if self.move(tx, ty, move, before=True): - return - - lf = math.sqrt((h-hf)**2+(y-yg-tf)**2) - af = 90-math.degrees(math.atan((h-hf)/(y-yg-tf))) - - atemp = math.degrees(math.atan((h-hf-r)/(y-yg-tf))) - dtemp = math.sqrt((h-hf-r)**2+(y-yg-tf)**2) - lf = math.sqrt(dtemp**2-r**2) - af = 90-atemp-math.degrees(math.atan(r/lf)) - - self.moveTo(self.edges.get('f').margin(), self.edges.get("f").margin()) - - self.edges.get('f')(y) - self.edgeCorner(self.edges["f"],self.edges["F"],90) - self.edges.get('F')(hf) - self.edgeCorner(self.edges["F"],self.edges["f"],90) - self.edges.get('f')(tf) - self.corner(af-90,r) - self.edges.get('f')(lf) - self.edgeCorner(self.edges["f"],self.edges["e"],90-af) - self.edges.get('e')(yg) - self.edgeCorner(self.edges["e"],self.edges["F"],90) - self.edges.get('F')(h) - self.edgeCorner(self.edges["F"],self.edges["f"],90) - - self.move(tx, ty, move, label=label) - - return lf,math.radians(90-af) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shutterbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shutterbox.py deleted file mode 100644 index 55a9f00..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/shutterbox.py +++ /dev/null @@ -1,231 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class ShutterBox(Boxes): - """Box with a rolling shutter made of flex""" - - ui_group = "FlexBox" - - description = """Beware of the rolling shutter effect! Use wax on sliding surfaces. - -![Inside](static/samples/ShutterBox-3.jpg) - -![Detail](static/samples/ShutterBox-2.jpg) -""" - - def side(self, l, h, r, style, move=None): - t = self.thickness - - if self.move(l+2*t, h+2*t, move, True): - return - - self.moveTo(t, t) - - self.ctx.save() - - n = self.n - a = 90. / n - ls = 2*math.sin(math.radians(a/2)) * (r-2.5*t) - - #self.hole(l-r, r, r-2.5*t) - if style == "double": - #self.hole(r, r, r-2.5*t) - self.ctx.save() - self.fingerHolesAt(r, 2*t, l-2*r, 0) - self.moveTo(r, 2.5*t, 180 - a/2) - for i in range(n): - self.fingerHolesAt(0, 0.5*t, ls, 0) - self.moveTo(ls, 0, -a) - if h - 2*r > 2*t: - self.moveTo(0, 0, a/2) - self.fingerHolesAt(0, 0.5*t, h - 2*r, 0) - self.ctx.restore() - else: - self.fingerHolesAt(0, 2*t, l-r, 0) - self.moveTo(l-r, 2.5*t, a/2) - for i in range(n): - self.fingerHolesAt(0, -0.5*t, ls, 0) - self.moveTo(ls, 0, a) - if h - 2*r > 2*t: - self.moveTo(0, 0, -a/2) - self.fingerHolesAt(0, -0.5*t, h - 2*r, 0) - self.ctx.restore() - - self.edges["f"](l) - self.corner(90) - self.edges["f"](h-r) - self.polyline(0, -90, t, 90, 0, (90, r+t)) - if style == "single": - self.polyline(l-r, 90, t) - self.edges["f"](h) - else: - self.polyline(l-2*r, (90, r+t), 0, 90, t, -90) - self.edges["f"](h-r) - - self.move(l+2*t, h+2*t, move) - - def cornerRadius(self, r, two=False, move=None): - s = self.spacing - if self.move(r, r+s, move, True): - return - for i in range(2 if two else 1): - self.polyline(r, 90, r, 180, 0, (-90, r), 0 ,-180) - self.moveTo(r, r+s, 180) - self.move(r, r+s, move) - - def rails(self, l, r, move=None): - t = self.thickness - s = self.spacing - tw, th = l+2.5*t+3*s, r+1.5*t+3*s - - if self.move(tw, th, move, True): - return - - self.moveTo(2.5*t+s, 0) - self.polyline(l-r, (90, r+t), 0, 90, t, 90, 0, (-90, r), l-r, 90, t, 90) - self.moveTo(-t-s, t+s) - self.polyline(l-r, (90, r+t), 0, 90, t, 90, 0, (-90, r), l-r, 90, t, 90) - self.moveTo(0.5*t, t+s) - self.polyline(l-r, (90, r-1.5*t), 0, 90, t, 90, 0, (-90, r-2.5*t), l-r, 90, t, 90) - self.moveTo(-t-s, t+s) - self.polyline(l-r, (90, r-1.5*t), 0, 90, t, 90, 0, (-90, r-2.5*t), l-r, 90, t, 90) - - self.move(tw, th, move) - - def rails2(self, l, r, move=None): - t = self.thickness - s = self.spacing - tw, th = l+2.5*t+3*s, 2*r+t - - if self.move(tw, th, move, True): - return - - self.moveTo(r+t, 0) - for i in range(2): - self.polyline(l-2*r, (90, r+t), 0, 90, t, 90, 0, (-90, r), l-2*r, - (-90, r), 0, 90, t, 90, 0, (90, r+t)) - self.moveTo(0, 1.5*t) - self.polyline(l-2*r, (90, r-1.5*t), 0, 90, t, 90, 0, (-90, r-2.5*t), l-2*r, - (-90, r-2.5*t), 0, 90, t, 90, 0, (90, r-1.5*t)) - self.moveTo(0, r) - - self.move(tw, th, move) - - - def door(self, l, h, move=None): - t = self.thickness - if self.move(l, h, move, True): - return - self.fingerHolesAt(t, t, h-2*t) - self.edge(2*t) - self.edges["X"](l-2*t, h) - self.polyline(0, 90, h, 90, l, 90, h, 90) - self.move(l, h, move) - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=0.5) - self.addSettingsArgs(edges.FlexSettings, distance=.75, connection=2.) - - self.buildArgParser(x=150, y=100, h=100) - self.argparser.add_argument( - "--radius", action="store", type=float, default=40.0, - help="radius of the corners") - self.argparser.add_argument( - "--style", action="store", type=str, default="single", - choices=["single", "double"], - help="Number of rounded top corners") - - - def render(self): - x, y, h, r = self.x, self.y, self.h, self.radius - style = self.style - - self.n = n = 3 - - if not r: - self.radius = r = h / 2 - self.radius = r = min(r, h/2) - - t = self.thickness - self.ctx.save() - self.side(x, h, r, style, move="right") - self.side(x, h, r, style, move="right") - if style == "single": - self.rectangularWall(y, h, "fFEF", move="right") - else: - self.rectangularWall(y, h-r, "fFeF", move="right") - self.rectangularWall(y, h-r, "fFeF", move="right") - - if style == "double": - self.cornerRadius(r, two=True, move="right") - - self.cornerRadius(r, two=True, move="right") - if style == "single": - self.rails(x, r, move="right") - else: - self.rails2(x, r, move="right") - - self.ctx.restore() - self.side(x, h, r, style, move="up only") - - self.rectangularWall(x, y, "FFFF", move="right") - - if style == "single": - self.door(x-r+0.5*math.pi*r + 3*t, y-0.2*t, move="right") - else: - self.door(x-2*r+math.pi*r + 3*t, y-0.2*t, move="right") - - self.rectangularWall(2*t, y-2.2*t, edges="eeef", move="right") - - - a = 90. / n - ls = 2*math.sin(math.radians(a/2)) * (r-2.5*t) - - edges.FingerJointSettings(t, angle=a).edgeObjects(self, chars="aA") - edges.FingerJointSettings(t, angle=a/2).edgeObjects(self, chars="bB") - - - if style == "double": - if h - 2*r > 2*t: - self.rectangularWall(h - 2*r, y, "fBfe", move="right") - self.rectangularWall(ls, y, "fAfb", move="right") - else: - self.rectangularWall(ls, y, "fAfe", move="right") - - for i in range(n-2): - self.rectangularWall(ls, y, "fAfa", move="right") - - self.rectangularWall(ls, y, "fBfa", move="right") - - self.rectangularWall(x-2*r, y, "fbfb", move="right") - else: - self.rectangularWall(x-r, y, "fbfe", move="right") - - self.rectangularWall(ls, y, "fafB", move="right") - - for i in range(n-2): - self.rectangularWall(ls, y, "fafA", move="right") - - - if h - 2*r > 2*t: - self.rectangularWall(ls, y, "fbfA", move="right") - self.rectangularWall(h - 2*r, y, "fefB", move="right") - else: - self.rectangularWall(ls, y, "fefA", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sidedoorhousing.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sidedoorhousing.py deleted file mode 100644 index 1cbc666..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/sidedoorhousing.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (C) 2013-2020 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.generators.console2 import Console2 - - -class SideDoorHousing(Console2): - """Box with service hatches on either one or both of the sides that are locked with latches""" - - ui_group = "Box" - - description = """ -This box is designed as a housing for electronic projects but could be used for other purposes. It has hatches that can be re-opened with simple tools. If built from thin enough material, it intentionally cannot be opened with bare hands. - -The hatches are on the x sides. - -#### Assembly instructions -The main body is easy to assemble: -1. Starting with the floor and then add the four walls (for any removable sides, the wall will just be a small part on the base ) -2. Add the top piece - -For the removable walls: -1. Add the lips to the removable walls -2. Sit the latches in place (it is importand to make sure the springs on the latches point inwards and the angled ends point to the side walls. See image below) -3. Glue the U-shaped clamps in place (it is important **not** to glue the latches) - -![Wall details](static/samples/SideDoorHousing.jpg) - - -#### Re-Opening - -The latches lock in place when closed. To open them they need to be pressed in and can then be moved aside. - -![Closed Box](static/samples/SideDoorHousing-2.jpg) - -""" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=.5) - self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(x=100, y=100, h=100, bottom_edge="s") - self.argparser.add_argument( - "--double_door", action="store", type=boolarg, default=True, - help="allow removing the backwall, too") - - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - bottom = self.edges.get(self.bottom_edge) - - self.latchpos = latchpos = 3*t - - - self.rectangularWall(x, y, "ffff", move="right") # floor - if self.double_door: # top - self.rectangularWall(x, y, "EFEF", move="right") - else: - self.rectangularWall(x, y, "EFFF", move="right") - - for move in ("right", "mirror right"): - re = edges.CompoundEdge(self, ("f", "e"), - (bottom.endwidth()+t, h-t)) - if self.double_door: - le = edges.CompoundEdge(self, ("e", "f"), - (h-t, bottom.endwidth()+t)) - else: - le = "f" - self.rectangularWall( # side - y, h, (bottom, re, "f", le), ignore_widths=[1, 6], - callback=[ - None, None, lambda: - (self.rectangularHole(1.55*t, latchpos, 1.1*t, 1.1*t), - self.double_door and - self.rectangularHole(y-1.55*t, latchpos, 1.1*t, 1.1*t))], - move=move) - - - for i in range(2 if self.double_door else 1): - self.rectangularWall(x, t, (bottom, "F", "e", "F"), - ignore_widths=[1, 6], move="up") - self.rectangularWall( # back wall - x, h-1.1*t, "eEeE", - callback=[ - lambda: self.fingerHolesAt(.5*t, 0, h-4.05*t-latchpos), - lambda:self.latch_hole(h-1.2*t-latchpos), - lambda: self.fingerHolesAt(.5*t, 3.05*t+latchpos, h-4.05*t-latchpos), - lambda:self.latch_hole(latchpos)], - move="right") - self.rectangularWall(x, t, (bottom, "F", "e", "F"), - ignore_widths=[1, 6], move="down only") - if not self.double_door: - self.rectangularWall(x, h, (bottom, "F", "f", "F"), - ignore_widths=[1, 6], move="right") - - # hardware for back wall - if self.double_door: - latches = 4 - else: - latches = 2 - - self.partsMatrix(latches, 0, "right", - self.rectangularWall, 2*t, h-4.05*t-latchpos, "EeEf") - self.partsMatrix(latches, 2, "up", self.latch) - self.partsMatrix(2*latches, 2, "up", self.latch_clamp) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/silverwarebox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/silverwarebox.py deleted file mode 100644 index 32287c2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/silverwarebox.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import Boxes, restore - - -class Silverware(Boxes): - """ - Cuttlery stand with carrying grip - using flex for rounded corners - """ - - ui_group = "Unstable" - - - def __init__(self) -> None: - Boxes.__init__(self) - - self.buildArgParser(x=250, y=154, h=120) - - self.argparser.add_argument( - "--cornerradius", action="store", type=int, default=30, - help="Radius of the corners") - self.argparser.add_argument( - "--handleheight", action="store", type=int, default=150, - help="Height of the handle") - self.argparser.add_argument( - "--handlewidth", action="store", type=int, default=120, - help="Width of the handle") - - - #################################################################### - ### Parts - #################################################################### - - def basePlate(self, x, y, r): - self.roundedPlate(x, y, r, extend_corners=False, callback=[ - lambda: self.fingerHolesAt(x / 3.0 - r, 0, 0.5 * (y - self.thickness)), - lambda: self.fingerHolesAt(x / 6.0, 0, 0.5 * (y - self.thickness)), - lambda: self.fingerHolesAt(y / 2.0 - r, 0, x), - lambda: self.fingerHolesAt(x / 2.0 - r, 0, 0.5 * (y - self.thickness)) - ]) - - def wall(self, x=100, y=100, h=100, r=0): - self.surroundingWall(x, y, r, h, top="E", bottom='h', callback={ - 0: lambda: self.fingerHolesAt(x / 6.0, 0, h - 10), - 4: lambda: self.fingerHolesAt(x / 3.0 - r, 0, h - 10), - 1: lambda: self.fingerHolesAt(y / 2.0 - r, 0, h - 10), - 3: lambda: self.fingerHolesAt(y / 2.0 - r, 0, h - 10), - 2: lambda: self.fingerHolesAt(x / 2.0 - r, 0, h - 10), - }, - move="up") - - @restore - def centerWall(self, x, h): - self.moveTo(self.edges["f"].spacing(), self.edges["f"].spacing()) - for i in range(2, 5): - self.fingerHolesAt(i * x / 6.0, 0, h - 10) - - self.edges["f"](x) - self.corner(90) - self.edges["f"](h - 10) - self.corner(90) - - self.handle(x, self.handleheight, self.handlewidth) - - self.corner(90) - self.edges["f"](h - 10) - self.corner(90) - self.ctx.stroke() - - ################################################## - ### main - ################################################## - - def render(self): - x = self.x - y = self.y - h = self.h - r = self.cornerradius - - t = self.thickness - b = self.burn - - self.wall(x, y, h, r) - self.centerWall(x, h) - self.moveTo(x + 2 * self.edges["f"].spacing()) - - l = (y - t) / 2.0 - - for _ in range(3): - self.rectangularWall(l, h - 10, edges="ffef", move="right") - - self.moveTo(-3.0 * (l + 2 * t + 8 * b), h - 10 + 2 * t + 8 * b) - self.basePlate(x, y, r) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/skadis.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/skadis.py deleted file mode 100644 index 593dc89..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/skadis.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class SkadisBoard(Boxes): - """Customizable Ikea like pegboard""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.argparser.add_argument( - "--columns", action="store", type=int, default=17, - help="Number of holes left to right counting both even and odd rows") - self.argparser.add_argument( - "--rows", action="store", type=int, default=27, - help="Number of rows of holes top to bottom") - - - def CB(self): - for r in range(self.rows): - for c in range(self.columns): - if (r+c) % 2 == 0: - continue - self.rectangularHole((c+1)*20 - 8, (r+1)*20, 5, 15, r=2.5) - - def render(self): - self.roundedPlate((self.columns+1) * 20, (self.rows+1)*20, edge="e", r=8, - extend_corners=False, callback=[self.CB]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/slantedtray.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/slantedtray.py deleted file mode 100644 index 2aee928..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/slantedtray.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (C) 2013-2023 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from functools import partial - -from boxes import * - - -class SlantedTray(Boxes): - """One row tray with high back wall and low front wall""" - - ui_group = "Tray" - - description = """Can be used as a display or for cards or gaming tokens. Lay on the side to get piles to draw from. - ![Example Use](static/samples/SlantedTray-2.jpg)""" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - # self.addSettingsArgs(edges.StackableSettings) - - self.buildArgParser(sx="40*3", y=40.0, h=40.0, outside=False) - self.argparser.add_argument( - "--front_height", action="store", type=float, default=0.3, - help="height of the front as fraction of the total height") - - def finger_holes_CB(self, sx, h): - t = self.thickness - pos = -0.5 * t - for x in sx[:-1]: - pos += x + t - self.fingerHolesAt(pos, 0, h) - - def render(self): - # adjust to the variables you want in the local scope - sx, y, h = self.sx, self.y, self.h - t = self.thickness - - if self.outside: - self.sx = sx = self.adjustSize(sx) - self.y = y = self.adjustSize(y) - self.h = h = self.adjustSize(h, False) - - front_height = h * self.front_height - x = sum(sx) + t * (len(sx) - 1) - - self.rectangularWall( - x, - h, - "eFfF", - move="up", - callback=[partial(self.finger_holes_CB, sx, h)], - ) - - self.rectangularWall( - x, - y, - "FFfF", - move="up", - callback=[partial(self.finger_holes_CB, sx, y)], - ) - - self.rectangularWall( - x, - front_height, - "FFeF", - move="up", - callback=[ - partial(self.finger_holes_CB, sx, front_height) - ], - ) - - for _ in range(len(sx) + 1): - self.trapezoidWall(y, h, front_height, "ffef", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/slidingdrawer.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/slidingdrawer.py deleted file mode 100644 index 559e667..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/slidingdrawer.py +++ /dev/null @@ -1,50 +0,0 @@ -from boxes import * - - -class SlidingDrawer(Boxes): - """Sliding drawer box""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser(x=60, y=100, h=30, outside='true') - self.addSettingsArgs(edges.FingerJointSettings, finger=2.0, space=2.0) - self.addSettingsArgs(edges.GroovedSettings, width=0.4) - - self.argparser.add_argument( - "--play", action="store", type=float, default=0.15, - help="play between the two parts as multiple of the wall thickness") - - def render(self): - - x, y, h = self.x, self.y, self.h - x = self.adjustSize(x) - y = self.adjustSize(y) - h = self.adjustSize(h) - - t = self.thickness - p = self.play * t - - y = y + t - if not self.outside: - x = x + 4*t+ 2*p - y = y + 3*t+ 2*p - h = h + 3*t+ 2*p - - x2 = x - (2*t + 2*p) - y2 = y - (2*t + 2*p) - h2 = h - (t + 2*p) - - self.rectangularWall(x2, h2, "FFzF", label="in box wall", move="right") - self.rectangularWall(y2, h2, "ffef", label="in box wall", move="up") - self.rectangularWall(y2, h2, "ffef", label="in box wall") - self.rectangularWall(x2, h2, "FFeF", label="in box wall", move="left up") - self.rectangularWall(y2, x2, "FfFf", label="in box bottom", move="up") - - self.rectangularWall(y, x, "FFFe", label="out box bottom", move="right") - self.rectangularWall(y, x, "FFFe", label="out box top", move="up") - self.rectangularWall(y, h, "fffe", label="out box wall") - self.rectangularWall(y, h, "fffe", label="out box wall", move="up left") - - self.rectangularWall(x, h, "fFfF", label="out box wall") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/smallpartstray.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/smallpartstray.py deleted file mode 100644 index bca0fa6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/smallpartstray.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import lids -from boxes.edges import CompoundEdge - - -class SmallPartsTray(Boxes): - """Tray with slants to easier get out game tokens or screws""" - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - # self.addSettingsArgs(edges.StackableSettings) - self.addSettingsArgs(lids.LidSettings) - - self.buildArgParser(sx="50*3", y=100, h=30, outside=True) - self.argparser.add_argument( - "--angle", action="store", type=float, default=45., - help="angle of the ramps") - self.argparser.add_argument( - "--rampheight", action="store", type=float, default=.5, - help="height of the ramps relative to to total height") - self.argparser.add_argument( - "--two_sided", action="store", type=boolarg, default=True, - help="have ramps on both sides. Enables sliding dividers") - self.argparser.add_argument( - "--front_panel", action="store", type=boolarg, default=True, - help="have a vertical wall at the ramp") - - - def innerWall(self, h, y, ramp_h, ramp_y, two_ramps, front=True, - move=None): - a = math.degrees(math.atan(ramp_h/ramp_y)) - l = (ramp_h**2 + ramp_y**2)**.5 - if two_ramps: - self.polygonWall( - [y-2*ramp_y, a, l, 90-a, h-ramp_h, 90, y, - 90, h-ramp_h, 90-a, l, a], - "fffeff" if front else "ffeeef", move=move) - else: - self.polygonWall( - [y-ramp_y, 90, h, 90, y, 90, h-ramp_h, 90-a, l, a], - "ffeff" if front else "ffeef", move=move) - - def outerWall(self, h, y, ramp_h, ramp_y, two_ramps, front=True, - move=None): - a = math.degrees(math.atan(ramp_h/ramp_y)) - l = (ramp_h**2 + ramp_y**2)**.5 - t = self.thickness - - def cb(): - with self.saved_context(): - self.moveTo(ramp_y, 0, 180-a) - self.fingerHolesAt(0, 0.5*t, l, 0) - if two_ramps: - self.moveTo(y-ramp_y, 0, a) - self.fingerHolesAt(0, -0.5*t, l, 0) - - if two_ramps: - self.rectangularWall( - y, h, - [CompoundEdge(self, "EFE", (ramp_y, y-2*ramp_y, ramp_y)), - CompoundEdge(self, "EF", (ramp_h, h-ramp_h)) if front else "e", - "e", - CompoundEdge(self, "FE", (h-ramp_h, ramp_h)) if front else "e"], - callback=[cb], move=move) - else: - self.rectangularWall( - y, h, [ - CompoundEdge(self, "EF", (ramp_y, y-ramp_y)) if front else "e", - "F", - "e", - CompoundEdge(self, "FE", (h-ramp_h, ramp_h))], - callback=[cb], move=move) - - - def holeCB(self, sections, height): - def CB(): - pos = -0.5 * self.thickness - for l in sections[:-1]: - pos += l + self.thickness - self.fingerHolesAt(pos, 0, height) - return CB - - def render_simple_tray_divider(self, width, height, move): - """ - Simple movable divider. A wall with small feet for a little more stability. - """ - - if self.move(width, height, move, True): - return - - t = self.thickness - self.moveTo(t) - self.polyline( - width - 2 * t, - 90, - t, - -90, - t, - 90, - height - t, - 90, - width, - 90, - height - t, - 90, - t, - -90, - t, - 90, - ) - - self.move(width, height, move) - - def render_simple_tray_divider_feet(self, move=None): - sqr2 = math.sqrt(2) - t = self.thickness - divider_foot_width = 2 * t - full_width = t + 2 * divider_foot_width - move_length = full_width / sqr2 + 2 * self.burn - move_width = full_width / sqr2 + 2 * self.burn - - if self.move(move_width, move_length, move, True): - return - - self.moveTo(self.burn) - self.ctx.save() - self.polyline( - sqr2 * divider_foot_width, - 135, - t, - -90, - t, - -90, - t, - 135, - sqr2 * divider_foot_width, - 135, - full_width, - 135, - ) - self.ctx.restore() - - self.moveTo(-self.burn / sqr2, self.burn * (1 + 1 / sqr2), 45) - self.moveTo(full_width) - - self.polyline( - 0, - 135, - sqr2 * divider_foot_width, - 135, - t, - -90, - t, - -90, - t, - 135, - sqr2 * divider_foot_width, - 135, - ) - - self.move(move_width, move_length, move) - - - def render(self): - # adjust to the variables you want in the local scope - sx, y, h = self.sx, self.y, self.h - t = self.thickness - a = self.angle - b = "e" - - if self.outside: - self.sx = sx = self.adjustSize(sx) - self.h = h = self.adjustSize(h, False) - dy = t if self.front_panel else t / 2**0.5 - self.y = y = self.adjustSize(y, dy, dy) - - x = sum(sx) + (len(sx)-1) * t - - ramp_h = h * self.rampheight - ramp_y = ramp_h / math.tan(math.radians(a)) - - if self.two_sided and (2*ramp_y + 3*t > y): - ramp_y = (y - 3*t) / 2 - ramp_h = ramp_y * math.tan(math.radians(a)) - elif ramp_y > y - t: - ramp_y = y - t - ramp_h = ramp_y * math.tan(math.radians(a)) - - ramp_l = (ramp_h**2 + ramp_y**2)**.5 - - with self.saved_context(): - self.outerWall(h, y, ramp_h, ramp_y, - self.two_sided, self.front_panel, move="up") - self.outerWall(h, y, ramp_h, ramp_y, - self.two_sided, self.front_panel, move="mirror up") - for i in range(len(sx)-1): - self.innerWall(h, y, ramp_h, ramp_y, - self.two_sided, self.front_panel, move="up") - self.innerWall(h, y, ramp_h, ramp_y, - self.two_sided, self.front_panel, move="right only") - - if self.front_panel: - self.rectangularWall( - x, h-ramp_h, "efef", - callback=[self.holeCB(sx, h-ramp_h)], move="up") - self.rectangularWall(x, ramp_l, "efef", - callback=[self.holeCB(sx, ramp_l)], move="up") - if self.two_sided: - self.rectangularWall( - x, y-2*ramp_y, "efef", - callback=[self.holeCB(sx, y-2*ramp_y)], move="up") - self.rectangularWall( - x, ramp_l, "efef", - callback=[self.holeCB(sx, ramp_l)], move="up") - if self.front_panel: - self.rectangularWall( - x, h-ramp_h, "efef", - callback=[self.holeCB(sx, h-ramp_h)], move="up") - else: - self.rectangularWall( - x, y-ramp_y, "efff", - callback=[self.holeCB(sx, y-ramp_y)], move="up") - self.rectangularWall( - x, h, "Ffef", - callback=[self.holeCB(sx, h)], move="up") - - - if self.two_sided: - with self.saved_context(): - for l in self.sx: - self.render_simple_tray_divider(l, h, move="right") - - self.partsMatrix(len(self.sx), 0, "right", self.render_simple_tray_divider_feet) - self.render_simple_tray_divider(l, h, move="up only") - - self.lid(x, y) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/smallpartstray2.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/smallpartstray2.py deleted file mode 100644 index ed767fa..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/smallpartstray2.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright (C) 2013-2023 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.lids import LidSettings, _TopEdge - - -class TopEdge(edges.BaseEdge): - - def __init__(self, boxes, lengths, h): - super().__init__(boxes, None) - self.lengths = lengths - self.h = h - - def __call__(self, length, **kw): - h = self.h - t = self.boxes.thickness - t2 = t * 2**.5 - slot = h/2**.5 + t/2 - self.polyline( - 0, 90, t2, -45, - slot-t, -90, t, -90, slot, 135, - self.lengths[0] - t2/2) - - for l in self.lengths[1:]: - self.polyline( - 0, 45, t, 45, h/2-t2/2, -90, t, -90, h/2-t2, 135, - slot-t, -90, t, -90, slot, 135, - l - t2/2 - ) - self.polyline(t2/2) - -class SmallPartsTray2(_TopEdge): - """A Type Tray variant with slopes toward the front""" - - description = """Assemble inside out. If there are inner front to back walls start with attaching the floor boards to them. Then add the vertical inner left to right walls. After sliding in the slopes attach the outer wall to fix everything in place. - -If there are no inner front to back walls just add everything to one side wall and then add the other one after that. Possibly saving the front and back as last step.""" - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addTopEdgeSettings(fingerjoint={"surroundingspaces": 1.0}, - roundedtriangle={"outset" : 1}) - self.addSettingsArgs(LidSettings) - self.buildArgParser("sx", "sy", "hi", "outside", h=30) - # "bottom_edge", "top_edge") - self.argparser.add_argument( - "--back_height", action="store", type=float, default=0.0, - help="additional height of the back wall - e top edge only") - self.argparser.add_argument( - "--radius", action="store", type=float, default=0.0, - help="radius for strengthening side walls with back_height") - self.argparser.add_argument( - "--handle", type=boolarg, default=False, help="add handle to the bottom (changes bottom edge in the front)", - ) - - def fingerHolesCB(self, sections, height): - - def CB(): - posx = -0.5 * self.thickness - for x in sections[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, height) - return CB - - - def fingerHoleLineCB(self, posx, posy, sections): - def CB(): - self.moveTo(posx, posy, 90) - for l in sections: - self.fingerHolesAt(0, 0, l, 0) - self.moveTo(l+self.thickness) - return CB - - - def xHoles(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, self.hi) - - def yHoles(self): - t = self.thickness - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.hi-t*2**.5) - with self.saved_context(): - self.moveTo(posy-0.5*t, self.hi, 135) - self.fingerHolesAt(-0.5*t, 0, self.hi*2**.5+t/2) - - self.moveTo(posy+self.sy[-1]+0.5*t, self.hi, 135) - self.fingerHolesAt(-0.5*t, 0, self.hi*2**.5+t/2) - - def render(self): - - # tmp settings - self.top_edge = "e" - self.bottom_edge = "F" - - if self.outside: - self.sx = self.adjustSize(self.sx) - self.sy = self.adjustSize(self.sy) - self.h = self.adjustSize(self.h, e2=False) - if self.hi: - self.hi = self.adjustSize(self.hi, e2=False) - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - y = sum(self.sy) + self.thickness * (len(self.sy) - 1) - h = self.h - sameh = not self.hi - hi = self.hi = self.hi or h - t = self.thickness - - # outer walls - b = self.bottom_edge - tl, tb, tr, tf = self.topEdges(self.top_edge) - self.closedtop = self.top_edge in "fFhŠ" - - bh = self.back_height if self.top_edge == "e" else 0.0 - - # x sides - - self.ctx.save() - - # outer walls - front/back - if bh: - self.rectangularWall(x, h+bh, [b, "f", tb, "f"], - callback=[self.xHoles], - #ignore_widths=[], - move="up", label="back") - self.rectangularWall(x, h, ["f" if self.handle else b, "f", "e", "f"], - callback=[self.fingerHolesCB(self.sx[::-1], h),], - move="up", label="front") - else: - self.rectangularWall(x, h, [b, "F", tb, "F"], - callback=[self.xHoles], - #ignore_widths=[1, 6], - move="up", label="back") - self.rectangularWall(x, hi-t*2**.5, ["f" if self.handle else b, "F", "e", "F"], - callback=[self.fingerHolesCB(self.sx[::-1], hi-t*2**.5),], - #ignore_widths=[] if self.handle else [1, 6], - move="up", label="front") - - - # floor boards - - t2 = t * 2**.5 - dy = hi + t2/2 - slot = t + t2/2 # 1.5*t - floors = [self.sy[0]- hi - slot + t2, slot] - self.rectangularWall( - x, floors[0], "ffef", - callback=[self.fingerHolesCB(self.sx, self.sy[0]-dy)], - move="up", label="floor back side") - for y_ in self.sy[1:]: - self.rectangularWall( - x, y_ - slot + t, "efef", - callback=[self.fingerHolesCB(self.sx, y_ - slot + t), - self.fingerHoleLineCB(hi-t2+t/2, 0, self.sx[::-1])], - move="up", label="floor") - floors.extend([y_ - slot + t, slot]) - self.rectangularWall( - x, hi-t2, "efYf" if self.handle else "efff", - callback=[self.fingerHolesCB(self.sx, hi-t2)], - move="up", label="floor front side") - floors.append(hi-t2) - - # Inner walls - - be = "f" if b != "e" else "e" - - for i in range(len(self.sy) - 1): - e = [edges.SlottedEdge(self, self.sx, be, slots=0.5 * hi), "f", - edges.SlottedEdge(self, self.sx[::-1], "e"), "f"] - self.rectangularWall(x, hi-t2, e, move="up", label=f"inner x {i+1}") - # slopes - for i in self.sy: - self.rectangularWall( - x, hi*2**.5 + t/2, - [edges.SlottedEdge(self, self.sx, "e", slots=hi/2**.5), "f", - edges.SlottedEdge(self, self.sx[::-1], "e"), "f"], - move="up", label="slope") - - # top / lid - self.drawLid(x, y, self.top_edge) # XXX deal with front - self.lid(x, y, self.top_edge) - - self.ctx.restore() - self.rectangularWall(x, hi, "ffff", move="right only") - - # y walls - - # outer walls - left/right - - for move in ("up", "up mirror"): - if bh: - self.trapezoidSideWall( - y, h+bh, hi-t*2**.5, - [edges.CompoundEdge(self, ("FE"*len(self.sy))+"F", floors), - "h", "e", "h"], - radius=self.radius, callback=[self.yHoles, ], - move=move, label="side") - else: - self.rectangularWall( - y, h, - [edges.CompoundEdge(self, ("FE"*len(self.sy))+"F", floors), - edges.CompoundEdge(self, "fE", (hi-t*2**.5, h-hi+t*2**.5)), - tl, "f"], - callback=[self.yHoles, ], - #ignore_widths=[6] if self.handle else [1, 6], - move=move, label="side") - - # inner walls - for i in range(len(self.sx) - 1): - e = [edges.CompoundEdge(self, ("fE"*len(self.sy))+"f", floors), - edges.CompoundEdge(self, "fe", (hi-t*2**.5, t*2**.5)), - TopEdge(self, self.sy[::-1], hi), "f"] - self.rectangularWall(y, hi, e, move="up", label=f"inner y {i+1}") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/spicesrack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/spicesrack.py deleted file mode 100644 index f954e54..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/spicesrack.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class FrontEdge(edges.Edge): - - def __call__(self, length, **kw): - with self.saved_context(): - a = 90 - r = (self.diameter +self.space) / 2 - self.ctx.scale(1, self.edge_width/r) - for i in range(self.numx): - self.corner(-a) - self.corner(180, r) - self.corner(-a) - self.moveTo(length) - - def margin(self) -> float: - return self.edge_width - -class SpicesRack(Boxes): - """Rack for cans of spices""" - - ui_group = "Shelf" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1.0) - - self.argparser.add_argument( - "--diameter", action="store", type=float, default=55., - help="diameter of spice cans") - - self.argparser.add_argument( - "--height", action="store", type=float, default=60., - help="height of the cans that needs to be supported") - self.argparser.add_argument( - "--space", action="store", type=float, default=10., - help="space between cans") - self.argparser.add_argument( - "--numx", action="store", type=int, default=5, - help="number of cans in a row") - self.argparser.add_argument( - "--numy", action="store", type=int, default=6, - help="number of cans in a column") - self.argparser.add_argument( - "--in_place_supports", action="store", type=boolarg, default=False, - help="place supports pieces in holes (check for fit yourself)") - self.argparser.add_argument( - "--feet", action="store", type=boolarg, default=False, - help="add feet so the rack can stand on the ground") - - - def support(self, width, height, move=None): - t = self.thickness - tw = width + t - th = height - - r = min(width - 2*t, height - 2*t) - - if self.move(tw, th, move, True): - return - - self.polyline(width-r, 90, 0, (-90, r), 0, 90, height-r, 90, width, 90) - self.edges["f"](height) - - self.move(tw, th, move) - - def foot(self, width, height, move=None): - t = self.thickness - tw, th = height, width + t - - if self.move(tw, th, move, True): - return - - self.moveTo(0, t) - self.edges["f"](height) - self.polyline(0, 90, width, 90, 0, (90, height), width-height, 90) - - self.move(tw, th, move) - - def holes(self): - w = 2* self.base_r - r = self.diameter / 2 - a = self.base_angle - l = self.hole_length - self.moveTo(0, self.hole_distance) - - with self.saved_context(): - self.ctx.scale(1, l/self.base_h) - self.moveTo(self.space/2, 0, 90) - for i in range(self.numx): - self.polyline(0, -a, 0, (-180+2*a, r), 0, -90-a, w, -90) - self.moveTo(0, -(self.diameter+self.space)) - self.ctx.stroke() - if self.feet and not self.feet_done: - self.feet_done = True - return - - if not self.in_place_supports: - return - inner_width = self.hole_distance + self.hole_length/3 - t = self.thickness - for i in range(self.numx-1): - with self.saved_context(): - self.moveTo((self.diameter+self.space)*(i+0.5)- (inner_width+t)/2, self.spacing) - self.support(inner_width, (self.h-t)/2) - - def backCB(self): - t = self.thickness - dy = self.h/2 - t/2 - for i in range(self.numy): - self.fingerHolesAt(0, (i+1)*self.h-0.5*self.thickness-dy, self.x, 0) - for j in range(1, self.numx): - self.fingerHolesAt( - j*(self.diameter+self.space), - (i+1)*self.h-t-dy, (self.h-t)/2, -90) - - def render(self): - self.feet_done = False - t = self.thickness - self.x = x = self.numx * (self.diameter+self.space) - d = self.diameter - - self.base_angle = 10 - self.base_r = self.diameter/2 * math.cos(math.radians(self.base_angle)) - self.base_h = self.diameter/2 * (1-math.sin(math.radians(self.base_angle))) - self.angle = math.degrees(math.atan(self.base_r/self.height)) - self.hole_length = (self.base_h**2+self.height**2)**0.5 - self.hole_distance = (self.diameter-self.base_r) * math.sin(math.radians(self.angle)) - - self.h = (self.space + d) / math.cos(math.radians(self.angle)) - h = self.numy * self.h - self.h / 2 + 6*t - - width = self.hole_distance + self.hole_length + self.space/2 - inner_width = self.hole_distance + self.hole_length/3 - - self.edge_width = width - inner_width - - for i in range(self.numy): - self.rectangularWall(x, inner_width,[ - "f", "e", FrontEdge(self, self), "e"], - callback=[self.holes], move="up") - - self.rectangularWall(x, h, - callback=[self.backCB, - None, - lambda:self.hole(3*t, 3*t, 1.5), - lambda:self.hole(3*t, 3*t, 1.5), - ], move="up") - - - if not self.in_place_supports: - self.partsMatrix((self.numx-1)*self.numy, self.numx-1, "up", - self.support, inner_width, (self.h-t)/2) - if self.feet: - self.partsMatrix(self.numx-1, self.numx-1, "up", - self.foot, width, (self.h-t)/2) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/spool.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/spool.py deleted file mode 100644 index 52f22ae..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/spool.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Spool(Boxes): - """A simple spool""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - self.buildArgParser(h=100) - self.argparser.add_argument( - "--outer_diameter", action="store", type=float, default=200.0, - help="diameter of the flanges") - self.argparser.add_argument( - "--inner_diameter", action="store", type=float, default=80.0, - help="diameter of the center part") - self.argparser.add_argument( - "--axle_diameter", action="store", type=float, default=40.0, - help="diameter of the axle hole (axle not part of drawing)") - self.argparser.add_argument( - "--sides", action="store", type=int, default=8, - help="number of pieces for the center part") - self.argparser.add_argument( - "--reinforcements", action="store", type=int, default=8, - help="number of reinforcement ribs per side") - self.argparser.add_argument( - "--reinforcement_height", action="store", type=float, default=0.0, - help="height of reinforcement ribs on the flanges") - - def sideCB(self): - self.hole(0, 0, d=self.axle_diameter) - r, h, side = self.regularPolygon(self.sides, radius=self.inner_diameter/2) - t = self.thickness - for i in range(self.sides): - self.fingerHolesAt(-side/2, h+0.5*self.thickness, side, 0) - self.moveTo(0, 0, 360 / self.sides) - - if self.reinforcement_height: - for i in range(self.reinforcements): - self.fingerHolesAt( - self.axle_diameter / 2, 0, h-self.axle_diameter / 2, 0) - self.fingerHolesAt( - r + t, 0, self.outer_diameter / 2 - r - t, 0) - self.moveTo(0, 0, 360 / self.reinforcements) - - def reinforcementCB(self): - for i in range(self.reinforcements): - self.fingerHolesAt( - self.axle_diameter / 2, 0, - (self.inner_diameter - self.axle_diameter) / 2 + self.thickness, 0) - self.moveTo(0, 0, 360 / self.reinforcements) - - - def render(self): - t = self.thickness - r, h, side = self.regularPolygon(self.sides, radius=self.inner_diameter/2) - for i in range(2): - self.parts.disc( - self.outer_diameter, callback=self.sideCB, move="right") - for i in range(self.sides): - self.rectangularWall(side, self.h, "fefe", move="right") - if self.reinforcement_height: - for i in range(self.reinforcements*2): - edge = edges.CompoundEdge( - self, "fef", - [self.outer_diameter / 2 - r - t, - r - h + t, - h - self.axle_diameter / 2]) - self.trapezoidWall( - self.reinforcement_height - t, - (self.outer_diameter - self.axle_diameter) / 2, - (self.inner_diameter - self.axle_diameter) / 2 + t, - ["e", "f", "e", edge], - move="right") - for i in range(2): - self.parts.disc( - self.inner_diameter + 2*t, - hole=self.axle_diameter, - callback=self.reinforcementCB, - move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/stachel.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/stachel.py deleted file mode 100644 index cb3538b..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/stachel.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Stachel(Boxes): - """Bass Recorder Endpin""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.argparser.add_argument( - "--flutediameter", action="store", type=float, default=115.0, - help="diameter of the flutes bottom in mm") - self.argparser.add_argument( - "--polediameter", action="store", type=float, default=25., - help="diameter if the pin in mm") - self.argparser.add_argument( - "--wall", action="store", type=float, default=7., - help="width of the surrounding wall in mm") - - def layer(self, ri, ro, rp, holes=False, move=""): - - r = 2.5 # radius - l = 25 # depth of clamp - w = 20 # width of clamp - - wp = rp+8 # width pole - - tw = 2*ro + 2*rp - th = 2*ro + l - - if self.move(tw, th, move, True): - return - - self.moveTo(ro, r, 90) - - a1 = math.degrees(math.asin(w / ro)) - a2 = math.degrees(math.asin(wp / ro)) - l1 = ro*(1-math.cos(math.radians(a1))) - a3 = math.degrees(math.asin(1./rp)) - self.polyline(ro-ri+l-r, 90, 0, (-355, ri), 0, 90, ro-ri+l-r, # inside - (90, r), w-2*r, (90, r)) - if holes: # right side main clamp - poly1 = [(l+l1-2)/2-r, 90, w-2, -90, 2, -90, w-2, 90, - (l+l1-2)/2] - self.polyline(*poly1) - else: - self.polyline(l+l1-r) - self.polyline(0, -90+a1, 0 , (90-a1-a2, ro), 0, -90+a2) - if holes: - poly2 = [2*rp+15, 90, wp-2, -90, 2, -90, wp-2, 90, 10-2-r] - self.polyline(*poly2) - else: - self.polyline(25+2*rp-r) - self.polyline(0, (90, r), wp-1-r, 90, 20, 90-a3, 0, (-360+2*a3, rp), 0, 90-a3, 20, 90, wp-1-r, (90, r)) - if holes: - self.polyline(*list(reversed(poly2))) - else: - self.polyline(25+2*rp-r) - self.polyline(0, -90+a2, 0, (270-a2-a1-5, ro), 0, (-90+a1)) - if holes: # left sidemain clamp - self.polyline(*list(reversed(poly1))) - else: - self.polyline(l+l1-r) - self.polyline(0, (90, r), w-2*r, (90, r)) - - self.move(tw, th, move) - - - - def render(self): - - ri = self.flutediameter / 2.0 - ro = ri + self.wall - rp = self.polediameter / 2.0 - w = self.wall - self.layer(ri-20, ro, rp, move="up") - self.layer(ri, ro, rp, True, move="up") - self.layer(ri, ro, rp, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/storagerack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/storagerack.py deleted file mode 100644 index 89e5576..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/storagerack.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class StorageRack(Boxes): - """StorageRack to store boxes and trays which have their own floor""" - - ui_group = "Shelf" - - description = """ - -Drawers are not included: - -![Inside](static/samples/StorageRack-2.jpg) -![Back wall details](static/samples/StorageRack-3.jpg) - -""" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.StackableSettings) - - self.argparser.add_argument( - "--depth", action="store", type=float, default=200, - help="depth of the rack") - self.argparser.add_argument( - "--rail", action="store", type=float, default=30, - help="depth of the rack") - self.buildArgParser("x", "sh", "outside", "bottom_edge") - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("FheSŠ"), choices=list("FheSŠ"), - default="F", - help="edge type for top edge") - - def hHoles(self): - posh = -0.5 * self.thickness - for h in self.sh[:-1]: - posh += h + self.thickness - self.fingerHolesAt(posh, 0, self.depth) - - def backHoles(self): - posh = -0.5 * self.thickness - for nr, h in enumerate(self.sh[:-1]): - posh += h + self.thickness - if ((self.bottom_edge == "e" and nr == 0) or - (self.top_edge == "e" and nr == len(self.sh) - 2)): - self.fingerHolesAt(0, posh, self.x, 0) - else: - self.fingerHolesAt(0, posh, self.rail, 0) - self.fingerHolesAt(self.x, posh, self.rail, 180) - - def render(self): - if self.outside: - self.depth = self.adjustSize(self.depth, e2=False) - self.sh = self.adjustSize(self.sh, self.top_edge, self.bottom_edge) - self.x = self.adjustSize(self.x) - - h = sum(self.sh) + self.thickness * (len(self.sh) - 1) - x = self.x - d = self.depth - t = self.thickness - - - # outer walls - b = self.bottom_edge - t = self.top_edge - self.closedtop = self.top_edge in "fFhŠ" - - # sides - - self.ctx.save() - - # side walls - self.rectangularWall(d, h, [b, "F", t, "E"], callback=[None, self.hHoles, ], move="up") - self.rectangularWall(d, h, [b, "E", t, "F"], callback=[None, self.hHoles, ], move="up") - - # full floors - self.rectangularWall(d, x, "fffE", move="up") - self.rectangularWall(d, x, "fffE", move="up") - - num = len(self.sh)-1 - if b == "e": - num -= 1 - if t == "e": - num -= 1 - - for i in range(num): - self.rectangularWall(d, self.rail, "ffee", move="up") - self.rectangularWall(d, self.rail, "feef", move="up") - - self.ctx.restore() - self.rectangularWall(d, h, "ffff", move="right only") - - # back wall - self.rectangularWall(x, h, [b, "f", t, "f"], callback=[self.backHoles], move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/storageshelf.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/storageshelf.py deleted file mode 100644 index fc6beab..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/storageshelf.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.lids import _TopEdge - - -class StorageShelf(_TopEdge): - """StorageShelf can be used to store Typetray""" - - ui_group = "Shelf" - description = "This is a simple shelf box." - - def __init__(self) -> None: - Boxes.__init__(self) - self.addTopEdgeSettings(fingerjoint={"surroundingspaces": 0.5}, - roundedtriangle={"outset" : 1}) - self.buildArgParser("x", "sy", "sh", "outside", "bottom_edge", - "top_edge") - self.argparser.add_argument( - "--retainer", action="store", type=float, default=0.0, - help="height of retaining wall at the front edges") - self.argparser.add_argument( - "--retainer_hole_edge", action="store", type=boolarg, default=False, - help="use finger hole edge for retainer walls") - - - - def ySlots(self): - posy = -0.5 * self.thickness - h = sum(self.sh) + self.thickness * (len(self.sh) - 1) - for y in self.sy[:-1]: - posy += y + self.thickness - self.fingerHolesAt(posy, 0, h, 90) - - def hSlots(self): - posh = -0.5 * self.thickness - for h in self.sh[:-1]: - posh += h + self.thickness - posy = 0 - for y in reversed(self.sy): - self.fingerHolesAt(posh, posy, y) - posy += y + self.thickness - - def yHoles(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.x) - - def hHoles(self): - posh = -0.5 * self.thickness - for h in self.sh[:-1]: - posh += h + self.thickness - self.fingerHolesAt(posh, 0, self.x) - - def render(self): - if self.outside: - self.sy = self.adjustSize(self.sy) - self.sh = self.adjustSize(self.sh, self.top_edge, self.bottom_edge) - self.x = self.adjustSize(self.x, e2=False) - - y = sum(self.sy) + self.thickness * (len(self.sy) - 1) - h = sum(self.sh) + self.thickness * (len(self.sh) - 1) - x = self.x - t = self.thickness - - - # outer walls - b = self.bottom_edge - t1, t2, t3, t4 = self.topEdges(self.top_edge) - #if top_edge is t put the handle on the x walls - if(self.top_edge=='t'): - t1,t2,t3,t4=(t2,t1,t4,t3) - self.closedtop = self.top_edge in "fFhŠY" - - # x sides - - self.ctx.save() - - # outer walls - # XXX retainer - self.rectangularWall(x, h, [b, "F", t1, "e"], callback=[None, self.hHoles, ], move="up", label="left") - self.rectangularWall(x, h, [b, "e", t3, "F"], callback=[None, self.hHoles, ], move="up", label="right") - - # floor - if b != "e": - e = "fffe" - if self.retainer: - e = "ffff" - self.rectangularWall(x, y, e, callback=[None, self.yHoles], move="up", label="bottom") - - # inner walls - - be = "f" if b != "e" else "e" - - for i in range(len(self.sh) - 1): - e = ["f", edges.SlottedEdge(self, self.sy[::-1], "f", slots=0.5 * x), "f", "e"] - if self.retainer: - e[3] = "f" - - self.rectangularWall(x, y, e, move="up", label="inner horizontal " + str(i+1)) - - # top / lid - if self.closedtop: - e = "FFFe" if self.top_edge == "f" else "fffe" - self.rectangularWall(x, y, e, callback=[None, self.yHoles, ], move="up", label="top") - else: - self.drawLid(x, y, self.top_edge) - - self.ctx.restore() - self.rectangularWall(x, h, "ffff", move="right only", label="invisible") - - # y walls - - # outer walls - self.rectangularWall(y, h, [b, "f", t2, "f"], callback=[self.ySlots, self.hSlots,], move="up", label="back") - - # inner walls - for i in range(len(self.sy) - 1): - # XXX retainer - e = [be, edges.SlottedEdge(self, self.sh, "e", slots=0.5 * x), - "e", "f"] - if self.closedtop: - e = [be, edges.SlottedEdge(self, self.sh, "e", slots=0.5 * x),"f", "f"] - self.rectangularWall(x, h, e, move="up", label="inner vertical " + str(i+1)) - - - if self.retainer: - for i in range(len(self.sh)): - # XXX finger holes, F edges, left and right - e = "FEeE" - if self.retainer_hole_edge or (i == 0 and b == "h"): - e = "hEeE" - self.rectangularWall(y, self.retainer, e, move="up", label="retainer " + str(i+1)) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/tetris.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/tetris.py deleted file mode 100644 index ab463d9..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/tetris.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class Tetris(Boxes): - """3D Tetris shapes""" - - ui_group = "Misc" - - def __init__(self): - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - self.argparser.add_argument( - "--blocksize", action="store", type=float, default=40., - help="size of a square") - self.argparser.add_argument( - "--shape", action="store", type=str, default="L", - choices=['I', 'L', 'O', 'S', 'T'], - help="shape of the piece") - - def cb(self, nr): - t = self.thickness - s = self.blocksize - self.ctx.stroke() - self.set_source_color(Color.ETCHING) - - if nr == 0: - if self.shape in "LT": - for i in range(1, 3): - with self.saved_context(): - self.moveTo(s*i - t, 0, 90) - self.edge(s - 2*t) - if self.shape == "L": - self.moveTo(s*2, s - t, 0) - else: # "T" - self.moveTo(s, s - t, 0) - self.edge(s - 2*t) - if self.shape == "I": - for i in range(1, 4): - with self.saved_context(): - self.moveTo(s*i - t, 0, 90) - self.edge(s - 2*t) - if self.shape == "S" and nr in (0, 1, 4, 5): - self.moveTo(s - t, 0, 90) - self.edge(s - 2*t) - if self.shape == "O": - self.moveTo(s - t, 0, 90) - self.edge(s - t) - - - self.ctx.stroke() - - def render(self): - # adjust to the variables you want in the local scope - t = self.thickness - s = self.blocksize - - if self.shape == "L": - borders = [3*s - 2*t, 90, 2*s - 2*t, 90, s - 2*t, 90, - s, -90, 2*s, 90, s - 2*t, 90] - elif self.shape == "I": - borders = [4*s - 2*t, 90, s - 2*t, 90 ] * 2 - elif self.shape == "S": - borders = [2 * s - 2 * t, 90, s, -90, s, 90, s - 2 * t, 90] *2 - elif self.shape == "O": - borders = [2*s - 2*t, 90] * 4 - elif self.shape == "T": - borders = [90, s - 2*t, 90, s, -90, s, 90] - borders = [3*s - 2*t] + borders + [s - 2*t] + list(reversed(borders)) - self.polygonWall(borders=borders, callback=self.cb, move="right") - self.polygonWall(borders=borders, callback=self.cb, - move="mirror right") - - self.polygonWalls(borders=borders, h=s - 2 * t) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/trafficlight.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/trafficlight.py deleted file mode 100644 index 5c47cd4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/trafficlight.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class ShadyEdge(edges.BaseEdge): - char = "s" - - def __call__(self, length, **kw): - s = self.shades - h = self.h - a = math.atan(s/h) - angle = math.degrees(a) - for i in range(self.n): - self.polyline(0, -angle, h / math.cos(a), angle+90) - self.edges["f"](s) - self.corner(-90) - if i < self.n-1: - self.edge(self.thickness) - - def margin(self) -> float: - return self.shades - -class TrafficLight(Boxes): # change class name here and below - """Traffic light""" - description = """The traffic light was created to visualize the status of a Icinga monitored system. - -When turned by 90°, it can be also used to create a bottle holder.""" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings) - - # remove cli params you do not need - self.buildArgParser("h", "hole_dD") - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--depth", action="store", type=float, default=100, - help="inner depth not including the shades") - self.argparser.add_argument( - "--shades", action="store", type=float, default=50, - help="depth of the shaders") - self.argparser.add_argument( - "--n", action="store", type=int, default=3, - help="number of lights") - self.argparser.add_argument( - "--upright", action="store", type=boolarg, default=True, - help="stack lights upright (or side by side)") - - def backCB(self): - t = self.thickness - for i in range(1, self.n): - self.fingerHolesAt(i*(self.h+t)-0.5*t, 0, self.h) - - def sideCB(self): - t = self.thickness - for i in range(1, self.n): - self.fingerHolesAt(i*(self.h+t)-0.5*t, 0, self.depth) - for i in range(self.n): - self.fingerHolesAt(i*(self.h+t), self.depth-2*t, self.h, 0) - - def topCB(self): - t = self.thickness - for i in range(1, self.n): - self.fingerHolesAt(i*(self.h+t)-0.5*t, 0, self.depth + self.shades) - for i in range(self.n): - self.fingerHolesAt(i*(self.h+t), self.depth-2*t, self.h, 0) - - def frontCB(self): - self.hole(self.h/2, self.h/2, self.h/2-self.thickness) - - def wall(self, h1, h2, w, edges="ffef", callback=None, move="", label=""): - edges = [self.edges.get(e, e) for e in edges] - edges += edges # append for wrapping around - overallwidth = w + edges[-1].spacing() + edges[1].spacing() - overallheight = max(h1, h2) + edges[0].spacing() + edges[2].spacing() - - if self.move(overallwidth, overallheight, move, before=True, label=label): - return - - a = math.atan((h2-h1)/float(w)) - angle = math.degrees(a) - - self.moveTo(edges[-1].spacing(), edges[0].margin()) - for i, l in [(0, w), (1, h2)]: - self.cc(callback, i, y=edges[i].startwidth() + self.burn) - edges[i](l) - self.edgeCorner(edges[i], edges[i + 1], 90) - - self.corner(angle) - self.cc(callback, i, y=edges[2].startwidth() + self.burn) - edges[2](w / math.cos(a)) - self.corner(-angle) - self.edgeCorner(edges[2], edges[2 + 1], 90) - self.cc(callback, i, y=edges[3].startwidth() + self.burn) - edges[3](h1) - self.edgeCorner(edges[3], edges[3 + 1], 90) - - self.move(overallwidth, overallheight, move, label=label) - - def addMountH(self, width, height): - ds = self.hole_dD[0] - - if len(self.hole_dD) < 2: # if no head diameter is given - dh = 0 # only a round hole is generated - y = height - max (self.thickness * 1.25, self.thickness * 1.0 + ds) # and we assume that a typical screw head diameter is twice the shaft diameter - else: - dh = self.hole_dD[1] # use given head diameter - y = height - max (self.thickness * 1.25, self.thickness * 1.0 + dh / 2) # and offset the hole to have enough space for the head - - dx = width - x1 = dx * 0.125 - x2 = dx * 0.875 - - self.mountingHole(x1, y, ds, dh, 90) - self.mountingHole(x2, y, ds, dh, 90) - - def addMountV(self, width, height): - if self.hole_dD[0] < 2 * self.burn: - return # no hole if no diameter is given - - ds = self.hole_dD[0] - - if len(self.hole_dD) < 2: # if no head diameter is given - dh = 0 # only a round hole is generated - x = max (self.thickness * 2.75, self.thickness * 2.25 + ds) # and we assume that a typical screw head diameter is twice the shaft diameter - else: - dh = self.hole_dD[1] # use given head diameter - x = max (self.thickness * 2.75, self.thickness * 2.25 + dh / 2) # and offset the hole to have enough space for the head - - dy = height - - y1 = self.thickness * 0.75 + dy * 0.125 - y2 = self.thickness * 0.75 + dy * 0.875 - - self.mountingHole(x, y1, ds, dh, 180) - self.mountingHole(x, y2, ds, dh, 180) - - def render(self): - # adjust to the variables you want in the local scope - d, h, n = self.depth, self.h, self.n - s = self.shades - t = self.thickness - - th = n * (h + t) - t - - - self.addPart(ShadyEdge(self, None)) - - # back - if self.upright: - self.rectangularWall(th, h, "FFFF", callback=[self.backCB, self.addMountV(th, h)], move="up", label="back") - else: - self.rectangularWall(th, h, "FFFF", callback=[self.backCB, self.addMountH(th, h)], move="up", label="back") - - if self.upright: - # sides - self.rectangularWall(th, d, "fFsF", callback=[self.sideCB], move="up", label="left") - self.rectangularWall(th, d, "fFsF", callback=[self.sideCB], move="up", label="right") - - # horizontal Walls / blinds tops - e = edges.CompoundEdge(self, "fF", (d, s)) - e2 = edges.CompoundEdge(self, "Ff", (s, d)) - for i in range(n): - self.rectangularWall(h, d+s, ['f', e, 'e', e2], - move="right" if i. - -from boxes import * - - -class TrayInsert(Boxes): - """Tray insert without floor and outer walls - allows only continuous walls""" - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("sx", "sy", "h", "outside") - - def render(self): - - if self.outside: - self.sx = self.adjustSize(self.sx, False, False) - self.sy = self.adjustSize(self.sy, False, False) - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - y = sum(self.sy) + self.thickness * (len(self.sy) - 1) - h = self.h - t = self.thickness - - - # Inner walls - for i in range(len(self.sx) - 1): - e = [edges.SlottedEdge(self, self.sy, slots=0.5 * h), "e", "e", "e"] - self.rectangularWall(y, h, e, move="up") - - for i in range(len(self.sy) - 1): - e = ["e", "e", edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * h), "e"] - self.rectangularWall(x, h, e, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/traylayout.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/traylayout.py deleted file mode 100644 index b433a0c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/traylayout.py +++ /dev/null @@ -1,472 +0,0 @@ -# Copyright (C) 2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from __future__ import annotations - -import boxes -from boxes import * -from boxes import lids - - -class TrayLayoutFile(Boxes): - """Generate a layout file for a typetray.""" - # This class generates the skeleton text file that can then be edited - # to describe the actual box - - description = """This is a two step process. This is step 1. -The layout is based on a grid of sizes in x and y direction. -Choose how many distances you need in both directions. -The actual sizes and all other settings can be entered in the second step.""" - - webinterface = False - - ui_group = "Tray" - - sx: list[float] = [] # arg input - sy: list[float] = [] # arg input - hwalls: list[list[bool]] = [] - vwalls: list[list[bool]] = [] - floors: list[list[bool]] = [] - - def __init__(self, input=None, webargs=False) -> None: - Boxes.__init__(self) - self.argparser = argparse.ArgumentParser() - self.buildArgParser("sx", "sy") - self.argparser.add_argument( - "--output", action="store", type=str, default="traylayout.txt", - help="Name of the layout text file.") - - def open(self) -> None: - # Use empty open and close methods to avoid initializing the whole drawing infrastructure. - pass - - def close(self) -> None: - # Use empty open and close methods to avoid initializing the whole drawing infrastructure. - pass - - def fillDefault(self, sx: list[float], sy: list[float]) -> None: - self.sx = sx - self.sy = sy - x = len(sx) - y = len(sy) - self.hwalls = [[True for _ in range(x)] for _ in range(y + 1)] - self.vwalls = [[True for _ in range(x + 1)] for _ in range(y)] - self.floors = [[True for _ in range(x)] for _ in range(y)] - - def __str__(self) -> str: - r = [] - - for i, x in enumerate(self.sx): - r.append(" |" * i + " ,> %.1fmm\n" % x) - - for hwalls, vwalls, floors, y in zip(self.hwalls, self.vwalls, self.floors, self.sy): - r.append("".join("+" + " -"[h] for h in hwalls) + "+\n") - r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors))) + " |"[vwalls[-1]] + " %.1fmm\n" % y) - r.append("".join("+" + " -"[h] for h in self.hwalls[-1]) + "+\n") - - return "".join(r) - - def render(self) -> None: - self.fillDefault(self.sx, self.sy) - with open(self.output, 'w') as f: - f.write(str(self)) - - -class TrayLayout(Boxes): - """Generate a typetray from a layout file.""" - - # This class reads in the layout either from a file (with --input) or - # as string (with --layout) and turns it into a drawing for a box. - - ui_group = "Tray" - - description = """This is a two step process. This is step 2. -Edit the layout text graphics to adjust your tray. -Put in the sizes for each column and row. You can replace the hyphens and -vertical bars representing the walls with a space character to remove the walls. -You can replace the space characters representing the floor by a "X" to remove the floor for this compartment. -""" - - def __init__(self) -> None: - super().__init__() - self.addSettingsArgs(boxes.edges.FingerJointSettings) - self.addSettingsArgs(lids.LidSettings) - self.buildArgParser("h", "hi", "outside", "sx", "sy") - if self.UI == "web": - self.argparser.add_argument( - "--layout", action="store", type=str, default="\n") - else: - self.argparser.add_argument( - "--input", action="store", type=argparse.FileType('r'), - default="traylayout.txt", - help="layout file") - self.layout = None - - def vWalls(self, x: int, y: int) -> int: - """Number of vertical walls at a crossing.""" - result = 0 - if y > 0 and self.vwalls[y - 1][x]: - result += 1 - if y < len(self.y) and self.vwalls[y][x]: - result += 1 - return result - - def hWalls(self, x: int, y: int) -> int: - """Number of horizontal walls at a crossing.""" - result = 0 - if x > 0 and self.hwalls[y][x - 1]: - result += 1 - if x < len(self.x) and self.hwalls[y][x]: - result += 1 - return result - - def vFloor(self, x: int, y: int) -> bool: - """Is there floor under vertical wall.""" - if y >= len(self.y): - return False - - return (x > 0 and self.floors[y][x - 1]) or (x < len(self.x) and self.floors[y][x]) - - def hFloor(self, x: int, y: int) -> bool: - """Is there floor under horizontal wall.""" - if x >= len(self.x): - return False - return (y > 0 and self.floors[y - 1][x]) or (y < len(self.y) and self.floors[y][x]) - - @restore - def edgeAt(self, edge, x, y, length, angle=0): - self.moveTo(x, y, angle) - edge = self.edges.get(edge, edge) - edge(length) - - def prepare(self): - if self.layout: - self.parse(self.layout.split('\n')) - else: - self.parse(self.input) - - if self.outside: - self.x = self.adjustSize(self.x) - self.y = self.adjustSize(self.y) - self.h = self.adjustSize(self.h, e2=False) - - if self.hi: - self.hi = self.adjustSize(self.hi, e2=False) - - self.hi = self.hi or self.h - self.edges["s"] = boxes.edges.Slot(self, self.hi / 2.0) - self.edges["C"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi) - self.edges["D"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi, outset=self.thickness) - - def walls(self, move=None): - lx = len(self.x) - ly = len(self.y) - # t = self.thickness - # b = self.burn - # t2 = self.thickness / 2.0 - - self.ctx.save() - - # Horizontal Walls - for y in range(ly + 1): - if y == 0 or y == ly: - h = self.h - else: - h = self.hi - - start = 0 - end = 0 - - while end < lx: - lengths = [] - edges = [] - - while start < lx and not self.hwalls[y][start]: - start += 1 - - if start == lx: - break - - end = start - - while end < lx and self.hwalls[y][end]: - if self.hFloor(end, y): - edges.append("f") - else: - edges.append("E") - - lengths.append(self.x[end]) - if self.hFloor(end, y) == 0 and self.hFloor(end + 1, y) == 0: - edges.append("EDs"[self.vWalls(end + 1, y)]) - else: - edges.append("eCs"[self.vWalls(end + 1, y)]) - lengths.append(self.thickness) - end += 1 - - # remove last "slot" - lengths.pop() - edges.pop() - self.rectangularWall(sum(lengths), h, [ - boxes.edges.CompoundEdge(self, edges, lengths), - "f" if self.vWalls(end, y) else "e", - "e", - "f" if self.vWalls(start, y) else "e"], - move="right") - start = end - - self.ctx.restore() - self.rectangularWall(10, h, "ffef", move="up only") - self.ctx.save() - - # Vertical Walls - for x in range(lx + 1): - if x == 0 or x == lx: - h = self.h - else: - h = self.hi - start = 0 - end = 0 - - while end < ly: - lengths = [] - edges = [] - while start < ly and not self.vwalls[start][x]: - start += 1 - - if start == ly: - break - - end = start - - while end < ly and self.vwalls[end][x]: - if self.vFloor(x, end): - edges.append("f") - else: - edges.append("E") - - lengths.append(self.y[end]) - if self.vFloor(x, end) == 0 and self.vFloor(x, end + 1) == 0: - edges.append("EDs"[self.hWalls(x, end + 1)]) - else: - edges.append("eCs"[self.hWalls(x, end + 1)]) - lengths.append(self.thickness) - end += 1 - # remove last "slot" - lengths.pop() - edges.pop() - - upper = [{"f": "e", - "s": "s", - "e": "e", - "E": "e", - "C": "e", - "D": "e"}[e] for e in reversed(edges)] - edges = ["e" if e == "s" else e for e in edges] - self.rectangularWall(sum(lengths), h, [ - boxes.edges.CompoundEdge(self, edges, lengths), - "eFf"[self.hWalls(x, end)], - boxes.edges.CompoundEdge(self, upper, list(reversed(lengths))), - "eFf"[self.hWalls(x, start)]], - move="right") - start = end - - self.ctx.restore() - self.rectangularWall(10, h, "ffef", move="up only") - - def base_plate(self, callback=None, move=None): - lx = len(self.x) - ly = len(self.y) - t = self.thickness - w = self.edges["F"].startwidth() - b = self.burn - t2 = self.thickness / 2.0 - - tw = sum(self.x) + (lx - 1) * t + 2 * w - th = sum(self.y) + (ly - 1) * t + 2 * w - - if self.move(tw, th, move, True): - return - - for i, (x, y, a) in enumerate(( - (w, w + b, 0), - (tw - w, w + b, 90), - (tw - w, th - w + b, 180), - (w, th - w + b, 270))): - self.cc(callback, i, x, y, a) - - # Horizontal lines - posy = w - t - for y in range(ly, -1, -1): - posx = w - for x in range(lx): - if self.hwalls[y][x]: - e = "F" - else: - e = "e" - - if y < ly and self.floors[y][x]: - if y > 0 and self.floors[y - 1][x]: - # Inside Wall - if self.hwalls[y][x]: - self.fingerHolesAt(posx, posy + t2, self.x[x], angle=0) - else: - # Top edge - self.edgeAt(e, posx + self.x[x], - posy + w + b, self.x[x], - -180) - if x == 0 or not self.floors[y][x - 1]: - self.edgeAt("e", posx - w, posy + w + b, w, 0) - elif y == 0 or not self.floors[y - 1][x - 1]: - self.edgeAt("e", posx - t, posy + w + b, t, 0) - if x == lx - 1 or not self.floors[y][x + 1]: - self.edgeAt("e", posx + self.x[x], posy + w + b, w, 0) - elif y > 0 and self.floors[y - 1][x]: - # Bottom Edge - self.edgeAt(e, posx, posy - b + t - w, self.x[x]) - if x == 0 or not self.floors[y-1][x - 1]: - self.edgeAt("e", posx - w, posy + t - w - b, w) - elif x == 0 or y == ly or not self.floors[y][x - 1]: - self.edgeAt("e", posx - t, posy + t - w - b, t) - if x == lx - 1 or y == 0 or not self.floors[y-1][x + 1]: - self.edgeAt("e", posx + self.x[x], posy + t -w - b, w) - posx += self.x[x] + self.thickness - posy += self.y[y - 1] + self.thickness - - posx = w - t - for x in range(lx + 1): - posy = w - for y in range(ly - 1, -1, -1): - if self.vwalls[y][x]: - e = "F" - else: - e = "e" - if x > 0 and self.floors[y][x - 1]: - if x < lx and self.floors[y][x]: - # Inside wall - if self.vwalls[y][x]: - self.fingerHolesAt(posx + t2, posy, self.y[y]) - else: - # Right edge - self.edgeAt(e, posx + w + b, posy, self.y[y], 90) - if y == 0 or not self.floors[y-1][x-1]: - self.edgeAt("e", posx + w + b, posy + self.y[y], w, 90) - elif x == lx or y == 0 or not self.floors[y - 1][x]: - self.edgeAt("e", posx + w + b, posy + self.y[y], t, 90) - if y == ly - 1 or not self.floors[y+1][x-1]: - self.edgeAt("e", posx + w + b, posy - w, w, 90) - elif x < lx and self.floors[y][x]: - # Left edge - self.edgeAt(e, posx + t - w - b, posy + self.y[y], self.y[y], -90) - if y == 0 or not self.floors[y - 1][x]: - self.edgeAt("e", posx + t - w - b, - posy + self.y[y] + w, w, -90) - elif x == 0 or y == 0 or not self.floors[y - 1][x - 1]: - self.edgeAt("e", posx + t - w - b, - posy + self.y[y] + t, t, -90) - if y == ly - 1 or not self.floors[y + 1][x]: - self.edgeAt("e", posx + t - w - b, posy, w, -90) - posy += self.y[y] + self.thickness - if x < lx: - posx += self.x[x] + self.thickness - - self.move(tw, th, move) - - def parse(self, input): - x = [] - y = [] - hwalls = [] - vwalls = [] - floors = [] - for nr, line in enumerate(input): - if not line or line[0] == "#": - continue - m = re.match(r"( \|)* ,>\s*(\d*\.?\d+)\s*mm\s*", line) - if m: - x.append(float(m.group(2))) - continue - if line[0] == '+': - w = [] - for n, c in enumerate(line[:len(x) * 2 + 1]): - if n % 2: - if c == ' ': - w.append(False) - elif c == '-': - w.append(True) - else: - pass - # raise ValueError(line) - else: - if c != '+': - pass - # raise ValueError(line) - - hwalls.append(w) - if line[0] in " |": - w = [] - f = [] - for n, c in enumerate(line[:len(x) * 2 + 1]): - if n % 2: - if c in 'xX': - f.append(False) - elif c == ' ': - f.append(True) - else: - raise ValueError("""Can't parse line %i in layout: expected " ", "x" or "X" for char #%i""" % (nr + 1, n + 1)) - else: - if c == ' ': - w.append(False) - elif c == '|': - w.append(True) - else: - raise ValueError("""Can't parse line %i in layout: expected " ", or "|" for char #%i""" % (nr + 1, n + 1)) - - floors.append(f) - vwalls.append(w) - m = re.match(r"([ |][ xX])+[ |]\s*(\d*\.?\d+)\s*mm\s*", line) - if not m: - raise ValueError("""Can't parse line %i in layout: Can read height of the row""" % (nr + 1)) - else: - y.append(float(m.group(2))) - - # check sizes - lx = len(x) - ly = len(y) - - if lx == 0: - raise ValueError("Need more than one wall in x direction") - if ly == 0: - raise ValueError("Need more than one wall in y direction") - if len(hwalls) != ly + 1: - raise ValueError("Wrong number of horizontal wall lines: %i (%i expected)" % (len(hwalls), ly + 1)) - for nr, walls in enumerate(hwalls): - if len(walls) != lx: - raise ValueError("Wrong number of horizontal walls in line %i: %i (%i expected)" % (nr, len(walls), lx)) - if len(vwalls) != ly: - raise ValueError("Wrong number of vertical wall lines: %i (%i expected)" % (len(vwalls), ly)) - for nr, walls in enumerate(vwalls): - if len(walls) != lx + 1: - raise ValueError("Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx + 1)) - - self.x = x - self.y = y - self.hwalls = hwalls - self.vwalls = vwalls - self.floors = floors - - def render(self) -> None: - self.prepare() - self.walls() - self.base_plate(move="up") - self.lid(sum(self.x) + (len(self.x)-1) * self.thickness, - sum(self.y) + (len(self.y)-1) * self.thickness) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/trianglelamp.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/trianglelamp.py deleted file mode 100644 index c36d713..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/trianglelamp.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class CornerEdge(edges.Edge): - char = "C" - - def startwidth(self) -> float: - return self.boxes.thickness * math.tan(math.radians(90-22.5)) - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - with self.saved_context(): - self.ctx.stroke() - self.set_source_color(Color.RED) - self.moveTo(0, self.startwidth()) - self.edge(length) - self.ctx.stroke() - self.set_source_color(Color.BLACK) - super().__call__(length, bedBolts=None, bedBoltSettings=None, **kw) - - -class TriangleLamp(Boxes): - """Triangle LED Lamp""" - - ui_group = "Misc" - - def __init__(self) -> None: - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, finger=3.0,space=3.0, - surroundingspaces=0.5) - self.buildArgParser(x=250, h=40) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--cornersize", action="store", type=float, default=30, - help="short side of the corner triangles") - self.argparser.add_argument( - "--screenholesize", action="store", type=float, default=4, - help="diameter of the holes in the screen") - self.argparser.add_argument( - "--screwholesize", action="store", type=float, default=2, - help="diameter of the holes in the wood") - self.argparser.add_argument( - "--sharpcorners", action="store", type=boolarg, default=False, - help="extend walls for 45° corners. Requires grinding a 22.5° bevel.") - - def CB(self, l, size): - - def f(): - t = self.thickness - self.fingerHolesAt(0, self.h-1.5*t, size, 0) - self.fingerHolesAt(l, self.h-1.5*t, size, 180) - - return f - - def render(self): - # adjust to the variables you want in the local scope - x, h = self.x, self.h - l = (x**2+x**2)**.5 - c = self.cornersize - t = self.thickness - - r1 = self.screwholesize / 2 - r2 = self.screenholesize / 2 - - self.addPart(CornerEdge(self, None)) - - self.rectangularTriangle(x, x, num=2, move="up", callback=[ - lambda: self.hole(2/3.*c, 1/4.*c, r2), - lambda: (self.hole(1/3.*c, 1/3.*c, r2), - self.hole(x-2/3.*c, 1/4.*c, r2)), - ]) - self.rectangularTriangle(x, x, "fff", num=2, move="up") - - C = 'e' - if self.sharpcorners: - C = 'C' - - self.rectangularWall(x, h, "Ffe"+C, callback=[self.CB(x, c)], - move="up") - self.rectangularWall(x, h, "Ffe"+C, callback=[self.CB(x, c)], - move="up") - - self.rectangularWall(x, h, "F"+C+"eF", callback=[self.CB(x, c)], - move="up") - self.rectangularWall(x, h, "F"+C+"eF", callback=[self.CB(x, c)], - move="up") - - self.rectangularWall(l, h, "F"+C+"e" + C, - callback=[self.CB(l, c*2**.5)], move="up") - self.rectangularWall(l, h, "F"+C+"e" + C, - callback=[self.CB(l, c*2**.5)], move="up") - - - self.rectangularTriangle(c, c, "ffe", num=2, move="right", callback=[ - lambda:self.hole(2/3.*c,1/3.*c, r1)]) - self.rectangularTriangle(c, c, "fef", num=4, move="up", callback=[ - lambda: self.hole(2/3.*c, 1/4.*c, r1)]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/two_piece.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/two_piece.py deleted file mode 100644 index 8ceffa8..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/two_piece.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class TwoPiece(Boxes): - """A two piece box where top slips over the bottom half to form - the enclosure. - """ - - description = """ -Set *hi* larger than *h* to leave gap between the inner and outer shell. This can be used to make opening the box easier. Set *hi* smaller to only have a small inner ridge that will allow the content to be more visible after opening. - -![Bottom view](static/samples/TwoPiece2.jpg) -""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.buildArgParser("x", "y", "h", "hi", "outside") - self.addSettingsArgs(edges.FingerJointSettings, finger=2.0, space=2.0) - - self.argparser.add_argument( - "--play", action="store", type=float, default=0.15, - help="play between the two parts as multiple of the wall thickness") - - def render(self): - # adjust to the variables you want in the local scope - x, y, h = self.x, self.y, self.h - hi = self.hi or self.h - t = self.thickness - p = self.play * t - - if self.outside: - x -= 4*t + 2*p - y -= 4*t + 2*p - h -= 2 * t - hi -= 2 * t - - # Adjust h edge with play - self.edges["f"].settings.setValues(t, False, edge_width=self.edges["f"].settings.edge_width + p) - - for i in range(2): - d = i * 2 * (t+p) - height = [hi, h][i] - with self.saved_context(): - self.rectangularWall(x+d, height, "fFeF", move="right") - self.rectangularWall(y+d, height, "ffef", move="right") - self.rectangularWall(x+d, height, "fFeF", move="right") - self.rectangularWall(y+d, height, "ffef", move="right") - self.rectangularWall(y, height, "ffef", move="up only") - - self.rectangularWall(x, y, "hhhh", bedBolts=None, move="right") - self.rectangularWall(x+d, y+d, "FFFF", bedBolts=None, move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/typetray.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/typetray.py deleted file mode 100644 index e520de5..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/typetray.py +++ /dev/null @@ -1,355 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import Color, edges -from boxes.lids import LidSettings, _TopEdge - - -class FingerHoleEdgeSettings(edges.Settings): - """Settings for FingerHoleEdge -Values: -* absolute_params - - * radius : 10.0 : maximal radius (in mm) - * absolute_depth : 0.0 : depth of the hole in mm (in addition to the relative) - * absolute_width : 0.0 : width of the hole in mm (in addition to the relative) - * relative_depth : 0.0 : depth of the hole as fraction of the wall - * relative_width : 0.3 : width of the hole as fraction of the wall width - -""" - absolute_params = { - "radius": 10., - "absolute_depth": 0.0, - "relative_depth" : 0.9, - "absolute_width" : 0.0, - "relative_width" : 0.3, - } - - wallheight = 0.0 - -class FingerHoleEdge(edges.BaseEdge): - """An edge with room to get your fingers around cards""" - - char = "A" - - def __call__(self, length, **kw): - - width = min(self.settings.absolute_width + length * self.settings.relative_width, length) - depth = min(self.settings.absolute_depth + self.settings.wallheight * self.settings.relative_depth, self.settings.wallheight) - - r = min(width/2, depth, self.settings.radius) - - if depth < 1e-9 or width < 1e-9: - self.boxes.edge(length, tabs=2) - return - poly = (((length - width) / 2, 1), 90, depth-r, (-90, r)) - self.polyline(*poly, (width - 2*r, 1), *reversed(poly)) - - -class TypeTray(_TopEdge): - """Type tray - allows only continuous walls""" - - ui_group = "Tray" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addTopEdgeSettings(fingerjoint={"surroundingspaces": 0.5}, - roundedtriangle={"outset" : 1}) - self.addSettingsArgs(LidSettings) - self.buildArgParser("sx", "sy", "h", "hi", "outside", "bottom_edge", - "top_edge") - self.argparser.add_argument( - "--back_height", action="store", type=float, default=0.0, - help="additional height of the back wall - e top edge only") - self.argparser.add_argument( - "--radius", action="store", type=float, default=0.0, - help="radius for strengthening side walls with back_height") - self.argparser.add_argument( - "--gripheight", action="store", type=float, default=30, - dest="gh", help="height of the grip hole in mm") - self.argparser.add_argument( - "--gripwidth", action="store", type=float, default=70, - dest="gw", help="width of th grip hole in mm (zero for no hole)") - self.argparser.add_argument( - "--handle", type=boolarg, default=False, help="add handle to the bottom (changes bottom edge in the front)") - self.argparser.add_argument( - "--fingerholes", action="store", type=str, default="none", - choices=["none", "inside-only", "front", "back", "front-and-back"], - help="Decide which outer walls should have finger hole, too") - - label_group = self.argparser.add_argument_group("Compartment Labels") - label_group.add_argument( - "--text_size", action="store", type=int, default=12, - help="Textsize in mm for the traycontent") - label_group.add_argument( - "--text_alignment", action="store", type=str, default="left", - choices=['left', 'center', 'right'], - help="Text Alignment") - label_group.add_argument( - "--text_distance_x", action="store", type=float, default=2.0, - help="Distance in X from edge of tray in mm. Has no effect when text is centered.") - label_group.add_argument( - "--text_distance_y", action="store", type=float, default=2.0, - help="Distance in Y from edge of tray in mm.") - label_group.add_argument( - "--text_at_front", action="store", type=boolarg, default=False, - help="Start compartement labels on the front") - if self.UI == "web": - label_group.add_argument( - "--label_text", action="store", type=str, default="\n", - help="Every line is the text for one compartment. Beginning with front left") - else: - label_group.add_argument( - "--label_file", action="store", type=argparse.FileType('r'), - default="labels.txt", - help="file with compartment labels. One line per compartment") - - self.addSettingsArgs(FingerHoleEdgeSettings) - - @property - def fingerholedepth(self): - if self.fingerhole == 'custom': - return self.fingerhole_depth - elif self.fingerhole == 'regular': - a = self.h/4 - if a < 35: - return a - else: - return 35 - elif self.fingerhole == 'deep': - return self.h-self.thickness-10 - elif self.fingerhole == 'none': - return 0 - - def xSlots(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - posy = 0 - for y in self.sy: - self.fingerHolesAt(posx, posy, y) - posy += y + self.thickness - - def ySlots(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - posx = 0 - for x in reversed(self.sx): - self.fingerHolesAt(posy, posx, x) - posx += x + self.thickness - - def xHoles(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, self.hi) - - def yHoles(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.hi) - - def gripHole(self): - if not self.gw: - return - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - r = min(self.gw, self.gh) / 2.0 - self.rectangularHole(x / 2.0, self.gh * 1.5, self.gw, self.gh, r) - - def textCB(self): - ## declare text-variables - textsize = self.text_size - texty = self.hi - textsize - self.text_distance_y - if self.text_alignment == 'center': - texty -= self.fingerholedepth - textdistance = self.sx[0] + self.thickness - - ## Generate text-fields for each tray - for n in range(len(self.sx)): - # Break for-loop if further list is empty - if self.textnumber >= len(self.textcontent): - break - - textx = n * (self.sx[0] + self.thickness) - # Calculate textposition - if self.text_alignment == 'left': - textx += self.text_distance_x - elif self.text_alignment == 'center': - textx += self.sx[0] / 2 - elif self.text_alignment == 'right': - textx += self.sx[0] - self.text_distance_x - - # Generate text - self.text( - "%s" % self.textcontent[self.textnumber], - textx, - texty, - 0, - align=self.text_alignment, - fontsize=textsize, - color=Color.ETCHING) - self.textnumber +=1 - - def render(self): - if self.outside: - self.sx = self.adjustSize(self.sx) - self.sy = self.adjustSize(self.sy) - self.h = self.adjustSize(self.h, e2=False) - if self.hi: - self.hi = self.adjustSize(self.hi, e2=False) - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - y = sum(self.sy) + self.thickness * (len(self.sy) - 1) - h = self.h - sameh = not self.hi - hi = self.hi = self.hi or h - t = self.thickness - - s = FingerHoleEdgeSettings(self.thickness, True, - **self.edgesettings.get("FingerHoleEdge", {})) - s.wallheight = 0 if self.fingerholes == "none" else self.hi - p = FingerHoleEdge(self, s) - self.addPart(p) - - # outer walls - b = self.bottom_edge - tl, tb, tr, tf = self.topEdges(self.top_edge) - self.closedtop = self.top_edge in "fFhŠ" - - bh = self.back_height if self.top_edge == "e" else 0.0 - - if hasattr(self, "label_text"): - self.textcontent = self.label_text.split("\r\n") - else: - self.textcontent = self.label_file.readlines() - self.textnumber = 0 - - # x sides - - self.ctx.save() - - # floor - if b != "e": - if self.handle: - self.rectangularWall(x, y, "ffYf", callback=[self.xSlots, self.ySlots], move="up", label="bottom") - else: - self.rectangularWall(x, y, "ffff", callback=[self.xSlots, self.ySlots], move="up", label="bottom") - - # front - if self.text_at_front: - frontCBs = [lambda:(self.textCB(), self.mirrorX(self.xHoles, x)()), - None, self.gripHole] - else: - frontCBs = [self.mirrorX(self.xHoles, x), None, self.gripHole] - - # finger holes at front wall - if not self.closedtop and \ - self.fingerholes in ("front", "front-and-back"): - tf = edges.SlottedEdge(self, self.sx[::-1], "A") - - if bh: - self.rectangularWall( - x, h, ["f" if self.handle else b, "f", tf, "f"], - callback=frontCBs, move="up", label="front") - else: - self.rectangularWall( - x, h, ["f" if self.handle else b, "F", tf, "F"], - callback=frontCBs, ignore_widths=[] if self.handle else [1, 6], - move="up", label="front") - - - # Inner walls - - be = "f" if b != "e" else "e" - - ###### - for i in range(len(self.sy) - 1): - - e = [edges.SlottedEdge(self, self.sx, be), "f", - edges.SlottedEdge(self, self.sx[::-1], "A", slots=0.5 * hi), "f"] - - if self.closedtop and sameh: - e = [edges.SlottedEdge(self, self.sx, be), "f", - edges.SlottedEdge(self, self.sx[::-1], "f", slots=0.5 * hi), "f"] - - self.rectangularWall(x, hi, e, move="up", callback=[self.textCB], - label=f"inner x {i+1}") - - # back - - # finger holes at back wall - if not self.closedtop and \ - self.fingerholes in ("back", "front-and-back"): - tb = edges.SlottedEdge(self, self.sx, "A") - - if bh: - self.rectangularWall(x, h+bh, [b, "f", tb, "f"], - callback=[self.xHoles], - ignore_widths=[], - move="up", label="back") - else: - self.rectangularWall(x, h, [b, "F", tb, "F"], - callback=[self.xHoles], - ignore_widths=[1, 6], - move="up", label="back") - - # top / lid - if self.closedtop and sameh: - e = "FFFF" if self.top_edge == "f" else "ffff" - self.rectangularWall(x, y, e, callback=[ - self.xSlots, self.ySlots], move="up", label="top") - else: - self.drawLid(x, y, self.top_edge) - self.lid(x, y, self.top_edge) - - self.ctx.restore() - self.rectangularWall(x, hi, "ffff", move="right only") - - # y walls - - # outer walls - left/right - - if bh: - self.trapezoidSideWall( - y, h, h+bh, [b, "h", "e", "h"], - radius=self.radius, callback=[self.yHoles, ], - move="up", label="left side") - self.trapezoidSideWall( - y, h+bh, h, [b, "h", "e", "h"], radius=self.radius, - callback=[self.mirrorX(self.yHoles, y), ], - move="up", label="right side") - else: - self.rectangularWall( - y, h, [b, "f", tl, "f"], callback=[self.yHoles, ], - ignore_widths=[6] if self.handle else [1, 6], - move="up", label="left side") - self.rectangularWall( - y, h, [b, "f", tr, "f"], - callback=[self.mirrorX(self.yHoles, y), ], - ignore_widths=[1] if self.handle else [1, 6], - move="up", label="right side") - - # inner walls - for i in range(len(self.sx) - 1): - e = [edges.SlottedEdge(self, self.sy, be, slots=0.5 * hi), - "f", "e", "f"] - if self.closedtop and sameh: - e = [edges.SlottedEdge(self, self.sy, be, slots=0.5 * hi),"f", - edges.SlottedEdge(self, self.sy[::-1], "f"), "f"] - self.rectangularWall(y, hi, e, move="up", label=f"inner y {i+1}") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ubox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ubox.py deleted file mode 100644 index 05f7e8f..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/ubox.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2013-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.lids import LidSettings, _TopEdge - - -class UBox(_TopEdge): - """Box various options for different stypes and lids""" - - ui_group = "FlexBox" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addTopEdgeSettings() - self.addSettingsArgs(edges.FlexSettings) - self.addSettingsArgs(LidSettings) - self.buildArgParser("top_edge", "x", "y", "h") - self.argparser.add_argument( - "--radius", action="store", type=float, default=30.0, - help="radius of bottom corners") - self.angle = 0 - - def U(self, x, y, r, edge="e", move=None, label=""): - - e = self.edges.get(edge, edge) - - w = self.edges["f"].spacing() - tw = x+2*w - th = y+w+e.spacing() - if self.move(tw, th, move, True, label=label): - return - - self.moveTo(w+r, w) - self.edges["f"](x-2*r) - self.corner(90, r) - self.edges["f"](y-r) - self.edgeCorner("f", e) - e(x) - self.edgeCorner(e, "f") - self.edges["f"](y-r) - self.corner(90, r) - - self.move(tw, th, move, label=label) - - def Uwall(self, x, y, h, r, edges="ee", move=None, label=""): - - e = [self.edges.get(edge, edge) for edge in edges] - - w = self.edges["F"].spacing() - cl = r*math.pi/2 - - tw = 2*y + x - 4*(cl-r) + e[0].spacing() + e[1].spacing() - th = h + 2*w - if self.move(tw, th, move, True, label=label): - return - - self.moveTo(e[0].spacing()) - - for nr, flex in enumerate("XE"): - self.edges["F"](y-r) - if x-2*r > 0.1 * self.thickness: - self.edges[flex](cl, h=th) - self.edges["F"](x-2*r) - self.edges[flex](cl, h=th) - else: - self.edges[flex](2*cl+x-2*r, h=th) - self.edges["F"](y-r) - self.edgeCorner("F", e[nr]) - e[nr](h) - self.edgeCorner(e[nr], "F") - - self.move(tw, th, move, label=label) - - def render(self): - x, y, h, r = self.x, self.y, self.h, self.radius - - self.radius = r = min(r, x/2.0, y) - - _ = self.translations.gettext - t1, t2, t3, t4 = self.topEdges(self.top_edge) - - self.U(x, y, r, t1, move="right", label=_("left")) - self.U(x, y, r, t3, move="up", label=_("right")) - self.U(x, y, r, t3, move="left only") - self.Uwall(x, y, h, r, [t2, t4], move="up", label=_("wall")) - - self.drawLid(x, h, self.top_edge) - self.lid(x, h, self.top_edge) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/unevenheightbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/unevenheightbox.py deleted file mode 100644 index b6318fa..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/unevenheightbox.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (C) 2013-2018 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class UnevenHeightBox(Boxes): - """Box with different height in each corner""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(edges.GroovedSettings) - self.buildArgParser("x", "y", "outside", bottom_edge="F") - self.argparser.add_argument( - "--height0", action="store", type=float, default=50, - help="height of the front left corner in mm") - self.argparser.add_argument( - "--height1", action="store", type=float, default=50, - help="height of the front right corner in mm") - self.argparser.add_argument( - "--height2", action="store", type=float, default=100, - help="height of the right back corner in mm") - self.argparser.add_argument( - "--height3", action="store", type=float, default=100, - help="height of the left back corner in mm") - self.argparser.add_argument( - "--lid", action="store", type=boolarg, default=False, - help="add a lid (works best with high corners opposing each other)") - self.argparser.add_argument( - "--lid_height", action="store", type=float, default=0, - help="additional height of the lid") - self.argparser.add_argument( - "--edge_types", action="store", type=str, default="eeee", - help="which edges are flat (e) or grooved (z,Z), counter-clockwise from the front") - - def render(self): - - x, y = self.x, self.y - heights = [self.height0, self.height1, self.height2, self.height3] - - edge_types = self.edge_types - if len(edge_types) != 4 or any(et not in "ezZ" for et in edge_types): - raise ValueError("Wrong edge_types style: %s)" % edge_types) - - if self.outside: - x = self.adjustSize(x) - y = self.adjustSize(y) - for i in range(4): - heights[i] = self.adjustSize(heights[i], self.bottom_edge, - self.lid) - - t = self.thickness - h0, h1, h2, h3 = heights - b = self.bottom_edge - - self.trapezoidWall(x, h0, h1, [b, "F", edge_types[0], "F"], move="right") - self.trapezoidWall(y, h1, h2, [b, "f", edge_types[1], "f"], move="right") - self.trapezoidWall(x, h2, h3, [b, "F", edge_types[2], "F"], move="right") - self.trapezoidWall(y, h3, h0, [b, "f", edge_types[3], "f"], move="right") - - with self.saved_context(): - if b != "e": - self.rectangularWall(x, y, "ffff", move="up") - - if self.lid: - maxh = max(heights) - lidheights = [maxh-h+self.lid_height for h in heights] - h0, h1, h2, h3 = lidheights - lidheights += lidheights - edges = ["E" if (lidheights[i] == 0.0 and lidheights[i+1] == 0.0) else "f" for i in range(4)] - self.rectangularWall(x, y, edges, move="up") - - if self.lid: - self.moveTo(0, maxh+self.lid_height+self.edges["F"].spacing()+self.edges[b].spacing()+1*self.spacing, 180) - edge_inverse = {"e": "e", "z": "Z", "Z": "z"} - edge_types = [edge_inverse[et] for et in edge_types] - - self.trapezoidWall(y, h0, h3, "Ff" + edge_types[3] + "f", move="right" + - (" only" if h0 == h3 == 0.0 else "")) - self.trapezoidWall(x, h3, h2, "FF" + edge_types[2] + "F", move="right" + - (" only" if h3 == h2 == 0.0 else "")) - self.trapezoidWall(y, h2, h1, "Ff" + edge_types[1] + "f", move="right" + - (" only" if h2 == h1 == 0.0 else "")) - self.trapezoidWall(x, h1, h0, "FF" + edge_types[0] + "F", move="right" + - (" only" if h1 == h0 == 0.0 else "")) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/universalbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/universalbox.py deleted file mode 100644 index 9f1f6cf..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/universalbox.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes import lids -from boxes.edges import Bolts -from boxes.lids import _TopEdge - - -class UniversalBox(_TopEdge): - """Box with various options for different styles and lids""" - - ui_group = "Box" - - def __init__(self) -> None: - Boxes.__init__(self) - self.addTopEdgeSettings(roundedtriangle={"outset" : 1}, - hinge={"outset" : True}) - self.addSettingsArgs(edges.FlexSettings) - self.addSettingsArgs(lids.LidSettings) - self.buildArgParser("top_edge", "bottom_edge", - "x", "y", "h", "outside") - self.argparser.add_argument( - "--vertical_edges", action="store", type=str, - default="finger joints", - choices=("finger joints", "finger holes"), - help="connections used for the vertical edges") - - def top_hole(self, x, y, top_edge): - t = self.thickness - - if top_edge == "f": - edge = self.edges["F"] - self.moveTo(2*t+self.burn, 2*t, 90) - elif top_edge == "F": - edge = self.edges["f"] - self.moveTo(t+self.burn, 2*t, 90) - else: - raise ValueError("Only f and F supported") - - for l in (y, x, y, x): - edge(l) - if top_edge == "F": self.edge(t) - self.corner(-90) - if top_edge == "F": self.edge(t) - - def render(self): - x, y, h = self.x, self.y, self.h - t = self.thickness - - tl, tb, tr, tf = self.topEdges(self.top_edge) - b = self.edges.get(self.bottom_edge, self.edges["F"]) - - d2 = Bolts(2) - d3 = Bolts(3) - - d2 = d3 = None - - sideedge = "F" if self.vertical_edges == "finger joints" else "h" - - if self.outside: - self.x = x = self.adjustSize(x, sideedge, sideedge) - self.y = y = self.adjustSize(y) - self.h = h = self.adjustSize(h, b, self.top_edge) - - with self.saved_context(): - self.rectangularWall(x, h, [b, sideedge, tf, sideedge], - ignore_widths=[1, 6], - bedBolts=[d2], move="up", label="front") - self.rectangularWall(x, h, [b, sideedge, tb, sideedge], - ignore_widths=[1, 6], - bedBolts=[d2], move="up", label="back") - - if self.bottom_edge != "e": - self.rectangularWall(x, y, "ffff", bedBolts=[d2, d3, d2, d3], move="up", label="bottom") - if self.top_edge in "fF": - self.set_source_color(Color.MAGENTA) # I don't know why this part has a different color, but RED is not a good choice because RED is used for annotations - self.rectangularWall(x+4*t, y+4*t, callback=[ - lambda:self.top_hole(x, y, self.top_edge)], move="up", label="top hole") - self.set_source_color(Color.BLACK) - self.drawLid(x, y, self.top_edge, [d2, d3]) - self.lid(x, y, self.top_edge) - - self.rectangularWall(x, h, [b, sideedge, tf, sideedge], - ignore_widths=[1, 6], - bedBolts=[d2], move="right only", label="invisible") - self.rectangularWall(y, h, [b, "f", tl, "f"], - ignore_widths=[1, 6], - bedBolts=[d3], move="up", label="left") - self.rectangularWall(y, h, [b, "f", tr, "f"], - ignore_widths=[1, 6], - bedBolts=[d3], move="up", label="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallcaliperholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallcaliperholder.py deleted file mode 100644 index fe98af4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallcaliperholder.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes.walledges import _WallMountedBox - - -class WallCaliper(_WallMountedBox): - """Holds a single caliper to a wall""" - - def __init__(self) -> None: - super().__init__() - - # remove cli params you do not need - self.buildArgParser(h=100) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--width", action="store", type=float, default=18.0, - help="width of the long end") - self.argparser.add_argument( - "--height", action="store", type=float, default=6.0, - help="height of the body") - - def side(self, move=None): - t = self.thickness - h = self.h - hc = self.height - - tw = self.edges["b"].spacing() + hc + 8*t - - if self.move(tw, h, move, True): - return - - self.moveTo(self.edges["b"].startwidth()) - self.polyline(5*t+hc, (90, 2*t), h/2-2*t, (180, 1.5*t), 0.25*h, - -90, hc, -90, 0.75*h-2*t, (90, 2*t), 2*t, 90) - - self.edges["b"](h) - - self.move(tw, h, move) - - def render(self): - self.generateWallEdges() - - t = self.thickness - h = self.h - - self.side(move="right") - self.side(move="right") - w = self.width - self.flangedWall(w, h, flanges=[0, 2*t, 0, 2*t], edges="eeee", - r=2*t, - callback=[lambda:(self.wallHolesAt(1.5*t, 0, h, 90), self.wallHolesAt(w+2.5*t, 0, h, 90))]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallchiselholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallchiselholder.py deleted file mode 100644 index 848aab4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallchiselholder.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - - -class FrontEdge(edges.Edge): - - def __call__(self, length, **kw): - td = self.tooldiameter - rh = self.holediameter / 2.0 - r = self.radius - sw = self.slot_width - - a = math.degrees(math.asin((r+sw/2)/(r+rh))) - l = (td - sw - 2*r) / 2 - - for i in range(self.number): - self.polyline(l, (180-a, r), 0, (-360+2*a, rh), 0, (180-a, r), l) - - - -class WallChiselHolder(_WallMountedBox): - """Wall tool holder for chisels, files and similar tools""" - - def __init__(self) -> None: - super().__init__() - - self.buildArgParser(h=120) - - self.argparser.add_argument( - "--tooldiameter", action="store", type=float, default=30., - help="diameter of the tool including space to grab") - self.argparser.add_argument( - "--holediameter", action="store", type=float, default=30., - help="diameter of the hole for the tool (handle should not fit through)") - self.argparser.add_argument( - "--slot_width", action="store", type=float, default=5., - help="width of slots") - #self.argparser.add_argument( - # "--angle", action="store", type=float, default=0., - # help="angle of the top - positive for leaning backwards") - self.argparser.add_argument( - "--radius", action="store", type=float, default=5., - help="radius at the slots") - self.argparser.add_argument( - "--number", action="store", type=int, default=6, - help="number of tools/slots") - self.argparser.add_argument( - "--hooks", action="store", type=str, default="all", - choices=("all", "odds", "everythird"), - help="amount of hooks / braces") - - def brace(self, i): - n = self.number - if i in (0, n): - return True - # fold for symmetry - #if i > n//2: - # i = n - i - if self.hooks == "all": - return True - elif self.hooks == "odds": - return not (i % 2) - elif self.hooks == "everythird": - return not (i % 3) - - def braces(self): - return sum(self.brace(i) for i in range(self.number+1)) - - def backCB(self): - n = self.number - rt = self.holediameter - wt = self.tooldiameter - t = self.thickness - - d = min(2*t, (wt-rt)/4.) - self.wallHolesAt(d, 0, self.h, 90) - self.wallHolesAt(n*wt-d, 0, self.h, 90) - - for i in range(1, n): - if self.brace(i): - self.wallHolesAt(i*wt, 0, self.h, 90) - - def topCB(self): - n = self.number - rt = self.holediameter - wt = self.tooldiameter - t = self.thickness - l = self.depth - - d = min(2*t, (wt-rt)/4.) - self.fingerHolesAt(d, 0, l, 90) - self.fingerHolesAt(n*wt-d, 0, l, 90) - - for i in range(1, n): - if self.brace(i): - self.fingerHolesAt(i*wt, 0, l, 90) - - def render(self): - self.generateWallEdges() - - t = self.thickness - wt = self.tooldiameter - n = self.number - - self.depth = depth = wt + 4*t - - self.rectangularWall(n*wt, self.h, "eeee", callback=[self.backCB], move="up") - self.rectangularWall(n*wt, depth, [FrontEdge(self, None), "e","e","e"], callback=[self.topCB], move="up") - self.moveTo(0, t) - self.rectangularTriangle(depth, self.h, "fbe", r=3*t, num=self.braces()) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallconsole.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallconsole.py deleted file mode 100644 index 6b769c1..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallconsole.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes.walledges import _WallMountedBox - - -class WallConsole(_WallMountedBox): - """Outset and angled plate to mount stuff to""" - - def __init__(self) -> None: - super().__init__() - - self.buildArgParser(sx=100, h=100, outside=True) - - self.argparser.add_argument( - "--top_depth", action="store", type=float, default=50, - help="depth at the top") - self.argparser.add_argument( - "--bottom_depth", action="store", type=float, default=35, - help="depth at the bottom") - - def backHoles(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.wallHolesAt(posx, 0, self.h, 90) - - def frontHoles(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, self.front, 90) - - def render(self): - - self.generateWallEdges() - - if self.outside: - self.sx = self.adjustSize(self.sx) - self.h = self.adjustSize(self.h) - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - h = self.h - td = self.top_depth - bd = self.bottom_depth - - self.front = (h**2 + (td-bd)**2)**0.5 - - self.rectangularWall(x, h, "eCec", callback=[self.backHoles], - move="up") - self.rectangularWall(x, self.front, "eFeF", - callback=[self.frontHoles], move="up") - - for i in range(len(self.sx)+1): - self.trapezoidWall(h, td, bd, "befe", move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walldrillbox.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walldrillbox.py deleted file mode 100644 index 1789126..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walldrillbox.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - -from .drillstand import DrillStand - - -class WallDrillBox(DrillStand, _WallMountedBox): - """Box for drills with each compartment with a different height""" - ui_group = "WallMounted" - - def __init__(self) -> None: - _WallMountedBox.__init__(self) # don't call DrillStand.__init__ - - self.addSettingsArgs(edges.StackableSettings, height=1.0, width=3) - self.buildArgParser(sx="25*6", sy="10:20:30", sh="25:40:60") - self.argparser.add_argument( - "--extra_height", action="store", type=float, default=15.0, - help="height difference left to right") - - def render(self): - self.generateWallEdges() - - t = self.thickness - sx, sy, sh = self.sx, self.sy, self.sh - self.x = x = sum(sx) + len(sx)*t - t - self.y = y = sum(sy) + len(sy)*t - t - - bottom_angle = math.atan(self.extra_height / x) # radians - - self.xOutsideWall(sh[0], "hFeF", move="up") - for i in range(1, len(sy)): - self.xWall(i, move="up") - self.xOutsideWall(sh[-1], "hCec", move="up") - - self.rectangularWall(x/math.cos(bottom_angle)-t*math.tan(bottom_angle), y, "fefe", callback=[self.bottomCB], move="up") - - self.sideWall(edges="eBf", foot_height=2*t, move="right") - for i in range(1, len(sx)): - self.yWall(i, move="right") - self.sideWall(self.extra_height, foot_height=2*t, edges="eBf", move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walledges.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walledges.py deleted file mode 100644 index 71c5978..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walledges.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes.walledges import _WallMountedBox - - -class WallEdges(_WallMountedBox): - """Shows the different edge types for wall systems""" - - def __init__(self) -> None: - super().__init__() - self.buildArgParser(h=120) - - def render(self): - self.generateWallEdges() - - h = self.h - - self.moveTo(0, 25) - self.rectangularWall( - 40, h, "eAea", move="right", - callback=[lambda : (self.text("a", 0, -20), - self.text("A", 30, -20))]) - self.rectangularWall( - 40, h, "eBeb", move="right", - callback=[lambda : (self.text("b", 0, -20), - self.text("B", 30, -20))]) - self.rectangularWall(40, h, "eCec", - callback=[lambda : (self.text("c", 0, -20), - self.text("C", 30, -20), - self.text("wallHolesAt", -5, -30), - self.wallHolesAt(20, 0, h, 90))], move="right") - self.moveTo(10) - self.rectangularWall( - 40, h, "eDed", move="right", - callback=[lambda : (self.text("d", 0, -20), - self.text("D", 30, -20))]) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallpinrow.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallpinrow.py deleted file mode 100644 index 18ff72e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallpinrow.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - - -class PinEdge(edges.BaseEdge): - def __call__(self, length, **kw): - w2 = self.settings.pinwidth/2 - l = self.settings.pinlength - s = self.settings.pinspacing - inc = self.settings.pinspacing_increment - t = self.settings.thickness - - pin = [0, -90, l+t-w2, (180, w2), l+t-w2, -90] - - self.edge(s/2-w2) - s += inc/2 - for i in range(self.pins-1): - self.polyline(*pin, s-2*w2) - s+=inc - self.polyline(*pin, s/2-w2-inc/4) - - def margin(self) -> float: - return self.settings.thickness+self.settings.pinlength - -class WallPinRow(_WallMountedBox): - """Outset and angled plate to mount stuff to""" - - def __init__(self) -> None: - super().__init__() - - self.argparser.add_argument( - "--pins", action="store", type=int, default=8, - help="number of pins") - self.argparser.add_argument( - "--pinlength", action="store", type=float, default=35, - help="length of pins (in mm)") - self.argparser.add_argument( - "--pinwidth", action="store", type=float, default=10, - help="width of pins (in mm)") - self.argparser.add_argument( - "--pinspacing", action="store", type=float, default=35, - help="space from middle to middle of pins (in mm)") - self.argparser.add_argument( - "--pinspacing_increment", action="store", type=float, default=0.0, - help="increase spacing from left to right (in mm)") - self.argparser.add_argument( - "--angle", action="store", type=float, default=20.0, - help="angle of the pins pointing up (in degrees)") - - self.argparser.add_argument( - "--hooks", action="store", type=int, default=3, - help="number of hooks into the wall") - self.argparser.add_argument( - "--h", action="store", type=float, default=50.0, - help="height of the front plate (in mm) - needs to be at least 7 time the thickness") - - def frontCB(self): - s = self.pinspacing - inc = self.pinspacing_increment - t = self.thickness - - pos = s/2 - s += 0.5*inc - for i in range(self.pins): - self.rectangularHole(pos, 2*t, self.pinwidth, t) - pos += s - s+=inc - - for i in range(1, self.hooks-1): - self.fingerHolesAt(i*self.x/(self.hooks-1), self.h/2, self.h/2) - - - def backCB(self): - t = self.thickness - self.fingerHolesAt(0, 2*t, self.x, 0) - if self.angle < 0.001: - return - for i in range(1, self.hooks-1): - self.fingerHolesAt(i*self.x/(self.hooks-1), 3*t, self.h/2-3*t) - - def sideWall(self, move=None): - a = self.angle - ar = math.radians(a) - h = self.h - t = self.thickness - - sh = math.sin(ar)*6*t + math.cos(ar)*h - - tw = self.edges["a"].margin() + math.sin(ar)*h + math.cos(ar)*6*t - th = sh + 6 - if self.move(tw, th, move, True): - return - - self.moveTo(self.edges["a"].margin()) - - self.polyline(math.sin(ar)*h, a, 4*t) - self.fingerHolesAt(-3.5*t, 0, h/2, 90) - self.edgeCorner("e", "h") - self.edges["h"](h) - self.polyline(0, 90-a, math.cos(ar)*6*t, 90) - self.edges["a"](sh) - self.corner(90) - - self.move(tw, th, move) - - - def supportWall(self, move=None): - a = self.angle - ar = math.radians(a) - h = self.h - t = self.thickness - - sh = math.sin(ar)*6*t + math.cos(ar)*h - - tw = self.edges["a"].margin() + max( - math.sin(ar)*h/2 + math.cos(ar)*5*t, - math.sin(ar)*h) - th = sh + 6 - if self.move(tw, th, move, True): - return - - self.moveTo(self.edges["a"].margin()) - - if a > 0.001: - self.polyline(math.sin(ar)*h, a+90, 3*t) - self.edges["f"](h/2-3*t) - self.polyline(0, -90) - self.polyline(4*t, 90) - self.edges["f"](h/2) - self.polyline(math.sin(ar)*2*t, 90-a, - math.cos(ar)*4*t - math.sin(ar)**2*2*t, 90) - if a > 0.001: - self.edges["a"](sh) - else: - self.edges["a"](h/2) - self.corner(90) - - self.move(tw, th, move) - - - def render(self): - self.generateWallEdges() - - p = PinEdge(self, self) - n = self.pins - t = self.thickness - - if self.h < 7*t: - self.h = 7*t - - self.x = x = n*self.pinspacing + (n)*(n-1)/2 *self.pinspacing_increment - - - self.rectangularWall(x, 3*t, [p, "e", "f", "e"], move="up") - self.rectangularWall(x, self.h, "efef", callback=[self.frontCB], - move="up") - self.rectangularWall(x, self.h/2, "efef", callback=[self.backCB], - move="up") - self.sideWall(move="right") - for i in range(self.hooks-2): - self.supportWall(move="right") - self.sideWall(move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallplaneholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallplaneholder.py deleted file mode 100644 index e4e9aca..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallplaneholder.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes.walledges import _WallMountedBox - - -class WallPlaneHolder(_WallMountedBox): - """Hold a plane to a wall""" - - def __init__(self) -> None: - super().__init__() - - self.argparser.add_argument( - "--width", action="store", type=float, default=80, - help="width of the plane") - self.argparser.add_argument( - "--length", action="store", type=float, default=250, - help="length of the plane") - self.argparser.add_argument( - "--hold_length", action="store", type=float, default=30, - help="length of the part holding the plane over the front") - self.argparser.add_argument( - "--height", action="store", type=float, default=80, - help="height of the front of plane") - - def side(self): - l, w, h = self.length, self.width, self.height - hl = self.hold_length - t = self.thickness - self.fingerHolesAt(1.5*t, 2*t, 0.25*l, 90) - self.fingerHolesAt(1.5*t, 2*t+0.75*l, 0.25*l, 90) - self.fingerHolesAt(2.5*t+h, 2*t+l-hl, hl, 90) - self.fingerHolesAt(2*t, 1.5*t, h+2*t, 0) - - def render(self): - self.generateWallEdges() - - l, w, h = self.length, self.width, self.height - t = self.thickness - self.rectangularWall(h+4*t, l+2*t, "eeea", callback=[self.side], - move="right") - self.rectangularWall(h+4*t, l+2*t, "eeea", callback=[self.side], - move="right") - self.rectangularWall(w, h+2*t, "efFf", move="up") - self.rectangularWall(w, 0.25*l, "ffef", move="up") - self.rectangularWall(w, 0.25*l, "efef", move="up") - self.rectangularWall(w, self.hold_length, "efef", move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallpliersholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallpliersholder.py deleted file mode 100644 index 40a62f3..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallpliersholder.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - - -class WallPliersHolder(_WallMountedBox): - """Bar to hang pliers on""" - - def __init__(self) -> None: - super().__init__() - - self.buildArgParser(sx="100*3", y=50, h=50, outside=True) - - self.argparser.add_argument( - "--angle", action="store", type=float, default=45, - help="bracing angle - less for more bracing") - - def brace(self, h, d, a, outside=False, move=None): - t = self.thickness - - tw = d + self.edges["b"].spacing() + self.edges["f"].spacing() - th = self.h_t - - if self.move(tw, th, move, True): - return - - self.moveTo(self.edges["b"].spacing()) - - r = d / 4 - l = (d + t - r) / math.sin(math.radians(a)) - - if outside: - self.polyline(t, (90-a, r), l, (a, r)) - self.edges["h"](h) - self.polyline(0, 90, d + 2*t, 90) - else: - self.polyline(0, (90-a, r), l, (a, r), 0, 90, t, -90) - self.edges["f"](h) - self.polyline(0, 90, d, 90) - self.edges["b"](h + (d+t-r) * math.tan(math.radians(90-a)) + r) - self.polyline(0, 90) - - self.move(tw, th, move) - - def frontCB(self): - t = self.thickness - posx = -t - for dx in self.sx[:-1]: - posx += dx + t - self.fingerHolesAt(posx, 0, self.h, 90) - - def backCB(self): - t = self.thickness - posx = -t - for dx in self.sx[:-1]: - posx += dx + t - self.wallHolesAt(posx, 0, self.h_t, 90) - - def render(self): - self.generateWallEdges() - - if self.outside: - self.sx = self.adjustSize(self.sx) - - sx, y, h = self.sx, self.y, self.h - t = self.thickness - - r = y / 4 - self.h_t = h + (y+t-r) * math.tan(math.radians(90-self.angle)) + r - - self.rectangularWall(sum(sx) + (len(sx)-1) * t, h, "efef", callback=[self.frontCB], move="up") - self.rectangularWall(sum(sx) + (len(sx)-1) * t, self.h_t, "eCec", callback=[self.backCB], move="up") - for i in range(len(sx)+1): - self.brace(h, y, self.angle, i<2, move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallrack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallrack.py deleted file mode 100644 index d28b7f8..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallrack.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (C) 2013-2023 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from functools import partial - -from boxes import * - - -class WallRack(Boxes): - """Wall mountable rack for spices or other items""" - - ui_group = "WallMounted" - - def __init__(self): - Boxes.__init__(self) - - self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1.0) - self.addSettingsArgs(edges.MountingSettings) - self.addSettingsArgs(edges.HandleEdgeSettings) - - self.buildArgParser(x=200, y=50, sh="100*3", outside=False) - self.argparser.add_argument( - "--top_edge", action="store", - type=ArgparseEdgeType("eEGy"), choices=list("eEGy"), - default="G", help="edge type for top edge") - self.argparser.add_argument("--full_height_top", type=boolarg, default=True, help="Add full height of topmost rack to the back panel") - self.argparser.add_argument( - "--wall_height", action="store", type=float, default=20.0, - help="height of walls") - self.argparser.add_argument( - "--back_height", action="store", type=float, default=1.5, - help="height of the back as fraction of the front height") - self.argparser.add_argument( - "--side_edges", action="store", - type=ArgparseEdgeType("Fh"), choices=list("Fh"), - default="h", help="edge type holding the shelfs together") - self.argparser.add_argument( - "--flat_bottom", type=boolarg, default=False, help="Make bottom Flat, so that the rack can also stand") - - def generate_shelves(self, x, y, front_height, back_height): - se = self.side_edges - for i in range(len(self.sh)): - self.rectangularWall(x, y, "ffff", move="up", label=f"shelf {i+1}") - self.rectangularWall(x, front_height, se + "fef", move="up", label=f"front lip {i+1}") - self.trapezoidWall(y, front_height, back_height, se + "fe" + se, move="right", label=f"right lip {i+1}") - self.trapezoidWall(y, front_height, back_height, se + "fe" + se, move="up", label=f"left lip {i+1}") - self.move(y + self.thickness*2, back_height, "left", before=True) - - #Generate finger holes for back part - def generate_finger_holes(self, x, back_height): - t = self.thickness - pos_y = 0 - for h in self.sh: - self.fingerHolesAt(t*0.5, pos_y + 0.5*t, x, 0) - self.fingerHolesAt(0, pos_y + t, back_height, 90) - self.fingerHolesAt(x+t, pos_y + t, back_height, 90) - pos_y += h - - def render(self): - x, y, front_height = self.x, self.y, self.wall_height - back_height = front_height * self.back_height - t = self.thickness - if self.outside: - x = self.adjustSize(x, "h", "f") - y = self.adjustSize(y) - front_height = self.adjustSize(front_height) - back_height = self.adjustSize(back_height) - - if self.full_height_top: - total_height = sum(self.sh) - else: - total_height = sum(self.sh[:-1]) + back_height - - be = "e" if self.flat_bottom and self.side_edges == "F" else "E" - if be == "E" and self.full_height_top: - total_height -= t - - self.rectangularWall(x+self.thickness, total_height, be + "E" + self.top_edge + "E", - callback=[partial(self.generate_finger_holes, x, back_height)], label="back wall", move="right") - self.generate_shelves(x, y, front_height, back_height) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallrollholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallrollholder.py deleted file mode 100644 index 579c0c4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallrollholder.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - - -class WallRollHolder(_WallMountedBox): - """Holder for kitchen rolls or other rolls""" - - description = """Needs a dowel or pipe as axle.""" - - ui_group = "WallMounted" - - def __init__(self) -> None: - super().__init__() - - self.argparser.add_argument( - "--width", action="store", type=float, default=275, - help="length of the axle in mm") - self.argparser.add_argument( - "--diameter", action="store", type=float, default=120, - help="maximum diameter of the roll in mm (choose generously)") - self.argparser.add_argument( - "--height", action="store", type=float, default=80, - help="height of mounting plate in mm") - self.argparser.add_argument( - "--axle", action="store", type=float, default=25, - help="diameter of the axle in mm including play") - - def side(self, move=None): - d = self.diameter - a = self.axle - h = self.height - t = self.thickness - - tw, th = h, (d + a) / 2 + 3 * t + self.edges["B"].spacing() - - if self.move(tw, th, move, True): - return - - self.moveTo(0, self.edges["B"].margin()) - self.edges["B"](h) - self.fingerHolesAt(-(a/2+3*t), self.burn+self.edges["B"].endwidth(), d/2, 90) - self.polyline(0, 90, self.edges["B"].endwidth() + d/2, - (90, a/2 + 3*t)) - - r = a/2 + 3*t - a = math.atan2(float(d/2), (h-a-6*t)) - alpha = math.degrees(a) - - self.corner(alpha, r) - self.edge(((h-2*r)**2+(d/2)**2)**0.5) - self.corner(90-alpha, r) - self.edge(self.edges["B"].startwidth()) - self.corner(90) - - self.move(tw, th, move) - - def backCB(self): - t = self.thickness - a = self.axle - h = self.height - w = self.width - - plate = w + 2*t + h/2 - - self.wallHolesAt(h/4+t/2-3*t, 0, h, 90) - self.fingerHolesAt(h/4-3*t, h-3*t-a/2, h/4, 180) - - self.wallHolesAt(h/4+t/2+t-3*t+w, 0, h, 90) - self.fingerHolesAt(h/4+2*t-3*t+w, h-3*t-a/2, h/4, 0) - - def rings(self): - a = self.axle - r = a/2 - t = self.thickness - - self.moveTo(0, a+1.5*t, -90) - for i in range(2): - self.polyline(r-1.5*t, (180, r+3*t), 0, (180, 1.5*t), 0, - (-180, r), r-1.5*t, (180, 1.5*t)) - self.moveTo(a-t, a+12*t, 180) - - - def render(self): - - self.generateWallEdges() - - t = self.thickness - w = self.width - d = self.diameter - a = self.axle - h = self.height - - self.height = h = max(h, a+10*t) - - self.side(move="right") - self.side(move="right") - - self.rectangularTriangle(h/4, d/2, "ffe", num=2, r=3*t, move="right") - - self.roundedPlate(w+h/2+2*t, h, edge="e", r=3*t, - extend_corners=False, - callback=[self.backCB], move="right") - self.rings() diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallslottedholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallslottedholder.py deleted file mode 100644 index 61bf43d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallslottedholder.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - - -class FrontEdge(edges.Edge): - - def __call__(self, length, **kw): - ws = self.slot_width - wt = self.tool_width - ds = self.slot_depth - r1 = min(self.radius, ds/2, (wt-ws)/2) - r2 = min(self.radius, ws/2) - w = (wt-ws)/2 - r1 - for i in range(self.number): - self.polyline(w, (90, r1), ds-r1-r2, (-90, r2), ws-2*r2, - (-90, r2), ds-r1-r2, (90, r1), w) - -class WallSlottedHolder(_WallMountedBox): - """Wall tool holder with slots""" - - def __init__(self) -> None: - super().__init__() - - self.buildArgParser(h=120) - - self.argparser.add_argument( - "--slot_depth", action="store", type=float, default=50., - help="depth of slots from the front") - self.argparser.add_argument( - "--additional_depth", action="store", type=float, default=50., - help="depth behind the lots") - self.argparser.add_argument( - "--slot_width", action="store", type=float, default=5., - help="width of slots") - self.argparser.add_argument( - "--tool_width", action="store", type=float, default=35., - help="overall width for the tools") - #self.argparser.add_argument( - # "--angle", action="store", type=float, default=0., - # help="angle of the top - positive for leaning backwards") - self.argparser.add_argument( - "--radius", action="store", type=float, default=5., - help="radius of the slots at the front") - self.argparser.add_argument( - "--number", action="store", type=int, default=6, - help="number of tools/slots") - self.argparser.add_argument( - "--hooks", action="store", type=str, default="all", - choices=("all", "odds", "everythird"), - help="amount of hooks / braces") - - def brace(self, i): - n = self.number - if i in (0, n): - return True - # fold for symmetry - #if i > n//2: - # i = n - i - if self.hooks == "all": - return True - elif self.hooks == "odds": - return not (i % 2) - elif self.hooks == "everythird": - return not (i % 3) - - def braces(self): - return sum(self.brace(i) for i in range(self.number+1)) - - def backCB(self): - n = self.number - ws = self.slot_width - wt = self.tool_width - t = self.thickness - - d = min(2*t, (wt-ws)/4.) - self.wallHolesAt(d, 0, self.h, 90) - self.wallHolesAt(n*wt-d, 0, self.h, 90) - - for i in range(1, n): - if self.brace(i): - self.wallHolesAt(i*wt, 0, self.h, 90) - - def topCB(self): - n = self.number - ws = self.slot_width - wt = self.tool_width - t = self.thickness - l = self.additional_depth + self.slot_depth - - d = min(2*t, (wt-ws)/4.) - self.fingerHolesAt(d, 0, l, 90) - self.fingerHolesAt(n*wt-d, 0, l, 90) - - for i in range(1, n): - if self.brace(i): - self.fingerHolesAt(i*wt, 0, l, 90) - - def render(self): - self.generateWallEdges() - - t = self.thickness - l1, l2 = self.additional_depth, self.slot_depth - ws = self.slot_width - wt = self.tool_width - n = self.number - - self.rectangularWall(n*wt, self.h, "eeee", callback=[self.backCB], move="up") - self.rectangularWall(n*wt, l1+l2, [FrontEdge(self, None), "e","e","e"], callback=[self.topCB], move="up") - self.moveTo(0, t) - self.rectangularTriangle(l1+l2, self.h, "fbe", r=3*t, num=self.braces()) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallstairs.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallstairs.py deleted file mode 100644 index f67518e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallstairs.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes.walledges import _WallMountedBox - - -class WallStairs(_WallMountedBox): - """Platforms in different heights e.g. for screw drivers""" - - description = """You are supposed to add holes or slots to the stair tops yourself using Inkscape or another vector drawing or CAD program. - -sh gives height of the stairs from front to back. Note that the overall width and height is bigger than the nominal values as walls and the protrusions are not included in the measurements. -""" - def __init__(self) -> None: - super().__init__() - - self.buildArgParser(sx="250/3", sy="40*3", sh="30:100:180") - self.argparser.add_argument( - "--braceheight", action="store", type=float, default=30, - help="height of the brace at the bottom back (in mm). Zero for none") - - def yWall(self, move=None): - t = self.thickness - x, sx, y, sy, sh = self.x, self.sx, self.y, self.sy, self.sh - - tw, th = sum(sy), max(sh) + t - - if self.move(tw, th, move, True): - return - - self.polyline(y-t, 90) - self.edges["f"](self.braceheight) - self.step(t) - self.edges["A"](sh[-1] - self.braceheight) - self.corner(90) - for i in range(len(sy)-1, 0, -1): - self.edges["f"](sy[i]) - self.step(sh[i-1]-sh[i]) - self.edges["f"](sy[0]) - self.polyline(0, 90, sh[0], 90) - - self.move(tw, th, move) - - def yCB(self, width): - t = self.thickness - posx = -0.5 * t - for dx in self.sx[:-1]: - posx += dx + t - self.fingerHolesAt(posx, 0, width, 90) - - - def render(self): - self.generateWallEdges() - - self.extra_height = 20 - t = self.thickness - sx, sy, sh = self.sx, self.sy, self.sh - self.x = x = sum(sx) + len(sx)*t - t - self.y = y = sum(sy) - - for w in sy: - self.rectangularWall( - x, w, "eheh", callback=[lambda:self.yCB(w)], move="up") - if self.braceheight: - self.rectangularWall( - x, self.braceheight, "eheh", - callback=[lambda:self.yCB(self.braceheight)], move="up") - - for i in range(len(sx) + 1): - self.yWall(move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walltypetray.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walltypetray.py deleted file mode 100644 index 3d84fb9..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/walltypetray.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.lids import _TopEdge -from boxes.walledges import _WallMountedBox - - -class WallTypeTray(_WallMountedBox, _TopEdge): - """Type tray - allows only continuous walls""" - - def __init__(self) -> None: - super().__init__() - self.addSettingsArgs(edges.StackableSettings) - self.buildArgParser("sx", "sy", "h", "hi", "outside", "bottom_edge") - self.argparser.add_argument( - "--back_height", action="store", type=float, default=0.0, - help="additional height of the back wall") - self.argparser.add_argument( - "--radius", action="store", type=float, default=0.0, - help="radius for strengthening walls with the hooks") - - - def xSlots(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - posy = 0 - for y in self.sy: - self.fingerHolesAt(posx, posy, y) - posy += y + self.thickness - - def ySlots(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - posx = 0 - for x in reversed(self.sx): - self.fingerHolesAt(posy, posx, x) - posx += x + self.thickness - - def xHoles(self): - posx = -0.5 * self.thickness - for x in self.sx[:-1]: - posx += x + self.thickness - self.fingerHolesAt(posx, 0, self.hi) - - def yHoles(self): - posy = -0.5 * self.thickness - for y in self.sy[:-1]: - posy += y + self.thickness - self.fingerHolesAt(posy, 0, self.hi) - - def render(self): - - self.generateWallEdges() - b = self.bottom_edge - - if self.outside: - self.sx = self.adjustSize(self.sx) - self.sy = self.adjustSize(self.sy) - self.h = self.adjustSize(self.h, b, e2=False) - if self.hi: - self.hi = self.adjustSize(self.hi, b, e2=False) - - x = sum(self.sx) + self.thickness * (len(self.sx) - 1) - y = sum(self.sy) + self.thickness * (len(self.sy) - 1) - h = self.h - bh = self.back_height - sameh = not self.hi - hi = self.hi = self.hi or h - t = self.thickness - - - # outer walls - # x sides - - self.ctx.save() - - # outer walls - self.rectangularWall(x, h, [b, "f", "e", "f"], callback=[self.xHoles], move="up") - self.rectangularWall(x, h+bh, [b, "C", "e", "c"], callback=[self.mirrorX(self.xHoles, x), ], move="up") - - # floor - if b != "e": - self.rectangularWall(x, y, "ffff", callback=[ - self.xSlots, self.ySlots], move="up") - - # Inner walls - - be = "f" if b != "e" else "e" - - for i in range(len(self.sy) - 1): - e = [edges.SlottedEdge(self, self.sx, be), "f", - edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * hi), "f"] - - self.rectangularWall(x, hi, e, move="up") - - # y walls - - # outer walls - self.trapezoidSideWall(y, h, h+bh, [b, "B", "e", "h"], radius=self.radius, callback=[self.yHoles, ], move="up") - self.moveTo(0, 8) - self.trapezoidSideWall(y, h+bh, h, [b, "h", "e", "b"], radius=self.radius, callback=[self.mirrorX(self.yHoles, y), ], move="up") - self.moveTo(0, 8) - - # inner walls - for i in range(len(self.sx) - 1): - e = [edges.SlottedEdge(self, self.sy, be, slots=0.5 * hi), - "f", "e", "f"] - self.rectangularWall(y, hi, e, move="up") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallwrenchholder.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallwrenchholder.py deleted file mode 100644 index 6d22c2d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wallwrenchholder.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2013-2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * -from boxes.walledges import _WallMountedBox - - -class SlottedEdge(edges.Edge): - - def __call__(self, length, **kw): - - n = self.number - t = self.thickness - - self.polyline(t, 45) - - l = t - - for i in range(n): - w = self.min_width * ((n-i)/n) + self.max_width * (i / n) - s = self.min_strength * ((n-i)/n) + self.max_strength * (i / n) - if i == n-1: - self.polyline(w-s/2+2*s, (-180, s/2), w - 0.5*s, - (180, s/2)) - l += s *2 * 2**0.5 - else: - self.polyline(w-s/2+2*s, (-180, s/2), w - 0.5*s, - (135, s/2), self.extra_distance, (45, s/2)) - l += s *2 * 2**0.5 + self.extra_distance - self.polyline(0, -45) - self.edge(length-l) - -class WallWrenchHolder(_WallMountedBox): - """Hold a set of wrenches at a wall""" - - - def __init__(self) -> None: - super().__init__() - - # remove cli params you do not need - self.buildArgParser(x=100) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--depth", action="store", type=float, default=30.0, - help="depth of the sides (in mm)") - self.argparser.add_argument( - "--number", action="store", type=int, default=11, - help="number of wrenches (in mm)") - self.argparser.add_argument( - "--min_width", action="store", type=float, default=8.0, - help="width of smallest wrench (in mm)") - self.argparser.add_argument( - "--max_width", action="store", type=float, default=25.0, - help="width of largest wrench (in mm)") - self.argparser.add_argument( - "--min_strength", action="store", type=float, default=3.0, - help="strength of smallest wrench (in mm)") - self.argparser.add_argument( - "--max_strength", action="store", type=float, default=5.0, - help="strength of largest wrench (in mm)") - self.argparser.add_argument( - "--extra_distance", action="store", type=float, default=0.0, - help="additional distance between wrenches (in mm)") - - - def render(self): - self.generateWallEdges() - - h = ((self.min_strength + self.max_strength) * self.number * 2**0.5 - + self.extra_distance * (self.number - 1) - + self.max_width) - t = self.thickness - x = self.x-2*t - - self.rectangularWall(self.depth, h, - ["e", "B", "e", SlottedEdge(self, None)], - move="right") - self.rectangularWall(self.depth, h, - ["e", "B", "e", SlottedEdge(self, None)], - move="right") - self.rectangularWall(x, h, "eDed", - # callback=[lambda:self.fingerHolesAt(x/2, 0, h, 90)], - move="right") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wavyknob.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wavyknob.py deleted file mode 100644 index e20883d..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/wavyknob.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class WavyKnob(Boxes): - """Round knob serrated outside for better gripping""" - - ui_group = "Part" - - def __init__(self) -> None: - Boxes.__init__(self) - - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--diameter", action="store", type=float, default=50., - help="Diameter of the knob (mm)") - self.argparser.add_argument( - "--serrations", action="store", type=int, default=20, - help="Number of serrations") - self.argparser.add_argument( - "--serrationangle", action="store", type=float, default=45., - help="higher values for deeper serrations (degrees)") - self.argparser.add_argument( - "--bolthole", action="store", type=float, default=6., - help="Diameter of the bolt hole (mm)") - self.argparser.add_argument( - "--dhole", action="store", type=float, default=1., - help="D-Flat in fraction of the diameter") - self.argparser.add_argument( - "--hexhead", action="store", type=float, default=10., - help="Width of the hex bolt head (mm)") - - def render(self): - t = self.thickness - angle = self.serrationangle - self.parts.wavyKnob(self.diameter, self.serrations, angle, - callback=lambda:self.dHole(0, 0, d=self.bolthole, - rel_w=self.dhole), - move="right") - self.parts.wavyKnob(self.diameter, self.serrations, angle, - callback=lambda: self.nutHole(self.hexhead), - move="right") - self.parts.wavyKnob(self.diameter, self.serrations, angle) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/winerack.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/winerack.py deleted file mode 100644 index de89971..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/generators/winerack.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (C) 2013-2016 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from boxes import * - - -class WineRack(Boxes): - """Honey Comb Style Wine Rack""" - - ui_group = "Shelf" - - def __init__(self) -> None: - Boxes.__init__(self) - - # Uncomment the settings for the edge types you use - self.addSettingsArgs(edges.FingerJointSettings) - - # remove cli params you do not need - self.buildArgParser(x=400, y=300, h=210) - # Add non default cli params if needed (see argparse std lib) - self.argparser.add_argument( - "--radius", action="store", type=float, default=46., - help="Radius of comb") - self.argparser.add_argument( - "--walls", action="store", type=str, default="all", - choices=("minimal", "no_verticals", "all"), - help="which of the honey comb walls to add") - - def hexFingerHoles(self, x, y, l, angle=90): - with self.saved_context(): - self.moveTo(x, y, angle) - self.moveTo(self.delta, 0, 0) - self.fingerHolesAt(0, 0, l-2*self.delta, 0) - - def wallCB(self, frontwall=False, backwall=False): - r = self.r - x, y, h = self.x, self.y, self.h - dx, dy = self.dx, self.dy - cx, cy = self.cx, self.cy - t = self.thickness - - if cy % 2: - ty = cy // 2 * (2*dy + 2*r) + 2*dy + r - else: - ty = cy // 2 * (2*dy + 2*r) + dy - - self.moveTo((x-dx*2*cx)/2, (y-ty) / 2) - - wmin = self.walls == "minimal" - - for i in range(cy//2 + cy % 2): - if not frontwall and self.walls == "all": - self.hexFingerHoles(0, (2*r+2*dy)*i+dy, r, 90) - for j in range(cx): - if not backwall: - self.hole(j*2*dx+dx, (2*r+2*dy)*i + r, dx-t) - if frontwall: - continue - self.hexFingerHoles(j*2*dx+dx, (2*r+2*dy)*i, r, 150) - self.hexFingerHoles(j*2*dx+dx, (2*r+2*dy)*i, r, 30) - if self.walls == "all": - self.hexFingerHoles(j*2*dx+2*dx, (2*r+2*dy)*i+dy, r, 90) - if wmin and i == cy//2: # top row - continue - if j>0 or not wmin: - self.hexFingerHoles(j*2*dx+dx, (2*r+2*dy)*i+r+2*dy, r, -150) - if j 0: - self.hexFingerHoles(j*2*dx+dx, (2*r+2*dy)*i, r, 150) - if j < cx -1: - self.hexFingerHoles(j*2*dx+dx, (2*r+2*dy)*i, r, 30) - - - def render(self): - x, y, h, radius = self.x, self.y, self.h, self.radius - - t = self.thickness - r = self.r = 2 * (radius + t) * math.tan(math.pi/6) - - self.dx = dx = r * math.cos(math.pi/6) - self.dy = dy = r * math.sin(math.pi/6) - self.cx = cx = int((x-2*t) // (2*dx)) - self.cy = cy = int((y-dy-t) // (r+dy)) - self.delta = 3**0.5/6.*t - - self.rectangularWall(x, y, callback=[self.wallCB], move="up") - self.rectangularWall(x, y, callback=[lambda:self.wallCB(backwall=True)], move="up") - self.rectangularWall(x, y, callback=[lambda:self.wallCB(frontwall=True)], move="up") - if self.walls == "all": - tc = (cy//2 + cy % 2) * (6 * cx + 1) - else: - tc = (cy//2 + cy % 2) * (4 * cx) - - if self.walls == "minimal": - tc -= 2 * (cy//2) # roofs of outer cells - - if cy % 2: - if self.walls == "all": - tc -= cx - else: - if self.walls != "minimal": - tc += 2 * cx - 2 # very top row - - self.partsMatrix(tc, cx, "up", self.rectangularWall, r-2*self.delta, h, "fefe") diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/lids.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/lids.py deleted file mode 100644 index 6a8b878..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/lids.py +++ /dev/null @@ -1,337 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from __future__ import annotations - -import math -from typing import Any, Callable - -import boxes -from boxes import Boxes, edges - - -class LidSettings(edges.Settings): - """Settings for the Lid -Values: -* absolute - - * style : "none" : type of lid to create - * handle : "none" : type of handle - -* relative (in multiples of thickness) - - * height : 4.0 : height of the brim (if any) - * play : 0.1 : play when sliding the lid on (if applicable) - * handle_height : 8.0 : height of the handle (if applicable) - """ - absolute_params = { - "style": ("none", "flat", "chest", "overthetop", "ontop"), - "handle": ("none", "long_rounded", "long_trapezoid", "long_doublerounded", "knob"), - } - - relative_params = { - "height": 4.0, - "play": 0.1, - "handle_height": 8.0, - } - - -class Lid: - def __init__(self, boxes, settings: LidSettings) -> None: - self.boxes = boxes - self.settings = settings - - def __getattr__(self, name: str) -> Any: - """Hack for using unaltered code form Boxes class""" - if hasattr(self.settings, name): - return getattr(self.settings, name) - return getattr(self.boxes, name) - - def __call__(self, x: float, y: float, edge=None) -> bool: - t = self.thickness - style = self.settings.style - height = self.height - if style == "flat": - self.rectangularWall(x, y, "eeee", - callback=[self.handleCB(x, y)], - move="up", label="lid bottom") - self.rectangularWall(x, y, "EEEE", - callback=[self.handleCB(x, y)], - move="up", label="lid top") - elif style == "chest": - self.chestSide(x, move="right", label="lid right") - self.chestSide(x, move="up", label="lid left") - self.chestSide(x, move="left only", label="invisible") - self.chestTop(x, y, - callback=[None, self.handleCB(x, 3*t)], - move="up", label="lid top") - elif style in ("overthetop", "ontop"): - x2 = x - y2 = y - b = { - "Š": "š", - "S": "š", - }.get(edge, "e") - if style == "overthetop": - x2 += 2*t + self.play - y2 += 2*t + self.play - self.rectangularWall(x2, y2, "ffff", - callback=[self.handleCB(x2, y2)], - move="up") - self.rectangularWall(x2, self.height, b +"FFF", - ignore_widths=[1, 2, 5, 6], move="up") - self.rectangularWall(x2, self.height, b + "FFF", - ignore_widths=[1, 2, 5, 6], move="up") - self.rectangularWall(y2, self.height, b + "fFf", - ignore_widths=[1, 2, 5, 6], move="up") - self.rectangularWall(y2, self.height, b + "fFf", - ignore_widths=[1, 2, 5, 6], move="up") - if style == "ontop": - self.rectangularWall(y - self.play, height + 2*t, "eeee", - move="up") - self.rectangularWall(y - self.play, height + 2*t, "eeee", - move="up") - else: - return False - - self.handleParts(x, y) - return True - - ###################################################################### - ### Handles - ###################################################################### - - def handleCB(self, x: float, y: float) -> Callable: - t = self.thickness - - def cb() -> None: - if self.handle.startswith("long"): - self.rectangularHole(x/2, y/2, x/2, t) - elif self.handle.startswith("knob"): - h = v = 3 * t # adjust for different styles - self.moveTo((x - t) / 2 + self.burn, (y - t) / 2 + self.burn, 180) - self.ctx.stroke() - with self.saved_context(): - self.set_source_color(boxes.Color.INNER_CUT) - for l in (h, v, h, v): - self.polyline(l, -90, t, -90, l, 90) - self.ctx.stroke() - - return cb - - def longHandle(self, x:float, y: float, style="long_rounded", move=None) -> None: - t = self.settings.thickness - hh = self.handle_height - tw, th = x/2 + 2*t, self.handle_height + 2*t - - if self.move(tw, th, move, True): - return - - self.moveTo(0.5*t) - - poly = [(90, t/2), t/2, 90, t, -90] - - if style == "long_rounded": - r = min(hh/2, x/4) - poly += [t + hh - r, (90, r)] - l = x/2 - 2*r - elif style == "long_trapezoid": - poly += [t, (45, t), (hh - t) * 2**.5, (45, t)] - l = x/2 - 2 * hh - elif style == "long_doublerounded": - poly += [t, 90, 0, (-90, hh /2), 0, (90, hh/2)] - l = x/2 - 2*hh - - poly = [x/2+t] + poly + [l] + list(reversed(poly)) - self.polyline(*poly) - - self.move(tw, th, move) - - def knobHandle(self, x: float, y: float, style, move=None) -> None: - t = self.settings.thickness - hh = self.handle_height - tw, th = 2 * 7 * t + self.spacing, self.handle_height + 2*t - - if self.move(tw, th, move, True): - return - - poly = [(90, t/2), t/2, 90, t/2, -90] - - poly += [hh - 2*t, (90, 3*t)] - - for bottom, top in (([3*t, 90, 2*t + hh/2, -90, t, -90, hh/2 + 2*t, 90, 3*t], [t]), - ([7*t], [0, 90, hh/2, -90, t, -90, hh/2, 90, 0])) : - self.moveTo(0.5*t) - p = bottom + poly + top + list(reversed(poly)) - self.polyline(*p) - self.moveTo(tw/2 + self.spacing) - - self.move(tw, th, move) - - def handleParts(self, x: float, y: float) -> None: - if self.handle.startswith("long"): - self.longHandle(x, y, self.handle, move="up") - elif self.handle.startswith("knob"): - self.knobHandle(x, y, self.handle, move="up") - - ###################################################################### - ### Chest Lid - ###################################################################### - - def getChestR(self, x: float, angle: float = 0) -> float: - t = self.thickness - d = x - 2*math.sin(math.radians(angle)) * (3*t) - - r = d / 2.0 / math.cos(math.radians(angle)) - return r - - def chestSide(self, x: float, angle: float = 0, move="", label: str = "") -> None: - if "a" not in self.edges: - s = edges.FingerJointSettings(self.thickness, True, - finger=1.0, space=1.0) - s.edgeObjects(self, "aA.") - - t = self.thickness - r = self.getChestR(x, angle) - if self.move(x+2*t, 0.5*x+3*t, move, True, label=label): - return - - self.moveTo(t, 0) - self.edge(x) - self.corner(90+angle) - self.edges["a"](3*t) - self.corner(180-2*angle, r) - self.edges["a"](3*t) - self.corner(90+angle) - - self.move(x+2*t, 0.5*x+3*t, move, False, label=label) - - def chestTop(self, x: float, y: float, angle: float = 0, callback=None, move=None, label: str = "") -> None: - if "a" not in self.edges: - s = edges.FingerJointSettings(self.thickness, True, finger=1.0, space=1.0) - s.edgeObjects(self, "aA.") - - t = self.thickness - l = math.radians(180-2*angle) * self.getChestR(x, angle) - - tw = l + 6*t - th = y+2*t - - if self.move(tw, th, move, True, label=label): - return - - self.cc(callback, 0, self.edges["A"].startwidth()+self.burn) - self.edges["A"](3*t) - self.edges["X"](l, y+2*t) - self.edges["A"](3*t) - self.corner(90) - self.cc(callback, 1) - self.edge(y+2*t) - self.corner(90) - self.cc(callback, 2, self.edges["A"].startwidth()+self.burn) - self.edges["A"](3*t) - self.edge(l) - self.edges["A"](3*t) - self.corner(90) - self.cc(callback, 3) - self.edge(y+2*t) - self.corner(90) - - self.move(tw, th, move, label=label) - - -class _TopEdge(Boxes): - def addTopEdgeSettings(self, fingerjoint={}, stackable={}, hinge={}, - cabinethinge={}, slideonlid={}, click={}, - roundedtriangle={}, mounting={}, handle={}): - self.addSettingsArgs(edges.FingerJointSettings, **fingerjoint) - self.addSettingsArgs(edges.StackableSettings, **stackable) - self.addSettingsArgs(edges.HingeSettings, **hinge) - self.addSettingsArgs(edges.CabinetHingeSettings, **cabinethinge) - self.addSettingsArgs(edges.SlideOnLidSettings, **slideonlid) - self.addSettingsArgs(edges.ClickSettings, **click) - self.addSettingsArgs(edges.RoundedTriangleEdgeSettings, **roundedtriangle) - self.addSettingsArgs(edges.MountingSettings, **mounting) - self.addSettingsArgs(edges.HandleEdgeSettings, **handle) - - def topEdges(self, top_edge): - """Return top edges belonging to given main edge type - as a list containing edge for left, back, right, front. - """ - tl = tb = tr = tf = self.edges.get(top_edge, self.edges["e"]) - - if tl.char == "i": - tb = tf = "e" - tl = "j" - elif tl.char == "k": - tl = tr = "e" - elif tl.char == "L": - tl = "M" - tf = "e" - tr = "N" - elif tl.char == "v": - tl = tr = tf = "e" - elif tl.char == "t": - tf = tb = "e" - elif tl.char == "G": - tl = tb = tr = tf = "e" - if self.edges["G"].settings.side == edges.MountingSettings.PARAM_LEFT: - tl = "G" - elif self.edges["G"].settings.side == edges.MountingSettings.PARAM_RIGHT: - tr = "G" - elif self.edges["G"].settings.side == edges.MountingSettings.PARAM_FRONT: - tf = "G" - else: #PARAM_BACK - tb = "G" - elif tl.char == "y": - tl = tb = tr = tf = "e" - if self.edges["y"].settings.on_sides == True: - tl = tr = "y" - else: - tb = tf = "y" - elif tl.char == "Y": - tl = tb = tr = tf = "h" - if self.edges["Y"].settings.on_sides == True: - tl = tr = "Y" - else: - tb = tf = "Y" - return [tl, tb, tr, tf] - - def drawLid(self, x: float, y: float, top_edge, bedBolts=[None, None]) -> bool: - d2, d3 = bedBolts - if top_edge == "c": - self.rectangularWall(x, y, "CCCC", bedBolts=[d2, d3, d2, d3], move="up", label="top") - elif top_edge == "f": - self.rectangularWall(x, y, "FFFF", move="up", label="top") - elif top_edge in "FhŠY": - self.rectangularWall(x, y, "ffff", move="up", label="top") - elif top_edge == "L": - self.rectangularWall(x, y, "Enlm", move="up", label="lid top") - elif top_edge == "i": - self.rectangularWall(x, y, "EJeI", move="up", label="lid top") - elif top_edge == "k": - outset = self.edges["k"].settings.outset - self.edges["k"].settings.setValues(self.thickness, outset=True) - lx = x/2.0-0.1*self.thickness - self.edges['k'].settings.setValues(self.thickness, grip_length=5) - self.rectangularWall(lx, y, "IeJe", move="right", label="lid top left") - self.rectangularWall(lx, y, "IeJe", move="mirror up", label="lid top right") - self.rectangularWall(lx, y, "IeJe", move="left only", label="invisible") - self.edges["k"].settings.setValues(self.thickness, outset=outset) - elif top_edge == "v": - self.rectangularWall(x, y, "VEEE", move="up", label="lid top") - self.edges["v"].parts(move="up") - else: - return False - return True diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/parts.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/parts.py deleted file mode 100644 index fa3a035..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/parts.py +++ /dev/null @@ -1,169 +0,0 @@ -from __future__ import annotations - -from math import * -from typing import Any, Callable - -from boxes import vectors - - -def arcOnCircle(spanning_angle: float, outgoing_angle: float, r: float = 1.0) -> tuple[float, float]: - angle = spanning_angle + 2 * outgoing_angle - radius = r * sin(radians(0.5 * spanning_angle)) / sin(radians(180 - outgoing_angle - 0.5 * spanning_angle)) - return angle, abs(radius) - - -class Parts: - def __init__(self, boxes) -> None: - self.boxes = boxes - - """ - def roundKnob(self, diameter: float, n: int = 20, callback: Callable | None = None, move: str = ""): - size = diameter+diameter/n - if self.move(size, size, move, before=True): - return - self.moveTo(size/2, size/2) - self.cc(callback, None, 0, 0) - - self.move(size, size, move) - """ - - def __getattr__(self, name: str) -> Any: - return getattr(self.boxes, name) - - def disc(self, diameter: float, hole: float = 0, dwidth: float = 1.0, callback: Callable | None = None, move: str = "", label: str = "") -> None: - """Simple disc - - :param diameter: diameter of the disc - :param hole: (Default value = 0) - :param callback: (Default value = None) called in the center - :param dwidth: (Default value = 1) flatten on right side to given ratio - :param move: (Default value = "") - :param label: (Default value = "") - """ - size = diameter - r = diameter / 2.0 - - if self.move(size*dwidth, size, move, before=True, label=label): - return - - self.moveTo(size / 2, size / 2) - - if hole: - self.hole(0, 0, hole / 2) - - self.cc(callback, None, 0, 0) - if dwidth == 1.0: - self.moveTo(r + self.burn, 0, 90) - self.corner(360, r, tabs=6) - else: - w = (2.0 * dwidth - 1) * r - a = degrees(acos(w / r)) - self.moveTo(0, 0, -a) - self.moveTo(r, 0, -90) - self.corner(-360+2*a, r) - self.corner(-a) - self.edge(2*r*sin(radians(a))) - self.move(size*dwidth, size, move, label=label) - - def wavyKnob(self, diameter: float, n: int = 20, angle: float = 45, hole: float = 0, callback: Callable | None = None, move: str = "") -> None: - """Disc with a wavy edge to be easier to be gripped - - :param diameter: diameter of the knob - :param n: (Default value = 20) number of waves - :param angle: (Default value = 45) maximum angle of the wave - :param hole: (Default value = 0) - :param callback: (Default value = None) called in the center - :param move: (Default value = "") - """ - - if n < 2: - return - - size = diameter + pi * diameter / n - - if self.move(size, size, move, before=True): - return - - self.moveTo(size / 2, size / 2) - self.cc(callback, None, 0, 0) - - if hole: - self.hole(0, 0, hole / 2) - - self.moveTo(diameter / 2, 0, 90-angle) - a, r = arcOnCircle(360. / n / 2, angle, diameter / 2) - a2, r2 = arcOnCircle(360. / n / 2, -angle, diameter / 2) - - for i in range(n): - self.boxes.corner(a, r, tabs=(i % max(1, (n+1) // 6) == 0)) - self.boxes.corner(a2, r2) - - self.move(size, size, move) - - def concaveKnob(self, diameter: float, n: int = 3, rounded: float = 0.2, angle: float = 70, hole: float = 0, - callback: Callable | None = None, move: str = "") -> None: - """Knob with dents to be easier to be gripped - - :param diameter: diameter of the knob - :param n: (Default value = 3) number of dents - :param rounded: (Default value = 0.2) proportion of circumference remaining - :param angle: (Default value = 70) angle the dents meet the circumference - :param hole: (Default value = 0) - :param callback: (Default value = None) called in the center - :param move: (Default value = "") - """ - size = diameter - - if n < 2: - return - - if self.move(size, size, move, before=True): - return - - self.moveTo(size / 2, size / 2) - - if hole: - self.hole(0, 0, hole / 2) - - self.cc(callback, None, 0, 0) - self.moveTo(diameter / 2, 0, 90 + angle) - a, r = arcOnCircle(360. / n * (1 - rounded), -angle, diameter / 2) - - if abs(a) < 0.01: # avoid trying to make a straight line as an arc - a, r = arcOnCircle(360. / n * (1 - rounded), -angle - 0.01, diameter / 2) - - for i in range(n): - self.boxes.corner(a, r) - self.corner(angle) - self.corner(360. / n * rounded, diameter / 2, tabs=(i % max(1, (n+1) // 6) == 0)) - self.corner(angle) - - self.move(size, size, move) - - def ringSegment(self, r_outside: float, r_inside: float, angle: float, n: int = 1, move: str = "") -> None: - """Ring Segment - - :param r_outside: outer radius - :param r_inside: inner radius - :param angle: angle the segment is spanning - :param n: (Default value = 1) number of segments - :param move: (Default value = "") - """ - space = 360 * self.spacing / r_inside / 2 / pi - nc = int(min(n, 360 / (angle+space))) - - while n > 0: - if self.move(2*r_outside, 2*r_outside, move, True): - return - self.moveTo(0, r_outside, -90) - for i in range(nc): - self.polyline( - 0, (angle, r_outside), 0, 90, (r_outside-r_inside, 2), - 90, 0, (-angle, r_inside), 0, 90, (r_outside-r_inside, 2), - 90) - x, y = vectors.circlepoint(r_outside, radians(angle+space)) - self.moveTo(y, r_outside-x, angle+space) - n -=1 - if n == 0: - break - self.move(2*r_outside, 2*r_outside, move) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/pulley.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/pulley.py deleted file mode 100644 index c13f7d9..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/pulley.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -// Parametric Pulley with multiple belt profiles -// by droftarts January 2012 - -// Based on pulleys by: -// https://www.thingiverse.com/thing:11256 by me! -// https://github.com/prusajr/PrusaMendel by Josef Prusa -// https://www.thingiverse.com/thing:3104 by GilesBathgate -// https://www.thingiverse.com/thing:2079 by nophead - -// dxf tooth data from http://oem.cadregister.com/asp/PPOW_Entry.asp?company=915217&elementID=07807803/METRIC/URETH/WV0025/F -// pulley diameter checked and modelled from data at https://www.sdp-si.com/D265/HTML/D265T016.html -""" -from math import * - -from boxes.vectors import * - - -def tooth_spaceing_curvefit(teeth, b, c, d): - return ((c * teeth ** d) / (b + teeth ** d)) * teeth - - -def tooth_spacing(teeth, tooth_pitch, pitch_line_offset): - return (2 * ((teeth * tooth_pitch) / (3.14159265 * 2) - pitch_line_offset)) - - -def mirrorx(points): - return [[-x, y] for x, y in points] - -class Pulley: - - spacing = { - "MXL": (False, 2.032, 0.254), - "40DP": (False, 2.07264, 0.1778), - "XL": (False, 5.08, 0.254), - "H": (False, 9.525, 0.381), - "T2_5": (True, 0.7467, 0.796, 1.026), - "T5": (True, 0.6523, 1.591, 1.064), - "T10": (False, 10, 0.93), - "AT5": (True, 0.6523, 1.591, 1.064), - "HTD_3mm": (False, 3, 0.381), - "HTD_5mm": (False, 5, 0.5715), - "HTD_8mm": (False, 8, 0.6858), - "GT2_2mm": (False, 2, 0.254), - "GT2_3mm": (False, 3, 0.381), - "GT2_5mm": (False, 5, 0.5715), - } - - profile_data = { - "MXL": (0.508, 1.321), - "40DP": (0.457, 1.226), - "XL": (1.27, 3.051), - "H": (1.905, 5.359), - "T2_5": (0.7, 1.678), - "T5": (1.19, 3.264), - "T10": (2.5, 6.13), - "AT5": (1.19, 4.268), - "HTD_3mm": (1.289, 2.27), - "HTD_5mm": (2.199, 3.781), - "HTD_8mm": (3.607, 6.603), - "GT2_2mm": (0.764, 1.494), - "GT2_3mm": (1.169, 2.31), - "GT2_5mm": (1.969, 3.952), - } - - teeth = { "MXL" : [[-0.660421,-0.5],[-0.660421,0],[-0.621898,0.006033],[-0.587714,0.023037],[-0.560056,0.049424],[-0.541182,0.083609],[-0.417357,0.424392],[-0.398413,0.458752],[-0.370649,0.48514],[-0.336324,0.502074],[-0.297744,0.508035],[0.297744,0.508035],[0.336268,0.502074],[0.370452,0.48514],[0.39811,0.458752],[0.416983,0.424392],[0.540808,0.083609],[0.559752,0.049424],[0.587516,0.023037],[0.621841,0.006033],[0.660421,0],[0.660421,-0.5]], - "40DP" : [[-0.612775,-0.5],[-0.612775,0],[-0.574719,0.010187],[-0.546453,0.0381],[-0.355953,0.3683],[-0.327604,0.405408],[-0.291086,0.433388],[-0.248548,0.451049],[-0.202142,0.4572],[0.202494,0.4572],[0.248653,0.451049],[0.291042,0.433388],[0.327609,0.405408],[0.356306,0.3683],[0.546806,0.0381],[0.574499,0.010187],[0.612775,0],[0.612775,-0.5]], - "XL" : [[-1.525411,-1],[-1.525411,0],[-1.41777,0.015495],[-1.320712,0.059664],[-1.239661,0.129034],[-1.180042,0.220133],[-0.793044,1.050219],[-0.733574,1.141021],[-0.652507,1.210425],[-0.555366,1.254759],[-0.447675,1.270353],[0.447675,1.270353],[0.555366,1.254759],[0.652507,1.210425],[0.733574,1.141021],[0.793044,1.050219],[1.180042,0.220133],[1.239711,0.129034],[1.320844,0.059664],[1.417919,0.015495],[1.525411,0],[1.525411,-1]], - "H" : [[-2.6797,-1],[-2.6797,0],[-2.600907,0.006138],[-2.525342,0.024024],[-2.45412,0.052881],[-2.388351,0.091909],[-2.329145,0.140328],[-2.277614,0.197358],[-2.234875,0.262205],[-2.202032,0.334091],[-1.75224,1.57093],[-1.719538,1.642815],[-1.676883,1.707663],[-1.62542,1.764693],[-1.566256,1.813112],[-1.500512,1.85214],[-1.4293,1.880997],[-1.353742,1.898883],[-1.274949,1.905021],[1.275281,1.905021],[1.354056,1.898883],[1.429576,1.880997],[1.500731,1.85214],[1.566411,1.813112],[1.625508,1.764693],[1.676919,1.707663],[1.719531,1.642815],[1.752233,1.57093],[2.20273,0.334091],[2.235433,0.262205],[2.278045,0.197358],[2.329455,0.140328],[2.388553,0.091909],[2.454233,0.052881],[2.525384,0.024024],[2.600904,0.006138],[2.6797,0],[2.6797,-1]], - "T2_5" : [[-0.839258,-0.5],[-0.839258,0],[-0.770246,0.021652],[-0.726369,0.079022],[-0.529167,0.620889],[-0.485025,0.67826],[-0.416278,0.699911],[0.416278,0.699911],[0.484849,0.67826],[0.528814,0.620889],[0.726369,0.079022],[0.770114,0.021652],[0.839258,0],[0.839258,-0.5]], - "T5" : [[-1.632126,-0.5],[-1.632126,0],[-1.568549,0.004939],[-1.507539,0.019367],[-1.450023,0.042686],[-1.396912,0.074224],[-1.349125,0.113379],[-1.307581,0.159508],[-1.273186,0.211991],[-1.246868,0.270192],[-1.009802,0.920362],[-0.983414,0.978433],[-0.949018,1.030788],[-0.907524,1.076798],[-0.859829,1.115847],[-0.80682,1.147314],[-0.749402,1.170562],[-0.688471,1.184956],[-0.624921,1.189895],[0.624971,1.189895],[0.688622,1.184956],[0.749607,1.170562],[0.807043,1.147314],[0.860055,1.115847],[0.907754,1.076798],[0.949269,1.030788],[0.9837,0.978433],[1.010193,0.920362],[1.246907,0.270192],[1.273295,0.211991],[1.307726,0.159508],[1.349276,0.113379],[1.397039,0.074224],[1.450111,0.042686],[1.507589,0.019367],[1.568563,0.004939],[1.632126,0],[1.632126,-0.5]], - "T10" : [[-3.06511,-1],[-3.06511,0],[-2.971998,0.007239],[-2.882718,0.028344],[-2.79859,0.062396],[-2.720931,0.108479],[-2.651061,0.165675],[-2.590298,0.233065],[-2.539962,0.309732],[-2.501371,0.394759],[-1.879071,2.105025],[-1.840363,2.190052],[-1.789939,2.266719],[-1.729114,2.334109],[-1.659202,2.391304],[-1.581518,2.437387],[-1.497376,2.47144],[-1.408092,2.492545],[-1.314979,2.499784],[1.314979,2.499784],[1.408091,2.492545],[1.497371,2.47144],[1.581499,2.437387],[1.659158,2.391304],[1.729028,2.334109],[1.789791,2.266719],[1.840127,2.190052],[1.878718,2.105025],[2.501018,0.394759],[2.539726,0.309732],[2.59015,0.233065],[2.650975,0.165675],[2.720887,0.108479],[2.798571,0.062396],[2.882713,0.028344],[2.971997,0.007239],[3.06511,0],[3.06511,-1]], - "AT5" : [[-2.134129,-0.75],[-2.134129,0],[-2.058023,0.005488],[-1.984595,0.021547],[-1.914806,0.047569],[-1.849614,0.082947],[-1.789978,0.127073],[-1.736857,0.179338],[-1.691211,0.239136],[-1.653999,0.305859],[-1.349199,0.959203],[-1.286933,1.054635],[-1.201914,1.127346],[-1.099961,1.173664],[-0.986896,1.18992],[0.986543,1.18992],[1.099614,1.173664],[1.201605,1.127346],[1.286729,1.054635],[1.349199,0.959203],[1.653646,0.305859],[1.690859,0.239136],[1.73651,0.179338],[1.789644,0.127073],[1.849305,0.082947],[1.914539,0.047569],[1.984392,0.021547],[2.057906,0.005488],[2.134129,0],[2.134129,-0.75]], - "HTD_3mm" : [[-1.135062,-0.5],[-1.135062,0],[-1.048323,0.015484],[-0.974284,0.058517],[-0.919162,0.123974],[-0.889176,0.206728],[-0.81721,0.579614],[-0.800806,0.653232],[-0.778384,0.72416],[-0.750244,0.792137],[-0.716685,0.856903],[-0.678005,0.918199],[-0.634505,0.975764],[-0.586483,1.029338],[-0.534238,1.078662],[-0.47807,1.123476],[-0.418278,1.16352],[-0.355162,1.198533],[-0.289019,1.228257],[-0.22015,1.25243],[-0.148854,1.270793],[-0.07543,1.283087],[-0.000176,1.28905],[0.075081,1.283145],[0.148515,1.270895],[0.219827,1.252561],[0.288716,1.228406],[0.354879,1.19869],[0.418018,1.163675],[0.477831,1.123623],[0.534017,1.078795],[0.586276,1.029452],[0.634307,0.975857],[0.677809,0.91827],[0.716481,0.856953],[0.750022,0.792167],[0.778133,0.724174],[0.800511,0.653236],[0.816857,0.579614],[0.888471,0.206728],[0.919014,0.123974],[0.974328,0.058517],[1.048362,0.015484],[1.135062,0],[1.135062,-0.5]], - "HTD_5mm" : [[-1.89036,-0.75],[-1.89036,0],[-1.741168,0.02669],[-1.61387,0.100806],[-1.518984,0.21342],[-1.467026,0.3556],[-1.427162,0.960967],[-1.398568,1.089602],[-1.359437,1.213531],[-1.310296,1.332296],[-1.251672,1.445441],[-1.184092,1.552509],[-1.108081,1.653042],[-1.024167,1.746585],[-0.932877,1.832681],[-0.834736,1.910872],[-0.730271,1.980701],[-0.62001,2.041713],[-0.504478,2.09345],[-0.384202,2.135455],[-0.259708,2.167271],[-0.131524,2.188443],[-0.000176,2.198511],[0.131296,2.188504],[0.259588,2.167387],[0.384174,2.135616],[0.504527,2.093648],[0.620123,2.04194],[0.730433,1.980949],[0.834934,1.911132],[0.933097,1.832945],[1.024398,1.746846],[1.108311,1.653291],[1.184308,1.552736],[1.251865,1.445639],[1.310455,1.332457],[1.359552,1.213647],[1.39863,1.089664],[1.427162,0.960967],[1.467026,0.3556],[1.518984,0.21342],[1.61387,0.100806],[1.741168,0.02669],[1.89036,0],[1.89036,-0.75]], - "HTD_8mm" : [[-3.301471,-1],[-3.301471,0],[-3.16611,0.012093],[-3.038062,0.047068],[-2.919646,0.10297],[-2.813182,0.177844],[-2.720989,0.269734],[-2.645387,0.376684],[-2.588694,0.496739],[-2.553229,0.627944],[-2.460801,1.470025],[-2.411413,1.691917],[-2.343887,1.905691],[-2.259126,2.110563],[-2.158035,2.30575],[-2.041518,2.490467],[-1.910478,2.66393],[-1.76582,2.825356],[-1.608446,2.973961],[-1.439261,3.10896],[-1.259169,3.22957],[-1.069074,3.335006],[-0.869878,3.424485],[-0.662487,3.497224],[-0.447804,3.552437],[-0.226732,3.589341],[-0.000176,3.607153],[0.226511,3.589461],[0.447712,3.552654],[0.66252,3.497516],[0.870027,3.424833],[1.069329,3.33539],[1.259517,3.229973],[1.439687,3.109367],[1.608931,2.974358],[1.766344,2.825731],[1.911018,2.664271],[2.042047,2.490765],[2.158526,2.305998],[2.259547,2.110755],[2.344204,1.905821],[2.411591,1.691983],[2.460801,1.470025],[2.553229,0.627944],[2.588592,0.496739],[2.645238,0.376684],[2.720834,0.269734],[2.81305,0.177844],[2.919553,0.10297],[3.038012,0.047068],[3.166095,0.012093],[3.301471,0],[3.301471,-1]], - "GT2_2mm" : mirrorx([[0.747183,-0.5],[0.747183,0],[0.647876,0.037218],[0.598311,0.130528],[0.578556,0.238423],[0.547158,0.343077],[0.504649,0.443762],[0.451556,0.53975],[0.358229,0.636924],[0.2484,0.707276],[0.127259,0.750044],[0,0.76447],[-0.127259,0.750044],[-0.2484,0.707276],[-0.358229,0.636924],[-0.451556,0.53975],[-0.504797,0.443762],[-0.547291,0.343077],[-0.578605,0.238423],[-0.598311,0.130528],[-0.648009,0.037218],[-0.747183,0],[-0.747183,-0.5]]), - "GT2_3mm" : [[-1.155171,-0.5],[-1.155171,0],[-1.065317,0.016448],[-0.989057,0.062001],[-0.93297,0.130969],[-0.90364,0.217664],[-0.863705,0.408181],[-0.800056,0.591388],[-0.713587,0.765004],[-0.60519,0.926747],[-0.469751,1.032548],[-0.320719,1.108119],[-0.162625,1.153462],[0,1.168577],[0.162625,1.153462],[0.320719,1.108119],[0.469751,1.032548],[0.60519,0.926747],[0.713587,0.765004],[0.800056,0.591388],[0.863705,0.408181],[0.90364,0.217664],[0.932921,0.130969],[0.988924,0.062001],[1.065168,0.016448],[1.155171,0],[1.155171,-0.5]], - "GT2_5mm" : [[-1.975908,-0.75],[-1.975908,0],[-1.797959,0.03212],[-1.646634,0.121224],[-1.534534,0.256431],[-1.474258,0.426861],[-1.446911,0.570808],[-1.411774,0.712722],[-1.368964,0.852287],[-1.318597,0.989189],[-1.260788,1.123115],[-1.195654,1.25375],[-1.12331,1.380781],[-1.043869,1.503892],[-0.935264,1.612278],[-0.817959,1.706414],[-0.693181,1.786237],[-0.562151,1.851687],[-0.426095,1.9027],[-0.286235,1.939214],[-0.143795,1.961168],[0,1.9685],[0.143796,1.961168],[0.286235,1.939214],[0.426095,1.9027],[0.562151,1.851687],[0.693181,1.786237],[0.817959,1.706414],[0.935263,1.612278],[1.043869,1.503892],[1.123207,1.380781],[1.195509,1.25375],[1.26065,1.123115],[1.318507,0.989189],[1.368956,0.852287],[1.411872,0.712722],[1.447132,0.570808],[1.474611,0.426861],[1.534583,0.256431],[1.646678,0.121223],[1.798064,0.03212],[1.975908,0],[1.975908,-0.75]], - } - - def __init__(self, boxes) -> None: - self.boxes = boxes - - @classmethod - def getProfiles(cls): - return list(sorted(cls.teeth.keys())) - - def diameter(self, teeth, profile): - if self.spacing[profile][0]: - return tooth_spaceing_curvefit(teeth, *self.spacing[profile][1:]) - - return tooth_spacing(teeth, *self.spacing[profile][1:]) - - def __call__(self, teeth, profile, insideout=False, r_axle=None, - callback=None, move=""): - - # ******************************** - # ** Scaling tooth for good fit ** - # ******************************** - # To improve fit of belt to pulley, set the following constant. Decrease or increase by 0.1mm at a time. We are modelling the *BELT* tooth here, not the tooth on the pulley. Increasing the number will *decrease* the pulley tooth size. Increasing the tooth width will also scale proportionately the tooth depth, to maintain the shape of the tooth, and increase how far into the pulley the tooth is indented. Can be negative - - additional_tooth_width = 0.2 # mm - - # If you need more tooth depth than this provides, adjust the following constant. However, this will cause the shape of the tooth to change. - additional_tooth_depth = 0 # mm - - pulley_OD = self.diameter(teeth, profile) - - tooth_depth, tooth_width = self.profile_data[profile] - tooth_distance_from_centre = ((pulley_OD / 2) ** 2 - ((tooth_width + additional_tooth_width) / 2) ** 2) ** 0.5 - tooth_width_scale = (tooth_width + additional_tooth_width) / tooth_width - tooth_depth_scale = ((tooth_depth + additional_tooth_depth) / tooth_depth) - - if insideout: - pulley_OD += 2*tooth_depth * tooth_depth_scale - tooth_depth_scale *= -1 - - total_width = max(pulley_OD, 2*(r_axle or 0.0)) - - if self.boxes.move(total_width, total_width, move, before=True): - return - - self.boxes.moveTo(total_width / 2, total_width / 2) - self.boxes.cc(callback, None, 0.0, 0.0) - - if r_axle: - if insideout: - self.boxes.circle(0, 0, r_axle) - else: - self.boxes.hole(0, 0, r_axle) - - points = [] - for i in range(teeth): - m = [[tooth_width_scale, 0, 0], - [0, tooth_depth_scale, -tooth_distance_from_centre]] - m = mmul(m, rotm(i * 2 * pi / teeth)) - points.extend(vtransl(pt, m) for pt in self.teeth[profile][1:-1]) - - self.boxes.drawPoints(points, kerfdir=-1 if insideout else 1) - self.boxes.move(total_width, total_width, move) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/qrcode_factory.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/qrcode_factory.py deleted file mode 100644 index 8760f42..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/qrcode_factory.py +++ /dev/null @@ -1,63 +0,0 @@ -from decimal import Decimal - -import qrcode.image.base -import qrcode.image.svg - - -class BoxesQrCodeFactory(qrcode.image.base.BaseImage): - """ - SVG image builder - Creates a QR-code image as a SVG document fragment. - """ - _SVG_namespace = "http://www.w3.org/2000/svg" - kind = "SVG" - allowed_kinds = ("SVG",) - - def __init__(self, *args, ctx=None, x=0, y=0, **kwargs): - super().__init__(*args, **kwargs) - self.ctx = ctx - self.x, self.y = x, y - # Save the unit size, for example the default box_size of 10 is '1mm'. - self.unit_size = self.units(self.box_size) - - def drawrect(self, row, col): - self.ctx.rectangle(*self._rect(row, col)) - self._img.append(self._rect(row, col)) - - def units(self, pixels, text=True): - """ - A box_size of 10 (default) equals 1mm. - """ - units = Decimal(pixels) / 10 - if not text: - return units - return '%smm' % units - - def save(self, stream, kind=None): - self.check_kind(kind=kind) - self._write(stream) - - def to_string(self): - return f"".join(self._img) - - def new_image(self, **kwargs): - self._img = [] - return self._img - - def _rect(self, row, col): - size = self.box_size / 10 - x = self.x + (row + self.border) * size - y = self.y + (col + self.border) * size - return x, y, size, size - - def _write(self, stream): - stream.write("".join(self._img)) - -if __name__=="__main__": - import qrcode - import qrcode.image - q = qrcode.QRCode(image_factory=BoxesQrCodeFactory, box_size=10) - q.add_data('hello') - ctx = "a context" - img = q.make_image(ctx="a context") - print(img.to_string()) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/robot.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/robot.py deleted file mode 100644 index fcaa4b0..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/robot.py +++ /dev/null @@ -1,185 +0,0 @@ -__all__ = [ - "RobotArg", - "RobotArmMM", - "RobotArmMm", - "RobotArmUU", - "RobotArmUu", - "RobotArmMu", -] - -class RobotArg: - - def __init__(self, includenone=False) -> None: - self.robotarms = [ - (name, globals()[name].__doc__[23:]) for name in __all__ - if name.startswith("RobotArm")] - if includenone: - self.robotarms[0:0] = [("none", "")] - - def __call__(self, arg): - return str(arg) - - def choices(self): - return [name for name, descr in self.robotarms] - - def html(self, name, default, translate): - options = "\n".join( - ("""""" % - (name, ' selected="selected"' if name == default else "", - name, descr) for name, descr in self.robotarms)) - return f"""\n""" - - -class _RobotArm: - - def __init__(self, boxes, servo, servo2=None) -> None: - self.boxes = boxes - self.servo = servo - self.servo2 = servo2 or servo - - def __getattr__(self, name): - """Hack for easy access of Boxes methods""" - return getattr(self.boxes, name) - -class RobotArmMM(_RobotArm): - """Robot arm segment with two parallel servos""" - def __call__(self, length, move=None): - t = self.thickness - w = self.servo.height - l = max(self.servo.length * 2, length + 2*self.servo.axle_pos) - - th = max(2 * t + l, 2*w + 4*t + self.spacing) - tw = 5 * (w + 2*self.thickness + self.spacing) - - if self.move(tw, th, move, True): - return - - self.rectangularWall(w, l, "FfFf", callback=[ - lambda:self.servo.top(w/2), None, - lambda:self.servo.top(w/2)], move="right") - self.rectangularWall(w, l, "FfFf", callback=[ - lambda:self.servo.bottom(w/2), None, - lambda:self.servo.bottom(w/2)], move="right") - self.rectangularWall(w, l, "FFFF", move="right") - self.rectangularWall(w, l, "FFFF", move="right") - self.rectangularWall(w, w, "ffff", callback=[ - lambda:self.servo.front(w/2)], move="up") - self.rectangularWall(w, w, "ffff", callback=[ - lambda:self.servo.front(w/2)], move="") - - self.move(tw, th, move) - -class RobotArmMm(_RobotArm): - """Robot arm segment with two orthogonal servos""" - def __call__(self, length, move=None): - t = self.thickness - w = self.servo.height - w2 = self.servo2.height - l = max(self.servo.length * 2, length + 2*self.servo.axle_pos) - - th = max(2 * self.thickness + l, w + w2 + 4*t + self.spacing) - tw = 5 * (max(w, w2) + 2*self.thickness + self.spacing) - - if self.move(tw, th, move, True): - return - - self.rectangularWall(w2, l, "FfFf", callback=[ - lambda:self.servo.top(w2/2)], move="right") - self.rectangularWall(w2, l, "FfFf", callback=[ - lambda:self.servo.bottom(w2/2)], move="right") - self.rectangularWall(w, l, "FFFF", callback=[ - None, None, lambda:self.servo2.top(w/2)], move="right") - self.rectangularWall(w, l, "FFFF", callback=[ - None, None, lambda:self.servo2.bottom(w/2)], move="right") - self.rectangularWall(w2, w, "ffff", callback=[ - lambda:self.servo.front(w2/2)], move="up") - self.rectangularWall(w, w2, "ffff", callback=[ - lambda:self.servo2.front(w/2)], move="") - - self.move(tw, th, move) - -class RobotArmUU(_RobotArm): - """Robot arm segment with two parallel sets of hinge knuckles""" - def __call__(self, length, move=None): - t = self.thickness - w = self.servo.hinge_width() - l = max(4*self.thickness, length - 2*t - 2*self.servo.height) - - th = max(2 * self.servo._edges["m"].spacing() + l, - 2*w + 4*t + self.spacing) - tw = 5 * (w + 2*self.thickness + self.spacing) - - if self.move(tw, th, move, True): - return - - iw = (0, 3, 4, 7) - e = self.servo.edges - self.rectangularWall(w, l, e("mFmF"), ignore_widths=iw, move="right") - self.rectangularWall(w, l, e("MFMF"), ignore_widths=iw, move="right") - self.rectangularWall(w, l, "FfFf", move="right") - self.rectangularWall(w, l, "FfFf", move="right") - self.rectangularWall(w, w, "ffff", callback=[ - lambda: self.hole(w/2, w/2, 6)], move="up") - self.rectangularWall(w, w, "ffff", callback=[ - lambda: self.hole(w/2, w/2, 6)], move="") - - self.move(tw, th, move) - -class RobotArmUu(_RobotArm): - """Robot arm segment with two orthogonal sets of hinge knuckles""" - def __call__(self, length, move=None): - t = self.thickness - w = self.servo.hinge_width() - w2 = self.servo2.hinge_width() - l = max(4*self.thickness, length - 2*t - 2*self.servo.height) - - th = max(self.thickness + self.servo._edges["m"].spacing() + l, - 2*w + self.thickness + 4 * self.edges["f"].spacing()) - tw = 5 * (w + 2*self.thickness + self.spacing) - - if self.move(tw, th, move, True): - return - iw = (3, 4) - e = self.servo.edges - self.rectangularWall(w2, l, e("nfFf"), move="right") - self.rectangularWall(w2, l, e("NfFf"), move="right") - self.rectangularWall(w, l, e("FFmF"), ignore_widths=iw, move="right") - self.rectangularWall(w, l, e("FFMF"), ignore_widths=iw, move="right") - self.rectangularWall(w2, w, "ffff", callback=[ - lambda: self.hole(w2/2, w/2, 6)], move="up") - self.rectangularWall(w2, w, "ffff", callback=[ - lambda: self.hole(w2/2, w/2, 6)], move="") - - self.move(tw, th, move) - -class RobotArmMu(_RobotArm): - """Robot arm segment with a servo and an orthogonal sets of hinge knuckles""" - def __call__(self, length, move=None): - t = self.thickness - w = self.servo.height - w2 = self.servo2.hinge_width() - l = max(self.servo.length, length + self.servo.axle_pos - self.servo.height - t) - - th = max(t + l + self.servo2._edges["m"].spacing(), - w + w2 + self.thickness + 4 * self.edges["f"].spacing()) - tw = 5 * (w + 2*self.thickness + self.spacing) - - if self.move(tw, th, move, True): - return - - e = self.servo2.edges - iw = (3, 4) - self.rectangularWall(w2, l, "FfFf", callback=[ - lambda:self.servo.top(w2/2)], move="right") - self.rectangularWall(w2, l, "FfFf", callback=[ - lambda:self.servo.bottom(w2/2)], move="right") - self.rectangularWall(w, l, e("FFmF"), ignore_widths=iw, move="right") - self.rectangularWall(w, l, e("FFMF"), ignore_widths=iw, move="right") - self.rectangularWall(w2, w, "ffff", callback=[ - lambda:self.servo.front(w2/2)], move="up") - self.rectangularWall(w2, w, "ffff", callback=[ - lambda: self.hole(w2/2, w/2, 6)], move="") - - self.move(tw, th, move) - -# class RobotArmMU(_RobotArm): diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/servos.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/servos.py deleted file mode 100644 index 08d1c77..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/servos.py +++ /dev/null @@ -1,121 +0,0 @@ -from __future__ import annotations - -import math - -import boxes.vectors - - -class EyeEdge(boxes.edges.FingerHoleEdge): - char = "m" - - def __init__(self, boxes, servo, fingerHoles=None, driven: bool = False, outset: bool = False, **kw) -> None: - self.servo = servo - self.outset = outset - self.driven = driven - super().__init__(boxes, fingerHoles, **kw) - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - t = self.fingerHoles.settings.thickness - dist = self.fingerHoles.settings.edge_width - - pos_axle = self.servo.hinge_depth() - self.ctx.save() - self.hole(length / 2.0, - -pos_axle, - self.servo.axle / 2.0 if self.driven else self.servo.servo_axle / 2.0) - if self.outset: - self.fingerHoles(t, self.thickness / 2, length - 2 * t, 0) - else: - self.fingerHoles(0, self.thickness / 2, length, 0) - self.ctx.restore() - r = self.servo.servo_axle * 2 - a, l = boxes.vectors.tangent(length / 2, pos_axle, r) - angle = math.degrees(a) - self.polyline(0, -angle, l, (2 * angle, r), l, -angle, 0) - - def startwidth(self) -> float: - return self.fingerHoles.settings.thickness - - def margin(self) -> float: - return self.servo.hinge_depth() + self.fingerHoles.settings.thickness + self.servo.servo_axle * 2 - - -def buildEdges(boxes, servo, chars: str = "mMnN"): - result = {} - for n, char in enumerate(chars): - e = EyeEdge(boxes, servo, outset=(n < 2), driven=((n % 2) == 1)) - e.char = char - result[char] = e - return result - - -class ServoArg: - def __init__(self, includeNone: bool = False) -> None: - self.servos = ["Servo9g"] - if includeNone: - self.servos[0:0] = ["none"] - - def __call__(self, arg) -> str: - return str(arg) - - def choices(self) -> list[str]: - return [name for name in self.servos] - - def html(self, name: str, default: str, translate) -> str: - options = "\n".join("""""".format(name, ' selected="selected"' if name == default else "", name) for name in self.servos) - return f"""\n""" - - -class Servo: - def __init__(self, boxes, axle: float = 3) -> None: - self.boxes = boxes - self.axle = axle - self._edges = buildEdges(boxes, self) - - def edges(self, edges): - return [self._edges.get(e, e) for e in edges] - - -class Servo9g(Servo): - height: float = 22.5 - length: float = 28.0 # one tab in the wall - width: float = 12.0 - axle_pos: float = 6.0 - servo_axle: float = 4.6 # 6.9 for servo arm - - def top(self, x: float = 0.0, y: float = 0.0, angle: float = 90.0) -> None: - self.boxes.moveTo(x, y, angle) - self.boxes.hole(6, 0, 6) - self.boxes.hole(12, 0, 3) - - def bottom(self, x: float = 0.0, y: float = 0.0, angle: float = 90.0) -> None: - self.boxes.moveTo(x, y, angle) - self.boxes.hole(6, 0, self.axle / 2.0) - - def front(self, x: float = 0.0, y: float = 0.0, angle: float = 90.0) -> None: - self.boxes.moveTo(x, y, angle) - self.boxes.rectangularHole(5.4, 0, 2.4, 12) - self.boxes.rectangularHole(17, 0, 4, 16) - - def hinge_width(self) -> float: - return self.height + self.boxes.thickness + 4.5 - - def hinge_depth(self) -> float: - return self.height # XXX - - -class Servo9gt(Servo9g): - height = 35 - - def top(self, x: float = 0.0, y: float = 0.0, angle: float = 90.0) -> None: - self.boxes.moveTo(x, y, angle) - self.boxes.hole(6, 0, 6) - self.boxes.hole(12, 0, 5) - - def bottom(self, x: float = 0.0, y: float = 0.0, angle: float = 90.0) -> None: - self.boxes.moveTo(x, y, angle) - self.boxes.hole(6, 0, self.axle) - - def front(self, x: float = 0.0, y: float = 0.0, angle: float = 90.0) -> None: - self.boxes.moveTo(x, y, angle) - self.boxes.rectangularHole(5.4, 0, 2.4, 12) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/vectors.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/vectors.py deleted file mode 100644 index 7fe19e6..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/vectors.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright (C) 2013-2014 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import math - - -def normalize(v): - """set length of vector to one""" - l = (v[0] ** 2 + v[1] ** 2) ** 0.5 - if l == 0.0: - return (0.0, 0.0) - return (v[0] / l, v[1] / l) - - -def vlength(v): - return (v[0] ** 2 + v[1] ** 2) ** 0.5 - - -def vclip(v, length): - l = vlength(v) - if l > length: - return vscalmul(v, length / l) - return v - - -def vdiff(p1, p2): - """vector from point1 to point2""" - return (p2[0] - p1[0], p2[1] - p1[1]) - - -def vadd(v1, v2): - """Sum of two vectors""" - return (v1[0] + v2[0], v1[1] + v2[1]) - - -def vorthogonal(v): - """Orthogonal vector""" - return (-v[1], v[0]) - - -def vscalmul(v, a): - """scale vector by a""" - return (a * v[0], a * v[1]) - - -def dotproduct(v1, v2): - """Dot product""" - return v1[0] * v2[0] + v1[1] * v2[1] - -def circlepoint(r, a): - return (r * math.cos(a), r * math.sin(a)) - -def tangent(x, y, r): - """angle and length of a tangent to a circle at x,y with radius r""" - l1 = vlength((x, y)) - a1 = math.atan2(y, x) - a2 = math.asin(r / l1) - l2 = math.cos(a2) * l1 - - return (a1+a2, l2) - -def rotm(angle): - """Rotation matrix""" - return [[math.cos(angle), -math.sin(angle), 0], - [math.sin(angle), math.cos(angle), 0]] - - -def vtransl(v, m): - m0, m1 = m - return [m0[0] * v[0] + m0[1] * v[1] + m0[2], - m1[0] * v[0] + m1[1] * v[1] + m1[2]] - - -def mmul(m0, m1): - result = [[0, ] * len(m0[0]) for i in range(len(m0))] - for i in range(len(m0[0])): - for j in range(len(m0)): - for k in range(len(m0)): - result[j][i] += m0[k][i] * m1[j][k] - return result - - -def kerf(points, k, closed=True): - """Outset points by k - Assumes a closed loop of points - """ - result = [] - lp = len(points) - - for i in range(len(points)): - # get normalized orthogonals of both segments - v1 = vorthogonal(normalize(vdiff(points[i - 1], points[i]))) - v2 = vorthogonal(normalize(vdiff(points[i], points[(i + 1) % lp]))) - - if not closed: - if i == 0: - v1 = v2 - if i == lp-1: - v2 = v1 - # direction the point has to move - d = normalize(vadd(v1, v2)) - # cos of the half the angle between the segments - cos_alpha = dotproduct(v1, d) - result.append(vadd(points[i], vscalmul(d, -k / cos_alpha))) - - return result diff --git a/extensions/fablabchemnitz/boxes.py/boxes/boxes/walledges.py b/extensions/fablabchemnitz/boxes.py/boxes/boxes/walledges.py deleted file mode 100644 index 4fb5c71..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/boxes/walledges.py +++ /dev/null @@ -1,447 +0,0 @@ -from __future__ import annotations - -import math -from typing import Any - -from boxes import Boxes, edges - -from .edges import BaseEdge, Settings - - -class _WallMountedBox(Boxes): - ui_group = "WallMounted" - - def __init__(self) -> None: - super().__init__() - self.addWallSettingsArgs() - - def addWallSettingsArgs(self): - self.addSettingsArgs(edges.FingerJointSettings) - self.addSettingsArgs(WallSettings) - self.addSettingsArgs(SlatWallSettings) - self.addSettingsArgs(DinRailSettings) - self.addSettingsArgs(FrenchCleatSettings) - self.argparser.add_argument( - "--walltype", action="store", type=str, default="plain", - choices=["plain", "plain reinforced", "slatwall", "dinrail", - "french cleat"], - help="Type of wall system to attach to") - - def generateWallEdges(self): - if self.walltype.startswith("plain"): - s = WallSettings( - self.thickness, True, - **self.edgesettings.get("Wall", {})) - elif self.walltype == "slatwall": - s = SlatWallSettings( - self.thickness, True, - **self.edgesettings.get("SlatWall", {})) - elif self.walltype == "dinrail": - s = DinRailSettings( - self.thickness, True, - **self.edgesettings.get("DinRail", {})) - elif self.walltype == "french cleat": - s = FrenchCleatSettings( - self.thickness, True, - **self.edgesettings.get("FrenchCleat", {})) - - s.edgeObjects(self) - self.wallHolesAt = self.edges["|"] - if self.walltype.endswith("reinforced"): - self.edges["c"] = self.edges["d"] - self.edges["C"] = self.edges["D"] - -############################################################################# -#### Straight Edge / Base class -############################################################################# - -class WallEdge(BaseEdge): - - _reversed = False - - def lengths(self, length): - return [length] - - def _joint(self, length): - self.edge(length) - - def _section(self, nr, length): - self.edge(length) - - def __call__(self, length, **kw): - lengths = list(enumerate(self.lengths(length))) - if self._reversed: - lengths = list(reversed(lengths)) - - for nr, l in lengths: - if l == 0.0: - continue - if nr % 2: - self._section(nr // 2, l) - else: - self._joint(l) - -class WallJoinedEdge(WallEdge): - char = "b" - - def _joint(self, length): - t = self.settings.thickness - self.step(-t) - self.edges["f"](length) - self.step(t) - - def startwidth(self) -> float: - return self.settings.thickness - -class WallBackEdge(WallEdge): - - def _section(self, nr, length): - self.edge(length) - - def _joint(self, length): - t = self.settings.thickness - self.step(t) - self.edges["F"](length) - self.step(-t) - - def margin(self) -> float: - return self.settings.thickness - -class WallHoles(WallEdge): - - def _section(self, nr, length): - self.rectangularHole(length/2, 0, length, self.settings.thickness) - self.moveTo(length, 0) - - def _joint(self, length): - self.fingerHolesAt(0, 0, length, 0) - self.moveTo(length, 0) - - def __call__(self, x, y, length, angle, **kw): - """ - Draw holes for a matching WallJoinedEdge - - :param x: position - :param y: position - :param length: length of matching edge - :param angle: (Default value = 90) - """ - with self.boxes.saved_context(): - self.boxes.moveTo(x, y, angle) - b = self.boxes.burn - t = self.settings.thickness - - if self.boxes.debug: # XXX - width = self.settings.thickness - self.ctx.rectangle(b, -width / 2 + b, - length - 2 * b, width - 2 * b) - - self.boxes.moveTo(length, 0, 180) - super().__call__(length) - -class WallHoleEdge(WallHoles): - """Edge with holes for a parallel finger joint""" - description = "Edge (parallel slot wall Holes)" - - def __init__(self, boxes, wallHoles, **kw) -> None: - super().__init__(boxes, wallHoles.settings, **kw) - self.wallHoles = wallHoles - - def __call__(self, length, bedBolts=None, bedBoltSettings=None, **kw): - dist = self.wallHoles.settings.edge_width + self.settings.thickness / 2 - with self.saved_context(): - px, angle = (0, 0) if self._reversed else (length, 180) - self.wallHoles( - px, dist, length, angle) - self.edge(length, tabs=2) - - def startwidth(self) -> float: - """ """ - return self.wallHoles.settings.edge_width + self.settings.thickness - - def margin(self) -> float: - return 0.0 - -class WallSettings(Settings): - """Settings for plain WallEdges -Values: - -* relative (in multiples of thickness) - - * edge_width : 1.0 : space below holes of FingerHoleEdge (multiples of thickness) - -""" - - absolute_params: dict[str, Any] = { - } - - relative_params = { - "edge_width": 1.0, - } - - base_class = WallEdge - - def edgeObjects(self, boxes, chars="aAbBcCdD|", add=True): - bc = self.base_class - bn = bc.__name__ - wallholes = type(bn+"Hole", (WallHoles, bc), {})(boxes, self) - - edges = [bc(boxes, self), - type(bn+"Reversed", (bc,), {'_reversed' : True})(boxes, self), - type(bn+"Joined", (WallJoinedEdge, bc), {})(boxes, self), - type(bn+"JoinedReversed", (WallJoinedEdge, bc), {'_reversed' : True})(boxes, self), - type(bn+"Back", (WallBackEdge, bc), {})(boxes, self), - type(bn+"BackReversed", (WallBackEdge, bc), {'_reversed' : True})(boxes, self), - type(bn+"Hole", (WallHoleEdge, bc), {})(boxes, wallholes), - type(bn+"HoleReversed", (WallHoleEdge, bc), {'_reversed' : True})(boxes, wallholes), - wallholes, - ] - return self._edgeObjects(edges, boxes, chars, add) - -############################################################################# -#### Slat wall -############################################################################# - - -class SlatWallEdge(WallEdge): - - def lengths(self, length): - pitch = self.settings.pitch - h = self.settings.hook_height - he = self.settings.hook_extra_height - - lengths = [] - if length < h + he: - return [length] - lengths = [0, h + he] - length -= h + he - if length > pitch: - lengths.extend([(length // pitch) * pitch - h - 2 - 2*he, - h + 2 + 2*he, - length % pitch]) - else: - lengths.append(length) - return lengths - - def _section(self, nr, length): - w = self.settings.hook_height # vertical width of hook - hd = self.settings.hook_depth - hdist = self.settings.hook_distance - hh = self.settings.hook_overall_height - ro = w # outer radius - ri = min(w/2, hd/2) # inner radius - rt = min(1, hd/2) # top radius - slot = self.settings.hook_height + 2 # XXX - if nr == 0: - poly = [0, -90, hdist-ri, (-90, ri), hh-ri-w-rt, (90, rt), - hd-2*rt, (90, rt), hh-ro-rt, (90, ro), hdist+hd-ro, -90, - length-6] - elif nr == 1: - if self.settings.bottom_hook == "spring": - r_plug = slot*.4 - slotslot = slot - r_plug * 2**0.5 - poly = [self.settings.hook_extra_height, -90, - 5.0, -45, 0, (135, r_plug), - 0, 90, 10, -90, slotslot, -90, 10, 90, 0, - (135, r_plug), 0, -45, 5, -90, - self.settings.hook_extra_height] - elif self.settings.bottom_hook == "hook": - d = 2 - poly = [self.settings.hook_extra_height + d - 1, -90, - 4.5+hd, (90,1), slot-2, (90, 1), hd-1, 90, d, - -90, 5.5, -90, self.settings.hook_extra_height + 1] - elif self.settings.bottom_hook == "stud": - poly = [self.settings.hook_extra_height, -90, - 6, (90, 1) , slot-2, (90, 1), 6, -90, - self.settings.hook_extra_height] - else: - poly = [2*self.settings.hook_extra_height + slot] - - if self._reversed: - poly = reversed(poly) - self.polyline(*poly) - - def margin(self) -> float: - return self.settings.hook_depth + self.settings.hook_distance - -class SlatWallSettings(WallSettings): - """Settings for SlatWallEdges -Values: - -* absolute_params - - * bottom_hook : "hook" : "spring", "stud" or "none" - * pitch : 101.6 : vertical spacing of slots middle to middle (in mm) - * hook_depth : 4.0 : horizontal width of the hook - * hook_distance : 5.5 : horizontal space to the hook - * hook_height : 6.0 : height of the horizontal bar of the hook - * hook_overall_height : 12.0 : height of the hook top to bottom - -* relative (in multiples of thickness) - - * hook_extra_height : 2.0 : space surrounding connectors (multiples of thickness) - * edge_width : 1.0 : space below holes of FingerHoleEdge (multiples of thickness) - -""" - - absolute_params = { - "bottom_hook" : ("hook", "spring", "stud", "none"), - "pitch" : 101.6, - "hook_depth" : 4.0, - "hook_distance" : 5.5, - "hook_height" : 6.0, - "hook_overall_height" : 12.0, - } - - relative_params = { - "hook_extra_height" : 2.0, - "edge_width": 1.0, - } - - base_class = SlatWallEdge - - -############################################################################# -#### DIN rail -############################################################################# - -class DinRailEdge(WallEdge): - - def lengths(self, length): - if length < 20: - return [length] - if length > 50 and self.settings.bottom == "stud": - return [0, 20, length - 40, 20] - return [0, 20, - length - 20] - - def _section(self, nr, length): - d = self.settings.depth - - if nr == 0: - r = 1. - poly = [0, -90, d-0.5-r, (90, r), 15+3-2*r, (90, r), - d-4-r, 45, - 4*2**.5, -45, .5, -90, 6] - elif nr == 1: - slot = 20 - if self.settings.bottom == "stud": - r = 1. - poly = [0, -90, 7.5-r, (90, r), - slot - 2*r, - (90, r), 7.5-r, -90, 0] - else: - poly = [slot] - if self._reversed: - poly = reversed(poly) - self.polyline(*poly) - - def margin(self) -> float: - return self.settings.depth - -class DinRailSettings(WallSettings): - """Settings for DinRailEdges -Values: - -* absolute_params - - * bottom : "stud" : "stud" or "none" - * depth : 4.0 : horizontal width of the hook - -* relative (in multiples of thickness) - - * edge_width : 1.0 : space below holes of FingerHoleEdge (multiples of thickness) - -""" - - absolute_params = { - "bottom" : ("stud", "none"), - "depth" : 8.0, - } - - relative_params = { - "edge_width": 1.0, - } - - base_class = DinRailEdge - -############################################################################# -#### French Cleats -############################################################################# - -class FrenchCleatEdge(WallEdge): - - def lengths(self, length): - d = self.settings.depth - t = self.settings.thickness - s = self.settings.spacing - h = d * math.tan(math.radians(self.settings.angle)) - # make small enough to not have finger holes - top = 0.5*t - bottom = 0.5 * t - if length < top + bottom + 1.5*d + h: - return [length] - if length > top + bottom + 2*t + 1.5*d + h and \ - self.settings.bottom == "stud": - return [top, 1.5*d + h, length - top - bottom - 2.5*d - h, - d, bottom] - if length > top + bottom + 2.5*d + s and \ - self.settings.bottom == "hook": - dist = ((length - top - t - 1.5*d - h) // s ) * s - 1.5*d - h - return [top, 1.5*d + h, dist, 1.5*d + h, length-dist-top-3*d-2*h] - return [top, 2.5*d, length-top-2.5*d] - - def _section(self, nr, length): - d = self.settings.depth - t = self.settings.thickness - r = min(0.5*t, 0.1*d) - a = self.settings.angle - h = d * math.tan(math.radians(a)) - l = d / math.cos(math.radians(a)) - - if nr == 0 or self.settings.bottom == "hook": - poly = [0, -90, 0, (90, d), .5*d+h, 90+a, l, -90-a, length-1.5*d] - elif nr == 1: - if self.settings.bottom == "stud": - r = min(t, length/4, d) - poly = [0, -90, d-r, (90, r), - length - 2*r, - (90, r), d-r, -90, 0] - else: - poly = [length] - if self._reversed: - poly = reversed(poly) - self.polyline(*poly) - - def margin(self) -> float: - return self.settings.depth - -class FrenchCleatSettings(WallSettings): - """Settings for FrenchCleatEdges -Values: - -* absolute_params - - * bottom : "stud" : "stud", "hook" or "none" - * depth : 18.0 : horizontal width of the hook in mm - * angle : 45.0 : angle of the cut (0 for horizontal) - * spacing : 200.0 : distance of the cleats in mm (for bottom hook) - -* relative (in multiples of thickness) - - * edge_width : 1.0 : space below holes of FingerHoleEdge (multiples of thickness) - -""" - - absolute_params = { - "bottom" : ("stud", "hook", "none"), - "depth" : 18.0, - "spacing" : 200.0, - "angle" : 45.0, - } - - relative_params = { - "edge_width": 1.0, - } - - base_class = FrenchCleatEdge diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxes.1 b/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxes.1 deleted file mode 100644 index fa88c02..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxes.1 +++ /dev/null @@ -1,63 +0,0 @@ -'\" t -.\" Title: Boxes -.\" Author: Georges Khaznadar -.\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 10/26/2019 -.\" Manual: boxes User Manual -.\" Source: boxes -.\" Language: English -.\" -.TH "BOXES" "1" "10/26/2019" "boxes" "boxes User Manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -boxes \- program design boxes -.SH "DESCRIPTION" -.PP -\fBboxes\fR -is a program that generates SVG images that can be viewed directly in a web browser but also postscript and \- with pstoedit as external helper \- other vector formats including dxf, plt (aka hpgl) and gcode\&. -.PP -Of course the library and the generators allow selecting the "thickness" of the material used and automatically adjusts lengths and width of joining fingers and other elements\&. -.PP -The "burn" parameter compensates for the material removed by the laser\&. This allows fine tuning the gaps between joins up to the point where plywood can be press fitted even without any glue\&. -.PP -inger Joints are the work horse of the library\&. They allow 90\(de edges and T connections\&. Their size is scaled up with the material "thickness" to maintain the same appearance\&. The library also allows putting holes and slots for screws (bed bolts) into finger joints, although this is currently not supported for the included generators\&. -.PP -Dovetail joints can be used to join pieces in the same plane\&. -.PP -Flex cuts allows bending and stretching the material in one direction\&. This is used for rounded edges and living hinges\&. -.SH "AUTHOR" -.PP -\fBGeorges Khaznadar\fR <\&georgesk@debian\&.org\&> -.RS 4 -Wrote this manpage for the Debian system\&. -.RE -.SH "COPYRIGHT" -.br -Copyright \(co 2019 Georges Khaznadar -.br -.PP -This manual page was written for the Debian system (and may be used by others)\&. -.PP -Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. -.PP -On Debian systems, the complete text of the GNU General Public License can be found in -/usr/share/common\-licenses/GPL\&. -.sp diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxes.xml b/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxes.xml deleted file mode 100644 index 10253f5..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxes.xml +++ /dev/null @@ -1,135 +0,0 @@ - -.
will be generated. You may view the -manual page with: nroff -man .
| less'. A typical entry -in a Makefile or Makefile.am is: - -DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl -XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" - -manpage.1: manpage.xml - $(XP) $(DB2MAN) $< - -The xsltproc binary is found in the xsltproc package. The XSL files are in -docbook-xsl. A description of the parameters you can use can be found in the -docbook-xsl-doc-* packages. Please remember that if you create the nroff -version in one of the debian/rules file targets (such as build), you will need -to include xsltproc and docbook-xsl in your Build-Depends control field. -Alternatively use the xmlto command/package. That will also automatically -pull in xsltproc and docbook-xsl. - -Notes for using docbook2x: docbook2x-man does not automatically create the -AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as - ... . - -To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections -read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be -found in the docbook-xsl-doc-html package. - -Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` - -General documentation about man-pages and man-page-formatting: -man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ - ---> - - - - - - - - - - - - - -]> - - - - &dhtitle; - &dhpackage; - - - &dhfirstname; - &dhsurname; - Wrote this manpage for the Debian system. -
- &dhemail; -
-
-
- - 2019 - &dhusername; - - - This manual page was written for the Debian system - (and may be used by others). - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU General Public License, - Version 2 or (at your option) any later version published by - the Free Software Foundation. - On Debian systems, the complete text of the GNU General Public - License can be found in - /usr/share/common-licenses/GPL. - -
- - &dhucpackage; - &dhsection; - - - &dhpackage; - program design boxes - - - DESCRIPTION - - &dhpackage; is a program that generates - SVG images that can be viewed directly in a web browser but also - postscript and - with pstoedit as external helper - - other vector formats including dxf, plt (aka hpgl) and gcode. - - - Of course the library and the generators allow selecting the - "thickness" of the material used and automatically adjusts lengths and - width of joining fingers and other elements. - - - The "burn" parameter compensates for the material removed by the - laser. This allows fine tuning the gaps between joins up to the point - where plywood can be press fitted even without any glue. - - - inger Joints are the work horse of the library. They allow 90° - edges and T connections. Their size is scaled up with the material - "thickness" to maintain the same appearance. The library also allows - putting holes and slots for screws (bed bolts) into finger joints, - although this is currently not supported for the included generators. - - - Dovetail joints can be used to join pieces in the same plane. - - - Flex cuts allows bending and stretching the material in one - direction. This is used for rounded edges and living hinges. - - -
diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxesserver.1 b/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxesserver.1 deleted file mode 100644 index a55ea92..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxesserver.1 +++ /dev/null @@ -1,64 +0,0 @@ -'\" t -.\" Title: BoxesServer -.\" Author: Georges Khaznadar -.\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 10/31/2019 -.\" Manual: boxesserver User Manual -.\" Source: boxesserver -.\" Language: English -.\" -.TH "BOXESSERVER" "1" "10/31/2019" "boxesserver" "boxesserver User Manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -boxesserver \- a web server to make boxes\&. -.SH "SYNOPSIS" -.HP \w'\fBboxesserver\fR\ 'u -\fBboxesserver\fR [\fB\fIport_number\fR\fR] -.SH "DESCRIPTION" -.PP -\fBboxesserver\fR -is a web server which allows one to compute sketches to cut materials with a laser and make various types of boxes\&. -.SH "OPTIONS" -.PP -\fB\fIport_number\fR\fR -.RS 4 -If this optional parameter is set, the web service will be done using this port number\&. By default, the port number is 8000\&. -.sp -Please notice that port numbers lesser than 1024 are privileged, and can be used only by root\&. -.RE -.SH "AUTHOR" -.PP -\fBGeorges Khaznadar\fR <\&georgesk@debian\&.org\&> -.RS 4 -Wrote this manpage for the Debian system\&. -.RE -.SH "COPYRIGHT" -.br -Copyright \(co 2019 Georges Khaznadar -.br -.PP -This manual page was written for the Debian system (and may be used by others)\&. -.PP -Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. -.PP -On Debian systems, the complete text of the GNU General Public License can be found in -/usr/share/common\-licenses/GPL\&. -.sp diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxesserver.xml b/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxesserver.xml deleted file mode 100644 index d6d17a2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/boxesserver.xml +++ /dev/null @@ -1,132 +0,0 @@ - -.
will be generated. You may view the -manual page with: nroff -man .
| less'. A typical entry -in a Makefile or Makefile.am is: - -DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl -XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" - -manpage.1: manpage.xml - $(XP) $(DB2MAN) $< - -The xsltproc binary is found in the xsltproc package. The XSL files are in -docbook-xsl. A description of the parameters you can use can be found in the -docbook-xsl-doc-* packages. Please remember that if you create the nroff -version in one of the debian/rules file targets (such as build), you will need -to include xsltproc and docbook-xsl in your Build-Depends control field. -Alternatively use the xmlto command/package. That will also automatically -pull in xsltproc and docbook-xsl. - -Notes for using docbook2x: docbook2x-man does not automatically create the -AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as - ... . - -To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections -read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be -found in the docbook-xsl-doc-html package. - -Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` - -General documentation about man-pages and man-page-formatting: -man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ - ---> - - - - - - - - - - - - - -]> - - - - &dhtitle; - &dhpackage; - - - &dhfirstname; - &dhsurname; - Wrote this manpage for the Debian system. -
- &dhemail; -
-
-
- - 2019 - &dhusername; - - - This manual page was written for the Debian system - (and may be used by others). - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU General Public License, - Version 2 or (at your option) any later version published by - the Free Software Foundation. - On Debian systems, the complete text of the GNU General Public - License can be found in - /usr/share/common-licenses/GPL. - -
- - &dhucpackage; - &dhsection; - - - &dhpackage; - a web server to make boxes. - - - - &dhpackage; - - - - - DESCRIPTION - &dhpackage; is a web server which allows - one to compute sketches to - cut materials with a laser and make various types of boxes. - - - OPTIONS - - - - - If this optional parameter is set, the web service - will be done using this port number. By default, the port number - is 8000. - - - Please notice that port numbers lesser than 1024 are privileged, - and can be used only by root. - - - - - -
diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/presentation.odp b/extensions/fablabchemnitz/boxes.py/boxes/documentation/presentation.odp deleted file mode 100644 index 0fd25d3..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/presentation.odp and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/CONTRIBUTING.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/CONTRIBUTING.rst deleted file mode 100644 index ac7b6bc..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/CONTRIBUTING.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../CONTRIBUTING.rst diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/Makefile b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/Makefile deleted file mode 100644 index 43276bb..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = ../build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/README.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/README.rst deleted file mode 100644 index 4d547b7..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/README.rst +++ /dev/null @@ -1,2 +0,0 @@ -.. include:: ../../README.rst - :end-before: Documentation diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_architecture.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_architecture.rst deleted file mode 100644 index c723b95..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_architecture.rst +++ /dev/null @@ -1,97 +0,0 @@ -Architecture ------------- - -Boxes.py it structured into several distinct tiers. - -User Interfaces -............... - -User interfaces allow users to render the different generators. They -handle the parameters of Generators and convert them to a readable -form. The user interfaces are located in :code:`scripts/`. Currently there is - -* scripts/boxes -- the command line interface -* scripts/boxesserver -- the web interface -* scripts/boxes2inx -- generates Inkscape extensions -* scripts/boxes_example.ipynb -- Jupyter notebook - - -Generators -.......... - -A (box) generator is a subclass of boxes.Boxes. It generates one -drawing. The subclasses overload .__init__() to set their parameters -and implement .render() that does the actual drawing. - -Generators are found in ``boxes/generators/``. They are included into -the web UI and the CLI tool by the name of their class. So whenever -you copy either an existing generator or the sceleton in -``boxes/generators/_template.py`` you need to change the name of the -main class first. - -Parts -..... - -Parts are a single call that draws something according to a set of parameters. -There are a number of standard parts. Their typical params are -explained in the API docs. - -The only real requirement for a part is that it must support the move -parameter for placement. - -Part Callbacks -++++++++++++++ - -Most parts support callbacks - either one in the middle for round -parts or one for each edge. They allow placing holes or other features -on the part, independent of edge type. Without using callbacks, you -will not have consistent placement of internal features. - -Navigation and Turtle Graphics -.............................. - -Many drawing commands in Boxes.py are Turtle Graphics commands. They -start at the current position and in the current direction and move -the coordinate system with them. This way the absolute coordinates are -never used and placement and movement is always relative to the -current position. - -There are a few functions to move the origin to a convenient position -or to return to a previously saved position. - -Edges -..... - -Edges are turtle graphic commands. But they have been elevated to -proper Classes to handle outsets. They can be passed as parameters to parts. -There is a set of standard edges found in ``.edges``. They are -associated with a single char which can be used instead of the -Edge object itself at most places. This allows passing the edge -description of a part as a string. - -Turtle graphics -............... - -There are a few turtle graphics commands that do the actual -drawing. Corners with an positive angle (going counter clockwise) -close the part while negative angles (going clockwise) create protrusions. -This is inversed for holes which need to be drawn clockwise. - -Getting this directions right is important to make the burn correction -(aka kerf) work properly. - -Simple drawing commands -....................... - -These also are simple drawing commands. Some of them get ``x``, ``y`` and -``angle`` parameters to draw somewhere specific. Some just draw right -at the current coordinate origin. Often these commands create holes or -hole patterns. - -Back end -........ - -Boxes.py used to use cairo as graphics library. It now uses its own - -pure Python - back end. It is not fully encapsulated -within the drawing methods of the Boxes class. Although this is the -long term goal. Boxes.ctx is the context all drawing is made on. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_arguments.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_arguments.rst deleted file mode 100644 index 7b93e45..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_arguments.rst +++ /dev/null @@ -1,75 +0,0 @@ -Generator Arguments -------------------- - -Boxes.py uses the ``argparse`` standard library for handling the -arguments for the generators. It is used directly for the ``boxes`` -command line tool. But it also handles -- with some additional code -- -the web interface and the Inkscape extensions. To make this work one -has to limit the kind of parameters used. Boxes.py supports the -following types: - - * ``int`` - * ``float`` - * ``str`` - * ``boxes.boolarg`` -- an alternative to ``bool`` that works with the - web interface - * ``boxes.argparseSections`` -- multiple lengths e.g. for dividing up - a box in one direction - -and - -.. autoclass:: boxes.ArgparseEdgeType - -For the standard types there is code to create HTML and Inkscape -extensions. The other types can have ``.html()`` and ``.inx()`` -methods. - -The argument parser need to be built in the ``.__init__()`` method -after calling the method of the super class. Have a look at - -.. automethod:: boxes.generators._template.BOX.__init__ - -As many arguments are used over and over there is a function that can -add the most common ones: - -.. automethod:: boxes.Boxes.buildArgParser - -Check the source for details about the single arguments. - -Other arguments can be added with the normal argparser API - namely - -.. automethod:: argparse.ArgumentParser.add_argument - -of the ``Boxes.argparser`` attribute. - -Edge style arguments -.................... - -Edges that work together share a Settings class (and object). These -classes can create ``argparse`` groups: - -.. automethod:: boxes.edges.Settings.parserArguments - -See - -.. automethod:: boxes.generators._template.BOX.__init__ - -for a list of possible edge settings. These regular settings are used -in the standard edge instances used everywhere. For special edge -instances you can call them with a ``prefix`` parameter. But you then -need to deal with the results on your own. - -Default Arguments -................. - -The :ref:`default-args` get added automatically by the super class's -constructor. - -Accessing the Arguments -....................... - -For convenience content of the arguments are written to attributes of -the Boxes instance before ``.render()`` is called. This is done by -``Boxes.parseArgs``. But most people won't need to care as this is -handled by the framework. Be careful to **not overwrite important -methods or attributes by using conflicting argument names**. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_burn.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_burn.rst deleted file mode 100644 index ea65527..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_burn.rst +++ /dev/null @@ -1,80 +0,0 @@ -Burn correction -=============== - -The burn correction -- aka kerf -- is done in two separate steps. The -first mechanism is used during drawing. After rendering there is -a post processing step that replaces the inverted arcs of the inner corners by -Bezier loops that can be cut in a continuous motion. - -The first mechanism is integrated into the low level -commands of Boxes.py. So for the most part developers do not need to -care about it. Nevertheless they need to understand how it works to -catch the places the do need to care. - -Burn correction is done by increasing the radius of all outer -corners. This moves all the straight lines outward by the same -amount. This has the added benefit of not needing to change the length -of the straight lines -- making them independent of the adjacent -angles. An issue arises when it comes to inner corners. If they do -have a radius reducing it by the burn value does the right thing. But -for small radii and sharp corners (radius zero) this results in a -negative values. It turns out flipping over the arc for negative radii -allows keeping the lengths of the straight lines unchanged. So this is -what Boxes.py does: - -.. image:: burn.svg - -This results in the straight lines touching the piece. This would lead to -overcuts that are not as nice as proper dog bones as might be used by -a dedicated CAM software. But as Boxes.py is meant to be used for laser -cutting this deemed acceptable for a long time: - -.. image:: overcuts.svg - -Programmer's perspective ------------------------- - -For this to work it is important that outside is drawn in a -counterclockwise direction while holes are drawn in a -clockwise direction. - -:py:meth:`boxes.Boxes.corner` adjusts the radius automatically -according to **.burn**. This propagates to higher level -functions. Parts shipped with Boxes.py do take the -burn outset into account and execute callbacks at the correct position. - -In case developers move to a feature inside of a part or executing -callbacks while implementing a part they need to be aware of the burn -correction. :py:meth:`boxes.Boxes.cc` does correct for the outset if -called without an **y** parameter. But if a value is given one has to -add **self.burn** to compensate. Note that the **x** value typically -does not have to be corrected as the callbacks are executed from right -underneath the part. - -A similar approach is necessary when moving to a feature drawn inside -the part without the use of callbacks. Here you typically have to -correct for the outset at the outside of the part and again for inset -of the hole one is about to cut. This can be done in **x** or **y** -direction depending on whether the cut is started vertical or -horizontally. - -Replacing the inverted arcs ---------------------------- - -The inverted arcs have several drawbacks. For one they remove more -material than needed. This is not a big deal for laser cutters. But if -the boxes are cut with a CNC milling machine that can be -annoying. Another drawback is that the direction is reversed twice -which requires the tool (typically the laser head) to come to a total stop. - -To solve this issue all paths are scanned for intersecting lines that -are connected by an inverted arc. There the lines are shortened to the -intersection point and the arc is replaced by a Bezier loop that is -continues the lines and loops on the outside of the corner. That way -the path still removes additional material to make sure the full -inner corner is cleared out. The current implementation uses the -former end points of the lines as control points. This gives -reasonable results but errs on the save side. The amount of material -removed can probably be further optimized. - -.. image:: burn2.svg diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_drawing.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_drawing.rst deleted file mode 100644 index 8b56ecd..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_drawing.rst +++ /dev/null @@ -1,90 +0,0 @@ -Drawing commands -================ - - -Turtle Graphics commands ------------------------- - -These commands all move the coordinate system with them. - -.. automethod:: boxes.Boxes.edge -.. automethod:: boxes.Boxes.corner -.. automethod:: boxes.Boxes.curveTo -.. automethod:: boxes.Boxes.polyline - -Special Functions -................. - -.. automethod:: boxes.Boxes.bedBoltHole - -Latch and Grip -.............. - -These should probably be Edge classes. But right now they are still functions. - -.. automethod:: boxes.Boxes.grip -.. automethod:: boxes.Boxes.latch -.. automethod:: boxes.Boxes.handle - -Tab support -........... - -Tabs are small interruptions in the border of a part to keep it in -place. They are enabled with the **tabs** parameter. All -**Edges** automatically create about two tabs. So parts like -:py:meth:`boxes.Boxes.rectangularWall` will have 8 tabs holding them -in place. Because of this developers often don't need to be concerned -about tabs. But some part may be completely drawn by low level Turtle -Graphics commands. For those both :py:meth:`boxes.Boxes.edge` and -:py:meth:`boxes.Boxes.corner` do support a **tabs** parameter. In -addition the length of the line segments in :py:meth:`boxes.Boxes.polyline` can -be given as a tuple **(length, tabs)**. - -Draw Commands -------------- - -These commands do not change the coordinate system but get the -coordinates passed as parameters. All of them are either some sort of -hole or text. These artifacts are placed somewhere independently of -some continuous outline of the part their on. - -.. automethod:: boxes.Boxes.hole -.. automethod:: boxes.Boxes.rectangularHole -.. automethod:: boxes.Boxes.dHole -.. automethod:: boxes.Boxes.flatHole -.. automethod:: boxes.Boxes.text -.. automethod:: boxes.Boxes.NEMA -.. automethod:: boxes.Boxes.TX -.. automethod:: boxes.Boxes.flex2D -.. py:class:: NutHole - -An instance is available as **boxes.Boxes.nutHole()** - -An instance of - -.. autoclass:: boxes.edges.FingerHoles - :noindex: - -is accessible as **Boxes.fingerHolesAt**. - - -Hexagonal Hole patterns -....................... - -Hexagonal hole patterns are one way to have some ventilation for -housings made with Boxes.py. Right now both ``.rectangularWall()`` -and ``.roundedPlate()`` do supports this pattern directly by passing -the parameters to the calls. For other use cases these more low level -methods can be used. - -For now this is the only supported pattern for ventilation slots. More -may be added in the future. - -There is a global Boxes.hexHolesSettings object that is used if no settings are -passed. It currently is just a tuple of (r, dist, style) defaulting to -(5, 3, 'circle') but might be replace by a Settings instance in the future. - -.. automethod:: boxes.Boxes.hexHolesRectangle -.. automethod:: boxes.Boxes.hexHolesCircle -.. automethod:: boxes.Boxes.hexHolesPlate -.. automethod:: boxes.Boxes.hexHolesHex diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_edges.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_edges.rst deleted file mode 100644 index 7e77477..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_edges.rst +++ /dev/null @@ -1,193 +0,0 @@ -Edges -===== - -Edges are what makes Boxes.py work. They draw a -- more or less -- straight -border to the current piece. They are part of the turtle graphics part -of Boxes.py. This means they start at the current position and current -direction and move the current position to the end of the edge. - -Edge instances have a Settings object associated with them that keeps -the details about what the edge should look like. Edges that are -supposed to work together share the same Settings object to ensure -they fit together - assuming they have the same length. Most edges are -symmetrical to ensure they fit together even when drawn from different -directions. Although there are a few exceptions - mainly edges that -provide special features like hinges. - -As edges started out as methods of the main Boxes class they still are -callables. It turned out that the edges need to provide a bit more -information to allow the surrounding code to handle them -properly. When drawing an Edge there is a virtual straight line that -is the border the shape of the part (e.g. an rectangle). But the -actual Edge often has to be drawn elsewhere. The best example is probably -the ``F`` Edge that matches the normal finger joints. It has to start -one material thickness outside of the virtual border of the part so the -cutouts for the opposing fingers just touch the border. The Edge -classes have a number of methods to deal with these kinds of offsets. - -A set of instances are kept in the ``.edges`` attribute of the -``Boxes`` class. It is a dict with strings of length one as keys: - -* aAbB : reserved to be used in generators -* c : ClickConnector -* C : ClickEdge -* d : DoveTailJoint -* D : DoveTailJointCounterPart -* e : Edge -* E : OutSetEdge -* f : FingerJointEdge -* F : FingerJointEdgeCounterPart -* g : GrippingEdge -* G : MountingEdge -* h : FingerHoleEdge -* ijk : Hinge (start, end, both sides) -* IJK : HingePin (start, end, both sides) -* L : LidHoleEdge -* l : LidEdge -* M : LidSideLeft -* m : LidLeft -* N : LidSideRight -* n : LidRight -* Oo : ChestHinge -* Pp : ChestHingeTop -* Q : ChestHingeFront -* q : ChestHingePin -* R : RackEdge -* s : StackableEdge -* S : StackableEdgeTop -* š : StackableFeet -* Š : StackableHoleEdgeTop -* T : RoundedTriangleFingerHolesEdge -* t : RoundedTriangleEdge -* uUvV : CabinetHingeEdge -* X : FlexEdge -* y : HandleEdge -* Y : HandleHoleEdge -* Z : GroovedEdgeCounterPart -* z : GroovedEdge - -Edge base class ---------------- - -.. autoclass:: boxes.edges.BaseEdge - :members: - -.. automethod:: boxes.edges.BaseEdge.__call__ - -Settings Class --------------- - -.. autoclass:: boxes.edges.Settings - :members: - - -Straight Edges --------------- - -.. autoclass:: boxes.edges.Edge -.. autoclass:: boxes.edges.OutSetEdge - -Grip ----- - -.. autoclass:: boxes.edges.GripSettings -.. autoclass:: boxes.edges.GrippingEdge - -Stackable Edges ---------------- - -.. autoclass:: boxes.edges.StackableEdge -.. autoclass:: boxes.edges.StackableEdgeTop - -Stackable Edge Settings -....................... - -.. autoclass:: boxes.edges.StackableSettings - :members: - -Finger joints -------------- - -Finger joints are a simple way of joining two sheets (e.g. of plywood). They -work best at an 90° angle. There are two different sides matching each -other. As a third alternative there are holes that the fingers of one -sheet can plug into. This allows stable T connections especially -useful for inner walls. - -.. autoclass:: boxes.edges.FingerJointEdge -.. autoclass:: boxes.edges.FingerJointEdgeCounterPart -.. autoclass:: boxes.edges.FingerHoleEdge -.. autoclass:: boxes.edges.CrossingFingerHoleEdge - -In addition there is - -.. autoclass:: boxes.edges.FingerHoles - -which is no Edge but fits ``FingerJointEdge``. - -An instance of is accessible as **Boxes.fingerHolesAt**. - -Finger Joint Settings -..................... - -.. autoclass:: boxes.edges.FingerJointSettings - :members: - -Bed Bolts -......... - -.. autoclass:: boxes.edges.BoltPolicy - -.. autoclass:: boxes.edges.Bolts - -Dovetail Joints ----------------- -Dovetails joints can only be used to join two pieces flatly. This -limits their use to closing some round form created with flex areas or -for joining several parts to a bigger one. For this use case they are -much stronger than simple finger joints and can also bare pulling forces. - -.. autoclass:: boxes.edges.DoveTailJoint -.. autoclass:: boxes.edges.DoveTailJointCounterPart - -Dovetail Settings -.................. - -.. autoclass:: boxes.edges.DoveTailSettings - :members: - -Flex ----- -.. autoclass:: boxes.edges.FlexEdge - -Flex Settings -............. - -.. autoclass:: boxes.edges.FlexSettings - -Slots ------ -.. autoclass:: boxes.edges.Slot -.. autoclass:: boxes.edges.SlottedEdge - -CompoundEdge ------------- -.. autoclass:: boxes.edges.CompoundEdge - -Hinges ------- - -Hinge Settings -.............. - -.. autoclass:: boxes.edges.HingeSettings - -Hinge -..... - -.. autoclass:: boxes.edges.Hinge - -HingePin -........ - -.. autoclass:: boxes.edges.HingePin diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_examples.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_examples.rst deleted file mode 100644 index 2e69e47..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_examples.rst +++ /dev/null @@ -1,97 +0,0 @@ -Examples --------- - -Decide whether you want to start from scratch or want to rework an -existing generator. - -You should go over the arguments first. Get at least the most basic -arguments done. For things you are still unsure you can just use a -attribute set in the .__init__() method and turn it into a proper -argument later on. - -Depending on what you want to do you can work on the different levels -of the API. You can either use what is there and combine it into -something new or you can implements new things in the appropriate level. - -Here are some examples: - -Housing for some electronics -............................ - -You can use the ElectronicsBox or the ClosedBox as a basis. Write some -callbacks to place holes in the walls to allow accessing the ports of -the electronics boards. Place some holes to screw spacers into the -bottom to mount the PBC on. - -NemaMount -......... - -This is a good non box example to look at. - -.. autoclass:: boxes.generators.nemamount.NemaMount - -Note that although it produces a cube like object it uses separate -variables (``x``, ``y``, ``h``) for the different axis. Probably -because it started as a copy of another generator like ``ClosedBox``. - -DisplayShelf -............ - -.. autoclass:: boxes.generators.displayshelf.DisplayShelf - -The DisplayShelf is completely made out of rectangularWalls(). It uses -a callback to place all the fingerHolesAt() at the right places on the sides. -While the use of the Boxes.py API is pretty straightforward the -calculations needed are a bit more tricky. You can use the ``debug`` -default param to check if you got things right when attempting -something like this yourself. - -Note that the front walls and the shelfs form a 90° angle so they work -with the default FingerJoints. - -BinTray -....... - -.. autoclass:: boxes.generators.bintray.BinTray - -The BinTray is based on the TypeTray generator: - -.. autoclass:: boxes.generators.typetray.TypeTray - -TypeTray is an already pretty complicated generator. - -BinTray replaces the now vertical front (former top) edges with a -special purpose one that does add the triangles: - -.. autoclass:: boxes.generators.bintray.BinFrontEdge - -The ``hi`` (height of inner walls) argument was removed although the -variable is still used internally - out of laziness. - -To complete the bin the front walls are added. Follow up patches then -switched the slots between the vertical and horizontal walls to have -better support for the now bottoms of the bins. Another patch adds -angled finger joints for connecting the front walls with the bottoms -of the bins. - -The TrafficLight generator uses a similar technique implementing its -own Edge class. But it uses its own code to generate all the wall needed. - -Stachel -....... - -.. autoclass:: boxes.generators.stachel.Stachel - -Stachel allows mounting a monopod to a bass recorder. It is basically -just one part repeated with different parameters. It can't really make -use of much of the Boxes.py library. It implements this one part -including the ``move`` parameter and draws everything using the -``.polyline()`` method. This is pretty painful as lots of angles and -distances need to be calculated by hand. - -For symmetric sections it passes the parameters to ``.polyline`` twice --- first in normal order and then reversed to get the mirrored section. - -This generator is beyond what Boxes.py is designed for. If you need -something similar you may want to use another tool like OpenScad or a -traditional CAD program. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_existing_parts.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_existing_parts.rst deleted file mode 100644 index b3fb4bf..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_existing_parts.rst +++ /dev/null @@ -1,27 +0,0 @@ -Existing Parts --------------- - -A couple of commands can create whole parts like walls. Typically the -sizes given are the inner dimension not including additional space -needed for burn compensation or joints. - -Currently there are the following parts: - -.. automethod:: boxes.Boxes.rectangularWall -.. automethod:: boxes.Boxes.flangedWall -.. automethod:: boxes.Boxes.rectangularTriangle -.. automethod:: boxes.Boxes.regularPolygonWall -.. automethod:: boxes.Boxes.polygonWall -.. automethod:: boxes.Boxes.roundedPlate -.. automethod:: boxes.Boxes.surroundingWall - -Parts Class -........... - -More parts are available in a separate class. An instance is available as -**Boxes.parts** - -.. automethod:: boxes.parts.Parts.disc -.. automethod:: boxes.parts.Parts.wavyKnob -.. automethod:: boxes.parts.Parts.concaveKnob -.. automethod:: boxes.parts.Parts.ringSegment diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_generator.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_generator.rst deleted file mode 100644 index 26be044..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_generator.rst +++ /dev/null @@ -1,45 +0,0 @@ - -Generators -========== - -Generators are subclasses of - -.. autoclass:: boxes.Boxes - -Most code is directly in this class. Subclass are supposed to over -write the ``.__init__()`` and ``.render()`` method. - -The Boxes class keeps a canvas object (self.ctx) that all -drawing is made on. In addition it keeps a couple of global settings -used for various drawing operations. See the ``.__init__()`` method -for the details. - -For implementing a new generator forking an existing one or using the -``boxes/generators/_template.py`` is probably easier than starting -from scratch. - -Many methods and attributes are for use of the subclasses. These -methods are the interface for the user interfaces to interact with the -generators: - -.. automethod:: boxes.Boxes.__init__ - -.. automethod:: boxes.Boxes.parseArgs -.. automethod:: boxes.Boxes.render - -.. automethod:: boxes.Boxes.open -.. automethod:: boxes.Boxes.close - -Handling Generators -------------------- - -To handle the generators there is code in the ``boxes.generators`` -package. - -.. automodule:: boxes.generators - :members: - :undoc-members: - -This adds generators to the user interfaces automatically. For this to -work it is important that the class names are unique. So whenever you -start a new generator please change the class name right away. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_navigation.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_navigation.rst deleted file mode 100644 index 98265de..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_navigation.rst +++ /dev/null @@ -1,42 +0,0 @@ -Navigation ----------- - -The back end can both move the origin and the current point from -which the next line is going to start. Boxes.py hides this by using -Turtle Graphics commands that also move the origin to the end of the -last line. Other drawing commands restore the current position after -they are finished. - -Moving the origin like this allows ignoring the absolute coordinates -and for all movement and drawing to be relative to the current -position. The current position not only consists of a point on -the drawing canvas but also a direction. - -To move the origin to a different location there are these two methods: - -.. automethod:: boxes.Boxes.moveTo -.. automethod:: boxes.Boxes.moveArc - -Often it is necessary to return to a position e.g. after placing a -row of parts. This can be done with the following context manager: - -.. automethod:: boxes.Boxes.saved_context() - -It can be used with the following code pattern: - -.. code-block:: python - - with self.saved_context(): - self.rectangularWall(x, h, move="right") - self.rectangularWall(y, h, move="right") - self.rectangularWall(y, h, move="right") - self.rectangularWall(x, h, move="right") - self.rectangularWall(x, h, move="up only") - - # continue above the row - -Parts of the code still directly use the back end primitives **Boxes.ctx.save()** -and **Boxes.ctx.restore()**. But this has several disadvantages and is -discouraged. For one it requires matching calls. It also does not -reset the starting point of the next line. This is "healed" by a -follow up **.moveTo()**. Use **.moveTo(0, 0)** if in doubt. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_parts.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_parts.rst deleted file mode 100644 index 1e46f29..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/api_parts.rst +++ /dev/null @@ -1,86 +0,0 @@ -Parts ------ - - - - -There are a few parameters shared by many of the parts: - -The callback parameter -...................... - -The callback parameter can take on of the following forms: - -* A function (or bound method) that expects one parameter: the number of the side the callback is currently called for. -* A dict with some of the numbers of the sides as keys and functions without parameters as values. -* A list of functions without parameters. The list may contain None as place holder and be shorter than the number of sides. - -The callback functions are called with the side of the part at the -positive x and y axis. If the edge uses up space this space is below -the x axis. You do not have to restore the coordinate settings in the -callback. - -Instead of functions it can be handy to use a lambda expression -calling the one building block function you need (e.g. fingerHolesAt). - -For your own parts you can use this helper function: - -.. automethod:: boxes.Boxes.cc - -For finding the right piece to the *callback* parameter this function is used: - -.. automethod:: boxes.Boxes.getEntry - - -The move parameter -.................. - -For placing the parts the ``move`` parameter can be used. It is string -with space separated words - at most one of each of those options: - -* left / right -* up / down -* only - -If "only" is given the part is not drawn but only the move is -done. This can be useful to go in one direction after having placed -multiple parts in the other and have returned with ``.ctx.restore()``. - -For implementing parts the following helper function can be used to -implement a ``move`` parameter: - -.. automethod:: boxes.Boxes.move - -It needs to be called before and after drawing the actual part with -the proper ``before`` parameter set. - -The edges parameter -................... - -The ``edges`` parameter needs to be an iterable of Edge instances to be -used as edges of the part. Instead of instances it is possible to pass -a single character that is looked up in the ``.edges`` dict. This -allows to pass a string with the desired characters per edge. By -default the following character are supported: - -* e : straight edge -* E : as above but extended outside by one thickness -* f, F : finger joints -* h : edge with holes for finger joints -* d, D : dove tail joints - -Generators can register their own Edges by putting them into the -``.edges`` dictionary. - -Same applies to the parameters of ``.surroundingWall`` although they -denominate single edge (types) only. - -PartsMatrix -........... - -To place a grid of identical parts, partMatrix can used: - -.. automethod:: boxes.Boxes.partsMatrix - -It creates one big block of parts. The move param treats this block like one big -part. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/apidoc.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/apidoc.rst deleted file mode 100644 index cd3b80f..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/apidoc.rst +++ /dev/null @@ -1,20 +0,0 @@ -Using the Boxes.py API -====================== - -If there is no generator fitting your needs you can either adjust an -existing one (may be by copying it to another name first) or writing a -new one from scratch. - -.. toctree:: - :maxdepth: 1 - - api_architecture - api_generator - api_arguments - api_navigation - api_parts - api_existing_parts - api_edges - api_drawing - api_burn - api_examples diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/boxes.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/boxes.rst deleted file mode 100644 index 3778556..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/boxes.rst +++ /dev/null @@ -1,120 +0,0 @@ -boxes package -============= - -Subpackage boxes.generators ---------------------------- - -.. automodule:: boxes.generators - :members: - :undoc-members: - :show-inheritance: - -:doc:`generators` - -Submodules ----------- - -boxes.Color module ------------------- - -.. automodule:: boxes.Color - :members: - :undoc-members: - :show-inheritance: - -boxes.edges module ------------------- - -.. automodule:: boxes.edges - :members: - :undoc-members: - :show-inheritance: - -boxes.formats module --------------------- - -.. automodule:: boxes.formats - :members: - :undoc-members: - :show-inheritance: - -boxes.gears module ------------------- - -.. automodule:: boxes.gears - :members: - :undoc-members: - :show-inheritance: - -boxes.lids module ------------------ - -.. automodule:: boxes.lids - :members: - :undoc-members: - :show-inheritance: - -boxes.mounts module -------------------- - -.. automodule:: boxes.mounts - :members: - :undoc-members: - :show-inheritance: - -boxes.parts module ------------------- - -.. automodule:: boxes.parts - :members: - :undoc-members: - :show-inheritance: - -boxes.pulley module -------------------- - -.. automodule:: boxes.pulley - :members: - :undoc-members: - :show-inheritance: - -boxes.robot module ------------------- - -.. automodule:: boxes.robot - :members: - :undoc-members: - :show-inheritance: - -boxes.servos module -------------------- - -.. automodule:: boxes.servos - :members: - :undoc-members: - :show-inheritance: - -boxes.svgutil module --------------------- - -.. automodule:: boxes.svgutil - :members: - :undoc-members: - :show-inheritance: - -boxes.vectors module --------------------- - -.. automodule:: boxes.vectors - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: boxes - :members: - :undoc-members: - :show-inheritance: diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/boxes2rst.py b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/boxes2rst.py deleted file mode 100755 index 8dd98bc..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/boxes2rst.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os.path -import sys - -try: - import boxes.generators -except ImportError: - sys.path.append(os.path.dirname(__file__) + "/../..") - import boxes.generators - - -class Boxes2rst: - def __init__(self) -> None: - self.boxes = {b.__name__: b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface} - self.groups = boxes.generators.ui_groups - self.groups_by_name = boxes.generators.ui_groups_by_name - - for name, box in self.boxes.items(): - self.groups_by_name.get(box.ui_group, self.groups_by_name["Misc"]).add(box) - - def write(self, targetFile: str) -> None: - with open(targetFile, "w") as f: - for name, group in self.groups_by_name.items(): - f.write(f"{name}\n----------------\n\n") - for box in group.generators: - f.write(box.__class__.__name__) - f.write("\n..........................................\n\n") - f.write(f"\n\n.. autoclass:: {box.__class__.__module__}.{box.__class__.__name__}") - f.write("\n\n") - if os.path.exists(f"../../static/samples/{box.__class__.__name__}.jpg"): - f.write(f".. image:: ../../static/samples/{box.__class__.__name__}.jpg\n\n") - - -def main() -> None: - if len(sys.argv) != 2: - print("Usage: boxes2rst.py TARGETFILE") - return - b = Boxes2rst() - b.write(sys.argv[1]) - - -if __name__ == "__main__": - main() diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/burn.svg b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/burn.svg deleted file mode 100644 index 44a3633..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/burn.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/burn2.svg b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/burn2.svg deleted file mode 100644 index ed1298c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/burn2.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - RoundedBox - - - - FlexBox - RoundedBox - 2021-04-25 18:47:19 - http://localhost:8000/RoundedBox?FingerJoint_angle=90.0&FingerJoint_style=rectangular&FingerJoint_surroundingspaces=1&FingerJoint_edge_width=1.0&FingerJoint_finger=2.0&FingerJoint_play=0.0&FingerJoint_space=2.0&FingerJoint_width=1.0&Flex_stretch=1.05&Flex_connection=1.0&Flex_distance=0.5&Flex_width=5.0&x=50&y=50&h=50&outside=0&radius=5&wallpieces=1&edge_style=f&top=closed&thickness=3.0&format=svg&tabs=0.0&debug=0&reference=100&burn=1&render=1 - Box with vertical edges rounded - -Created with Boxes.py (https://festi.info/boxes.py) -Command line: boxes RoundedBox --FingerJoint_angle=90.0 --FingerJoint_style=rectangular --FingerJoint_surroundingspaces=1 --FingerJoint_edge_width=1.0 --FingerJoint_finger=2.0 --FingerJoint_play=0.0 --FingerJoint_space=2.0 --FingerJoint_width=1.0 --Flex_stretch=1.05 --Flex_connection=1.0 --Flex_distance=0.5 --Flex_width=5.0 --x=50 --y=50 --h=50 --outside=0 --radius=5 --wallpieces=1 --edge_style=f --top=closed --thickness=3.0 --format=svg --tabs=0.0 --debug=0 --reference=100 --burn=1 -Url: http://localhost:8000/RoundedBox?FingerJoint_angle=90.0&FingerJoint_style=rectangular&FingerJoint_surroundingspaces=1&FingerJoint_edge_width=1.0&FingerJoint_finger=2.0&FingerJoint_play=0.0&FingerJoint_space=2.0&FingerJoint_width=1.0&Flex_stretch=1.05&Flex_connection=1.0&Flex_distance=0.5&Flex_width=5.0&x=50&y=50&h=50&outside=0&radius=5&wallpieces=1&edge_style=f&top=closed&thickness=3.0&format=svg&tabs=0.0&debug=0&reference=100&burn=1&render=1 -SettingsUrl: http://localhost:8000/RoundedBox?FingerJoint_angle=90.0&FingerJoint_style=rectangular&FingerJoint_surroundingspaces=1&FingerJoint_edge_width=1.0&FingerJoint_finger=2.0&FingerJoint_play=0.0&FingerJoint_space=2.0&FingerJoint_width=1.0&Flex_stretch=1.05&Flex_connection=1.0&Flex_distance=0.5&Flex_width=5.0&x=50&y=50&h=50&outside=0&radius=5&wallpieces=1&edge_style=f&top=closed&thickness=3.0&format=svg&tabs=0.0&debug=0&reference=100&burn=1 - - image/svg+xml - - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/conf.py b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/conf.py deleted file mode 100644 index 304b482..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/conf.py +++ /dev/null @@ -1,94 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -import os -import sys -from datetime import datetime - -sys.path.append(os.path.abspath('../..')) - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - -project = 'boxes.py' -project_copyright = datetime.now().year.__str__() + ', Florian Festi' -author = 'Florian Festi' - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.coverage', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', -] - -templates_path = ['_templates'] -#exclude_patterns = [] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The root toctree document. -root_doc = 'index' - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = 'nature' -html_static_path = ['_static'] - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -html_logo = "../../static/boxes-logo.svg" - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -html_favicon = "../../static/favicon.ico" - -# Output file base name for HTML help builder. -htmlhelp_basename = 'boxespydoc' - -# If this is not None, a ‘Last updated on:’ timestamp is inserted at every page bottom. -html_last_updated_fmt = '' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = {} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'boxespy.tex', 'boxes.py Documentation', - 'Florian Festi', 'manual'), -] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'boxespy', 'boxes.py Documentation', - ['Florian Festi'], 1) -] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'boxespy', 'boxes.py Documentation', - 'Florian Festi', 'boxespy', 'One line description of project.', - 'Miscellaneous'), -] diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/faq.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/faq.rst deleted file mode 100644 index 93320aa..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/faq.rst +++ /dev/null @@ -1,54 +0,0 @@ -========================== -Frequently Asked Questions -========================== - -.. toctree:: - :maxdepth: 1 - -Can I sell boxes I created with Boxes.py ----------------------------------------- - -Yes. Boxes.py is under the GPLv3 license (see https://www.gnu.org/licenses/gpl-3.0.html). This license grants you far reaching rights on what you can do with the software including using it and the drawings it produces to any means. The license also puts some obligations on you. But those are about changing and distributing the software itself. The resulting drawings do not fall under the GPL license. - -Why do my parts not fit together? ---------------------------------- - -Well, this could be a bug in Boxes.py but there are a few more likely causes to check for: - -* The material you use does not have the thickness you think. Measure it with at least a caliper. Even a few hundredth of a millimeter will make the difference between a loose fit, a light or a heavy pressfit or no fit at all. - -* You might have chosen the "burn" value too big. As it compensates for the material cut away by the laser smaller values make a looser fit, bigger values make a tighter fit. The right value may be different for different materials and different thicknesses. - -Why is my box a bit too big? ----------------------------- - -By default all sizes are inner sizes. So on the outside the box is bigger as the walls need to go somewhere. Some generators offer an "outside" param that includes the walls in the measurements. In general you should check the generated parts for plausibility before hitting the start button on your laser cutter. - -Why is my box a bit too small? ------------------------------- - -See above. - -Why are my parts in the totally wrong size? -------------------------------------------- - -Unfortunately some formats do not save the units of measurement or don't do so properly. DXF and SVG fall into this category. So different tools may see the same file in different sizes. You can use the "reference" param to get a rectangle of a defined size to check if the size is still right at the end of your tool chain. - -Why are there tiny, weird loops in the corners? ------------------------------------------------ - -These are called dog bones and make sure the corner is completely cut out. As lasers and milling tools are round they can't cut sharp inner corners. Have a look at :doc:`burn correction details ` for details. - -I really don't want those weird, tiny loops? --------------------------------------------- - -You can set the ``inner_corners`` default setting to ``corner`` - -What settings were used to generate a drawing? ----------------------------------------------- - -If you do have a SVG or PostScript you can look into the meta data of the file. Most document viewers will have a ``Document properties`` window. You can also just open the file with a text editor and find the details at the first few lines. - -Note that you can just use the URL in there to get back to the settings page to change some values. The difference between the settings and the rendered drawing is just ``render=0`` or ``render=1`` at the end of the URL. - -For other formats you are currently out of luck. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/generators.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/generators.rst deleted file mode 100644 index c6e1348..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/generators.rst +++ /dev/null @@ -1,9 +0,0 @@ -All Box Generators -================== - -Generators are organized in several Groups - -.. contents:: - :local: - -.. include:: generators.inc diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/index.html b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/index.html deleted file mode 100644 index bab73b0..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - Page Redirection - - - If you are not redirected automatically, follow this link. - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/index.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/index.rst deleted file mode 100644 index 3cf232b..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/index.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. boxes.py documentation master file, created by - sphinx-quickstart on Sun Mar 27 12:04:59 2016. - -Boxes.py -======== - -Create boxes and more with a laser cutter! - -Contents: - -.. toctree:: - :maxdepth: 1 - - README - faq - install - usermanual - CONTRIBUTING.rst - apidoc - generators - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install.rst deleted file mode 100644 index 6966fad..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install.rst +++ /dev/null @@ -1,112 +0,0 @@ -Installation -============ - -Boxes.py is a pure Python project that does support the regular setuptools -method of shipping with :code:`setup.py`. :code:`setup.py --help-commands` and -:code:`setup.py CMD --help` provide the necessary documentation for building, -installing or building binary formats. - -Requirements ------------- - -Affine -........ -:code:`Affine` (package name may be :code:`python-affine` or -:code:`python3-affine`) is used for vector calculation. - -Shapely -....... -:code:`shapely` (package name may be :code:`python-shapely` or -:code:`python3-shapely`) is used for filling shapes (with holes). - - -Markdown -........ -:code:`Markdown` (package name may be :code:`python-markdown` or -:code:`python3-markdown`) is used to format the description texts. - - -setuptools -.......... - -Setup.py uses the :code:`setuptools` library (package name may be -:code:`python*-setuptools`). You only need it if you want to build the -package. - -pstoedit -........ - -While not a hard requirement Boxes.py uses :code:`pstoedit` (sometimes :code:`ps2edit`) to offer formats -that are not supported by Cairo: DXF, gcode, PLT. Currently the location -Boxes.py looks for :code:`pstoedit` is hard coded to :code:`/usr/bin/pstoedit` -in the :code:`boxes.formats.Formats` class. - -Python -...... - -Boxes.py is implemented in Python 3. For supported minor version see :code:`setup.py`. - -Sphinx -...... - -For building the documentation locally you need the *Sphinx* documentation -generator (package name may be python-sphinx or python3-sphinx). It is -not needed for anything else. Boxes.py can be run and changed just -fine without. - -Running from working dir ------------------------- - -Due to lazy developer(s) Boxes.py can also run from the Git checkout. -The scripts in :code:`scripts/` are all supposed to just work right -after :code:`git clone`. The Inkscape needs a bit manual work to get -running. See below. - -Inkscape --------- - -**As binary** - -Boxes.py can be used as a set of Inkscape plugins. The package does -install the necessary .inx files to :code:`/usr/share/inkscape/extensions` -on unix operating systems. The .inx files assume that the :code:`boxes` -executable is available in the path (which it is when installing the -binary package) - -**git repository easy way** - -After cloning it may be most convenient to generate the .inx files -right in place by executing :code:`scripts/boxes2inkscape` with the target -path as only parameter. - -- global: :code:`scripts/boxes2inkscape /usr/share/inkscape/extensions/` -- userspace: :code:`scripts/boxes2inkscape ~/.config/inkscape/extensions/` - -On non unix operating the target directories may differ. You can look -up the directories *"User extensions"* and *"Inkscape extensions"* within -the Inkscape preferences *Edit -> Preferences... -> System*. - -**git repository manual way** - -:code:`setup.py build` creates the :code:`*.inx` files in the :code:`inkex/` directory. - -They then have to be copied in either the global or the per user -extension directory of Inkscape. These are -:code:`/usr/share/inkscape/extensions/` and -:code:`~/.config/inkscape/extensions/` on a unix operating system. -On non unix operating the target directories may differ. You can look -up the directories *"User extensions"* and *"Inkscape extensions"* within -the Inkscape preferences *Edit -> Preferences... -> System*. - -As an alternative you can create a symlink to the :code:`inkex/` directory -within the desired inkscape extension directory. - - -Platform specific instructions ------------------------------- - -.. toctree:: - :maxdepth: 2 - :glob: - - install/* diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/log-wsl-win11.txt b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/log-wsl-win11.txt deleted file mode 100644 index d1c474b..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/log-wsl-win11.txt +++ /dev/null @@ -1,173 +0,0 @@ -usuario@Soporte-3:~$ git clone https://github.com/florianfesti/boxes.git -Cloning into 'boxes'... -remote: Enumerating objects: 7867, done. -remote: Counting objects: 100% (545/545), done. -remote: Compressing objects: 100% (328/328), done. -remote: Total 7867 (delta 234), reused 514 (delta 216), pack-reused 7322 -Receiving objects: 100% (7867/7867), 64.82 MiB | 5.45 MiB/s, done. -Resolving deltas: 100% (5330/5330), done. -usuario@Soporte-3:~$ cd boxes -usuario@Soporte-3:~/boxes$ ls -boxes documentation LICENSE.txt po scripts -CODE_OF_CONDUCT.md examples locale README.rst setup.py -CONTRIBUTING.rst inkex MANIFEST.in requirements.txt static -usuario@Soporte-3:~/boxes$ python3 -m pip install -r requirements.txt -Collecting affine - Downloading affine-2.3.1-py2.py3-none-any.whl (16 kB) -Collecting markdown - Downloading Markdown-3.4.1-py3-none-any.whl (93 kB) - |████████████████████████████████| 93 kB 1.7 MB/s -Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from -r requirements.txt (line 3)) (52.0.0) -Collecting sphinx - Downloading sphinx-5.2.3-py3-none-any.whl (3.2 MB) - |████████████████████████████████| 3.2 MB 8.2 MB/s -Collecting shapely - Downloading Shapely-1.8.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (2.1 MB) - |████████████████████████████████| 2.1 MB 5.4 MB/s -Collecting importlib-metadata>=4.4 - Downloading importlib_metadata-5.0.0-py3-none-any.whl (21 kB) -Collecting zipp>=0.5 - Downloading zipp-3.9.0-py3-none-any.whl (5.8 kB) -Collecting docutils<0.20,>=0.14 - Downloading docutils-0.19-py3-none-any.whl (570 kB) - |████████████████████████████████| 570 kB 5.2 MB/s -Collecting snowballstemmer>=2.0 - Downloading snowballstemmer-2.2.0-py2.py3-none-any.whl (93 kB) - |████████████████████████████████| 93 kB 1.2 MB/s -Collecting Pygments>=2.12 - Downloading Pygments-2.13.0-py3-none-any.whl (1.1 MB) - |████████████████████████████████| 1.1 MB 4.4 MB/s -Collecting sphinxcontrib-serializinghtml>=1.1.5 - Downloading sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl (94 kB) - |████████████████████████████████| 94 kB 3.6 MB/s -Collecting packaging>=21.0 - Downloading packaging-21.3-py3-none-any.whl (40 kB) - |████████████████████████████████| 40 kB 4.4 MB/s -Collecting sphinxcontrib-devhelp - Downloading sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl (84 kB) - |████████████████████████████████| 84 kB 4.6 MB/s -Collecting sphinxcontrib-htmlhelp>=2.0.0 - Downloading sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl (100 kB) - |████████████████████████████████| 100 kB 6.5 MB/s -Collecting requests>=2.5.0 - Downloading requests-2.28.1-py3-none-any.whl (62 kB) - |████████████████████████████████| 62 kB 1.1 MB/s -Collecting Jinja2>=3.0 - Downloading Jinja2-3.1.2-py3-none-any.whl (133 kB) - |████████████████████████████████| 133 kB 8.4 MB/s -Collecting sphinxcontrib-jsmath - Downloading sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl (5.1 kB) -Collecting imagesize>=1.3 - Downloading imagesize-1.4.1-py2.py3-none-any.whl (8.8 kB) -Collecting alabaster<0.8,>=0.7 - Downloading alabaster-0.7.12-py2.py3-none-any.whl (14 kB) -Collecting babel>=2.9 - Downloading Babel-2.10.3-py3-none-any.whl (9.5 MB) - |████████████████████████████████| 9.5 MB 9.2 MB/s -Collecting sphinxcontrib-applehelp - Downloading sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl (121 kB) - |████████████████████████████████| 121 kB 9.5 MB/s -Collecting sphinxcontrib-qthelp - Downloading sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl (90 kB) - |████████████████████████████████| 90 kB 7.2 MB/s -Collecting pytz>=2015.7 - Downloading pytz-2022.4-py2.py3-none-any.whl (500 kB) - |████████████████████████████████| 500 kB 10.4 MB/s -Collecting MarkupSafe>=2.0 - Downloading MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB) -Collecting pyparsing!=3.0.5,>=2.0.2 - Downloading pyparsing-3.0.9-py3-none-any.whl (98 kB) - |████████████████████████████████| 98 kB 6.0 MB/s -Collecting charset-normalizer<3,>=2 - Downloading charset_normalizer-2.1.1-py3-none-any.whl (39 kB) -Collecting idna<4,>=2.5 - Downloading idna-3.4-py3-none-any.whl (61 kB) - |████████████████████████████████| 61 kB 206 kB/s -Collecting certifi>=2017.4.17 - Downloading certifi-2022.9.24-py3-none-any.whl (161 kB) - |████████████████████████████████| 161 kB 9.3 MB/s -Collecting urllib3<1.27,>=1.21.1 - Downloading urllib3-1.26.12-py2.py3-none-any.whl (140 kB) - |████████████████████████████████| 140 kB 8.0 MB/s -Installing collected packages: zipp, urllib3, pytz, pyparsing, MarkupSafe, idna, charset-normalizer, certifi, sphinxcontrib-serializinghtml, sphinxcontrib-qthelp, sphinxcontrib-jsmath, sphinxcontrib-htmlhelp, sphinxcontrib-devhelp, sphinxcontrib-applehelp, snowballstemmer, requests, Pygments, packaging, Jinja2, importlib-metadata, imagesize, docutils, babel, alabaster, sphinx, shapely, markdown, affine - WARNING: The script normalizer is installed in '/home/usuario/.local/bin' which is not on PATH. - Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. - WARNING: The script pygmentize is installed in '/home/usuario/.local/bin' which is not on PATH. - Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. - WARNING: The script docutils is installed in '/home/usuario/.local/bin' which is not on PATH. - Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. - WARNING: The script pybabel is installed in '/home/usuario/.local/bin' which is not on PATH. - Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. - WARNING: The scripts sphinx-apidoc, sphinx-autogen, sphinx-build and sphinx-quickstart are installed in '/home/usuario/.local/bin' which is not on PATH. - Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. - WARNING: The script markdown_py is installed in '/home/usuario/.local/bin' which is not on PATH. - Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. -Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.1 Pygments-2.13.0 affine-2.3.1 alabaster-0.7.12 babel-2.10.3 certifi-2022.9.24 charset-normalizer-2.1.1 docutils-0.19 idna-3.4 imagesize-1.4.1 importlib-metadata-5.0.0 markdown-3.4.1 packaging-21.3 pyparsing-3.0.9 pytz-2022.4 requests-2.28.1 shapely-1.8.5 snowballstemmer-2.2.0 sphinx-5.2.3 sphinxcontrib-applehelp-1.0.2 sphinxcontrib-devhelp-1.0.2 sphinxcontrib-htmlhelp-2.0.0 sphinxcontrib-jsmath-1.0.1 sphinxcontrib-qthelp-1.0.3 sphinxcontrib-serializinghtml-1.1.5 urllib3-1.26.12 zipp-3.9.0 -usuario@Soporte-3:~/boxes$ ls -boxes documentation LICENSE.txt po scripts -CODE_OF_CONDUCT.md examples locale README.rst setup.py -CONTRIBUTING.rst inkex MANIFEST.in requirements.txt static -usuario@Soporte-3:~/boxes$ ls scripts -boxes boxes2inkscape boxes2pot boxes_example.ipynb boxesserver Dockerfile gen_thumbnails.sh -usuario@Soporte-3:~/boxes$ python3 scripts/boxesserver -BoxesServer serving on host:port :8000... -127.0.0.1 - - [13/Oct/2022 10:53:34] "GET / HTTP/1.1" 200 32493 -127.0.0.1 - - [13/Oct/2022 10:53:34] "GET /static/self.css HTTP/1.1" 200 2357 -127.0.0.1 - - [13/Oct/2022 10:53:34] "GET /static/fonts.css HTTP/1.1" 200 1592 -127.0.0.1 - - [13/Oct/2022 10:53:35] "GET /static/normalize.css HTTP/1.1" 200 4693 -127.0.0.1 - - [13/Oct/2022 10:53:35] "GET /static/boxes-logo.svg HTTP/1.1" 200 12702 -127.0.0.1 - - [13/Oct/2022 10:53:35] "GET /static/nothing.png HTTP/1.1" 200 89 -127.0.0.1 - - [13/Oct/2022 10:53:35] "GET /static/fonts/bungeeshade/v3/DtVkJxarWL0t2KdzK3oI_jkc6SjT.woff2 HTTP/1.1" 200 42432 -127.0.0.1 - - [13/Oct/2022 10:53:35] "GET /static/nothing.png HTTP/1.1" 200 89 -127.0.0.1 - - [13/Oct/2022 10:53:35] "GET /static/favicon.ico HTTP/1.1" 200 16958 -127.0.0.1 - - [13/Oct/2022 10:53:36] "GET /static/samples/TrafficLight-thumb.jpg HTTP/1.1" 200 4100 -127.0.0.1 - - [13/Oct/2022 10:53:37] "GET /static/samples/BurnTest-thumb.jpg HTTP/1.1" 200 3422 -127.0.0.1 - - [13/Oct/2022 10:53:37] "GET /static/samples/ HTTP/1.1" 404 9 -127.0.0.1 - - [13/Oct/2022 10:53:38] "GET /static/samples/UniversalBox-thumb.jpg HTTP/1.1" 200 5133 -127.0.0.1 - - [13/Oct/2022 10:53:38] "GET /static/samples/RoundedBox-thumb.jpg HTTP/1.1" 200 2803 -127.0.0.1 - - [13/Oct/2022 10:53:38] "GET /static/samples/TypeTray-thumb.jpg HTTP/1.1" 200 3553 -127.0.0.1 - - [13/Oct/2022 10:53:38] "GET /static/samples/DisplayShelf-thumb.jpg HTTP/1.1" 200 4419 -127.0.0.1 - - [13/Oct/2022 10:53:38] "GET /static/samples/WallTypeTray-thumb.jpg HTTP/1.1" 200 4143 -127.0.0.1 - - [13/Oct/2022 10:53:41] "GET /static/samples/ HTTP/1.1" 404 9 -127.0.0.1 - - [13/Oct/2022 10:53:42] "GET /static/samples/ HTTP/1.1" 404 9 -127.0.0.1 - - [13/Oct/2022 10:53:42] "GET /static/samples/Atreus21-thumb.jpg HTTP/1.1" 200 6502 -127.0.0.1 - - [13/Oct/2022 10:53:42] "GET /static/samples/BottleTag-thumb.jpg HTTP/1.1" 200 6969 -127.0.0.1 - - [13/Oct/2022 10:53:42] "GET /static/samples/CanStorage-thumb.jpg HTTP/1.1" 200 5444 -127.0.0.1 - - [13/Oct/2022 10:53:43] "GET /static/samples/CoinDisplay-thumb.jpg HTTP/1.1" 200 4469 -127.0.0.1 - - [13/Oct/2022 10:53:43] "GET /static/samples/CoffeeCapsuleHolder-thumb.jpg HTTP/1.1" 200 4235 -127.0.0.1 - - [13/Oct/2022 10:53:47] "GET /static/samples/BottleStack-thumb.jpg HTTP/1.1" 200 89 -127.0.0.1 - - [13/Oct/2022 10:53:50] "GET /static/samples/Arcade-thumb.jpg HTTP/1.1" 200 89 -127.0.0.1 - - [13/Oct/2022 10:53:53] "GET /BottleTag?language=en HTTP/1.1" 200 7965 -127.0.0.1 - - [13/Oct/2022 10:53:53] "GET /static/self.css HTTP/1.1" 200 2357 -127.0.0.1 - - [13/Oct/2022 10:53:54] "GET /static/fonts.css HTTP/1.1" 200 1592 -127.0.0.1 - - [13/Oct/2022 10:53:54] "GET /static/normalize.css HTTP/1.1" 200 4693 -127.0.0.1 - - [13/Oct/2022 10:53:54] "GET /static/boxes-logo.svg HTTP/1.1" 200 12702 -127.0.0.1 - - [13/Oct/2022 10:53:54] "GET /static/samples/BottleTag.jpg HTTP/1.1" 200 82889 -127.0.0.1 - - [13/Oct/2022 10:53:54] "GET /static/fonts/bungeeshade/v3/DtVkJxarWL0t2KdzK3oI_jkc6SjT.woff2 HTTP/1.1" 200 42432 -127.0.0.1 - - [13/Oct/2022 10:53:54] "GET /static/fonts/luckiestguy/v8/_gP_1RrxsjcxVyin9l9n_j2hTd52.woff2 HTTP/1.1" 200 17024 -127.0.0.1 - - [13/Oct/2022 10:53:57] "GET /BottleTag?width=72&height=98&min_diameter=24&max_diameter=50&radius=15&segment_width=3&thickness=3.0&format=svg&tabs=0.0&debug=0&labels=0&labels=1&reference=100&inner_corners=loop&burn=0.1&render=1 HTTP/1.1" 200 6346 -127.0.0.1 - - [13/Oct/2022 10:53:57] "GET /favicon.ico HTTP/1.1" 200 32493 -127.0.0.1 - - [13/Oct/2022 10:55:22] "GET /BottleTag?width=70&height=90&min_diameter=44&max_diameter=60&radius=8&segment_width=3&thickness=3.0&format=svg&tabs=0.0&debug=0&labels=0&labels=1&reference=100&inner_corners=loop&burn=0.1&render=1 HTTP/1.1" 200 7988 -127.0.0.1 - - [13/Oct/2022 10:55:22] "GET /favicon.ico HTTP/1.1" 200 32493 -127.0.0.1 - - [13/Oct/2022 12:04:45] "GET / HTTP/1.1" 200 32493 -127.0.0.1 - - [13/Oct/2022 12:04:45] "GET /static/self.css HTTP/1.1" 200 2357 -127.0.0.1 - - [13/Oct/2022 12:04:45] "GET /static/fonts.css HTTP/1.1" 200 1592 -127.0.0.1 - - [13/Oct/2022 12:04:45] "GET /static/normalize.css HTTP/1.1" 200 4693 -127.0.0.1 - - [13/Oct/2022 12:04:45] "GET /static/boxes-logo.svg HTTP/1.1" 200 12702 -127.0.0.1 - - [13/Oct/2022 12:04:45] "GET /static/nothing.png HTTP/1.1" 200 89 -127.0.0.1 - - [13/Oct/2022 12:04:46] "GET /static/fonts/bungeeshade/v3/DtVkJxarWL0t2KdzK3oI_jkc6SjT.woff2 HTTP/1.1" 200 42432 -127.0.0.1 - - [13/Oct/2022 12:04:46] "GET /static/samples/RoundedBox-thumb.jpg HTTP/1.1" 200 2803 -127.0.0.1 - - [13/Oct/2022 12:04:53] "GET /static/samples/RoundedBox-thumb.jpg HTTP/1.1" 200 2803 -127.0.0.1 - - [13/Oct/2022 12:04:54] "GET /static/samples/UniversalBox-thumb.jpg HTTP/1.1" 200 5133 -127.0.0.1 - - [13/Oct/2022 12:04:54] "GET /static/samples/ HTTP/1.1" 404 9 -127.0.0.1 - - [13/Oct/2022 12:04:54] "GET /static/samples/BurnTest-thumb.jpg HTTP/1.1" 200 3422 -127.0.0.1 - - [13/Oct/2022 12:04:55] "GET /static/samples/TrafficLight-thumb.jpg HTTP/1.1" 200 4100 -127.0.0.1 - - [13/Oct/2022 12:04:55] "GET /static/samples/ HTTP/1.1" 404 9 -127.0.0.1 - - [13/Oct/2022 12:04:55] "GET /static/samples/TypeTray-thumb.jpg HTTP/1.1" 200 3553 -127.0.0.1 - - [13/Oct/2022 12:04:57] "GET /static/samples/ HTTP/1.1" 404 9 -127.0.0.1 - - [13/Oct/2022 12:07:01] "GET /static/samples/RoundedBox-thumb.jpg HTTP/1.1" 200 2803 -127.0.0.1 - - [13/Oct/2022 12:07:01] "GET /static/samples/UniversalBox-thumb.jpg HTTP/1.1" 200 5133 -127.0.0.1 - - [13/Oct/2022 12:07:03] "GET /static/samples/TypeTray-thumb.jpg HTTP/1.1" 200 3553 -127.0.0.1 - - [13/Oct/2022 12:07:03] "GET /static/samples/TrafficLight-thumb.jpg HTTP/1.1" 200 4100 -127.0.0.1 - - [13/Oct/2022 12:07:05] "GET /static/samples/ HTTP/1.1" 404 9 -^CBoxesServer stops. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/macos.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/macos.rst deleted file mode 100644 index f385d15..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/macos.rst +++ /dev/null @@ -1,124 +0,0 @@ -macOS -===== - -It is recommended to use Homebrew to install the dependencies for Boxes.py. -See `brew.sh `__ on how to install Homebrew. - -General -------- - -1. Install Python 3 and other dependencies: - - .. code:: - - brew install python3 git - - Optional: - - .. code:: - - brew install pstoedit - - -2. Install cairio: - - .. code:: - - brew install pkg-config - - -3. Install required Python modules: - - .. code:: - - pip3 install Markdown affine shapely - -4. Download Boxes.py via Git: - - .. code:: - - git clone https://github.com/florianfesti/boxes.git - -5. Run Boxes.py: - - Local web server on port 8000: - - .. code:: - - ./scripts/boxesserver - - Command line variant (CLI): - - .. code:: - - ./scripts/boxes - - -System-wide with Inkscape extension ------------------------------------ - -To install Boxes.py system-wide with the Inkscape extension, following steps -are required: - -1. Install Inkscape with Homebrew Cask - (requires `XQuartz `__): - - .. code:: - - brew install inkscape - -2. From the root directory of the repository, run: - - .. code:: - - ./setup.py install - -3. Now :code:`boxes` and :code:`boxesserver` can be executed like other commands - and the Inkscape extension should be available. - - -Troubleshooting -............... - -When using the Inkscape extension something like the following error -might occur: - -:: - - Traceback (most recent call last): - File "/Users/martin/.config/inkscape/extensions/boxes", line 107, in - main() - File "/Users/martin/.config/inkscape/extensions/boxes", line 47, in main - run_generator(name, sys.argv[2:]) - File "/Users/martin/.config/inkscape/extensions/boxes", line 73, in run_generator - box.close() - File "/usr/local/lib/python3.7/site-packages/boxes-0.1-py3.7.egg/boxes/__init__.py", line 594, in close - svgutil.svgMerge(self.output, self.inkscapefile, out) - File "/usr/local/lib/python3.7/site-packages/boxes-0.1-py3.7.egg/boxes/svgutil.py", line 144, in svgMerge - from lxml import etree as et - ImportError: dlopen(/Applications/Inkscape.app/Contents/Resources/lib/python2.7/site-packages/lxml/etree.so, 2): Symbol not found: _PyBaseString_Type - Referenced from: /Applications/Inkscape.app/Contents/Resources/lib/python2.7/site-packages/lxml/etree.so - Expected in: flat namespace - -This is because Inkscape on macOS ships its own version of Python 2.7 where -:code:`lxml` and other dependencies are missing. - -A workaround is to edit the file at -:code:`/Applications/Inkscape.app/Contents/Resources/bin/inkscape`. -At line 79 there should be following code: - -.. code:: - - export PYTHONPATH="$TOP/lib/python$PYTHON_VERS/site-packages/" - -which needs to be changed to - -.. code:: - - #export PYTHONPATH="$TOP/lib/python$PYTHON_VERS/site-packages/" - -This forces Inkscape to use the Python version installed by Homebrew which -has all the necessary dependencies installed. - -Note: This might break other extensions. In this case simply change the line -back and restart Inkscape. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/win11-wsl-boxesserver-localhost.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/win11-wsl-boxesserver-localhost.png deleted file mode 100644 index 83c00a6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/win11-wsl-boxesserver-localhost.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows.rst deleted file mode 100644 index ce6a3ed..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows.rst +++ /dev/null @@ -1,93 +0,0 @@ -Windows -======= - -Getting the Inkscape plugins to run will likely need manual -installation (see above). Note that Inkscape may come with its own -Python. If you run into trouble or have better installation -instructions please open a ticket on GitHub. - -Native ------- - -Following steps are known to work under Windows 10/11 (64-bit): - -1. Go to https://www.python.org/downloads/windows/ - and download the current stable "Windows x86-64 executable installer" - for Python 3. - When this guide was written, Python 3.7 was the current version. - - .. figure:: windows_browser_download_python.png - :scale: 50% - :alt: Screenshot of python.org with download of Python 3.7 (64-bit) - :align: center - -2. Install Python 3 and make sure to check "Add Python 3.X to PATH" - while doing so - - .. figure:: windows_install_python_path.png - :scale: 50% - :alt: Screenshot of Python 3.7 (64-bit) installer with PATH checked - :align: center - -3. Run the command :code:`pip install Markdown affine shapely qrcode` - (Note: If the command pip is not found, you probably forgot to add the - Python installation to the PATH environment variable in step 2) - -4. Download Boxes.py as ZIP archive from GitHub - - .. figure:: windows_browser_download_boxespy.png - :scale: 50% - :alt: Screenshot of download from Boxes.py project on GitHub - :align: center - -5. Extract the ZIP archive - (e.g. via the built-in Windows feature or other tools like 7-Zip) - - .. figure:: windows_boxespy_zip_extract.png - :scale: 50% - :alt: Screenshot of Windows tools to extract the ZIP archive - :align: center - -6. Change into the folder for Boxes.py, - e.g. with the command :code:`cd \\Users\\[USERNAME]\\Downloads\\boxes-master` -7. Run the development server with the command - :code:`python scripts\\boxesserver` - Note: You likely will be notified by your firewall that it blocked network - access. If you want to use boxesserver you need to allow connections. - - .. figure:: windows_cmd_python_boxesserver_firewall.png - :scale: 50% - :alt: Screenshot of command for running boxesserver and firewall notice - :align: center - -8. Open the address http://localhost:8000/ in your browser and have fun :) - - .. figure:: windows_browser_boxespy.png - :scale: 50% - :alt: Screenshot of a browser window running Boxes.py locally - :align: center - - -Additionally the command line version of Boxes.py can be used with -the command :code:`python scripts\\boxes`. - -Windows Subsystem for Linux ---------------------------- - -Another way of installing Boxes.py on Windows is to use the Windows Subsystem -for Linux (WSL). This requires newer versions of Windows 10. Once it is -installed (e.g. via the Ubuntu App from the Microsoft Store), the installation -is identical to the installation on Linux systems. - -Once wsl is installed, run it and enter the following commands: - -- :code:`cd ~` -- :code:`git clone https://github.com/florianfesti/boxes.git` -- :code:`cd ~/boxes` -- :code:`python3 -m pip install -r ~/boxes/requirements.txt` -- :code:`python3 ~/boxes/scripts/boxesserver` - -.. figure:: win11-wsl-boxesserver-localhost.png - :scale: 50% - :alt: Screenshot of a browser window running Boxes.py locally on WSL - :align: center diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_boxespy_zip_extract.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_boxespy_zip_extract.png deleted file mode 100644 index 2c45312..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_boxespy_zip_extract.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_boxespy.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_boxespy.png deleted file mode 100644 index 5adeed8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_boxespy.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_download_boxespy.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_download_boxespy.png deleted file mode 100644 index 0fb9578..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_download_boxespy.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_download_python.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_download_python.png deleted file mode 100644 index 06b14a1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_browser_download_python.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_cmd_python_boxesserver_firewall.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_cmd_python_boxesserver_firewall.png deleted file mode 100644 index b3f8e76..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_cmd_python_boxesserver_firewall.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_install_python_path.png b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_install_python_path.png deleted file mode 100644 index 014257a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/install/windows_install_python_path.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/make.bat b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/make.bat deleted file mode 100644 index b12580f..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=../build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/modules.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/modules.rst deleted file mode 100644 index 8a714cb..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/modules.rst +++ /dev/null @@ -1,9 +0,0 @@ -:orphan: - -boxes -===== - -.. toctree:: - :maxdepth: 4 - - boxes diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/overcuts.svg b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/overcuts.svg deleted file mode 100644 index 39e6a8e..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/overcuts.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/static b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/static deleted file mode 120000 index 1bf4a07..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/static +++ /dev/null @@ -1 +0,0 @@ -../../static/ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/usermanual.rst b/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/usermanual.rst deleted file mode 100644 index 4428a7c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/documentation/src/usermanual.rst +++ /dev/null @@ -1,253 +0,0 @@ -============== -Using Boxes.py -============== - -.. toctree:: - :maxdepth: 2 - -Boxes.py is made of a library that is not visible to the user and -multiple generators -- each having its own set of parameters and -creating a drawing for it own type of object. These generators are -divided up into different groups to make it easier to find them: - -* Boxes -* Boxes with flex -* Trays and Drawer Inserts -* Shelves -* Parts and Samples -* Misc -* Unstable - -The parameters for each generators also come in groups. - -Units of measurements ---------------------- - -In general all measurements are in Millimeters (mm). There is no -option to change the units of measurement and there is no plan to add -such a option. - -A second way to define lengths is as multiple of the material -thickness which is one of the standard parameters described -below. This allows features to retain their proportions even if some -parts depend on the material thickness. - -The description texts should state the unit of each argument - -please open a ticket if the units are missing somewhere. - -.. _default-args: - -Default arguments ------------------ -In the web interface this is the bottom group right before the -``Render`` button. These are basically all technical settings that -have little to do with the object being rendered but more with the -material used and the way the drawing and the material is processed. - -The settings are - -thickness -......... - -The thickness of the material used. This value is used at many places -to define the sizes of features like finger joints, hinges, ... It is -very important to get the value right - especially if there are -fingers that need to fit into some holes. Be aware that many materials -may differ from their nominal value. You should **always measure the -thickness** for every sheet unless you have a very reliable supply -that is known to stick very closely to specifications. For (ply) wood -even a 100th of a millimeter makes a notable difference in how stiff -the fit is. Harder more brittle materials may be even more picky. - -burn -.... - -The burn correction aka kerf is the distance the laser has to keep -from the edge of the parts. If the laser would cut right on the edge -it would cut away the outside perimeter of the part. So the burn value is -basically the radius of the laser - or half the width of the laser cut. - -The value of the burn parameter depends on your laser cutter, the -material cut and the thickness of the material. In addition it depends -on whether you want the parts to be over or under sized. Materials -that are spongy like wood can be cut oversized (larger burn value) so -they can be press fitted with some force and may be assembled without -glue. Brittle materials (like Acrylic) need to be cut undersized to -leave a gap for the glue. - -**Note:** The way the burn param works is a bit counter intuitive. Bigger -burn values make a tighter fit. Smaller values make a looser fit. - -Small changes in the burn param can make a notable difference. Typical -steps for adjustment are 0.01 or even 0.005mm to choose between -different amounts of force needed to press plywood together. - -To find the right burn value cut out a rectangle and then measure how -much smaller it is than its nominal size. The burn value should be -around half of the difference. To test the fit for several values at -once you can use the **BurnTest** generator in the "Parts and Samples" section. - -format -...... - -Boxes.py is able to create multiple formats. For most of them it -requires ``pstoedit``. Without ``pstoedit`` only ``SVG`` -and ``postscript`` (ps) is supported. Otherwise you can also -select - -* dxf -* gcode -* pdf -* plt - -Other formats supported by ``pstoedit`` can be added easily. Please -open a ticket on GitHub if you need one. - -tabs -.... - -Tabs are small bridges between the parts and surrounding material that -keep the part from falling out. In theory their width should be -affected by the burn parameter. But it is more practical to have both -independent so you can tune them separately. Most parts and generators -support this features but there may be some that don't. - -For plywood values of 0.2 to 0.3mm still allow getting the parts out -by hand (Depending on you laser cutter and the exact material). With -little more you will need a knife to cut them loose. - -inner_corners -............. - -How to handle inner corners. Inner corners are an issue as a round -tool like a laser or mill cannot create sharp inner corners. There are -different options: - -* ``loop`` create a loop that fills the corner -* ``corner`` just a simple sharp corner in the path that will leave a - radius untouched. -* ``backarc`` naive implementation with inverted arcs connection the - straight lines. - -See also :doc:`burn correction details ` - -debug -..... - -Most regular users won't need this option. - -It adds some construction lines that are helpful for -developing new generators. Only few pieces actually support the -parameter. The most notable being finger holes that show the border of -the piece they belong to. This helps checking whether the finger holes -are placed correctly. - -reference -......... - -Converting vector graphics is error prone. Many formats have very -weird ideas how their internal units translates to real world -dimensions. If reference is set to non zero Boxes.py renders a rectangle of -the given length. It can be used to check if the drawing is still at -the right scale or may give clues on how to scale it back to the right -proportions. - -Common Parameters and Types ---------------------------- - -Section parameters -.................. - -Some generators support an arbitrary number of sections. This can be used for rows or columns of compartments, staggered heights or otherwise dividing some length in multiple sub sections. The standard parameter making use of this are ``sx``, ``sy`` and ``sh`` (instead of ``x``, ``y`` and ``h``). - -Most generators will add walls between the comparments, so the total size might be larger depending on the number of compartments (and additional walls). - -The sizes of the sections are divided by a colon (``:``) e.g. ``30:25.5:70``. Instead of repeating the same value they can be replaced by ``value*numberofsections`` e.g. ``50*3`` meaning the same as ``50:50:50``. To equally divide a length into several sections ``overallwidth/numberofsections`` can be used - e.g. ``120/4`` being the same as ``30:30:30:30``. All these formats can be freely mixed. - -mounting_holes -.................. -Some generators provide the option to create pear shaped mounting holes. To generate the right size holes, the shaft and the head diameter of the mounting screw must be configured. The format is "shaft:head", both diameters given in mm (e.g ``3.5:6.5``). If only the shaft diameter is given (e.g. ``3.5``), a round mounting hole is generated. Setting the mounting hole diameter parameter to ``0`` disables the creation of mounting holes. - -outside -....... - -Most measurements are internal sizes. If a generator offers this parameter it will re-calculate the inner sizes to fit walls and outside features within the given dimensions. This can be a bit surprising for edge types that have protrusions like hinge eyes, handles, feet, etc as those are typically also taken into account. If the dimensions are not sufficient to accommodate these features the box may not work properly. Most generators do not have checks for such issues (like negative height) and it is left in the responsibility of the user to check if the result still is sane. - -For generators offering multiple compartments this will also fit-in the inner walls. It will sum up all sections then subtract the space needed for the walls and then scale all compartments so they will fill the remaining space. - - -Edge Type parameters --------------------- - -All but the simplest edge types have a number of settings controlling -how exactly they should look. Generators are encouraged to offer these -settings to the user. In the web interface they are folded up. In the -command line interface they are grouped together. Users should be -aware that not all settings are practical to change. For now Boxes.py -does not allow hiding some settings. - -Finger Joint Settings -..................... - -.. glossary:: - - finger - width of the fingers in multiples of the thickness - - space - width of the spaces between fingers in multiples of the thickness - - surroundingspaces - amount of space before the first and after the last finger. This is in multiples of regular space between fingers. The actual space is larger when needed but can be smaller for very short edges. - - style - how finger joints should look like. There may be more styles to choose from in the future. Note that snap fingers will only be drawn for fingers of width 1.9 and above. - - extra_length - Make the outset part of the finger joint longer to allow grinding off burn marks. Note that this may not be great for non 90° joints where the corner is butted against the opposing cutout. - - bottom_lip - Generate pieces to be glued on the inside of finger hole edges. This allows stacking boxes on top of each other. Note that finger hole edges that are used elsewhere may not have use of these pieces and you should probably just delete them before cutting. - -Stackable Edge Settings -....................... - -For boxes to actually stack they need to be the same width and depth and ``angle``, ``width`` and ``height`` of the feet need to be the same. - -.. glossary:: - - angle - inside angle of the feet. - - height - height of the feet - - holedistance - distance from finger holes to bottom edge. May be reduced to save height by sacrificing stability of the connection to the bottom of the box. - - width - width of the feet - - bottom_stabilizers - generate pieces to be glued inside of the bottom edges to stack more securely. Use a value a bit less than ``height`` ( + ``holedistance`` ) to leave some of the feet sticking out. - -Colors ------- -The generated files uses the following color conventions: - -.. glossary:: - - Black - The outer edges of a part - - Blue - Inner edges of a part - - Red - Comments or help lines that are not meant to be cut or etched - - Green - Etchings - -Normally you will cut things in the order: Green, Blue, Black. If other -colors are present, the meaning should hopefully be obvious. diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/box2.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/box2.svg deleted file mode 100644 index f667722..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/box2.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/box3.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/box3.svg deleted file mode 100644 index 386cef5..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/box3.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/castle.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/castle.svg deleted file mode 100644 index be58646..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/castle.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/drillbox.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/drillbox.svg deleted file mode 100644 index 4fb65b4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/drillbox.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox.svg deleted file mode 100644 index 467a1d2..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox2.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox2.svg deleted file mode 100644 index 6c01d2a..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox2.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox3.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox3.svg deleted file mode 100644 index e277c8b..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/flexbox3.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/folder.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/folder.svg deleted file mode 100644 index 419b438..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/folder.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/generate.sh b/extensions/fablabchemnitz/boxes.py/boxes/examples/generate.sh deleted file mode 100755 index 73e7110..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/generate.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -BOXES=../scripts/boxes - -set -x -$BOXES closedbox --x=50 --y=50 --h=70 --output=closedbox.svg -$BOXES hingebox --x=50 --y=50 --h=70 --output=hingebox.svg -$BOXES castle --output=castle.svg -$BOXES drillbox --output=drillbox.svg -$BOXES flexbox --x=70 --y=100 --h=50 --radius=20 --output=flexbox.svg -$BOXES flexbox2 --x=70 --y=100 --h=50 --radius=20 --output=flexbox2.svg -$BOXES flexbox3 --x=70 --y=100 --z=50 --h=8 --radius=30 --output=flexbox3.svg -$BOXES folder --x=165 --y=240 --h=20 --r=10 --output=folder.svg -#$BOXES lamp --x=50 --y=50 --r=10 --output=lamp.svg -$BOXES magazinefile --output=magazinefile.svg -#$BOXES printer --output=printer.svg -#$BOXES Silverwaree --output=silverwarebox.svg -#$BOXES traylayout --x=4 --y=4 --output=traylayout.txt -$BOXES traylayout2 --input=traylayout.txt --h=50 --hi=40 --output=traylayout.svg -$BOXES trayinsert --sx=70:100:70 --sy=100*3 --h=50 --output=trayinsert.svg -$BOXES typetray --sx=70:100:70 --sy=100*3 --h=60 --hi=50 --output=typetray.svg diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/lamp.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/lamp.svg deleted file mode 100644 index 061e2eb..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/lamp.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/magazinefile.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/magazinefile.svg deleted file mode 100644 index 0930a13..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/magazinefile.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/silverwarebox.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/silverwarebox.svg deleted file mode 100644 index 26cf5a0..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/silverwarebox.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/trayinsert.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/trayinsert.svg deleted file mode 100644 index d861588..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/trayinsert.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/traylayout.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/traylayout.svg deleted file mode 100644 index 4e24fcc..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/traylayout.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/traylayout.txt b/extensions/fablabchemnitz/boxes.py/boxes/examples/traylayout.txt deleted file mode 100644 index bd05b85..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/traylayout.txt +++ /dev/null @@ -1,13 +0,0 @@ - ,> 40.0mm - | ,> 50.0mm - | | ,> 50.0mm - | | | ,> 40.0mm -+-+-+-+-+ -| | | 60.0mm -+-+-+-+-+ -| | | | 50.0mm -+ +-+-+ + -| | | | 50.0mm -+-+-+-+-+ -| | | 40.0mm -+ + + + + diff --git a/extensions/fablabchemnitz/boxes.py/boxes/examples/typetray.svg b/extensions/fablabchemnitz/boxes.py/boxes/examples/typetray.svg deleted file mode 100644 index 2c01f77..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/examples/typetray.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/locale/de/LC_MESSAGES/boxes.py.mo b/extensions/fablabchemnitz/boxes.py/boxes/locale/de/LC_MESSAGES/boxes.py.mo deleted file mode 100644 index e409ac4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/locale/de/LC_MESSAGES/boxes.py.mo and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/locale/en/LC_MESSAGES/boxes.py.mo b/extensions/fablabchemnitz/boxes.py/boxes/locale/en/LC_MESSAGES/boxes.py.mo deleted file mode 100644 index 78e21f2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/locale/en/LC_MESSAGES/boxes.py.mo and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/locale/fr/LC_MESSAGES/boxes.py.mo b/extensions/fablabchemnitz/boxes.py/boxes/locale/fr/LC_MESSAGES/boxes.py.mo deleted file mode 100644 index 64bd4f9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/locale/fr/LC_MESSAGES/boxes.py.mo and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/locale/zh_CN/LC_MESSAGES/boxes.py.mo b/extensions/fablabchemnitz/boxes.py/boxes/locale/zh_CN/LC_MESSAGES/boxes.py.mo deleted file mode 100644 index 636db54..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/locale/zh_CN/LC_MESSAGES/boxes.py.mo and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/po/boxes.py.pot b/extensions/fablabchemnitz/boxes.py/boxes/po/boxes.py.pot deleted file mode 100644 index 307f7af..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/po/boxes.py.pot +++ /dev/null @@ -1,8668 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-07-16 21:47+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#. e edge description -#: boxes/edges.py -msgid "Straight Edge" -msgstr "" - -#. e edge description -#: boxes/edges.py -msgid "e Straight Edge" -msgstr "" - -#. E edge description -#: boxes/edges.py -msgid "Straight Edge (outset by thickness)" -msgstr "" - -#. E edge description -#: boxes/edges.py -msgid "E Straight Edge (outset by thickness)" -msgstr "" - -#. G edge description -#: boxes/edges.py -msgid "Edge with pear shaped mounting holes" -msgstr "" - -#. G edge description -#: boxes/edges.py -msgid "G Edge with pear shaped mounting holes" -msgstr "" - -#. z edge description -#: boxes/edges.py -msgid "Edge with grooves" -msgstr "" - -#. z edge description -#: boxes/edges.py -msgid "z Edge with grooves" -msgstr "" - -#. Z edge description -#: boxes/edges.py -msgid "Edge with grooves (opposing side)" -msgstr "" - -#. Z edge description -#: boxes/edges.py -msgid "Z Edge with grooves (opposing side)" -msgstr "" - -#. g edge description -#: boxes/edges.py -msgid "Corrugated edge useful as an gipping area" -msgstr "" - -#. g edge description -#: boxes/edges.py -msgid "g Corrugated edge useful as an gipping area" -msgstr "" - -#. f edge description -#: boxes/edges.py -msgid "Finger Joint" -msgstr "" - -#. f edge description -#: boxes/edges.py -msgid "f Finger Joint" -msgstr "" - -#. F edge description -#: boxes/edges.py -msgid "Finger Joint (opposing side)" -msgstr "" - -#. F edge description -#: boxes/edges.py -msgid "F Finger Joint (opposing side)" -msgstr "" - -#. h edge description -#: boxes/edges.py -msgid "Edge (parallel Finger Joint Holes)" -msgstr "" - -#. h edge description -#: boxes/edges.py -msgid "h Edge (parallel Finger Joint Holes)" -msgstr "" - -#. | edge description -#: boxes/edges.py -msgid "Edge (orthogonal Finger Joint Holes)" -msgstr "" - -#. | edge description -#: boxes/edges.py -msgid "| Edge (orthogonal Finger Joint Holes)" -msgstr "" - -#. s edge description -#: boxes/edges.py -msgid "Stackable (bottom, finger joint holes)" -msgstr "" - -#. s edge description -#: boxes/edges.py -msgid "s Stackable (bottom, finger joint holes)" -msgstr "" - -#. S edge description -#: boxes/edges.py -msgid "Stackable (top)" -msgstr "" - -#. S edge description -#: boxes/edges.py -msgid "S Stackable (top)" -msgstr "" - -#. š edge description -#: boxes/edges.py -msgid "Stackable feet (bottom)" -msgstr "" - -#. š edge description -#: boxes/edges.py -msgid "š Stackable feet (bottom)" -msgstr "" - -#. Š edge description -#: boxes/edges.py -msgid "Stackable edge with finger holes (top)" -msgstr "" - -#. Š edge description -#: boxes/edges.py -msgid "Š Stackable edge with finger holes (top)" -msgstr "" - -#. i edge description -#: boxes/edges.py -msgid "Straight edge with hinge eye" -msgstr "" - -#. i edge description -#: boxes/edges.py -msgid "i Straight edge with hinge eye" -msgstr "" - -#. I edge description -#: boxes/edges.py -msgid "Edge with hinge pin" -msgstr "" - -#. I edge description -#: boxes/edges.py -msgid "I Edge with hinge pin" -msgstr "" - -#. o edge description -#: boxes/edges.py -msgid "Edge with chest hinge" -msgstr "" - -#. o edge description -#: boxes/edges.py -msgid "o Edge with chest hinge" -msgstr "" - -#. p edge description -#: boxes/edges.py -msgid "p Edge with chest hinge" -msgstr "" - -#. q edge description -#: boxes/edges.py -msgid "Edge with pins for an chest hinge" -msgstr "" - -#. q edge description -#: boxes/edges.py -msgid "q Edge with pins for an chest hinge" -msgstr "" - -#. Q edge description -#: boxes/edges.py -msgid "Edge opposing a chest hinge" -msgstr "" - -#. Q edge description -#: boxes/edges.py -msgid "Q Edge opposing a chest hinge" -msgstr "" - -#. u edge description -#: boxes/edges.py -msgid "Edge with cabinet hinges" -msgstr "" - -#. u edge description -#: boxes/edges.py -msgid "u Edge with cabinet hinges" -msgstr "" - -#. l edge description -#: boxes/edges.py -msgid "Edge for slide on lid (back)" -msgstr "" - -#. l edge description -#: boxes/edges.py -msgid "l Edge for slide on lid (back)" -msgstr "" - -#. L edge description -#: boxes/edges.py -msgid "Edge for slide on lid (box back)" -msgstr "" - -#. L edge description -#: boxes/edges.py -msgid "L Edge for slide on lid (box back)" -msgstr "" - -#. n edge description -#: boxes/edges.py -msgid "Edge for slide on lid (right)" -msgstr "" - -#. n edge description -#: boxes/edges.py -msgid "n Edge for slide on lid (right)" -msgstr "" - -#. m edge description -#: boxes/edges.py -msgid "Edge for slide on lid (left)" -msgstr "" - -#. m edge description -#: boxes/edges.py -msgid "m Edge for slide on lid (left)" -msgstr "" - -#. N edge description -#: boxes/edges.py -msgid "Edge for slide on lid (box right)" -msgstr "" - -#. N edge description -#: boxes/edges.py -msgid "N Edge for slide on lid (box right)" -msgstr "" - -#. M edge description -#: boxes/edges.py -msgid "Edge for slide on lid (box left)" -msgstr "" - -#. M edge description -#: boxes/edges.py -msgid "M Edge for slide on lid (box left)" -msgstr "" - -#. c edge description -#: boxes/edges.py -msgid "Click on (bottom side)" -msgstr "" - -#. c edge description -#: boxes/edges.py -msgid "c Click on (bottom side)" -msgstr "" - -#. C edge description -#: boxes/edges.py -msgid "Click on (top)" -msgstr "" - -#. C edge description -#: boxes/edges.py -msgid "C Click on (top)" -msgstr "" - -#. d edge description -#: boxes/edges.py -msgid "Dove Tail Joint" -msgstr "" - -#. d edge description -#: boxes/edges.py -msgid "d Dove Tail Joint" -msgstr "" - -#. D edge description -#: boxes/edges.py -msgid "Dove Tail Joint (opposing side)" -msgstr "" - -#. D edge description -#: boxes/edges.py -msgid "D Dove Tail Joint (opposing side)" -msgstr "" - -#. X edge description -#: boxes/edges.py -msgid "Flex cut" -msgstr "" - -#. X edge description -#: boxes/edges.py -msgid "X Flex cut" -msgstr "" - -#. R edge description -#: boxes/edges.py -msgid "Rack (and pinion) Edge" -msgstr "" - -#. R edge description -#: boxes/edges.py -msgid "R Rack (and pinion) Edge" -msgstr "" - -#. t edge description -#: boxes/edges.py -msgid "Triangle for handle" -msgstr "" - -#. t edge description -#: boxes/edges.py -msgid "t Triangle for handle" -msgstr "" - -#. T edge description -#: boxes/edges.py -msgid "T Triangle for handle" -msgstr "" - -#. y edge description -#: boxes/edges.py -msgid "Handle for e.g. a drawer" -msgstr "" - -#. y edge description -#: boxes/edges.py -msgid "y Handle for e.g. a drawer" -msgstr "" - -#. Y edge description -#: boxes/edges.py -msgid "Handle with holes for parallel finger joint" -msgstr "" - -#. Y edge description -#: boxes/edges.py -msgid "Y Handle with holes for parallel finger joint" -msgstr "" - -#. j edge description -#: boxes/edges.py -msgid "Straight edge with hinge eye (other end)" -msgstr "" - -#. j edge description -#: boxes/edges.py -msgid "j Straight edge with hinge eye (other end)" -msgstr "" - -#. J edge description -#: boxes/edges.py -msgid "Edge with hinge pin (other end)" -msgstr "" - -#. J edge description -#: boxes/edges.py -msgid "J Edge with hinge pin (other end)" -msgstr "" - -#. k edge description -#: boxes/edges.py -msgid "Straight edge with hinge eye (both ends)" -msgstr "" - -#. k edge description -#: boxes/edges.py -msgid "k Straight edge with hinge eye (both ends)" -msgstr "" - -#. K edge description -#: boxes/edges.py -msgid "Edge with hinge pin (both ends)" -msgstr "" - -#. K edge description -#: boxes/edges.py -msgid "K Edge with hinge pin (both ends)" -msgstr "" - -#. O edge description -#: boxes/edges.py -msgid "Edge with chest hinge (other end)" -msgstr "" - -#. O edge description -#: boxes/edges.py -msgid "O Edge with chest hinge (other end)" -msgstr "" - -#. P edge description -#: boxes/edges.py -msgid "P Edge with chest hinge (other end)" -msgstr "" - -#. U edge description -#: boxes/edges.py -msgid "Edge with cabinet hinges top side" -msgstr "" - -#. U edge description -#: boxes/edges.py -msgid "U Edge with cabinet hinges top side" -msgstr "" - -#. v edge description -#: boxes/edges.py -msgid "Edge with cabinet hinges for 90° lid" -msgstr "" - -#. v edge description -#: boxes/edges.py -msgid "v Edge with cabinet hinges for 90° lid" -msgstr "" - -#. V edge description -#: boxes/edges.py -msgid "Edge with cabinet hinges 90° lid" -msgstr "" - -#. V edge description -#: boxes/edges.py -msgid "V Edge with cabinet hinges 90° lid" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Box" -msgstr "" - -#. title of group Box -#: boxes/generators/__init__.py -msgid "Boxes" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "FlexBox" -msgstr "" - -#. title of group FlexBox -#: boxes/generators/__init__.py -msgid "Boxes with flex" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Tray" -msgstr "" - -#. title of group Tray -#: boxes/generators/__init__.py -msgid "Trays and Drawer Inserts" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Shelf" -msgstr "" - -#. title of group Shelf -#: boxes/generators/__init__.py -msgid "Shelves" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "WallMounted" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Holes" -msgstr "" - -#. title of group Holes -#: boxes/generators/__init__.py -msgid "Hole patterns" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Part" -msgstr "" - -#. title of group Part -#: boxes/generators/__init__.py -msgid "Parts and Samples" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Misc" -msgstr "" - -#. name of generator group -#: boxes/generators/__init__.py -msgid "Unstable" -msgstr "" - -#. description of group Unstable -#: boxes/generators/__init__.py -msgid "Generators are still untested or need manual adjustment to be useful." -msgstr "" - -msgid "DefaultParams Settings" -msgstr "" - -#. parameter name -msgid "x" -msgstr "" - -#. help for parameter x -msgid "inner width in mm (unless outside selected)" -msgstr "" - -#. parameter name -msgid "y" -msgstr "" - -#. help for parameter y -msgid "inner depth in mm (unless outside selected)" -msgstr "" - -#. parameter name -msgid "h" -msgstr "" - -#. help for parameter h -msgid "inner height in mm (unless outside selected)" -msgstr "" - -#. parameter name -msgid "hi" -msgstr "" - -#. help for parameter hi -msgid "" -"inner height of inner walls in mm (unless outside selected)(leave to zero " -"for same as outer walls)" -msgstr "" - -#. parameter name -msgid "sx" -msgstr "" - -#. help for parameter sx -msgid "" -"sections left to right in mm [🛈](https://florianfesti.github.io/boxes/html/" -"usermanual.html#section-parameters)" -msgstr "" - -#. parameter name -msgid "sy" -msgstr "" - -#. help for parameter sy -msgid "" -"sections back to front in mm [🛈](https://florianfesti.github.io/boxes/html/" -"usermanual.html#section-parameters)" -msgstr "" - -#. parameter name -msgid "sh" -msgstr "" - -#. help for parameter sh -msgid "" -"sections bottom to top in mm [🛈](https://florianfesti.github.io/boxes/html/" -"usermanual.html#section-parameters)" -msgstr "" - -#. parameter name -msgid "bottom_edge" -msgstr "" - -#. help for parameter bottom_edge -msgid "edge type for bottom edge" -msgstr "" - -#. possible choice for bottom_edge -msgid "F" -msgstr "" - -#. possible choice for bottom_edge -msgid "s" -msgstr "" - -#. possible choice for bottom_edge -msgid "e" -msgstr "" - -#. parameter name -msgid "top_edge" -msgstr "" - -#. help for parameter top_edge -msgid "edge type for top edge" -msgstr "" - -#. possible choice for top_edge -msgid "f" -msgstr "" - -#. possible choice for top_edge -msgid "c" -msgstr "" - -#. possible choice for top_edge -msgid "E" -msgstr "" - -#. possible choice for top_edge -msgid "S" -msgstr "" - -#. possible choice for top_edge -msgid "Š" -msgstr "" - -#. possible choice for top_edge -msgid "i" -msgstr "" - -#. possible choice for top_edge -msgid "k" -msgstr "" - -#. possible choice for top_edge -msgid "v" -msgstr "" - -#. possible choice for top_edge -msgid "L" -msgstr "" - -#. possible choice for top_edge -msgid "t" -msgstr "" - -#. possible choice for top_edge -msgid "G" -msgstr "" - -#. possible choice for top_edge -msgid "Y" -msgstr "" - -#. parameter name -msgid "outside" -msgstr "" - -#. help for parameter outside -msgid "" -"treat sizes as outside measurements [🛈](https://florianfesti.github.io/boxes/" -"html/usermanual.html#outside)" -msgstr "" - -#. parameter name -msgid "nema_mount" -msgstr "" - -#. help for parameter nema_mount -msgid "NEMA size of motor" -msgstr "" - -msgid "Default Settings" -msgstr "" - -#. parameter name -msgid "thickness" -msgstr "" - -#. help for parameter thickness -msgid "" -"thickness of the material (in mm) [🛈](https://florianfesti.github.io/boxes/" -"html/usermanual.html#thickness)" -msgstr "" - -#. parameter name -msgid "format" -msgstr "" - -#. help for parameter format -msgid "" -"format of resulting file [🛈](https://florianfesti.github.io/boxes/html/" -"usermanual.html#format)" -msgstr "" - -#. possible choice for format -msgid "dxf" -msgstr "" - -#. possible choice for format -msgid "gcode" -msgstr "" - -#. possible choice for format -msgid "lbrn2" -msgstr "" - -#. possible choice for format -msgid "pdf" -msgstr "" - -#. possible choice for format -msgid "plt" -msgstr "" - -#. possible choice for format -msgid "ps" -msgstr "" - -#. possible choice for format -msgid "svg" -msgstr "" - -#. possible choice for format -msgid "svg_Ponoko" -msgstr "" - -#. parameter name -msgid "tabs" -msgstr "" - -#. help for parameter tabs -msgid "" -"width of tabs holding the parts in place (in mm)(not supported everywhere) " -"[🛈](https://florianfesti.github.io/boxes/html/usermanual.html#tabs)" -msgstr "" - -#. parameter name -msgid "qr_code" -msgstr "" - -#. help for parameter qr_code -msgid "Add a QR Code with link or command line to the generated output" -msgstr "" - -#. parameter name -msgid "debug" -msgstr "" - -#. help for parameter debug -msgid "" -"print surrounding boxes for some structures [🛈](https://florianfesti.github." -"io/boxes/html/usermanual.html#debug)" -msgstr "" - -#. parameter name -msgid "labels" -msgstr "" - -#. help for parameter labels -msgid "label the parts (where available)" -msgstr "" - -#. parameter name -msgid "reference" -msgstr "" - -#. help for parameter reference -msgid "" -"print reference rectangle with given length (in mm)(zero to disable) [🛈]" -"(https://florianfesti.github.io/boxes/html/usermanual.html#reference)" -msgstr "" - -#. parameter name -msgid "inner_corners" -msgstr "" - -#. help for parameter inner_corners -msgid "" -"style for inner corners [🛈](https://florianfesti.github.io/boxes/html/" -"usermanual.html#inner-corners)" -msgstr "" - -#. possible choice for inner_corners -msgid "loop" -msgstr "" - -#. possible choice for inner_corners -msgid "corner" -msgstr "" - -#. possible choice for inner_corners -msgid "backarc" -msgstr "" - -#. parameter name -msgid "burn" -msgstr "" - -#. help for parameter burn -msgid "" -"burn correction (in mm)(bigger values for tighter fit) [🛈](https://" -"florianfesti.github.io/boxes/html/usermanual.html#burn)" -msgstr "" - -msgid "Settings for Finger Joints" -msgstr "" - -#. parameter name for FingerJoint -msgid "angle" -msgstr "" - -#. parameter name for FingerJoint -msgid "style" -msgstr "" - -#. help for parameter style -msgid "style of the fingers" -msgstr "" - -#. possible choice for style -msgid "rectangular" -msgstr "" - -#. possible choice for style -msgid "springs" -msgstr "" - -#. possible choice for style -msgid "barbs" -msgstr "" - -#. possible choice for style -msgid "snap" -msgstr "" - -#. parameter name for FingerJoint -msgid "surroundingspaces" -msgstr "" - -#. help for parameter surroundingspaces -msgid "space at the start and end in multiple of normal spaces" -msgstr "" - -#. parameter name for FingerJoint -msgid "bottom_lip" -msgstr "" - -#. help for parameter bottom_lip -msgid "" -"height of the bottom lips sticking out (multiples of thickness) " -"FingerHoleEdge only!" -msgstr "" - -#. parameter name for FingerJoint -msgid "edge_width" -msgstr "" - -#. help for parameter edge_width -msgid "space below holes of FingerHoleEdge (multiples of thickness)" -msgstr "" - -#. parameter name for FingerJoint -msgid "extra_length" -msgstr "" - -#. help for parameter extra_length -msgid "extra material to grind away burn marks (multiples of thickness)" -msgstr "" - -#. parameter name for FingerJoint -msgid "finger" -msgstr "" - -#. help for parameter finger -msgid "width of the fingers (multiples of thickness)" -msgstr "" - -#. parameter name for FingerJoint -msgid "play" -msgstr "" - -#. help for parameter play -msgid "extra space to allow finger move in and out (multiples of thickness)" -msgstr "" - -#. parameter name for FingerJoint -msgid "space" -msgstr "" - -#. help for parameter space -msgid "space between fingers (multiples of thickness)" -msgstr "" - -#. parameter name for FingerJoint -msgid "width" -msgstr "" - -#. help for parameter width -msgid "width of finger holes (multiples of thickness)" -msgstr "" - -msgid "Settings for Stackable Edges" -msgstr "" - -#. help for parameter angle -msgid "inside angle of the feet" -msgstr "" - -#. parameter name for Stackable -msgid "bottom_stabilizers" -msgstr "" - -#. help for parameter bottom_stabilizers -msgid "" -"height of strips to be glued to the inside of bottom edges (multiples of " -"thickness)" -msgstr "" - -#. parameter name for Stackable -msgid "height" -msgstr "" - -#. help for parameter height -msgid "height of the feet (multiples of thickness)" -msgstr "" - -#. parameter name for Stackable -msgid "holedistance" -msgstr "" - -#. help for parameter holedistance -msgid "distance from finger holes to bottom edge (multiples of thickness)" -msgstr "" - -#. help for parameter width -msgid "width of the feet (multiples of thickness)" -msgstr "" - -msgid "Settings for Hinges and HingePins" -msgstr "" - -#. parameter name for Hinge -msgid "grip_percentage" -msgstr "" - -#. parameter name for Hinge -msgid "outset" -msgstr "" - -#. help for parameter outset -msgid "have lid overlap at the sides (similar to OutSetEdge)" -msgstr "" - -#. parameter name for Hinge -msgid "pinwidth" -msgstr "" - -#. help for parameter pinwidth -msgid "set to lower value to get disks surrounding the pins" -msgstr "" - -#. help for parameter style -msgid "\"outset\" or \"flush\"" -msgstr "" - -#. possible choice for style -msgid "flush" -msgstr "" - -#. parameter name for Hinge -msgid "axle" -msgstr "" - -#. help for parameter axle -msgid "diameter of the pin hole (multiples of thickness)" -msgstr "" - -#. parameter name for Hinge -msgid "grip_length" -msgstr "" - -#. help for parameter grip_length -msgid "fixed length of the grips on he lids (multiples of thickness)" -msgstr "" - -#. parameter name for Hinge -msgid "hingestrength" -msgstr "" - -#. help for parameter hingestrength -msgid "thickness of the arc holding the pin in place (multiples of thickness)" -msgstr "" - -msgid "Settings for Slide-on Lids" -msgstr "" - -#. parameter name for SlideOnLid -msgid "hole_width" -msgstr "" - -#. help for parameter hole_width -msgid "width of the \"finger hole\" in mm" -msgstr "" - -#. parameter name for SlideOnLid -msgid "second_pin" -msgstr "" - -#. help for parameter second_pin -msgid "additional pin for better positioning" -msgstr "" - -#. parameter name for SlideOnLid -msgid "spring" -msgstr "" - -#. help for parameter spring -msgid "position(s) of the extra locking springs in the lid" -msgstr "" - -#. possible choice for spring -msgid "both" -msgstr "" - -#. possible choice for spring -msgid "none" -msgstr "" - -#. possible choice for spring -msgid "left" -msgstr "" - -#. possible choice for spring -msgid "right" -msgstr "" - -msgid "Settings for Click-on Lids" -msgstr "" - -#. help for parameter angle -msgid "angle of the hooks bending outward" -msgstr "" - -#. parameter name for Click -msgid "bottom_radius" -msgstr "" - -#. help for parameter bottom_radius -msgid "radius at the bottom (multiples of thickness)" -msgstr "" - -#. parameter name for Click -msgid "depth" -msgstr "" - -#. help for parameter depth -msgid "length of the hooks (multiples of thickness)" -msgstr "" - -msgid "Settings for Flex" -msgstr "" - -#. parameter name for Flex -msgid "stretch" -msgstr "" - -#. help for parameter stretch -msgid "Hint of how much the flex part should be shortened" -msgstr "" - -#. parameter name for Flex -msgid "connection" -msgstr "" - -#. help for parameter connection -msgid "width of the gaps in the cuts (multiples of thickness)" -msgstr "" - -#. parameter name for Flex -msgid "distance" -msgstr "" - -#. help for parameter distance -msgid "width of the pattern perpendicular to the cuts (multiples of thickness)" -msgstr "" - -#. help for parameter width -msgid "width of the pattern in direction of the cuts (multiples of thickness)" -msgstr "" - -msgid "Settings for the Lid" -msgstr "" - -#. parameter name for Lid -msgid "handle" -msgstr "" - -#. help for parameter handle -msgid "type of handle" -msgstr "" - -#. possible choice for handle -msgid "long_rounded" -msgstr "" - -#. possible choice for handle -msgid "long_trapezoid" -msgstr "" - -#. possible choice for handle -msgid "long_doublerounded" -msgstr "" - -#. possible choice for handle -msgid "knob" -msgstr "" - -#. help for parameter style -msgid "type of lid to create" -msgstr "" - -#. possible choice for style -msgid "flat" -msgstr "" - -#. possible choice for style -msgid "chest" -msgstr "" - -#. possible choice for style -msgid "overthetop" -msgstr "" - -#. possible choice for style -msgid "ontop" -msgstr "" - -#. parameter name for Lid -msgid "handle_height" -msgstr "" - -#. help for parameter handle_height -msgid "height of the handle (if applicable)" -msgstr "" - -#. help for parameter height -msgid "height of the brim (if any)" -msgstr "" - -#. help for parameter play -msgid "play when sliding the lid on (if applicable)" -msgstr "" - -#. name of box generator -#: boxes/generators/abox.py -msgid "ABox" -msgstr "" - -#. description of ABox -#: boxes/generators/abox.py -msgid "A simple Box" -msgstr "" - -#. long description of ABox in markdown -#: boxes/generators/abox.py -msgid "" -"This box is kept simple on purpose. If you need more features have a look at " -"the UniversalBox." -msgstr "" - -msgid "ABox Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/agricolainsert.py -msgid "AgricolaInsert" -msgstr "" - -#. description of AgricolaInsert -#: boxes/generators/agricolainsert.py -msgid "" -"\n" -" Agricola Revised Edition game box insert, including some expansions.\n" -" " -msgstr "" - -#. long description of AgricolaInsert in markdown -#: boxes/generators/agricolainsert.py -msgid "" -"\n" -"This insert was designed with 3 mm plywood in mind, and should work fine " -"with\n" -"materials around this thickness.\n" -"\n" -"This is an insert for the [Agricola Revised Edition](https://boardgamegeek." -"com/boardgame/200680/agricola-revised-edition)\n" -"board game. It is specifically designed around the [Farmers Of The Moor " -"expansion](https://boardgamegeek.com/boardgameexpansion/257344/agricola-" -"farmers-moor),\n" -"and should also store the [5-6 players expansion](https://boardgamegeek.com/" -"boardgameexpansion/210625/agricola-expansion-5-and-6-players)\n" -"(not tested, but I tried to take everything into account for it, please " -"inform\n" -"us if you tested it).\n" -"\n" -"It can be stored inside the original game box, including the 2 expansions,\n" -"with the lid slightly raised.\n" -"\n" -"The parts of a given element are mostly generated next to each other " -"vertically.\n" -"It should be straightforward to match them.\n" -"\n" -"Here are the different elements, from left to right in the generated file.\n" -"\n" -"#### Card tray\n" -"\n" -"The cards are all kept in a tray, with paper dividers to sort them easily. " -"When\n" -"the tray is not full of cards, wood dividers slides in slots in order to " -"keep\n" -"the cards from falling into the empty space.\n" -"\n" -"There should be enough space for the main game, Farmers Of The Moor, and the " -"5-6\n" -"player expansion, but not much more than that.\n" -"\n" -"To keep a lower profile, the cards are at a slight angle, and the paper " -"dividers\n" -"tabs are horizontal instead of vertical.\n" -"A small wall keeps the card against one side while the tabs protrude on the\n" -"other side, above the small wall.\n" -"\n" -"The wall with the big hole is the sloped one. It goes between the two\n" -"\"comb-like\" walls first, with its two small holes at the bottom. Then " -"there is a\n" -"low-height long wall with a sloped edge which should go from the sloped wall " -"to\n" -"the other side. You can finish the tray with the last wall at the end.\n" -"\n" -"#### Upper level trays\n" -"\n" -"4 trays with movable walls are used to store resources. They were designed " -"to\n" -"store them in this order:\n" -"\n" -"* Stone / Vegetable / Pig / Cow\n" -"* Reed / Grain / Sheep\n" -"* Wood / Clay\n" -"* Food / Fire\n" -"\n" -"The wall would probably be better if fixed instead of movable, but I would " -"like\n" -"to test with the 5-6 player expansion to be sure their positions are " -"correct\n" -"with it too.\n" -"\n" -"The little feet of the movable wall should be glued. The triangles are put\n" -"horizontally, with their bases towards the sides.\n" -"\n" -"#### Lower level tray\n" -"\n" -"The lower level tray is used to store the horses.\n" -"\n" -"#### Room/Field tiles\n" -"\n" -"Two boxes are generated to store the room/field tiles. One for the wood/" -"field,\n" -"the other for the clay/stone. They are stored with the main opening upside, " -"but\n" -"I prefer to use them during play with this face on the side.\n" -"\n" -"#### Moor/Forest and miscellaneous tiles\n" -"\n" -"A box is generated to store the Moor/Forest tiles, and some other tiles such " -"as\n" -"the \"multiple resources\" cardboard tokens.\n" -"\n" -"The Moor/Forest tiles are at the same height as the Room/Field, and the " -"upper\n" -"level trays are directly on them. The horse box and player box are slightly\n" -"lower. This Moor/Forest box have a lowered corner (the one for the " -"miscellaneous\n" -"tiles). Two cardboard pieces can be stored between the smaller boxes and " -"the\n" -"upper level trays (as seen on the picture).\n" -"\n" -"Be sure to match the pieces so that the walls with smaller heights are next " -"to\n" -"each other.\n" -"\n" -"#### Players bit boxes\n" -"\n" -"Each player has its own box where the bits of his color are stored.\n" -"The cardboard bed from Farmers Of The Moor is central to this box.\n" -"\n" -"* The fences are stored inside the bed\n" -"* The bed is placed in the box, with holes to keep it there (and to take " -"less\n" -" height)\n" -"* The stables are stored in the two corners\n" -"* The five farmers are stored between the bed and the three walls, " -"alternatively\n" -" head up and head down.\n" -"\n" -"During assembly, the small bars are put in the middle holes. The two bigger\n" -"holes at the ends are used for the bed feet. The bar keeps the bed from\n" -"protruding underneath.\n" -"\n" -msgstr "" - -msgid "AgricolaInsert Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/alledges.py -msgid "AllEdges" -msgstr "" - -#. description of AllEdges -#: boxes/generators/alledges.py -msgid "Showing all edge types" -msgstr "" - -msgid "AllEdges Settings" -msgstr "" - -#. help for parameter x -#: boxes/generators/alledges.py -msgid "inner width in mm" -msgstr "" - -msgid "Settings for HandleEdge" -msgstr "" - -#. help for parameter height -#: boxes/generators/alledges.py -msgid "height above the wall in mm" -msgstr "" - -#. parameter name for HandleEdge -#: boxes/generators/alledges.py -msgid "hole_height" -msgstr "" - -#. help for parameter hole_height -#: boxes/generators/alledges.py -msgid "" -"height of hole(s) in percentage of maximum hole height (handle height - 2 * " -"material thickness)" -msgstr "" - -#. help for parameter hole_width -#: boxes/generators/alledges.py -msgid "" -"width of hole(s) in percentage of maximum hole width (width of edge - (n+1) " -"* material thickness)" -msgstr "" - -#. parameter name for HandleEdge -#: boxes/generators/alledges.py -msgid "on_sides" -msgstr "" - -#. help for parameter on_sides -#: boxes/generators/alledges.py -msgid "" -"added to side panels if checked, to front and back otherwise (only used with " -"top_edge parameter)" -msgstr "" - -#. parameter name for HandleEdge -#: boxes/generators/alledges.py -msgid "radius" -msgstr "" - -#. help for parameter radius -#: boxes/generators/alledges.py -msgid "radius of corners in mm" -msgstr "" - -#. help for parameter outset -#: boxes/generators/alledges.py -msgid "extend the handle along the length of the edge (multiples of thickness)" -msgstr "" - -#. name of box generator -#: boxes/generators/angledbox.py -msgid "AngledBox" -msgstr "" - -#. description of AngledBox -#: boxes/generators/angledbox.py -msgid "Box with both ends cornered" -msgstr "" - -msgid "AngledBox Settings" -msgstr "" - -#. parameter name -#: boxes/generators/angledbox.py -msgid "n" -msgstr "" - -#. help for parameter n -#: boxes/generators/angledbox.py -msgid "number of walls at one side (1+)" -msgstr "" - -#. parameter name -#: boxes/generators/angledbox.py -msgid "top" -msgstr "" - -#. help for parameter top -#: boxes/generators/angledbox.py -msgid "style of the top and lid" -msgstr "" - -#. possible choice for top -#: boxes/generators/angledbox.py -msgid "angled hole" -msgstr "" - -#. possible choice for top -#: boxes/generators/angledbox.py -msgid "angled lid" -msgstr "" - -#. possible choice for top -#: boxes/generators/angledbox.py -msgid "angled lid2" -msgstr "" - -#. name of box generator -#: boxes/generators/angledcutjig.py -msgid "AngledCutJig" -msgstr "" - -#. description of AngledCutJig -#: boxes/generators/angledcutjig.py -msgid "Jig for making angled cuts in a laser cutter" -msgstr "" - -msgid "AngledCutJig Settings" -msgstr "" - -#. help for parameter y -#: boxes/generators/angledcutjig.py -msgid "inner depth in mm" -msgstr "" - -#. help for parameter angle -#: boxes/generators/angledcutjig.py -msgid "Angle of the cut" -msgstr "" - -#. name of box generator -#: boxes/generators/arcade.py -msgid "Arcade" -msgstr "" - -#. description of Arcade -#: boxes/generators/arcade.py -msgid "Desktop Arcade Machine" -msgstr "" - -msgid "Arcade Settings" -msgstr "" - -#. help for parameter width -#: boxes/generators/arcade.py -msgid "inner width of the console" -msgstr "" - -#. parameter name -#: boxes/generators/arcade.py -msgid "monitor_height" -msgstr "" - -#. parameter name -#: boxes/generators/arcade.py -msgid "keyboard_depth" -msgstr "" - -#. name of box generator -#: boxes/generators/atreus21.py -msgid "Atreus21" -msgstr "" - -#. description of Atreus21 -#: boxes/generators/atreus21.py -msgid "Generator for a split atreus keyboard." -msgstr "" - -msgid "Atreus21 Settings" -msgstr "" - -#. parameter name -#: boxes/generators/atreus21.py -msgid "hotswap_enable" -msgstr "" - -#. help for parameter hotswap_enable -#: boxes/generators/atreus21.py -msgid "enlarge switches holes for hotswap pcb sockets" -msgstr "" - -#. parameter name -#: boxes/generators/atreus21.py -msgid "pcb_mount_enable" -msgstr "" - -#. help for parameter pcb_mount_enable -#: boxes/generators/atreus21.py -msgid "adds holes for pcb mount switches" -msgstr "" - -#. parameter name -#: boxes/generators/atreus21.py -msgid "led_enable" -msgstr "" - -#. help for parameter led_enable -#: boxes/generators/atreus21.py -msgid "adds pin holes under switches for leds" -msgstr "" - -#. parameter name -#: boxes/generators/atreus21.py -msgid "diode_enable" -msgstr "" - -#. help for parameter diode_enable -#: boxes/generators/atreus21.py -msgid "adds pin holes under switches for diodes" -msgstr "" - -#. parameter name -#: boxes/generators/atreus21.py -msgid "cutout_type" -msgstr "" - -#. help for parameter cutout_type -#: boxes/generators/atreus21.py -msgid "" -"Shape of the plate cutout: 'castle' allows for modding, and 'simple' is a " -"tighter and simpler square" -msgstr "" - -#. parameter name -#: boxes/generators/atreus21.py -msgid "columns_definition" -msgstr "" - -#. help for parameter columns_definition -#: boxes/generators/atreus21.py -msgid "" -"Each column is separated by '/', and is in the form 'nb_rows @ offset x " -"repeat_count'. Nb_rows is the number of rows for this column. The offset is " -"in mm and optional. Repeat_count is optional and repeats this column " -"multiple times. Spaces are not important.For example '3x2 / 4@11' means we " -"want 3 columns, the two first with 3 rows without offset, and the last with " -"4 rows starting at 11mm high." -msgstr "" - -#. name of box generator -#: boxes/generators/basedbox.py -msgid "BasedBox" -msgstr "" - -#. description of BasedBox -#: boxes/generators/basedbox.py -msgid "Fully closed box on a base" -msgstr "" - -#. long description of BasedBox in markdown -#: boxes/generators/basedbox.py -msgid "" -"This box is more of a building block than a finished item.\n" -"Use a vector graphics program (like Inkscape) to add holes or adjust the " -"base\n" -"plate. The width of the \"brim\" can also be adjusted with the " -"**edge_width**\n" -" parameter in the **Finger Joints Settings**.\n" -" \n" -"See ClosedBox for variant without a base.\n" -msgstr "" - -msgid "BasedBox Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/bayonetbox.py -msgid "BayonetBox" -msgstr "" - -#. description of BayonetBox -#: boxes/generators/bayonetbox.py -msgid "Round box made from layers with twist on top" -msgstr "" - -#. long description of BayonetBox in markdown -#: boxes/generators/bayonetbox.py -msgid "" -"Glue together - all outside rings to the bottom, all inside rings to the top." -msgstr "" - -msgid "BayonetBox Settings" -msgstr "" - -#. parameter name -#: boxes/generators/bayonetbox.py -msgid "diameter" -msgstr "" - -#. help for parameter diameter -#: boxes/generators/bayonetbox.py -msgid "Diameter of the box in mm" -msgstr "" - -#. parameter name -#: boxes/generators/bayonetbox.py -msgid "lugs" -msgstr "" - -#. help for parameter lugs -#: boxes/generators/bayonetbox.py -msgid "number of locking lugs" -msgstr "" - -#. parameter name -#: boxes/generators/bayonetbox.py -msgid "alignment_pins" -msgstr "" - -#. help for parameter alignment_pins -#: boxes/generators/bayonetbox.py -msgid "diameter of the alignment pins" -msgstr "" - -#. name of box generator -#: boxes/generators/bintray.py -msgid "BinTray" -msgstr "" - -#. description of BinTray -#: boxes/generators/bintray.py -msgid "A Type tray variant to be used up right with sloped walls in front" -msgstr "" - -msgid "BinTray Settings" -msgstr "" - -#. parameter name -#: boxes/generators/bintray.py -msgid "hole_dD" -msgstr "" - -#. help for parameter hole_dD -#: boxes/generators/bintray.py -msgid "" -"mounting hole diameter (shaft:head) in mm [🛈](https://florianfesti.github.io/" -"boxes/html/usermanual.html#mounting-holes)" -msgstr "" - -#. parameter name -#: boxes/generators/bintray.py -msgid "front" -msgstr "" - -#. help for parameter front -#: boxes/generators/bintray.py -msgid "fraction of bin height covert with slope" -msgstr "" - -#. name of box generator -#: boxes/generators/birdhouse.py -msgid "BirdHouse" -msgstr "" - -#. description of BirdHouse -#: boxes/generators/birdhouse.py -msgid "Simple Bird House" -msgstr "" - -msgid "BirdHouse Settings" -msgstr "" - -#. help for parameter h -#: boxes/generators/birdhouse.py -msgid "inner height in mm" -msgstr "" - -#. parameter name -#: boxes/generators/birdhouse.py -msgid "roof_overhang" -msgstr "" - -#. help for parameter roof_overhang -#: boxes/generators/birdhouse.py -msgid "overhang as fraction of the roof length" -msgstr "" - -#. name of box generator -#: boxes/generators/bottlestack.py -msgid "BottleStack" -msgstr "" - -#. description of BottleStack -#: boxes/generators/bottlestack.py -msgid "Stack bottles in a fridge" -msgstr "" - -#. long description of BottleStack in markdown -#: boxes/generators/bottlestack.py -msgid "" -"When rendered with the \"double\" option the parts with the double slots get " -"connected the shorter beams in the asymmetrical slots.\n" -"\n" -"Without the \"double\" option the stand is a bit more narrow.\n" -msgstr "" - -msgid "BottleStack Settings" -msgstr "" - -#. help for parameter diameter -#: boxes/generators/bottlestack.py -msgid "diameter of the bottles in mm" -msgstr "" - -#. parameter name -#: boxes/generators/bottlestack.py -msgid "number" -msgstr "" - -#. help for parameter number -#: boxes/generators/bottlestack.py -msgid "number of bottles to hold in the bottom row" -msgstr "" - -#. help for parameter depth -#: boxes/generators/bottlestack.py -msgid "depth of the stand along the base of the bottles" -msgstr "" - -#. parameter name -#: boxes/generators/bottlestack.py -msgid "double" -msgstr "" - -#. help for parameter double -#: boxes/generators/bottlestack.py -msgid "two pieces that can be combined to up to double the width" -msgstr "" - -#. name of box generator -#: boxes/generators/bottletag.py -msgid "BottleTag" -msgstr "" - -#. description of BottleTag -#: boxes/generators/bottletag.py -msgid "Paper slip over bottle tag" -msgstr "" - -msgid "BottleTag Settings" -msgstr "" - -#. help for parameter width -#: boxes/generators/bottletag.py -msgid "width of neck tag" -msgstr "" - -#. help for parameter height -#: boxes/generators/bottletag.py -msgid "height of neck tag" -msgstr "" - -#. parameter name -#: boxes/generators/bottletag.py -msgid "min_diameter" -msgstr "" - -#. help for parameter min_diameter -#: boxes/generators/bottletag.py -msgid "inner diameter of bottle neck hole" -msgstr "" - -#. parameter name -#: boxes/generators/bottletag.py -msgid "max_diameter" -msgstr "" - -#. help for parameter max_diameter -#: boxes/generators/bottletag.py -msgid "outer diameter of bottle neck hole" -msgstr "" - -#. help for parameter radius -#: boxes/generators/bottletag.py -msgid "corner radius of bottom tag" -msgstr "" - -#. parameter name -#: boxes/generators/bottletag.py -msgid "segment_width" -msgstr "" - -#. help for parameter segment_width -#: boxes/generators/bottletag.py -msgid "inner segment width" -msgstr "" - -#. name of box generator -#: boxes/generators/breadbox.py -msgid "BreadBox" -msgstr "" - -#. description of BreadBox -#: boxes/generators/breadbox.py -msgid "A BreadBox with a gliding door" -msgstr "" - -#. long description of BreadBox in markdown -#: boxes/generators/breadbox.py -msgid "Beware of the rolling shutter effect! Use wax on sliding surfaces.\n" -msgstr "" - -msgid "BreadBox Settings" -msgstr "" - -#. help for parameter radius -#: boxes/generators/breadbox.py -msgid "radius of the corners" -msgstr "" - -#. name of box generator -#: boxes/generators/burntest.py -msgid "BurnTest" -msgstr "" - -#. description of BurnTest -#: boxes/generators/burntest.py -msgid "Test different burn values" -msgstr "" - -#. long description of BurnTest in markdown -#: boxes/generators/burntest.py -msgid "" -"This generator will make shapes that you can use to select\n" -"optimal value for burn parameter for other generators. After burning try to\n" -"attach sides with the same value and use best fitting one on real projects.\n" -"In this generator set burn in the Default Settings to the lowest value\n" -"to be tested. To get an idea cut a rectangle with known nominal size and\n" -"measure the shrinkage due to the width of the laser cut. Now you can\n" -"measure the burn value that you should use in other generators. It is half\n" -"the difference of the overall size as shrinkage is occurring on both\n" -"sides. You can use the reference rectangle as it is rendered without burn\n" -"correction.\n" -"\n" -"See also LBeam that can serve as compact BurnTest and FlexTest for testing " -"flex settings.\n" -msgstr "" - -msgid "BurnTest Settings" -msgstr "" - -#. parameter name -#: boxes/generators/burntest.py -msgid "step" -msgstr "" - -#. help for parameter step -#: boxes/generators/burntest.py -msgid "increases in burn value between the sides" -msgstr "" - -#. parameter name -#: boxes/generators/burntest.py -msgid "pairs" -msgstr "" - -#. help for parameter pairs -#: boxes/generators/burntest.py -msgid "number of pairs (each testing four burn values)" -msgstr "" - -#. name of box generator -#: boxes/generators/can_storage.py -msgid "CanStorage" -msgstr "" - -#. description of CanStorage -#: boxes/generators/can_storage.py -msgid "Storage box for round containers" -msgstr "" - -#. long description of CanStorage in markdown -#: boxes/generators/can_storage.py -msgid "" -"\n" -"for AA batteries:\n" -"\n" -"![CanStorage for AA batteries](static/samples/CanStorageAA.jpg)\n" -"\n" -"for canned tomatoes:\n" -msgstr "" - -msgid "CanStorage Settings" -msgstr "" - -#. possible choice for bottom_edge -#: boxes/generators/can_storage.py -msgid "š" -msgstr "" - -#. parameter name -#: boxes/generators/can_storage.py -msgid "canDiameter" -msgstr "" - -#. help for parameter canDiameter -#: boxes/generators/can_storage.py -msgid "outer diameter of the cans to be stored (in mm)" -msgstr "" - -#. parameter name -#: boxes/generators/can_storage.py -msgid "canHeight" -msgstr "" - -#. help for parameter canHeight -#: boxes/generators/can_storage.py -msgid "height of the cans to be stored (in mm)" -msgstr "" - -#. parameter name -#: boxes/generators/can_storage.py -msgid "canNum" -msgstr "" - -#. help for parameter canNum -#: boxes/generators/can_storage.py -msgid "number of cans to be stored" -msgstr "" - -#. parameter name -#: boxes/generators/can_storage.py -msgid "chuteAngle" -msgstr "" - -#. help for parameter chuteAngle -#: boxes/generators/can_storage.py -msgid "slope angle of the chutes" -msgstr "" - -msgid "Settings for Hole filling" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "bar_length" -msgstr "" - -#. help for parameter bar_length -#: boxes/generators/can_storage.py -msgid "maximum length of bars" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "fill_pattern" -msgstr "" - -#. help for parameter fill_pattern -#: boxes/generators/can_storage.py -msgid "style of hole pattern" -msgstr "" - -#. possible choice for fill_pattern -#: boxes/generators/can_storage.py -msgid "no fill" -msgstr "" - -#. possible choice for fill_pattern -#: boxes/generators/can_storage.py -msgid "hex" -msgstr "" - -#. possible choice for fill_pattern -#: boxes/generators/can_storage.py -msgid "square" -msgstr "" - -#. possible choice for fill_pattern -#: boxes/generators/can_storage.py -msgid "random" -msgstr "" - -#. possible choice for fill_pattern -#: boxes/generators/can_storage.py -msgid "hbar" -msgstr "" - -#. possible choice for fill_pattern -#: boxes/generators/can_storage.py -msgid "vbar" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "hole_max_radius" -msgstr "" - -#. help for parameter hole_max_radius -#: boxes/generators/can_storage.py -msgid "maximum radius of generated holes (in mm)" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "hole_min_radius" -msgstr "" - -#. help for parameter hole_min_radius -#: boxes/generators/can_storage.py -msgid "minimum radius of generated holes (in mm)" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "hole_style" -msgstr "" - -#. help for parameter hole_style -#: boxes/generators/can_storage.py -msgid "style of holes (does not apply to fill patterns 'vbar' and 'hbar')" -msgstr "" - -#. possible choice for hole_style -#: boxes/generators/can_storage.py -msgid "round" -msgstr "" - -#. possible choice for hole_style -#: boxes/generators/can_storage.py -msgid "triangle" -msgstr "" - -#. possible choice for hole_style -#: boxes/generators/can_storage.py -msgid "hexagon" -msgstr "" - -#. possible choice for hole_style -#: boxes/generators/can_storage.py -msgid "octagon" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "max_random" -msgstr "" - -#. help for parameter max_random -#: boxes/generators/can_storage.py -msgid "maximum number of random holes" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "space_between_holes" -msgstr "" - -#. help for parameter space_between_holes -#: boxes/generators/can_storage.py -msgid "hole to hole spacing (in mm)" -msgstr "" - -#. parameter name for fillHoles -#: boxes/generators/can_storage.py -msgid "space_to_border" -msgstr "" - -#. help for parameter space_to_border -#: boxes/generators/can_storage.py -msgid "hole to border spacing (in mm)" -msgstr "" - -#. name of box generator -#: boxes/generators/cardbox.py -msgid "CardBox" -msgstr "" - -#. description of CardBox -#: boxes/generators/cardbox.py -msgid "Box for storage of playing cards, with versatile options" -msgstr "" - -#. long description of CardBox in markdown -#: boxes/generators/cardbox.py -msgid "" -"\n" -"### Description\n" -"Versatile Box for Storage of playing cards. Multiple different styles of " -"storage are supportet, e.g. a flat storage or a trading card deck box style " -"storage. See images for ideas.\n" -"\n" -"#### Building instructions\n" -"Place inner walls on floor first (if any). Then add the outer walls. Glue " -"the two walls without finger joins to the inside of the side walls. Make " -"sure there is no squeeze out on top, as this is going to form the rail for " -"the lid.\n" -"\n" -"Add the top of the rails to the sides (front open) or to the back and front " -"(right side open) and the grip rail to the lid.\n" -"Details of the lid and rails\n" -"![Details](static/samples/CardBox-detail.jpg)\n" -"Whole box (early version still missing grip rail on the lid):\n" -msgstr "" - -msgid "CardBox Settings" -msgstr "" - -#. parameter name -#: boxes/generators/cardbox.py -msgid "openingdirection" -msgstr "" - -#. help for parameter openingdirection -#: boxes/generators/cardbox.py -msgid "" -"Direction in which the lid slides open. Lid length > Lid width recommended." -msgstr "" - -#. parameter name -#: boxes/generators/cardbox.py -msgid "fingerhole" -msgstr "" - -#. help for parameter fingerhole -#: boxes/generators/cardbox.py -msgid "Depth of cutout to grab the cards" -msgstr "" - -#. possible choice for fingerhole -#: boxes/generators/cardbox.py -msgid "regular" -msgstr "" - -#. possible choice for fingerhole -#: boxes/generators/cardbox.py -msgid "deep" -msgstr "" - -#. possible choice for fingerhole -#: boxes/generators/cardbox.py -msgid "custom" -msgstr "" - -#. parameter name -#: boxes/generators/cardbox.py -msgid "fingerhole_depth" -msgstr "" - -#. help for parameter fingerhole_depth -#: boxes/generators/cardbox.py -msgid "Depth of cutout if fingerhole is set to 'custom'. Disabled otherwise." -msgstr "" - -#. parameter name -#: boxes/generators/cardbox.py -msgid "add_lidtopper" -msgstr "" - -#. help for parameter add_lidtopper -#: boxes/generators/cardbox.py -msgid "Add an additional lid topper for optical reasons and customisation" -msgstr "" - -#. name of box generator -#: boxes/generators/cardholder.py -msgid "CardHolder" -msgstr "" - -#. description of CardHolder -#: boxes/generators/cardholder.py -msgid "Shelf for holding (multiple) piles of playing cards / notes" -msgstr "" - -msgid "CardHolder Settings" -msgstr "" - -#. help for parameter angle -#: boxes/generators/cardholder.py -msgid "backward angle of floor" -msgstr "" - -#. parameter name -#: boxes/generators/cardholder.py -msgid "stackable" -msgstr "" - -#. help for parameter stackable -#: boxes/generators/cardholder.py -msgid "make holders stackable" -msgstr "" - -msgid "Settings for Grooved Edge" -msgstr "" - -#. parameter name for Grooved -#: boxes/generators/cardholder.py -msgid "arc_angle" -msgstr "" - -#. help for parameter arc_angle -#: boxes/generators/cardholder.py -msgid "the angle of arc cuts" -msgstr "" - -#. parameter name for Grooved -#: boxes/generators/cardholder.py -msgid "gap" -msgstr "" - -#. help for parameter gap -#: boxes/generators/cardholder.py -msgid "the gap between grooves (fraction of the edge length)" -msgstr "" - -#. parameter name for Grooved -#: boxes/generators/cardholder.py -msgid "interleave" -msgstr "" - -#. help for parameter interleave -#: boxes/generators/cardholder.py -msgid "alternate the direction of grooves" -msgstr "" - -#. parameter name for Grooved -#: boxes/generators/cardholder.py -msgid "inverse" -msgstr "" - -#. help for parameter inverse -#: boxes/generators/cardholder.py -msgid "invert the groove directions" -msgstr "" - -#. parameter name for Grooved -#: boxes/generators/cardholder.py -msgid "margin" -msgstr "" - -#. help for parameter margin -#: boxes/generators/cardholder.py -msgid "" -"minimum space left and right without grooves (fraction of the edge length)" -msgstr "" - -#. help for parameter style -#: boxes/generators/cardholder.py -msgid "the style of grooves" -msgstr "" - -#. possible choice for style -#: boxes/generators/cardholder.py -msgid "arc" -msgstr "" - -#. possible choice for style -#: boxes/generators/cardholder.py -msgid "softarc" -msgstr "" - -#. parameter name for Grooved -#: boxes/generators/cardholder.py -msgid "tri_angle" -msgstr "" - -#. help for parameter tri_angle -#: boxes/generators/cardholder.py -msgid "the angle of triangular cuts" -msgstr "" - -#. help for parameter width -#: boxes/generators/cardholder.py -msgid "the width of each groove (fraction of the edge length)" -msgstr "" - -#. name of box generator -#: boxes/generators/castle.py -msgid "Castle" -msgstr "" - -#. description of Castle -#: boxes/generators/castle.py -msgid "Castle tower with two walls" -msgstr "" - -#. long description of Castle in markdown -#: boxes/generators/castle.py -msgid "" -"This was done as a table decoration. May be at some point in the future " -"someone will create a proper castle\n" -"with towers and gates and walls that can be attached in multiple " -"configurations." -msgstr "" - -msgid "Castle Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/closedbox.py -msgid "ClosedBox" -msgstr "" - -#. description of ClosedBox -#: boxes/generators/closedbox.py -msgid "Fully closed box" -msgstr "" - -#. long description of ClosedBox in markdown -#: boxes/generators/closedbox.py -msgid "" -"This box is more of a building block than a finished item.\n" -"Use a vector graphics program (like Inkscape) to add holes or adjust the " -"base\n" -"plate.\n" -"\n" -"See BasedBox for variant with a base." -msgstr "" - -msgid "ClosedBox Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/coffeecapsulesholder.py -msgid "CoffeeCapsuleHolder" -msgstr "" - -#. description of CoffeeCapsuleHolder -#: boxes/generators/coffeecapsulesholder.py -msgid "" -"\n" -" Coffee capsule holder\n" -" " -msgstr "" - -#. long description of CoffeeCapsuleHolder in markdown -#: boxes/generators/coffeecapsulesholder.py -msgid "" -"\n" -" You can store your coffee capsule near your espresso machine with this. " -"It works both vertically, or upside down under a shelf.\n" -msgstr "" - -msgid "CoffeeCapsuleHolder Settings" -msgstr "" - -#. parameter name -#: boxes/generators/coffeecapsulesholder.py -msgid "columns" -msgstr "" - -#. help for parameter columns -#: boxes/generators/coffeecapsulesholder.py -msgid "Number of columns of capsules." -msgstr "" - -#. parameter name -#: boxes/generators/coffeecapsulesholder.py -msgid "rows" -msgstr "" - -#. help for parameter rows -#: boxes/generators/coffeecapsulesholder.py -msgid "Number of capsules by columns." -msgstr "" - -#. parameter name -#: boxes/generators/coffeecapsulesholder.py -msgid "backplate" -msgstr "" - -#. help for parameter backplate -#: boxes/generators/coffeecapsulesholder.py -msgid "True if a backplate should be generated." -msgstr "" - -#. name of box generator -#: boxes/generators/coindisplay.py -msgid "CoinDisplay" -msgstr "" - -#. description of CoinDisplay -#: boxes/generators/coindisplay.py -msgid "A showcase for a single coin" -msgstr "" - -msgid "CoinDisplay Settings" -msgstr "" - -#. parameter name -#: boxes/generators/coindisplay.py -msgid "coin_d" -msgstr "" - -#. help for parameter coin_d -#: boxes/generators/coindisplay.py -msgid "The diameter of the coin in mm" -msgstr "" - -#. parameter name -#: boxes/generators/coindisplay.py -msgid "coin_plate" -msgstr "" - -#. help for parameter coin_plate -#: boxes/generators/coindisplay.py -msgid "The size of the coin plate" -msgstr "" - -#. parameter name -#: boxes/generators/coindisplay.py -msgid "coin_showcase_h" -msgstr "" - -#. help for parameter coin_showcase_h -#: boxes/generators/coindisplay.py -msgid "The height of the coin showcase piece" -msgstr "" - -#. help for parameter angle -#: boxes/generators/coindisplay.py -msgid "The angle that the coin will tilt as" -msgstr "" - -#. name of box generator -#: boxes/generators/concaveknob.py -msgid "ConcaveKnob" -msgstr "" - -#. description of ConcaveKnob -#: boxes/generators/concaveknob.py -msgid "Round knob serrated outside for better gripping" -msgstr "" - -msgid "ConcaveKnob Settings" -msgstr "" - -#. help for parameter diameter -#: boxes/generators/concaveknob.py -msgid "Diameter of the knob (mm)" -msgstr "" - -#. parameter name -#: boxes/generators/concaveknob.py -msgid "serrations" -msgstr "" - -#. help for parameter serrations -#: boxes/generators/concaveknob.py -msgid "Number of serrations" -msgstr "" - -#. parameter name -#: boxes/generators/concaveknob.py -msgid "rounded" -msgstr "" - -#. help for parameter rounded -#: boxes/generators/concaveknob.py -msgid "Amount of circumference used for non convex parts" -msgstr "" - -#. help for parameter angle -#: boxes/generators/concaveknob.py -msgid "Angle between convex and concave parts" -msgstr "" - -#. parameter name -#: boxes/generators/concaveknob.py -msgid "bolthole" -msgstr "" - -#. help for parameter bolthole -#: boxes/generators/concaveknob.py -msgid "Diameter of the bolt hole (mm)" -msgstr "" - -#. parameter name -#: boxes/generators/concaveknob.py -msgid "dhole" -msgstr "" - -#. help for parameter dhole -#: boxes/generators/concaveknob.py -msgid "D-Flat in fraction of the diameter" -msgstr "" - -#. parameter name -#: boxes/generators/concaveknob.py -msgid "hexhead" -msgstr "" - -#. help for parameter hexhead -#: boxes/generators/concaveknob.py -msgid "Width of the hex bolt head (mm)" -msgstr "" - -#. name of box generator -#: boxes/generators/console.py -msgid "Console" -msgstr "" - -#. description of Console -#: boxes/generators/console.py -msgid "Console with slanted panel" -msgstr "" - -#. long description of Console in markdown -#: boxes/generators/console.py -msgid "" -"\n" -"\n" -"Console Arcade Stick\n" -"\n" -"![Front](static/samples/ConsoleArcadeStickFront.jpg)\n" -"![Back](static/samples/ConsoleArcadeStickBack.jpg)\n" -"![Inside](static/samples/ConsoleArcadeStickInside.jpg)\n" -"\n" -"Keyboard enclosure:\n" -msgstr "" - -msgid "Console Settings" -msgstr "" - -#. parameter name -#: boxes/generators/console.py -msgid "front_height" -msgstr "" - -#. help for parameter front_height -#: boxes/generators/console.py -msgid "height of the front below the panel (in mm)" -msgstr "" - -#. help for parameter angle -#: boxes/generators/console.py -msgid "angle of the front panel (90°=upright)" -msgstr "" - -#. name of box generator -#: boxes/generators/console2.py -msgid "Console2" -msgstr "" - -#. description of Console2 -#: boxes/generators/console2.py -msgid "Console with slanted panel and service hatches" -msgstr "" - -#. long description of Console2 in markdown -#: boxes/generators/console2.py -msgid "" -"\n" -"This box is designed as a housing for electronic projects. It has hatches " -"that can be re-opened with simple tools. It intentionally cannot be opened " -"with bare hands - if build with thin enough material.\n" -"\n" -"#### Caution\n" -"There is a chance that the latches of the back wall or the back wall itself " -"interfere with the front panel or it's mounting frame/lips. The generator " -"does not check for this. So depending on the variant chosen you might need " -"to make the box deeper (increase y parameter) or the panel angle steeper " -"(increase angle parameter) until there is enough room.\n" -"\n" -"It's also possible that the frame of the panel interferes with the floor if " -"the hi parameter is too small.\n" -"\n" -"#### Assembly instructions\n" -"The main body is easy to assemble by starting with the floor and then adding " -"the four walls and (if present) the top piece.\n" -"\n" -"If the back wall is removable you need to add the lips and latches. The U-" -"shaped clamps holding the latches in place need to be clued in place without " -"also gluing the latches themselves. Make sure the springs on the latches " -"point inwards and the angled ends point to the side walls as shown here:\n" -"\n" -"![Back wall details](static/samples/Console2-backwall-detail.jpg)\n" -"\n" -"If the panel is removable you need to add the springs with the tabs to the " -"side lips. This photo shows the variant which has the panel glued to the " -"frame:\n" -"\n" -"![Back wall details](static/samples/Console2-panel-detail.jpg)\n" -"\n" -"If space is tight you may consider not gluing the cross pieces in place and " -"remove them after the glue-up. This may prevent the latches of the back wall " -"and the panel from interfering with each other.\n" -"\n" -"The variant using finger joints only has the two side lips without the cross " -"bars.\n" -"\n" -"#### Re-Opening\n" -"\n" -"The latches at the back wall lock in place when closed. To open them they " -"need to be pressed in and can then be moved aside.\n" -"\n" -"To remove the panel you have to press in the four tabs at the side. It is " -"easiest to push them in and then pull the panel up a little bit so the tabs " -"stay in.\n" -msgstr "" - -msgid "Console2 Settings" -msgstr "" - -#. parameter name -#: boxes/generators/console2.py -msgid "removable_backwall" -msgstr "" - -#. help for parameter removable_backwall -#: boxes/generators/console2.py -msgid "have latches at the backwall" -msgstr "" - -#. parameter name -#: boxes/generators/console2.py -msgid "removable_panel" -msgstr "" - -#. help for parameter removable_panel -#: boxes/generators/console2.py -msgid "The panel is held by tabs and can be removed" -msgstr "" - -#. parameter name -#: boxes/generators/console2.py -msgid "glued_panel" -msgstr "" - -#. help for parameter glued_panel -#: boxes/generators/console2.py -msgid "the panel is glued and not held by finger joints" -msgstr "" - -#. name of box generator -#: boxes/generators/crypticfont.py -msgid "CrypticFont" -msgstr "" - -#. description of CrypticFont -#: boxes/generators/crypticfont.py -msgid "DESCRIPTION" -msgstr "" - -msgid "CrypticFont Settings" -msgstr "" - -#. parameter name -#: boxes/generators/crypticfont.py -msgid "ctext" -msgstr "" - -#. help for parameter ctext -#: boxes/generators/crypticfont.py -msgid "text to render" -msgstr "" - -msgid "Settings for the Cryptic Font" -msgstr "" - -#. parameter name for CrypticFont -#: boxes/generators/crypticfont.py -msgid "ratio" -msgstr "" - -#. help for parameter ratio -#: boxes/generators/crypticfont.py -msgid "ratio of height to width" -msgstr "" - -#. parameter name for CrypticFont -#: boxes/generators/crypticfont.py -msgid "spacing" -msgstr "" - -#. help for parameter width -#: boxes/generators/crypticfont.py -msgid "width of the glphys in mm" -msgstr "" - -#. name of box generator -#: boxes/generators/desksign.py -msgid "Desksign" -msgstr "" - -#. description of Desksign -#: boxes/generators/desksign.py -msgid "Simple diagonal plate with stands to show name or mesage" -msgstr "" - -#. long description of Desksign in markdown -#: boxes/generators/desksign.py -msgid "" -"Text to be engraved can be genarated by inputing the label and fontsize " -"fields.\n" -" height represents the area that can be used for writing " -"text, does not match the actual\n" -" height when standing. Generated text is put in the center. " -"Currently only a single\n" -" line of text is supported." -msgstr "" - -msgid "Desksign Settings" -msgstr "" - -#. help for parameter width -#: boxes/generators/desksign.py -msgid "plate width in mm (excluding holes)" -msgstr "" - -#. help for parameter height -#: boxes/generators/desksign.py -msgid "plate height in mm" -msgstr "" - -#. help for parameter angle -#: boxes/generators/desksign.py -msgid "plate angle in degrees (90 is vertical)" -msgstr "" - -#. parameter name -#: boxes/generators/desksign.py -msgid "label" -msgstr "" - -#. help for parameter label -#: boxes/generators/desksign.py -msgid "optional text to engrave (leave blank to omit)" -msgstr "" - -#. parameter name -#: boxes/generators/desksign.py -msgid "fontsize" -msgstr "" - -#. help for parameter fontsize -#: boxes/generators/desksign.py -msgid "height of text" -msgstr "" - -#. parameter name -#: boxes/generators/desksign.py -msgid "feet" -msgstr "" - -#. help for parameter feet -#: boxes/generators/desksign.py -msgid "add raised feet" -msgstr "" - -#. parameter name -#: boxes/generators/desksign.py -msgid "mirror" -msgstr "" - -#. help for parameter mirror -#: boxes/generators/desksign.py -msgid "" -"mirrors one of the stand so the same side of the material can be placed on " -"the outside" -msgstr "" - -#. name of box generator -#: boxes/generators/dicebox.py -msgid "DiceBox" -msgstr "" - -#. description of DiceBox -#: boxes/generators/dicebox.py -msgid "Box with lid and integraded hinge for storing dice" -msgstr "" - -msgid "DiceBox Settings" -msgstr "" - -#. parameter name -#: boxes/generators/dicebox.py -msgid "lidheight" -msgstr "" - -#. help for parameter lidheight -#: boxes/generators/dicebox.py -msgid "height of lid in mm" -msgstr "" - -#. parameter name -#: boxes/generators/dicebox.py -msgid "hex_hole_corner_radius" -msgstr "" - -#. help for parameter hex_hole_corner_radius -#: boxes/generators/dicebox.py -msgid "The corner radius of the hexagonal dice holes, in mm" -msgstr "" - -#. parameter name -#: boxes/generators/dicebox.py -msgid "magnet_diameter" -msgstr "" - -#. help for parameter magnet_diameter -#: boxes/generators/dicebox.py -msgid "The diameter of magnets for holding the box closed, in mm" -msgstr "" - -msgid "Settings for Chest Hinges" -msgstr "" - -#. parameter name for ChestHinge -#: boxes/generators/dicebox.py -msgid "finger_joints_on_box" -msgstr "" - -#. help for parameter finger_joints_on_box -#: boxes/generators/dicebox.py -msgid "whether to include finger joints on the edge with the box" -msgstr "" - -#. parameter name for ChestHinge -#: boxes/generators/dicebox.py -msgid "finger_joints_on_lid" -msgstr "" - -#. help for parameter finger_joints_on_lid -#: boxes/generators/dicebox.py -msgid "whether to include finger joints on the edge with the lid" -msgstr "" - -#. parameter name for ChestHinge -#: boxes/generators/dicebox.py -msgid "hinge_strength" -msgstr "" - -#. parameter name for ChestHinge -#: boxes/generators/dicebox.py -msgid "pin_height" -msgstr "" - -#. help for parameter pin_height -#: boxes/generators/dicebox.py -msgid "radius of the disc rotating in the hinge (multiples of thickness)" -msgstr "" - -#. name of box generator -#: boxes/generators/dinrailbox.py -msgid "DinRailBox" -msgstr "" - -#. description of DinRailBox -#: boxes/generators/dinrailbox.py -msgid "Box for DIN rail used in electrical junction boxes" -msgstr "" - -msgid "DinRailBox Settings" -msgstr "" - -#. parameter name -#: boxes/generators/dinrailbox.py -msgid "rail_width" -msgstr "" - -#. help for parameter rail_width -#: boxes/generators/dinrailbox.py -msgid "width of the rail (typically 35 or 15mm)" -msgstr "" - -#. parameter name -#: boxes/generators/dinrailbox.py -msgid "rail_offset" -msgstr "" - -#. help for parameter rail_offset -#: boxes/generators/dinrailbox.py -msgid "offset of the rail from the middle of the box (in mm)" -msgstr "" - -#. name of box generator -#: boxes/generators/discrack.py -msgid "DiscRack" -msgstr "" - -#. description of DiscRack -#: boxes/generators/discrack.py -msgid "A rack for storing disk-shaped objects vertically next to each other" -msgstr "" - -msgid "DiscRack Settings" -msgstr "" - -#. parameter name -#: boxes/generators/discrack.py -msgid "disc_diameter" -msgstr "" - -#. help for parameter disc_diameter -#: boxes/generators/discrack.py -msgid "Disc diameter in mm" -msgstr "" - -#. parameter name -#: boxes/generators/discrack.py -msgid "disc_thickness" -msgstr "" - -#. help for parameter disc_thickness -#: boxes/generators/discrack.py -msgid "Thickness of the discs in mm" -msgstr "" - -#. parameter name -#: boxes/generators/discrack.py -msgid "lower_factor" -msgstr "" - -#. help for parameter lower_factor -#: boxes/generators/discrack.py -msgid "Position of the lower rack grids along the radius" -msgstr "" - -#. parameter name -#: boxes/generators/discrack.py -msgid "rear_factor" -msgstr "" - -#. help for parameter rear_factor -#: boxes/generators/discrack.py -msgid "Position of the rear rack grids along the radius" -msgstr "" - -#. parameter name -#: boxes/generators/discrack.py -msgid "disc_outset" -msgstr "" - -#. help for parameter disc_outset -#: boxes/generators/discrack.py -msgid "Additional space kept between the disks and the outbox of the rack" -msgstr "" - -#. help for parameter angle -#: boxes/generators/discrack.py -msgid "Backwards slant of the rack" -msgstr "" - -#. name of box generator -#: boxes/generators/dispenser.py -msgid "Dispenser" -msgstr "" - -#. description of Dispenser -#: boxes/generators/dispenser.py -msgid "Dispenser for stackable (flat) items of same size" -msgstr "" - -#. long description of Dispenser in markdown -#: boxes/generators/dispenser.py -msgid "" -"Set *bottomheight* to 0 for a wall mounting variant.\n" -"Please add mounting holes yourself." -msgstr "" - -msgid "Dispenser Settings" -msgstr "" - -#. parameter name -#: boxes/generators/dispenser.py -msgid "slotheight" -msgstr "" - -#. help for parameter slotheight -#: boxes/generators/dispenser.py -msgid "height of the dispenser slot / items (in mm)" -msgstr "" - -#. parameter name -#: boxes/generators/dispenser.py -msgid "bottomheight" -msgstr "" - -#. help for parameter bottomheight -#: boxes/generators/dispenser.py -msgid "height underneath the dispenser (in mm)" -msgstr "" - -#. parameter name -#: boxes/generators/dispenser.py -msgid "sideedges" -msgstr "" - -#. help for parameter sideedges -#: boxes/generators/dispenser.py -msgid "edges used for holding the front panels and back" -msgstr "" - -#. name of box generator -#: boxes/generators/display.py -msgid "Display" -msgstr "" - -#. description of Display -#: boxes/generators/display.py -msgid "Display for flyers or leaflets" -msgstr "" - -msgid "Display Settings" -msgstr "" - -#. help for parameter radius -#: boxes/generators/display.py -msgid "radius of the corners in mm" -msgstr "" - -#. help for parameter angle -#: boxes/generators/display.py -msgid "greater zero for top wider as bottom" -msgstr "" - -#. name of box generator -#: boxes/generators/displaycase.py -msgid "DisplayCase" -msgstr "" - -#. description of DisplayCase -#: boxes/generators/displaycase.py -msgid "" -"Fully closed box intended to be cut from transparent acrylics and to serve " -"as a display case." -msgstr "" - -msgid "DisplayCase Settings" -msgstr "" - -#. parameter name -#: boxes/generators/displaycase.py -msgid "overhang" -msgstr "" - -#. help for parameter overhang -#: boxes/generators/displaycase.py -msgid "overhang for joints in mm" -msgstr "" - -#. name of box generator -#: boxes/generators/displayshelf.py -msgid "DisplayShelf" -msgstr "" - -#. description of DisplayShelf -#: boxes/generators/displayshelf.py -msgid "Shelf with slanted floors" -msgstr "" - -msgid "DisplayShelf Settings" -msgstr "" - -#. parameter name -#: boxes/generators/displayshelf.py -msgid "num" -msgstr "" - -#. help for parameter num -#: boxes/generators/displayshelf.py -msgid "number of shelves" -msgstr "" - -#. parameter name -#: boxes/generators/displayshelf.py -msgid "front_wall_height" -msgstr "" - -#. help for parameter front_wall_height -#: boxes/generators/displayshelf.py -msgid "height of front walls" -msgstr "" - -#. help for parameter angle -#: boxes/generators/displayshelf.py -msgid "angle of floors (negative values for slanting backwards)" -msgstr "" - -#. parameter name -#: boxes/generators/displayshelf.py -msgid "include_back" -msgstr "" - -#. help for parameter include_back -#: boxes/generators/displayshelf.py -msgid "Include panel on the back of the shelf" -msgstr "" - -#. parameter name -#: boxes/generators/displayshelf.py -msgid "slope_top" -msgstr "" - -#. help for parameter slope_top -#: boxes/generators/displayshelf.py -msgid "Slope the sides and the top by front wall height" -msgstr "" - -#. parameter name -#: boxes/generators/displayshelf.py -msgid "divider_wall_height" -msgstr "" - -#. help for parameter divider_wall_height -#: boxes/generators/displayshelf.py -msgid "height of divider walls" -msgstr "" - -#. name of box generator -#: boxes/generators/dividertray.py -msgid "DividerTray" -msgstr "" - -#. description of DividerTray -#: boxes/generators/dividertray.py -msgid "Divider tray - rows and dividers" -msgstr "" - -#. long description of DividerTray in markdown -#: boxes/generators/dividertray.py -msgid "" -"\n" -"Adding '0:' at the start of the sy parameter adds a slot at the very back. " -"Adding ':0' at the end of sy adds a slot meeting the bottom at the very " -"front. This is especially useful if slot angle is set above zero.\n" -"\n" -"There are 4 different sets of dividers rendered:\n" -"\n" -"* With asymmetric tabs so the tabs fit on top of each other\n" -"* With tabs of half wall thickness that can go side by side\n" -"* With tabs of a full wall thickness\n" -"* One single divider spanning across all columns\n" -"\n" -"You will likely need to cut each of the dividers you want multiple times.\n" -msgstr "" - -msgid "DividerTray Settings" -msgstr "" - -#. parameter name -#: boxes/generators/dividertray.py -msgid "notches_in_wall" -msgstr "" - -#. help for parameter notches_in_wall -#: boxes/generators/dividertray.py -msgid "generate the same notches on the walls that are on the dividers" -msgstr "" - -#. parameter name -#: boxes/generators/dividertray.py -msgid "left_wall" -msgstr "" - -#. help for parameter left_wall -#: boxes/generators/dividertray.py -msgid "generate wall on the left side" -msgstr "" - -#. parameter name -#: boxes/generators/dividertray.py -msgid "right_wall" -msgstr "" - -#. help for parameter right_wall -#: boxes/generators/dividertray.py -msgid "generate wall on the right side" -msgstr "" - -#. parameter name -#: boxes/generators/dividertray.py -msgid "bottom" -msgstr "" - -#. help for parameter bottom -#: boxes/generators/dividertray.py -msgid "generate wall on the bottom" -msgstr "" - -#. help for parameter handle -#: boxes/generators/dividertray.py -msgid "add handle to the bottom" -msgstr "" - -msgid "Settings for Divider Slots" -msgstr "" - -#. help for parameter angle -#: boxes/generators/dividertray.py -msgid "angle at which slots are generated, in degrees. 0° is vertical." -msgstr "" - -#. help for parameter depth -#: boxes/generators/dividertray.py -msgid "depth of the slot in mm" -msgstr "" - -#. parameter name for Slot -#: boxes/generators/dividertray.py -msgid "extra_slack" -msgstr "" - -#. help for parameter extra_slack -#: boxes/generators/dividertray.py -msgid "" -"extra slack (in addition to thickness and kerf) to help insert dividers in mm" -msgstr "" - -#. help for parameter radius -#: boxes/generators/dividertray.py -msgid "radius of the slot entrance in mm" -msgstr "" - -msgid "Settings for Notches on the Dividers" -msgstr "" - -#. parameter name for Notch -#: boxes/generators/dividertray.py -msgid "lower_radius" -msgstr "" - -#. parameter name for Notch -#: boxes/generators/dividertray.py -msgid "upper_radius" -msgstr "" - -msgid "Settings for Dividers" -msgstr "" - -#. parameter name for Divider -#: boxes/generators/dividertray.py -msgid "bottom_margin" -msgstr "" - -#. help for parameter bottom_margin -#: boxes/generators/dividertray.py -msgid "margin between box's bottom and divider's in mm" -msgstr "" - -#. help for parameter play -#: boxes/generators/dividertray.py -msgid "play to avoid them clamping onto the walls (in multiples of thickness)" -msgstr "" - -#. name of box generator -#: boxes/generators/doubleflexdoorbox.py -msgid "DoubleFlexDoorBox" -msgstr "" - -#. description of DoubleFlexDoorBox -#: boxes/generators/doubleflexdoorbox.py -msgid "Box with two part lid with living hinges and round corners" -msgstr "" - -msgid "DoubleFlexDoorBox Settings" -msgstr "" - -#. help for parameter radius -#: boxes/generators/doubleflexdoorbox.py -msgid "Radius of the latch in mm" -msgstr "" - -#. parameter name -#: boxes/generators/doubleflexdoorbox.py -msgid "latchsize" -msgstr "" - -#. help for parameter latchsize -#: boxes/generators/doubleflexdoorbox.py -msgid "size of latch in multiples of thickness" -msgstr "" - -#. name of box generator -#: boxes/generators/drillbox.py -msgid "DrillBox" -msgstr "" - -#. description of DrillBox -#: boxes/generators/drillbox.py -msgid "A parametrized box for drills" -msgstr "" - -#. long description of DrillBox in markdown -#: boxes/generators/drillbox.py -msgid "![Multiple DrillBoxes](static/samples/DrillBoxes.jpg) " -msgstr "" - -msgid "DrillBox Settings" -msgstr "" - -#. parameter name -#: boxes/generators/drillbox.py -msgid "holes" -msgstr "" - -#. help for parameter holes -#: boxes/generators/drillbox.py -msgid "Number of holes for each size" -msgstr "" - -#. parameter name -#: boxes/generators/drillbox.py -msgid "firsthole" -msgstr "" - -#. help for parameter firsthole -#: boxes/generators/drillbox.py -msgid "Smallest hole" -msgstr "" - -#. parameter name -#: boxes/generators/drillbox.py -msgid "holeincrement" -msgstr "" - -#. help for parameter holeincrement -#: boxes/generators/drillbox.py -msgid "increment between holes" -msgstr "" - -msgid "Settings for RoundedTriangleEdge" -msgstr "" - -#. help for parameter height -#: boxes/generators/drillbox.py -msgid "height above the wall" -msgstr "" - -#. parameter name for RoundedTriangleEdge -#: boxes/generators/drillbox.py -msgid "r_hole" -msgstr "" - -#. help for parameter r_hole -#: boxes/generators/drillbox.py -msgid "radius of hole" -msgstr "" - -#. help for parameter radius -#: boxes/generators/drillbox.py -msgid "radius of top corner" -msgstr "" - -#. help for parameter outset -#: boxes/generators/drillbox.py -msgid "" -"extend the triangle along the length of the edge (multiples of thickness)" -msgstr "" - -msgid "Settings for Mounting Edge" -msgstr "" - -#. parameter name for Mounting -#: boxes/generators/drillbox.py -msgid "d_head" -msgstr "" - -#. help for parameter d_head -#: boxes/generators/drillbox.py -msgid "head diameter of mounting screw (in mm)" -msgstr "" - -#. parameter name for Mounting -#: boxes/generators/drillbox.py -msgid "d_shaft" -msgstr "" - -#. help for parameter d_shaft -#: boxes/generators/drillbox.py -msgid "shaft diameter of mounting screw (in mm)" -msgstr "" - -#. help for parameter margin -#: boxes/generators/drillbox.py -msgid "" -"minimum space left and right without holes (fraction of the edge length)" -msgstr "" - -#. help for parameter num -#: boxes/generators/drillbox.py -msgid "number of mounting holes (integer)" -msgstr "" - -#. parameter name for Mounting -#: boxes/generators/drillbox.py -msgid "side" -msgstr "" - -#. help for parameter side -#: boxes/generators/drillbox.py -msgid "side of box (not all valid configurations make sense...)" -msgstr "" - -#. possible choice for side -#: boxes/generators/drillbox.py -msgid "back" -msgstr "" - -#. help for parameter style -#: boxes/generators/drillbox.py -msgid "edge style" -msgstr "" - -#. possible choice for style -#: boxes/generators/drillbox.py -msgid "straight edge, within" -msgstr "" - -#. possible choice for style -#: boxes/generators/drillbox.py -msgid "straight edge, extended" -msgstr "" - -#. possible choice for style -#: boxes/generators/drillbox.py -msgid "mounting tab" -msgstr "" - -#. name of box generator -#: boxes/generators/drillstand.py -msgid "DrillStand" -msgstr "" - -#. description of DrillStand -#: boxes/generators/drillstand.py -msgid "Box for drills with each compartment of a different height" -msgstr "" - -#. long description of DrillStand in markdown -#: boxes/generators/drillstand.py -msgid "" -"Note: `sh` gives the hight of the rows front to back. It though should have " -"the same number of entries as `sy`. These heights are the one on the left " -"side and increase throughout the row. To have each compartment a bit higher " -"than the previous one the steps in `sh` should be a bit bigger than " -"`extra_height`.\n" -"\n" -"Assembly:\n" -"\n" -"![Parts](static/samples/DrillStand-drawing.png)\n" -"\n" -"Start with putting the slots of the inner walls together. Be especially " -"careful with adding the bottom. It is always asymmetrical and flush with the " -"right/lower side while being a little short on the left/higher side to not " -"protrude into the side wall.\n" -"\n" -"| | |\n" -"| ---- | ---- |\n" -"| ![Assembly inner walls](static/samples/DrillStand-assembly-1.jpg) | !" -"[Assembly bottom](static/samples/DrillStand-assembly-2.jpg) |\n" -"| Then add the front and the back wall. | Add the very left and right walls " -"last. |\n" -"| ![Assembly front and back](static/samples/DrillStand-assembly-3.jpg) | !" -"[Assembly side walls](static/samples/DrillStand-assembly-4.jpg) |\n" -msgstr "" - -msgid "DrillStand Settings" -msgstr "" - -#. parameter name -#: boxes/generators/drillstand.py -msgid "extra_height" -msgstr "" - -#. help for parameter extra_height -#: boxes/generators/drillstand.py -msgid "height difference left to right" -msgstr "" - -#. name of box generator -#: boxes/generators/electronicsbox.py -msgid "ElectronicsBox" -msgstr "" - -#. description of ElectronicsBox -#: boxes/generators/electronicsbox.py -msgid "Closed box with screw on top and mounting holes" -msgstr "" - -msgid "ElectronicsBox Settings" -msgstr "" - -#. help for parameter triangle -#: boxes/generators/electronicsbox.py -msgid "Sides of the triangles holding the lid in mm" -msgstr "" - -#. parameter name -#: boxes/generators/electronicsbox.py -msgid "d1" -msgstr "" - -#. help for parameter d1 -#: boxes/generators/electronicsbox.py -msgid "Diameter of the inner lid screw holes in mm" -msgstr "" - -#. parameter name -#: boxes/generators/electronicsbox.py -msgid "d2" -msgstr "" - -#. help for parameter d2 -#: boxes/generators/electronicsbox.py -msgid "Diameter of the lid screw holes in mm" -msgstr "" - -#. parameter name -#: boxes/generators/electronicsbox.py -msgid "d3" -msgstr "" - -#. help for parameter d3 -#: boxes/generators/electronicsbox.py -msgid "Diameter of the mounting screw holes in mm" -msgstr "" - -#. parameter name -#: boxes/generators/electronicsbox.py -msgid "outsidemounts" -msgstr "" - -#. help for parameter outsidemounts -#: boxes/generators/electronicsbox.py -msgid "Add external mounting points" -msgstr "" - -#. parameter name -#: boxes/generators/electronicsbox.py -msgid "holedist" -msgstr "" - -#. help for parameter holedist -#: boxes/generators/electronicsbox.py -msgid "Distance of the screw holes from the wall in mm" -msgstr "" - -#. name of box generator -#: boxes/generators/eurorackskiff.py -msgid "EuroRackSkiff" -msgstr "" - -#. description of EuroRackSkiff -#: boxes/generators/eurorackskiff.py -msgid "3U Height case with adjustable width and height and included rails" -msgstr "" - -msgid "EuroRackSkiff Settings" -msgstr "" - -#. parameter name -#: boxes/generators/eurorackskiff.py -msgid "hp" -msgstr "" - -#. help for parameter hp -#: boxes/generators/eurorackskiff.py -msgid "Width of the case in HP" -msgstr "" - -#. name of box generator -#: boxes/generators/fanhole.py -msgid "FanHole" -msgstr "" - -#. description of FanHole -#: boxes/generators/fanhole.py -msgid "Hole pattern for mounting a fan" -msgstr "" - -msgid "FanHole Settings" -msgstr "" - -#. help for parameter diameter -#: boxes/generators/fanhole.py -msgid "diameter of the fan hole" -msgstr "" - -#. parameter name -#: boxes/generators/fanhole.py -msgid "mounting_holes" -msgstr "" - -#. help for parameter mounting_holes -#: boxes/generators/fanhole.py -msgid "diameter of the fan mounting holes" -msgstr "" - -#. parameter name -#: boxes/generators/fanhole.py -msgid "mounting_holes_inset" -msgstr "" - -#. help for parameter mounting_holes_inset -#: boxes/generators/fanhole.py -msgid "distance of the fan mounting holes from the outside" -msgstr "" - -#. parameter name -#: boxes/generators/fanhole.py -msgid "arms" -msgstr "" - -#. help for parameter arms -#: boxes/generators/fanhole.py -msgid "number of arms" -msgstr "" - -#. parameter name -#: boxes/generators/fanhole.py -msgid "inner_disc" -msgstr "" - -#. help for parameter inner_disc -#: boxes/generators/fanhole.py -msgid "relative size of the inner disc" -msgstr "" - -#. help for parameter style -#: boxes/generators/fanhole.py -msgid "Style of the fan hole" -msgstr "" - -#. possible choice for style -#: boxes/generators/fanhole.py -msgid "CW Swirl" -msgstr "" - -#. possible choice for style -#: boxes/generators/fanhole.py -msgid "CCW Swirl" -msgstr "" - -#. possible choice for style -#: boxes/generators/fanhole.py -msgid "Hole" -msgstr "" - -#. name of box generator -#: boxes/generators/filamentspool.py -msgid "FilamentSpool" -msgstr "" - -#. description of FilamentSpool -#: boxes/generators/filamentspool.py -msgid "A two part spool for 3D printing filament" -msgstr "" - -#. long description of FilamentSpool in markdown -#: boxes/generators/filamentspool.py -msgid "" -"\n" -"Use small nails to properly align the pieces of the bayonet latch. Glue the " -"parts of the bayonet latch before assembling the \"axle\". The inner parts " -"go at the side and the outer parts at the inside of the axle.\n" -"![opened spool](static/samples/FilamentSpool-2.jpg)" -msgstr "" - -msgid "FilamentSpool Settings" -msgstr "" - -#. parameter name -#: boxes/generators/filamentspool.py -msgid "outer_diameter" -msgstr "" - -#. help for parameter outer_diameter -#: boxes/generators/filamentspool.py -msgid "diameter of the flanges" -msgstr "" - -#. parameter name -#: boxes/generators/filamentspool.py -msgid "inner_diameter" -msgstr "" - -#. help for parameter inner_diameter -#: boxes/generators/filamentspool.py -msgid "diameter of the center part" -msgstr "" - -#. parameter name -#: boxes/generators/filamentspool.py -msgid "axle_diameter" -msgstr "" - -#. help for parameter axle_diameter -#: boxes/generators/filamentspool.py -msgid "diameter of the axle hole" -msgstr "" - -#. parameter name -#: boxes/generators/filamentspool.py -msgid "sides" -msgstr "" - -#. help for parameter sides -#: boxes/generators/filamentspool.py -msgid "number of pieces for the center part" -msgstr "" - -#. name of box generator -#: boxes/generators/filltest.py -msgid "FillTest" -msgstr "" - -#. description of FillTest -#: boxes/generators/filltest.py -msgid "Piece for testing different settings for hole filling" -msgstr "" - -msgid "FillTest Settings" -msgstr "" - -#. description of FlexBox -#: boxes/generators/flexbox.py -msgid "Box with living hinge and round corners" -msgstr "" - -msgid "FlexBox Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/flexbox2.py -msgid "FlexBox2" -msgstr "" - -#. description of FlexBox2 -#: boxes/generators/flexbox2.py -msgid "Box with living hinge and top corners rounded" -msgstr "" - -msgid "FlexBox2 Settings" -msgstr "" - -#. help for parameter radius -#: boxes/generators/flexbox2.py -msgid "Radius of the corners in mm" -msgstr "" - -#. name of box generator -#: boxes/generators/flexbox3.py -msgid "FlexBox3" -msgstr "" - -#. description of FlexBox3 -#: boxes/generators/flexbox3.py -msgid "Box with living hinge" -msgstr "" - -msgid "FlexBox3 Settings" -msgstr "" - -#. parameter name -#: boxes/generators/flexbox3.py -msgid "z" -msgstr "" - -#. help for parameter z -#: boxes/generators/flexbox3.py -msgid "height of the box" -msgstr "" - -#. help for parameter h -#: boxes/generators/flexbox3.py -msgid "height of the lid" -msgstr "" - -#. help for parameter radius -#: boxes/generators/flexbox3.py -msgid "radius of the lids living hinge" -msgstr "" - -#. help for parameter c -#: boxes/generators/flexbox3.py -msgid "clearance of the lid" -msgstr "" - -#. name of box generator -#: boxes/generators/flexbox4.py -msgid "FlexBox4" -msgstr "" - -#. description of FlexBox4 -#: boxes/generators/flexbox4.py -msgid "Box with living hinge and left corners rounded" -msgstr "" - -msgid "FlexBox4 Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/flexbox5.py -msgid "FlexBox5" -msgstr "" - -msgid "FlexBox5 Settings" -msgstr "" - -#. parameter name -#: boxes/generators/flexbox5.py -msgid "top_diameter" -msgstr "" - -#. help for parameter top_diameter -#: boxes/generators/flexbox5.py -msgid "diameter at the top" -msgstr "" - -#. parameter name -#: boxes/generators/flexbox5.py -msgid "bottom_diameter" -msgstr "" - -#. help for parameter bottom_diameter -#: boxes/generators/flexbox5.py -msgid "diameter at the bottom" -msgstr "" - -#. name of box generator -#: boxes/generators/flextest.py -msgid "FlexTest" -msgstr "" - -#. description of FlexTest -#: boxes/generators/flextest.py -msgid "Piece for testing different flex settings" -msgstr "" - -msgid "FlexTest Settings" -msgstr "" - -#. name of box generator -#: boxes/generators/flextest2.py -msgid "FlexTest2" -msgstr "" - -#. description of FlexTest2 -#: boxes/generators/flextest2.py -msgid "Piece for testing 2D flex settings" -msgstr "" - -msgid "FlexTest2 Settings" -msgstr "" - -#. parameter name -#: boxes/generators/flextest2.py -msgid "fw" -msgstr "" - -#. help for parameter fw -#: boxes/generators/flextest2.py -msgid "distance of flex cuts in multiples of thickness" -msgstr "" - -#. name of box generator -#: boxes/generators/folder.py -msgid "Folder" -msgstr "" - -#. description of Folder -#: boxes/generators/folder.py -msgid "Book cover with flex for the spine" -msgstr "" - -msgid "Folder Settings" -msgstr "" - -#. parameter name -#: boxes/generators/folder.py -msgid "r" -msgstr "" - -#. name of box generator -#: boxes/generators/frontpanel.py -msgid "FrontPanel" -msgstr "" - -#. description of FrontPanel -#: boxes/generators/frontpanel.py -msgid "Mounting Holes and cutouts for all your holy needs." -msgstr "" - -#. long description of FrontPanel in markdown -#: boxes/generators/frontpanel.py -msgid "" -"\n" -" -""") - return b''.join(s.encode("utf-8") for s in result) - - def writeINX(self, name, box, path): - with open(os.path.join(path, "boxes.py." + name + '.inx'), "wb") as f: - f.write(self.generator2inx(name, box)) - - def writeAllINX(self, path): - for name, box in self.boxes.items(): - if name.startswith("TrayLayout"): - # The two stage thing does not work (yet?) - continue - self.writeINX(name, box, path) - - -def main() -> None: - if len(sys.argv) != 2: - print("Usage: boxes2inkscape TARGETPATH") - return - b = Boxes2INX() - b.writeAllINX(sys.argv[1]) - - -if __name__ == "__main__": - main() diff --git a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes2pot b/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes2pot deleted file mode 100755 index 9159969..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes2pot +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2019 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from __future__ import annotations - -import argparse -import os.path -import sys -from typing import Any - -try: - import boxes.generators -except ImportError: - sys.path.append(os.path.dirname(__file__) + "/..") - import boxes.generators -from boxes import edges, lids - - -class DefaultParams(boxes.Boxes): - - def __init__(self) -> None: - boxes.Boxes.__init__(self) - self.buildArgParser("x", "y", "h", "hi", "sx", "sy", "sh", - "bottom_edge", "top_edge", "outside", "nema_mount") - self.addSettingsArgs(edges.FingerJointSettings, finger=1.0, space=1.0) - self.addSettingsArgs(edges.StackableSettings) - self.addSettingsArgs(edges.HingeSettings) - self.addSettingsArgs(edges.SlideOnLidSettings) - self.addSettingsArgs(edges.ClickSettings) - self.addSettingsArgs(edges.FlexSettings) - self.addSettingsArgs(lids.LidSettings) - - -class Boxes2pot: - def __init__(self) -> None: - self.messages: list[Any] = [] - self.message_set: set[Any] = set() - self.boxes = {b.__name__: b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface} - self.groups = boxes.generators.ui_groups - self.groups_by_name = boxes.generators.ui_groups_by_name - self._readEdgeDescriptions() - - def add(self, msg, comment=None, reference=None): - if not msg or msg in self.message_set: - return - self.message_set.add(msg) - self.messages.append((msg, comment, reference)) - - def filename_from_module(self, modulename): - modulenames = modulename.split(".") - return "/".join(modulenames) + ".py" - - def _readEdgeDescriptions(self): - for char, descr in edges.getDescriptions().items(): - self.add(descr, f"{char} edge description", "boxes/edges.py") - self.add(f"{char} {descr}", f"{char} edge description", "boxes/edges.py") - - def addBoxParams(self, name, box, location=None): - for group in box.argparser._action_groups: - if not group._group_actions: - continue - self.add(group.title) - for a in group._group_actions: - if a.dest in ("input", "output"): - continue - if isinstance(a, argparse._HelpAction): - continue - prefix = getattr(group, "prefix", "") - name = a.option_strings[0].replace("-", "") - if prefix and name.startswith(prefix + '_'): - name = name[len(prefix) + 1:] - self.add(name, "parameter name for " + prefix, location) - else: - self.add(name, "parameter name", location) - if a.help: - self.add(a.help, "help for parameter " + name, location) - for c in a.choices or []: - if isinstance(c, (float, int)): - continue - self.add(c, "possible choice for " + name, location) - - def readBoxes(self): - for group in self.groups: - location = "boxes/generators/__init__.py" - self.add(group.name, "name of generator group", location) - self.add(group.title, "title of group " + group.name, location) - self.add(group.description, "description of group " + group.name, location) - self.addBoxParams(None, DefaultParams()) - for name, box in self.boxes.items(): - location = self.filename_from_module(box.__module__) - self.add(name, "name of box generator", location) - if box.__doc__: - self.add(box.__doc__, "description of " + name, location) - if box.description: - self.add(box.description, "long description of " + name + " in markdown", location) - self.addBoxParams(name, box, location) - - def writePOT(self, fn): - with open(fn, encoding="utf-8", mode="w") as f: - f.write(r"""msgid "" -msgstr "" -"Project-Id-Version: boxes.py VERSION\n" -"PO-Revision-Date: 2019-04-20 14:53+0200\n" -"Last-Translator: Florian Festi \n" -"Language-Team: English\n" -"Language: en_US\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -""") - - for msg, comment, reference in self.messages: - f.write("\n") - if comment: - f.write("#. %s\n" % comment) - if reference: - f.write("#: %s\n" % reference) - msg = msg.split("\n") - for i in range(len(msg) - 1): - msg[i] += "\\n" - f.write('msgid ') - for m in msg: - f.write(' "%s"\n' % m.replace('"', '\\"')) - f.write('msgstr ""\n') - - -def main() -> None: - if len(sys.argv) != 2: - print("Usage: boxes2pot TARGETPATH") - return - b = Boxes2pot() - b.readBoxes() - b.writePOT(sys.argv[1]) - - -if __name__ == "__main__": - main() diff --git a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes_example.ipynb b/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes_example.ipynb deleted file mode 100644 index e451b80..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes_example.ipynb +++ /dev/null @@ -1,176 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Boxes.py example\n", - "\n", - "This notebook is an interactive example of a Boxes.py generator. Feel free to play around and see how the result changes.\n", - "\n", - "Check out http://florianfesti.github.io/boxes/html/index.html for documentation." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import SVG, display\n", - "\n", - "import sys\n", - "# sys.path.append('..') # uncomments and adjust if your Boxes.py copy in not in the Python path\n", - "from boxes import *" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "Example\n", - "\n", - "\n", - "Shelves - Example\n", - "2024-02-11 17:45:59\n", - "boxes Example --reference=0 --debug=0\n", - "Example: Single Shelve to screw to the wall\n", - "\n", - "Created with Boxes.py (https://festi.info/boxes.py)\n", - "Command line: boxes Example --reference=0 --debug=0\n", - "Command line short: boxes Example --reference=0\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "class Example(Boxes): # Adjust class name and call below\n", - " \"\"\"Example: Single Shelve to screw to the wall\"\"\"\n", - "\n", - " ui_group = \"Shelves\" # change for generators belonging in another group\n", - " \n", - " def __init__(self):\n", - " Boxes.__init__(self)\n", - " # arguments\n", - " self.addSettingsArgs(edges.FingerJointSettings, finger=3.0) # arguments for finger joints\n", - " self.buildArgParser(x=150, y=70, h=50)\n", - " self.argparser.add_argument(\n", - " \"--hole_dist\", action=\"store\", type=float, default=10.,\n", - " help=\"distance of the mounting holes to the boards\")\n", - " self.argparser.add_argument(\n", - " \"--hole_dia\", action=\"store\", type=float, default=3., # can't use \"hole\" as param name as it is a method\n", - " help=\"diameter of the mounting holes\")\n", - " \n", - " def render(self):\n", - " x, y, h = self.x, self.y, self.h\n", - " t = self.thickness\n", - " \n", - " # render-magic goes here\n", - " \n", - " hole = lambda: self.hole(self.hole_dist, self.hole_dist, d=self.hole_dia) # use lambda as a callback\n", - " # holes are placed relative to the inner rectangle of the back wall. The top part with the finger holes and \n", - " # the finges at the sides do not count.\n", - " # Callbacks start in the bottom left corner. Place holes in the third and forth corners only. \n", - " self.rectangularWall(x, h, \"eFhF\", move=\"up\", callback=[None, None, hole, hole]) # back board\n", - "\n", - " self.rectangularWall(x, y, \"ehfh\", move=\"up\") # top board\n", - " self.rectangularTriangle(y, h, \"ff\", num=2) # braces \n", - " \n", - "\n", - "b = Example()\n", - "b.parseArgs(['--reference=0', '--debug=0'])\n", - "b.open()\n", - "b.render()\n", - "data = b.close()\n", - "\n", - "display(SVG(data=data.getvalue()))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.1" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes_proxy.py b/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes_proxy.py deleted file mode 100755 index 0800ab3..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxes_proxy.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python3 - -""" -Extension for InkScape 1.0+ - -boxes.py wrapper script to make it work on Windows and Linux systems without duplicating .inx files - -Author: Mario Voigt / FabLab Chemnitz -Mail: mario.voigt@stadtfabrikanten.org -Date: 27.04.2021 -Last patch: 27.04.2021 -License: GNU GPL v3 - -""" -pass -import subprocess -import sys - -pass -from shlex import quote - -from inkex.extensions import GenerateExtension -from lxml import etree - -import inkex - - -class boxesPyWrapper(GenerateExtension): - def add_arguments(self, pars): - args = sys.argv[1:] - for arg in args: - key = arg.split("=")[0] - if key == "--id": - continue - if len(arg.split("=")) == 2: - value = arg.split("=")[1] - pars.add_argument(key, default=key) - - def generate(self): - cmd = "boxes" # boxes.exe in this local dir (or if present in %PATH%), or boxes from $PATH in linux - for arg in vars(self.options): - if arg in ( - "output", "id", "ids", "selected_nodes", - "input_file", "tab"): - continue - # fix behaviour of "original" arg which does not correctly gets - # interpreted if set to false - if arg == "original" and str(getattr(self.options, arg)) == "false": - continue - cmd += f" --{arg} {quote(str(getattr(self.options, arg)))}" - cmd += f" --output -" - cmd = cmd.replace("boxes --generator", "boxes") - - # run boxes with the parameters provided - result = subprocess.run(cmd.split(), capture_output=True) - - if result.returncode: - inkex.utils.debug("Generating box svg failed. Cannot continue. Command was:") - inkex.utils.debug(str(cmd)) - inkex.utils.debug(str(result.stderr)) - exit(1) - - # write the generated SVG into Inkscape's canvas - p = etree.XMLParser(huge_tree=True) - doc = etree.fromstring(result.stdout, parser=etree.XMLParser(huge_tree=True)) - group = inkex.Group(id="boxes.py") - for element in doc: - group.append(element) - return group - - -def main() -> None: - boxesPyWrapper().run() - - -if __name__ == '__main__': - main() diff --git a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxesserver b/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxesserver deleted file mode 100755 index ef4e862..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/scripts/boxesserver +++ /dev/null @@ -1,711 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2016-2017 Florian Festi -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from __future__ import annotations - -import argparse -import gettext -import glob -import html -import io -import mimetypes -import os.path -import re -import sys -import threading -import time -import traceback -from typing import Any, NoReturn -from urllib.parse import quote, unquote_plus -from wsgiref.simple_server import make_server - -import markdown -import qrcode - -try: - import boxes.generators -except ImportError: - sys.path.append(os.path.join(os.path.dirname(__file__), "..")) - import boxes.generators - - -class FileChecker(threading.Thread): - def __init__(self, files=[], checkmodules: bool = True) -> None: - super().__init__() - self.checkmodules = checkmodules - self.timestamps = {} - self._stopped = False - for path in files: - self.timestamps[path] = os.stat(path).st_mtime - if checkmodules: - self._addModules() - - def _addModules(self) -> None: - for name, module in sys.modules.items(): - path = getattr(module, "__file__", None) - if not path: - continue - if path not in self.timestamps: - self.timestamps[path] = os.stat(path).st_mtime - - def filesOK(self) -> bool: - if self.checkmodules: - self._addModules() - for path, timestamp in self.timestamps.items(): - try: - if os.stat(path).st_mtime != timestamp: - return False - except FileNotFoundError: - return False - return True - - def run(self) -> None: - while not self._stopped: - if not self.filesOK(): - os.execv(__file__, sys.argv) - time.sleep(1) - - def stop(self) -> None: - self._stopped = True - - -def filter_url(url, non_default_args): - if len(url) == 0: - return '' - try: - base, args = url.split('?') - except ValueError: - return '' - args = args.split('&') - new_args = [] - args_to_ignore = ["qr_code", "format"] - for arg in args: - a, b = arg.split('=') - if a.strip() in args_to_ignore: - continue - if a in non_default_args: - new_args.append(arg) - if len(new_args): - return f"{base}?{'&'.join(new_args)}" - else: - return f"{base}" - - -class ArgumentParserError(Exception): pass - - -class ThrowingArgumentParser(argparse.ArgumentParser): - def error(self, message) -> NoReturn: - raise ArgumentParserError(message) - - -# Evil hack -boxes.ArgumentParser = ThrowingArgumentParser # type: ignore - - -class BServer: - lang_re = re.compile(r"([a-z]{2,3}(-[-a-zA-Z0-9]*)?)\s*(;\s*q=(\d\.?\d*))?") - - def __init__(self, url_prefix="", static_url="static") -> None: - self.boxes = {b.__name__: b for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface} - self.groups = boxes.generators.ui_groups - self.groups_by_name = boxes.generators.ui_groups_by_name - - for name, box in self.boxes.items(): - box.UI = "web" - self.groups_by_name.get(box.ui_group, - self.groups_by_name["Misc"]).add(box) - - self.staticdir = os.path.join(os.path.dirname(__file__), '../static/') - self._languages = None - self._cache: dict[Any, Any] = {} - self.url_prefix = url_prefix - self.static_url = static_url - - def getLanguages(self, domain=None, localedir=None): - if self._languages is not None: - return self._languages - self._languages = [] - domain = "boxes.py" - for localedir in ["locale", gettext._default_localedir]: - files = glob.glob(os.path.join(localedir, '*', 'LC_MESSAGES', '%s.mo' % domain)) - self._languages.extend([file.split(os.path.sep)[-3] for file in files]) - self._languages.sort() - return self._languages - - def getLanguage(self, args, accept_language): - lang = None - langs = [] - - for i, arg in enumerate(args): - if arg.startswith("language="): - lang = arg[len("language="):] - del args[i] - break - if lang: - try: - return gettext.translation('boxes.py', localedir='locale', languages=[lang]) - except OSError: - pass - try: - return gettext.translation('boxes.py', languages=[lang]) - except OSError: - pass - - # selected language not found try browser default - languages = accept_language.split(",") - for l in languages: - m = self.lang_re.match(l.strip()) - if m: - langs.append((float(m.group(4) or 1.0), m.group(1))) - - langs.sort(reverse=True) - langs = [l[1].replace("-", "_") for l in langs] - - try: - return gettext.translation('boxes.py', localedir='locale', languages=langs) - except OSError: - return gettext.translation('boxes.py', languages=langs, fallback=True) - - def arg2html(self, a, prefix, defaults={}, _=lambda s: s): - name = a.option_strings[0].replace("-", "") - if isinstance(a, argparse._HelpAction): - return "" - viewname = name - if prefix and name.startswith(prefix + '_'): - viewname = name[len(prefix) + 1:] - - default = defaults.get(name, None) - row = """%%s%s\n""" % \ - (name + "_id", name, _(viewname), name + "_description", "" if not a.help else markdown.markdown(_(a.help))) - if (isinstance(a, argparse._StoreAction) and - hasattr(a.type, "html")): - input = a.type.html(name, default or a.default, _) - elif a.type == str and "\n" in a.default: - val = (default or a.default).split("\n") - input = """""" % \ - (name, name, name + "_id", name + "_description", max(len(l) for l in val) + 10, len(val) + 1, default or a.default) - elif a.choices: - options = "\n".join( - """""" % - (e, ' selected="selected"' if (e == (default or a.default)) or (str(e) == str(default or a.default)) else "", - _(e)) for e in a.choices) - input = """\n""".format(name, name, name + "_id", name + "_description", options) - else: - input = """""" % \ - (name, name, name + "_id", name + "_description", default or a.default) - - return row % input - - def args2html_cached(self, name, box, lang, action="", defaults={}): - if defaults == {}: - key = (name, lang.info().get('language', None), action) - if key not in self._cache: - self._cache[key] = list(self.args2html(name, box, lang, action, defaults)) - return self._cache[key] - - return self.args2html(name, box, lang, action, defaults) - - def args2html(self, name, box, lang, action="", defaults={}): - _ = lang.gettext - lang_name = lang.info().get('language', None) - - langparam = "" - if lang_name: - langparam = "?language=" + lang_name - - result = [f"""{self.genHTMLStart(lang)} - - {_("%s - Boxes") % _(name)} - {self.genHTMLMeta()} - {self.genHTMLMetaLanguageLink()} - {self.genHTMLCSS()} - {self.genHTMLJS()} - - - -
- -
-self-Logo -
-
-
-
-

{_(name)}

-

{_(box.__doc__) if box.__doc__ else ""}

-
- """] - groupid = 0 - for group in box.argparser._action_groups[3:] + box.argparser._action_groups[:3]: - if not group._group_actions: - continue - if len(group._group_actions) == 1 and isinstance(group._group_actions[0], argparse._HelpAction): - continue - prefix = getattr(group, "prefix", None) - result.append(f'''

{_(group.title)}

\n\n''') - - for a in group._group_actions: - if a.dest in ("input", "output"): - continue - result.append(self.arg2html(a, prefix, defaults, _)) - result.append("") - groupid += 1 - - result.append(f""" - - -

- - - - -

-
-
- -
-
-
-""") - no_img_msg = _('There is no image yet. Please donate an image of your project on GitHub!') - - if box.description: - result.append( - markdown.markdown(_(box.description), extensions=["extra"]) - .replace('src="static/', f'src="{self.static_url}/')) - - result.append(f'''
-Picture of box. -
-
-
-{self.genPagePartFooter(lang)} - - - ''') - return (s.encode("utf-8") for s in result) - - def genPageMenu(self, lang): - _ = lang.gettext - lang_name = lang.info().get('language', None) - - langparam = "" - if lang_name: - langparam = "?language=" + lang_name - - result = [f"""{self.genHTMLStart(lang)} - - {_("Boxes.py")} - {self.genHTMLMeta()} - {self.genHTMLMetaLanguageLink()} - {self.genHTMLCSS()} - {self.genHTMLJS()} - - -
-
-{self.genPagePartHeader(lang)} - -
-{_("Gallery")} -{_("Menu")} -
-
- - -
-
-
-
-
-{self.genPagePartFooter(lang)} - - -""") - return (s.encode("utf-8") for s in result) - - def genHTMLStart(self, lang) -> str: - lang_attr = lang.info().get("language", "") - - if lang_attr != "": - return f"""""" - - return "" - - def genHTMLMeta(self) -> str: - return f''' - - - - - - ''' - - def genHTMLMetaLanguageLink(self) -> str: - """Generates meta language list for search engines.""" - languages = self.getLanguages() - - s = "" - for language in languages: - s += f'\n' - return s - - def genHTMLCSS(self) -> str: - return f'' - - def genHTMLJS(self) -> str: - return f'' - - def genHTMLLanguageSelection(self, lang) -> str: - """Generates a dropdown selection for the language change.""" - current_language = lang.info().get('language', '') - languages = self.getLanguages() - - if len(languages) < 2: - return "" - - html_option = "" - for language in languages: - html_option += f"\n" - - return """ -
- -
- """ - - def genPagePartHeader(self, lang) -> str: - _ = lang.gettext - lang_name = lang.info().get('language', None) - - langparam = "" - if lang_name: - langparam = "?language=" + lang_name - - return f""" -

{_("Boxes.py")}

-

{_("Create boxes and more with a laser cutter!")}

-

-{_(''' - Boxes.py is an Open Source box generator written in Python. It features both finished parametrized generators as well as a Python API for writing your own. It features finger and (flat) dovetail joints, flex cuts, holes and slots for screws, hinges, gears, pulleys and much more.''')} -

- - -
-self-Logo -
- -
- -
- -""" - - def genPagePartFooter(self, lang) -> str: - _ = lang.gettext - - return """ - -""" - - def genPageError(self, name, e, lang) -> list[bytes]: - """Generates a error page.""" - _ = lang.gettext - - h = f"""{self.genHTMLStart(lang)} - - {_("Error generating %s") % _(name)} - {self.genHTMLMeta()} - - - -

{_("An error occurred!")}

-""" - for s in str(e).split("\n"): - h += f"

{html.escape(s)}

\n" - h += "" - return [h.encode("utf-8")] - - def serveStatic(self, environ, start_response): - filename = environ["PATH_INFO"][len("/static/"):] - path = os.path.join(self.staticdir, filename) - if (not re.match(r"[a-zA-Z0-9_/-]+\.[a-zA-Z0-9]+", filename) or - not os.path.exists(path)): - if re.match(r"samples/.*-thumb.jpg", filename): - path = os.path.join(self.staticdir, "nothing.png") - else: - start_response("404 Not Found", [('Content-type', 'text/plain')]) - return [b"Not found"] - - type_, encoding = mimetypes.guess_type(filename) - if encoding is None: - encoding = "utf-8" - - # Images do not have charset. Just bytes. Except text based svg. - # Todo: fallback if type_ is None? - if type_ is not None and "image" in type_ and type_ != "image/svg+xml": - start_response("200 OK", [('Content-type', "%s" % type_)]) - else: - start_response("200 OK", [('Content-type', f"{type_}; charset={encoding}")]) - - f = open(path, 'rb') - return environ['wsgi.file_wrapper'](f, 512 * 1024) - - def getURL(self, environ) -> str: - url = environ['wsgi.url_scheme'] + '://' - - if environ.get('HTTP_HOST'): - url += environ['HTTP_HOST'] - else: - url += environ['SERVER_NAME'] - - if environ['wsgi.url_scheme'] == 'https': - if environ['SERVER_PORT'] != '443': - url += ':' + environ['SERVER_PORT'] - else: - if environ['SERVER_PORT'] != '80': - url += ':' + environ['SERVER_PORT'] - url += quote(self.url_prefix) - url += quote(environ.get('SCRIPT_NAME', '')) - url += quote(environ.get('PATH_INFO', '')) - if environ.get('QUERY_STRING'): - url += '?' + environ['QUERY_STRING'] - - return url - - def serveGallery(self, environ, start_response, lang): - _ = lang.gettext - lang_name = lang.info().get('language', None) - - start_response("200 OK", [('Content-type', "text/html; charset=utf-8")]) - - if ("Gallery", lang_name) in self._cache: - return self._cache[("Gallery", lang_name)] - - langparam = "" - if lang_name: - langparam = "?language=" + lang_name - - result = [f""" -{self.genHTMLStart(lang)} - - {_("Gallery")} - {_("Boxes.py")} - {self.genHTMLMeta()} - {self.genHTMLMetaLanguageLink()} - {self.genHTMLCSS()} - {self.genHTMLJS()} - - -
-
-{self.genPagePartHeader(lang)} -
-{_("Gallery")} -{_("Menu")} -
-"""] - for nr, group in enumerate(self.groups): - result.append(f"

{_(group.title)}

\n") - for box in group.generators: - name = box.__name__ - fn = f"samples/{name}-thumb.jpg" - thumbnail = f"{self.static_url}/{fn}" - static_filename = os.path.join(self.staticdir, fn) - alt = f"{_(name)}" - href = f"{name}{langparam}" - if not os.path.exists(static_filename): - result.append(f""" {_(name)}

{_(box.__doc__)}
\n""") - else: - result.append(f""" {alt}\n""") - - result.append(f""" -
-

-{self.genPagePartFooter(lang)} - - -""" - ) - self._cache[("Gallery", lang_name)] = [s.encode("utf-8") for s in result] - return self._cache[("Gallery", lang_name)] - - def serve(self, environ, start_response): - # serve favicon from static for generated SVGs - if environ["PATH_INFO"] == "favicon.ico": - environ["PATH_INFO"] = "/static/favicon.ico" - if environ["PATH_INFO"].startswith("/static/"): - return self.serveStatic(environ, start_response) - - status = '200 OK' - headers = [('Content-type', 'text/html; charset=utf-8'), ('X-XSS-Protection', '1; mode=block'), ('X-Content-Type-Options', 'nosniff'), ('x-frame-options', 'SAMEORIGIN'), ('Referrer-Policy', 'no-referrer')] - - name = environ["PATH_INFO"][1:] - args = [unquote_plus(arg) for arg in environ.get('QUERY_STRING', '').split("&")] - render = "0" - for arg in args: - if arg.startswith("render="): - render = arg[len("render="):] - - lang = self.getLanguage(args, environ.get("HTTP_ACCEPT_LANGUAGE", "")) - _ = lang.gettext - - if not name or name == "Gallery": - return self.serveGallery(environ, start_response, lang) - - box_cls = self.boxes.get(name, None) - if not box_cls: - start_response(status, headers) - - lang_name = lang.info().get('language', None) - if lang_name not in self._cache: - self._cache[lang_name] = list(self.genPageMenu(lang)) - return self._cache[lang_name] - - box = box_cls() - - box.translations = lang - - if render == "0": - defaults = {} - for a in args: - kv = a.split('=') - if len(kv) == 2: - k, v = kv - defaults[k] = html.escape(v, True) - start_response(status, headers) - return self.args2html_cached(name, box, lang, "./" + name, defaults=defaults) - - args = ["--" + arg for arg in args if not arg.startswith("render=")] - try: - box.parseArgs(args) - except ArgumentParserError as e: - start_response(status, headers) - return self.genPageError(name, e, lang) - - try: - box.metadata["url"] = self.getURL(environ) - box.metadata["url_short"] = filter_url(box.metadata["url"], - box.non_default_args) - box.open() - box.render() - data = box.close() - except Exception as e: - if not isinstance(e, ValueError): - print("Exception during rendering:") - traceback.print_exc() - start_response("500 Internal Server Error", headers) - return self.genPageError(name, e, lang) - - http_headers = box.formats.http_headers.get(box.format, [('Content-type', 'application/unknown; charset=utf-8')])[:] - # Prevent crawlers. - http_headers.append(('X-Robots-Tag', 'noindex,nofollow')) - - if render == "3": - http_headers = [('Content-type', 'image/png')] - http_headers.append(('X-Robots-Tag', 'noindex,nofollow')) - qr_format = "png" - fn = box.__class__.__name__ - start_response(status, http_headers) - qrcode = get_qrcode(box.metadata["url_short"], qr_format) - return (qrcode,) - - if box.format != "svg" or render == "2": - extension = box.format - if extension == "svg_Ponoko": - extension = "svg" - http_headers.append(('Content-Disposition', f'attachment; filename="{box.__class__.__name__}.{extension}"')) - start_response(status, http_headers) - return environ['wsgi.file_wrapper'](data, 512 * 1024) - - -def get_qrcode(url, format): - if url is None: - url = "no url" - img = qrcode.make(url) - image_bytes = io.BytesIO() - img.save(image_bytes, format=format) - return image_bytes.getvalue() - - -def main() -> None: - parser = argparse.ArgumentParser() - - parser.add_argument("--host", default="") - parser.add_argument("--port", type=int, default=8000) - parser.add_argument("--url_prefix", default="", - help="URL path to Boxes.py instance") - parser.add_argument("--static_url", default="static", - help="URL of static content") - args = parser.parse_args() - - boxserver = BServer(url_prefix=args.url_prefix, static_url=args.static_url) - - fc = FileChecker() - fc.start() - - httpd = make_server(args.host, args.port, boxserver.serve) - print(f"BoxesServer serving on {args.host}:{args.port}...") - try: - httpd.serve_forever() - except KeyboardInterrupt: - fc.stop() - httpd.server_close() - print("BoxesServer stops.") - - -if __name__ == "__main__": - main() -else: - boxserver = BServer(url_prefix='/boxes.py', static_url="https://florianfesti.github.io/boxes/static") - application = boxserver.serve diff --git a/extensions/fablabchemnitz/boxes.py/boxes/scripts/gen_thumbnails.sh b/extensions/fablabchemnitz/boxes.py/boxes/scripts/gen_thumbnails.sh deleted file mode 100755 index 15d12a4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/scripts/gen_thumbnails.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -set -e - -STATIC_DIR=../static/samples/ -THUMB_WIDTH=200 -THUMB_HEIGHT=10000 # height: auto; - -thumbnail() { - echo "convert \"$1\" -thumbnail ${THUMB_WIDTH}x${THUMB_HEIGHT} \"${1%.*}-thumb.jpg\"" - convert "$1" -thumbnail ${THUMB_WIDTH}x${THUMB_HEIGHT} "${1%.*}-thumb.jpg" -} - -[ ! -f "$STATIC_DIR"samples.sha256 ] && touch "$STATIC_DIR"samples.sha256 - -find "$STATIC_DIR" -name '*.jpg' ! -name '*-thumb.jpg' -type f | while read -r f -do - f_=$(echo "$f" | sed -E -e 's@([.])@\\\1@g') - checksum=$(grep "$f_" "$STATIC_DIR"samples.sha256 || /bin/true) - if [ -n "$checksum" ] - then - echo "$checksum" | sha256sum -c --status || { - echo "File $f changed" - sed -i "/$f_/ c\\ -$(sha256sum "$f") -" "$STATIC_DIR"samples.sha256 - thumbnail "$f" - } - else - echo "New file $f" - sha256sum "$f" >> "$STATIC_DIR"samples.sha256 - thumbnail "$f" - fi -done diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/boxes-logo.svg b/extensions/fablabchemnitz/boxes.py/boxes/static/boxes-logo.svg deleted file mode 100644 index dd5dd8a..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/static/boxes-logo.svg +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/favicon.ico b/extensions/fablabchemnitz/boxes.py/boxes/static/favicon.ico deleted file mode 100644 index 2e76dba..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/favicon.ico and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts.css b/extensions/fablabchemnitz/boxes.py/boxes/static/fonts.css deleted file mode 100644 index 7747f4c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts.css +++ /dev/null @@ -1,41 +0,0 @@ -/*https://github.com/fontsource/fontsource/tree/main/fonts/google/bungee-shade#readme*/ -/*Font version (provided by source): v11.*/ -/* bungee-shade-vietnamese-400-normal*/ -@font-face { - font-family: 'Bungee Shade'; - font-style: normal; - font-display: swap; - font-weight: 400; - src: url('./fonts/bungeeshade/bungee-shade-vietnamese-400-normal.woff2') format('woff2'); - unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+1EA0-1EF9,U+20AB; -} -/* bungee-shade-latin-ext-400-normal*/ -@font-face { - font-family: 'Bungee Shade'; - font-style: normal; - font-display: swap; - font-weight: 400; - src: url('./fonts/bungeeshade/bungee-shade-latin-ext-400-normal.woff2') format('woff2'); - unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; -} -/* bungee-shade-latin-400-normal*/ -@font-face { - font-family: 'Bungee Shade'; - font-style: normal; - font-display: swap; - font-weight: 400; - src: url('./fonts/bungeeshade/bungee-shade-latin-400-normal.woff2') format('woff2'); - unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; -} - -/*https://github.com/fontsource/fontsource/tree/main/fonts/google/luckiest-guy*/ -/*Font version (provided by source): v18*/ -/* luckiest-guy-latin-400-normal*/ -@font-face { - font-family: 'Luckiest Guy'; - font-style: normal; - font-display: swap; - font-weight: 400; - src: url('./fonts/luckiestguy/luckiest-guy-latin-400-normal.woff2') format('woff2'); - unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; -} diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-latin-400-normal.woff2 b/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-latin-400-normal.woff2 deleted file mode 100644 index 72bd6c6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-latin-400-normal.woff2 and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-latin-ext-400-normal.woff2 b/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-latin-ext-400-normal.woff2 deleted file mode 100644 index 2583d29..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-latin-ext-400-normal.woff2 and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-vietnamese-400-normal.woff2 b/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-vietnamese-400-normal.woff2 deleted file mode 100644 index 5819b92..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/bungeeshade/bungee-shade-vietnamese-400-normal.woff2 and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/luckiestguy/luckiest-guy-latin-400-normal.woff2 b/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/luckiestguy/luckiest-guy-latin-400-normal.woff2 deleted file mode 100644 index a1c865f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/fonts/luckiestguy/luckiest-guy-latin-400-normal.woff2 and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/needs-image.png b/extensions/fablabchemnitz/boxes.py/boxes/static/needs-image.png deleted file mode 100644 index f1fdd27..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/needs-image.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/normalize.css b/extensions/fablabchemnitz/boxes.py/boxes/static/normalize.css deleted file mode 100644 index ad3b58c..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/static/normalize.css +++ /dev/null @@ -1,298 +0,0 @@ -/*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ - -/* -Document -======== -*/ - -/** -Use a better box model (opinionated). -*/ - -*, -::before, -::after { - box-sizing: border-box; -} - -/** -Use a more readable tab size (opinionated). -*/ - -html { - -moz-tab-size: 4; - tab-size: 4; -} - -/** -1. Correct the line height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -*/ - -html { - line-height: 1.15; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* -Sections -======== -*/ - -/** -Remove the margin in all browsers. -*/ - -body { - margin: 0; -} - -/** -Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) -*/ - -body { - font-family: - system-ui, - -apple-system, /* Firefox supports this but not yet `system-ui` */ - 'Segoe UI', - Roboto, - Helvetica, - Arial, - sans-serif, - 'Apple Color Emoji', - 'Segoe UI Emoji'; -} - -/* -Grouping content -================ -*/ - -/** -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -*/ - -hr { - height: 0; /* 1 */ - color: inherit; /* 2 */ -} - -/* -Text-level semantics -==================== -*/ - -/** -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr[title] { - text-decoration: underline dotted; -} - -/** -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/** -1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) -2. Correct the odd 'em' font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: - ui-monospace, - SFMono-Regular, - Consolas, - 'Liberation Mono', - Menlo, - monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/** -Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -Tabular data -============ -*/ - -/** -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -*/ - -table { - text-indent: 0; /* 1 */ - border-color: inherit; /* 2 */ -} - -/* -Forms -===== -*/ - -/** -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** -Remove the inheritance of text transform in Edge and Firefox. -1. Remove the inheritance of text transform in Firefox. -*/ - -button, -select { /* 1 */ - text-transform: none; -} - -/** -Correct the inability to style clickable types in iOS and Safari. -*/ - -button, -[type='button'], -[type='reset'], -[type='submit'] { - -webkit-appearance: button; -} - -/** -Remove the inner border and padding in Firefox. -*/ - -::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** -Restore the focus styles unset by the previous rule. -*/ - -:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** -Remove the additional ':invalid' styles in Firefox. -See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737 -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/** -Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. -*/ - -legend { - padding: 0; -} - -/** -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/** -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/** -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to 'inherit' in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* -Interactive -=========== -*/ - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/nothing.png b/extensions/fablabchemnitz/boxes.py/boxes/static/nothing.png deleted file mode 100644 index 56cd9eb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/nothing.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ABox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ABox-thumb.jpg deleted file mode 100644 index 0005508..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ABox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ABox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ABox.jpg deleted file mode 100644 index e530599..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ABox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AgricolaInsert-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AgricolaInsert-thumb.jpg deleted file mode 100644 index b2770e5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AgricolaInsert-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AgricolaInsert.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AgricolaInsert.jpg deleted file mode 100644 index ac33c7b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AgricolaInsert.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AirPurifier-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AirPurifier-thumb.jpg deleted file mode 100644 index db7ee71..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AirPurifier-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AirPurifier.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AirPurifier.jpg deleted file mode 100644 index 43558bb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AirPurifier.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AllEdges-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AllEdges-thumb.jpg deleted file mode 100644 index ecf8ef7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AllEdges-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AllEdges.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AllEdges.jpg deleted file mode 100644 index f298496..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AllEdges.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledBox-thumb.jpg deleted file mode 100644 index d91c49a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledBox.jpg deleted file mode 100644 index 2276773..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledCutJig-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledCutJig-thumb.jpg deleted file mode 100644 index ce8f171..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledCutJig-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledCutJig.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledCutJig.jpg deleted file mode 100644 index a9712f2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/AngledCutJig.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Arcade-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Arcade-thumb.jpg deleted file mode 100644 index f7deb9b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Arcade-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Arcade.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Arcade.jpg deleted file mode 100644 index 95373f7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Arcade.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Atreus21-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Atreus21-thumb.jpg deleted file mode 100644 index aec4159..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Atreus21-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Atreus21.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Atreus21.jpg deleted file mode 100644 index 42eefe9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Atreus21.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BasedBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BasedBox-thumb.jpg deleted file mode 100644 index 5e04f19..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BasedBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BasedBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BasedBox.jpg deleted file mode 100644 index 4aca630..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BasedBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BayonetBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BayonetBox-thumb.jpg deleted file mode 100644 index 8dcb20f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BayonetBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BayonetBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BayonetBox.jpg deleted file mode 100644 index 14cc40a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BayonetBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BinTray-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BinTray-thumb.jpg deleted file mode 100644 index 3e4e9f6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BinTray-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BinTray.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BinTray.jpg deleted file mode 100644 index 6a49e39..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BinTray.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BirdHouse-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BirdHouse-thumb.jpg deleted file mode 100644 index 3552aba..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BirdHouse-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BirdHouse.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BirdHouse.jpg deleted file mode 100644 index 280ad95..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BirdHouse.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BottleTag-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BottleTag-thumb.jpg deleted file mode 100644 index 9797a87..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BottleTag-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BottleTag.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BottleTag.jpg deleted file mode 100644 index 4810ab2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BottleTag.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BreadBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BreadBox-thumb.jpg deleted file mode 100644 index 09cd8f7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BreadBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BreadBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BreadBox.jpg deleted file mode 100644 index 3411507..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BreadBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BurnTest-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BurnTest-thumb.jpg deleted file mode 100644 index 54c25b2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BurnTest-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BurnTest.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BurnTest.jpg deleted file mode 100644 index ad1ded9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/BurnTest.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorage-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorage-thumb.jpg deleted file mode 100644 index 04ec4eb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorage-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorage.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorage.jpg deleted file mode 100644 index 3a2cd6b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorage.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorageAA-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorageAA-thumb.jpg deleted file mode 100644 index 49e9c6d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorageAA-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorageAA.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorageAA.jpg deleted file mode 100644 index 8969c12..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CanStorageAA.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-detail-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-detail-thumb.jpg deleted file mode 100644 index 5741850..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-detail-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-detail.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-detail.jpg deleted file mode 100644 index 1528d8e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-detail.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-thumb.jpg deleted file mode 100644 index b13a9d5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox.jpg deleted file mode 100644 index 6f96ca5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardHolder-thumb.jpg deleted file mode 100644 index c42388a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardHolder.jpg deleted file mode 100644 index d47cdd2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CardHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Castle-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Castle-thumb.jpg deleted file mode 100644 index db09017..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Castle-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Castle.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Castle.jpg deleted file mode 100644 index e176f7c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Castle.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ClosedBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ClosedBox-thumb.jpg deleted file mode 100644 index 91f2ca1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ClosedBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ClosedBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ClosedBox.jpg deleted file mode 100644 index 5891fe6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ClosedBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoffeeCapsuleHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoffeeCapsuleHolder-thumb.jpg deleted file mode 100644 index dc30882..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoffeeCapsuleHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoffeeCapsuleHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoffeeCapsuleHolder.jpg deleted file mode 100644 index c33dfdb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoffeeCapsuleHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-closed-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-closed-thumb.jpg deleted file mode 100644 index ff28c8f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-closed-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-closed.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-closed.jpg deleted file mode 100644 index 5239e1b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-closed.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-open-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-open-thumb.jpg deleted file mode 100644 index 83767fb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-open-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-open.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-open.jpg deleted file mode 100644 index e3b3357..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-open.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-pins-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-pins-thumb.jpg deleted file mode 100644 index 7d35814..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-pins-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-pins.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-pins.jpg deleted file mode 100644 index b336e55..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-pins.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-thumb.jpg deleted file mode 100644 index 4330eb7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe.jpg deleted file mode 100644 index 1ec97d1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinBankSafe.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinDisplay-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinDisplay-thumb.jpg deleted file mode 100644 index 27ddb85..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinDisplay-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinDisplay.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinDisplay.jpg deleted file mode 100644 index 8d36c14..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/CoinDisplay.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConcaveKnob-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConcaveKnob-thumb.jpg deleted file mode 100644 index f72ca0c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConcaveKnob-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConcaveKnob.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConcaveKnob.jpg deleted file mode 100644 index e0c0e34..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConcaveKnob.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console-thumb.jpg deleted file mode 100644 index d41fbb7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console.jpg deleted file mode 100644 index 1ccec4f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-backwall-detail-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-backwall-detail-thumb.jpg deleted file mode 100644 index 994c280..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-backwall-detail-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-backwall-detail.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-backwall-detail.jpg deleted file mode 100644 index 8f5387b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-backwall-detail.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-panel-detail-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-panel-detail-thumb.jpg deleted file mode 100644 index 9768daf..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-panel-detail-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-panel-detail.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-panel-detail.jpg deleted file mode 100644 index 70ce3e4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-panel-detail.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-thumb.jpg deleted file mode 100644 index d2dcfca..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2.jpg deleted file mode 100644 index 7822242..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Console2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickBack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickBack-thumb.jpg deleted file mode 100644 index d925638..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickBack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickBack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickBack.jpg deleted file mode 100644 index 2694235..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickBack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickFront-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickFront-thumb.jpg deleted file mode 100644 index 732354d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickFront-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickFront.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickFront.jpg deleted file mode 100644 index a97823b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickFront.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickInside-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickInside-thumb.jpg deleted file mode 100644 index 52082f7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickInside-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickInside.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickInside.jpg deleted file mode 100644 index bf3544d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ConsoleArcadeStickInside.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Desksign-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Desksign-thumb.jpg deleted file mode 100644 index fa569eb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Desksign-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Desksign.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Desksign.jpg deleted file mode 100644 index b2f1ab8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Desksign.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiceBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiceBox-thumb.jpg deleted file mode 100644 index 59a130f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiceBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiceBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiceBox.jpg deleted file mode 100644 index 27e6bce..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiceBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiscRack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiscRack-thumb.jpg deleted file mode 100644 index 4e283db..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiscRack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiscRack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiscRack.jpg deleted file mode 100644 index a8341eb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DiscRack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Dispenser-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Dispenser-thumb.jpg deleted file mode 100644 index eadae58..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Dispenser-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Dispenser.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Dispenser.jpg deleted file mode 100644 index 7a9c395..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Dispenser.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayCase-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayCase-thumb.jpg deleted file mode 100644 index 8666518..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayCase-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayCase.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayCase.jpg deleted file mode 100644 index c642c8f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayCase.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayShelf-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayShelf-thumb.jpg deleted file mode 100644 index aea03b4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayShelf-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayShelf.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayShelf.jpg deleted file mode 100644 index 89f1186..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DisplayShelf.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DividerTray-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DividerTray-thumb.jpg deleted file mode 100644 index 4e73af4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DividerTray-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DividerTray.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DividerTray.jpg deleted file mode 100644 index abbfe58..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DividerTray.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DoubleFlexDoorBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DoubleFlexDoorBox-thumb.jpg deleted file mode 100644 index da223c8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DoubleFlexDoorBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DoubleFlexDoorBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DoubleFlexDoorBox.jpg deleted file mode 100644 index 0dcb9a5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DoubleFlexDoorBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBox-thumb.jpg deleted file mode 100644 index 646e2c2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBox.jpg deleted file mode 100644 index 84274f4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBoxes-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBoxes-thumb.jpg deleted file mode 100644 index 372084d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBoxes-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBoxes.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBoxes.jpg deleted file mode 100644 index 480ac5c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillBoxes.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-1-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-1-thumb.jpg deleted file mode 100644 index 12c909e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-1-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-1.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-1.jpg deleted file mode 100644 index 57519f9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-1.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-2-thumb.jpg deleted file mode 100644 index cae3c57..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-2.jpg deleted file mode 100644 index b368e35..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-3-thumb.jpg deleted file mode 100644 index d11d271..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-3-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-3.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-3.jpg deleted file mode 100644 index 02d034b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-3.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-4-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-4-thumb.jpg deleted file mode 100644 index 5ff8f1f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-4-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-4.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-4.jpg deleted file mode 100644 index 2285c91..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-assembly-4.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-drawing.png b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-drawing.png deleted file mode 100644 index c368f8e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-drawing.png and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-thumb.jpg deleted file mode 100644 index efc8176..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand.jpg deleted file mode 100644 index ca3de11..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/DrillStand.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ElectronicsBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ElectronicsBox-thumb.jpg deleted file mode 100644 index b627122..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ElectronicsBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ElectronicsBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ElectronicsBox.jpg deleted file mode 100644 index 9d3005b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ElectronicsBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/EuroRackSkiff-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/EuroRackSkiff-thumb.jpg deleted file mode 100644 index 7e1c9f8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/EuroRackSkiff-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/EuroRackSkiff.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/EuroRackSkiff.jpg deleted file mode 100644 index ca1236a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/EuroRackSkiff.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FanHole-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FanHole-thumb.jpg deleted file mode 100644 index b25bb2a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FanHole-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FanHole.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FanHole.jpg deleted file mode 100644 index e039bab..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FanHole.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-2-thumb.jpg deleted file mode 100644 index 61b5efa..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-2.jpg deleted file mode 100644 index 8f81611..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-thumb.jpg deleted file mode 100644 index 2c3333d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool.jpg deleted file mode 100644 index 73933de..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FilamentSpool.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FillTest-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FillTest-thumb.jpg deleted file mode 100644 index 3bb0401..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FillTest-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FillTest.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FillTest.jpg deleted file mode 100644 index b9ab612..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FillTest.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-2-thumb.jpg deleted file mode 100644 index d8e2a2f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-2.jpg deleted file mode 100644 index 16d9724..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-thumb.jpg deleted file mode 100644 index a29939b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook.jpg deleted file mode 100644 index 4bdf260..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBook.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox-thumb.jpg deleted file mode 100644 index 9349fc7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox.jpg deleted file mode 100644 index c26271a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox2-thumb.jpg deleted file mode 100644 index 866a749..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox2.jpg deleted file mode 100644 index 44ce889..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox3-thumb.jpg deleted file mode 100644 index 71fd8d0..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox3-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox3.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox3.jpg deleted file mode 100644 index 97b28f6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox3.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox4-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox4-thumb.jpg deleted file mode 100644 index e455b64..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox4-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox4.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox4.jpg deleted file mode 100644 index 92b66c5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox4.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox5-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox5-thumb.jpg deleted file mode 100644 index 50af933..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox5-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox5.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox5.jpg deleted file mode 100644 index 4187829..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexBox5.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest-thumb.jpg deleted file mode 100644 index 543ccba..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest.jpg deleted file mode 100644 index 3bd1949..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest2-thumb.jpg deleted file mode 100644 index 475e8cd..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest2.jpg deleted file mode 100644 index b9039ce..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FlexTest2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-2-thumb.jpg deleted file mode 100644 index 7967b07..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-2.jpg deleted file mode 100644 index 3225ce6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-thumb.jpg deleted file mode 100644 index f23c221..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder.jpg deleted file mode 100644 index 9d678e6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Folder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FrontPanel-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FrontPanel-thumb.jpg deleted file mode 100644 index 54b362b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FrontPanel-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FrontPanel.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FrontPanel.jpg deleted file mode 100644 index 322b33c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/FrontPanel.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GearBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GearBox-thumb.jpg deleted file mode 100644 index 095b2cf..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GearBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GearBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GearBox.jpg deleted file mode 100644 index e96e469..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GearBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityBase-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityBase-thumb.jpg deleted file mode 100644 index 0b3eea3..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityBase-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityBase.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityBase.jpg deleted file mode 100644 index 032624e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityBase.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityTrayLayout-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityTrayLayout-thumb.jpg deleted file mode 100644 index d1cc411..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityTrayLayout-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityTrayLayout.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityTrayLayout.jpg deleted file mode 100644 index 132be5a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/GridfinityTrayLayout.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox-thumb.jpg deleted file mode 100644 index a74f7c2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox.jpg deleted file mode 100644 index 05183dd..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_AngleJig_usage-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_AngleJig_usage-thumb.jpg deleted file mode 100644 index f1c08a1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_AngleJig_usage-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_AngleJig_usage.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_AngleJig_usage.jpg deleted file mode 100644 index e4700da..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_AngleJig_usage.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Bookend_usage-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Bookend_usage-thumb.jpg deleted file mode 100644 index f5ab223..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Bookend_usage-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Bookend_usage.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Bookend_usage.jpg deleted file mode 100644 index a03ec4a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Bookend_usage.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Shelf_usage-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Shelf_usage-thumb.jpg deleted file mode 100644 index 44844a2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Shelf_usage-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Shelf_usage.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Shelf_usage.jpg deleted file mode 100644 index 4a5caad..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HalfBox_Shelf_usage.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HeartBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HeartBox-thumb.jpg deleted file mode 100644 index c5819e3..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HeartBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HeartBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HeartBox.jpg deleted file mode 100644 index 1740d10..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HeartBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HingeBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HingeBox-thumb.jpg deleted file mode 100644 index 0ea777b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HingeBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HingeBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HingeBox.jpg deleted file mode 100644 index 2468e47..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HingeBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HolePattern-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HolePattern-thumb.jpg deleted file mode 100644 index 3227ac3..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HolePattern-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HolePattern.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HolePattern.jpg deleted file mode 100644 index 17076fc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/HolePattern.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Hook-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Hook-thumb.jpg deleted file mode 100644 index 397aa51..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Hook-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Hook.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Hook.jpg deleted file mode 100644 index b224a26..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Hook.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/IntegratedHingeBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/IntegratedHingeBox-thumb.jpg deleted file mode 100644 index 2312f7c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/IntegratedHingeBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/IntegratedHingeBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/IntegratedHingeBox.jpg deleted file mode 100644 index c7785f1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/IntegratedHingeBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/JointPanel-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/JointPanel-thumb.jpg deleted file mode 100644 index 0fabee5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/JointPanel-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/JointPanel.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/JointPanel.jpg deleted file mode 100644 index e808e10..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/JointPanel.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-2-thumb.jpg deleted file mode 100644 index 40ddf17..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-2.jpg deleted file mode 100644 index 2544441..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-thumb.jpg deleted file mode 100644 index 9935708..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder.jpg deleted file mode 100644 index 007660e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/KeyHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Keypad-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Keypad-thumb.jpg deleted file mode 100644 index bf0596a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Keypad-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LBeam-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LBeam-thumb.jpg deleted file mode 100644 index 8fa6641..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LBeam-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LBeam.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LBeam.jpg deleted file mode 100644 index 7ada9db..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LBeam.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaptopStand-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaptopStand-thumb.jpg deleted file mode 100644 index df82dc1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaptopStand-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaptopStand.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaptopStand.jpg deleted file mode 100644 index 38544b8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaptopStand.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserClamp-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserClamp-thumb.jpg deleted file mode 100644 index ec9509a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserClamp-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserClamp.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserClamp.jpg deleted file mode 100644 index 760e2db..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserClamp.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserHoldfast-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserHoldfast-thumb.jpg deleted file mode 100644 index a7880d6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserHoldfast-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserHoldfast.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserHoldfast.jpg deleted file mode 100644 index a64b4fc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/LaserHoldfast.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MagazineFile-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MagazineFile-thumb.jpg deleted file mode 100644 index 89f644a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MagazineFile-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MagazineFile.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MagazineFile.jpg deleted file mode 100644 index ec7942c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MagazineFile.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MakitaPowerSupply-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MakitaPowerSupply-thumb.jpg deleted file mode 100644 index 41e518b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MakitaPowerSupply-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MakitaPowerSupply.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MakitaPowerSupply.jpg deleted file mode 100644 index fe3645c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/MakitaPowerSupply.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/March36539-box.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/March36539-box.jpg deleted file mode 100644 index 00ea4c9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/March36539-box.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NemaPattern-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NemaPattern-thumb.jpg deleted file mode 100644 index 7203d0a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NemaPattern-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NemaPattern.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NemaPattern.jpg deleted file mode 100644 index e9faa5d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NemaPattern.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NotesHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NotesHolder-thumb.jpg deleted file mode 100644 index cce37af..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NotesHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NotesHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NotesHolder.jpg deleted file mode 100644 index 27e30e6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/NotesHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OpenBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OpenBox-thumb.jpg deleted file mode 100644 index bc0c0ed..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OpenBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OpenBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OpenBox.jpg deleted file mode 100644 index 05c16b2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OpenBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoBody-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoBody-thumb.jpg deleted file mode 100644 index f04d1f1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoBody-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoBody.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoBody.jpg deleted file mode 100644 index 78f3adb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoBody.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoLegs-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoLegs-thumb.jpg deleted file mode 100644 index 227cdcc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoLegs-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoLegs.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoLegs.jpg deleted file mode 100644 index 615a24f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoLegs.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoSoles-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoSoles-thumb.jpg deleted file mode 100644 index ac6b621..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoSoles-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoSoles.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoSoles.jpg deleted file mode 100644 index 25d56b0..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/OttoSoles.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaintStorage-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaintStorage-thumb.jpg deleted file mode 100644 index 161d296..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaintStorage-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaintStorage.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaintStorage.jpg deleted file mode 100644 index 539dfe2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaintStorage.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaperBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaperBox-thumb.jpg deleted file mode 100644 index 1ba656f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaperBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaperBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaperBox.jpg deleted file mode 100644 index 362c27e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PaperBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PhoneHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PhoneHolder-thumb.jpg deleted file mode 100644 index 1f25718..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PhoneHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PhoneHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PhoneHolder.jpg deleted file mode 100644 index f5643fc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PhoneHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PirateChest-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PirateChest-thumb.jpg deleted file mode 100644 index 40248cb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PirateChest-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PirateChest.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PirateChest.jpg deleted file mode 100644 index fb0879b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PirateChest.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PizzaShovel-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PizzaShovel-thumb.jpg deleted file mode 100644 index 210f0a7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PizzaShovel-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PizzaShovel.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PizzaShovel.jpg deleted file mode 100644 index 053de42..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/PizzaShovel.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-Icosahedron-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-Icosahedron-thumb.jpg deleted file mode 100644 index 9a909b6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-Icosahedron-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-Icosahedron.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-Icosahedron.jpg deleted file mode 100644 index 20f7d0c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-Icosahedron.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-thumb.jpg deleted file mode 100644 index e036fc8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic.jpg deleted file mode 100644 index f6f548d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Platonic.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rack19Box-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rack19Box-thumb.jpg deleted file mode 100644 index 91e5d5f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rack19Box-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rack19Box.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rack19Box.jpg deleted file mode 100644 index 0f4c04e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rack19Box.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RackBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RackBox-thumb.jpg deleted file mode 100644 index 24d02f3..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RackBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RackBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RackBox.jpg deleted file mode 100644 index eed5505..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RackBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RectangularWall-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RectangularWall-thumb.jpg deleted file mode 100644 index 4d586cd..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RectangularWall-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RectangularWall.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RectangularWall.jpg deleted file mode 100644 index 8d023cb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RectangularWall.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularBox-thumb.jpg deleted file mode 100644 index 021208a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularBox.jpg deleted file mode 100644 index bacf78b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-2-thumb.jpg deleted file mode 100644 index 1187fcc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-2.jpg deleted file mode 100644 index 2d3295c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-thumb.jpg deleted file mode 100644 index c26fb63..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox.jpg deleted file mode 100644 index e158bb2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RegularStarBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RobotArm-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RobotArm-thumb.jpg deleted file mode 100644 index dfa5568..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RobotArm-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RobotArm.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RobotArm.jpg deleted file mode 100644 index 63b572a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RobotArm.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RollHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RollHolder-thumb.jpg deleted file mode 100644 index ea134d6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RollHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RollHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RollHolder.jpg deleted file mode 100644 index e51e6bc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RollHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rotary-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rotary-thumb.jpg deleted file mode 100644 index e828292..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rotary-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rotary.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rotary.jpg deleted file mode 100644 index 2a100b6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Rotary.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-2-thumb.jpg deleted file mode 100644 index c8bf295..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-2.jpg deleted file mode 100644 index 7db7149..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-3-thumb.jpg deleted file mode 100644 index 3e9a1b8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-3-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-3.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-3.jpg deleted file mode 100644 index 478e464..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-3.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-thumb.jpg deleted file mode 100644 index b7a9827..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox.jpg deleted file mode 100644 index 42a3234..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoundedBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-2-thumb.jpg deleted file mode 100644 index 6c1c63b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-2.jpg deleted file mode 100644 index 1813ee4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-3-thumb.jpg deleted file mode 100644 index d8bae16..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-3-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-3.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-3.jpg deleted file mode 100644 index cb55090..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-3.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-thumb.jpg deleted file mode 100644 index 9468614..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame.jpg deleted file mode 100644 index 36161f4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/RoyalGame.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SBCMicroRack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SBCMicroRack-thumb.jpg deleted file mode 100644 index 05fbd8e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SBCMicroRack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SBCMicroRack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SBCMicroRack.jpg deleted file mode 100644 index 97d8e4b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SBCMicroRack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SevenSegmentPattern-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SevenSegmentPattern-thumb.jpg deleted file mode 100644 index c51ff35..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SevenSegmentPattern-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SevenSegmentPattern.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SevenSegmentPattern.jpg deleted file mode 100644 index 2115ace..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SevenSegmentPattern.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-backlit-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-backlit-thumb.jpg deleted file mode 100644 index 3ac0558..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-backlit-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-backlit.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-backlit.jpg deleted file mode 100644 index d8805d8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-backlit.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-diagram-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-diagram-thumb.jpg deleted file mode 100644 index a7f5d55..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-diagram-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-diagram.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-diagram.jpg deleted file mode 100644 index f7d22d0..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-diagram.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-thumb.jpg deleted file mode 100644 index ffd2794..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox.jpg deleted file mode 100644 index 1a7e705..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shadowbox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shoe-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shoe-thumb.jpg deleted file mode 100644 index 06d2aca..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shoe-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shoe.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shoe.jpg deleted file mode 100644 index 9bb6cbf..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Shoe.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-2-thumb.jpg deleted file mode 100644 index ff34e89..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-2.jpg deleted file mode 100644 index 3440099..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-3-thumb.jpg deleted file mode 100644 index 6e541ba..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-3-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-3.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-3.jpg deleted file mode 100644 index 9f473b9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-3.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-thumb.jpg deleted file mode 100644 index ee36dbe..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox.jpg deleted file mode 100644 index 78d517e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/ShutterBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-2-thumb.jpg deleted file mode 100644 index ef4d2a9..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-2.jpg deleted file mode 100644 index f1d6efa..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-thumb.jpg deleted file mode 100644 index f9998ec..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing.jpg deleted file mode 100644 index c97e2fb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SideDoorHousing.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Silverware-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Silverware-thumb.jpg deleted file mode 100644 index b670bca..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Silverware-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Silverware.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Silverware.jpg deleted file mode 100644 index 823bf41..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Silverware.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SkadisBoard-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SkadisBoard-thumb.jpg deleted file mode 100644 index a6ebc1d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SkadisBoard-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SkadisBoard.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SkadisBoard.jpg deleted file mode 100644 index 9d16302..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SkadisBoard.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-2-thumb.jpg deleted file mode 100644 index 0e56869..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-2.jpg deleted file mode 100644 index 176c042..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-thumb.jpg deleted file mode 100644 index c81d501..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray.jpg deleted file mode 100644 index e4c6d03..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlantedTray.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlidingDrawer-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlidingDrawer-thumb.jpg deleted file mode 100644 index 39beb03..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlidingDrawer-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlidingDrawer.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlidingDrawer.jpg deleted file mode 100644 index ac06d03..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SlidingDrawer.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray-thumb.jpg deleted file mode 100644 index fd7fbd7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray.jpg deleted file mode 100644 index c5d3263..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray2-thumb.jpg deleted file mode 100644 index 15ded3a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray2.jpg deleted file mode 100644 index f7bd952..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SmallPartsTray2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SpicesRack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SpicesRack-thumb.jpg deleted file mode 100644 index c57d0b6..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SpicesRack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SpicesRack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SpicesRack.jpg deleted file mode 100644 index cf22f9d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/SpicesRack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Spool-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Spool-thumb.jpg deleted file mode 100644 index 3af542e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Spool-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Spool.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Spool.jpg deleted file mode 100644 index 6dd249e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Spool.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Stachel-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Stachel-thumb.jpg deleted file mode 100644 index 3726f33..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Stachel-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Stachel.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Stachel.jpg deleted file mode 100644 index 756cf79..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Stachel.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-2-thumb.jpg deleted file mode 100644 index e07a25a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-2.jpg deleted file mode 100644 index 6f9ece5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-3-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-3-thumb.jpg deleted file mode 100644 index dc8be16..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-3-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-3.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-3.jpg deleted file mode 100644 index 81831a0..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-3.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-thumb.jpg deleted file mode 100644 index 10aa1d1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack.jpg deleted file mode 100644 index 21d18d7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageRack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageShelf-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageShelf-thumb.jpg deleted file mode 100644 index 6f3d879..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageShelf-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageShelf.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageShelf.jpg deleted file mode 100644 index 5d1a6b0..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/StorageShelf.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Tetris-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Tetris-thumb.jpg deleted file mode 100644 index 2adfe7a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Tetris-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Tetris.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Tetris.jpg deleted file mode 100644 index 60f03b7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/Tetris.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrafficLight-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrafficLight-thumb.jpg deleted file mode 100644 index db4f2b0..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrafficLight-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrafficLight.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrafficLight.jpg deleted file mode 100644 index a508ede..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrafficLight.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-2-thumb.jpg deleted file mode 100644 index 1a4098a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-2.jpg deleted file mode 100644 index ec659ce..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-thumb.jpg deleted file mode 100644 index 022d263..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert.jpg deleted file mode 100644 index 4c7c096..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayInsert.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout-thumb.jpg deleted file mode 100644 index c9d7d7b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout.jpg deleted file mode 100644 index 5b996ae..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout2-thumb.jpg deleted file mode 100644 index c9d7d7b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout2.jpg deleted file mode 100644 index 5b996ae..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TrayLayout2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece-thumb.jpg deleted file mode 100644 index b7bf2eb..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece.jpg deleted file mode 100644 index 265cf29..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece2-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece2-thumb.jpg deleted file mode 100644 index 0b25d2b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece2-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece2.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece2.jpg deleted file mode 100644 index 0d506ec..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TwoPiece2.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TypeTray-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TypeTray-thumb.jpg deleted file mode 100644 index 4178486..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TypeTray-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TypeTray.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TypeTray.jpg deleted file mode 100644 index b4adbdc..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/TypeTray.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UBox-thumb.jpg deleted file mode 100644 index aad9aa4..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UBox.jpg deleted file mode 100644 index 591664c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UnevenHeightBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UnevenHeightBox-thumb.jpg deleted file mode 100644 index 17bf7f8..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UnevenHeightBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UnevenHeightBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UnevenHeightBox.jpg deleted file mode 100644 index 11e055e..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UnevenHeightBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UniversalBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UniversalBox-thumb.jpg deleted file mode 100644 index 4178ace..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UniversalBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UniversalBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UniversalBox.jpg deleted file mode 100644 index 4a90814..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/UniversalBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallCaliper-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallCaliper-thumb.jpg deleted file mode 100644 index a948013..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallCaliper-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallCaliper.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallCaliper.jpg deleted file mode 100644 index 304eed2..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallCaliper.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallChiselHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallChiselHolder-thumb.jpg deleted file mode 100644 index 5806953..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallChiselHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallChiselHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallChiselHolder.jpg deleted file mode 100644 index ffdda10..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallChiselHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallConsole-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallConsole-thumb.jpg deleted file mode 100644 index d7d819b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallConsole-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallConsole.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallConsole.jpg deleted file mode 100644 index a7f5e46..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallConsole.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallDrillBox-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallDrillBox-thumb.jpg deleted file mode 100644 index 52e874d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallDrillBox-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallDrillBox.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallDrillBox.jpg deleted file mode 100644 index 7784fc7..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallDrillBox.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPinRow-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPinRow-thumb.jpg deleted file mode 100644 index e3c239a..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPinRow-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPinRow.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPinRow.jpg deleted file mode 100644 index d4dc114..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPinRow.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPlaneHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPlaneHolder-thumb.jpg deleted file mode 100644 index ff7e455..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPlaneHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPlaneHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPlaneHolder.jpg deleted file mode 100644 index a43d61f..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPlaneHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPliersHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPliersHolder-thumb.jpg deleted file mode 100644 index b1e7197..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPliersHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPliersHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPliersHolder.jpg deleted file mode 100644 index bd32ba1..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallPliersHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRack-thumb.jpg deleted file mode 100644 index 3be0760..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRack.jpg deleted file mode 100644 index 2d97e83..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRollHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRollHolder-thumb.jpg deleted file mode 100644 index b80397d..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRollHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRollHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRollHolder.jpg deleted file mode 100644 index 72ae60c..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallRollHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallSlottedHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallSlottedHolder-thumb.jpg deleted file mode 100644 index c023cbd..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallSlottedHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallSlottedHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallSlottedHolder.jpg deleted file mode 100644 index 440f076..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallSlottedHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallStairs-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallStairs-thumb.jpg deleted file mode 100644 index 62a1144..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallStairs-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallStairs.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallStairs.jpg deleted file mode 100644 index 58b5b27..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallStairs.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallTypeTray-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallTypeTray-thumb.jpg deleted file mode 100644 index 2e98efe..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallTypeTray-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallTypeTray.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallTypeTray.jpg deleted file mode 100644 index 288fc51..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallTypeTray.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallWrenchHolder-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallWrenchHolder-thumb.jpg deleted file mode 100644 index 3768f86..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallWrenchHolder-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallWrenchHolder.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallWrenchHolder.jpg deleted file mode 100644 index c93fe5b..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WallWrenchHolder.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WineRack-thumb.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WineRack-thumb.jpg deleted file mode 100644 index 1d30c75..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WineRack-thumb.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WineRack.jpg b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WineRack.jpg deleted file mode 100644 index d56c9a5..0000000 Binary files a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/WineRack.jpg and /dev/null differ diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/samples.sha256 b/extensions/fablabchemnitz/boxes.py/boxes/static/samples/samples.sha256 deleted file mode 100644 index 4e5c4f4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/static/samples/samples.sha256 +++ /dev/null @@ -1,167 +0,0 @@ -99b28ad0d4e5f7dcfe01e44be6aaa6accef896675e689a2d66babbe09e71057d ../static/samples/Folder-2.jpg -45e778299b32dd2c2bc84e61568b9876071e61aafae6913adae3f872b3e8c46d ../static/samples/DisplayShelf.jpg -9f0801935dc69a93d39e2c5fb79c8f3a05bb34318b9206669e9ce18389511129 ../static/samples/FlexBox2.jpg -e21f917775a9a1d08964c46c67eac7ac994122d674d1be437ee42aecfb608efa ../static/samples/IntegratedHingeBox.jpg -771a05e44b3d1dcd01edac3f8a438122e3bf331d4122ee5c5a2a0a60af67a8ef ../static/samples/TwoPiece.jpg -093cb28c608a71cd285bc316e196f7eec58f7f7235ed15338450d8cb4589e1c1 ../static/samples/DividerTray.jpg -7d21349780dc53e632ea5edfd98dd2eab181ad985454e70726a4b58673af2555 ../static/samples/TrayInsert-2.jpg -8700581788e743778996ee769123a64a91ccebf066d3df90b4a03751c79dc2d9 ../static/samples/Stachel.jpg -7467e1d2625d1cc75322e86edb20b4361d61556f908f2a8e5886212ca281fbe6 ../static/samples/TrayLayout.jpg -828edca9c85df8e6762c7093655a8cb324d4f0174be56a8fb19aba462031ebdd ../static/samples/OpenBox.jpg -f60561e58fbe66509c0f839dc02043192862b2f886a23178bdef9102050ee6fa ../static/samples/Folder.jpg -b93f528b3c1252c996858c1b0ec6482e177ed767c8d47646b17629fb8b115ce7 ../static/samples/UBox.jpg -c07ecba64de889a551e1634bd9d30494d225c1167ac877672282326e68543d8d ../static/samples/UniversalBox.jpg -293085a6678d31431ecd8331fd3fbe1897611fd94065c20ac6dfd635d4b70522 ../static/samples/OttoBody.jpg -aec34803225353bf9503e7dec3e0459de4191e337d5272db0042c6f636b30c9f ../static/samples/RobotArm.jpg -18826f349517bdea85c8ce2bd8a8df83ee41ebee84eef6b331daf8f31736e25a ../static/samples/UnevenHeightBox.jpg -55bdf7b75fa5f710c0c09763bd5ea5792eae57033ca5bc59d70d74576b40b6ba ../static/samples/CardBox.jpg -22cef7f029a96c493ea96304e8fac6fa628e44a1c896a3fbb9a6b8a1bba9635a ../static/samples/ShutterBox.jpg -af2d69de8f8633d162172e996f05efc53d8b3db9bbe72d47ad74afe12245d699 ../static/samples/AngledBox.jpg -fcd293dcc1849c9d7771aefab0c26fcdeda27119d0bd2a8d266b8fd97a8b1389 ../static/samples/ClosedBox.jpg -0315b1a59e60a21b5152c2d5ea2e03652465e082fde468617b528951a5ca1181 ../static/samples/DiscRack.jpg -fda934c68150c212f9fb65463609802209aa4c6005d0050ca882bf34e26e51b7 ../static/samples/RoundedBox.jpg -05c06103351345c2d38404d6c96eaa8feb77f61e5c6c088fcadb4400ad446051 ../static/samples/TrafficLight.jpg -24a6ce75121e765b79f069944b52baaaa1942a7dfdfa6e5bb9b23664dd6a6d24 ../static/samples/FlexBox3.jpg -9428ddd1ba93b34b8dbcfa0b570421684cfa159fff63ff6e382d2a91f70ba366 ../static/samples/TrayInsert.jpg -0dfb345bc6f37d130503ee5a08f3f7230d536c855a12e5ba94e255104b67090a ../static/samples/FlexBox4.jpg -312e7c5732ab18b717a434d8c97067bcd6402f8cec75a81e33082176b979d53e ../static/samples/FlexBox.jpg -c73566a05dcf23565073d48efac6a91f9c2c0f8ae3b062818ac3f3d47a311572 ../static/samples/DisplayCase.jpg -54ea279afec60e79467147040e9eb0caf31628218aa46483eb9fdf3d2391ec0e ../static/samples/HingeBox.jpg -52633330c9e363e2c087f893a3d7b3259f016440bf1576f849b2ced8e3f33498 ../static/samples/StorageShelf.jpg -41f0faab616167c40a344f787e0bd20fa408f9a168831e4f32227e13dfa00da3 ../static/samples/RegularBox.jpg -0479b9373b06b63a8f765189787609a9b8acb63683f0472007ad8926cf6d2a9c ../static/samples/TypeTray.jpg -9b62db63fad5b5dfd1aac5f24fa2799c0dc2bedd37c0aa700c225a5a022f928e ../static/samples/March36539-box.jpg -d95d24d4637fb132b68be9e761ec117d411279bbd11278a72041d08d8b13c838 ../static/samples/BinTray.jpg -ece3d9a431098d2fca7a40804cfc7f47539639b04b26e42878addfb967219f2f ../static/samples/LaserHoldfast.jpg -d0fd3cad7a96dc88c94cd81f1a545e8af2bea1ab43f0c0644fbea63d45a710ea ../static/samples/NotesHolder.jpg -2fc9504d852f7eeabcb1bc1459a34109b0b3d805c49ea2982e038509455e3a5e ../static/samples/PaintStorage.jpg -c3f110f1bb2192afe15d893ca3020e74c3dc56e9e8b4aeef59ae86c3a49e7721 ../static/samples/ElectronicsBox.jpg -2efcc61f6c8651f15152e49eea013c8f947cc4f85ecca75e64673174cab77916 ../static/samples/WineRack.jpg -f90c6b745eb586c8086e053a07ba05bd8dffb5e131c928b0bd9c66e7b890f4a8 ../static/samples/SBCMicroRack.jpg -c494a70c6846bfd972fdf7889ddfe255a92bf3c49efaad4e58fe4a71410bf14d ../static/samples/SpicesRack.jpg -9b60cc2f60803777040e9fe0822c09534011c82bc83c0b3d98cf8a15f2383cf1 ../static/samples/EuroRackSkiff.jpg -668abdfdcd2d52a5d7c386b3169ec08cb35c39739e6dcc9e527054b86c4a5b3d ../static/samples/Console2.jpg -76a237c9f681214af47839656d81998cb71e4ad0790e6d0c7d5a92d9b0fb7b5a ../static/samples/Console2-panel-detail.jpg -fa30d73340ba5be23443475f2f689b8f62ec378f1a6ee12685c208f4a9ca4932 ../static/samples/Console2-backwall-detail.jpg -7d93f6cd5bce2b0f4c110711c21b9a08fb39c7ad223eca97357c9cfb1167fe62 ../static/samples/Atreus21.jpg -5971e72af92a6d259266d1d3f5df4d0165f49bf35a1e2a46438afdaf24ddc2db ../static/samples/CardBox-detail.jpg -1a84dc40eedeb509f2edaf2d50636346d46010d83f7736fb040d1096a99319f0 ../static/samples/Console.jpg -c639d0bc530aaa917d32647917231ba232696f1e13aff27b5cf4f244974e3367 ../static/samples/HeartBox.jpg -b14f225b7c9050942e412bff8964ae1b1f91413932f6e59a98fcb874680ae26a ../static/samples/Rotary.jpg -0abb91506e88de68ee32dcc0735f42a7f2498b08a4e98d606774b0d066083e0a ../static/samples/AgricolaInsert.jpg -8a2ec80f6bb23210231fb1b781a6c1c9edc2f50f8c5d8b932373d61bc5aa16e4 ../static/samples/FlexTest.jpg -174c9c27a9a855d33fd3641337c3de1b0ac3a3b91c11e1063b68089db4cfda7d ../static/samples/LBeam.jpg -e8548fdfd34ca9bbc89be5d263c8c9bf758cfe3dfee5ff5206c3ec55c5c5213d ../static/samples/BasedBox.jpg -fc0e56cf56670bc26719f0eb362ddbda1ffae0b461405e79b518e8e91aa54feb ../static/samples/BayonetBox.jpg -f67ff6007c69677983f087a5a3f7cdcd242d4d27e8fd7ba5f0f0c82f768ca3f4 ../static/samples/MakitaPowerSupply.jpg -475c7739e0ad6ac9abf1ca343fc7ab1fc12b1dac96b3a4cf47a3810917deb5d0 ../static/samples/Castle.jpg -24554b559f4398c22023bcfe7e5dd70158c4fa99fff01615d28752b1b11fa837 ../static/samples/StorageRack-2.jpg -71ce6b80b8d0e80b954b32b4b1b7af8a86d3f6d10414fd1424490ce4a7bdf0cd ../static/samples/StorageRack.jpg -a29143694a0ae80ec8280bd4281bebbf09fdca83ed0e5aea3b77653eae7463e0 ../static/samples/StorageRack-3.jpg -6efa7cc54e03d25555851655dcc768eeb8650fc9114fd0ad7ea4e638084da496 ../static/samples/PaperBox.jpg -7467e1d2625d1cc75322e86edb20b4361d61556f908f2a8e5886212ca281fbe6 ../static/samples/TrayLayout2.jpg -6805a93915d15cb5016ff91b20d47b1a1631ac77a447496acab36b221e52ac98 ../static/samples/PhoneHolder.jpg -77dc3330fb90fd20ee7882dac32de60886f7d86aab8b3b7fbee945c0f4a4a2f0 ../static/samples/BurnTest.jpg -598ad23a026edbca0e946fb89fa47af5f9bd6407b3a8c681ef86c5fa002d5dfd ../static/samples/CoffeeCapsuleHolder.jpg -4429c0d8faaa01f97c6fd059dfd1adbd0abd05bc6aca65af3d7196f9e7edd8db ../static/samples/Platonic.jpg -e61e5917b5f96d5fdea5d902dcd570153faa6ae5caa2b4725cc748fab3011386 ../static/samples/DoubleFlexDoorBox.jpg -fea1ad6057f3d53cc30afc816c42ad2904a4a1952ff0155718b8683bd6242b38 ../static/samples/AngledCutJig.jpg -68ae5070810636f4bbaec62bcd4be42d3d11196774214a27ce9d93b3fb381033 ../static/samples/RoyalGame-2.jpg -1779f0e2016efb5194dbaad01117b53815a43a87eeff30b08224416214c1cde2 ../static/samples/RoyalGame.jpg -db4062278f568963a215396bc807615540f1956aa20f70290aaa3acef1909b2d ../static/samples/RoyalGame-3.jpg -fd518cca166474e563773b7dff044fd38faf4717cfa8313d150777e05560e538 ../static/samples/RoundedBox-2.jpg -313d8ed138f3c853fb37ab38a555d721ff43499dd9ad25c9e73bdff3bc876ee4 ../static/samples/RoundedBox-3.jpg -6aeb08f0e657e47e056aae65a2f6d878d991400da754b41b2ad2214b9be3835e ../static/samples/ShutterBox-3.jpg -710e697a2324c2245bf802bde512e9fec75cc1f4f36e3ba73fb5d9a78cdfddec ../static/samples/ShutterBox-2.jpg -a7bc259742b5a0ca9b611ec635f7aacf4a6259f3667c396d5d9c9ee88dfe86ff ../static/samples/LaserClamp.jpg -5bc17e845c7ec9f34cb5d5ec350304eafa2154e2fd6e30d6da5bdb491bd6c0e2 ../static/samples/DrillStand-assembly-2.jpg -5f4a7bf592c2bc5151a9143d77574d9f291b389657fe1eeff9babe3874cc3125 ../static/samples/DrillStand.jpg -252c184f000cc8be310072297faa6aacb2f213d557116f19f0fe70b909a280d3 ../static/samples/DrillStand-assembly-4.jpg -c5863a8e2e11ab3fbea972cc3b9897385954b1ecff957d8905a0bd86ff5b2749 ../static/samples/DrillStand-assembly-1.jpg -91656f22588648ac8af6a02da6f3809d39e39c548b98d5b635caad2108dd7319 ../static/samples/BottleTag.jpg -8e4629ccff0c0f056b73a967317d68a4a6c8ac66edaa4730b5437a41964d72c4 ../static/samples/DrillStand-assembly-3.jpg -4e0764884f1660c29b62934b964a25e1a387d1906cddad2534e9bd384073e8a1 ../static/samples/TwoPiece2.jpg -5ab5efe962e21a4aae7453a96bf44f7fef860a11b4ae85b91071c956a163cd76 ../static/samples/Silverware.jpg -a3b88caa90c99082e1395b654c8a25c887e4ecff64dbf1115a93c55edd7ea4ac ../static/samples/AllEdges.jpg -2abba522e9a314bae8b25566abedbfa0c09760e50f1707a77765f1e17aabe459 ../static/samples/JointPanel.jpg -487ab7b840a3dfc77e6d3705942e9b6498c8992500d5c5cdd93d2a9d82a3de6f ../static/samples/WallCaliper.jpg -4bbf12c696a75b0642ec85400a3e1d5ad5312b40f608d260db5a3720890f7baa ../static/samples/WallDrillBox.jpg -3ae3855a2994d1f4f0dde19d695b68e9ba5603b7e0a1520938b42d94856d45e1 ../static/samples/WallTypeTray.jpg -561d17eb8493d7b32feb56de3507421f23c05edb876bbc5c1aa85b66a3100e9f ../static/samples/WallSlottedHolder.jpg -ead589b977eb6114b4b310a4a05bd421c257b5f69fc17169045e64d9017858c8 ../static/samples/WallPliersHolder.jpg -213391abadb1c842bb6990a10dcad1be9b4a73985d22586e8a5f5c832e70148b ../static/samples/Platonic-Icosahedron.jpg -88624b975503d962841df0e5a7199910b2b04c8ad01e1d8e389deb7f114d30ce ../static/samples/SlidingDrawer.jpg -30587818f77dde452925cf52d9e09f5777f937ba2aac10fe80831f1083e7503b ../static/samples/RegularStarBox.jpg -b75547e1126c799c37be4a6b256947e0cdad1d4b3a2146134142773b462e099a ../static/samples/RegularStarBox-2.jpg -a95305025a8136290e95f8232463bb1c6023a1d98d502e7a249d52c60aafdd94 ../static/samples/CardHolder.jpg -34058c3a37bc70dc72e467d2da1ece7cde2aacedf7b751243a7c264c9998afb2 ../static/samples/DiceBox.jpg -e90b4a90c1dbd2a4a03e4cf50ba82bc7119b721bd5c90c5fdbd0a356c9eabfd3 ../static/samples/CanStorageAA.jpg -0580043276c800c68dfba840d47c27f974ef2d0629751ecd250df2400f03cca8 ../static/samples/CanStorage.jpg -bb250512410c007a74f91caee4e25eac817021f5a535987a7f5ff46148a074ca ../static/samples/MagazineFile.jpg -59c29899a7f6cfa1727830b35ba621747bf1fe16b8559884054bf50235559a11 ../static/samples/CoinDisplay.jpg -c21b47963a9de686eec4bcdb04dc84a64fef1e943d9c276f6ecb7d619af22791 ../static/samples/HalfBox_Shelf_usage.jpg -3bdbb6dab2beea4dcdcf84941bf1f763bc9eb60ca9369965c4b003d5bb57f83b ../static/samples/HalfBox_AngleJig_usage.jpg -9a0c0bf1d3b74a1e09f278ad9f89d8b7e59261a870bb60ed547d45117594cf93 ../static/samples/HalfBox.jpg -e1e5001ad1c59e0815a684f2eb2d25bb88113423ec6b582fb81f835c25947127 ../static/samples/HalfBox_Bookend_usage.jpg -2300383efee9aebb910fb8967edcee9689e1143031c5bca4d7d9a2c4109bd7f9 ../static/samples/GridfinityBase.jpg -6a8a5789897d4836ca1d0eab54b66e77efde181cdf375374253be8a3eb85a183 ../static/samples/BreadBox.jpg -2b53f202726de27f65cb36bd3b8e7fc0f54af4e8021257a2084771613c604401 ../static/samples/SlantedTray-2.jpg -5a7ff061d7e3d6b4ec587926f81b594bd12c0a2516ac939260564164d7d01db2 ../static/samples/SlantedTray.jpg -b4b0aeecfd34eedb1a1e0b9763e219b77f4d0cea0ae39c5197e22dbae5d4f0d4 ../static/samples/SmallPartsTray.jpg -f342316e00a07329aec8a9377274db4709870511126a3cada10ae9057f3f5367 ../static/samples/BirdHouse.jpg -7046e8171d15e3a01685ab0763fa8b4cbdecf98956c02203343579cab39b9c6f ../static/samples/SmallPartsTray2.jpg -bb294909eb5e7a1a49cc7d5ba72b08ca0baf42dd2302494aa1932432817ce973 ../static/samples/RollHolder.jpg -a7ee83b42685295fd02db666841984c55af2f9632540c651f5dea42088a3c170 ../static/samples/FilamentSpool.jpg -0524ca976f76c181135044b185eb4e6cf2ce92ab3316f48a6bc61b9366daefd1 ../static/samples/FilamentSpool-2.jpg -ab47e02fb9736d20b457964aa640f50852ac97bb2857cea753fa4c3067a60d41 ../static/samples/Spool.jpg -cfc0782f3a952dd0c6ceb0fb7998050f3bdea135d791fa32b731808371514e63 ../static/samples/GearBox.jpg -75733dfdfd601ace1521bddfea28546ca34d8281acbeb6ec44f15b2b942cb944 ../static/samples/Arcade.jpg -a21471512fd73c15e1d8a11aa3bd4ef807791895855c2f1d30a00bd207d79919 ../static/samples/FrontPanel.jpg -5640a59072afac58b4bb8410967cb8434a455ac3570118d2163887c17099e064 ../static/samples/WallChiselHolder.jpg -cfec3b4f915befc29efc3913c131204948e63a444fd41370989173b0243617d7 ../static/samples/WallPlaneHolder.jpg -6a5222b9d886454f6c4fda8ead777f2136f8c1d0231e145a30ea853430ee7baa ../static/samples/WallRollHolder.jpg -cedf3c9ce40a379c4ca52089d0cda51cdf4c3899df1368c6374ed45afcb8cef8 ../static/samples/WallWrenchHolder.jpg -5b123ea245e7670cd0a55cea8348aa1f2628080f5ec005902cdd86bab231aad1 ../static/samples/WallConsole.jpg -d7b9c4a9ea70c2cc7ede5e992862fa4c001cff0f592a689ed4d5fab5ac339249 ../static/samples/GridfinityTrayLayout.jpg -885a89ccdf04ddcbd31e8ccd8c7157129443b9b6a3e2b720085c0f11c406a748 ../static/samples/ABox.jpg -f340b90d92d445a626d5e162bc1081fdeda9ba11d563c7f7c4632996379f34da ../static/samples/ConsoleArcadeStickBack.jpg -005751de891a4faa50cf65bcad6781cc5499329a5596a7fa93cee901c7e89537 ../static/samples/ConsoleArcadeStickFront.jpg -4f0b46c88c1c425dcec6b9a0bff754f6b5580f82aa7004233dec03f8f4c5ce41 ../static/samples/ConsoleArcadeStickInside.jpg -2432b6095e513cecaf5e96552dd4136615a0470e36d8804668cbb5b73684249e ../static/samples/DrillBox.jpg -4e055c330eb95303fcce029f6efb1089e9a5b61cf0eef25c95267a8c90d1c2c4 ../static/samples/RackBox.jpg -71f7fb03035c12037beb4bc6c9acdd5fb75ee044d20b4e4be910aae8085ca592 ../static/samples/ConcaveKnob.jpg -4508f68ec6c233b116b6268322996ed50146df34318ffffe4062041fd289fbf6 ../static/samples/DrillBoxes.jpg -70644df6aa7191ae32a66039d3231fc9b84f4f49210571632d2a2f010e728a9b ../static/samples/LaptopStand.jpg -72ea1d0144f27354febffcef5d55ee0897ea6082d05cef78f3dd786b9e943243 ../static/samples/Dispenser.jpg -622576918df92b533f6a689525dbbce3822ad59f58378a2fd1a117a650d30c0e ../static/samples/OttoLegs.jpg -eedccf62c193224e2b86e52be8cd02faddf97d565330e2d5770390141da35069 ../static/samples/OttoSoles.jpg -e9ee43e336401d3a0cb8e141c3a0b87a84e90f99eed30bdd420dcaead92940e1 ../static/samples/NemaPattern.jpg -3070eb2ed89461497d4dcc67021a0619338ab6d4d4d89d3cd1f83160da3c7920 ../static/samples/FanHole.jpg -c8adb0661956430ccec7fc00aa4b8e3c42d02083e17a9307541bc0160251cb96 ../static/samples/HolePattern.jpg -7c399c1cd235c3c044f676a31aa5215109e815055f2f69aef5d0cb1a24dfae41 ../static/samples/Desksign.jpg -fda14ba0920ef7ea0579117a30b5bb4a05ab3be4da3d87a4fc03fc40b085992b ../static/samples/PirateChest.jpg -125033a02263e74d5688287936f54cd83e917276b7c35f3fd37e6cb86efc0dcc ../static/samples/Shoe.jpg -7bf29dc9e2f0b5a0bbedc8b7b6814fe4cec58e9dcebfcd1167757a2bbcc91c17 ../static/samples/Hook.jpg -16013717335b8561b5d78bd586dceee5bac6a35e9e6f0bb9c3b36dc6ea5218bd ../static/samples/PizzaShovel.jpg -b860c4e6a0016c1fb4742d4a70a8201af88a18e36ae0c4d601549a640471fe11 ../static/samples/KeyHolder.jpg -d63379683d34c42994610bf1d0c3fb5daa2c790431a7c2dd94c76302163979b6 ../static/samples/KeyHolder-2.jpg -60f7f3ac2b046107cb573607706f688380c4f9322fe612e1972627f3b01f507a ../static/samples/AirPurifier.jpg -cdd8658c4bd66de5e00c5a961583986a47c29532e006cb4fedb69faab60c9bac ../static/samples/SevenSegmentPattern.jpg -1335103ec002a662753fbf1850c9bdb7fa8bac7925dab1d5878b90aa54e9e963 ../static/samples/WallStairs.jpg -80e1e5eb264277ab69fcdf689e8e91cf6735e1f9d0e595d845fbe7685f9b8725 ../static/samples/Rack19Box.jpg -70f5fd1ef2f65c54867ef74c20ae30465d52226b69a1c82b9213676ff634aa0d ../static/samples/WallPinRow.jpg -56456fde428172ead54947709758b5d79995fa7c5e9bc89b5da84742c7960749 ../static/samples/SkadisBoard.jpg -4f8047786f1eeb256de2edf070efa758648a83dad2ad1c5d7c45388804117d3a *../static/samples/FlexBox5.jpg -22525c5c4fc9e25a68d79a4f6db6a169b2a9038ee9c2ba4a1dd69fcbe2944fb1 *../static/samples/SideDoorHousing-2.jpg -37eefc7aca018887debb9b9671ba8485289a4d5375fabef50d59efe656edbcf8 *../static/samples/SideDoorHousing.jpg -27c3d97e7d141dd72d065160d7fe48d7be700fa8175a034e40599b60d8c64d8c *../static/samples/Tetris.jpg -0195265c174c157690112bc01563439e536952c7015a41fbc562020fcdb270c3 *../static/samples/FillTest.jpg -27699d62eab473d903f2bcf0f334c2c36ff3601772c4c0ddeae89606a7bb10b5 *../static/samples/FlexTest2.jpg -853ace5a13ac571696a1965c72ae456c769ed4bc01ea29bb60bbe40518dcecf9 *../static/samples/RectangularWall.jpg -ed533e9827b58591fccbed9e6d31ff8c10bb7f9981501771f6577616a9fbe71b *../static/samples/WallRack.jpg -f625a31c8f1f08341f8e4c0ba5d34524f92e258ca2ae3027774c399a200ddfc9 ../static/samples/CoinBankSafe.jpg -49d330c7159dd77fc2e7a4d82ca46f2834c7e35a8c59b44739c0defbd045bedf ../static/samples/CoinBankSafe-open.jpg -17e9c4f4da3a74b94168913b78695918096269dfd2c59feb70bd4a833e155d04 ../static/samples/CoinBankSafe-pins.jpg -94e37a41d8b873f39bd3e8c74465b012c8f861031c93f64fd6eda89af02015c0 ../static/samples/FlexBook-2.jpg -4d8b4d5467a88431ba24e893157a6e09997d74654cd7e27878d2a54b1ee751c6 ../static/samples/CoinBankSafe-closed.jpg -bace3582c13ee543f09fd45752d4403e237d01541aaa4ea266e61e64fd12156a ../static/samples/FlexBook.jpg diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/self.css b/extensions/fablabchemnitz/boxes.py/boxes/static/self.css deleted file mode 100644 index 3327ac1..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/static/self.css +++ /dev/null @@ -1,237 +0,0 @@ -@import 'fonts.css'; -@import 'normalize.css'; - -html, -button, -input, -select, -textarea { - color: #222; -} - -html { - font-size: 1em; - line-height: 1.4; -} - -a { - text-decoration: none; - color: #5F584A; -} - -.menu li { - color: #666; - list-style-type: none; -} - -li a, a h1 { - text-decoration: none; - color: #333; -} - - -body { - min-width: 996px; -} - -h1 { - font-family: 'Bungee Shade', cursive; - font-size: 3em; -} - -h2 { - font-family: 'Luckiest Guy', cursive; - - font-size: 2.5em; -} - -h3 { - padding: 5px; - padding-left: 15px; - margin: 0px; - width: 75% -} - -h3::before { - font-family: system-ui, 'Segoe UI', 'Arial'; - content: "▶ "; -} - -h3.open::before { - font-family: system-ui, 'Segoe UI', 'Arial'; - content: "▼ "; -} - -h3:hover { - background-color: #333; - color: #eee; - border-radius: 10px; -} - -table { - margin-left: 30px; -} - -table tr p { - display: inline; -} - -/* Container */ - -.container { - background-color: #FFF8EA; - margin-top: 20px; - margin-left: auto; - margin-right: auto; - padding: 10px; - padding-bottom: 15px; - width: 996px; - border-radius: 30px; - box-shadow: 0 0 5px 0 #333333; - -} - -hr { - display: block; - height: 1px; - border: 0; - border-top: 1px solid #ccc; - margin: 1em 0; - padding: 0; -} - -audio, -canvas, -img, -video { - vertical-align: middle; -} - - -/* - * Clear after each row - */ -.clear { - clear: both; - display: block; - overflow: hidden; - visibility: hidden; - width: 0; - height: 0; -} - -.description img { - width: 100%; -} - -.footer { - margin-left: auto; - margin-right: auto; - padding: 10px; - padding-bottom: 15px; - width: 996px; - border-radius: 30px; - text-align: center; - margin-top: 0px; -} - -.footer ul { - margin-top: 0px; -} - -.footer ul li { - list-style-type: circle; - display: inline-block; - font-size: 0.9em; -} - -.search { - float : right; - padding-top: 10px; -} - -.footer ul li a { - color: #555; - margin-right: 10px; -} - -img[id|=sample] { - position: fixed; - bottom: 100px; - right: calc(50% - 498px); -} - -.menu ul { - padding-left: 5px; -} - -.menu ul li { - padding: 5px 5px 5px 10px; -} - -.menu ul li:hover { - background-color: #333; - color: #eee; - border-radius: 10px; -} - -.menu ul li:hover a { - color: #bbb; -} - -.menu ul li span { - display: none; - font-size: 1.8em; - font-weight: bold; - color: #333; - margin-left: 10px; -} - -.menu ul li:hover span { - display: inline-block; -} - -.menu h3 { - cursor: pointer; -} - -textarea { - font-family: monospace; -} - -.gallery_missing { - display : inline-block; - text-align : center; - vertical-align: middle; - width : 200px; - margin : 5px; - font-weight: bold; -} - -.gallery img { - max-height : 200px; - max-width : 200px; - margin : 5px; -} - -.modenav { - overflow: hidden; -} - -.modebutton { - float: left; - border: none; - outline: none; - padding: 10px 16px; - margin-right: 10px; - text-align : center; - border-radius: 10px; - font-size: 17px; - width: 25%; - background-color: #EFE8DA; -} - -.modeactive { - background-color: #DFD8BA; - -} diff --git a/extensions/fablabchemnitz/boxes.py/boxes/static/self.js b/extensions/fablabchemnitz/boxes.py/boxes/static/self.js deleted file mode 100644 index df063e4..0000000 --- a/extensions/fablabchemnitz/boxes.py/boxes/static/self.js +++ /dev/null @@ -1,303 +0,0 @@ -function showThumbnail(img_link) { - const img = document.getElementById("sample-preview"); - img.src = img_link; - img.style.height = "auto"; - img.style.display = "block"; -} - -function showThumbnailEvt(evt) { - const url = evt.target.getAttribute("data-thumbnail"); - showThumbnail(url); -} - -function hideThumbnail() { - const img = document.getElementById("sample-preview"); - img.style.display = "none"; -} - -function expandId(id) { - const e = document.getElementById(id); - const h = document.getElementById("h-" + id); - e.style.display = "block"; - h.classList.add("open"); - h.setAttribute("aria-expanded", "true"); -} -function collapseId(id) { - const e = document.getElementById(id); - const h = document.getElementById("h-" + id); - e.style.display = "none"; - h.classList.remove("open"); - h.setAttribute("aria-expanded", "false"); -} - -function toggleId(id) { - const e = document.getElementById(id); - const h = document.getElementById("h-" + id); - if (e.style.display == null || e.style.display === "none") { - expandId(id); - } else { - collapseId(id); - } -} - -function toggleEl(el) { - const id = el.getAttribute("data-id"); - toggleId(id); -} - -function toggleEvt(evt) { - const id = evt.target.getAttribute("data-id"); - // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role#examples - if (evt instanceof MouseEvent) { - toggleId(id); - } - if (evt instanceof KeyboardEvent && (evt.key === "Enter" || evt.key === " ")) { - evt.preventDefault(); - toggleId(id); - } -} - -function initToggle(el, hide = false) { - // Add event handler. - el.addEventListener("click", toggleEvt); - el.addEventListener("keydown", toggleEvt); - // Hide. - if (hide) { - toggleEl(el); - } -} - -function initThumbnail(el) { - // Add event handler. - el.addEventListener("mouseenter", showThumbnailEvt); - el.addEventListener("mouseleave", hideThumbnail); -} - -function initPage(num_hide = null) { - const h = document.getElementsByClassName("toggle"); - let i = 0; - for (let el of h) { - if (num_hide === null || i < num_hide) { - initToggle(el, true); - } else { - initToggle(el, false); - } - i++; - } - const t = document.getElementsByClassName("thumbnail"); - for (let el of t) initThumbnail(el); -} - -function GridfinityTrayLayout_GenerateLayout(x, y, nx, ny, countx, county) { - // x = width in mm - // y = height in mm - // nx # of gridfinity grids in X - // ny # of gridfinity grids in Y - // countx split x into this many - // county split y into this many - layout = ''; - if (countx == 0) - countx = nx; - if (county == 0) - county = ny - stepx = x / countx; - stepy = y / county; - for (i = 0; i < countx; i++) { - line = ' |'.repeat(i) + ` ,> ${stepx}mm\n`; - layout += line; - } - for (i = 0; i < county; i++) { - layout += "+-".repeat(countx) + "+\n"; - layout += "| ".repeat(countx) + `| ${stepy}mm\n`; - } - layout += "+-".repeat(countx) + "+\n"; - return layout -} - -function GridfinityTrayUpdateLayout(event) { - console.log("update"); - if (window.layoutUpdated == true) { - // Don't do the update if the layout has been manually touched. - if (confirm("You have manually updated the Layout. Do you wish to regenerate it?")) { - window.layoutUpdated = false; - } else { - return; - } - } - console.log("updating"); - nx = document.getElementById('nx').value; - ny = document.getElementById('ny').value; - countx = document.getElementById('countx').value; - county = document.getElementById('county').value; - margin = document.getElementById('margin').value; - x = nx*42 - margin - y = ny*42 - margin - layout_id = document.getElementById('layout'); - layout_id.value = GridfinityTrayLayout_GenerateLayout(x, y, nx, ny, countx, county); -} - -function setUpdated() { - console.log("this was updated"); - window.layoutUpdated=true; -} -function GridfinityTrayLayoutInit() { - console.log("update init"); - ids = ['nx', 'ny', 'countx', 'county', 'margin']; - window.layoutUpdated=false; - for (id_string of ids) { - id = document.getElementById(id_string); - id.addEventListener('input', GridfinityTrayUpdateLayout); - } - layout_id = document.getElementById('layout'); - layout_id.addEventListener('change', setUpdated); - layout_id.addEventListener('input', setUpdated); - - GridfinityTrayUpdateLayout(); - layout_id = document.getElementById('layout'); - layout_id.rows = 20; - layout_id.cols = 24; -} - -function ParseSections(s) { - var sections = []; - for (var section of s.split(":")) { - var operands = section.split("/"); - if (operands.length > 2) return sections; - if (operands.length == 2) { - for (var i=0; i 2) return sections; - if (operands.length == 2) { - for (var i=0; i ${sx[i].toFixed(2)}mm\n`; - layout += line; - } - for (i = 0; i < ny; i++) { - layout += "+-".repeat(nx) + "+\n"; - layout += "| ".repeat(nx) + `| ${sy[i].toFixed(2)}mm\n`; - } - layout += "+-".repeat(nx) + "+\n"; - return layout -} - -function TrayUpdateLayout(event) { - if (window.layoutUpdated == true) { - // Don't do the update if the layout has been manually touched. - if (confirm("You have manually updated the Layout. Do you wish to regenerate it?")) { - window.layoutUpdated = false; - } else { - return; - } - } - sx = document.getElementById('sx').value; - sy = document.getElementById('sy').value; - layout_id = document.getElementById('layout'); - layout_id.value = TrayLayout_GenerateLayout(sx, sy); -} - - -function TrayLayoutInit() { - ids = ['sx', 'sy']; - window.layoutUpdated=false; - for (id_string of ids) { - id = document.getElementById(id_string); - id.addEventListener('input', TrayUpdateLayout); - } - TrayUpdateLayout(); - layout_id = document.getElementById('layout'); - layout_id.addEventListener('change', setUpdated); - layout_id.addEventListener('input', setUpdated); - layout_id.rows = 20; - layout_id.cols = 24; -} - -function addCallbacks() { - page_callbacks = { - "TrayLayout": TrayLayoutInit, - "GridfinityTrayLayout": GridfinityTrayLayoutInit, - }; - loc = new URL(window.location.href); - pathname = loc.pathname; - page = pathname.substr(pathname.lastIndexOf('/')+1); - if (page in page_callbacks) { - callback = page_callbacks[page]; - callback(); - } -} - -document.addEventListener('DOMContentLoaded', function() { - addCallbacks(); -}, false); - -function collapseAll() { - const h = document.getElementsByClassName("toggle"); - for (let el of h) { - id = el.getAttribute("data-id") - collapseId(id); - } -} - -function expandAll() { - const h = document.getElementsByClassName("toggle"); - for (let el of h) { - id = el.getAttribute("data-id") - expandId(id); - } -} - -function showAll(str) { - let matching_ids = document.querySelectorAll('[id^="search_id_"]') - for (let id of matching_ids) { - id.style.display = "inline-block"; - } -} - -function showOnly(str) { - str = str.toLowerCase(); - let matching_ids = document.querySelectorAll('[id^="search_id_"]') - for (let id of matching_ids) { - name = id.id.replace("search_id_", "").toLowerCase(); - if (name.includes(str) || id.textContent.toLowerCase().includes(str)) { - id.style.display = "inline-block"; - } else { - id.style.display = "none"; - } - } -} - -function filterSearchItems() { - const search = document.getElementById("search") - if (search.value.length == 0) { - collapseAll(); - showAll() - } else { - expandAll(); - showOnly(search.value) - } -} diff --git a/extensions/fablabchemnitz/boxes.py/boxes_proxy.py b/extensions/fablabchemnitz/boxes.py/boxes_proxy.py index 3449a02..3c711fd 100644 --- a/extensions/fablabchemnitz/boxes.py/boxes_proxy.py +++ b/extensions/fablabchemnitz/boxes.py/boxes_proxy.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.2 +Extension for Inkscape 1.2 boxes.py wrapper script to make it work on Windows and Linux systems @@ -12,6 +12,7 @@ Last patch: 05.07.2024 License: GNU GPL v3 """ +import boxes import inkex import sys import subprocess @@ -37,8 +38,9 @@ class boxesPyWrapper(inkex.GenerateExtension): if os.path.exists(box_file): os.remove(box_file) #remove previously generated box file at the beginning - boxes_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'boxes', 'scripts') - + boxes_dir = os.path.join(os.path.dirname(boxes.__file__), 'scripts') + boxes_executable = 'boxes_main.py' + #get the correct python executable. If Inkscape has a custom interpreter in preferences.xml, we should honor it preferencesPath = os.environ["INKSCAPE_PROFILE_DIR"] preferencesXml = os.path.join(preferencesPath, "preferences.xml") @@ -66,7 +68,7 @@ class boxesPyWrapper(inkex.GenerateExtension): if customPythonInterpreter is not None: PYTHONBIN = customPythonInterpreter - cmd = PYTHONBIN + ' ' + os.path.join(boxes_dir, 'boxes') #the boxes python file (without .py ending) - we add python at the beginning to support Windows too + cmd = PYTHONBIN + ' ' + os.path.join(boxes_dir, boxes_executable) #the boxes python file (without .py ending) - we add python at the beginning to support Windows too for arg in vars(self.options): if arg not in ("output", "ids", "selected_nodes"): #inkex.utils.debug(str(arg) + " = " + str(getattr(self.options, arg))) @@ -79,7 +81,7 @@ class boxesPyWrapper(inkex.GenerateExtension): cmd += ' --' + arg + ' "' + str(getattr(self.options, arg)) + '"' #cmd += ' --' + arg + '="' + str(getattr(self.options, arg)) + '"' cmd += " --output=" + box_file + " " - cmd = cmd.replace("boxes --generator", "boxes") + cmd = cmd.replace("{} --generator".format(boxes_executable), boxes_executable) # run boxes with the parameters provided #with os.popen(cmd, "r") as boxes: diff --git a/extensions/fablabchemnitz/boxes.py/icons/info.festi.boxes.py.ABox.svg b/extensions/fablabchemnitz/boxes.py/icons/info.festi.boxes.py.ABox.svg deleted file mode 100644 index c2e4834..0000000 --- a/extensions/fablabchemnitz/boxes.py/icons/info.festi.boxes.py.ABox.svg +++ /dev/null @@ -1,310 +0,0 @@ - - - -image/svg+xml diff --git a/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py b/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py index 4947261..d0a3ab2 100644 --- a/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py +++ b/extensions/fablabchemnitz/contour_scanner_and_trimmer/contour_scanner_and_trimmer.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 ''' -Extension for InkScape 1.0+ +Extension for Inkscape 1.0+ - ToDo: - add more comments - add more debug output diff --git a/extensions/fablabchemnitz/convert_to_polylines/convert_to_polylines.py b/extensions/fablabchemnitz/convert_to_polylines/convert_to_polylines.py index 7f3a640..f4f368e 100644 --- a/extensions/fablabchemnitz/convert_to_polylines/convert_to_polylines.py +++ b/extensions/fablabchemnitz/convert_to_polylines/convert_to_polylines.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 Converts curves to polylines - a quick and dirty helper for a lot of elements. Basically the same functionality can be done with default UI featureset but with a lot more mouse clicks diff --git a/extensions/fablabchemnitz/convert_vertical_horizontal_to_line/convert_vertical_horizontal_to_line.py b/extensions/fablabchemnitz/convert_vertical_horizontal_to_line/convert_vertical_horizontal_to_line.py index 0c53440..b147cfe 100644 --- a/extensions/fablabchemnitz/convert_vertical_horizontal_to_line/convert_vertical_horizontal_to_line.py +++ b/extensions/fablabchemnitz/convert_vertical_horizontal_to_line/convert_vertical_horizontal_to_line.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.X +Extension for Inkscape 1.X This extension converts an SVG path's d attribute the following way: find each V (vertical line) and each H (horizontal line) and replace it by a generic line (L type). A lot of extensions do not work with V and H, but with L commands. So this is just a helper extension for other extensions :-) diff --git a/extensions/fablabchemnitz/create_links/create_links.py b/extensions/fablabchemnitz/create_links/create_links.py index 08551f8..3495b9c 100644 --- a/extensions/fablabchemnitz/create_links/create_links.py +++ b/extensions/fablabchemnitz/create_links/create_links.py @@ -23,7 +23,7 @@ It is a modification of the file addelements.py It is a modification of the file convert2dash.py Extension to convert paths into dash-array line -Extension for InkScape 1.X +Extension for Inkscape 1.X Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org Date: 09.04.2021 diff --git a/extensions/fablabchemnitz/cutcraft/cutcraftshape.py b/extensions/fablabchemnitz/cutcraft/cutcraftshape.py index 11d80b6..1f8b4c5 100644 --- a/extensions/fablabchemnitz/cutcraft/cutcraftshape.py +++ b/extensions/fablabchemnitz/cutcraft/cutcraftshape.py @@ -8,7 +8,7 @@ from lxml import etree #TODOS ''' -since InkScape 1.0 / Python 3 adjustments are required to fix "TypeError: '<' not supported between instances of 'Pier' and 'Pier'". A __lt__ method has to be implemented +since Inkscape 1.0 / Python 3 adjustments are required to fix "TypeError: '<' not supported between instances of 'Pier' and 'Pier'". A __lt__ method has to be implemented "for this reasion items = sorted([(p[0].area(),p[0]) for p in shape.parts], reverse=True)" was commented out ''' diff --git a/extensions/fablabchemnitz/cutting_optimizer/cutting_optimizer.py b/extensions/fablabchemnitz/cutting_optimizer/cutting_optimizer.py index 95641fa..1969dde 100644 --- a/extensions/fablabchemnitz/cutting_optimizer/cutting_optimizer.py +++ b/extensions/fablabchemnitz/cutting_optimizer/cutting_optimizer.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.2 +Extension for Inkscape 1.2 CutOptim OS Wrapper script to make CutOptim work on Windows and Linux systems without duplicating .inx files @@ -198,4 +198,4 @@ class CuttingOptimizer(inkex.EffectExtension): self.document.getroot().append(group) if __name__ == '__main__': - CuttingOptimizer().run() \ No newline at end of file + CuttingOptimizer().run() diff --git a/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.inx b/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.inx index 7367271..0e9e917 100644 --- a/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.inx +++ b/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.inx @@ -38,7 +38,7 @@ - + diff --git a/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.py b/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.py index 0676ca5..b18dd34 100644 --- a/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.py +++ b/extensions/fablabchemnitz/dxf2papercraft/dxf2papercraft.py @@ -9,9 +9,9 @@ from lxml import etree from inkex import Transform """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 -Unfold and import DXF into InkScape using dxf2papercraft. This is some kind of wrapper extension utilizing kabeja to convert the dxf output from dxf2papercraft into SVG. +Unfold and import DXF into Inkscape using dxf2papercraft. This is some kind of wrapper extension utilizing kabeja to convert the dxf output from dxf2papercraft into SVG. To make it work you need to install at least java. Author: Mario Voigt / FabLab Chemnitz @@ -113,7 +113,7 @@ class DXF2Papercraft(inkex.EffectExtension): if proc.returncode != 0: inkex.errormsg("kabeja failed: %d %s %s" % (proc.returncode, stdout, stderr)) - # Write the generated SVG into InkScape's canvas + # Write the generated SVG into Inkscape's canvas try: stream = open(svg_output, 'r') except FileNotFoundError as e: diff --git a/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.inx b/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.inx index c67b214..8da5c4f 100644 --- a/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.inx +++ b/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.inx @@ -11,7 +11,7 @@ - + true 0.0 diff --git a/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.py b/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.py index dff964f..0d08355 100644 --- a/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.py +++ b/extensions/fablabchemnitz/dxf_dwg_importer/dxf_dwg_importer.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.3 +Extension for Inkscape 1.3 Import any DWG or DXF file using ODA File Converter, sk1 UniConvertor, ezdxf and more tools. @@ -398,7 +398,7 @@ class DXFDWGImport(inkex.EffectExtension): self.msg("undefined parser") exit(1) - # Write the generated SVG into InkScape's canvas + # Write the generated SVG into Inkscape's canvas try: stream = open(svg_file, 'r') except FileNotFoundError as e: @@ -455,4 +455,4 @@ class DXFDWGImport(inkex.EffectExtension): self.msg("Error finding bounding box. Skipped that step ...") if __name__ == '__main__': - DXFDWGImport().run() \ No newline at end of file + DXFDWGImport().run() diff --git a/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py b/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py index a4cd550..5ed046e 100644 --- a/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py +++ b/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 ''' -Extension for InkScape 1.3 +Extension for Inkscape 1.3 Features - This tool is a helper to adjust the document border including an offset value, which is added. Sending vector data to Epilog Dashboard often results in trimmed paths. This leads to wrong geometry where the laser misses to cut them. @@ -55,7 +55,7 @@ class EpilogDashboardBboxAdjust(inkex.EffectExtension): applyTransformationsAvailable = True except Exception as e: # self.msg(e) - self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...") + self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery. Skipping ...") if self.options.apply_transformations is True and applyTransformationsAvailable is True: apply_transformations.ApplyTransformations().recursiveFuseTransform(self.document.getroot()) diff --git a/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py b/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py index ddc600c..9d1c93b 100644 --- a/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py +++ b/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 ''' -Extension for InkScape 1.0+ +Extension for Inkscape 1.0+ Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org @@ -118,7 +118,7 @@ class FilterByLengthArea(inkex.EffectExtension): applyTransformationsAvailable = True except Exception as e: # self.msg(e) - self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...") + self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery. Skipping ...") so.min_threshold = self.svg.unittouu(str(so.min_threshold) + self.svg.unit) so.max_threshold = self.svg.unittouu(str(so.max_threshold) + self.svg.unit) @@ -269,7 +269,7 @@ class FilterByLengthArea(inkex.EffectExtension): import remove_empty_groups remove_empty_groups.RemoveEmptyGroups.effect(self) except: - self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...") + self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery. Skipping ...") if __name__ == '__main__': FilterByLengthArea().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py index 990a282..668b5ab 100644 --- a/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py +++ b/extensions/fablabchemnitz/imagetracerjs/imagetracerjs.py @@ -10,7 +10,7 @@ from io import BytesIO from lxml import etree """ -Extension for InkScape 1.X +Extension for Inkscape 1.X Features - will vectorize your beautiful image into a more beautiful SVG trace with separated infills(break apart into single surfaces like a puzzle) diff --git a/extensions/fablabchemnitz/inventory_sticker/inventory_sticker.py b/extensions/fablabchemnitz/inventory_sticker/inventory_sticker.py index 805c86e..c9aa8c0 100644 --- a/extensions/fablabchemnitz/inventory_sticker/inventory_sticker.py +++ b/extensions/fablabchemnitz/inventory_sticker/inventory_sticker.py @@ -6,7 +6,7 @@ # # Made by FabLab Chemnitz / Stadtfabrikanten e.V. - Developer: Mario Voigt (year 2021) # -# This extension is based on the "original" barcode extension included in default InkScape Extension Set, which is licensed by the following: +# This extension is based on the "original" barcode extension included in default Inkscape Extension Set, which is licensed by the following: # # Copyright (C) 2009 John Beard john.j.beard@gmail.com # @@ -489,7 +489,7 @@ class InventorySticker(inkex.Effect): { "font-size": str(objectNameFontSize) + "px", "x": str(x_pos) + "px", - #"xml:space": "preserve", #we cannot add this here because InkScape throws an error + #"xml:space": "preserve", #we cannot add this here because Inkscape throws an error "y": str(objectNameFontSize) + "px", "text-align" : "left", "text-anchor": "left", diff --git a/extensions/fablabchemnitz/papercraft_unfold/papercraft_unfold.py b/extensions/fablabchemnitz/papercraft_unfold/papercraft_unfold.py index 851d598..8a38f9f 100644 --- a/extensions/fablabchemnitz/papercraft_unfold/papercraft_unfold.py +++ b/extensions/fablabchemnitz/papercraft_unfold/papercraft_unfold.py @@ -15,7 +15,7 @@ import d3.model.tools as mt from d3.model.basemodel import Vector """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org @@ -173,7 +173,7 @@ class PapercraftUnfold(inkex.EffectExtension): p = Popen(fstl_cmd, shell=True) p.wait() - # Write the generated SVG into InkScape's canvas + # Write the generated SVG into Inkscape's canvas try: stream = open(converted_flattenfile, 'r') except FileNotFoundError as e: diff --git a/extensions/fablabchemnitz/paperfold/paperfold.py b/extensions/fablabchemnitz/paperfold/paperfold.py index ab8d131..ccc3872 100644 --- a/extensions/fablabchemnitz/paperfold/paperfold.py +++ b/extensions/fablabchemnitz/paperfold/paperfold.py @@ -11,7 +11,7 @@ from lxml import etree import copy """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 Paperfold is another flattener for triangle mesh files, heavily based on paperfoldmodels by Felix Scholz aka felixfeliz. diff --git a/extensions/fablabchemnitz/path_intersections/path_intersections.inx b/extensions/fablabchemnitz/path_intersections/path_intersections.inx index 387cafa..c714954 100644 --- a/extensions/fablabchemnitz/path_intersections/path_intersections.inx +++ b/extensions/fablabchemnitz/path_intersections/path_intersections.inx @@ -2,7 +2,7 @@ Path Intersections fablabchemnitz.de.path_intersections - + 4012452351 all diff --git a/extensions/fablabchemnitz/path_intersections/path_intersections.py b/extensions/fablabchemnitz/path_intersections/path_intersections.py index b724e37..e7d1152 100644 --- a/extensions/fablabchemnitz/path_intersections/path_intersections.py +++ b/extensions/fablabchemnitz/path_intersections/path_intersections.py @@ -24,7 +24,7 @@ Migrator: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org Date: 13.08.2020 -This plugin - initially called "Precut" - was found deeply on web and was nearly lost in translation. Ported to Python 3.0 for InkScape 1.0. This tool finds path intersections within the complete SVG document. Intersections are going to be marked with little squares. +This plugin - initially called "Precut" - was found deeply on web and was nearly lost in translation. Ported to Python 3.0 for Inkscape 1.0. This tool finds path intersections within the complete SVG document. Intersections are going to be marked with little squares. """ """ diff --git a/extensions/fablabchemnitz/plycutter/plycutter.py b/extensions/fablabchemnitz/plycutter/plycutter.py index 174213b..e395fe3 100644 --- a/extensions/fablabchemnitz/plycutter/plycutter.py +++ b/extensions/fablabchemnitz/plycutter/plycutter.py @@ -83,7 +83,7 @@ class PlyCutter(inkex.EffectExtension): str(stderr.decode('UTF-8')).replace('\\n', '\n').replace('\\t', '\t')) ) - # Write the generated SVG into InkScape's canvas + # Write the generated SVG into Inkscape's canvas try: stream = open(svg_output, 'r') except FileNotFoundError as e: diff --git a/extensions/fablabchemnitz/primitive/primitive.py b/extensions/fablabchemnitz/primitive/primitive.py index ee75251..9457a41 100644 --- a/extensions/fablabchemnitz/primitive/primitive.py +++ b/extensions/fablabchemnitz/primitive/primitive.py @@ -11,7 +11,7 @@ from lxml import etree from inkex import Color """ -Extension for InkScape 1.X +Extension for Inkscape 1.X Features - Primitive - Reproducing images with geometric primitives written in Go. diff --git a/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py index 25383cc..459be64 100644 --- a/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py +++ b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py @@ -7,7 +7,7 @@ More usesless and/or redundant filters for removing duplicate nodes and segments - https://stadtfabrikanten.org/display/IFM/Purge+Duplicate+Path+Segments - https://stadtfabrikanten.org/display/IFM/Purge+Duplicate+Path+Nodes -Extension for InkScape 1.X +Extension for Inkscape 1.X Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org Date: 21.04.2021 diff --git a/extensions/fablabchemnitz/remove_empty_groups/remove_empty_groups.py b/extensions/fablabchemnitz/remove_empty_groups/remove_empty_groups.py index a8c65c6..8096845 100644 --- a/extensions/fablabchemnitz/remove_empty_groups/remove_empty_groups.py +++ b/extensions/fablabchemnitz/remove_empty_groups/remove_empty_groups.py @@ -3,7 +3,7 @@ import inkex """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 This extension is totally minimal. It will just clean the whole document from groups without content (dangling groups). That usually happens if you have a group but remove its paths for example. The group will possibly stay in the XML tree. This also applies for layers because layers are just special types of groups. This effect applies to the whole document ONLY! diff --git a/extensions/fablabchemnitz/round_corners/round_corners.py b/extensions/fablabchemnitz/round_corners/round_corners.py index 8348846..d8a51fc 100644 --- a/extensions/fablabchemnitz/round_corners/round_corners.py +++ b/extensions/fablabchemnitz/round_corners/round_corners.py @@ -30,7 +30,7 @@ # v1.3, 2020-12-12, jw - minimalistic compatibility layer for inkscape 0.92.4 done. It now works in both, 1.0 and 0.92! # v1.4, 2020-12-15, jw - find_roundable_nodes() added for auto selecting nodes, if none were selected. # And fix https://github.com/jnweiger/inkscape-round-corners/issues/2 -# 2021-01-15, Mario Voigt - removed oboslete InkScape 0.92.* stuff +# 2021-01-15, Mario Voigt - removed oboslete Inkscape 0.92.* stuff # # Bad side-effect: As the node count increases during operation, the list of # selected nodes is incorrect afterwards. We have no way to give inkscape an update. diff --git a/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py b/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py index 541b70f..03288c5 100644 --- a/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py +++ b/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org diff --git a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py index f24d485..3d9e066 100644 --- a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py +++ b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.0 +Extension for Inkscape 1.0 Features - filters the current selection or the whole document for fill or stroke style. Each style will be put onto it's own layer. This way you can devide elements by their colors. @@ -73,7 +73,7 @@ class StylesToLayers(inkex.EffectExtension): applyTransformationsAvailable = True except Exception as e: # self.msg(e) - self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...") + self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery. Skipping ...") layer_name = None layerNodeList = [] #list with layer, neutral_value, element and self.options.separateby type @@ -91,7 +91,7 @@ class StylesToLayers(inkex.EffectExtension): if self.options.apply_transformations is True and applyTransformationsAvailable is True: apply_transformations.ApplyTransformations().recursiveFuseTransform(element) - if isinstance(element, inkex.ShapeElement): # Elements which have a visible representation on the canvas (even without a style attribute but by their type); if we do not use that ifInstance Filter we provokate unkown InkScape fatal crashes + if isinstance(element, inkex.ShapeElement): # Elements which have a visible representation on the canvas (even without a style attribute but by their type); if we do not use that ifInstance Filter we provokate unkown Inkscape fatal crashes style = element.style if style is not None: @@ -302,7 +302,7 @@ class StylesToLayers(inkex.EffectExtension): import remove_empty_groups remove_empty_groups.RemoveEmptyGroups.effect(self) except: - self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...") + self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery. Skipping ...") if __name__ == '__main__': StylesToLayers().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py b/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py index cb176de..952948c 100644 --- a/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py +++ b/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.3.2 +Extension for Inkscape 1.3.2 This extension parses the selection and will put all elements into one single group. If you have a cluster with lots of groups and elements you will clean up this way (one top level group, all elements below it). If you select a single element or a set of elements you just wrap it like using CTRL + G (like making a usual group). You can also use this extension to filter out unwanted SVG elements at all. @@ -108,7 +108,7 @@ class UngrouperAndElementMigratorFilter(inkex.EffectExtension): self.msg("{} tails/texts were removed during nodes while migration.".format(tails)) namespace = [] #a list of selected types we are going to process for filtering (dropping items) - #namespace.append("{http://www.w3.org/2000/svg}sodipodi") if so.sodipodi else "" #do not do this. it will crash InkScape + #namespace.append("{http://www.w3.org/2000/svg}sodipodi") if so.sodipodi else "" #do not do this. it will crash Inkscape #namespace.append("{http://www.w3.org/2000/svg}svg") if so.svg else "" #we handle svg:svg the same type like svg:g namespace.append("{http://www.w3.org/2000/svg}circle") if so.circle else "" namespace.append("{http://www.w3.org/2000/svg}clipPath") if so.clipPath else "" @@ -196,7 +196,7 @@ class UngrouperAndElementMigratorFilter(inkex.EffectExtension): applyTransformationsAvailable = True except Exception as e: # self.msg(e) - self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery. Skipping ...") + self.msg("Calling 'Apply Transformations' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery. Skipping ...") if so.apply_transformations is True and applyTransformationsAvailable is True: apply_transformations.ApplyTransformations().recursiveFuseTransform(self.document.getroot()) @@ -244,7 +244,7 @@ class UngrouperAndElementMigratorFilter(inkex.EffectExtension): if so.operationmode == "filter_only" or so.operationmode == "ungroup_and_filter": if so.showdroplist: self.msg("{} elements were removed during nodes while migration.".format(len(self.allDrops))) - if len(self.allDrops) > 100: #if we print too much to the output stream we will freeze InkScape forever wihtout any visual error message. So we write to file instead + if len(self.allDrops) > 100: #if we print too much to the output stream we will freeze Inkscape forever wihtout any visual error message. So we write to file instead migrate_log_file = open('migrategroups.log', 'w') else: migrate_log_file = None @@ -296,7 +296,7 @@ class UngrouperAndElementMigratorFilter(inkex.EffectExtension): import remove_empty_groups remove_empty_groups.RemoveEmptyGroups.effect(self) except: - self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery.") + self.msg("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official Inkscape Gallery.") if __name__ == '__main__': UngrouperAndElementMigratorFilter().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/unwind_paths/unwind_paths.py b/extensions/fablabchemnitz/unwind_paths/unwind_paths.py index 833205b..bca97cd 100644 --- a/extensions/fablabchemnitz/unwind_paths/unwind_paths.py +++ b/extensions/fablabchemnitz/unwind_paths/unwind_paths.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -Extension for InkScape 1.0+ +Extension for Inkscape 1.0+ Paperfold is another flattener for triangle mesh files, heavily based on paperfoldmodels by Felix Scholz aka felixfeliz. diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools.py b/extensions/fablabchemnitz/vpypetools/vpypetools.py index f470d95..7b98783 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools.py +++ b/extensions/fablabchemnitz/vpypetools/vpypetools.py @@ -26,15 +26,15 @@ import warnings # we import this to suppress moderngl warnings from vpype_viewer from shapely.geometry import LineString, Point """ -Extension for InkScape 1.X +Extension for Inkscape 1.X Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org Date: 02.04.2021 Last patch: 06.06.2021 License: GNU GPL v3 -This piece of spaghetti-code, called "vpypetools", is a wrapper to pass (pipe) line elements from InkScape selection (or complete canvas) to vpype. -It allows to run basic commands on the geometry. The converted lines are getting pushed back into InkScape. +This piece of spaghetti-code, called "vpypetools", is a wrapper to pass (pipe) line elements from Inkscape selection (or complete canvas) to vpype. +It allows to run basic commands on the geometry. The converted lines are getting pushed back into Inkscape. vpypetools allows to enable some important adjusters and debugging settings to get the best out of it. vpypetools is based on @@ -124,7 +124,7 @@ class vpypetools (inkex.EffectExtension): pars.add_argument("--decimals", type=int, default=3, help="Accuracy for imported lines' coordinates into vpype. Does not work for 'Multilayer/document'") pars.add_argument("--simplify", type=inkex.Boolean, default=False, help="Reduces significantly the number of segments used to approximate the curve while still guaranteeing an accurate conversion, but may increase the execution time. Does not work for 'Singlelayer/paths'") pars.add_argument("--parallel", type=inkex.Boolean, default=False, help="Enables multiprocessing for the SVG conversion. This is recommended ONLY when using 'Simplify geometry' on large SVG files with many curved elements. Does not work for 'Singlelayer/paths'") - pars.add_argument("--output_show", type=inkex.Boolean, default=False, help="This will open a separate window showing the finished SVG data. If enabled, output is not applied to InkScape canvas (only for preview)!") + pars.add_argument("--output_show", type=inkex.Boolean, default=False, help="This will open a separate window showing the finished SVG data. If enabled, output is not applied to Inkscape canvas (only for preview)!") pars.add_argument("--output_show_points", type=inkex.Boolean, default=False, help="Enable point display in viewer") pars.add_argument("--output_stats", type=inkex.Boolean, default=False, help="Show output statistics before/after conversion") pars.add_argument("--output_trajectories", type=inkex.Boolean, default=False, help="Add paths for the travel trajectories") diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_deduplicate.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_deduplicate.inx index 7f1bc01..5a6d5f1 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_deduplicate.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_deduplicate.inx @@ -11,7 +11,7 @@ false - + @@ -23,11 +23,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_filter.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_filter.inx index 97c00bc..e6d6d64 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_filter.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_filter.inx @@ -16,7 +16,7 @@ 0.000 - + @@ -28,11 +28,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_freemode.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_freemode.inx index c37d5c2..f8e6d57 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_freemode.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_freemode.inx @@ -21,7 +21,7 @@ false - + @@ -33,11 +33,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_linemerge.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_linemerge.inx index ddf8311..e6f79f3 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_linemerge.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_linemerge.inx @@ -11,7 +11,7 @@ false - + @@ -23,11 +23,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_linesort.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_linesort.inx index 5272bdb..cc892d5 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_linesort.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_linesort.inx @@ -10,7 +10,7 @@ false - + @@ -22,11 +22,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_multipass.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_multipass.inx index 4acb1c7..c11beb8 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_multipass.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_multipass.inx @@ -10,7 +10,7 @@ 2 - + @@ -22,11 +22,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_occult.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_occult.inx index cb82ae0..c7f4749 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_occult.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_occult.inx @@ -11,7 +11,7 @@ false - + @@ -23,11 +23,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_relooping.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_relooping.inx index bdc4e93..6dea4be 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_relooping.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_relooping.inx @@ -10,7 +10,7 @@ 0.500 - + @@ -22,11 +22,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_splitall.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_splitall.inx index b04099a..647c1d9 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_splitall.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_splitall.inx @@ -9,7 +9,7 @@ true - + @@ -21,11 +21,11 @@ false - false + false false false - + false false true diff --git a/extensions/fablabchemnitz/vpypetools/vpypetools_trim.inx b/extensions/fablabchemnitz/vpypetools/vpypetools_trim.inx index 9ebfc1b..df1b192 100644 --- a/extensions/fablabchemnitz/vpypetools/vpypetools_trim.inx +++ b/extensions/fablabchemnitz/vpypetools/vpypetools_trim.inx @@ -11,7 +11,7 @@ 0.000 - + @@ -23,11 +23,11 @@ false - false + false false false - + false false true