Coverage for klayout_pex/klayout/shapes_pb2_converter.py: 81%

67 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-31 20:14 +0000

1# 

2# -------------------------------------------------------------------------------- 

3# SPDX-FileCopyrightText: 2024-2025 Martin Jan Köhler and Harald Pretl 

4# Johannes Kepler University, Institute for Integrated Circuits. 

5# 

6# This file is part of KPEX 

7# (see https://github.com/iic-jku/klayout-pex). 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21# SPDX-License-Identifier: GPL-3.0-or-later 

22# -------------------------------------------------------------------------------- 

23# 

24 

25import klayout.db as kdb 

26import klayout_pex_protobuf.kpex.geometry.shapes_pb2 as shapes_pb2 

27 

28 

29class ShapesConverter: 

30 def __init__(self, dbu: float): 

31 self.dbu = dbu 

32 

33 def klayout_point(self, point: shapes_pb2.Point) -> kdb.Point: 

34 # FIXME: there is no PointWithProperties yet 

35 return kdb.Point(point.x, point.y) 

36 

37 def klayout_point_to_pb(self, 

38 point_kly: kdb.Point, 

39 point_pb: shapes_pb2.Point): 

40 point_pb.x = point_kly.x 

41 point_pb.y = point_kly.y 

42 

43 def klayout_box(self, box: shapes_pb2.Box) -> kdb.Box: 

44 box_kly = kdb.Box(box.lower_left.x, 

45 box.lower_left.y, 

46 box.upper_right.x, 

47 box.upper_right.y) 

48 if box.net: 

49 box_kly = kdb.BoxWithProperties(box_kly, {'net': box.net}) 

50 return box_kly 

51 

52 def klayout_box_to_pb(self, 

53 box_kly: kdb.Box, 

54 shape_pb: shapes_pb2.Shape): 

55 shape_pb.kind = shapes_pb2.Shape.Kind.SHAPE_KIND_BOX 

56 box_pb = shape_pb.box 

57 if isinstance(box_kly, kdb.BoxWithProperties): 

58 net_name = box_kly.property('net') 

59 if net_name: 

60 box_pb.net = net_name 

61 box_pb.lower_left.x = box_kly.left 

62 box_pb.lower_left.y = box_kly.bottom 

63 box_pb.upper_right.x = box_kly.right 

64 box_pb.upper_right.y = box_kly.top 

65 

66 def klayout_polygon(self, polygon: shapes_pb2.Polygon) -> kdb.Polygon: 

67 points_kly = [self.klayout_point(pt) for pt in polygon.hull_points] 

68 polygon_kly = kdb.Polygon(points_kly) 

69 if len(polygon.net) >= 1: 

70 polygon_kly = kdb.PolygonWithProperties(polygon_kly, {'net': polygon.net}) 

71 return polygon_kly 

72 

73 def klayout_polygon_to_pb(self, 

74 polygon_kly: kdb.Polygon, 

75 shape_pb: shapes_pb2.Shape): 

76 shape_pb.kind = shapes_pb2.Shape.Kind.SHAPE_KIND_POLYGON 

77 net_name = polygon_kly.property('net') 

78 if net_name: 

79 shape_pb.polygon.net = net_name 

80 for p_kly in polygon_kly.each_point_hull(): 

81 self.klayout_point_to_pb(p_kly, shape_pb.polygon.hull_points.add()) 

82 

83 def klayout_shape(self, shape: shapes_pb2.Shape) -> kdb.Shape: 

84 match shape.kind: 

85 case shapes_pb2.Shape.Kind.SHAPE_KIND_BOX: 

86 return self.klayout_box(shape.box) 

87 case shapes_pb2.Shape.Kind.SHAPE_KIND_POLYGON: 

88 return self.klayout_polygon(shape.polygon) 

89 case _: 

90 raise NotImplementedError() 

91 

92 def klayout_shape_to_pb(self, 

93 shape_kly: kdb.Shape, 

94 shape_pb: shapes_pb2.Shape): 

95 if shape_kly.is_box(): 

96 self.klayout_box_to_pb(shape_kly.bbox(), shape_pb) 

97 elif shape_kly.is_polygon(): 

98 self.klayout_polygon_to_pb(shape_kly.polygon(), shape_pb) 

99 else: 

100 raise NotImplementedError() 

101 

102 def klayout_region(self, region: shapes_pb2.Region) -> kdb.Region: 

103 region_kly = kdb.Region() 

104 for shape in region.shapes: 

105 match shape.kind: 

106 case shapes_pb2.Shape.Kind.SHAPE_KIND_POLYGON: 

107 region_kly.insert(self.klayout_polygon(shape.polygon)) 

108 case shapes_pb2.Shape.Kind.SHAPE_KIND_BOX: 

109 region_kly.insert(self.klayout_box(shape.box)) 

110 case _: 

111 raise NotImplementedError() 

112 return region_kly 

113 

114 def klayout_region_to_pb(self, 

115 region_kly: kdb.Region, 

116 region_pb: shapes_pb2.Region): 

117 for sh_kly in region_kly: 

118 self.klayout_polygon_to_pb(sh_kly, region_pb.shapes.add())