PCB coordinate type
Stefan Schuermans

Stefan Schuermans commited on 2021-02-17 19:13:39
Showing 2 changed files, with 120 additions and 30 deletions.

... ...
@@ -143,17 +143,18 @@ class PcbBaseParser(StringBuffer):
143 143
         'square', 'via'
144 144
     ])
145 145
 
146
-    def parseCoord(self) -> float:
146
+    def parseCoord(self) -> pcb_types.Coordinate:
147 147
         """
148 148
         Parse a coordinate.
149 149
         """
150 150
         with self:
151 151
             f = self.parseFloat()
152
+            c = pcb_types.Coordinate(f)
152 153
             if self.check('mil'):
153
-                f *= 100  # native unit == .01mil
154
+                c.mil = f
154 155
             elif self.check('mm'):
155
-                f *= 1e5 / 25.4  # 25.4mm == 1inch == 1e5 * .01mil
156
-            return f
156
+                c.mm = f
157
+            return c
157 158
 
158 159
     def parseFloat(self) -> float:
159 160
         """
... ...
@@ -5,6 +5,73 @@ Types representing entities of GNU PCB files.
5 5
 import collections
6 6
 
7 7
 
8
+class Coordinate():
9
+    """
10
+    A coordinate in a PCB file.
11
+    """
12
+
13
+    MIL = 1e2
14
+    MM = 1e5 / 25.4
15
+
16
+    def __init__(self, raw: float = 0):
17
+        self._raw = round(raw)
18
+
19
+    def __repr__(self) -> str:
20
+        return f'Coordinate({self._raw:d})'
21
+
22
+    def _compare(self, other) -> int:
23
+        if not isinstance(other, Coordinate):
24
+            raise ValueError(f'{type(self).__name__:s} cannot be'
25
+                             f' compared to {type(other).__name__:s}')
26
+        if self._raw < other._raw:
27
+            return -1
28
+        if self._raw > other._raw:
29
+            return 1
30
+        return 0
31
+
32
+    def __eq__(self, other) -> bool:
33
+        return self._compare(other) == 0
34
+
35
+    def __ne__(self, other) -> bool:
36
+        return self._compare(other) != 0
37
+
38
+    def __lt__(self, other) -> bool:
39
+        return self._compare(other) < 0
40
+
41
+    def __le__(self, other) -> bool:
42
+        return self._compare(other) <= 0
43
+
44
+    def __gt__(self, other) -> bool:
45
+        return self._compare(other) > 0
46
+
47
+    def __ge__(self, other) -> bool:
48
+        return self._compare(other) >= 0
49
+
50
+    @property
51
+    def mil(self) -> float:
52
+        return self._raw / self.MIL
53
+
54
+    @mil.setter
55
+    def mil(self, mil: float):
56
+        self._raw = round(mil * self.MIL)
57
+
58
+    @property
59
+    def mm(self) -> float:
60
+        return self._raw / self.MM
61
+
62
+    @mm.setter
63
+    def mm(self, mm: float):
64
+        self._raw = round(mm * self.MM)
65
+
66
+    @property
67
+    def raw(self) -> int:
68
+        return self._raw
69
+
70
+    @raw.setter
71
+    def raw(self, raw: float):
72
+        self._raw = round(raw)
73
+
74
+
8 75
 class Struct:
9 76
     """
10 77
     Base class for struct-like Python objects
... ...
@@ -66,12 +133,21 @@ class Element(Struct):
66 133
     Element entity in a GNU PCB file.
67 134
     """
68 135
 
69
-    _attrs = collections.OrderedDict([('s_flags', []), ('desc', ''),
70
-                                      ('name', ''), ('value', ''),
71
-                                      ('m_x', 0.0), ('m_y', 0.0), ('t_x', 0.0),
72
-                                      ('t_y', 0.0), ('t_dir', 0),
73
-                                      ('t_scale', 0.0), ('t_s_flags', []),
74
-                                      ('body', [])])
136
+    _attrs = collections.OrderedDict([
137
+        # attributes
138
+        ('s_flags', []),
139
+        ('desc', ''),
140
+        ('name', ''),
141
+        ('value', ''),
142
+        ('m_x', Coordinate(0)),
143
+        ('m_y', Coordinate(0)),
144
+        ('t_x', Coordinate(0)),
145
+        ('t_y', Coordinate(0)),
146
+        ('t_dir', 0),
147
+        ('t_scale', 0.0),
148
+        ('t_s_flags', []),
149
+        ('body', [])
150
+    ])
75 151
 
76 152
     def __init__(self, **kwargs):
77 153
         super().__init__(**kwargs)
... ...
@@ -82,10 +158,16 @@ class ElementArc(Struct):
82 158
     ElementArc entity in a GNU PCB file.
83 159
     """
84 160
 
85
-    _attrs = collections.OrderedDict([('r_x', 0.0), ('r_y', 0.0),
86
-                                      ('width', 0.0), ('height', 0.0),
87
-                                      ('start_angle', 0.0), ('end_angle', 0.0),
88
-                                      ('thickness', 0.0)])
161
+    _attrs = collections.OrderedDict([
162
+        # attributes
163
+        ('r_x', Coordinate(0)),
164
+        ('r_y', Coordinate(0)),
165
+        ('width', Coordinate(0)),
166
+        ('height', Coordinate(0)),
167
+        ('start_angle', 0.0),
168
+        ('end_angle', 0.0),
169
+        ('thickness', Coordinate(0))
170
+    ])
89 171
 
90 172
     def __init__(self, **kwargs):
91 173
         super().__init__(**kwargs)
... ...
@@ -96,9 +178,14 @@ class ElementLine(Struct):
96 178
     ElementLine entity in a GNU PCB file.
97 179
     """
98 180
 
99
-    _attrs = collections.OrderedDict([('r_x1', 0.0), ('r_y1', 0.0),
100
-                                      ('r_x2', 0.0), ('r_y2', 0.0),
101
-                                      ('thickness', 0.0)])
181
+    _attrs = collections.OrderedDict([
182
+        # attributes
183
+        ('r_x1', Coordinate(0)),
184
+        ('r_y1', Coordinate(0)),
185
+        ('r_x2', Coordinate(0)),
186
+        ('r_y2', Coordinate(0)),
187
+        ('thickness', Coordinate(0))
188
+    ])
102 189
 
103 190
     def __init__(self, **kwargs):
104 191
         super().__init__(**kwargs)
... ...
@@ -110,13 +197,14 @@ class Pad(Struct):
110 197
     """
111 198
 
112 199
     _attrs = collections.OrderedDict([
113
-        ('r_x1', 0.0),
114
-        ('r_y1', 0.0),
115
-        ('r_x2', 0.0),
116
-        ('r_y2', 0.0),
117
-        ('thickness', 0.0),
118
-        ('clearance', 0.0),
119
-        ('mask', 0.0),
200
+        # attributes
201
+        ('r_x1', Coordinate(0)),
202
+        ('r_y1', Coordinate(0)),
203
+        ('r_x2', Coordinate(0)),
204
+        ('r_y2', Coordinate(0)),
205
+        ('thickness', Coordinate(0)),
206
+        ('clearance', Coordinate(0)),
207
+        ('mask', Coordinate(0)),
120 208
         ('name', ''),
121 209
         ('number', ''),
122 210
         ('s_flags', []),
... ...
@@ -132,12 +220,13 @@ class Pin(Struct):
132 220
     """
133 221
 
134 222
     _attrs = collections.OrderedDict([
135
-        ('r_x', 0.0),
136
-        ('r_y', 0.0),
137
-        ('thickness', 0.0),
138
-        ('clearance', 0.0),
139
-        ('mask', 0.0),
140
-        ('drill', 0.0),
223
+        # attributes
224
+        ('r_x', Coordinate(0)),
225
+        ('r_y', Coordinate(0)),
226
+        ('thickness', Coordinate(0)),
227
+        ('clearance', Coordinate(0)),
228
+        ('mask', Coordinate(0)),
229
+        ('drill', Coordinate(0)),
141 230
         ('name', ''),
142 231
         ('number', ''),
143 232
         ('s_flags', []),
144 233