Esempio n. 1
0
        def pcell(self, layout, cell=None, params=None):
            if cell is None:
                cell = layout.create_cell(self.name)

            cp = self.parse_param_args(params)
            origin, _, _ = CellWithPosition.origin_ex_ey(self,
                                                         params,
                                                         multiple_of_90=True)

            if from_library is not None:
                # Topcell must be same as filename
                gdscell = get_lib_cell(layout, cell_name, from_library)
            else:
                # BUG loading this file twice segfaults klayout
                layout2 = pya.Layout()
                layout2.read(os.path.join(gds_dir, filename))
                gdscell2 = layout2.cell(cell_name)
                gdscell = layout.create_cell(cell_name)
                gdscell.copy_tree(gdscell2)
                del gdscell2
                del layout2

            rot_DTrans = pya.DTrans.R0
            angle_multiple_90 = cp.angle_ex // 90
            rot_DTrans.rot = (angle_multiple_90) % 4

            cell.insert(
                pya.DCellInstArray(gdscell.cell_index(),
                                   pya.DTrans(rot_DTrans, origin)))

            return cell, {}
Esempio n. 2
0
def place_cell(parent_cell, pcell, ports_dict, placement_origin, relative_to=None, transform_into=False):
    """ Places an pya cell and return ports with updated positions
    Args:
        parent_cell: cell to place into
        pcell, ports_dict: result of KLayoutPCell.pcell call
        placement_origin: pya.Point object to be used as origin
        relative_to: port name
            the cell is placed so that the port is located at placement_origin
        transform_into:
            if used with relative_into, transform the cell's coordinate system
            so that its origin is in the given port.

    Returns:
        ports(dict): key:port.name, value: geometry.Port with positions relative to parent_cell's origin
    """
    offset = pya.DVector(0, 0)
    port_offset = placement_origin
    if relative_to is not None:
        offset = ports_dict[relative_to].position
        port_offset = placement_origin - offset
        if transform_into:
            # print(type(pcell))
            offset_transform = pya.DTrans(pya.DTrans.R0, -offset)
            for instance in pcell.each_inst():
                instance.transform(offset_transform)
            pcell.transform_into(offset_transform)
        else:
            placement_origin = placement_origin - offset

    transformation = pya.DTrans(pya.Trans.R0, placement_origin)
    instance = pya.DCellInstArray(pcell.cell_index(), transformation)
    parent_cell.insert(instance)
    for port in ports_dict.values():
        port.position += port_offset

    return ports_dict
Esempio n. 3
0
            def wrapper_pcell(self, layout, cell=None, params=None):
                global layer_map_dict
                try:
                    layer_map_dict[layout]
                except KeyError:
                    layer_map_dict[layout] = pya.LayerMap()
                if cell is None:
                    # copy source code of class and all its ancestors
                    source_code = "".join(
                        [inspect.getsource(klass) for klass in self.__class__.__mro__ if issubclass(klass, KLayoutPCell)])

                    # Default params before instantiation
                    original_default_params = {name: value["default"]
                                               for name, value in self.param_definition.items()}

                    # Updated params after instantiation and placement
                    # (could be bigger than the original default)
                    if params is not None:
                        default_params = dict(self.default_params, **params)
                    else:
                        default_params = self.default_params

                    # Differential parameters (non-default)
                    diff_params = {}
                    for name, value in original_default_params.items():
                        if default_params[name] != value:
                            diff_params[name] = default_params[name]

                    long_hash_pcell = sha256((source_code +
                                              str(diff_params) +
                                              self.name).encode()).hexdigest()
                    short_hash_pcell = long_hash_pcell[0:7]
                    cache_fname = f'cache_{self.__class__.__qualname__}_{short_hash_pcell}'
                    # if short_hash_pcell in cell_cache.keys():  # already loaded
                    #     print(f"Preloaded {self.__class__.__name__}: {diff_params}")
                    #     cached_cell, ports_bytecode, cellname = cell_cache[short_hash_pcell]
                    #     ports = pickle.loads(ports_bytecode)
                    #     # print('read:', cell_index, ports, cellname)
                    #     newcell = layout.create_cell(cellname)
                    #     newcell.copy_tree(cached_cell)
                    #     # newcell.insert(pya.DCellInstArray(cell.cell_index(),
                    #     #                                   pya.DTrans(pya.Trans.R0, pya.DPoint(0, 0))))
                    #     return newcell, deepcopy(ports)

                    def read_layout(layout, gds_filename):
                        global layer_map_dict
                        load_options = pya.LoadLayoutOptions()
                        load_options.text_enabled = True
                        load_options.set_layer_map(layer_map_dict[layout], True)

                        # store and take away the cell names of all cells read so far
                        # (by setting the cell name to "" the cells basically become invisible for
                        # the following read)
                        # take out the pcells
                        cell_list = [cell for cell in layout.each_cell()]
                        cell_indices = {cell.name: cell.cell_index() for cell in cell_list}
                        for i in cell_indices.values():
                            layout.rename_cell(i, "")

                        lmap = layout.read(gds_filename, load_options)
                        # in the new layout, get all cells names
                        cell_names2 = [(cell.cell_index(), cell.name)
                                       for cell in layout.each_cell()]

                        # make those cells point to older cells
                        prune_cells_indices = []
                        for i_duplicate, name_cached_cell in cell_names2:
                            if name_cached_cell in cell_indices.keys():
                                if name_cached_cell.startswith('cache_'):
                                    for parent_inst_array in layout.cell(i_duplicate).each_parent_inst():
                                        cell_instance = parent_inst_array.child_inst()
                                        cell_instance.cell = layout.cell(
                                            cell_indices[name_cached_cell])
                                    prune_cells_indices.append(i_duplicate)
                                else:
                                    # print('RENAME', name_cached_cell)
                                    k = 1
                                    while (name_cached_cell + f"_{k}") in cell_indices.keys():
                                        k += 1
                                    layout.rename_cell(i_duplicate, name_cached_cell + f"_{k}")

                        for i_pruned in prune_cells_indices:
                            # print('deleting cell', layout.cell(i_pruned).name)
                            layout.prune_cell(i_pruned, -1)

                        # every conflict should have been caught above
                        for name, i in cell_indices.items():
                            layout.rename_cell(i, name)

                        layer_map_dict[layout] = lmap
                        return lmap

                    cache_fname_gds = cache_fname + '.gds'
                    cache_fname_pkl = cache_fname + '.klayout.pkl'

                    os.makedirs(cache_dir, mode=0o775, exist_ok=True)

                    cache_fpath_gds = os.path.join(cache_dir, cache_fname_gds)
                    cache_fpath_pkl = os.path.join(cache_dir, cache_fname_pkl)
                    if os.path.isfile(cache_fpath_gds) and os.path.isfile(cache_fpath_pkl):
                        with open(cache_fpath_pkl, 'rb') as file:
                            ports, read_short_hash_pcell, cellname = pickle.load(file)
                        if debug:
                            print(f"Reading from cache: {cache_fname}: {diff_params}, {cellname}")
                        else:
                            print('r', end='', flush=True)
                        if not layout.has_cell(cache_fname):
                            read_layout(layout, cache_fpath_gds)
                        retrieved_cell = layout.cell(cache_fname)
                        cell = layout.create_cell(cellname)
                        cell.insert(pya.DCellInstArray(retrieved_cell.cell_index(),
                                                       pya.DTrans(pya.Trans.R0, pya.DPoint(0, 0))))
                        # cell.move_tree(retrieved_cell)
                    else:
                        if layout.has_cell(cache_fname):
                            print(f"WARNING: {cache_fname_gds} does not exist but {cache_fname} is in layout.")

                        # populating .gds and .pkl
                        empty_layout = pya.Layout()
                        compiled_cell, ports = pcell(
                            self, empty_layout, cell=None, params=params)
                        if debug:
                            print(f"Writing to cache: {cache_fname}: {diff_params}, {compiled_cell.name}")
                        else:
                            print('w', end='', flush=True)
                        cellname, compiled_cell.name = compiled_cell.name, cache_fname
                        compiled_cell.write(cache_fpath_gds)
                        with open(cache_fpath_pkl, 'wb') as file:
                            pickle.dump((ports, short_hash_pcell, cellname), file)
                        read_layout(layout, cache_fpath_gds)

                        retrieved_cell = layout.cell(cache_fname)
                        cell = layout.create_cell(cellname)
                        cell.insert(pya.DCellInstArray(retrieved_cell.cell_index(),
                                                       pya.DTrans(pya.Trans.R0, pya.DPoint(0, 0))))

                else:
                    cell, ports = pcell(self, layout, cell=cell, params=params)
                return cell, ports
Esempio n. 4
0
CARAVEL_GDS_PATH = "./gds/caravel.gds"
USER_GDS_PATH = "./gds/user_project_wrapper.gds"

# ly = pya.CellView.active().cell.layout
ly = pya.Layout()
ly.read(CARAVEL_GDS_PATH)
TOP = ly.cell("caravel")

# x, y = 326.38500, 1382.01000
for each in TOP.each_inst():
    if "user_project_wrapper" in (each.cell.name):
        x, y = each.dtrans.disp.x, each.dtrans.disp.y
        print("Placing module at (%f,%f)" % (x, y))

ly.delete_cell(ly.cell_by_name("user_project_wrapper"))

ly.read(USER_GDS_PATH)
tiles = ly.cell('user_project_wrapper')

TOP.insert(
    pya.DCellInstArray(tiles.cell_index(),
                       pya.DTrans(pya.DTrans.R0, pya.DPoint(x, y))))

for c in ly.top_cells():
    if c.name != "caravel":
        print("removing cell " + c.name)
        ly.delete_cell(c.cell_index())

ly.write("./gds/caravel_merged.gds")
Esempio n. 5
0
horizontal = np.concatenate((
  np.array([0, 4, 4]),
  np.full(6, 4)))   # Pad to total length 9 with 4's

vertical = np.concatenate((
  np.array([16, 20, 20]),
  np.full(6, 20)))  # Pad to total length 9 with 20's

# Generate the spiral and instantiate its cell
paths.delay_spiral_geo(layout, rib, sp, 
  turns=4, 
  spacing=2.5, 
  vertical=vertical,
  horizontal=horizontal,
  horizontal_mode='symmetric',
  vertical_mode='symmetric',
  quad_shift=0,
  start_turn=1, 
  start_angle=0, 
  end_angle=0,
  radial_shift=4.80, 
  n_pts=5000)
  
top.insert(pya.DCellInstArray(
  sp.cell_index(),
  pya.DTrans(pya.DVector(0, 30))
))


layout.write(my_constants.gds_models_path + 'test_spiral.gds')
Esempio n. 6
0
    def produce_impl(self):
        #Calculate layout database unit
        #dbu = self.layout.dbu
        dbu = 1
        size = []
        if len(self.size) < 2:
            if self.debug:
                print("Size < 2 dimension")
            if len(self.size) == 0:
                if self.debug:
                    print(
                        "paramter size has been adjusted to default - invalid data have provided"
                    )
                size = [100.0, 100.0]
            else:
                if self.debug:
                    print("Size has been adjusted to {}:{}".format(
                        self.size[0] / dbu, self.size[0] / dbu))
                size.append(float(self.size[0]) / dbu)
                size.append(float(self.size[0]) / dbu)
        else:
            size.append(float(self.size[0]) / dbu)
            size.append(float(self.size[1]) / dbu)

        ovSize = []
        if len(self.ovsize) < 2:
            if self.debug:
                print("overal size < 2 dimension")
            if len(self.ovsize) == 0:
                if self.debug:
                    print(
                        "paramter size has been adjusted to default - invalid data have provided"
                    )
                ovSize = [100.0, 100.0]
            else:
                ovSize.append(float(self.ovsize[0]) / dbu)
                ovSize.append(float(self.ovsize[0]) / dbu)
        else:
            ovSize.append(float(self.ovsize[0]) / dbu)
            ovSize.append(float(self.ovsize[1]) / dbu)

        armLenght = self.armLenght / dbu
        armWidth = self.armWidth / dbu
        activeArea = [size[0] - self.actOffset, size[1] - self.actOffset]
        woW = self.woW / dbu
        woOP = self.woOP / dbu

        # Membrane Geometry:

        ## arm location on a rectangle = edgeArmOffset
        edgeArmOffset = armWidth / 2 * math.sqrt(2)

        if self.debug:
            print("Size 0:{:.3f}, {}, {}".format(size[0], armLenght, armWidth))
        ## arm starts at following points
        pointArmA = pya.DPoint(size[0] / 2 - edgeArmOffset, size[1] / 2)
        pointArmD = pya.DPoint(size[0] / 2, size[1] / 2 - edgeArmOffset)

        ## arm ends in the point P - might be usefull as a connector point
        pointP = pya.DPoint(size[0] / 2 + armLenght / math.sqrt(2),
                            size[1] / 2 + armLenght / math.sqrt(2))

        ## arm edge points offsets from the center point P
        armEndPointoffset = armWidth / 2 / math.sqrt(2)

        ## Arm edge points in relation to the P point

        pointArmB = pya.DPoint(pointP.x - armEndPointoffset,
                               pointP.y + armEndPointoffset)
        pointArmC = pya.DPoint(pointP.x + armEndPointoffset,
                               pointP.y - armEndPointoffset)

        ## Lets Try to assemble the membrane as 1/4

        polyPoints = []
        polyPoints.append(pya.DPoint(0.0, 0.0))
        polyPoints.append(pya.DPoint(0.0, size[1] / 2))
        polyPoints.append(pointArmA)
        polyPoints.append(pointArmB)
        polyPoints.append(pointArmC)
        polyPoints.append(pointArmD)
        polyPoints.append(pya.DPoint(size[0] / 2, 0.0))

        #Lets put it there
        shapeSet = []

        Poly = pya.DPolygon(polyPoints)
        shapeSet.append(Poly)

        t = pya.DCplxTrans(1.0, 180, False, 0.0, 0.0)
        Poly1 = pya.DPolygon(polyPoints)
        Poly1.transform(t)
        shapeSet.append(Poly1)

        t = pya.DCplxTrans(1.0, 0, True, 0.0, 0.0)
        Poly2 = pya.DPolygon(polyPoints)
        Poly2.transform(t)
        shapeSet.append(Poly2)

        t = pya.DCplxTrans(1.0, 180, True, 0.0, 0.0)
        Poly3 = pya.DPolygon(polyPoints)
        Poly3.transform(t)
        shapeSet.append(Poly3)

        tr = pya.DCplxTrans(1000.0)
        region = pya.Region(shapeSet)
        region.merge()
        region.transform(tr)

        self.cell.shapes(self.l_layer).insert(region)

        #Active Area
        if self.showAct:
            actBox = pya.DBox(-activeArea[0] / 2, -activeArea[1] / 2,
                              activeArea[0] / 2, activeArea[1] / 2)
            self.cell.shapes(self.la_layer).insert(actBox)

        # Etch area - a rectangele limited by the membrane shape and P point
        etchBox = pya.DBox(-pointP.x, -pointP.y, pointP.x, pointP.y)
        etchRegion = pya.Region(etchBox)
        etchRegion.transform(tr)
        tempRegion = region ^ etchRegion
        etchRegion = tempRegion & etchRegion
        self.cell.shapes(self.ool_layer).insert(etchRegion)

        # Heater wire
        if self.genHeater:
            if self.heatType == 0:
                #Hilbert is defined only for square areas. We would fit whatever is smaller

                if activeArea[0] != activeArea[1]:
                    if (activeArea[0] > activeArea[1]):
                        wireArea = activeArea[1] / 2
                    else:
                        wireArea = activeArea[0] / 2
                else:
                    wireArea = activeArea[0] / 2

                #issue num2:
                #  the diagonal contact placemnet is required
                #  so we have to calculate space for the return path
                #  segment separation 1sqg => seg = wireArea / 2^n + 1

                Hcnt = 2**self.heatOrder + 1
                Hseg = wireArea / (Hcnt)
                print("Hseq: {:.3f}".format(Hseg))
                wireAreaRed = wireArea - Hseg
                a = wireAreaRed + wireAreaRed * 1j
                b = wireAreaRed - wireAreaRed * 1j
                z = 0

                for i in range(1, self.heatOrder + 1):
                    w = 1j * z.conjugate()
                    z = numpy.array([w - a, z - b, z + a, b - w]) / 2
                z = z.flatten()
                X = [x.real for x in z]
                Y = [x.imag for x in z]

                heatPoints = []

                for i in range(0, len(X)):
                    heatPoints.append(pya.DPoint(X[i], Y[i]))

                #lets add the return path
                #  start with calculation of intersection to the beam

                #  linEqa = -1*(pointP.y / pointP.x) - valid only for Square
                #
                #print("Linear equation is y = {:.3f}.x".format(linEqa))

                heatInitial = heatPoints[0]

                pointS1 = pya.DPoint(-size[0] / 2, size[1] / 2)
                #pointS2 = pya.DPoint(activeArea[0]/2, -activeArea[1]/2)
                if self.debug:
                    print("P:{:.3f},{:.3f} ; S:{:.3f},{:.3f}".format(
                        -pointP.x, pointP.y, pointS1.x, pointS1.y))
                linEqa = (pointP.y - pointS1.y) / (-pointP.x - pointS1.x)
                linEqb = pointP.y - linEqa * -pointP.x
                if self.debug:
                    print("Line equation is: y={:.3f}x+{:.3f}".format(
                        linEqa, linEqb))

                heatPoints.insert(
                    0, pya.DPoint(heatPoints[0].x - 2 * Hseg, heatPoints[0].y))
                heatPoints.insert(
                    0,
                    pya.DPoint(heatPoints[0].x,
                               linEqa * (heatPoints[0].x + Hseg) + linEqb))
                heatPoints.append(pya.DPoint(heatPoints[len(heatPoints)-1].x, \
                    linEqa*(heatPoints[len(heatPoints)-1].x+Hseg)-linEqb))

                heatPoints.append(pya.DPoint(pointP.x - Hseg,
                                             -pointP.y))  #arm contacts
                heatPoints.insert(0, pya.DPoint(-pointP.x - Hseg, pointP.y))

                #probably somewhere here is a good time to calculate perforations
                # teoretically first opening should be -Heg/2 to the left of the very first
                # point and should repeat in X and Y axis with interval of Hseg
                #

                # center is HeatPoints[2] -Hseg/2 ?
                if self.perfAct:
                    perfW = self.perfSize / 2 / dbu
                    #perfCenter = pya.DPoint(heatPoints[2].x - Hseg, heatPoints[2].y - Hseg)
                    #perfBox = pya.DBox(perfCenter.x-perfW, perfCenter.y-perfW, perfCenter.x+perfW, perfCenter.y-perfW)
                    elCell = self.layout.create_cell("Perforator")
                    perfBox = pya.DPolygon(
                        pya.DBox(-perfW, -perfW, perfW, perfW))
                    if self.roundPath:
                        perfBox = perfBox.round_corners(Hseg / 2, Hseg / 2, 32)
                    elCell.shapes(self.perfl_layer).insert(perfBox)

                    #lets make an array of them
                    x_vect = pya.DVector(2 * Hseg, 0.0)
                    y_vect = pya.DVector(0.0, 2 * Hseg)
                    t = pya.DCplxTrans(heatInitial.x, heatInitial.y + Hseg)
                    perfArr = pya.DCellInstArray(elCell.cell_index(), t,
                                                 x_vect, y_vect, Hcnt - 1,
                                                 Hcnt - 2)

                    self.cell.insert(perfArr)

                    #move to the right coordinates
                    pathT = pya.DCplxTrans(Hseg, 0)
                    heatPath = pya.DPath(heatPoints, self.heatW)
                    heatPathT = heatPath.transformed(pathT)
                    if self.roundPath:
                        heatPathT = heatPath.round_corners(Hseg / 2, 32, 0.001)
                        heatCenter = heatPathT.bbox().center()
                        print(heatCenter)
                        print("Rounded Path center: {}:{}".format(
                            heatCenter.x, heatCenter.y))
                        pathTr = pya.DCplxTrans(-heatCenter.x, -heatCenter.y)
                        heatPathT = heatPathT.transformed(pathTr)
                    self.cell.shapes(self.heatl_layer).insert(heatPathT)
            else:
                print("Wire definition has not been found!")
                #TODO ... other types of heaters

        if self.genWO:
            #we would make a wire connection from the P point to the edge of the membrane
            # overpass on both sides as an option

            # it has to be realized as a set of the 4 path
            print("Overal size: {}:{}".format(ovSize[0], ovSize[1]))
            woPathA = pya.DPath(
                [pointP, pya.DPoint(ovSize[0] / 2, ovSize[1] / 2)], woW, woOP,
                woOP)
            woPathB = pya.DPath([pya.DPoint(-pointP.x, pointP.y), pya.DPoint(-ovSize[0]/2, ovSize[1]/2)],\
                woW, woOP, woOP)
            woPathC = pya.DPath([pya.DPoint(-pointP.x, -pointP.y), pya.DPoint(-ovSize[0]/2, -ovSize[1]/2)],\
                woW, woOP, woOP)
            woPathD = pya.DPath([pya.DPoint(pointP.x, -pointP.y), pya.DPoint(ovSize[0]/2, -ovSize[1]/2)],\
                woW, woOP, woOP)
            self.cell.shapes(self.cntl_layer).insert(woPathA)
            self.cell.shapes(self.cntl_layer).insert(woPathB)
            self.cell.shapes(self.cntl_layer).insert(woPathC)
            self.cell.shapes(self.cntl_layer).insert(woPathD)

        if self.genCnt:
            # Ok that would be fun ...
            #   so at first we should be able to find how many of the IGC we would be able to fit
            #   in between of the perforations (maybe we should count also for the minimal separation)
            #   principally:
            #       single IGS pair consists of 2 wires and 2 gaps = IGSpairW?
            #       testing condition is therefore IGSCnt = floor((Hseg - perfW) / IGSpairW)
            cntW = self.cntW / dbu
            cntSp = self.cntSp / dbu
            cntB = self.cntB / dbu
            cntBunchW = 2 * (cntW + cntSp)
            cntCnt = math.floor((2 * Hseg - 2 * perfW) / cntBunchW)
            if self.debug:
                print("IDC W={}".format(cntBunchW))
                print("IDCs per bunch: {}".format(cntCnt))
            if cntCnt == 0:
                print(
                    "Error: Interdigital contacts with given specs could not be realized because of geometric containts!"
                )
            else:
                #lets make a subcell with interdigital pair
                #   so first calculate the active area - contact bars to get the lenght
                #   contacts singles
                cntCell = self.layout.create_cell("IDC_subcell")
                cntArrCell = self.layout.create_cell("IDC_cell")

                #cntLenght = activeArea - 2*cntB - cntSp

                cntPath_p1 = pya.DPoint((cntSp + cntW) / 2,
                                        activeArea[1] / 2 - cntB)
                cntPath_p2 = pya.DPoint((cntSp + cntW) / 2,
                                        -activeArea[1] / 2 + cntSp +
                                        cntB)  #TODO tohle je asi blbe ...
                cntPath_pA = [cntPath_p1, cntPath_p2]
                cntPath_pB = [cntPath_p1 * -1, cntPath_p2 * -1]

                cntPath_A = pya.DPath(cntPath_pA, cntW, 0.0, 0.0)
                cntPath_B = pya.DPath(cntPath_pB, cntW, 0.0, 0.0)

                cntCell.shapes(self.idcl_layer).insert(cntPath_A)
                cntCell.shapes(self.idcl_layer).insert(cntPath_B)

                #now lets make bunches of cntCnt and center them
                # TODO: tady jsem skoncil ... potreba projit odstavec pod
                #BEGIN
                x_vect = pya.DVector(cntBunchW, 0.0)
                y_vect = pya.DVector(0.0, 0.0)
                if self.debug:
                    print("IDC bunch Vectors: {}, {}, {}, {}".format(\
                        x_vect.x, x_vect.y, y_vect.x, y_vect.y))
                t = pya.DCplxTrans(0, 0)
                cntArr = pya.DCellInstArray(cntCell.cell_index(), t, x_vect,
                                            y_vect, cntCnt, 1)

                #center the origins on top of each other
                #   here we have a bunch of IDCs
                cntArr_center = cntArr.bbox(self.layout).center()
                if self.debug:
                    print("Bunch center: {},{}".format(cntArr_center.x,
                                                       cntArr_center.y))
                t = pya.DCplxTrans(1.0, 0, False, -cntArr_center.x,
                                   -cntArr_center.y)
                cntArr.transform(t)
                cntArrCell.insert(cntArr)

                #   move the array to the position of Hilb. initial and paste it into the overal array

                a_vect = pya.DVector(2 * Hseg, 0.0)
                b_vect = pya.DVector(0.0, 0.0)

                cntLoct = pya.DCplxTrans(1.0, 0, False, heatInitial.x - Hseg,
                                         0.0)

                cntArrAll = pya.DCellInstArray(cntArrCell.cell_index(),
                                               cntLoct, a_vect, b_vect, Hcnt,
                                               1)
                self.cell.insert(cntArrAll)

                #Top and bottom contact
                #  by principle the bar-contact should be horizontally oriented across the active zone
                #  then they should continue to the respective P-points (upright, lowerleft)

                #  Contact bar would be a box from the edge to the edge of active area with a width of
                #  cntB

                # pointCNT1A = pya.DPoint(activeArea[0]/2, activeArea[1]/2)

                # if self.debug:
                #     print("P:{:.3f},{:.3f} ; CNT:{:.3f},{:.3f}".format(-pointP.x, pointP.y, pointCNT1A.x, pointCNT1A.y))
                # linCntEqa = (pointP.y-pointCNT1A.y)/(-pointP.x-pointCNT1A.x)
                # linCntEqb = pointP.y - linCntEqa*-pointP.x

                # if self.debug:
                #     print("CNT line equation is: y={:.3f}x+{:.3f}".format(linEqa,linEqb))

                # pointCNT1B =

                # Contact Bars
                cntBarW = self.cntB / dbu
                cntWoW = self.cntWO / dbu
                shapeSetCNT = []
                #cntBarA
                shapeSetCNT.append(pya.DBox(-activeArea[0]/2, activeArea[1]/2-cntBarW,\
                    activeArea[0]/2, activeArea[1]/2))
                #cntBarB
                shapeSetCNT.append(pya.DBox(-activeArea[0]/2, -activeArea[1]/2,\
                    activeArea[0]/2, -activeArea[1]/2+cntBarW))

                pointS2 = pya.DPoint(activeArea[0] / 2, activeArea[1] / 2)
                #cntWOPathA
                shapeSetCNT.append(
                    pya.DPath([pointS2, pointP], cntWoW, cntWoW / 2,
                              cntWoW).polygon())
                #cntWOPathB
                shapeSetCNT.append(
                    pya.DPath([-pointS2, -pointP], cntWoW, cntWoW / 2,
                              cntWoW).polygon())

                for shape in shapeSetCNT:
                    self.cell.shapes(self.idcl_layer).insert(shape)

                #Vias
                #TODO: repair position of the vias

                cntViaW = cntWoW * 0.9 / 2  # 10% smaller then the wire
                tr = pya.DCplxTrans(1.0, 45.0, False, pya.DVector(pointP))
                cntViaA = pya.DPolygon(pya.DBox(-cntViaW, -cntViaW,\
                    cntViaW, cntViaW)).transform(tr)
                tr = pya.DCplxTrans(1.0, 45.0, False, pya.DVector(-pointP))
                cntViaB = pya.DPolygon(pya.DBox(-cntViaW, -cntViaW,\
                    cntViaW, cntViaW)).transformed(tr)
                self.cell.shapes(self.lvia_layer).insert(cntViaA)
                self.cell.shapes(self.lvia_layer).insert(cntViaB)