summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2022-02-01 22:08:54 +0100
committerjaseg <git@jaseg.de>2022-02-01 22:08:54 +0100
commit7473e471dc69d09a35bb0762549cc4f3ab8b04b3 (patch)
treedcd162f56a5dbeac6ee669fc85d582813fd48eea /docs
parentc3ca4f95bd59f69d45e582a4149327f57a360760 (diff)
downloadgerbonara-7473e471dc69d09a35bb0762549cc4f3ab8b04b3.tar.gz
gerbonara-7473e471dc69d09a35bb0762549cc4f3ab8b04b3.tar.bz2
gerbonara-7473e471dc69d09a35bb0762549cc4f3ab8b04b3.zip
Add some documentation
Diffstat (limited to 'docs')
-rw-r--r--docs/aperture-macros.rst48
-rw-r--r--docs/apertures.rst138
-rw-r--r--docs/api-concepts.rst60
-rw-r--r--docs/conf.py57
-rw-r--r--docs/file-api.rst25
-rw-r--r--docs/graphic-primitive-api.rst27
-rw-r--r--docs/index.rst115
-rw-r--r--docs/object-api.rst30
-rw-r--r--docs/utilities.rst3
9 files changed, 503 insertions, 0 deletions
diff --git a/docs/aperture-macros.rst b/docs/aperture-macros.rst
new file mode 100644
index 0000000..1284c49
--- /dev/null
+++ b/docs/aperture-macros.rst
@@ -0,0 +1,48 @@
+Aperture Macros
+===============
+
+.. autoclass:: gerbonara.aperture_macros.parse.ApertureMacro
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.parse.GenericMacros
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.expression.Expression
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.expression.UnitExpression
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.expression.ConstantExpression
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.expression.VariableExpression
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.expression.OperatorExpression
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.Primitive
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.Circle
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.VectorLine
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.CenterLine
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.Polygon
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.Thermal
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.Outline
+ :members:
+
+.. autoclass:: gerbonara.aperture_macros.primitive.Comment
+ :members:
+
diff --git a/docs/apertures.rst b/docs/apertures.rst
new file mode 100644
index 0000000..2a17a04
--- /dev/null
+++ b/docs/apertures.rst
@@ -0,0 +1,138 @@
+Apertures in Gerbonara
+======================
+
+Gerbonara maps all standard Gerber apertures to subclasses of the Aperture_ class. These subclasses: CircleAperture_,
+RectangleAperture_, ObroundAperture_ and PolygonAperture_. Aperture macro instantiations get mapped to
+ApertureMacroInstance_ (also an Aperture_ subclass).
+
+All Aperture_ subclasses have these common attributes:
+
+
+`hole_dia`
+ float with diameter of hole. 0 for no hole.
+
+`hole_rect_h`
+ float or None. If not None, specifies a rectangular hole of size `hole_dia * hole_rect_h` instead of a round hole.
+
+`unit`
+ LengthUnit_ for all of this aperture's fields
+
+`attrs`
+ GerberX2 attributes of this aperture. Note that this will only contain aperture attributes, not file attributes.
+ File attributes are stored in the `attrs` of GerberFile_.
+
+`original_number`
+ int of aperture index this aperture had when it was read from the Gerber file. This field is purely informational
+ since apertures are de-duplicated and re-numbered when writing a Gerber file. For `D10`, this field would be `10`.
+ If you programmatically create a new aperture, you do not have to set this.
+
+`rotation`
+ Aperture rotation in radians counter-clockwise. This field is not part of the Gerber standard. Standard rectangle
+ and obround apertures do not support rotation. Gerbonara converts rotated apertures into aperture macros during
+ Gerber export as necessary.
+
+CircleAperture
+--------------
+
+This is the only one valid for use in Line_ or Arc_.
+
+Attributes:
+
+Common attributes:
+ `hole_dia`, `hole_rect_h`, `unit`, `attrs`, and `original_number`. `rotation` is present but has no effect in
+ CircleAperture_.
+
+`diameter`
+ float with diameter of aperture in the unit from the aperture's `unit` field.
+
+RectangleAperture
+-----------------
+
+Common attributes:
+ `hole_dia`, `hole_rect_h`, `unit`, `attrs`, `original_number`, and `rotation`
+
+`w`, `h`
+ floats with width or height of rectangle in units from the aperture's `unit` field.
+
+ObroundAperture
+---------------
+
+Aperture whose shape is the convex hull of two circles of equal radii.
+
+Common attributes:
+ `hole_dia`, `hole_rect_h`, `unit`, `attrs`, `original_number`, and `rotation`
+
+`w`, `h`
+ floats with width and height of bounding box of obround. The smaller one of these will be the diameter of the
+ obround's ends. If `w` is larger, the result will be a landscape obround. If `h` is larger, it will be a portrait
+ obround.
+
+PolygonAperture
+---------------
+
+Aperture whose shape is a regular n-sided polygon (e.g. pentagon, hexagon etc.).
+
+
+Common attributes:
+ `hole_dia`, `unit`, `attrs`, `original_number`, and `rotation`. `hole_rect_h` is not supported in PolygonAperture_
+ since the Gerber spec does not list it.
+
+`diameter`
+ float with diameter of circumscribing circle, i.e. the circle that all the polygon's corners lie on.
+
+`n_vertices`
+ int with number of corners of this polygon. Three for a triangle, four for a square, five for a pentagon etc.
+
+ApertureMacroInstance
+---------------------
+
+One instance of an aperture macro. An aperture macro defined with an `AM` statement can be instantiated by multiple `AD`
+aperture definition statements using different parameters. An ApertureMacroInstance_ is one such binding of a macro to a
+particular set of parameters. Note that you still need an ApertureMacroInstance_ even if your ApertureMacro_ has no
+parameters since an ApertureMacro_ is not an Aperture_ by itself.
+
+Attributes:
+
+Common attributes:
+ `unit`, `attrs`, `original_number`, and `rotation`. ApertureMacroInstance_ does not support `hole_dia` or
+ `hole_rect_h`. `rotation` is handled by re-writing the ApertureMacro_ during export.
+
+`macro`
+ The ApertureMacro_ that is bound here
+
+`parameters`
+ list of ints or floats with the parameters for this macro. The first element is `$1`, the second is `$2` etc.
+
+ExcellonTool
+------------
+
+Special Aperture_ subclass for use in ExcellonFile_. Similar to CircleAperture_, but does not have `hole_dia` or
+`hole_rect_h`, and has additional `plated` and `depth_offset` attributes.
+
+
+Common attributes:
+ `unit`, `original_number`
+
+`plated`
+ bool or None. True if this hole/slot is copper-plated, False if not, and None if it is undefined or unknown.
+
+`depth_offset`
+ float with Excellon depth offset for this hole or slot. If the fab supports this, this can be used to create
+ features that do not go all the way through the board.
+
+Aperture generalization
+-----------------------
+
+Gerbonara supports rotating both individual graphic objects and whole files. Alas, this was not a use case that was
+intended when the Gerber format was developed. We can rotate lines, arcs, and regions alright by simply rotatint all of
+their points. Flashes are where things get tricky: Individual flashes cannot be rotated at all in any widely supported
+way. There are some newer additions to the standard, but I would be surprised if any of the cheap board houses
+understand those. The only way to rotate a flash is to rotate the aperture, not the flash. For cirlces, this is a no-op.
+For polygons, we simply change the angle parameter. However, for rectangles and obrounds this gets tricky: Neither one
+supports a rotation parameter. The only way to rotate these is to convert them to an aperture macro, then rotate that.
+
+This behavior of using aperture macros for general rotated rectangles is common behavior among CAD tools. Gerbonara adds
+a non-standard `rotation` attribute to all apertures except CircleAperture_ and transparently converts rotated instances
+to the appropriate ApertureMacroInstance_ objects while it writes out the file. Be aware that this may mean that an
+object that in memory has a RectangleAperture_ might end up with an aperture macro instance in the output Gerber file.
+
diff --git a/docs/api-concepts.rst b/docs/api-concepts.rst
new file mode 100644
index 0000000..075498b
--- /dev/null
+++ b/docs/api-concepts.rst
@@ -0,0 +1,60 @@
+Gerbonara API concepts
+======================
+
+High-level overview
+-------------------
+
+Gerbonara's API is split into three larger sub-areas:
+
+**File API**
+ This is where the main user interface classes live: :py:class:`.LayerStack` (for opening a directory/zip full of
+ files, and automatically matching file roles based on filenames), :py:class:`.GerberFile` (for opening an individual
+ RS-274X file), :py:class:`.ExcellonFile` (for Excellon drill files) and :py:class:`.Netlist` (for IPC-356 netlist
+ files).
+
+**Graphic Object API**
+ This is where the nuts and bolts inside a :py:class:`.GerberFile` or :py:class:`.ExcellonFile` such as
+ :py:class:`~.graphic_objects.Line`, :py:class:`~.graphic_objects.Arc`, :py:class:`.Region` and :py:class:`.Flash`
+ live. Everything in here has explicit unit support. A part of the Graphic object API is the :doc:`Aperture
+ API<apertures>`.
+
+**Graphic Primitive API**
+ This is a rendering abstraction layer. Graphic objects can be converted into graphic primitives for rendering.
+ Graphic primitives are unit-less. Units are converted during :py:class:`.GraphicObject` to
+ :py:class:`.GraphicPrimitive` rendering.
+
+The hierarchy works like: A :py:class:`.LayerStack` contains either a :py:class:`.GerberFile`, an
+:py:class:`.ExcellonFile` or a :py:class:`.Netlist` for each layer. Each of these file objects contains a number of
+:py:class:`.GraphicObject` instances such as :py:class:`~.graphic_objects.Line` or :py:class:`.Flash`. These objects can
+easily be changed or deleted, and new ones can be created programmatically. For rendering, each of these objects as well
+as file objects can be rendered into :py:class:`.GraphicPrimitive` instances using
+:py:meth:`.GraphicObject.to_primitives`.
+
+Apertures
+---------
+
+Gerber apertures are represented by subclasses of :py:class:`.Aperture` such as :py:class:`.CircleAperture`. An instance
+of an aperture class is stored inside the :py:attr:`~.graphic_objects.Line.aperture` field of a
+:py:class:`.GraphicObject`. :py:class:`.GraphicObject` subclasses that have an aperture are
+:py:class:`~.graphic_objects.Line`, :py:class:`~.graphic_objects.Arc` and :py:class:`.Flash`. You can create and
+duplicate :py:class:`.Aperture` objects as needed. They are automatically de-duplicated when a Gerber file is written.
+
+Gerbonara has full aperture macro support. Each aperture macro is represented by an :py:class:`.parse.ApertureMacro`
+instance. Like apertures, :py:class:`.parse.ApertureMacro` instances are de-duplicated when writing a file. An aperture
+macro-based aperture definition is represented by the :py:class:`.ApertureMacroInstance` subclass of
+:py:class:`.Aperture`. An aperture macro instance basically binds an aperture macro to a given set of macro parameters.
+Note that even if a macro does not accept any parameters you still cannot directly stick it into the aperture field of a
+graphic object, and instead need to wrap it inside an :py:class:`.ApertureMacroInstance` first.
+
+Excellon vs. Gerber
+-------------------
+
+Excellon files use the same graphic object classes as Gerber files. Inside an Excellon file, only
+:py:class:`~.graphic_objects.Line`, :py:class:`~.graphic_objects.Arc` and :py:class:`.Flash` are allowed. Lines and arcs map to milled
+Excellon slots. Excellon drills are mapped to :py:class:`.Flash` instances.
+
+Excellon drills are internally handled using a special :py:class:`.ExcellonTool` aperture class. When you put a
+:py:class:`.GraphicObject` from an Excellon file into a Gerber file, these become circular apertures. You can also take
+objects from an Excellon file and put them into a Gerber file if they have a simple :py:class:`.CircleAperture`. Copying
+objects with other apertures into an Excellon file will raise an error when saving.
+
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..915f0dc
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,57 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+
+from pathlib import Path
+import sys
+sys.path.insert(0, str(Path(__file__).parent.parent.absolute()))
+
+# -- Project information -----------------------------------------------------
+
+project = 'gerbonara'
+copyright = '2022, Jan Götte'
+author = 'jaseg'
+
+# The full version, including alpha/beta/rc tags
+release = '0.9.0'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+]
+
+autodoc_member_order = 'groupwise'
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
diff --git a/docs/file-api.rst b/docs/file-api.rst
new file mode 100644
index 0000000..d73b5f1
--- /dev/null
+++ b/docs/file-api.rst
@@ -0,0 +1,25 @@
+Layers and Files
+================
+
+Gerbonara currently supports three file types: RS-274-X Gerber as `specified by Ucamco
+<https://www.ucamco.com/en/gerber>`:py:class:`._` through :py:class:`.GerberFile`, Excellon/XNC through
+:py:class:`.ExcellonFile`, and IPC-356 netlists through :py:class:`.Netlist`.
+
+Usually, a PCB is sent to a manufacturer as a bundle of several of these files. Such a bundle of files (each of which is
+either a :py:class:`.GerberFile` or an :py:class:`.ExcellonFile`) is represented by :py:class:`.LayerStack`.
+:py:class:`.LayerStack` contains logic to automatcally
+recognize a wide variety of CAD tools from file name and syntactic hints, and can automatically match all files in a
+folder to their appropriate layers.
+
+.. autoclass:: gerbonara.layers.LayerStack
+ :members:
+
+.. autoclass:: gerbonara.rs274x.GerberFile
+ :members:
+
+.. autoclass:: gerbonara.excellon.ExcellonFile
+ :members:
+
+.. autoclass:: gerbonara.ipc356.Netlist
+ :members:
+
diff --git a/docs/graphic-primitive-api.rst b/docs/graphic-primitive-api.rst
new file mode 100644
index 0000000..d506e87
--- /dev/null
+++ b/docs/graphic-primitive-api.rst
@@ -0,0 +1,27 @@
+Graphic Primitives
+==================
+
+.. autoclass:: gerbonara.graphic_primitives.GraphicPrimitive
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.Circle
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.Obround
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.ArcPoly
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.Line
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.Arc
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.Rectangle
+ :members:
+
+.. autoclass:: gerbonara.graphic_primitives.RegularPolygon
+ :members:
+
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..55d2456
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,115 @@
+Welcome to gerbonara's documentation!
+=====================================
+
+Gerbonara is a library to read, modify and write PCB manufacturing files such as Gerber, Excellon and IPC-356 through a
+pythonic API. Gerbonara can open a folder of manufacturing files, and parse file names and metadata to figure out which
+file contains what. Gerbonara is tested using an extensive library of real-world example files from CAD tools including
+KiCAD, Altium, Eagle, Allegro, gEDA, Fritzing, Siemens/Mentor Graphics PADS, and Target3001!.
+
+Gerbonara's API is built on two principles:
+
+**Meaningful, object-oriented API**
+ Gerbonara abstracts away the details of the underlying file format such as tool indices, coordinate notation and
+ graphical state, and presents meaningful "graphical objects" such as a :py:class:`~primitives.Line`,
+ :py:class:`~primitives.Arc`, or :py:class:`.Region` through its API. These objects can be easily created,
+ manipulated or deleted from code without breaking anything else. You can even copy graphical objects between files,
+ and Gerbonara will automatically convert coordinate format, units etc. for you. :py:class:`.GerberFile` and
+ :py:class:`.ExcellonFile` use the same types of :doc:`graphic objects <object-api>`, so objects can be directly
+ copied between file types without conversion.
+
+**Unit-safety**
+ Gerbonara embeds physical :py:class:`.LengthUnit` information in all objects. The high-level API such as
+ :py:meth:`.LayerStack.merge` or :py:meth:`.GerberFile.offset` accepts arguments with an explicitly given unit and
+ automatically converts them as needed. Objects can be copied between :py:class:`.GerberFile` instances and unit
+ conversion will be handled transparently in the background.
+
+Gerbonara was started as an extensive refactoring of the pcb-tools_ and pcb-tools-extension_ packages. Both of these
+have statement-based APIs, that is, they parse input files into one python object for every line in the file. This means
+that when saving files they can recreate the input file almost byte by byte, but manipulating a file by changing
+statements without breaking things is *hard*.
+
+Gerbonara powers gerbolyze_, a tool for converting SVG_ vector graphics files into Gerber, and embedding SVG_ into
+existing Gerber files exported from a normal PCB tool for artistic purposes.
+
+Features
+========
+
+ * File I/O
+ * Gerber, Excellon (drill file), IPC-356 (netlist) read and write
+ * supports file-level operations: offset, rotate, merge for all file types
+ * Modification API (:py:class:`GraphicObject`)
+ * Rendering API (:py:class:`GraphicPrimitive`)
+ * SVG export
+ * Full aperture macro support, including transformations (offset, rotation)
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ api-concepts
+ file-api
+ object-api
+ apertures
+ aperture-macros
+ graphic-primitive-api
+ utilities
+
+Quick Start
+===========
+
+
+
+Development
+===========
+
+Gerbonara is developed on Gitlab under the gerbolyze org:
+
+https://gitlab.com/gerbolyze/gerbonara/
+
+A mirror of the repository can be found at:
+
+https://git.jaseg.de/gerbonara
+
+Our issue tracker is also on Gitlab:
+
+https://gitlab.com/gerbolyze/gerbonara/-/issues
+
+With Gebronara, we aim to support as many different format variants as possible. If you have a file that Gerbonara can't
+open, please file an issue on our issue tracker. Even if Gerbonara can open all your files, for regression testing we
+are very interested in example files generated by any CAD or CAM tool that is not already on the list of supported
+tools.
+
+Supported CAD Tools
+===================
+
+Compatibility with the output of these CAD tools is tested as part of our test suite using example files generated by
+these tools. Note that not all of these tools come with default Gerber file naming rules, so YMMV if your Gerbers use
+some non-standard naming convention.
+
+ * Allegro
+ * Altium
+ * Diptrace
+ * Eagle
+ * EasyEDA
+ * Fritzing
+ * gEDA
+ * KiCAD
+ * pcb-rnd
+ * Siemens / Mentor Graphics Xpedition
+ * Siemens / Mentor Graphics PADS
+ * Target 3001!
+ * Upverter
+ * Soon: Zuken CADSTAR and CR-8000
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+.. _pcb-tools: https://github.com/opiopan/pcb-tools-extension
+.. _pcb-tools-extension: https://github.com/curtacircuitos/pcb-tools/issues
+.. _gerbolyze: https://github.com/jaseg/gerbolyze
+.. _SVG: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
+
diff --git a/docs/object-api.rst b/docs/object-api.rst
new file mode 100644
index 0000000..f6345b9
--- /dev/null
+++ b/docs/object-api.rst
@@ -0,0 +1,30 @@
+Graphic Objects
+===============
+
+Graphic objects are the lego blocks a gerbonara :py:class:`gerbonara.rs274x.GerberFile` or
+:py:class:`gerbonara.excellon.ExcellonFile` is built from. They are stored in the file's
+:py:attr:`gerbonara.rs274x.GerberFile.objects` list. You can directly manipulate that list from code.
+
+There are four graphic object types: :py:class:`gerbonara.graphic_objects.Flash`,
+:py:class:`gerbonara.graphic_objects.Line`, :py:class:`gerbonara.graphic_objects.Arc`, and
+:py:class:`gerbonara.graphic_objects.Region` . All of them are derived from
+:py:class:`gerbonara.graphic_objects.GraphicObject`.
+
+.. autoclass:: gerbonara.graphic_objects.GraphicObject
+ :members:
+
+.. autoclass:: gerbonara.graphic_objects.Flash
+ :members:
+
+.. autoclass:: gerbonara.graphic_objects.Line
+ :members:
+
+.. autoclass:: gerbonara.graphic_objects.Arc
+ :members:
+
+.. autoclass:: gerbonara.graphic_objects.Region
+ :members:
+
+.. _pcb-tools: https://github.com/opiopan/pcb-tools-extension
+.. _gerbolyze: https://github.com/jaseg/gerbolyze
+.. _svg-flatten: https://github.com/jaseg/gerbolyze/tree/main/svg-flatten
diff --git a/docs/utilities.rst b/docs/utilities.rst
new file mode 100644
index 0000000..89b1cde
--- /dev/null
+++ b/docs/utilities.rst
@@ -0,0 +1,3 @@
+Utilities
+=========
+