Simple Geometric Objects Class

edited February 2022 in Python scripting

Hello,
I did not find anything comparable yet. The PCell Library is, from what I read here, not for scripting. So I leave this piece of code here. Hope you enjoy. I am happy for feedback.

class SimpleGeometry:
    import pya as pya
    import numpy as np
    def __init__(self,layout):
        self.dbu=layout.dbu

    def circle(self,rad=1,npts=100):
        """
        creates a klayout database object Polygon with points of a circle outline
        origin is 0,0
        units in microns
        @param rad: radius 1
        @type rad:float
        @param npts: number of points
        @return: Polygon of shape
        @rtype: pya:Polygon
        """
        out=[]
        delta_phi=(2*np.pi)/npts
        rad_dbu=int(rad/self.dbu)

        for i in range(0, npts):
            out.append(
                Point.new(rad_dbu * np.cos(i * delta_phi),
                                             rad_dbu * np.sin(i * delta_phi)))

        return pya.Polygon.new(out)

    def torus(self,rad1=10,rad2=1,start_phi=0,end_phi=90,npts=100):
        """
        creates a klayout database object Polygon with points of a torus outline
        origin is 0,0
        units in microns
        @param rad1: radius 1
        @type rad1:float
        @param rad2: radius 2
        @type rad2:float
        @param start_phi: starting angle
        @param end_phi: end angle
        @param npts: number of points
        @return: Polygon of shape
        @rtype: pya:Polygon
        """
        out = []
        delta_phi = ((start_phi - end_phi) / 360 * 2 * np.pi) / npts
        rad1_dbu = int(rad1 / self.dbu)
        rad2_dbu = int(rad2 / self.dbu)
        for i in range(0, npts + 1):
            out.append(
                pya.Point.new(rad1_dbu * np.cos(i * delta_phi),
                          rad1_dbu * np.sin(i * delta_phi)))

        for i in range(npts, -1, -1):
            out.append(
                pya.Point.new(rad2_dbu * np.cos(i * delta_phi),
                          rad2_dbu * np.sin(i * delta_phi)))
        return pya.Polygon.new(out)

    def ellipse(self,rad1=0.5,rad2=1,npts=100):
        """
        creates a klayout database object Polygon with points of an ellipse outline
        origin is 0,0
        units in microns
        @param rad1: radius 1 in x direction
        @type rad1:float
        @param rad2: radius 2 in y direction
        @type rad2:float
        @param npts: number of points
        @return: Polygon of shape
        @rtype: pya:Polygon
        """
        out = []
        delta_phi = (2 * np.pi) / npts
        rad1_dbu = int(rad1 / self.dbu)
        rad2_dbu = int(rad2 / self.dbu)

        for i in range(0, npts):
            out.append(
                pya.Point.new(rad1_dbu * np.cos(i * delta_phi),
                          rad2_dbu * np.sin(i * delta_phi)))

        return pya.Polygon.new(out)

    def box(self,*args):
        """
        args: width, height
        Returns box object with origin at lower left corner
        If only one argument is passed, a square with length of parameter 1 is returned
        @param args: length in x direction, length in y direction
        @type args: float
        @return: box of shape
        @rtype: pya:Box
        """
        if len(args) < 1:
            raise Exception('At least one argument is expected')
        if len(args) > 2:
            raise Exception('Maximum of two arguments is expected')
        if len(args) < 2:
            a = args[0]
            b = a
        else:
            a = args[0]
            b = args[1]
        return pya.Box.new(int(0), int(0), int(a/self.dbu), int(b/self.dbu))

*edit: renamed def Box -> def box to avoid confusion with the box object
and implemented import of dependencies

Comments

  • edited February 2022

    @LeoPh Thank you for sharing this code!

    Actually you are right, the CIRCLE PCell is way too heavy for scripting a simple circle.

    But there actually is a simple solution for generating circles and ellipses:

    # circle centered around the origin
    circle = pya.Polygon.ellipse(pya.Box(-r, -r, r, r), npoints)
    # ellipse centered around the origin
    ellipse = pya.Polygon.ellipse(pya.Box(-rx, -ry, rx, ry), npoints)
    

    The torus however is nice :) One could do that with a boolean, but coding it explicitly makes some sense here.

    Plus, owning the code opens space for individual adjustments - e.g. whether the polygon provides an inner or outer approximation of the circle or whether it satisfies special tangential constraints.

    Thanks,

    Matthias

Sign In or Register to comment.