Beispiel #1
0
 class Layout(WireWaveguideTemplate.Layout):
     core_process = ProcessProperty(locked=True, default=TECH.PROCESS.WG)
     core_purpose = PurposeProperty(locked=True, default=TECH.PURPOSE.CORE)
     cladding_process = ProcessProperty(locked=True, default=TECH.PROCESS.WG)
     cladding_purpose = PurposeProperty(locked=True, default=TECH.PURPOSE.CLADDING)
     core_width = PositiveNumberProperty(default=TECH.WG.CORE_WIDTH)
     cladding_width = PositiveNumberProperty(default=TECH.WG.CLADDING_WIDTH)
Beispiel #2
0
    class Layout(wire_wg.WireWaveguideTemplate.Layout):
        core_width = PositiveNumberProperty(
            doc="Width of the core of the wire waveguide.")
        trench_width = PositiveNumberProperty(
            doc="Lateral material exclusion.")
        cladding_width = PositiveNumberProperty(
            doc="Cladding width of the wire waveguide.")

        core_process = ProcessProperty(
            locked=True,
            doc="Process used for the core layer of the MSN wire waveguide.")
        core_purpose = PurposeProperty(
            locked=True,
            doc="Purpose used for the core layer of the MSN wire waveguide.")

        trench_process = ProcessProperty(
            locked=True,
            doc=
            "Process used for the exclusion layer of the MSN wire waveguide.")
        trench_purpose = PurposeProperty(
            locked=True,
            doc=
            "Purpose used for the exclusion layer of the MSN wire waveguide.")

        cladding_process = ProcessProperty(
            locked=True,
            doc="Process used for the cladding layer of the MSN wire waveguide."
        )
        cladding_purpose = PurposeProperty(
            locked=True,
            doc="Purpose used for the cladding layer of the MSN wire waveguide."
        )

        def _default_core_process(self):
            return TECH.PROCESS.MSN

        def _default_core_purpose(self):
            return TECH.PURPOSE.DRAWING

        def _default_trench_process(self):
            return TECH.PROCESS.MSN_TRENCH

        def _default_trench_purpose(self):
            return TECH.PURPOSE.DRAWING

        def _default_cladding_process(self):
            return TECH.PROCESS.CLADDING

        def _default_cladding_purpose(self):
            return TECH.PURPOSE.DRAWING

        def _default_core_width(self):
            return TECH.WIREWG.WIRE_WIDTH

        def _default_trench_width(self):
            return TECH.WIREWG.TRENCH_WIDTH

        def _default_cladding_width(self):
            return TECH.WIREWG.CLADDING_WIDTH
Beispiel #3
0
    class Layout(rib_wg.RibWaveguideTemplate.Layout):
        core_process = ProcessProperty(
            locked=True,
            doc="Process used for the core layer of the MSN rib_old waveguide."
        )
        core_purpose = PurposeProperty(
            locked=True,
            doc="Purpose used for the core layer of the MSN rib_old waveguide."
        )
        exclusion_process = ProcessProperty(
            locked=True,
            doc=
            "Process used for the exclusion layer of the silicon wire waveguide."
        )
        exclusion_purpose = PurposeProperty(
            locked=True,
            doc=
            "Purpose used for the exclusion layer of the silicon wire waveguide."
        )
        cladding_process = ProcessProperty(
            locked=True,
            doc=
            "Process used for the cladding layer of the MSN rib_old waveguide."
        )
        cladding_purpose = PurposeProperty(
            locked=True,
            doc=
            "Purpose used for the cladding layer of the MSN rib_old waveguide."
        )
        core_width = PositiveNumberProperty(
            doc="Width of the core of the rib_old waveguide.")
        cladding_width = PositiveNumberProperty(
            doc="Cladding width of the rib_old waveguide.")

        def _default_core_process(self):
            return TECH.PROCESS.MSN

        def _default_core_purpose(self):
            return TECH.PURPOSE.DRAWING

        def _default_exclusion_process(self):
            return TECH.PROCESS.MSN

        def _default_exclusion_purpose(self):
            return TECH.PURPOSE.DRAWING

        def _default_cladding_process(self):
            return TECH.PROCESS.SHALLOW

        def _default_cladding_purpose(self):
            return TECH.PURPOSE.DRAWING

        def _default_core_width(self):
            return TECH.RIBWG.RIB_WIDTH

        def _default_cladding_width(self):
            return TECH.WIREWG.CLADDING_WIDTH
Beispiel #4
0
class Font(StrongPropertyInitializer):
    coords = RestrictedProperty(restriction = RestrictType(dict), default = {})
    line_width = PositiveNumberProperty(default = 0.1)
    default_char = RestrictedProperty(restriction = RestrictType(list), default = [[]])
    cell_size = Size2Property(default = (0.6, 1.0))
    spacing = NonNegativeNumberProperty(default = 0.2)
    def __init__(self, **kwargs):
        super(Font, self).__init__(
            **kwargs)

    def shapes_character (self, character, letter_height = 1.0, south_west_coord = (0.0,0.0), angle = 0.0):
        #returns a list of shapes!!!
        if character in self.coords:
            shapes = self.coords[character]
        else:
            shapes = [self.default_char]
        ret_shapes = []
        #T = Rotation((0.0,0.0), angle) + Magnification((0.0,0,0), letter_height) + Translation(south_west_coord)
        T = NoDistortTransform(south_west_coord, angle, letter_height/self.letter_height())
        for s in shapes:
            if len(s) < 2:
                LOG.warning("Shape with too few coordinates in letter " % character)
            #ret_shapes.append(shape_translate(shape_scale(shape_rotate(s, (0.0,0.0), angle), (letter_height, letter_height)), south_west_coord))		
            ret_shapes.append(T.apply_to_copy(s))
        return ret_shapes

    def letter_width(self):
        return self.cell_size[0]
    
    def letter_height(self):
        return self.cell_size[1]
Beispiel #5
0
class ShapeRegularPolygon(Shape):
    """ regular N-sided polygon """
    center = Coord2Property(default=(0.0, 0.0))
    radius = PositiveNumberProperty(default=1.0)
    n_o_sides = IntProperty(default=8, restriction=RestrictRange(lower=3))

    def __init__(self, **kwargs):
        kwargs["closed"] = True
        super(ShapeRegularPolygon, self).__init__(**kwargs)

    def define_points(self, pts):
        if self.radius == 0.0:
            pts.append(self.center)
            return pts
        angle_step = 2 * math.pi / self.n_o_sides
        for i in xrange(0, self.n_o_sides):
            pts.append(
                (self.center[0] +
                 self.radius * math.cos((i + 0.5) * angle_step + math.pi / 2),
                 self.center[1] +
                 self.radius * math.sin((i + 0.5) * angle_step + math.pi / 2)))
        return pts

    def move(self, position):
        self.center = Coord2(self.center[0] + position[0],
                             self.center[1] + position[1])
        return self

    def is_empty(self):
        return (self.radius == 0.0)
Beispiel #6
0
class InputBasic(BasicInput):
    scaling = PositiveNumberProperty(default=1.0)
    layer_map = DefinitionProperty()
    prefix = StringProperty(default="")

    def __init__(self, i_stream=sys.stdin, **kwargs):
        super(InputBasic, self).__init__(i_stream=i_stream, **kwargs)
        self.library = None

    def read(self):
        return self.parse()

    def parse(self):
        return self.parse_library()

    def parse_library(self):
        self.library = Library("IMPORT")
        self.__parse_library__()
        return self.library

    def map_layer(self, layer):
        L = self.layer_map.get(layer, None)
        if isinstance(L, __Layer__):
            return L
        elif L is None:
            return L
        else:
            return Layer(L)

    def make_structure_name(self, name):
        return self.prefix + name

    def define_layer_map(self):
        return TECH.GDSII.IMPORT_LAYER_MAP  #FIXME : using 'default' for the property would be better, but that gives an exception ...
Beispiel #7
0
class UnitGridContainer(StrongPropertyInitializer):
    grids_per_unit = DefinitionProperty(fdef_name="define_grids_per_unit")
    units_per_grid = DefinitionProperty(fdef_name="define_units_per_grid")
    unit = PositiveNumberProperty(default=TECH.METRICS.UNIT)
    grid = PositiveNumberProperty(default=TECH.METRICS.GRID)

    def define_grids_per_unit(self):
        return self.unit / self.grid

    def define_units_per_grid(self):
        return self.grid / self.unit

    def validate_properties(self):
        if self.grid > self.unit:
            raise Exception("The grid should be smaller than the unit.")
        return True
Beispiel #8
0
class ShapeCross(Shape):
    """ cross. thickness sets the width of the arms """
    center = Coord2Property(default=(0.0, 0.0))
    box_size = PositiveNumberProperty(default=20.0)
    thickness = PositiveNumberProperty(default=5.0)

    def __init__(self, **kwargs):
        kwargs["closed"] = True
        super(ShapeCross, self).__init__(**kwargs)

    def define_points(self, pts):
        pts += [(self.center[0] - self.box_size / 2.0,
                 self.center[1] - self.thickness / 2.0),
                (self.center[0] - self.box_size / 2.0,
                 self.center[1] + self.thickness / 2.0),
                (self.center[0] - self.thickness / 2.0,
                 self.center[1] + self.thickness / 2.0),
                (self.center[0] - self.thickness / 2.0,
                 self.center[1] + self.box_size / 2.0),
                (self.center[0] + self.thickness / 2.0,
                 self.center[1] + self.box_size / 2.0),
                (self.center[0] + self.thickness / 2.0,
                 self.center[1] + self.thickness / 2.0),
                (self.center[0] + self.box_size / 2.0,
                 self.center[1] + self.thickness / 2.0),
                (self.center[0] + self.box_size / 2.0,
                 self.center[1] - self.thickness / 2.0),
                (self.center[0] + self.thickness / 2.0,
                 self.center[1] - self.thickness / 2.0),
                (self.center[0] + self.thickness / 2.0,
                 self.center[1] - self.box_size / 2.0),
                (self.center[0] - self.thickness / 2.0,
                 self.center[1] - self.box_size / 2.0),
                (self.center[0] - self.thickness / 2.0,
                 self.center[1] - self.thickness / 2.0),
                (self.center[0] - self.box_size / 2.0,
                 self.center[1] - self.thickness / 2.0)]
        return pts

    def move(self, position):
        self.center = Coord2(self.center[0] + position[0],
                             self.center[1] + position[1])
        return self

    def is_empty(self):
        return self.box_size == 0.0 or self.thickness == 0.0
Beispiel #9
0
class ShapeRoundedRectangleArc(Shape):
    center = Coord2Property(default=(0.0, 0.0))
    box_size = Size2Property(default=(1.0, 1.0))
    radius = PositiveNumberProperty(default=0.1)
    start_angle = AngleProperty(default=0.0)
    end_angle = AngleProperty(default=90.0)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)
    clockwise = BoolProperty(default=False)

    def __init__(self, **kwargs):
        super(ShapeRoundedRectangleArc, self).__init__(**kwargs)
        # restrict radius
        if self.radius > min(self.box_size) / 2.0:
            self.radius = min(self.box_size) / 2.0

    def define_points(self, pts):
        cx = self.center[0]
        cy = self.center[1]
        dx = 0.5 * self.box_size[0]
        dy = 0.5 * self.box_size[1]
        if self.clockwise:
            as_sign = -1
        else:
            as_sign = 1
        # radius = box: circle arc
        if (self.radius == self.box_size[0] / 2.0) and (
                self.radius == self.box_size[1] / 2.0):
            pts += ShapeArc(
                self.center,
                self.radius,
                self.start_angle,
                self.end_angle,
                angle_step=self.angle_step,
                clockwise=self.clockwise)
        # radius = zero: part of rectangle
        elif self.radius <= 0:
            for a in arange(self.start_angle, self.end_angle + 45.0,
                            as_sign * 90.0):
                pts += [(cx + sign(math.cos(DEG2RAD * a)) * dx,
                         cy + sign(math.sin(DEG2RAD * a)) * dy)]
        # arbitrary
        else:
            for a in numpy.arange(self.start_angle, self.end_angle + 45.0,
                                  as_sign * 90.0):
                start = max(self.start_angle,
                            a - a % 90.0 + 45.0 - as_sign * 45.0)
                end = min(self.end_angle, a - a % 90.0 + 45.0 + as_sign * 45.0)
                pts += ShapeArc(
                    center=(cx + numpy.sign(math.cos(DEG2RAD * a)) *
                            (dx - self.radius),
                            cy + numpy.sign(math.sin(DEG2RAD * a)) *
                            (dy - self.radius)),
                    radius=self.radius,
                    start_angle=start,
                    end_angle=end,
                    angle_step=self.angle_step,
                    clockwise=self.clockwise)
        return pts
Beispiel #10
0
class ShapeSamplePeriodic(ShapeSample):
    """ creates a shape sampling points on another shape along specified periodic distances from the start point of the shape """
    sampling_period = PositiveNumberProperty(required = True)
    exclude_ends = Size2Property(default = (0.0, 0.0), doc = "Lengths not taken into account on both ends")
    sampling_distances = LockedProperty()
    
    def define_sampling_distances(self):
        L = self.original_shape.length()
        return arange(self.exclude_ends[0], L-self.exclude_ends[1]+0.001 * self.sampling_period, self.sampling_period)
Beispiel #11
0
    class Layout(WindowWaveguideTemplate.Layout):

        core_process        = ProcessProperty(default=TECH.PROCESS.WG, doc="process for the waveguide core")
        core_purpose        = PurposeProperty(default=TECH.PURPOSE.LF.LINE, doc="drawing purpose for the waveguide core")
        cladding_process    = ProcessProperty(doc="process for the waveguide cladding, defaults to the core process")
        cladding_purpose    = PurposeProperty(default=TECH.PURPOSE.LF_AREA, doc="drawing purpose layer for the cladding")
        # core_width          = PositiveNumberProperty(default=TECH.WG.CORE_WIDTH)
        cladding_width      = PositiveNumberProperty(default=TECH.WG.CLADDING_WIDTH,
                                                doc="total width of the waveguide with cladding")

        def _default_cladding_process(self):
            return self.core_process

        def _default_cover_layers(self):
            # Layer for Manhattan rectangles
            return [PPLayer(self.cladding_process, self.cladding_purpose)]

        def validate_properties(self):
            if self.cladding_width < self.core_width:
                raise PropertyValidationError(
                    "The waveguide cladding should be at least of as wide as the core. core={:f}, cladding={:f}".format(
                        self.core_width, self.cladding_width))
            return True

        def _default_width(self):
            return self.cladding_width

        def _default_windows(self):

            # populate the cladding PPlayers
            clad_pp_layers_list = [
                TECH.PPLAYER.AIM.BESAMFILL,
                TECH.PPLAYER.AIM.BCAAMFILL,
                TECH.PPLAYER.AIM.BSEAMFILL,
                TECH.PPLAYER.AIM.BFNAMFILL,
                TECH.PPLAYER.AIM.BSNAMFILL,
                TECH.PPLAYER.AIM.BM1AMFILL,
                TECH.PPLAYER.AIM.BMLAMFILL,
                TECH.PPLAYER.AIM.BM2AMFILL,
                    ]

            windows = []

            # add cladding windows
            for pplayer in clad_pp_layers_list:
                windows.append(PathTraceWindow(layer=pplayer,
                                               start_offset=-0.5 * self.cladding_width,
                                               end_offset=+0.5 * self.cladding_width,
                                               shape_property_name="cladding_shape"))

            # add core layer
            windows.append(PathTraceWindow( layer           = TECH.PPLAYER.WG.COR,
                                            start_offset    = -0.5 * self.core_width,
                                            end_offset      = +0.5 * self.core_width))

            return windows
Beispiel #12
0
class ShapeRadialWedge(Shape):
    """ radial wedge: the coordinates of the start and end point are specified in polar coordinates
        from a given center """
    center = Coord2Property(default=(0.0, 0.0))
    inner_radius = PositiveNumberProperty(required=True)
    outer_radius = PositiveNumberProperty(required=True)
    inner_width = PositiveNumberProperty(required=True)
    outer_width = PositiveNumberProperty(required=True)
    angle = NormalizedAngleProperty(required=True)

    def __init__(self, **kwargs):
        kwargs["closed"] = True
        super(ShapeRadialWedge, self).__init__(**kwargs)

    def define_points(self, pts):
        cosangle = math.cos(self.angle * DEG2RAD)
        sinangle = math.sin(self.angle * DEG2RAD)
        bc = (self.center[0] +
              self.inner_radius * math.cos(self.angle * DEG2RAD),
              self.center[1] +
              self.inner_radius * math.sin(self.angle * DEG2RAD))
        ec = (self.center[0] +
              self.outer_radius * math.cos(self.angle * DEG2RAD),
              self.center[1] +
              self.outer_radius * math.sin(self.angle * DEG2RAD))
        pts += [(bc[0] + sinangle * self.inner_width / 2.0,
                 bc[1] - cosangle * self.inner_width / 2.0),
                (bc[0] - sinangle * self.inner_width / 2.0,
                 bc[1] + cosangle * self.inner_width / 2.0),
                (ec[0] - sinangle * self.outer_width / 2.0,
                 ec[1] + cosangle * self.outer_width / 2.0),
                (ec[0] + sinangle * self.outer_width / 2.0,
                 ec[1] - cosangle * self.outer_width / 2.0)]
        return pts

    def move(self, position):
        self.center = (self.center[0] + position[0],
                       self.center[1] + position[1])
        return self

    def is_empty(self):
        return self.inner_radius == self.outer_radius
Beispiel #13
0
    class Layout(GenericWaveGuideTemplate.Layout):

        cladding_width = PositiveNumberProperty(default=2.0)
        exclusion_width = PositiveNumberProperty(default=20.0)
        cladding_layer = LayerProperty()
        exclusion_layer = LayerProperty()

        def _default_exclusion_layer(self):
            return TECH.PPLAYER.MSN_TRENCH

        def _default_core_layer(self):
            return TECH.PPLAYER.MSN

        def _default_cladding_layer(self):
            return TECH.PPLAYER.CLADDING

        def _default_core_width(self):
            return 0.45

        def _default_windows(self):
            windows = [
                PathTraceWindow(layer=self.core_layer,
                                start_offset=-0.5 * self.core_width,
                                end_offset=0.5 * self.core_width),
                PathTraceWindow(layer=self.cladding_layer,
                                start_offset=-0.5 * self.cladding_width,
                                end_offset=0.5 * self.cladding_width),
                PathTraceWindow(layer=self.exclusion_layer,
                                start_offset=-0.5 * self.exclusion_width,
                                end_offset=0.5 * self.exclusion_width)
            ]

            windows = [
                PathTraceWindow(layer=layer,
                                start_offset=-off / 2.0,
                                end_offset=off / 2.0)
                for off, layer in zip([1, 2., 3.0, 5.0, 9.0], [
                    self.core_layer, self.cladding_layer, self.exclusion_layer
                ])
            ]
            return windows
Beispiel #14
0
class ShapeArc(ShapeEllipseArc):
    """ circular arc """
    radius = PositiveNumberProperty(default=1.0)
    box_size = DefinitionProperty(fdef_name="define_box_size")

    def __init__(self, **kwargs):
        ShapeEllipseArc.__init__(self,
                                 **kwargs)  # super gives error -- why? FIXME

    def define_box_size(self):
        bs = Coord2(2 * self.radius, 2 * self.radius)
        return bs
Beispiel #15
0
class ShapeRingSegment(Shape):
    """ ring segment """
    center = Coord2Property(default=(0.0, 0.0))
    angle_start = AngleProperty(default=0.0)
    angle_end = AngleProperty(default=90.0)
    inner_radius = PositiveNumberProperty(required=True)
    outer_radius = PositiveNumberProperty(required=True)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)

    def __init__(self, **kwargs):
        kwargs["closed"] = True
        super(ShapeRingSegment, self).__init__(**kwargs)

    def define_points(self, pts):
        arc1 = ShapeArc(
            center=self.center,
            radius=self.inner_radius,
            start_angle=self.angle_start,
            end_angle=self.angle_end,
            angle_step=self.angle_step)
        Shape.reverse(arc1)  # do not destroy dynamism
        arc2 = ShapeArc(
            center=self.center,
            radius=self.outer_radius,
            start_angle=self.angle_start,
            end_angle=self.angle_end,
            angle_step=self.angle_step)
        pts += arc1
        pts += arc2
        return pts

    def move(self, position):
        self.center = (self.center[0] + position[0],
                       self.center[1] + position[1])
        return self

    def is_empty(self):
        return self.inner_radius == self.outer_radius or self.angle_start == self.angle_end
Beispiel #16
0
class __TextElement__(__LayerElement__):
    text = StringProperty(required=True)
    coordinate = Coord2Property(default=(0.0, 0.0))
    alignment = AlignmentProperty(default=(constants.TEXT_ALIGN_CENTER,
                                           constants.TEXT_ALIGN_TOP))
    height = PositiveNumberProperty(default=20.0)
    font = FontProperty(default=TEXT_FONT_DEFAULT)

    def __init__(self,
                 layer,
                 text,
                 coordinate=(0.0, 0.0),
                 alignment=(constants.TEXT_ALIGN_CENTER,
                            constants.TEXT_ALIGN_TOP),
                 font=TEXT_FONT_DEFAULT,
                 height=20.0,
                 transformation=None,
                 **kwargs):
        super(__TextElement__, self).__init__(layer=layer,
                                              text=text,
                                              coordinate=coordinate,
                                              alignment=alignment,
                                              font=font,
                                              height=height,
                                              transformation=transformation,
                                              **kwargs)

    def get_h_alignment(self):
        return self.alignment[0]

    h_alignment = property(get_h_alignment)

    def get_v_alignment(self):
        return self.alignment[1]

    v_alignment = property(get_v_alignment)

    def is_empty(self):
        return (len(string.strip(self.text)) == 0) or (self.height == 0)
Beispiel #17
0
class OneEndedNaturalSpline(Shape):
    radius = PositiveNumberProperty(required=True)
    angle = AngleProperty(required=True)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)

    def define_points(self, pts):
        alpha = self.angle * DEG2RAD
        c = math.sin(alpha)
        if self.angle == 45.0:
            t = 0.5
        else:
            c2 = c**2
            t = math.sin(math.atan(((1.0 - c2) / c2)**0.125))**2

        a2 = (1 - t)**2 * (t**4 + (1 - t)**4)

        L = self.radius * 2 * t * (1 - t) / (
            3 * (t**4 + (1 - t)**4)**1.5
        )  # characteristic length of the full natural spline of a right angle

        # control points of full natural spline (right angle)
        q0_0 = Coord2(-L, 0)
        q0_1 = Coord2(0, 0)
        q0_2 = Coord2(0, 0)
        q0_3 = Coord2(0, L)

        # control points of first section of the spline
        q1_0 = t * q0_0 + (1 - t) * q0_1
        q2_0 = t**2 * q0_0 + 2 * t * (1 - t) * q0_1 + (1 - t)**2 * q0_2
        q3_0 = t**3 * q0_0 + 3 * t**2 * (1 - t) * q0_1 + 3 * t * (
            1 - t)**2 * q0_2 + (1 - t)**3 * q0_3

        S_control = Shape(points=[q0_0, q1_0, q2_0, q3_0])

        steps = int(math.ceil(2.0 * self.angle / self.angle_step))
        return ShapeBezier(original_shape=S_control,
                           steps=steps).points  # add angle step as a parameter
Beispiel #18
0
    class Layout(GenericWaveGuideTemplate.Layout):

        cladding_width = PositiveNumberProperty()
        cladding_layer = LayerProperty()

        def _default_cladding_width(self):
            return self.core_width + 4.0

        def _default_core_layer(self):
            return TECH.PPLAYER.SI

        def _default_cladding_layer(self):
            return TECH.PPLAYER.SHALLOW

        def _default_windows(self):
            windows = [
                PathTraceWindow(layer=self.core_layer,
                                start_offset=-0.5 * self.core_width,
                                end_offset=0.5 * self.core_width),
                PathTraceWindow(layer=self.cladding_layer,
                                start_offset=-0.5 * self.cladding_width,
                                end_offset=0.5 * self.cladding_width)
            ]
            return windows
Beispiel #19
0
class __ShapePathBase__(__ShapeStartEndAngle__):
    """ base class for path shapes"""
    path_width = PositiveNumberProperty(required=True)
Beispiel #20
0
class ShapeSerif(__ShapeModifier__):
    """ puts a bump on the corners of a given shape """
    stub_width = PositiveNumberProperty(required=True)
    stub_height = PositiveNumberProperty(required=True)
    tip_width = NonNegativeNumberProperty(required=True)
    only_sharp_angles = BoolProperty(default=False)

    def __init__(self, **kwargs):
        super(ShapeSerif, self).__init__(**kwargs)
        if self.original_shape.closed:
            self.close()
        else:
            self.open()

    def define_points(self, pts):
        c = Shape(self.original_shape)
        if len(c) == 0:
            return

        if self.original_shape.is_closed():
            if not c[0] == c[-1]:
                c.append(c[0])
            #closed curve
            c.append(c[1])
        else:
            # open curve
            pts.append(c[0])

        c.remove_identicals()

        min_sw = self.stub_width
        for i in range(1, len(c) - 1):
            angle1 = angle_rad(c[i], c[i - 1])
            angle2 = angle_rad(c[i + 1], c[i])
            turn = (angle2 - angle1 + pi) % (2 * pi) - pi
            if turn == 0 or (abs(turn) <=
                             (pi / 2.0) and self.only_sharp_angles):
                pts.append(c[i])
            elif abs(turn == pi):
                LOG.error("Cannot stub shape with a 180 degree turn")
            else:
                d1 = distance(c[i], c[i - 1])
                d2 = distance(c[i + 1], c[i])
                L = self.stub_width * sin(turn / 2.0) / sin(turn)
                max_L = max([d1 / 2.0, d2 / 2.0])
                if L > max_L:
                    L = max_L
                    sw = L * sin(turn) / sin(turn / 2.0)
                else:
                    sw = self.stub_width
                if sw < min_sw:
                    min_sw = sw

                theta_div2 = (pi - angle1 + angle2) % (2 * pi) / 2.0

                s1 = Coord2(c[i][0] - L * cos(angle1),
                            c[i][1] - L * sin(angle1))
                s2 = (c[i][0] + L * cos(angle2), c[i][1] + L * sin(angle2))

                B = -self.stub_height * sign(turn)
                delta = 0.5 * (self.stub_width - self.tip_width)
                s2 = (s1[0] + B * cos(angle1 + theta_div2) +
                      delta * cos(angle1 + theta_div2 - pi / 2.0),
                      s1[1] + B * sin(angle1 + theta_div2) +
                      delta * sin(angle1 + theta_div2 - pi / 2.0))
                s4 = Coord2(c[i][0] + L * cos(angle2),
                            c[i][1] + L * sin(angle2))
                s3 = (s4[0] + B * cos(angle2 + pi - theta_div2) +
                      delta * cos(angle2 + pi - theta_div2 + pi / 2.0),
                      s4[1] + B * sin(angle2 + pi - theta_div2) +
                      delta * sin(angle2 + pi - theta_div2 + pi / 2.0))
                pts.append(s1)
                pts.append(s2)
                pts.append(s3)
                pts.append(s4)

        if not self.original_shape.closed:
            # open curve
            pts.append(c[-1])

        if min_sw < self.stub_width:
            LOG.warning("Stub width is reduced from " + str(self.stub_width) +
                        " to " + str(min_sw) + "to stub shape.")

        return pts
Beispiel #21
0
class AdiabaticSplineCircleSplineShape(Shape):
    start_point = Coord2Property(required=True)
    turn_point = Coord2Property(required=True)
    end_point = Coord2Property(required=True)

    radius = PositiveNumberProperty(required=True)
    adiabatic_angles = RestrictedProperty(
        allow_none=True,
        doc="tuple of adiabatic transistion angles for input and output")
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)

    def define_points(self, pts):
        alpha_in = self.adiabatic_angles[0]
        alpha_out = self.adiabatic_angles[1]
        turn_angle = turn_deg(self.start_point, self.turn_point,
                              self.end_point)

        if (alpha_in + alpha_out) > abs(turn_angle):
            alpha_in = alpha_out = 0.5 * abs(turn_angle)

        bend_angle = abs(turn_angle) - alpha_in - alpha_out

        # first section
        if alpha_in > 0.0:
            S5 = OneEndedNaturalSpline(radius=self.radius,
                                       angle=alpha_in,
                                       angle_step=self.angle_step)
        else:
            S5 = Shape((-self.radius, 0))

        # middle section
        if bend_angle > 0.0:
            S5 += ShapeBendRelative(
                start_point=S5[-1],
                input_angle=alpha_in,
                angle_amount=bend_angle,
                radius=self.radius,
                angle_step=self.angle_step,
            )

        # last section
        if alpha_out > 0.0:
            S6 = Shape(
                OneEndedNaturalSpline(radius=self.radius,
                                      angle=alpha_out,
                                      angle_step=self.angle_step))
        else:
            S6 = Shape((-self.radius, 0))
        S6.h_mirror()
        S6.rotate((0, 0), abs(turn_angle))
        S6.reverse()
        S6.move(S5[-1] - S6[0])

        # transform to match the right position

        S = S5 + S6

        if turn_angle < 0:
            S.v_mirror()

        L = straight_line_from_point_angle((0.0, 0.0), turn_angle)
        d = L.distance(S[-1])

        ep = S[-1]
        if abs(turn_angle) == 90.0:
            d = ep.x
        else:
            d = ep.x - ep.y * math.cos(turn_angle * DEG2RAD) / math.sin(
                turn_angle * DEG2RAD)

        S.move((-d, 0.0))
        S.rotate((0.0, 0.0), angle_deg(self.turn_point, self.start_point))
        S.move(self.turn_point)
        S.remove_identicals()

        return S.points
Beispiel #22
0
class ShapeArcLineArc(Shape):
    coord_start = Coord2Property(required=True)
    angle_start = AngleProperty(required=True)
    radius_start = PositiveNumberProperty(required=True)

    coord_end = Coord2Property(required=True)
    angle_end = AngleProperty(required=True)
    radius_end = PositiveNumberProperty(required=True)

    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)

    def __init__(self, coord_start, angle_start, radius_start, coord_end,
                 angle_end, radius_end, **kwargs):
        super(ShapeArcLineArc, self).__init__(coord_start=coord_start,
                                              coord_end=coord_end,
                                              angle_start=angle_start,
                                              angle_end=angle_end,
                                              radius_start=radius_start,
                                              radius_end=radius_end,
                                              **kwargs)

    def define_points(self, pts):
        sa = self.angle_start * DEG2RAD
        ea = self.angle_end * DEG2RAD
        bae = (ea + pi) % (2 * pi)

        # normalize angles between 0 and 2pi
        sa = (sa) % (2 * pi)
        ea = (ea) % (2 * pi)

        #angle bvetween two points
        connect_angle = angle_rad(self.coord_end, self.coord_start)
        ca_start = (connect_angle - sa) % (2 * pi)
        ca_end = (connect_angle - ea) % (2 * pi)
        #LOG.debug("ca: %f %f %f" %(, connect_angle , ca_start, ca_end))

        #check both positive and negative radii
        valid = False
        signs = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
        for s in signs:
            radius_start = abs(self.radius_start) * s[0]
            radius_end = abs(self.radius_end) * s[1]

            # Centers of circles through the points.
            c_start = (self.coord_start[0] + radius_start * sin(sa),
                       self.coord_start[1] - radius_start * cos(sa))
            c_end = (self.coord_end[0] + radius_end * sin(ea),
                     self.coord_end[1] - radius_end * cos(ea))

            #distance between centers
            dm = distance(c_start, c_end)
            if abs(radius_start - radius_end) > dm:
                # no valid solution possible
                continue

            # unit vector between circle centers
            mm = ((c_end[0] - c_start[0]) / dm, (c_end[1] - c_start[1]) / dm)
            # angle between normal to connector line and circle centers
            alpha = -acos((radius_start - radius_end) / dm)

            # unit vector from m to p.
            mp = (mm[0] * cos(alpha) + mm[1] * sin(alpha),
                  -mm[0] * sin(alpha) + mm[1] * cos(alpha))

            # Point at first circle.
            p0 = (c_start[0] + radius_start * mp[0],
                  c_start[1] + radius_start * mp[1])
            # Point at second circle.
            p1 = (c_end[0] + radius_end * mp[0], c_end[1] + radius_end * mp[1])

            #LOG.debug("p0, p1:" %( p0, p1))

            forward_angle = angle_rad(p1, p0) % (2 * pi)
            backward_angle = angle_rad(p0, p1) % (2 * pi)

            forward_turn = (forward_angle - sa + pi) % (2 * pi) - pi
            backward_turn = (backward_angle - bae + pi) % (2 * pi) - pi

            # LOG.debug("F: %f B:%f %f %f" % (s[0],  s[1], forward_turn, backward_turn))

            if (forward_turn * s[0] <= 0) and (backward_turn * s[1] >= 0):
                valid = True
                break

        if not valid:
            LOG.error("Can't connect two points with arc_line_arc")
            raise SystemExit

        #LOG.debug("angles: %f %f %f %f" %( angle_start, straight_angle*180/pi, angle_end, backward_angle*180/pi))
        if forward_turn == 0.0:
            pts += [self.coord_start]
        else:
            pts += ShapeBendRelative(self.coord_start,
                                     abs(radius_start),
                                     sa * RAD2DEG,
                                     forward_turn * RAD2DEG,
                                     angle_step=self.angle_step)

        if backward_turn == 0.0:
            pts += [self.coord_end]
        else:
            bend2 = ShapeBendRelative(self.coord_end,
                                      abs(radius_end),
                                      bae * RAD2DEG,
                                      backward_turn * RAD2DEG,
                                      angle_step=self.angle_step)
            bend2.reverse()
            pts += bend2

        return pts

    def move(self, position):
        self.coord_start = (self.coord_start[0] + position[0],
                            self.coord_start[1] + position[1])
        self.coord_end = (self.coord_end[0] + position[0],
                          self.coord_end[1] + position[1])
        return self
Beispiel #23
0
 class Layout(AIMWGWireWaveguideTemplate.Layout):
     core_width      = PositiveNumberProperty(default=0.4)
     cladding_width  = PositiveNumberProperty(default=8.0)