diff --git a/documentation/src/Boxes.rst b/documentation/src/Boxes.rst deleted file mode 100644 index 4784711..0000000 --- a/documentation/src/Boxes.rst +++ /dev/null @@ -1,221 +0,0 @@ - -========================== -The boxes.Boxes main class -========================== - -.. toctree:: - :maxdepth: 2 - -There is basically one class that takes care of everything. You are -supposed to sub class it and implement the ``.__init__()`` and -``.render()`` method. This Boxes class keeps a cairo 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. - -.. autoclass:: boxes.Boxes - -And easier way to get started is using the -``boxes/generators/_template.py`` as a basis for your own generators. - -Basic operation ---------------- -.. automethod:: boxes.Boxes.__init__ - -.. automethod:: boxes.Boxes.parseArgs -.. automethod:: boxes.Boxes.render - -.. automethod:: boxes.Boxes.open -.. automethod:: boxes.Boxes.close - - -Generating Parts ----------------- - -A couple of commands can create whole parts like walls. Typically the -sizes given are the inner dimmensions 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.roundedPlate -.. automethod:: boxes.Boxes.surroundingWall - -Parts Class -........... - -More parts are available in a separete class. An instance is available as -**Boxes.parts** - -.. automethod:: boxes.parts.Parts.disc -.. automethod:: boxes.parts.Parts.waivyKnob -.. automethod:: boxes.parts.Parts.concaveKnob -.. automethod:: boxes.parts.Parts.ringSegment - - -There are a few parameter shared by many of those 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 funtion 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`` paramter 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 many of the same part partMatrix can used: - -.. automethod:: boxes.Boxes.partsMatrix - -It creates one big block of parts. The move param treat this block like on big -part. - -Navigation ----------- -.. automethod:: boxes.Boxes.moveTo -.. automethod:: boxes.Boxes.moveArc - -**Boxes.ctx.save()** allows to save (among other things) the current position. -**Boxes.ctx.restore()** restores the previously saved state. Always make sure -to have balanced calls to those two functions. - -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 - -Draw Commands -------------- - -These commands do not change the coordinate system but get the -coordinates passed as parameters. All of them are either som sort of -hole or text. These artefacts 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 maded 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) defualting 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/documentation/src/Makefile b/documentation/src/Makefile index 7cbfdce..f6223b5 100644 --- a/documentation/src/Makefile +++ b/documentation/src/Makefile @@ -50,7 +50,8 @@ clean: rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + ./boxes2rst generators.inc + $(SPHINXBUILD) --color -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 2>&1 | grep -v "WARNING: duplicate object description" cp index.html $(BUILDDIR)/ @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/documentation/src/api_architecture.rst b/documentation/src/api_architecture.rst new file mode 100644 index 0000000..f34c344 --- /dev/null +++ b/documentation/src/api_architecture.rst @@ -0,0 +1,95 @@ +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 `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 an sub class of boxes.Boxes. It generates one +drawing. The sub classes over load .__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 is a number of standard parts. Their typical params are +explained in the API docs. + +Only real requirement for a part it supporting 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. + +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 +acciociated 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. + +Cairo +..... + +Boxes.py uses cairo as graphics library. It is not fully encapsulated +within the drawing methods of the Boxes class. Although this is the +long term goal. Boxes.ctx is the cairo context all drawing is made on. diff --git a/documentation/src/api_arguments.rst b/documentation/src/api_arguments.rst new file mode 100644 index 0000000..27bb2ca --- /dev/null +++ b/documentation/src/api_arguments.rst @@ -0,0 +1,76 @@ +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 frame work. Be careful to **not overwrite important +methods or attributes by using conflicting argument names**. + diff --git a/documentation/src/api_drawing.rst b/documentation/src/api_drawing.rst new file mode 100644 index 0000000..24d648c --- /dev/null +++ b/documentation/src/api_drawing.rst @@ -0,0 +1,76 @@ +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 + +Draw Commands +------------- + +These commands do not change the coordinate system but get the +coordinates passed as parameters. All of them are either som sort of +hole or text. These artefacts 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 maded 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) defualting 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/documentation/src/edges.rst b/documentation/src/api_edges.rst similarity index 100% rename from documentation/src/edges.rst rename to documentation/src/api_edges.rst diff --git a/documentation/src/api_examples.rst b/documentation/src/api_examples.rst new file mode 100644 index 0000000..9979002 --- /dev/null +++ b/documentation/src/api_examples.rst @@ -0,0 +1,97 @@ +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() right places on the sides. +While the use of the Boxes.py API is pretty straight forward 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 lazyness. + +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/documentation/src/api_existing_parts.rst b/documentation/src/api_existing_parts.rst new file mode 100644 index 0000000..9ade760 --- /dev/null +++ b/documentation/src/api_existing_parts.rst @@ -0,0 +1,26 @@ +Existing Parts +-------------- + +A couple of commands can create whole parts like walls. Typically the +sizes given are the inner dimmensions 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.roundedPlate +.. automethod:: boxes.Boxes.surroundingWall + +Parts Class +........... + +More parts are available in a separete class. An instance is available as +**Boxes.parts** + +.. automethod:: boxes.parts.Parts.disc +.. automethod:: boxes.parts.Parts.waivyKnob +.. automethod:: boxes.parts.Parts.concaveKnob +.. automethod:: boxes.parts.Parts.ringSegment diff --git a/documentation/src/api_generator.rst b/documentation/src/api_generator.rst new file mode 100644 index 0000000..43da2b0 --- /dev/null +++ b/documentation/src/api_generator.rst @@ -0,0 +1,45 @@ + +Generators +========== + +Generators are sub classes of + +.. autoclass:: boxes.Boxes + +Most code is directly in this class. Sub class are supposed to over +write the ``.__init__()`` and ``.render()`` method. + +The Boxes class keeps a cairo 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 sub classes. 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/documentation/src/api_navigation.rst b/documentation/src/api_navigation.rst new file mode 100644 index 0000000..86e586d --- /dev/null +++ b/documentation/src/api_navigation.rst @@ -0,0 +1,12 @@ +Navigation +---------- +.. automethod:: boxes.Boxes.moveTo +.. automethod:: boxes.Boxes.moveArc + +**Boxes.ctx.save()** allows to save (among other things) the current position. +**Boxes.ctx.restore()** restores the previously saved state. Always make sure +to have balanced calls to those two functions. + +XXX + +.. automethod:: boxes.Boxes.saved_context() diff --git a/documentation/src/api_parts.rst b/documentation/src/api_parts.rst new file mode 100644 index 0000000..b70313a --- /dev/null +++ b/documentation/src/api_parts.rst @@ -0,0 +1,86 @@ +Parts +----- + + + + +There are a few parameter shared by many of those 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 funtion 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`` paramter 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 many of the same part partMatrix can used: + +.. automethod:: boxes.Boxes.partsMatrix + +It creates one big block of parts. The move param treat this block like on big +part. diff --git a/documentation/src/apidoc.rst b/documentation/src/apidoc.rst new file mode 100644 index 0000000..76cc551 --- /dev/null +++ b/documentation/src/apidoc.rst @@ -0,0 +1,19 @@ +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_examples diff --git a/documentation/src/apiintro.rst b/documentation/src/apiintro.rst deleted file mode 100644 index 1adccb9..0000000 --- a/documentation/src/apiintro.rst +++ /dev/null @@ -1,245 +0,0 @@ -========================== -Using the Boxes.py library -========================== - -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. - -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. - -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 frame work. Be careful to **not overwrite important -methods or attributes by using conflicting argument names**. - -API Levels ----------- - -For actual drawing there are multiple levels of abscractions thta can -be used. From the simplest to the more powerful they are the following: - -Simple drawing commands -....................... - -These 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. - -Moving the coordinate system -............................ - -Boxes.py moves the coordinate system around a lot. You basically never have to -deal with the global position on the sheet but only with coordnates -relative to where you are. There are a few functions to move the -origin to a convenient position. - -Turtle graphics -............... - -To draw parts turtle graphic commands are used. The always start at -the current origin following the X axis. The move the origin with -them. The inside of the part is above the X axis and the outside -below. 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. The burn correction is implemented by -increasing the radius of positive corners and decresing the radius of -negative corners. (TODO: nice pictures) - -Edges -..... - -Edges are also turtle graphic commands. But they have been elevated to -proper Classes. - -Parts -..... - -There are a couple of standard parts that can be drawn with a single -command. Their typical params are explained in the API docs. - - -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. - - -How to get things done ----------------------- - -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() right places on the sides. -While the use of the Boxes.py API is pretty straight forward 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 lazyness. - -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/documentation/src/boxes.rst b/documentation/src/boxes.rst new file mode 100644 index 0000000..3778556 --- /dev/null +++ b/documentation/src/boxes.rst @@ -0,0 +1,120 @@ +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/documentation/src/boxes2rst b/documentation/src/boxes2rst new file mode 100755 index 0000000..f7b5b86 --- /dev/null +++ b/documentation/src/boxes2rst @@ -0,0 +1,56 @@ +#!/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 sys +import os.path + +try: + import boxes.generators +except ImportError: + sys.path.append(os.path.dirname(__file__) + "/../..") + import boxes.generators + +class Boxes2rst: + def __init__(self): + 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, path): + with open(path, "w") as f: + for name, group in self.groups_by_name.items(): + f.write(name + """ +---------------- + +""") + for box in group.generators: + f.write(box.__class__.__name__) + f.write("\n..........................................\n\n") + f.write("\n\n.. autoclass:: %s.%s" % ( + box.__class__.__module__, box.__class__.__name__)) + f.write("\n\n") + if os.path.exists("../../static/samples/"+ box.__class__.__name__+".jpg"): + f.write(".. image:: ../../static/samples/" + box.__class__.__name__+".jpg\n\n") + +if __name__=="__main__": + if len(sys.argv) != 2: + print("Usage: boxes2inksacpe TARGETPATH") + b = Boxes2rst() + b.write(sys.argv[1]) diff --git a/documentation/src/generators.rst b/documentation/src/generators.rst new file mode 100644 index 0000000..c6e1348 --- /dev/null +++ b/documentation/src/generators.rst @@ -0,0 +1,9 @@ +All Box Generators +================== + +Generators are organized in several Groups + +.. contents:: + :local: + +.. include:: generators.inc diff --git a/documentation/src/index.rst b/documentation/src/index.rst index b2eeb4e..6856440 100644 --- a/documentation/src/index.rst +++ b/documentation/src/index.rst @@ -3,21 +3,22 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to boxes.py's documentation! -==================================== +Boxes.py +======== + +Create boxes and more with a laser cutter! Contents: .. toctree:: - :maxdepth: 2 + :maxdepth: 1 README install usermanual CONTRIBUTING.rst - apiintro - Boxes - edges + apidoc + generators Indices and tables ================== diff --git a/documentation/src/modules.rst b/documentation/src/modules.rst new file mode 100644 index 0000000..8a714cb --- /dev/null +++ b/documentation/src/modules.rst @@ -0,0 +1,9 @@ +:orphan: + +boxes +===== + +.. toctree:: + :maxdepth: 4 + + boxes