1###################################################################### 2# # 3# Copyright 2009 Lucas Heitzmann Gabrielli. # 4# This file is part of gdspy, distributed under the terms of the # 5# Boost Software License - Version 1.0. See the accompanying # 6# LICENSE file or <http://www.boost.org/LICENSE_1_0.txt> # 7# # 8###################################################################### 9 10import pytest 11import gdspy 12import numpy 13import uuid 14import os 15 16gdspy.library.use_current_library = False 17 18 19def unique(): 20 return str(uuid.uuid4()) 21 22 23@pytest.fixture 24def tree(): 25 p1 = gdspy.Polygon(((0, 0), (0, 1), (1, 0)), 0, 0) 26 p2 = gdspy.Polygon(((2, 0), (2, 1), (1, 0)), 1, 1) 27 l1 = gdspy.Label("label1", (0, 0), layer=11) 28 l2 = gdspy.Label("label2", (2, 1), layer=12) 29 c1 = gdspy.Cell("tree_" + unique()) 30 c1.add(p1) 31 c1.add(l1) 32 c2 = gdspy.Cell("tree_" + unique()) 33 c2.add(l2) 34 c2.add(p2) 35 c2.add(gdspy.CellReference(c1)) 36 c3 = gdspy.Cell("tree_" + unique()) 37 c3.add(gdspy.CellArray(c2, 3, 2, (3, 3))) 38 return c3, c2, c1 39 40 41def test_duplicate(): 42 lib = gdspy.GdsLibrary() 43 name = "c_duplicate" 44 c = gdspy.Cell(name) 45 lib.add(c) 46 with pytest.raises(ValueError) as e: 47 lib.add(gdspy.Cell(name), overwrite_duplicate=False) 48 assert name in str(e.value) 49 50 51def test_ignore_duplicate(): 52 lib = gdspy.GdsLibrary() 53 c1 = gdspy.Cell("c_ignore_duplicate") 54 lib.add(c1) 55 lib.add(c1, overwrite_duplicate=False) 56 lib.add(gdspy.Cell(c1.name), overwrite_duplicate=True) 57 assert lib.cells[c1.name] is not c1 58 59 60def test_str(): 61 c = gdspy.Cell("c_str") 62 assert str(c) == 'Cell ("c_str", 0 polygons, 0 paths, 0 labels, 0 references)' 63 64 65def test_add_element(): 66 p = gdspy.Polygon(((0, 0), (1, 0), (0, 1))) 67 c = gdspy.Cell("c_add_element") 68 assert c.add(p) is c 69 assert c.add([p, p]) is c 70 assert c.polygons == [p, p, p] 71 72 73def test_add_label(): 74 lbl = gdspy.Label("label", (0, 0)) 75 c = gdspy.Cell("c_add_label") 76 assert c.add(lbl) is c 77 assert c.add([lbl, lbl]) is c 78 assert c.labels == [lbl, lbl, lbl] 79 80 81def test_copy(): 82 name = "c_copy" 83 p = gdspy.Polygon(((0, 0), (1, 0), (0, 1))) 84 lbl = gdspy.Label("label", (0, 0)) 85 c1 = gdspy.Cell(name) 86 c1.add(p) 87 c1.add(lbl) 88 c3 = c1.copy(name, False) 89 assert c3.polygons == c1.polygons and c3.polygons is not c1.polygons 90 assert c3.labels == c1.labels and c3.labels is not c1.labels 91 cref = gdspy.Cell("c_ref").add(gdspy.Rectangle((-1, -1), (-2, -2))) 92 c1.add(gdspy.CellReference(cref)) 93 c1.get_bounding_box() 94 c4 = c1.copy("c_copy_1", True) 95 assert c4.polygons != c1.polygons 96 assert c4.labels != c1.labels 97 assert c1._bb_valid 98 assert cref._bb_valid 99 assert not c4._bb_valid 100 101 102def test_remove(tree): 103 c3, c2, c1 = tree 104 c1.remove_polygons(lambda p, layer, d: layer == 1) 105 assert len(c1.polygons) == 1 106 c1.remove_polygons(lambda p, layer, d: layer == 0) 107 assert len(c1.polygons) == 0 108 c1.remove_labels(lambda lbl: lbl.layer == 12) 109 assert len(c1.labels) == 1 110 c1.remove_labels(lambda lbl: lbl.layer == 11) 111 assert len(c1.labels) == 0 112 113 114def test_area(): 115 c = gdspy.Cell("c_area") 116 c.add(gdspy.Rectangle((0, 0), (1, 1), layer=0)) 117 c.add(gdspy.Rectangle((0, 0), (1, 1), layer=1)) 118 c.add(gdspy.Rectangle((1, 1), (2, 2), layer=1)) 119 c.add(gdspy.Rectangle((1, 1), (2, 2), datatype=2)) 120 assert c.area() == 4.0 121 assert c.area(True) == {(0, 0): 1.0, (1, 0): 2.0, (0, 2): 1} 122 123 124def test_flatten_00(tree): 125 c3, c2, c1 = tree 126 c3.flatten() 127 assert len(c3.polygons) == 12 128 for i in range(12): 129 assert c3.polygons[i].layers == [0] or c3.polygons[i].layers == [1] 130 assert c3.polygons[i].layers == c3.polygons[i].datatypes 131 assert len(c3.labels) == 12 132 133 134def test_flatten_01(tree): 135 c3, c2, c1 = tree 136 c3.flatten(None, 2, 3) 137 assert len(c3.polygons) == 12 138 for i in range(12): 139 assert c3.polygons[i].layers == [0] or c3.polygons[i].layers == [1] 140 assert c3.polygons[i].datatypes == [2] 141 assert len(c3.labels) == 12 142 assert all(lbl.texttype == 3 for lbl in c3.labels) 143 144 145def test_flatten_10(tree): 146 c3, c2, c1 = tree 147 c3.flatten(2) 148 assert len(c3.polygons) == 12 149 for i in range(12): 150 assert c3.polygons[i].datatypes == [0] or c3.polygons[i].datatypes == [1] 151 assert c3.polygons[i].layers == [2] 152 assert len(c3.labels) == 12 153 assert all(lbl.layer == 2 for lbl in c3.labels) 154 155 156def test_flatten_11(tree): 157 c3, c2, c1 = tree 158 c3.flatten(2, 3, 4) 159 assert len(c3.polygons) == 12 160 assert all(p.layers == [2] for p in c3.polygons) 161 assert all(p.datatypes == [3] for p in c3.polygons) 162 assert len(c3.labels) == 12 163 assert all(lbl.layer == 2 for lbl in c3.labels) 164 assert all(lbl.texttype == 4 for lbl in c3.labels) 165 166 167def test_bb(tree): 168 c3, c2, c1 = tree 169 err = numpy.array(((0, 0), (8, 4))) - c3.get_bounding_box() 170 assert numpy.max(numpy.abs(err)) == 0 171 172 p2 = gdspy.Polygon(((-1, 2), (-1, 1), (0, 2)), 2, 2) 173 c2.add(p2) 174 err = numpy.array(((-1, 0), (8, 5))) - c3.get_bounding_box() 175 assert numpy.max(numpy.abs(err)) == 0 176 177 p1 = gdspy.Polygon(((0, 3), (0, 2), (1, 3)), 3, 3) 178 c1.add(p1) 179 err = numpy.array(((-1, 0), (8, 6))) - c3.get_bounding_box() 180 assert numpy.max(numpy.abs(err)) == 0 181 182 183def test_layers(tree): 184 assert tree[0].get_layers() == {0, 1, 11, 12} 185 186 187def test_datatypes(tree): 188 assert tree[0].get_datatypes() == {0, 1} 189 190 191def test_get_polygons1(tree): 192 c3, c2, c1 = tree 193 p1 = gdspy.Polygon(((0, 3), (0, 2), (1, 3)), 3, 3) 194 c1.add(p1) 195 assert len(c3.get_polygons()) == 18 196 assert len(c3.get_polygons(False, 0)) == 6 197 assert len(c3.get_polygons(False, 1)) == 12 198 assert set(c3.get_polygons(True).keys()) == {(0, 0), (1, 1), (3, 3)} 199 assert set(c3.get_polygons(True, 0).keys()) == {c2.name} 200 assert set(c3.get_polygons(True, 1).keys()) == {c1.name, (1, 1)} 201 202 203def test_get_polygons2(tree): 204 c3, c2, c1 = tree 205 c1.add(gdspy.Rectangle((0, 0), (1, 1), 0, 0)) 206 assert len(c1.get_polygons()) == 2 207 d = c1.get_polygons(True) 208 assert len(d) == 1 209 assert (0, 0) in d 210 assert len(d[(0, 0)]) == 2 211 c3.add(gdspy.CellReference(c1)) 212 d = c3.get_polygons(True) 213 assert len(d) == 2 214 assert (0, 0) in d and (1, 1) in d 215 assert len(d[(0, 0)]) == 14 216 assert len(d[(1, 1)]) == 6 217 218 219def test_get_polygons3(): 220 c0 = gdspy.Cell("empty") 221 assert len(c0.get_polygons()) == 0 222 assert len(c0.get_polygons(True)) == 0 223 assert len(c0.get_polygons(False, -1)) == 0 224 225 226def test_get_polygons4(tree): 227 c3, c2, c1 = tree 228 c3.add(gdspy.Rectangle((0, 0), (1, 1), 0, 0)) 229 assert len(c3.get_polygons((0, 0))) == 7 230 assert len(c3.get_polygons((0, 0), 0)) == 1 231 assert len(c3.get_polygons((1, 1), 0)) == 0 232 assert len(c3.get_polygons((0, 0), 1)) == 1 233 assert len(c3.get_polygons((1, 1), 1)) == 6 234 235 236def test_write_svg(tree, tmpdir): 237 _, _, c1 = tree 238 fname = str(tmpdir.join("c1.svg")) 239 c1.write_svg(fname) 240 assert os.path.isfile(fname) 241 assert not os.stat(fname).st_size == 0 242 243 244def test_write_svg_with_style(tree, tmpdir): 245 _, _, c1 = tree 246 fname = str(tmpdir.join("c1.svg")) 247 style = {(0, 0): {"fill": "CC00FF"}} 248 c1.write_svg(fname, style=style) 249 assert os.path.isfile(fname) 250 assert not os.stat(fname).st_size == 0 251 252 253def assert_bb(bb1, bb2): 254 for p1, p2 in zip(bb1, bb2): 255 for c1, c2 in zip(p1, p2): 256 assert abs(c1 - c2) < 1e-12 257 258 259def test_bounding_box(): 260 cell1 = gdspy.Cell("1") 261 cell1.add(gdspy.Rectangle((0, 0), (1, 1))) 262 263 # Cell1: plain 1x1 um square, with bottom-left corner at 0,0 264 assert_bb(cell1.get_bounding_box(), ((0, 0), (1, 1))) 265 266 # Cell2: place and rotate Cell1 45deg about origin 267 cell2 = gdspy.Cell("2") 268 cell2.add(gdspy.CellReference(cell1, rotation=45)) 269 270 assert_bb(cell2.get_bounding_box(), ((-(0.5 ** 0.5), 0), (0.5 ** 0.5, 2 ** 0.5))) 271 272 # Cell3: place and rotate Cell2 an additional 45deg about origin (Cell1 is now rotated total 90deg) 273 cell3 = gdspy.Cell("3") 274 cell3.add(gdspy.CellReference(cell2, rotation=45)) 275 276 assert_bb(cell3.get_bounding_box(), ((-1, 0), (0, 1))) 277 278 # Cell4: nest Cell2 one level deeper with no transform (geometric equivalent to Cell2) 279 cell4 = gdspy.Cell("4") 280 cell4.add(gdspy.CellReference(cell2)) 281 282 assert_bb(cell4.get_bounding_box(), ((-(0.5 ** 0.5), 0), (0.5 ** 0.5, 2 ** 0.5))) 283 284 # Cell5: rotate Cell4 an addition 45 degrees (geometric equivalent to Cell3) 285 cell5 = gdspy.Cell("5") 286 cell5.add(gdspy.CellReference(cell4, rotation=45)) 287 288 assert_bb(cell5.get_bounding_box(), ((-1, 0), (0, 1))) 289 290 # Cell6: translate Cell1 by 2um east 291 cell6 = gdspy.Cell("6") 292 cell6.add(gdspy.CellReference(cell1, origin=(2, 0))) 293 294 assert_bb(cell6.get_bounding_box(), ((2, 0), (3, 1))) 295 296 cell7a = gdspy.Cell("7a") 297 298 assert cell7a.get_bounding_box() is None 299 300 cell7b = gdspy.Cell("7b") 301 cell7b.add(gdspy.CellReference(cell7a, rotation=90)) 302 303 assert cell7b.get_bounding_box() is None 304 305 cell7c = gdspy.Cell("7c") 306 cell7c.add(gdspy.CellReference(cell7b)) 307 308 assert cell7c.get_bounding_box() is None 309 310 cell7 = gdspy.Cell("7") 311 cell7.add(cell1) 312 cell7.add(cell7c) 313 314 assert_bb(cell7.get_bounding_box(), ((0, 0), (1, 1))) 315 316 317def test_bounding_box2(): 318 cell0 = gdspy.Cell("0") 319 cell0.add(gdspy.Rectangle((0, 0), (0.5, 0.25))) 320 321 cell1 = gdspy.Cell("1") 322 cell1.add(gdspy.CellArray(cell0, 2, 4, (0.5, 0.25))) 323 324 # Cell1: plain 1x1 um square, with bottom-left corner at 0,0 325 assert_bb(cell1.get_bounding_box(), ((0, 0), (1, 1))) 326 327 # Cell2: place and rotate Cell1 45deg about origin 328 cell2 = gdspy.Cell("2") 329 cell2.add(gdspy.CellReference(cell1, rotation=45)) 330 331 assert_bb(cell2.get_bounding_box(), ((-(0.5 ** 0.5), 0), (0.5 ** 0.5, 2 ** 0.5))) 332 333 # Cell3: place and rotate Cell2 an additional 45deg about origin (Cell1 is now rotated total 90deg) 334 cell3 = gdspy.Cell("3") 335 cell3.add(gdspy.CellReference(cell2, rotation=45)) 336 337 assert_bb(cell3.get_bounding_box(), ((-1, 0), (0, 1))) 338 339 # Cell4: nest Cell2 one level deeper with no transform (geometric equivalent to Cell2) 340 cell4 = gdspy.Cell("4") 341 cell4.add(gdspy.CellArray(cell2, 1, 1, (1, 1))) 342 343 assert_bb(cell4.get_bounding_box(), ((-(0.5 ** 0.5), 0), (0.5 ** 0.5, 2 ** 0.5))) 344 345 # Cell5: rotate Cell4 an addition 45 degrees (geometric equivalent to Cell3) 346 cell5 = gdspy.Cell("5") 347 cell5.add(gdspy.CellArray(cell4, 1, 1, (1, 1), rotation=45)) 348 349 assert_bb(cell5.get_bounding_box(), ((-1, 0), (0, 1))) 350 351 # Cell6: translate Cell1 by 2um east 352 cell6 = gdspy.Cell("6") 353 cell6.add(gdspy.CellArray(cell1, 1, 1, (1, 1), origin=(2, 0))) 354 355 assert_bb(cell6.get_bounding_box(), ((2, 0), (3, 1))) 356