Ejemplo n.º 1
0
class NoDistortTransform(GenericNoDistortTransform):
    """ A homothetic transformation that does not distort the item it is applied to (angle conservation) 
        The transform is defined by 
        - a mirror around the x-axis
        - a scaling with respect to the origin
        - a rotation around the origin
        - a translation
        
        it is also possible to set absolute magnification and rotation, which means that subsequent transformations
        will not affect the angle and size any further
        """
    # FIXME : Use transformation matrix which is computed once (and cached)
    
    def __init__(self, translation = (0.0, 0.0), rotation = 0.0, magnification = 1.0, v_mirror = False, absolute_magnification = False, absolute_rotation = False, **kwargs):
        # note: translation is no part of gdsII transform. It should be taken into account while writing the file
        super(NoDistortTransform, self).__init__(
            translation = translation,
            rotation = rotation,
            magnification = magnification,
            v_mirror = v_mirror,
            absolute_magnification = absolute_magnification,
            absolute_rotation =absolute_rotation,
            **kwargs)

    translation = Coord2Property("__translation__", default = (0.0, 0.0))
    """ the translation coordinate """
    
   
    #def get_rotation (self): return self.rotation
    def set_rotation(self, value):
        self.__rotation__ = value % 360.0
        if value % 90.0 == 0.0:
            # make sure sine and cosine are really zero when needed!
            if self.__rotation__ == 0.0:
                self.__ca__ = 1.0
                self.__sa__ = 0.0
            elif self.__rotation__ == 90.0:
                self.__ca__ = 0.0
                self.__sa__ = 1.0
            elif self.__rotation__ == 180.0:
                self.__ca__ = -1.0
                self.__sa__ = 0.0
            elif self.__rotation__ == 270.0:
                self.__ca__ = 0.0
                self.__sa__ = -1.0
        else:
            self.__ca__ = cos(value * DEG2RAD)
            self.__sa__ = sin(value * DEG2RAD)
    rotation = SetFunctionProperty("__rotation__", set_rotation, default=0.0)
    """ the rotation around the origin """

    magnification = NumberProperty("__magnification__", restriction = RESTRICT_NONZERO, default = 1.0)
    """ the magnification factor """

    v_mirror = BoolProperty("__v_mirror__", default = False)
    """ the vertical mirror """
    flip = v_mirror
    

    #""" set absolute magnification on or off"""
    absolute_magnification = BoolProperty("__absolute_magnification__", default = False)
    
    #""" set absolute rotation on or off"""
    absolute_rotation = BoolProperty("__absolute_rotation__", default = False)
    
    def __make_simple__(self):
        """ internal use: reduces special subclasses to this generic type """
        # if you change special types, they should revert to generic type
        self.__class__ = NoDistortTransform

    def __translate__(self, coord):
        """ internal use: applies translation to a coordinate """
        return Coord2(coord[0] + self.translation.x, coord[1] + self.translation.y)
    
    def __rotate__(self, coord):
        """ internal use: applies rotation to a coordinate """
        return Coord2(coord[0] * self.__ca__ - coord[1] * self.__sa__, coord[0] * self.__sa__ + coord[1] * self.__ca__)

    def __magnify__(self, coord):
        """ internal use: applies magnification to a coordinate """
        return Coord2(coord[0] * self.magnification, coord[1] * self.magnification)

    def __v_flip__(self, coord):
        """ internal use: applies v_mirror to a coordinate """
        if self.v_mirror:
            return Coord2(coord[0], -coord[1])
        else:
            return Coord2(coord[0], coord[1])

    def __inv_translate__(self, coord):
        """ internal use: applies reverse translation to a coordinate """
        return Coord2(coord[0] - self.translation.x, coord[1] - self.translation.y)
    
    def __inv_rotate__(self, coord):
        """ internal use: applies reverse rotation to a coordinate """
        return Coord2(coord[0] * self.__ca__ + coord[1] * self.__sa__, - coord[0] * self.__sa__ + coord[1] * self.__ca__)

    def __inv_magnify__(self, coord):
        """ internal use: applies reverse magnification to a coordinate """
        return Coord2(coord[0] / self.magnification, coord[1] / self.magnification)

    def __inv_v_flip__(self, coord):
        """ internal use: applies reverse v_mirror to a coordinate """
        if self.v_mirror:
            return Coord2(coord[0], - coord[1])
        else:
            return Coord2(coord[0], coord[1])

    def __translate3__(self, coord):
        """ internal use: applies translation to a 3d coordinate """
        return Coord3(coord[0] + self.translation.x, coord[1] + self.translation.y, coord[2])
    
    def __rotate3__(self, coord):
        """ internal use: applies rotation to a 3d coordinate """
        return Coord3(coord[0] * self.__ca__ - coord[1] * self.__sa__, coord[0] * self.__sa__ + coord[1] * self.__ca__, coord[2])

    def __magnify3__(self, coord):
        """ internal use: applies magnification to a 3d coordinate """
        return Coord3(coord[0] * self.magnification, coord[1] * self.magnification, coord[2])

    def __v_flip3__(self, coord):
        """ internal use: applies v_mirror to a 3d coordinate """
        if self.v_mirror:
            return Coord3(coord[0], -coord[1], coord[2])
        else:
            return Coord3(coord[0], coord[1], coord[2])

    def __inv_translate3__(self, coord):
        """ internal use: applies reverse translation to a 3d coordinate """
        return Coord3(coord[0] - self.translation.x, coord[1] - self.translation.y, coord[2])
    
    def __inv_rotate3__(self, coord):
        """ internal use: applies reverse rotation to a 3d coordinate """
        return Coord3(coord[0] * self.__ca__ + coord[1] * self.__sa__, - coord[0] * self.__sa__ + coord[1] * self.__ca__, coord[2])

    def __inv_magnify3__(self, coord):
        """ internal use: applies reverse magnification to a 3d coordinate """
        return Coord3(coord[0] / self.magnification, coord[1] / self.magnification, coord[2])

    def __inv_v_flip3__(self, coord):
        """ internal use: applies reverse v_mirror to a 3d coordinate """
        if self.v_mirror:
            return Coord3(coord[0], - coord[1], coord[2])
        else:
            return Coord3(coord[0], coord[1], coord[2])
        
    def __translate_array__(self, coords):
        """ internal use: applies translation to a numpy array """
        coords += numpy.array([self.translation.x, self.translation.y])
        return coords
    
    def __rotate_array__(self, coords):
        """ internal use: applies rotation to a numpy array """
        x_a = numpy.array([self.__ca__, -self.__sa__])
        y_a = numpy.array([self.__sa__, self.__ca__])
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1))))
        return coords

    def __magnify_array__(self, coords):
        """ internal use: applies magnification to a numpy array """
        coords *= numpy.array([self.magnification, self.magnification])
        return coords

    def __v_flip_array__(self, coords):
        """ internal use: applies v_mirror to a numpy array """
        coords *= (numpy.array([False, self.v_mirror]) * -2.0 + 1.0)
        return coords

    def __inv_translate_array__(self, coords):
        """ internal use: applies reverse translation to a numpy array """
        coords -= numpy.array([self.translation.x, self.translation.y])
        return coords
    
    def __inv_rotate_array__(self, coords):
        """ internal use: applies reverse rotation to a numpy array """
        x_a = array([self.__ca__, self.__sa__])
        y_a = array([-self.__sa__, self.__ca__])
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1))))
        return coords

    def __inv_magnify_array__(self, coords):
        """ internal use: applies reverse magnification to a numpy array """
        coords *= numpy.array([1.0 / self.magnification, 1.0 / self.magnification])
        return coords

    def __inv_v_flip_array__(self, coords):
        """ internal use: applies reverse v_mirror to a numpy array """
        coords *= numpy.array([False, self.v_mirror]) * (-2.0) + 1.0
        return coords

    def __translate_array3__(self, coords):
        """ internal use: applies translation to a numpy array """
        coords += numpy.array([self.translation.x, self.translation.y, 0.0])
        return coords
    
    def __rotate_array3__(self, coords):
        """ internal use: applies rotation to a numpy array """
        x_a = numpy.array([self.__ca__, -self.__sa__, 0])
        y_a = numpy.array([self.__sa__, self.__ca__, 0])
        z_a = numpy.array([0, 0, 1.0])
        
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1), numpy.sum(coords * z_a, 1))))
        return coords

    def __magnify_array3__(self, coords):
        """ internal use: applies magnification to a numpy array """
        coords *= numpy.array([self.magnification, self.magnification, 1.0])
        return coords

    def __v_flip_array3__(self, coords):
        """ internal use: applies v_mirror to a numpy array """
        coords *= (numpy.array([False, self.v_mirror, False]) * -2.0 + 1.0)
        return coords

    def __inv_translate_array3__(self, coords):
        """ internal use: applies reverse translation to a numpy array """
        coords -= numpy.array([self.translation.x, self.translation.y, 0.0])
        return coords
    
    def __inv_rotate_array3__(self, coords):
        """ internal use: applies reverse rotation to a numpy array """
        x_a = array([self.__ca__, self.__sa__, 0.0])
        y_a = array([-self.__sa__, self.__ca__, 0.0])
        z_a = numpy.array([0, 0, 1.0])
        
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1), numpy.sum(coords * z_a, 1))))
        return coords

    def __inv_magnify_array3__(self, coords):
        """ internal use: applies reverse magnification to a numpy array """
        coords *= numpy.array([1.0 / self.magnification, 1.0 / self.magnification, 1.0])
        return coords

    def __inv_v_flip_array3__(self, coords):
        """ internal use: applies reverse v_mirror to a numpy array """
        coords *= numpy.array([False, self.v_mirror, False]) * (-2.0) + 1.0
        return coords

    def apply_to_coord(self, coord):
        """ applies transformation to a coordinate """
        # this could be speeded up
        # Check the east order
        coord = self.__v_flip__(coord)# first flip 
        coord = self.__rotate__(coord)# then magnify
        coord = self.__magnify__(coord)# then rotate
        coord = self.__translate__(coord) # finally translate
        return coord
    
    def reverse_on_coord(self, coord):
        """ applies reverse transformation to a coordinate """
        # this could be speeded up
        # Check the right order
        coord = self.__inv_translate__(coord) # finally translate
        coord = self.__inv_magnify__(coord)# then rotate
        coord = self.__inv_rotate__(coord)# then magtnify
        coord = self.__inv_v_flip__(coord)# first flip 
        return coord

    def apply_to_array(self, coords):
        """ internal use: applies transformation to a numpy array"""
        # this could be speeded up
        # Check the right order
        coords = self.__v_flip_array__(coords)# first flip 
        coords = self.__rotate_array__(coords)# then rotate
        coords = self.__magnify_array__(coords)# then magnify
        coords = self.__translate_array__(coords) # finally translate
        return coords
    
    def reverse_on_array(self, coord):
        """ internal use: applies reverse transformation to a numpy array """
        # this could be speeded up
        # Check the right order
        coords = self.__inv_translate_array__(coords) # finally translate
        coords = self.__inv_magnify_array__(coords)# then magnify
        coords = self.__inv_rotate_array__(coords)# then rotate
        coords = self.__inv_v_flip_array__(coords)# first flip 
        return coords    

    def apply_to_coord3(self, coord):
        """ applies transformation to a coordinate """
        # this could be speeded up
        # Check the east order
        coord = self.__v_flip3__(coord)# first flip 
        coord = self.__rotate3__(coord)# then magnify
        coord = self.__magnify3__(coord)# then rotate
        coord = self.__translate3__(coord) # finally translate
        return coord
    
    def reverse_on_coord3(self, coord):
        """ applies reverse transformation to a coordinate """
        # this could be speeded up
        # Check the right order
        coord = self.__inv_translate3__(coord) # finally translate
        coord = self.__inv_magnify3__(coord)# then rotate
        coord = self.__inv_rotate3__(coord)# then magtnify
        coord = self.__inv_v_flip3__(coord)# first flip 
        return coord

    def apply_to_array3(self, coords):
        """ internal use: applies transformation to a numpy array"""
        # this could be speeded up
        # Check the right order
        coords = self.__v_flip_array3__(coords)# first flip 
        coords = self.__rotate_array3__(coords)# then rotate
        coords = self.__magnify_array3__(coords)# then magnify
        coords = self.__translate_array3__(coords) # finally translate
        return coords
    
    def reverse_on_array3(self, coord):
        """ internal use: applies reverse transformation to a numpy array """
        # this could be speeded up
        # Check the right order
        coords = self.__inv_translate_array3__(coords) # finally translate
        coords = self.__inv_magnify_array3__(coords)# then magnify
        coords = self.__inv_rotate_array3__(coords)# then rotate
        coords = self.__inv_v_flip_array3__(coords)# first flip 
        return coords    
    
    
    def apply_to_angle_deg(self, angle):
        """ applies transformation to an absolute angle (degrees) """
        a = angle
        if self.v_mirror:
            a = -a
        a += self.rotation
        return a % 360.0
    
    def reverse_on_angle_deg(self, angle):
        """ applies reverse transformation to an absolute angle (degrees)"""
        a = angle - self.rotation
        if self.v_mirror:
            a = -a
        return a % 360.0

    def apply_to_angle_rad(self, angle):
        """ applies transformation to an absolute angle (radians) """
        a = angle
        if self.v_mirror:
            a = -a
        a += self.rotation * DEG2RAD
        return a % (2 * pi)
    
    def reverse_on_angle_rad(self, angle):
        """ applies reverse transformation to an absolute angle (radians) """
        a = angle - self.rotation * DE2RAD
        if self.v_mirror:
            a = -a
        return a % (2 * pi)

    def apply_to_length(self, length):
        """ applies transformation to a distance """
        return length * self.magnification

    def reverse_on_length(self, length):
        """ applies reverse transformation to a distance """
        return length / self.magnification

    def __neg__(self):
        """ returns the reverse transformation """
        from .translation import Translation
        from .rotation import Rotation
        from .magnification import Magnification
        from .mirror import VMirror
        
        T = Translation(- self.translation) + Magnification((0.0, 0.0), 1 / self.magnification) + Rotation((0.0, 0.0), -self.rotation)
        if self.v_mirror:
            T += VMirror(0.0)
        return T

    def __sub__(self, other):
        """ returns the concatenation of this transform and the reverse of other """
        if other is None: return copy.deepcopy(self)
        if not isinstance(other, __ReversibleTransform__):
            raise TypeError("Cannot subtract an irreversible transform")
        return self.__add__(-other)

    def __isub__(self, other):
        """ concatenates the reverse of other to this transform """
        if other is None: return self
        if not isinstance(other, __ReversibleTransform__):
            raise TypeError("Cannot subtract an irreversible transform")
        return self.__iadd__(self, -other)

    def __add__(self, other):
        """ returns the concatenation of this transform and other """
        # performs transformation "other" after "self" and returns resulting transform
        if other is None: return copy.deepcopy(self)

        if isinstance(other, NoDistortTransform):
            T = NoDistortTransform()

            if self.absolute_magnification:
                M1 = 1.0
            else:
                M1 = other.magnification
            T.magnification = self.magnification * M1

            #flip signs
            if other.v_mirror: s_1 = -1
            else:              s_1 = 1

            if not self.absolute_rotation:
                T.rotation = s_1 * self.rotation + other.rotation
                ca = other.__ca__
                sa = other.__sa__
            else:
                T.rotation = s_1 * self.rotation
                ca = 1.0
                sa = 0.0


            # tricky part: translation
            T.translation = Coord2(other.translation.x + ca * self.translation.x * M1 - s_1 * sa * self.translation.y * M1,
                                   other.translation.y + sa * self.translation.x * M1 + s_1 * ca * self.translation.y * M1)

            T.absolute_rotation = self.absolute_rotation or other.absolute_rotation
            T.absolute_magnification = self.absolute_magnification or other.absolute_magnification
            T.v_mirror = (not self.v_mirror == other.v_mirror)
        else:
            T = Transform.__add__(self, other)
        return T

    def __iadd__(self, other):
        """ concatenates other to this transform """
        if other is None: return self
        # performs transformation other after self and returns self
        if isinstance(other, NoDistortTransform):
            # tricky part: translation
            if self.absolute_magnification:
                self.magnification = self.magnification * other.magnification
                M1 = 1
            else:
                M1 = other.magnification

            #flip signs
            if other.v_mirror: s_1 = -1
            else:              s_1 = 1


            if not self.absolute_rotation:
                self.rotation = s_1 * self.rotation + other.rotation
                ca = other.__ca__
                sa = other.__sa__
            else:
                self.rotation = s_1 * self.rotation                
                ca = 1
                sa = 0

            # tricky part: translation
            self.translation = (other.translation.x + ca * self.translation.x * M1 - s_1 * sa * self.translation.y * M1,
                                other.translation.y + sa * self.translation.x * M1 + s_1 * ca * self.translation.y * M1)

            self.absolute_rotation = self.absolute_rotation or other.absolute_rotation
            self.absolute_magnification = self.absolute_magnification or other.absolute_magnification
            self.v_mirror = (not self.v_mirror == other.v_mirror)
        else:
            raise TypeError("Error: Cannot perform += operation for NoDistortTransform and other transform of type " + str(type(other)))
        return self
    
    def __eq__(self, other):
        """ check if the transforms do the same thing """
        if other is None: return self.is_identity()
        if not isinstance(other, NoDistortTransform): return False
        return ((self.rotation == other.rotation) and
                (self.translation == other.translation) and
                (self.v_mirror == other.v_mirror) and
                (self.magnification == other.magnification) and
                (self.absolute_rotation == other.absolute_rotation) and
                (self.absolute_magnification == other.absolute_magnification)
                )

    def __ne__(self, other):
        """ checks if the transforms do different things """

        if other is None: return not self.is_identity()
        if not isinstance(other, NoDistortTransform): return False
        return ((self.rotation != other.rotation) or
                (self.translation != other.translation) or
                (self.v_mirror != other.v_mirror) or
                (self.magnification != other.magnification) or
                (self.absolute_rotation != other.absolute_rotation) or 
                (self.absolute_magnification != other.absolute_magnification)
                )
        
    def is_identity(self):
        """ returns True if the transformation does nothing """
        return ((self.rotation == 0.0) and
                (self.translation.x == 0.0) and
                (self.translation.y == 0.0) and
                not (self.v_mirror) and 
                (self.magnification == 1.0)
            )

    def is_isometric(self):
        """ returns True if the transformation conserves angles and distances """
        return self.magnification == 1.0

    def is_homothetic(self):
        """ returns True if the transformation conserves angles """
        return True

    def is_orthogonal(self):
        """ returns True if the transformation does only rotate on 90degree angles """
        return (self.rotation % 90.0) == 0.0

    def is_octogonal(self):
        """ returns True if the transformation does only rotate on 45degree angles """
        return (self.rotation % 45.0) == 0.0
    
    def id_string(self):
        """ gives a hash of the transform (for naming purposes) """
        return str(hash("R" + str(int(self.rotation * 10000)) + 
                        "T" + str(int(self.translation[0] * 1000)) + "_" + str(int(self.translation[1] * 1000)) +
                        "M" + str(int(self.magnification * 1000)) +
                        "V" + str(self.v_mirror) +
                        "AM" + str(self.absolute_magnification) +
                        "AR" + str(self.absolute_rotation) 
                        ))
    
    def __str__(self):
        """ gives a string representing the transform """
        return "R=%s-T=%s-M=%s-V=%s-AM=%s-AR=%s" % (str(int(self.rotation * 10000)), 
                                        str(int(self.translation[0] * 1000)) + "_" + str(int(self.translation[1] * 1000)),
                                        str(int(self.magnification * 1000)),
                                        str(self.v_mirror),
                                        str(self.absolute_magnification),
                                        str(self.absolute_rotation))    
Ejemplo n.º 2
0
class Path(__ShapeElement__):
    path_type = RestrictedProperty(restriction=RestrictValueList(
        constants.PATH_TYPES),
                                   default=constants.PATH_TYPE_NORMAL)
    absolute_line_width = BoolProperty(default=False)
    __min_length__ = 2

    def __init__(self,
                 layer,
                 shape,
                 line_width=1.0,
                 path_type=constants.PATH_TYPE_NORMAL,
                 transformation=None,
                 **kwargs):
        super(Path, self).__init__(layer=layer,
                                   shape=shape,
                                   line_width=line_width,
                                   path_type=path_type,
                                   transformation=transformation,
                                   **kwargs)

    def set_line_width(self, new_line_width):
        self.absolute_line_width = bool(new_line_width < 0)
        self.__line_width__ = abs(new_line_width)
        #line widths of zero must be allowed for e-beam

    line_width = SetFunctionProperty("__line_width__",
                                     set_line_width,
                                     required=True)

    def size_info(self):
        if self.line_width == 0.0:
            return self.shape.size_info.transform_copy(self.transformation)
        else:
            # this is slower, but accurate
            from ...geometry.shapes.modifiers import ShapePath
            return ShapePath(
                original_shape=self.shape,
                path_width=self.line_width,
                path_type=self.path_type).size_info.transform_copy(
                    self.transformation)
            # this is fast, but inaccurate
            #return self.shape.size_info().transform_copy(self.transformation)

    def convex_hull(self):
        if self.line_width == 0.0:
            return self.shape.convex_hull().transform(self.transformation)
        else:
            # this is slower, but accurate
            from ipkiss.geometry.shapes.modifiers import ShapePath
            return ShapePath(original_shape=self.shape,
                             path_width=self.line_width,
                             path_type=self.path_type).convex_hull().transform(
                                 self.transformation)
            # this is fast, but inaccurate
            #return self.shape.size_info().transform_copy(self.transformation)

    def flat_copy(self, level=-1):
        S = Path(layer=self.layer,
                 shape=self.shape,
                 line_width=self.line_width,
                 path_type=self.path_type,
                 transformation=self.transformation,
                 absolute_line_width=self.absolute_line_width)
        S.expand_transform()
        return S

    def expand_transform(self):
        if not self.transformation.is_identity():
            self.shape = self.shape.transform_copy(self.transformation)
            if not self.absolute_line_width:
                self.line_width = self.transformation.apply_to_length(
                    self.line_width)
            from ...geometry.transforms.identity import IdentityTransform
            self.transformation = IdentityTransform()
        return self
Ejemplo n.º 3
0
class Stretch(__ReversibleTransform__):
    """ non-homothetic scaling """

    stretch_center = Coord2Property(default=(0.0, 0.0))

    def set_stretch_factor(self, value):
        if isinstance(value, Coord2):
            self.__stretch_factor__ = value
        else:
            self.__stretch_factor__ = Coord2(value[0], value[1])
        if self.__stretch_factor__[0] == 0.0 or self.__stretch_factor__[
                1] == 0.0:
            raise IpcoreAttributeException(
                "Error: Stretch factor cannot be zero in Stretch transform")

    stretch_factor = SetFunctionProperty("__stretch_factor__",
                                         set_stretch_factor,
                                         required=True)
    """ stretch factor (x, y) """

    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        return Coord2(
            self.__stretch_factor__[0] * coord[0] +
            (1 - self.__stretch_factor__[0]) * self.stretch_center[0],
            self.__stretch_factor__[1] * coord[1] +
            (1 - self.__stretch_factor__[1]) * self.stretch_center[1])

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        return Coord2(
            1.0 / self.__stretch_factor__[0] * coord[0] +
            (1 - 1.0 / self.__stretch_factor__[0]) * self.stretch_center[0],
            1.0 / self.__stretch_factor__[1] * coord[1] +
            (1 - 1.0 / self.__stretch_factor__[1]) * self.stretch_center[1])

    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        coords *= array([self.stretch_factor.x, self.stretch_factor.y])
        coords += array([
            (1 - self.__stretch_factor__.x) * self.stretch_center.x,
            (1 - self.__stretch_factor__.y) * self.stretch_center.y
        ])
        return coords

    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        coords *= array(
            [1.0 / self.stretch_factor.x, 1.0 / self.stretch_factor.y])
        coords += array([
            (1 - 1.0 / self.__stretch_factor__.x) * self.stretch_center.x,
            (1 - 1.0 / self.__stretch_factor__.y) * self.stretch_center.y
        ])
        return coords

    def is_identity(self):
        """ returns True if the transformation does nothing """
        return ((self.stretch_factor.x == 1.0)
                and (self.stretch_factor.y == 1.0))

    def is_isometric(self):
        """ returns True if the transformation conserves angles and distances"""
        return ((self.stretch_factor.x == 1.0)
                and (self.stretch_factor.y == 1.0))

    def is_homothetic(self):
        """ returns True if the transformation conserves angles """
        return self.stretch_factor.x == self.stretch_factor.y
Ejemplo n.º 4
0
class VMirror(__SpecialNoDistortTransform__):
    """ mirror transformation around y-plane """
    def __init__(self, mirror_plane_y=0.0, **kwargs):
        kwargs['translation'] = SUPPRESSED
        kwargs['v_mirror'] = True

        super(VMirror, self).__init__(mirror_plane_y=mirror_plane_y, **kwargs)

    def set_mirror_plane_y(self, value):
        self.__mirror_plane_y__ = value
        self.translation = Coord2(0.0, 2.0 * value)

    mirror_plane_y = SetFunctionProperty("__mirror_plane_y__",
                                         set_mirror_plane_y,
                                         restriction=RESTRICT_NUMBER,
                                         default=0.0)

    # overloading for efficiency
    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        coord = self.__v_flip__(coord)
        coord = self.__translate__(coord)
        return coord

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        coord = self.__inv_translate__(coord)
        coord = self.__inv_v_flip__(coord)
        return coord

    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        coords = self.__v_flip_array__(coords)
        coords = self.__translate_array__(coords)
        return coords

    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        coords = self.__inv_translate_array__(coords)
        coords = self.__inv_v_flip_array__(coords)
        return coords

    def __neg__(self):
        """ returns reverse transformation """
        return VMirror(self.mirror_plane_y)

    def is_identity(self):
        """ returns True if the transformation does nothing """
        return False

    def apply_to_angle_deg(self, angle):
        """ apply transformation to absolute angle (degrees) """
        return (-angle) % 360.0

    def reverse_on_angle_deg(self, angle):
        """ apply reverse transformation to absolute angle (degrees) """
        return (-angle) % 360.0

    def apply_to_angle_rad(self, angle):
        """ apply transformation to absolute angle (radians) """
        return (-angle) % (2 * pi)

    def reverse_on_angle_rad(self, angle):
        """ apply reverse transformation to absolute angle (radians) """
        return (-angle) % (2 * pi)
Ejemplo n.º 5
0
class CMirror(__SpecialNoDistortTransform__):
    """ mirror around point (= 180 degree turn)"""
    def __init__(self, mirror_center=(0.0, 0.0), **kwargs):
        kwargs['translation'] = SUPPRESSED
        kwargs['rotation'] = 180.0
        super(CMirror, self).__init__(mirror_center=mirror_center, **kwargs)

    def set_mirror_center(self, center):
        self.__mirror_center__ = Coord2(center[0], center[1])
        self.translation = 2 * self.__mirror_center__

    """ mirror center """
    mirror_center = SetFunctionProperty("__mirror_center__",
                                        set_mirror_center,
                                        restriction=RestrictType(Coord2),
                                        preprocess=ProcessorTypeCast(Coord2),
                                        default=(0.0, 0.0))

    def __c_flip__(self, coord):
        """ internal use: point mirror coordinate """
        return (-coord[0], -coord[1])

    def __c_flip_array__(self, coords):
        """ internal use: point mirror numpy array """
        coords *= array([-1, -1])
        return coords

    # overloading for efficiency
    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        # faster than rotation!
        coord = self.__c_flip__(coord)
        coord = self.__translate__(coord)
        return coord

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        # faster than rotation!
        coord = self.__inv_translate__(coord)
        coord = self.__c_flip__(coord)
        return coord

    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        # faster than rotation!
        coords = self.__c_flip_array__(coords)
        coords = self.__translate_array__(coords)
        return coords

    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        # faster than rotation!
        coords = self.__inv_translate_array__(coords)
        coords = self.__c_flip_array__(coords)
        return coords

    def apply_to_angle_deg(self, angle):
        """ apply transformation to absolute angle (degrees) """
        return (180.0 + angle) % 360.0

    def reverse_on_angle_deg(self, angle):
        """ apply reverse transformation to absolute angle (degrees) """
        return (180.0 + angle) % 360.0

    def __neg__(self):
        """ returns reverse transformation """
        return CMirror(self.mirror_center)

    def is_identity(self):
        """ returns True if the transformation does nothing """
        return False
Ejemplo n.º 6
0
class HMirror(__SpecialNoDistortTransform__):
    """ mirror transformation around x plane """
    def __init__(self, mirror_plane_x=0.0, **kwargs):
        kwargs['translation'] = SUPPRESSED
        kwargs['v_mirror'] = True
        kwargs['rotation'] = 180.0

        super(HMirror, self).__init__(mirror_plane_x=mirror_plane_x, **kwargs)

    def set_mirror_plane_x(self, value):
        self.__mirror_plane_x__ = value
        self.translation = Coord2(2.0 * value, 0.0)

    mirror_plane_x = SetFunctionProperty("__mirror_plane_x__",
                                         set_mirror_plane_x,
                                         restriction=RESTRICT_NUMBER,
                                         default=0.0)

    def __h_flip__(self, coord):
        """ internal use: mirror coordinate around y-axis """
        return (-coord[0], coord[1])

    def __h_flip_array__(self, coords):
        """ internal use: mirror array around y axis """
        coords *= array([-1, 1])
        return coords

    # overloading for efficiency
    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        # faster than rotation!
        coord = self.__h_flip__(coord)
        coord = self.__translate__(coord)
        return coord

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        # faster than rotation!
        coord = self.__inv_translate__(coord)
        coord = self.__h_flip__(coord)
        return coord

    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        # faster than rotation!
        coords = self.__h_flip_array__(coords)
        coords = self.__translate_array__(coords)
        return coords

    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        # faster than rotation!
        coords = self.__inv_translate_array__(coords)
        coords = self.__h_flip_array__(coords)
        return coords

    def apply_to_angle_deg(self, angle):
        """ apply transformation to absolute angle (degrees) """
        return (180.0 - angle) % 360.0

    def reverse_on_angle_deg(self, angle):
        """ apply reverse transformation to absolute angle (degrees) """
        return (180.0 - angle) % 360.0

    def apply_to_angle_rad(self, angle):
        """ apply transformation to absolute angle (radians) """
        return (pi - angle) % (2 * pi)

    def reverse_on_angle_rad(self, angle):
        """ apply reverse transformation to absolute angle (radians) """
        return (pi - angle) % (2 * pi)

    def __neg__(self):
        """ returns reverse transformation """
        return HMirror(self.mirror_plane_x)

    def is_identity(self):
        """ returns True if the transformation does nothing """
        return False
Ejemplo n.º 7
0
class Rotation(__SpecialNoDistortTransform__):
    """ rotation around point over a given angle (degrees) """

    def __init__(self,
                 rotation_center=(0.0, 0.0),
                 rotation=0.0,
                 absolute_rotation=False,
                 **kwargs):
        if not 'translation' in kwargs:
            kwargs['translation'] = SUPPRESSED
        super(Rotation, self).__init__(
            rotation_center=rotation_center,
            rotation=rotation,
            absolute_rotation=absolute_rotation,
            **kwargs)

    absolute_rotation = getattr(NoDistortTransform, 'absolute_rotation')

    def set_rotation(self, value):
        self.__rotation__ = value % 360.0
        if value % 90.0 == 0.0:
            # make sure sine and cosine are really zero when needed!
            if self.__rotation__ == 0.0:
                self.__ca__ = 1.0
                self.__sa__ = 0.0
            elif self.__rotation__ == 90.0:
                self.__ca__ = 0.0
                self.__sa__ = 1.0
            elif self.__rotation__ == 180.0:
                self.__ca__ = -1.0
                self.__sa__ = 0.0
            elif self.__rotation__ == 270.0:
                self.__ca__ = 0.0
                self.__sa__ = -1.0
        else:
            self.__ca__ = cos(value * constants.DEG2RAD)
            self.__sa__ = sin(value * constants.DEG2RAD)
        if hasattr(self, "__rotation_center__"):
            center = self.__rotation_center__
            self.translation = Coord2(
                center.x * (1 - self.__ca__) + center.y * self.__sa__,
                center.y * (1 - self.__ca__) - center.x * self.__sa__)

    rotation = SetFunctionProperty("__rotation__", set_rotation, default=0.0)

    def set_rotation_center(self, center):
        if not isinstance(center, Coord2):
            center = Coord2(center[0], center[1])
        self.__rotation_center__ = center
        if hasattr(self, "__ca__"):
            self.translation = Coord2(
                center.x * (1 - self.__ca__) + center.y * self.__sa__,
                center.y * (1 - self.__ca__) - center.x * self.__sa__)

    rotation_center = SetFunctionProperty(
        "__rotation_center__",
        set_rotation_center,
        restriction=RestrictType(Coord2),
        preprocess=ProcessorTypeCast(Coord2),
        default=(0.0, 0.0))

    # overloading for efficiency
    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        coord = self.__rotate__(coord)
        coord = self.__translate__(coord)
        return coord

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        coord = self.__inv_translate__(coord)
        coord = self.__inv_rotate__(coord)
        return coord

    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        coords = self.__rotate_array__(coords)
        coords = self.__translate_array__(coords)
        return coords

    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        coords = self.__inv_translate_array__(coords)
        coords = self.__inv_rotate_array__(coords)
        return coords

    def apply_to_angle_deg(self, angle):
        """ apply transformation to absolute angle (degrees) """
        a = angle
        a += self.rotation
        return a % 360.0

    def reverse_on_angle_deg(self, angle):
        """ apply transformation to absolute angle (degrees) """
        a = angle - self.rotation
        return a % 360.0

    def apply_to_angle_rad(self, angle):
        a = angle
        a += self.rotation * constants.DEG2RAD
        return a % (2 * pi)

    def reverse_on_angle_rad(self, angle):
        a = angle - self.rotation * constants.DEG2RAD
        return a % (2 * pi)

    def __neg__(self):
        """  returns the reverse transformation """
        return Rotation(self.rotation_center, -self.rotation)

    def is_identity(self):
        """ returns True if the transformation does nothing """
        return (self.rotation == 0.0)
Ejemplo n.º 8
0
class Magnification(__SpecialNoDistortTransform__):
    """ scaling transformation with respect to a given point """
    def __init__(self,
                 magnification_center=(0.0, 0.0),
                 magnification=1.0,
                 absolute_magnification=False,
                 **kwargs):
        if not "translation" in kwargs:
            kwargs['translation'] = SUPPRESSED
        super(Magnification,
              self).__init__(magnification_center=magnification_center,
                             magnification=magnification,
                             absolute_magnification=absolute_magnification,
                             **kwargs)

    absolute_magnification = getattr(NoDistortTransform,
                                     'absolute_magnification')

    def set_magnification(self, value):
        self.__magnification__ = value
        if hasattr(self, "__magnification_center__"):
            center = self.__magnification_center__
            self.translation = Coord2((1 - self.__magnification__) * center.x,
                                      (1 - self.__magnification__) * center.y)

    magnification = SetFunctionProperty("__magnification__",
                                        set_magnification,
                                        default=1.0)

    def set_magnification_center(self, center):
        if not isinstance(center, Coord2):
            center = Coord2(center[0], center[1])
        self.__magnification_center__ = center
        if hasattr(self, "__magnification__"):
            self.translation = Coord2((1 - self.__magnification__) * center.x,
                                      (1 - self.__magnification__) * center.y)

    magnification_center = SetFunctionProperty(
        "__magnification_center__",
        set_magnification_center,
        restriction=RestrictType(Coord2),
        preprocess=ProcessorTypeCast(Coord2),
        default=(0.0, 0.0))

    # overloading for efficiency
    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        coord = self.__magnify__(coord)
        coord = self.__translate__(coord)
        return coord

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        coord = self.__inv_translate__(coord)
        coord = self.__inv_magnify__(coord)
        return coord

    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        coords = self.__magnify_array__(coords)
        coords = self.__translate_array__(coords)
        return coords

    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        coords = self.__inv_translate_array__(coords)
        coords = self.__inv_magnify__array__(coords)
        return coords

    def apply_to_length(self, length):
        """ applies transformation to a distance """
        return length * self.magnification

    def reverse_on_length(self, length):
        """ applies reverse transformation to a distance """
        return length / self.magnification

    def __neg__(self):
        """ returns reverse transformation """
        return Magnification(self.magnification_center,
                             1.0 / self.magnification)

    def is_identity(self):
        """ returns True if the transformation does nothing """
        return (self.magnification == 1.0)

    def is_isometric(self):
        """ returns True if the transformation does nothing """
        return (self.magnification == 1.0)