:remarks    Generates the control points for this path
        
        :return     <list> [ <tuple> ( <float> x, <float> y), .. ]

def controlPoints(self):
        """
        :remarks    Generates the control points for this path
        
        :return     <list> [ <tuple> ( <float> x, <float> y), .. ]
        """
        # define input variables
        in_point = self.inputPoint()
        in_rect = self.inputRect()

        in_x = in_point.x()
        in_y = in_point.y()

        in_cx = in_rect.center().x()
        in_cy = in_rect.center().y()
        in_left = in_rect.left()
        in_right = in_rect.right()
        in_top = in_rect.top()
        in_bot = in_rect.bottom()
        in_loc = self.inputLocation()

        # define output variables
        out_point = self.outputPoint()
        out_rect = self.outputRect()

        out_x = out_point.x()
        out_y = out_point.y()

        out_cx = out_rect.center().x()
        out_cy = out_rect.center().y()
        out_left = out_rect.left()
        out_right = out_rect.right()
        out_top = out_rect.top()
        out_bot = out_rect.bottom()
        out_loc = self.outputLocation()

        # define global variables
        pad = self.squashThreshold()
        loc_left = XConnectionLocation.Left
        loc_right = XConnectionLocation.Right
        loc_top = XConnectionLocation.Top
        loc_bot = XConnectionLocation.Bottom

        # calculate deltas
        delta_x = abs(in_x - out_x)
        delta_y = abs(in_y - out_y)
        buffer = 2

        # calculate point scenarios

        # right -> left
        if (out_loc & loc_right) and (in_loc & loc_left) and out_right < in_left:
            # no y change, bounding rects don't overlap
            if delta_y < buffer:
                return [(out_x, out_y), (in_x, in_y)]

            # y change, padding deltas don't overlap
            elif out_right + pad < in_left - pad:
                return [(out_x, out_y),
                        (out_x + delta_x / 2.0, out_y),
                        (out_x + delta_x / 2.0, in_y),
                        (in_x, in_y)]

        # left -> right
        if (out_loc & loc_left) and (in_loc & loc_right) and in_right < out_left:
            # no y change, bounding rects don't overlap
            if delta_y < buffer and in_x < out_x:
                return [(out_x, out_y), (in_x, in_y)]

            # y change, padding deltas don't overlap
            elif in_left + pad < out_right - pad:
                return [(out_x, out_y),
                        (out_x - delta_x / 2.0, out_y),
                        (out_x - delta_x / 2.0, in_y),
                        (in_x, in_y)]

        # bottom -> top
        if (out_loc & loc_bot) and (in_loc & loc_top) and out_bot < in_top:
            # no x change, bounding rects don't overlap
            if delta_x < buffer and out_y < in_y:
                return [(out_x, out_y), (in_x, in_y)]

            # x change, pading delta's don't overlap
            elif out_bot + pad < in_top - pad:
                return [(out_x, out_y),
                        (out_x, out_y + delta_y / 2.0),
                        (in_x, out_y + delta_y / 2.0),
                        (in_x, in_y)]

        # top -> bottom
        if (out_loc & loc_top) and (in_loc & loc_bot) and in_bot < out_top:
            # no x change, bounding rects don't overlap
            if delta_x < buffer and in_y < out_y:
                return [(out_x, out_y), (in_x, in_y)]

            # y change, padding deltas don't overlap
            elif in_bot + pad < out_top - pad:
                return [(out_x, out_y),
                        (out_x, out_y - delta_y / 2.0),
                        (in_x, out_y - delta_y / 2.0),
                        (in_x, in_y)]

        # bottom -> left
        if (out_loc & loc_bot) and (in_loc & loc_left):
            if out_y + pad < in_y and out_x + pad < in_x:
                return [(out_x, out_y),
                        (out_x, in_y),
                        (in_x, in_y)]

        # bottom -> right
        if (out_loc & loc_bot) and (in_loc & loc_right):
            if out_y + pad < in_y and out_x - pad > in_x:
                return [(out_x, out_y),
                        (out_x, in_y),
                        (in_x, in_y)]

        # top -> left
        if (out_loc & loc_top) and (in_loc & loc_left):
            if in_y + pad < out_y and out_x + pad < in_x:
                return [(out_x, out_y),
                        (out_x, in_y),
                        (in_x, in_y)]

        # top -> right
        if (out_loc & loc_top) and (in_loc & loc_right):
            if in_y + pad < out_y and out_x - pad > in_x:
                return [(out_x, out_y),
                        (out_x, in_y),
                        (in_x, in_y)]

        # right -> top
        if (out_loc & loc_right) and (in_loc & loc_top):
            if out_x + pad < in_x and out_y - pad < in_y:
                return [(out_x, out_y),
                        (in_x, out_y),
                        (in_x, in_y)]

        # right -> bottom
        if (out_loc & loc_right) and (in_loc & loc_bot):
            if out_x + pad < in_x and out_y + pad > in_y:
                return [(out_x, out_y),
                        (in_x, out_y),
                        (in_x, in_y)]

        # left -> top
        if (out_loc & loc_left) and (in_loc & loc_top):
            if in_x + pad < out_x and out_y - pad < in_y:
                return [(out_x, out_y),
                        (in_x, out_y),
                        (in_x, in_y)]

        # left -> bottom
        if (out_loc & loc_left) and (in_loc & loc_bot):
            if in_x + pad < out_x and out_y + pad > in_y:
                return [(out_x, out_y),
                        (in_x, out_y),
                        (in_x, in_y)]

        # right -> right
        if (out_loc & loc_right) and (in_loc & loc_right):
            max_x = max(out_right + 2 * pad, in_right + 2 * pad)
            if out_cx <= in_cx or not (out_loc & loc_left and in_loc & loc_left):
                return [(out_x, out_y),
                        (max_x, out_y),
                        (max_x, in_y),
                        (in_x, in_y)]

        # left -> left
        if (out_loc & loc_left) and (in_loc & loc_left):
            min_x = min(out_left - 2 * pad, in_left - 2 * pad)
            return [(out_x, out_y),
                    (min_x, out_y),
                    (min_x, in_y),
                    (in_x, in_y)]

        # top -> top
        if (out_loc & loc_top) and (in_loc & loc_top):
            if out_cy <= in_cy or not (out_loc & loc_bot and in_loc & loc_bot):
                min_y = min(out_top - 2 * pad, in_top - 2 * pad)
                return [(out_x, out_y),
                        (out_x, min_y),
                        (in_x, min_y),
                        (in_x, in_y)]

        # bottom -> bottom
        if (out_loc & loc_bot) and (in_loc & loc_bot):
            max_y = max(out_y + 2 * pad, out_y + 2 * pad)
            return [(out_x, out_y),
                    (out_x, max_y),
                    (in_x, max_y),
                    (in_x, in_y)]

        # right -> left with center squash
        if (out_loc & loc_right) and (in_loc & loc_left):
            if out_bot < in_top:
                mid_y = out_bot + (in_top - out_bot) / 2.0
            elif in_bot < out_top:
                mid_y = in_bot + (out_top - in_bot) / 2.0
            else:
                mid_y = None

            if mid_y:
                return [(out_x, out_y),
                        (out_x + 2 * pad, out_y),
                        (out_x + 2 * pad, mid_y),
                        (in_x - 2 * pad, mid_y),
                        (in_x - 2 * pad, in_y),
                        (in_x, in_y)]

        # left -> right with center squash
        if (out_loc & loc_left) and (in_loc & loc_right):
            if out_bot < in_top:
                mid_y = in_top + (in_top - out_bot) / 2.0
            elif in_bot < out_top:
                mid_y = out_top - (out_top - in_bot) / 2.0
            else:
                mid_y = None

            if mid_y:
                return [(out_x, out_y),
                        (out_x - 2 * pad, out_y),
                        (out_x - 2 * pad, mid_y),
                        (in_x + 2 * pad, mid_y),
                        (in_x + 2 * pad, in_y),
                        (in_x, in_y)]

        # bottom -> top with center squash
        if (out_loc & loc_bot) and (in_loc & loc_top):
            if out_right < in_left:
                mid_x = out_right + (in_left - out_right) / 2.0
            elif in_right < out_left:
                mid_x = in_right + (out_left - in_right) / 2.0
            else:
                mid_x = None

            if mid_x:
                return [(out_x, out_y),
                        (out_x, out_y + 2 * pad),
                        (mid_x, out_y + 2 * pad),
                        (mid_x, in_y - 2 * pad),
                        (in_x, in_y - 2 * pad),
                        (in_x, in_y)]

        # top -> bottom with center squash
        if (out_loc & loc_top) and (in_loc & loc_bot):
            if out_right < in_left:
                mid_x = in_left + (in_left - out_right) / 2.0
            elif in_right < out_left:
                mid_x = out_left - (out_left - in_right) / 2.0
            else:
                mid_x = None

            if mid_x:
                return [(out_x, out_y),
                        (out_x, out_y - 2 * pad),
                        (mid_x, out_y - 2 * pad),
                        (mid_x, in_y + 2 * pad),
                        (in_x, in_y + 2 * pad),
                        (in_x, in_y)]

        # right -> left with looping
        if (out_loc & loc_right) and (in_loc & loc_left):
            max_y = max(out_bot + 2 * pad, in_bot + 2 * pad)
            return [(out_x, out_y),
                    (out_x + 2 * pad, out_y),
                    (out_x + 2 * pad, max_y),
                    (in_x - 2 * pad, max_y),
                    (in_x - 2 * pad, in_y),
                    (in_x, in_y)]

        # left -> right with looping
        if (out_loc & loc_left) and (in_loc & loc_right):
            max_y = max(out_bot + 2 * pad, in_bot + 2 * pad)
            return [(out_x, out_y),
                    (out_x - 2 * pad, out_y),
                    (out_x - 2 * pad, max_y),
                    (in_x + 2 * pad, max_y),
                    (in_x + 2 * pad, in_y),
                    (in_x, in_y)]

        # bottom -> top with looping
        if (out_loc & loc_bot) and (in_loc & loc_top):
            max_x = max(out_right + 2 * pad, in_right + 2 * pad)
            return [(out_x, out_y),
                    (out_x, out_y + 2 * pad),
                    (max_x, out_y + 2 * pad),
                    (max_x, in_y - 2 * pad),
                    (in_x, in_y - 2 * pad),
                    (in_x, in_y)]

        # top -> bottom with looping
        if (out_loc & loc_top) and (in_loc & loc_bot):
            max_x = max(out_right + 2 * pad, in_right + 2 * pad)
            return [(out_x, out_y),
                    (out_x, out_y - 2 * pad),
                    (max_x, out_y - 2 * pad),
                    (max_x, in_y + 2 * pad),
                    (in_x, in_y + 2 * pad),
                    (in_x, in_y)]

        # right -> right with looping
        if (out_loc & loc_right) and (in_loc & loc_right):
            max_y = max(out_bot + 2 * pad, in_bot + 2 * pad)
            mid_x = out_left - abs(out_left - in_right) / 2.0
            return [(out_x, out_y),
                    (out_x + 2 * pad, out_y),
                    (out_x + 2 * pad, max_y),
                    (mid_x, max_y),
                    (mid_x, in_y),
                    (in_x, in_y)]

        # left -> left with looping
        if (out_loc & loc_left) and (in_loc & loc_left):
            max_y = max(out_bot + 2 * pad, in_bot + 2 * pad)
            mid_x = in_left - abs(in_left - out_right) / 2.0
            return [(out_x, out_y),
                    (out_x - 2 * pad, out_y),
                    (out_x - 2 * pad, max_y),
                    (mid_x, max_y),
                    (mid_x, in_y),
                    (in_x, in_y)]

        # unknown, return a direct route
        return [(out_x, out_y), (in_x, in_y)]