Example #1
0
class ShapeEllipseArc(Shape):
    """ ellipse arc around a given center """
    center = Coord2Property(default=(0.0, 0.0))
    box_size = Size2Property(default=(1.0, 1.0))
    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(ShapeEllipseArc, self).__init__(**kwargs)

    def define_points(self, pts):
        sa = self.start_angle * DEG2RAD
        ea = self.end_angle * DEG2RAD
        h_radius = self.box_size[0] / 2.0
        v_radius = self.box_size[1] / 2.0
        n_s = float(self.end_angle - self.start_angle) / self.angle_step
        n_steps = int(math.ceil(abs(n_s))) * numpy.sign(n_s)
        if n_steps == 0:
            if sa == ea:
                pts = numpy.array([[
                    math.cos(sa) * h_radius + self.center[0],
                    math.sin(sa) * v_radius + self.center[1]
                ]])
            else:
                pts = numpy.array([[
                    math.cos(sa) * h_radius + self.center[0],
                    math.sin(sa) * v_radius + self.center[1]
                ], [
                    math.cos(ea) * h_radius + self.center[0],
                    math.sin(ea) * v_radius + self.center[1]
                ]])
            return pts

        angle_step = float(ea - sa) / n_steps
        if self.clockwise:
            angle_step = -angle_step
            sign = -1
        else:
            sign = +1
        while sign * sa > sign * ea:
            ea += sign * 2 * math.pi

        angles = numpy.arange(sa, ea + 0.5 * angle_step, angle_step)
        pts = numpy.column_stack(
            (numpy.cos(angles), numpy.sin(angles))) * numpy.array([
                (h_radius, v_radius)
            ]) + numpy.array([(self.center[0], self.center[1])])
        return pts

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

    def is_empty(self):
        return self.start_angle == self.end_angle or self.box_size[0] == 0.0 or self.box_size[1] == 0.0
Example #2
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
Example #3
0
class ShapePathSpike(__ShapePathBase__):
    """ simple path based on a centerline shape,but with a sharp endpoint with a given angle """
    spike_angle = AngleProperty(restriction = RestrictRange(0.0, 180.0, False, True), default = 90.0)
    

    def define_points(self, pts):
        original = self.__get_original_shape_without_straight_angles__()
        if len(original) <= 1: return
        a = original.angles_rad() 
        a2 = a * 0.5
        a1 = roll(a2, 1)

        if original.closed:
            a2[-1] = a2[0]
            a1[0] = a1[-1]
        else:
            a2[-1] = self.end_face_angle * DEG2RAD - a2[-2]
            a1[0] = self.start_face_angle * DEG2RAD - a1[1]

        a_plus = a2 + a1
        cos_a_min = cos(a2 - a1)
        offsets = column_stack((-sin(a_plus) / cos_a_min, cos(a_plus) / cos_a_min)) * (0.5 * self.path_width)

        # spikes
        if not original.closed and self.spike_angle > 0 and self.spike_angle < 180.0:
            L = 0.5 * self.path_width / tan(self.spike_angle * constants.DEG2RAD * 0.5)
            start_spike = array([[original[0][0] - cos(a[0]) * L,  original[0][1] - sin(a[0]) * L]])
            end_spike = array([[original[-1][0] + cos(a[-2]) * L,  original[-1][1] + sin(a[-2]) * L]])
        else:
            start_spike = ndarray((0, 2))
            end_spike = ndarray((0, 2))

        pts = vstack((start_spike, original.points + offsets, end_spike, flipud(original.points - offsets)))
        return pts
Example #4
0
class Shape(transformable.Transformable, StrongPropertyInitializer, MixinBowl):
    '''Basic shape'''
    points = PointsDefinitionProperty(fdef_name="define_points")
    start_face_angle = AngleProperty(
        allow_none=True,
        doc=
        "Use this to overrule the 'dangling' angle at the start of an open shape"
    )
    end_face_angle = AngleProperty(
        allow_none=True,
        doc=
        "Use this to overrule the 'dangling' angle at the end of an open shape"
    )

    def __init__(self, points=[], closed=None, **kwargs):
        if not (isinstance(points, Shape) and (closed is None)):
            kwargs["closed"] = closed
        else:
            if (points.closed):
                kwargs["closed"] = True

        if isinstance(points, Shape):
            if not "start_face_angle" in kwargs:
                kwargs["start_face_angle"] = points.start_face_angle
            if not "end_face_angle" in kwargs:
                kwargs["end_face_angle"] = points.end_face_angle

        if (points is not None):
            if (isinstance(points, list) or isinstance(points, ndarray)
                    or isinstance(points, Shape) or isinstance(points, tuple)):
                if (len(points) > 0):
                    kwargs["points"] = points
            elif (isinstance(points, Coord2)):
                kwargs["points"] = [points]
            else:
                try:
                    from dependencies.shapely_wrapper import CoordinateSequence
                    if (isinstance(points, CoordinateSequence)):
                        pl = [pt for pt in points]
                        kwargs["points"] = pl
                    else:
                        raise Exception()
                except Exception, e:
                    raise IpkissException(
                        "Unexpected type %s for parameter 'points' in Shape::__init__"
                        % str(type(points)))
        super(Shape, self).__init__(**kwargs)
Example #5
0
class ShapeBend(ShapeArc):
    """ bend: circular arc but specified by its starting point insetad of center """
    start_point = Coord2Property(default=(0.0, 0.0))
    center = DefinitionProperty(fdef_name="define_center")
    start_angle = DefinitionProperty(fdef_name="define_start_angle")
    end_angle = DefinitionProperty(fdef_name="define_end_angle")
    input_angle = AngleProperty(default=0.0)
    output_angle = AngleProperty(default=90.0)

    def __init__(self, **kwargs):
        super(ShapeBend, self).__init__(**kwargs)

    def __get_sign(self):
        if self.clockwise:
            sign = -1
        else:
            sign = 1
        return sign

    def define_center(self):
        sign = self.__get_sign()
        c = (self.start_point[0] -
             sign * self.radius * math.sin(self.input_angle * DEG2RAD),
             self.start_point[1] +
             sign * self.radius * math.cos(self.input_angle * DEG2RAD))
        return c

    def define_start_angle(self):
        sign = self.__get_sign()
        a = self.input_angle - sign * 90.0
        return a

    def define_end_angle(self):
        sign = self.__get_sign()
        a = self.output_angle - sign * 90.0
        return a

    def move(self, position):
        self.start_point = Coord2(self.start_point[0] + position[0],
                                  self.start_point[1] + position[1])
        return self
Example #6
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
Example #7
0
class ShapeRoundAdiabaticSplineGeneric(__ShapeModifier__):
    """ returns a shape with adiabatic spline corners """
    radii = RestrictedProperty(
        restriction=RestrictList(restriction=RESTRICT_NONNEGATIVE),
        required=True)
    adiabatic_angles_list = RestrictedProperty(required=True)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)

    def __original_shape_without_straight_angles__(self):
        S1 = Shape(self.original_shape)
        S = Shape(S1).remove_straight_angles()
        straight = (numpy.abs(
            numpy.abs((S1.turns_rad() + (0.5 * numpy.pi)) % numpy.pi) -
            0.5 * numpy.pi) < 0.00001)
        if not S1.closed:
            straight[0] = False
            straight[-1] = False
        R = numpy.delete(self.radii, straight.nonzero()[0], 0)
        A = numpy.delete(self.adiabatic_angles_list, straight.nonzero()[0], 0)
        return (S, R, A)

    def define_points(self, pts):

        (s, R, A) = self.__original_shape_without_straight_angles__()

        if len(R) != len(s):
            raise AttributeError(
                "ShapeRoundAdiabaticSplineGeneric: length of radius vector should be identical to that of points in shape"
            )
        if len(A) != len(s):
            raise AttributeError(
                "ShapeRoundAdiabaticSplineGeneric: length of adiabatic_angles vector should be identical to that of points in shape"
            )

        if len(s) < 3:
            self.__points__ = s.points
            return
        margin = 0.5 / get_grids_per_unit()

        S = []

        if not self.original_shape.closed:
            S.append(numpy.array([s.points[0]]))
        L1 = 0.0

        for i in range(1, len(s) - 1):
            sh = AdiabaticSplineCircleSplineShape(start_point=s[i - 1],
                                                  turn_point=s[i],
                                                  end_point=s[i + 1],
                                                  radius=R[i],
                                                  adiabatic_angles=A[i],
                                                  angle_step=self.angle_step)
            L0 = sh[0].distance(s[i])
            if L0 + L1 - margin > s[i - 1].distance(s[i]):
                LOG.warning(
                    "Insufficient space for spline rounding in (%f, %f)" %
                    (s[i].x, s[i].y))
            L1 = sh[-1].distance(s[i])
            S.append(sh.points)

        if self.original_shape.closed:
            sh = AdiabaticSplineCircleSplineShape(start_point=s[-2],
                                                  turn_point=s[-1],
                                                  end_point=s[0],
                                                  radius=R[-1],
                                                  adiabatic_angles=A[-1],
                                                  angle_step=self.angle_step)
            L0 = sh[0].distance(s[-1])
            if L0 + L1 - margin > s[-2].distance(s[-1]):
                LOG.warning(
                    "Insufficient space for spline rounding in (%f, %f)" %
                    (s[-1].x, s[-1].y))
            L1 = sh[-1].distance(s[-1])
            S.append(sh.points)
            sh = AdiabaticSplineCircleSplineShape(start_point=s[-1],
                                                  turn_point=s[0],
                                                  end_point=s[1],
                                                  radius=R[0],
                                                  adiabatic_angles=A[0],
                                                  angle_step=self.angle_step)
            L0 = sh[0].distance(s[0])
            if L0 + L1 - margin > s[-1].distance(s[0]):
                LOG.warning(
                    "Insufficient space for spline rounding in (%f, %f)" %
                    (s[0].x, s[0].y))
            L1 = sh[-1].distance(s[0])
            S.append(sh.points)
            self.__closed__ = True
        else:
            # open curve
            S.append(numpy.array([s.points[-1]]))
            L0 = 0.0
            if L0 + L1 - margin > s[-2].distance(s[-1]):
                LOG.warning(
                    "Insufficient space for spline rounding in (%f, %f)" %
                    (s[-1].x, s[-1].y))
            L1 = sh[-1].distance(s[0])
            self.__closed__ = False
        return numpy.vstack(S)
Example #8
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
Example #9
0
class ShapeRoundedRectangle(Shape):
    """ rectangle with rounded corners """
    center = Coord2Property(default=(0.0, 0.0))
    box_size = Size2Property(default=(1.0, 1.0))
    radius = NonNegativeNumberProperty(default=1.0)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)

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

    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.radius <= 0:
            pts += [(cx + dx, cy + dy), (cx - dx, cy + dy), (cx - dx, cy - dy),
                    (cx + dx, cy - dy), (cx + dx, cy + dy)]
        else:
            if self.radius > min(self.box_size) / 2.0:
                self.radius = min(self.box_size) / 2.0

            if (self.radius == self.box_size[0] /
                    2.0) and (self.radius == self.box_size[1] / 2.0):
                pts += ShapeCircle(center=self.center,
                                   radius=self.radius,
                                   angle_step=self.angle_step)
            elif self.radius == self.box_size[0] / 2.0:
                pts += ShapeArc(center=(cx, cy + dy - self.radius),
                                radius=self.radius,
                                start_angle=0.0,
                                end_angle=180.0,
                                angle_step=self.angle_step)
                pts += ShapeArc(center=(cx, cy - dy + self.radius),
                                radius=self.radius,
                                start_angle=180.0,
                                end_angle=360.0,
                                angle_step=self.angle_step)
            elif self.radius == self.box_size[1] / 2.0:
                pts += ShapeArc(center=(cx + dx - self.radius, cy),
                                radius=self.radius,
                                start_angle=270,
                                end_angle=450.0,
                                angle_step=self.angle_step)
                pts += ShapeArc(center=(cx - dx + self.radius, cy),
                                radius=self.radius,
                                start_angle=90.0,
                                end_angle=270.0,
                                angle_step=self.angle_step)
            else:
                pts += ShapeArc(center=(cx + dx - self.radius,
                                        cy + dy - self.radius),
                                radius=self.radius,
                                start_angle=0.0,
                                end_angle=90.0,
                                angle_step=self.angle_step)
                pts += ShapeArc(center=(cx - dx + self.radius,
                                        cy + dy - self.radius),
                                radius=self.radius,
                                start_angle=90.0,
                                end_angle=180.0,
                                angle_step=self.angle_step)
                pts += ShapeArc(center=(cx - dx + self.radius,
                                        cy - dy + self.radius),
                                radius=self.radius,
                                start_angle=180.0,
                                end_angle=270.0,
                                angle_step=self.angle_step)
                pts += ShapeArc(center=(cx + dx - self.radius,
                                        cy - dy + self.radius),
                                radius=self.radius,
                                start_angle=270.0,
                                end_angle=360.0,
                                angle_step=self.angle_step)
        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.0 or self.box_size[1] == 0.0