summaryrefslogtreecommitdiff
path: root/gerber/primitives.py
diff options
context:
space:
mode:
Diffstat (limited to 'gerber/primitives.py')
-rw-r--r--gerber/primitives.py414
1 files changed, 216 insertions, 198 deletions
diff --git a/gerber/primitives.py b/gerber/primitives.py
index a291c26..bd93e04 100644
--- a/gerber/primitives.py
+++ b/gerber/primitives.py
@@ -16,14 +16,14 @@
# limitations under the License.
-
import math
from operator import add
from itertools import combinations
-from .utils import validate_coordinates, inch, metric, convex_hull, rotate_point, nearly_equal
+from .utils import validate_coordinates, inch, metric, convex_hull
+from .utils import rotate_point, nearly_equal
+
-
class Primitive(object):
""" Base class for all Cam file primitives
@@ -50,9 +50,8 @@ class Primitive(object):
def __init__(self, level_polarity='dark', rotation=0, units=None, net_name=None):
self.level_polarity = level_polarity
- self.net_name = net_name
- self._to_convert = list()
- self.id = id
+ self.net_name = net_name
+ self._to_convert = list()
self._memoized = list()
self._units = units
self._rotation = rotation
@@ -60,21 +59,21 @@ class Primitive(object):
self._sin_theta = math.sin(math.radians(rotation))
self._bounding_box = None
self._vertices = None
- self._segments = None
-
+ self._segments = None
+
@property
def flashed(self):
'''Is this a flashed primitive'''
-
+
raise NotImplementedError('Is flashed must be '
- 'implemented in subclass')
+ 'implemented in subclass')
def __eq__(self, other):
return self.__dict__ == other.__dict__
-
+
@property
def units(self):
- return self._units
+ return self._units
@units.setter
def units(self, value):
@@ -84,7 +83,7 @@ class Primitive(object):
@property
def rotation(self):
return self._rotation
-
+
@rotation.setter
def rotation(self, value):
self._changed()
@@ -103,7 +102,7 @@ class Primitive(object):
self._segments = [segment for segment in
combinations(self.vertices, 2)]
return self._segments
-
+
@property
def bounding_box(self):
""" Calculate axis-aligned bounding box
@@ -114,14 +113,14 @@ class Primitive(object):
"""
raise NotImplementedError('Bounding box calculation must be '
'implemented in subclass')
-
+
@property
def bounding_box_no_aperture(self):
""" Calculate bouxing box without considering the aperture
-
+
for most objects, this is the same as the bounding_box, but is different for
Lines and Arcs (which are not flashed)
-
+
Return ((min x, max x), (min y, max y))
"""
return self.bounding_box
@@ -175,7 +174,7 @@ class Primitive(object):
except:
if value is not None:
setattr(self, attr, metric(value))
-
+
def offset(self, x_offset=0, y_offset=0):
""" Move the primitive by the specified x and y offset amount.
@@ -186,7 +185,7 @@ class Primitive(object):
self.position = tuple([coord + offset for coord, offset
in zip(self.position,
(x_offset, y_offset))])
-
+
def to_statement(self):
pass
@@ -201,7 +200,7 @@ class Primitive(object):
self._bounding_box = None
self._vertices = None
self._segments = None
- for attr in self._memoized:
+ for attr in self._memoized:
setattr(self, attr, None)
class Line(Primitive):
@@ -214,8 +213,8 @@ class Line(Primitive):
self._end = end
self.aperture = aperture
self._to_convert = ['start', 'end', 'aperture']
-
- @property
+
+ @property
def flashed(self):
return False
@@ -244,8 +243,8 @@ class Line(Primitive):
angle = math.atan2(delta_y, delta_x)
return angle
- @property
- def bounding_box(self):
+ @property
+ def bounding_box(self):
if self._bounding_box is None:
if isinstance(self.aperture, Circle):
width_2 = self.aperture.radius
@@ -267,7 +266,7 @@ class Line(Primitive):
max_x = max(self.start[0], self.end[0])
min_y = min(self.start[1], self.end[1])
max_y = max(self.start[1], self.end[1])
- return ((min_x, max_x), (min_y, max_y))
+ return ((min_x, max_x), (min_y, max_y))
@property
def vertices(self):
@@ -291,30 +290,30 @@ class Line(Primitive):
# The line is defined by the convex hull of the points
self._vertices = convex_hull((start_ll, start_lr, start_ul, start_ur, end_ll, end_lr, end_ul, end_ur))
return self._vertices
-
+
def offset(self, x_offset=0, y_offset=0):
- self._changed()
+ self._changed()
self.start = tuple([coord + offset for coord, offset
in zip(self.start, (x_offset, y_offset))])
self.end = tuple([coord + offset for coord, offset
in zip(self.end, (x_offset, y_offset))])
-
+
def equivalent(self, other, offset):
-
+
if not isinstance(other, Line):
return False
-
+
equiv_start = tuple(map(add, other.start, offset))
- equiv_end = tuple(map(add, other.end, offset))
-
+ equiv_end = tuple(map(add, other.end, offset))
+
return nearly_equal(self.start, equiv_start) and nearly_equal(self.end, equiv_end)
class Arc(Primitive):
"""
"""
-
- def __init__(self, start, end, center, direction, aperture, quadrant_mode, **kwargs):
+
+ def __init__(self, start, end, center, direction, aperture, quadrant_mode, **kwargs):
super(Arc, self).__init__(**kwargs)
self._start = start
self._end = end
@@ -324,10 +323,10 @@ class Arc(Primitive):
self._quadrant_mode = quadrant_mode
self._to_convert = ['start', 'end', 'center', 'aperture']
- @property
+ @property
def flashed(self):
return False
-
+
@property
def start(self):
return self._start
@@ -354,11 +353,11 @@ class Arc(Primitive):
def center(self, value):
self._changed()
self._center = value
-
+
@property
def quadrant_mode(self):
return self._quadrant_mode
-
+
@quadrant_mode.setter
def quadrant_mode(self, quadrant_mode):
self._changed()
@@ -436,8 +435,8 @@ class Arc(Primitive):
min_y = min(y) - self.aperture.radius
max_y = max(y) + self.aperture.radius
self._bounding_box = ((min_x, max_x), (min_y, max_y))
- return self._bounding_box
-
+ return self._bounding_box
+
@property
def bounding_box_no_aperture(self):
'''Gets the bounding box without considering the aperture'''
@@ -472,12 +471,12 @@ class Arc(Primitive):
if theta1 <= math.pi * 1.5 and (theta0 >= math.pi * 1.5 or theta0 < theta1):
points.append((self.center[0], self.center[1] - self.radius ))
x, y = zip(*points)
-
+
min_x = min(x)
max_x = max(x)
min_y = min(y)
max_y = max(y)
- return ((min_x, max_x), (min_y, max_y))
+ return ((min_x, max_x), (min_y, max_y))
def offset(self, x_offset=0, y_offset=0):
self._changed()
@@ -489,19 +488,19 @@ class Arc(Primitive):
class Circle(Primitive):
"""
"""
-
- def __init__(self, position, diameter, hole_diameter = None, **kwargs):
+
+ def __init__(self, position, diameter, hole_diameter = None, **kwargs):
super(Circle, self).__init__(**kwargs)
validate_coordinates(position)
self._position = position
- self._diameter = diameter
+ self._diameter = diameter
self.hole_diameter = hole_diameter
- self._to_convert = ['position', 'diameter', 'hole_diameter']
+ self._to_convert = ['position', 'diameter', 'hole_diameter']
- @property
+ @property
def flashed(self):
return True
-
+
@property
def position(self):
return self._position
@@ -523,7 +522,7 @@ class Circle(Primitive):
@property
def radius(self):
return self.diameter / 2.
-
+
@property
def hole_radius(self):
if self.hole_diameter != None:
@@ -538,29 +537,28 @@ class Circle(Primitive):
min_y = self.position[1] - self.radius
max_y = self.position[1] + self.radius
self._bounding_box = ((min_x, max_x), (min_y, max_y))
- return self._bounding_box
-
+ return self._bounding_box
+
def offset(self, x_offset=0, y_offset=0):
self.position = tuple(map(add, self.position, (x_offset, y_offset)))
-
+
def equivalent(self, other, offset):
'''Is this the same as the other circle, ignoring the offiset?'''
if not isinstance(other, Circle):
return False
-
+
if self.diameter != other.diameter or self.hole_diameter != other.hole_diameter:
return False
-
+
equiv_position = tuple(map(add, other.position, offset))
- return nearly_equal(self.position, equiv_position)
+ return nearly_equal(self.position, equiv_position)
class Ellipse(Primitive):
"""
"""
-
def __init__(self, position, width, height, **kwargs):
super(Ellipse, self).__init__(**kwargs)
validate_coordinates(position)
@@ -568,19 +566,19 @@ class Ellipse(Primitive):
self._width = width
self._height = height
self._to_convert = ['position', 'width', 'height']
-
- @property
+
+ @property
def flashed(self):
return True
-
+
@property
def position(self):
return self._position
-
+
@position.setter
def position(self, value):
self._changed()
- self._position = value
+ self._position = value
@property
def width(self):
@@ -626,29 +624,29 @@ class Ellipse(Primitive):
class Rectangle(Primitive):
- """
+ """
When rotated, the rotation is about the center point.
-
+
Only aperture macro generated Rectangle objects can be rotated. If you aren't in a AMGroup,
then you don't need to worry about rotation
"""
-
- def __init__(self, position, width, height, hole_diameter=0, **kwargs):
+
+ def __init__(self, position, width, height, hole_diameter=0, **kwargs):
super(Rectangle, self).__init__(**kwargs)
validate_coordinates(position)
self._position = position
self._width = width
- self._height = height
+ self._height = height
self.hole_diameter = hole_diameter
self._to_convert = ['position', 'width', 'height', 'hole_diameter']
# TODO These are probably wrong when rotated
self._lower_left = None
self._upper_right = None
-
- @property
+
+ @property
def flashed(self):
return True
-
+
@property
def position(self):
return self._position
@@ -658,14 +656,14 @@ class Rectangle(Primitive):
self._changed()
self._position = value
- @property
+ @property
def width(self):
return self._width
@width.setter
def width(self, value):
self._changed()
- self._width = value
+ self._width = value
@property
def height(self):
@@ -675,7 +673,7 @@ class Rectangle(Primitive):
def height(self, value):
self._changed()
self._height = value
-
+
@property
def hole_radius(self):
"""The radius of the hole. If there is no hole, returns None"""
@@ -683,12 +681,12 @@ class Rectangle(Primitive):
return self.hole_diameter / 2.
return None
- @property
+ @property
def upper_right(self):
- return (self.position[0] + (self._abs_width / 2.),
- self.position[1] + (self._abs_height / 2.))
+ return (self.position[0] + (self.axis_aligned_width / 2.),
+ self.position[1] + (self.axis_aligned_height / 2.))
- @property
+ @property
def lower_left(self):
return (self.position[0] - (self.axis_aligned_width / 2.),
self.position[1] - (self.axis_aligned_height / 2.))
@@ -721,27 +719,22 @@ class Rectangle(Primitive):
def axis_aligned_width(self):
return (self._cos_theta * self.width + self._sin_theta * self.height)
- @property
- def _abs_height(self):
- return (math.cos(math.radians(self.rotation)) * self.height +
- math.sin(math.radians(self.rotation)) * self.width)
-
- @property
+ @property
def axis_aligned_height(self):
return (self._cos_theta * self.height + self._sin_theta * self.width)
-
+
def equivalent(self, other, offset):
"""Is this the same as the other rect, ignoring the offset?"""
if not isinstance(other, Rectangle):
return False
-
+
if self.width != other.width or self.height != other.height or self.rotation != other.rotation or self.hole_diameter != other.hole_diameter:
return False
-
+
equiv_position = tuple(map(add, other.position, offset))
- return nearly_equal(self.position, equiv_position)
+ return nearly_equal(self.position, equiv_position)
class Diamond(Primitive):
@@ -755,8 +748,8 @@ class Diamond(Primitive):
self._width = width
self._height = height
self._to_convert = ['position', 'width', 'height']
-
- @property
+
+ @property
def flashed(self):
return True
@@ -767,7 +760,7 @@ class Diamond(Primitive):
@position.setter
def position(self, value):
self._changed()
- self._position = value
+ self._position = value
@property
def width(self):
@@ -778,7 +771,7 @@ class Diamond(Primitive):
self._changed()
self._width = value
- @property
+ @property
def height(self):
return self._height
@@ -823,18 +816,17 @@ class Diamond(Primitive):
class ChamferRectangle(Primitive):
"""
"""
-
- def __init__(self, position, width, height, chamfer, corners, **kwargs):
+ def __init__(self, position, width, height, chamfer, corners=None, **kwargs):
super(ChamferRectangle, self).__init__(**kwargs)
validate_coordinates(position)
self._position = position
self._width = width
self._height = height
self._chamfer = chamfer
- self._corners = corners
+ self._corners = corners if corners is not None else [True] * 4
self._to_convert = ['position', 'width', 'height', 'chamfer']
-
- @property
+
+ @property
def flashed(self):
return True
@@ -895,7 +887,37 @@ class ChamferRectangle(Primitive):
@property
def vertices(self):
- # TODO
+ if self._vertices is None:
+ vertices = []
+ delta_w = self.width / 2.
+ delta_h = self.height / 2.
+ # order is UR, UL, LL, LR
+ rect_corners = [
+ ((self.position[0] + delta_w), (self.position[1] + delta_h)),
+ ((self.position[0] - delta_w), (self.position[1] + delta_h)),
+ ((self.position[0] - delta_w), (self.position[1] - delta_h)),
+ ((self.position[0] + delta_w), (self.position[1] - delta_h))
+ ]
+ for idx, corner, chamfered in enumerate((rect_corners, self.corners)):
+ x, y = corner
+ if chamfered:
+ if idx == 0:
+ vertices.append((x - self.chamfer, y))
+ vertices.append((x, y - self.chamfer))
+ elif idx == 1:
+ vertices.append((x + self.chamfer, y))
+ vertices.append((x, y - self.chamfer))
+ elif idx == 2:
+ vertices.append((x + self.chamfer, y))
+ vertices.append((x, y + self.chamfer))
+ elif idx == 3:
+ vertices.append((x - self.chamfer, y))
+ vertices.append((x, y + self.chamfer))
+ else:
+ vertices.append(corner)
+ self._vertices = [((x * self._cos_theta - y * self._sin_theta),
+ (x * self._sin_theta + y * self._cos_theta))
+ for x, y in vertices]
return self._vertices
@property
@@ -922,8 +944,8 @@ class RoundRectangle(Primitive):
self._radius = radius
self._corners = corners
self._to_convert = ['position', 'width', 'height', 'radius']
-
- @property
+
+ @property
def flashed(self):
return True
@@ -952,7 +974,7 @@ class RoundRectangle(Primitive):
@height.setter
def height(self, value):
self._changed()
- self._height = value
+ self._height = value
@property
def radius(self):
@@ -987,28 +1009,28 @@ class RoundRectangle(Primitive):
return (self._cos_theta * self.width +
self._sin_theta * self.height)
- @property
+ @property
def axis_aligned_height(self):
return (self._cos_theta * self.height +
self._sin_theta * self.width)
class Obround(Primitive):
- """
"""
-
- def __init__(self, position, width, height, hole_diameter=0, **kwargs):
+ """
+
+ def __init__(self, position, width, height, hole_diameter=0, **kwargs):
super(Obround, self).__init__(**kwargs)
validate_coordinates(position)
self._position = position
self._width = width
- self._height = height
+ self._height = height
self.hole_diameter = hole_diameter
self._to_convert = ['position', 'width', 'height', 'hole_diameter']
-
- @property
+
+ @property
def flashed(self):
- return True
+ return True
@property
def position(self):
@@ -1017,7 +1039,7 @@ class Obround(Primitive):
@position.setter
def position(self, value):
self._changed()
- self._position = value
+ self._position = value
@property
def width(self):
@@ -1028,11 +1050,6 @@ class Obround(Primitive):
self._changed()
self._width = value
- @property
- def upper_right(self):
- return (self.position[0] + (self._abs_width / 2.),
- self.position[1] + (self._abs_height / 2.))
-
@property
def height(self):
return self._height
@@ -1047,8 +1064,8 @@ class Obround(Primitive):
"""The radius of the hole. If there is no hole, returns None"""
if self.hole_diameter != None:
return self.hole_diameter / 2.
-
- return None
+
+ return None
@property
def orientation(self):
@@ -1096,31 +1113,31 @@ class Obround(Primitive):
class Polygon(Primitive):
- """
+ """
Polygon flash defined by a set number of sides.
- """
- def __init__(self, position, sides, radius, hole_diameter, **kwargs):
+ """
+ def __init__(self, position, sides, radius, hole_diameter, **kwargs):
super(Polygon, self).__init__(**kwargs)
validate_coordinates(position)
self._position = position
- self.sides = sides
+ self.sides = sides
self._radius = radius
self.hole_diameter = hole_diameter
self._to_convert = ['position', 'radius', 'hole_diameter']
-
- @property
+
+ @property
def flashed(self):
return True
-
+
@property
def diameter(self):
return self.radius * 2
-
+
@property
def hole_radius(self):
if self.hole_diameter != None:
return self.hole_diameter / 2.
- return None
+ return None
@property
def position(self):
@@ -1129,7 +1146,7 @@ class Polygon(Primitive):
@position.setter
def position(self, value):
self._changed()
- self._position = value
+ self._position = value
@property
def radius(self):
@@ -1149,22 +1166,22 @@ class Polygon(Primitive):
max_y = self.position[1] + self.radius
self._bounding_box = ((min_x, max_x), (min_y, max_y))
return self._bounding_box
-
+
def offset(self, x_offset=0, y_offset=0):
self.position = tuple(map(add, self.position, (x_offset, y_offset)))
-
+
@property
def vertices(self):
-
+
offset = self.rotation
da = 360.0 / self.sides
-
+
points = []
for i in xrange(self.sides):
points.append(rotate_point((self.position[0] + self.radius, self.position[1]), offset + da * i, self.position))
-
+
return points
-
+
@property
def vertices(self):
if self._vertices is None:
@@ -1175,17 +1192,17 @@ class Polygon(Primitive):
self._vertices = [(((x * self._cos_theta) - (y * self._sin_theta)),
((x * self._sin_theta) + (y * self._cos_theta)))
for x, y in vertices]
- return self._vertices
+ return self._vertices
def equivalent(self, other, offset):
"""
Is this the outline the same as the other, ignoring the position offset?
"""
-
+
# Quick check if it even makes sense to compare them
if type(self) != type(other) or self.sides != other.sides or self.radius != other.radius:
return False
-
+
equiv_pos = tuple(map(add, other.position, offset))
return nearly_equal(self.position, equiv_pos)
@@ -1193,14 +1210,14 @@ class Polygon(Primitive):
class AMGroup(Primitive):
"""
- """
+ """
def __init__(self, amprimitives, stmt = None, **kwargs):
"""
-
+
stmt : The original statment that generated this, since it is really hard to re-generate from primitives
"""
super(AMGroup, self).__init__(**kwargs)
-
+
self.primitives = []
for amprim in amprimitives:
prim = amprim.to_primitive(self.units)
@@ -1212,11 +1229,11 @@ class AMGroup(Primitive):
self._position = None
self._to_convert = ['_position', 'primitives']
self.stmt = stmt
-
+
def to_inch(self):
if self.units == 'metric':
super(AMGroup, self).to_inch()
-
+
# If we also have a stmt, convert that too
if self.stmt:
self.stmt.to_inch()
@@ -1225,15 +1242,15 @@ class AMGroup(Primitive):
def to_metric(self):
if self.units == 'inch':
super(AMGroup, self).to_metric()
-
+
# If we also have a stmt, convert that too
if self.stmt:
self.stmt.to_metric()
-
+
@property
def flashed(self):
return True
-
+
@property
def bounding_box(self):
# TODO Make this cached like other items
@@ -1245,49 +1262,49 @@ class AMGroup(Primitive):
min_y = min(miny)
max_y = max(maxy)
return ((min_x, max_x), (min_y, max_y))
-
+
@property
def position(self):
return self._position
-
+
def offset(self, x_offset=0, y_offset=0):
self._position = tuple(map(add, self._position, (x_offset, y_offset)))
-
+
for primitive in self.primitives:
primitive.offset(x_offset, y_offset)
-
+
@position.setter
def position(self, new_pos):
'''
Sets the position of the AMGroup.
This offset all of the objects by the specified distance.
'''
-
+
if self._position:
dx = new_pos[0] - self._position[0]
dy = new_pos[1] - self._position[1]
else:
dx = new_pos[0]
dy = new_pos[1]
-
+
for primitive in self.primitives:
primitive.offset(dx, dy)
-
+
self._position = new_pos
-
+
def equivalent(self, other, offset):
'''
Is this the macro group the same as the other, ignoring the position offset?
'''
-
+
if len(self.primitives) != len(other.primitives):
return False
-
+
# We know they have the same number of primitives, so now check them all
for i in range(0, len(self.primitives)):
if not self.primitives[i].equivalent(other.primitives[i], offset):
return False
-
+
# If we didn't find any differences, then they are the same
return True
@@ -1296,16 +1313,16 @@ class Outline(Primitive):
Outlines only exist as the rendering for a apeture macro outline.
They don't exist outside of AMGroup objects
"""
-
+
def __init__(self, primitives, **kwargs):
super(Outline, self).__init__(**kwargs)
self.primitives = primitives
self._to_convert = ['primitives']
-
+
if self.primitives[0].start != self.primitives[-1].end:
raise ValueError('Outline must be closed')
-
- @property
+
+ @property
def flashed(self):
return True
@@ -1326,7 +1343,7 @@ class Outline(Primitive):
self._changed()
for p in self.primitives:
p.offset(x_offset, y_offset)
-
+
@property
def vertices(self):
if self._vertices is None:
@@ -1337,7 +1354,7 @@ class Outline(Primitive):
self._vertices = [(((x * self._cos_theta) - (y * self._sin_theta)),
((x * self._sin_theta) + (y * self._cos_theta)))
for x, y in vertices]
- return self._vertices
+ return self._vertices
@property
def width(self):
@@ -1348,15 +1365,15 @@ class Outline(Primitive):
'''
Is this the outline the same as the other, ignoring the position offset?
'''
-
+
# Quick check if it even makes sense to compare them
if type(self) != type(other) or len(self.primitives) != len(other.primitives):
return False
-
+
for i in range(0, len(self.primitives)):
if not self.primitives[i].equivalent(other.primitives[i], offset):
return False
-
+
return True
class Region(Primitive):
@@ -1367,13 +1384,13 @@ class Region(Primitive):
super(Region, self).__init__(**kwargs)
self.primitives = primitives
self._to_convert = ['primitives']
-
- @property
+
+ @property
def flashed(self):
return False
@property
- def bounding_box(self):
+ def bounding_box(self):
if self._bounding_box is None:
xlims, ylims = zip(*[p.bounding_box_no_aperture for p in self.primitives])
minx, maxx = zip(*xlims)
@@ -1383,7 +1400,7 @@ class Region(Primitive):
min_y = min(miny)
max_y = max(maxy)
self._bounding_box = ((min_x, max_x), (min_y, max_y))
- return self._bounding_box
+ return self._bounding_box
def offset(self, x_offset=0, y_offset=0):
self._changed()
@@ -1401,10 +1418,10 @@ class RoundButterfly(Primitive):
self.position = position
self.diameter = diameter
self._to_convert = ['position', 'diameter']
-
+
# TODO This does not reset bounding box correctly
-
- @property
+
+ @property
def flashed(self):
return True
@@ -1433,13 +1450,13 @@ class SquareButterfly(Primitive):
self.position = position
self.side = side
self._to_convert = ['position', 'side']
-
+
# TODO This does not reset bounding box correctly
-
- @property
+
+ @property
def flashed(self):
- return True
-
+ return True
+
@property
def bounding_box(self):
if self._bounding_box is None:
@@ -1475,14 +1492,14 @@ class Donut(Primitive):
else:
# Hexagon
self.width = 0.5 * math.sqrt(3.) * outer_diameter
- self.height = outer_diameter
-
+ self.height = outer_diameter
+
self._to_convert = ['position', 'width',
'height', 'inner_diameter', 'outer_diameter']
-
+
# TODO This does not reset bounding box correctly
-
- @property
+
+ @property
def flashed(self):
return True
@@ -1494,7 +1511,7 @@ class Donut(Primitive):
@property
def upper_right(self):
return (self.position[0] + (self.width / 2.),
- self.position[1] + (self.height / 2.)
+ self.position[1] + (self.height / 2.))
@property
def bounding_box(self):
@@ -1521,11 +1538,11 @@ class SquareRoundDonut(Primitive):
self.inner_diameter = inner_diameter
self.outer_diameter = outer_diameter
self._to_convert = ['position', 'inner_diameter', 'outer_diameter']
-
- @property
+
+ @property
def flashed(self):
return True
-
+
@property
def bounding_box(self):
if self._bounding_box is None:
@@ -1537,7 +1554,7 @@ class SquareRoundDonut(Primitive):
class Drill(Primitive):
""" A drill hole
- """
+ """
def __init__(self, position, diameter, hit, **kwargs):
super(Drill, self).__init__('dark', **kwargs)
validate_coordinates(position)
@@ -1545,14 +1562,14 @@ class Drill(Primitive):
self._diameter = diameter
self.hit = hit
self._to_convert = ['position', 'diameter', 'hit']
-
+
# TODO Ths won't handle the hit updates correctly
-
- @property
+
+ @property
def flashed(self):
- return False
+ return False
- @property
+ @property
def position(self):
return self._position
@@ -1583,15 +1600,15 @@ class Drill(Primitive):
max_y = self.position[1] + self.radius
self._bounding_box = ((min_x, max_x), (min_y, max_y))
return self._bounding_box
-
+
def offset(self, x_offset=0, y_offset=0):
self._changed()
self.position = tuple(map(add, self.position, (x_offset, y_offset)))
-
+
def __str__(self):
return '<Drill %f (%f, %f) [%s]>' % (self.diameter, self.position[0], self.position[1], self.hit)
-
-
+
+
class Slot(Primitive):
""" A drilled slot
"""
@@ -1604,13 +1621,13 @@ class Slot(Primitive):
self.diameter = diameter
self.hit = hit
self._to_convert = ['start', 'end', 'diameter', 'hit']
-
+
# TODO this needs to use cached bounding box
-
- @property
+
+ @property
def flashed(self):
return False
-
+
def bounding_box(self):
if self._bounding_box is None:
ll = tuple([c - self.outer_diameter / 2. for c in self.position])
@@ -1621,7 +1638,7 @@ class Slot(Primitive):
def offset(self, x_offset=0, y_offset=0):
self.start = tuple(map(add, self.start, (x_offset, y_offset)))
self.end = tuple(map(add, self.end, (x_offset, y_offset)))
-
+
class TestRecord(Primitive):
""" Netlist Test record
@@ -1633,3 +1650,4 @@ class TestRecord(Primitive):
self.position = position
self.net_name = net_name
self.layer = layer
+ self._to_convert = ['position']