summaryrefslogtreecommitdiff
path: root/gerber/pcb.py
diff options
context:
space:
mode:
authorHamilton Kibbe <hamilton.kibbe@gmail.com>2015-12-22 02:45:48 -0500
committerHamilton Kibbe <hamilton.kibbe@gmail.com>2015-12-22 02:47:23 -0500
commit6f876edd09d9b81649691e529f85653f14b8fd1c (patch)
tree808e3ea789816452f52e834d4c5c1744bdee6541 /gerber/pcb.py
parentaf5541ac93b222c05229ee05c9def8dbae5f6e25 (diff)
downloadgerbonara-6f876edd09d9b81649691e529f85653f14b8fd1c.tar.gz
gerbonara-6f876edd09d9b81649691e529f85653f14b8fd1c.tar.bz2
gerbonara-6f876edd09d9b81649691e529f85653f14b8fd1c.zip
Add PCB interface
this incorporates some of @chintal's layers.py changes PCB.from_directory() simplifies loading of multiple gerbers the PCB() class should be pretty helpful going forward... the context classes could use some cleaning up, although I'd like to wait until the freecad stuff gets merged, that way we can try to refactor the context base to support more use cases
Diffstat (limited to 'gerber/pcb.py')
-rw-r--r--gerber/pcb.py107
1 files changed, 107 insertions, 0 deletions
diff --git a/gerber/pcb.py b/gerber/pcb.py
new file mode 100644
index 0000000..990a05c
--- /dev/null
+++ b/gerber/pcb.py
@@ -0,0 +1,107 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# copyright 2015 Hamilton Kibbe <ham@hamiltonkib.be>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import os
+from .exceptions import ParseError
+from .layers import PCBLayer, LayerSet, sort_layers
+from .common import read as gerber_read
+from .utils import listdir
+from .render import theme
+
+
+class PCB(object):
+
+ @classmethod
+ def from_directory(cls, directory, board_name=None, verbose=False):
+ layers = []
+ names = set()
+ # Validate
+ directory = os.path.abspath(directory)
+ if not os.path.isdir(directory):
+ raise TypeError('{} is not a directory.'.format(directory))
+ # Load gerber files
+ for filename in listdir(directory, True, True):
+ try:
+ camfile = gerber_read(os.path.join(directory, filename))
+ layer = PCBLayer.from_gerber(camfile)
+ layers.append(layer)
+ names.add(os.path.splitext(filename)[0])
+ if verbose:
+ print('Added {} layer <{}>'.format(layer.layer_class, filename))
+ except ParseError:
+ if verbose:
+ print('Skipping file {}'.format(filename))
+ # Try to guess board name
+ if board_name is None:
+ if len(names) == 1:
+ board_name = names.pop()
+ else:
+ board_name = os.path.basename(directory)
+ # Return PCB
+ return cls(layers, board_name)
+
+ def __init__(self, layers, name=None):
+ self.layers = sort_layers(layers)
+ self.name = name
+ self._theme = theme.THEMES['Default']
+ self.theme = self._theme
+
+ def __len__(self):
+ return len(self.layers)
+
+ @property
+ def theme(self):
+ return self._theme
+
+ @theme.setter
+ def theme(self, theme):
+ self._theme = theme
+ for layer in self.layers:
+ layer.settings = theme[layer.layer_class]
+
+ @property
+ def top_layers(self):
+ board_layers = [l for l in reversed(self.layers) if l.layer_class in ('topsilk', 'topmask', 'top')]
+ drill_layers = [l for l in self.drill_layers if 'top' in l.layers]
+ return board_layers + drill_layers
+
+ @property
+ def bottom_layers(self):
+ board_layers = [l for l in self.layers if l.layer_class in ('bottomsilk', 'bottommask', 'bottom')]
+ drill_layers = [l for l in self.drill_layers if 'bottom' in l.layers]
+ return board_layers + drill_layers
+
+ @property
+ def drill_layers(self):
+ return [l for l in self.layers if l.layer_class == 'drill']
+
+ @property
+ def layer_count(self):
+ """ Number of *COPPER* layers
+ """
+ return len([l for l in self.layers if l.layer_class in ('top', 'bottom', 'internal')])
+
+ @property
+ def board_bounds(self):
+ for layer in self.layers:
+ if layer.layer_class == 'outline':
+ return layer.bounds
+ for layer in self.layers:
+ if layer.layer_class == 'top':
+ return layer.bounds
+