class ShapeCutFilter(Filter): grids_per_unit = IntProperty(default=200, restriction=RESTRICT_POSITIVE) overlap = IntProperty(default=1, restriction=RESTRICT_NONNEGATIVE) max_path_length = IntProperty(required=True, restriction=RESTRICT_POSITIVE) def __filter_Shape__(self, shape): coordinates = Shape(shape) coordinates.closed = False # this one is open, but the original one can be closed coordinates.remove_identicals() if shape.closed: min_sections = 2 if (coordinates[-1] == coordinates[0]): coordinates.append(coordinates[1]) # create overlap elif ((coordinates[-2] != coordinates[0]) or (coordinates[-1] != coordinates[1])): coordinates.append(coordinates[0]) # close coordinates.append(coordinates[1]) # create overlap coordinates.end_face_angle = 0.5 * ( shape_info.angle_deg(coordinates[2], coordinates[1]) + shape_info.angle_deg(coordinates[1], coordinates[0])) coordinates.start_face_angle = 0.5 * ( shape_info.angle_deg(coordinates[-2], coordinates[-3]) + shape_info.angle_deg(coordinates[-1], coordinates[-2])) elif coordinates[-1] == coordinates[0]: # not closed, but ends will overlap: min_sections = 2 else: min_sections = 1 shapes = shape_cut.cut_open_shape_in_sections_with_overlap( coordinates, self.max_path_length, self.overlap, min_sections) return shapes def __repr__(self): return "<ShapeCutFilter>"
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)
class Layer(__Layer__): number = IntProperty(required = True) name = StringProperty(required = True) def __init__(self, number = 0, name=None, layerlist = None, **kwargs): if name is None: name = "layer" + str(number) super(Layer, self).__init__(number = number, name = name, **kwargs) def __str__(self): return "LAYER" + str(self.number) def __repr__(self): return "<Layer %d>" %self.number def __eq__(self, other): if isinstance(other, Layer): return other.id() == self.id() elif isinstance(other, int): # this should be changed when new layer properties come in... return self.id() == other else: return False def __ne__(self, other): if isinstance(other, Layer): return other.id() != self.id() elif isinstance(other, int): return self.id() != other else: return True def id(self): # can become more complex when datatype etc. is included return self.number
class __ARef1dElement__(ARef): period = DefinitionProperty(fdef_name="define_period") n_o_periods = DefinitionProperty(fdef_name="define_n_o_periods") period_1d = NumberProperty(default=1.0, restriction=RESTRICT_NONZERO) n_o_periods_1d = IntProperty(default=1, restriction=RESTRICT_POSITIVE) def __init__(self, reference, origin, period_1d, n_o_periods_1d, transformation=None, **kwargs): kwargs["period"] = SUPPRESSED kwargs["n_o_periods"] = SUPPRESSED super(__ARef1dElement__, self).__init__(reference=reference, origin=origin, period_1d=period_1d, n_o_periods_1d=n_o_periods_1d, transformation=transformation, **kwargs) def is_empty(self): return __RefElement__.is_empty(self) or (self.n_o_periods_1d == 0)
class GdsiiLayer(StrongPropertyInitializer): number = IntProperty(required=True, restriction=RESTRICT_NONNEGATIVE) datatype = IntProperty(default=0, restriction=RESTRICT_NONNEGATIVE) def __init__(self, number, datatype=0, **kwargs): super(GdsiiLayer, self).__init__( number=number, datatype=datatype, **kwargs) def __eq__(self, other): return self.number == other.number and self.datatype == other.datatype def __ne__(self, other): return (not self.__eq__(other)) def __repr__(self): return "GdsiiLayer %i/%i" % (self.number, self.datatype)
class Label(__TextElement__): font = IntProperty(restriction=RESTRICT_NONNEGATIVE, required=True) 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(Label, self).__init__(layer=layer, text=text, coordinate=coordinate, alignment=alignment, font=font, height=height, transformation=transformation, **kwargs) def size_info(self): text_width = len(self.text) * self.height if self.h_alignment == constants.TEXT_ALIGN_RIGHT: L = self.coordinate[0] - text_width elif self.h_alignment == constants.TEXT_ALIGN_CENTER: L = self.coordinate[0] - text_width / 2.0 else: L = self.coordinate[0] R = L + text_width if self.v_alignment == constants.TEXT_ALIGN_BOTTOM: B = self.coordinate[1] elif self.v_alignment == constants.TEXT_ALIGN_MIDDLE: B = self.coordinate[1] - self.height / 2.0 else: B = self.coordinate[1] - self.height T = B + self.height return size_info.size_info_from_numpyarray( (Shape([(L, B), (L, T), (R, B), (R, T)], True).transform(self.transformation)).points) def flat_copy(self, level=-1): return self.__copy__()
class ShapeBezier(__ShapeModifier__): """ polynomial bezier curve based on a shape with control points """ steps = IntProperty(restriction=RESTRICT_POSITIVE, default=100) def __init__(self, original_shape, steps=100, **kwargs): super(ShapeBezier, self).__init__(original_shape=original_shape, steps=steps, **kwargs) def define_points(self, pts): # perform decasteljau iteration step = 1.0 / self.steps t = arange(0.0, 1.0 + 0.5 * step, step) P = array(self.original_shape.points) Px = outer(P[:, 0], ones(size(t))) Py = outer(P[:, 1], ones(size(t))) for j in range(len(self.original_shape) - 1, 0, -1): Px = Px[0:j, :] + diff(Px, 1, 0) * t Py = Py[0:j, :] + diff(Py, 1, 0) * t pts = transpose(row_stack((Px, Py))) return pts
class ShapeDodecagon(ShapeRegularPolygon): """ dodecagon """ n_o_sides = IntProperty(default=12, restriction=RestrictRange(lower=3))
class ShapeHexagon(ShapeRegularPolygon): """ hexagon """ n_o_sides = IntProperty(default=6, restriction=RestrictRange(lower=3))
class StackARef(CompoundArefElement): stack_size = IntProperty(restriction=RESTRICT_POSITIVE, default=20) def __init__(self, reference, origin=(0.0, 0.0), period=(1.0, 1.0), n_o_periods=(1, 1), transformation=None, stack_size=20, **kwargs): super(StackARef, self).__init__(reference=reference, origin=origin, period=period, n_o_periods=n_o_periods, transformation=transformation, stack_size=stack_size, **kwargs) def define_elements(self, elems): # X_periodicity: 1 if self.n_o_periods[0] == 1: # do not create X-cell, but use self.reference for Y-periodicity x_cell = self.reference x_cell_content = SRef(self.reference, (0.0, 0.0)) # X-periodicity: smaller than 2 * stack size: elif self.n_o_periods[0] < 2 * self.stack_size: # use soft_aref x_cell_content = SoftARef(self.reference, (0.0, 0.0), self.period, (self.n_o_periods, 1)) # X-periodicity: larger than 2 * stack size else: # should become autoname structure x_cell_stack = structure_module.Structure( "R_" + self.reference.name + "_SX" + str(int(self.stack_size)), SoftARef(self.reference, (0.0, 0.0), self.period, (self.stack_size, 1))) x_cell_content = SoftARef( x_cell_stack, (0.0, 0.0), (self.period[0] * self.stack_size, self.period[1]), (self.n_o_periods[0] / self.stack_size, 1)) x_cell_content += SoftARef( self.reference, (self.period[0] * self.stack_size * (self.n_o_periods[0] / self.stack_size), 0.0), self.period, (self.n_o_periods[0] % self.stack_size, 1)) # do not yet create the X-cell # Y-periodicity: 1 if self.n_o_periods[1] == 1: x_cell_content.move(self.origin) # transformation is passed automatically through the compound_element transformation elems += x_cell_content # do not create X-cell, but add the previously defined content to self, return return # create x_cell # this should become an autoname_structure x_cell = structure_module.Structure( "R_" + self.reference + "_X" + str(int(n_o_periods[0])), x_cell_content) if self.n_o_periods[1] < 2 * self.stack_size: # soft_aref of X_cell elems += SoftARef(x_cell, self.origin, self.period, (1, self.n_o_periods[1])) else: # Y_periodicity < 2* stack_size: y_cell_stack = structure_module.Structure( "R_" + x_cell.name + "_SY" + str(int(self.stack_size)), SoftARef(x_cell, (0.0, 0.0), (self.period[0], self.stack_size * self.period[1]), (1, self.n_o_periods[1] / self.stack_size))) elems += SoftARef( y_cell_stack, self.origin, (self.period[0], self.stack_size * self.period[1]), (1, self.n_o_periods[1] / self.stack_size)) elems += SoftARef(x_cell, (self.origin[0], self.origin[1] + self.period[1] * self.stack_size * (self.n_o_periods[1] / self.stack_size)), self.period, (1, self.n_o_periods[1] % self.stack_size)) return elems def size_info(self): return ARef.size_info(self) def convex_hull(self): return ARef.convex_hull(self) def __deepcopy__( self, memo ): #cannot be removed ! self.reference should not be deepcopied ! return StackARef(self.reference, deepcopy(self.origin), deepcopy(self.period), deepcopy(self.n_o_periods), deepcopy(self.transformation))