def _get_alpha(self):
     if abs(self.dec) + self.radius > 89.9:
         return 180
     return math.degrees(
         abs(
             math.atan(
                 math.sin(math.radians(self.radius)) / np.sqrt(
                     abs(
                         math.cos(math.radians(self.dec - self.radius)) *
                         math.cos(math.radians(self.dec + self.radius)))))))
Ejemplo n.º 2
0
def get_alpha(radius, dec):
    if abs(dec) + radius > 89.9:
        return 180
    return math.degrees(
        abs(
            math.atan(
                math.sin(math.radians(radius)) / np.sqrt(
                    abs(
                        math.cos(math.radians(dec - radius)) *
                        math.cos(math.radians(dec + radius)))))))
Ejemplo n.º 3
0
def angle_between(v1, v2):
    """ Returns the angle in radians between vectors 'v1' and 'v2'::

            >>> angle_between((1, 0, 0), (0, 1, 0))
            1.5707963267948966
            >>> angle_between((1, 0, 0), (1, 0, 0))
            0.0
            >>> angle_between((1, 0, 0), (-1, 0, 0))
            3.141592653589793
    """
    v1_u = unit_vector(v1)
    v2_u = unit_vector(v2)
    angle = np.arccos(np.dot(v1_u, v2_u))
    if math.isnan(angle):
        if (v1_u == v2_u).all():
            return 0.0
        else:
            return 180
    return math.degrees(angle)
    def Evolvent(self):
        '''Расчет эвольвенты зуба
        '''
        #Расчет эвольветы зуба 
        # Читаем данные из полей формы
        # z = Количество зубьев
        z = self.doubleSpinBox_Z.value() 
        # m = Модуль зуба
        m = self.doubleSpinBox_m.value() 
        # a = Угол главного профиля
        a = self.doubleSpinBox_a.value()
        #b = Угол наклона зубьев
        b = self.doubleSpinBox_b.value()
        #ha = Коэффициент высоты головки
        ha = self.doubleSpinBox_ha.value()
        #pf = К-т радиуса кривизны переходной кривой
        pf = self.doubleSpinBox_pf.value()
        #c = Коэффициент радиального зазора
        c = self.doubleSpinBox_c.value()
        #x = К-т смещения исходного контура
        x = self.doubleSpinBox_x.value()
        #y =Коэффициент уравнительного смещения
        y = self.doubleSpinBox_y.value()
        # n= Количество точек (точность построения)
        #n=int(self.doubleSpinBox_n.value())
        n=100
        # заполня переменные 
        # Делительный диаметр
        d = z * m
        # Высота зуба h=
        h = 2.25 * m
        # Высота головки ha =
        hav = m
        # Высота ножки hf=
        hf = 1.25 * m
        #Диаметр вершин зубьев
        #da = d + (2 * m)*(ha+x+y)
        da = d + 2 * (ha + x - y) * m
        #Диаметр впадин (справочно)
        #df = d -(2 * hf)
        df = d -2 * (ha + c - x) * m
        #Окружной шаг зубьев или Шаг зацепления по дуге делительной окружности: Pt или p
        pt = math.pi * m
        #Окружная толщина зуба или Толщина зуба по дуге делительной окружности: St или S
        #Суммарный коэффициент смещений: XΣ
        X = 0.60 + 0.12
       # St = 0.5 * pf
       # St = 0.5 * pt
        St = 0.5 * pt + 2 * x * m * math.tan(math.radians(a))
        #inv a 
        inva=math.tan(math.radians(a))-math.radians(a)
        #Угол зацепления invαw
        invaw= (2 * X - math.tan(math.radians(a))) / (10+26) + inva
        #Угол профиля
        at = math.ceil(math.degrees(math.atan(math.tan(math.radians(a))
            /math.cos( math.radians(b)))))
        # Диаметр основной окружности
        db = d * math.cos(math.radians(at)) 
        #Диаметр начала выкружки зуба
        D  = 2 * m * ( ( z/( 2 * math.cos(math.radians(b)) )-(1-x)) ** 2 +
            ((1-x)/math.tan(math.radians(at)))**2)**0.5
        #Промежуточные данные
        yi = math.pi/2-math.radians(at)

        hy = yi/(n-1)

        x0 = math.pi/(4*math.cos(math.radians(b))
             )+pf*math.cos(math.radians(at))+math.tan(math.radians(at))

        y0 = 1-pf*math.sin(math.radians(at))-x

        C  = (math.pi/2+2*x*math.tan(math.radians(a))
             )/z+math.tan(math.radians(at))-math.radians(at)
        #Расчетный шаг точек эвольвенты
        hdy = (da-D)/(n-1)
        dyi = da
        fi = 2*math.cos(math.radians(b))/z*(x0+y0*math.tan(yi))
        #Заполняем текстовые поля в форме
        # Делительный диаметр
    #    self.lineEdit_d.setText(str(d))
        # Высота зуба h=
    #    self.lineEdit_h.setText(str(h))
        # Высота головки ha =
    #    self.lineEdit_ha.setText(str(hav))
        # Высота ножки hf=
    #    self.lineEdit_hf.setText(str(hf))
        # Диаметр вершин зубьев
    #    self.lineEdit_da.setText(str(da))
        # Диаметр впадин (справочно)
    #    self.lineEdit_df.setText(str(df))
        # Окружной шаг зубьев Pt=
    #    self.lineEdit_Pt.setText(str(math.ceil(pt)))
        # Окружная толщина зуба St=
    #    self.lineEdit_St.setText(str(math.ceil(St)))
        # Угол профиля
    #    self.lineEdit_at.setText(str(at))
        # Диаметр основной окружности
    #    self.lineEdit_db.setText(str(math.ceil(db)))
        
        # Создаем списки 
        List_dyi=[]
        List_Di=[]
        List_Yei=[]
        List_Xei=[]
        List_Minus_Xei=[]
        List_Xdai=[]
        List_Ydai=[]
        List_yi=[]
        List_Ai=[]
        List_Bi=[]
        List_fi=[]
        List_Ypki=[]
        List_Xpki=[]
        List_Minus_Xpki=[]
        # Заполняем нуливой (первый )индекс списка значениями
        List_dyi.append(dyi)
        List_Di.append( math.acos( db/ List_dyi[0] ) - math.tan( math.acos( db / List_dyi[0] ) ) + C )
        List_Yei.append(dyi / 2*math.cos( List_Di[0]))
        List_Xei.append(List_Yei[0]*math.tan(List_Di[0]))
        List_Minus_Xei.append(-List_Xei[0])
        List_Xdai.append(-List_Xei[0])
        List_Ydai.append(((da/2)**2-List_Xdai[0]**2)**0.5)
        hda=(List_Xei[0]-List_Minus_Xei[0])/(n-1)
        # Заполняем первый (второй по счету )индекс списка значениями 
        List_dyi.append(dyi-hdy)
        List_Di.append( math.acos(db/List_dyi[1])-math.tan(math.acos(db/List_dyi[1]))+C)
        List_Yei.append( List_dyi[1]/2*math.cos(List_Di[1]))
        List_Xei.append( List_Yei[1]* math.tan(List_Di[1]))
        List_Minus_Xei.append(-List_Xei[1])
        List_Xdai.append(List_Xdai[0]+hda)
        List_Ydai.append(((da/2)**2-List_Xdai[1]**2)**0.5)
        Xdai=List_Xdai[1]
        dyi=dyi-hdy
        # Начинаем  заполнять списки в цикле 
        i=0
        while i < n-2:  
            i=i+1
            dyi=dyi-hdy
            List_Di.append(math.acos(db/dyi)-math.tan(math.acos(db/dyi))+C)
            Di=math.acos(db/dyi)-math.tan(math.acos(db/dyi))+C
            Yei=dyi/2*math.cos(Di)
            Xei=Yei*math.tan(Di) 
            List_dyi.append(dyi) 
            List_Yei.append(dyi/2*math.cos(Di))
            List_Xei.append(Yei*math.tan(Di))
            List_Minus_Xei.append(-Xei) 
            Xdai=Xdai+hda
            List_Xdai.append(Xdai)
            List_Ydai.append(((da/2)**2-Xdai**2)**0.5)
        #Заполняем последний индекс  списка    
        List_dyi[n-1]=D
        # Заполняем нуливой (первый )индекс списка значениями
        List_yi.append(yi)
        List_Ai.append(z/(2*math.cos(math.radians(b)))-y0-pf*math.cos(List_yi[0]) )
        List_Bi.append(y0*math.tan(List_yi[0])+pf*math.sin(List_yi[0]))
        List_fi.append(fi)
        List_Ypki.append((List_Ai[0] * math.cos(fi)+List_Bi[0] * math.sin(fi)) * m)
        List_Xpki.append((List_Ai[0] * math.sin(fi)-List_Bi[0] * math.cos(fi)) * m)
        List_Minus_Xpki.append(-List_Xpki[0])
        # Начинаем  заполнять списки в цикле 
        i=0
        while i < n-2:
            i=i+1
            yi=yi-hy
            List_yi.append(yi)
            Ai = z / (2 * math.cos(math.radians(b)))-y0-pf*math.cos(yi)
            List_Ai.append( z / (2 * math.cos(math.radians(b)))-y0-pf*math.cos(yi))
            Bi =y0*math.tan(yi)+pf*math.sin(yi)
            List_Bi.append(y0*math.tan(yi)+pf*math.sin(yi))
            fi = 2*math.cos(math.radians(b))/z*(x0+y0*math.tan(yi))
            List_fi.append(2*math.cos(math.radians(b))/z*(x0+y0*math.tan(yi)))
            List_Ypki.append((Ai*math.cos(fi)+Bi*math.sin(fi))*m)
            Ypki=(Ai*math.cos(fi)+Bi*math.sin(fi))*m
            Xpki=(Ai*math.sin(fi)-Bi*math.cos(fi))*m
            List_Xpki.append((Ai*math.sin(fi)-Bi*math.cos(fi))*m)
            List_Minus_Xpki.append(-Xpki)
        #Заполняем последний индекс  списка  
        List_yi.append(yi-yi)
        List_Ai.append(z/(2*math.cos(math.radians(b)))-y0-pf*math.cos(List_yi[n-1]) )  
        List_Bi.append(y0*math.tan(List_yi[n-1])+pf*math.sin(List_yi[n-1])) 
        List_fi.append(2*math.cos(math.radians(b))/z*(x0+y0*math.tan(List_yi[n-1])))
        List_Ypki.append((List_Ai[n-1] * math.cos(fi)+List_Bi[n-1] * math.sin(List_fi[n-1])) * m)
        List_Xpki.append((List_Ai[n-1] * math.sin(fi)-List_Bi[n-1] * math.cos(List_fi[n-1])) * m)
        List_Minus_Xpki.append(-List_Xpki[n-1])

       # self.WiPfileZub(List_Yei,List_Xei,List_Minus_Xei,List_Ypki,List_Xpki,List_Minus_Xpki,List_Ydai,List_Xdai)
        self.GragEvolvent(List_Minus_Xei+List_Minus_Xpki,List_Yei+List_Ypki,n)

        DFreza = self.lineEditDFreza.text()
        VisotaYAxis = self.lineEditVisota.text()
        Diametr = self.lineEditDiametr.text()
        if DFreza and VisotaYAxis:
            E30 = (int(DFreza)/2) +float(VisotaYAxis)
        else:
            E30 = 0
        angi_B=0
        if ValkosZub:
            angie_A:float = 90# угол А треугольника по высоте детали 
            angie_B:float = float(b) #угол B треугольника по высоте детали ( угол наклона зуба по чертежу)
            angie_Y:float = 180 - (angie_A + angie_B) # трерий уго треугольника по высоте детали 
            side_c:float = float(E30)# высота детали первая сторона треугольника 
            side_a = side_c * math.sin(math.radians(angie_A)) / math.sin(math.radians(angie_Y))# вторая сторона треугольника 
            side_b = side_c * math.sin(math.radians(angie_B)) / math.sin(math.radians(angie_Y))# третия сторона треугольника ( ось Х)
            sid_a:float = float(Diametr)/2 # радиус детали первая и вторая тророны треугольника по торцу
           # sid_a:float = float(self.lineEdit_da.text())/2 # радиус детали первая и вторая тророны треугольника по торцу
            sid_c:float = sid_a
            if sid_c < 10 :
                sid_a:float = 10
                sid_c:float = 10
                angi_B = float('{:.3f}'.format(math.degrees(math.acos((sid_a**2+sid_c**2-side_b**2)/(2*sid_a*sid_c)))))
                QMessageBox.about (self, "Ошибка " , "Диаметр шестерни задан меньше 20 мм. \n Введите риальный диаметр шестерни " )
            else:
                angi_B = float('{:.3f}'.format(math.degrees(math.acos((sid_a**2+sid_c**2-side_b**2)/(2*sid_a*sid_c)))))# результат угол поворота стола 


        self.label_da.setText(str(round(da,1)))
        self.label_d.setText(str(round(d,1)))
        self.label_at.setText(str(round(at,1)))
        self.label_db.setText(str(round(db,1)))
        self.label_df.setText(str(round(df,1)))
        self.label_St.setText(str(round(St,1)))
        self.label_Pt.setText(str(round(pt,1)))
        self.label_hf.setText(str(round(hf,1)))
        self.label_ha.setText(str(round(ha,1)))
        self.label_h.setText(str(round(h,1)))
        self.lineEditDiametr.setText(str(da))
        self.lineEditUgol.setText(str(angi_B))
Ejemplo n.º 5
0
def get_line_data(pixels, x1, y1, x2, y2, line_w=2, the_z=0, the_c=0, the_t=0):
    """
    Grabs pixel data covering the specified line, and rotates it horizontally
    so that x1,y1 is to the left,
    Returning a numpy 2d array. Used by Kymograph.py script.
    Uses PIL to handle rotating and interpolating the data. Converts to numpy
    to PIL and back (may change dtype.)

    @param pixels:          PixelsWrapper object
    @param x1, y1, x2, y2:  Coordinates of line
    @param line_w:          Width of the line we want
    @param the_z:           Z index within pixels
    @param the_c:           Channel index
    @param the_t:           Time index
    """

    size_x = pixels.getSizeX()
    size_y = pixels.getSizeY()

    line_x = x2 - x1
    line_y = y2 - y1

    rads = math.atan(float(line_x) / line_y)

    # How much extra Height do we need, top and bottom?
    extra_h = abs(math.sin(rads) * line_w)
    bottom = int(max(y1, y2) + extra_h / 2)
    top = int(min(y1, y2) - extra_h / 2)

    # How much extra width do we need, left and right?
    extra_w = abs(math.cos(rads) * line_w)
    left = int(min(x1, x2) - extra_w)
    right = int(max(x1, x2) + extra_w)

    # What's the larger area we need? - Are we outside the image?
    pad_left, pad_right, pad_top, pad_bottom = 0, 0, 0, 0
    if left < 0:
        pad_left = abs(left)
        left = 0
    x = left
    if top < 0:
        pad_top = abs(top)
        top = 0
    y = top
    if right > size_x:
        pad_right = right - size_x
        right = size_x
    w = int(right - left)
    if bottom > size_y:
        pad_bottom = bottom - size_y
        bottom = size_y
    h = int(bottom - top)
    tile = (x, y, w, h)

    # get the Tile
    plane = pixels.getTile(the_z, the_c, the_t, tile)

    # pad if we wanted a bigger region
    if pad_left > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((data_h, pad_left), dtype=plane.dtype)
        plane = hstack((pad_data, plane))
    if pad_right > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((data_h, pad_right), dtype=plane.dtype)
        plane = hstack((plane, pad_data))
    if pad_top > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((pad_top, data_w), dtype=plane.dtype)
        plane = vstack((pad_data, plane))
    if pad_bottom > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((pad_bottom, data_w), dtype=plane.dtype)
        plane = vstack((plane, pad_data))

    pil = script_utils.numpy_to_image(plane, (plane.min(), plane.max()), int32)

    # Now need to rotate so that x1,y1 is horizontally to the left of x2,y2
    to_rotate = 90 - math.degrees(rads)

    if x1 > x2:
        to_rotate += 180
    # filter=Image.BICUBIC see
    # http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2172449/
    rotated = pil.rotate(to_rotate, expand=True)
    # rotated.show()

    # finally we need to crop to the length of the line
    length = int(math.sqrt(math.pow(line_x, 2) + math.pow(line_y, 2)))
    rot_w, rot_h = rotated.size
    crop_x = (rot_w - length) / 2
    crop_x2 = crop_x + length
    crop_y = (rot_h - line_w) / 2
    crop_y2 = crop_y + line_w
    cropped = rotated.crop((crop_x, crop_y, crop_x2, crop_y2))
    return asarray(cropped)
Ejemplo n.º 6
0
def get_line_data(image, x1, y1, x2, y2, line_w=2, the_z=0, the_c=0, the_t=0):
    """
    Grab pixel data covering the specified line, and rotates it horizontally.

    Uses current rendering settings and returns 8-bit data.
    Rotates it so that x1,y1 is to the left,
    Returning a numpy 2d array. Used by Kymograph.py script.
    Uses PIL to handle rotating and interpolating the data. Converts to numpy
    to PIL and back (may change dtype.)

    @param pixels:          PixelsWrapper object
    @param x1, y1, x2, y2:  Coordinates of line
    @param line_w:          Width of the line we want
    @param the_z:           Z index within pixels
    @param the_c:           Channel index
    @param the_t:           Time index
    """
    size_x = image.getSizeX()
    size_y = image.getSizeY()

    line_x = x2 - x1
    line_y = y2 - y1

    rads = math.atan2(line_y, line_x)

    # How much extra Height do we need, top and bottom?
    extra_h = abs(math.sin(rads) * line_w)
    bottom = int(max(y1, y2) + extra_h / 2)
    top = int(min(y1, y2) - extra_h / 2)

    # How much extra width do we need, left and right?
    extra_w = abs(math.cos(rads) * line_w)
    left = int(min(x1, x2) - extra_w)
    right = int(max(x1, x2) + extra_w)

    # What's the larger area we need? - Are we outside the image?
    pad_left, pad_right, pad_top, pad_bottom = 0, 0, 0, 0
    if left < 0:
        pad_left = abs(left)
        left = 0
    x = left
    if top < 0:
        pad_top = abs(top)
        top = 0
    y = top
    if right > size_x:
        pad_right = right - size_x
        right = size_x
    w = int(right - left)
    if bottom > size_y:
        pad_bottom = bottom - size_y
        bottom = size_y
    h = int(bottom - top)

    # get the Tile - render single channel white
    image.set_active_channels([the_c + 1], None, ['FFFFFF'])
    jpeg_data = image.renderJpegRegion(the_z, the_t, x, y, w, h)
    pil = Image.open(StringIO(jpeg_data))

    # pad if we wanted a bigger region
    if pad_left > 0 or pad_right > 0 or pad_top > 0 or pad_bottom > 0:
        img_w, img_h = pil.size
        new_w = img_w + pad_left + pad_right
        new_h = img_h + pad_top + pad_bottom
        canvas = Image.new('RGB', (new_w, new_h), '#ff0000')
        canvas.paste(pil, (pad_left, pad_top))
        pil = canvas

    # Now need to rotate so that x1,y1 is horizontally to the left of x2,y2
    to_rotate = math.degrees(rads)

    # filter=Image.BICUBIC see
    # http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2172449/
    rotated = pil.rotate(to_rotate, expand=True)

    # finally we need to crop to the length of the line
    length = int(math.sqrt(math.pow(line_x, 2) + math.pow(line_y, 2)))
    rot_w, rot_h = rotated.size
    crop_x = (rot_w - length) / 2
    crop_x2 = crop_x + length
    crop_y = (rot_h - line_w) / 2
    crop_y2 = crop_y + line_w
    cropped = rotated.crop((crop_x, crop_y, crop_x2, crop_y2))

    # return numpy array
    rgb_plane = asarray(cropped)
    # greyscale image. r, g, b all same. Just use first
    return rgb_plane[::, ::, 0]
Ejemplo n.º 7
0
def getLineData(pixels, x1, y1, x2, y2, lineW=2, theZ=0, theC=0, theT=0):
    """
    Grabs pixel data covering the specified line, and rotates it horizontally
    so that x1,y1 is to the left,
    Returning a numpy 2d array. Used by Kymograph.py script.
    Uses PIL to handle rotating and interpolating the data. Converts to numpy
    to PIL and back (may change dtype.)

    @param pixels:          PixelsWrapper object
    @param x1, y1, x2, y2:  Coordinates of line
    @param lineW:           Width of the line we want
    @param theZ:            Z index within pixels
    @param theC:            Channel index
    @param theT:            Time index
    """

    from numpy import asarray

    sizeX = pixels.getSizeX()
    sizeY = pixels.getSizeY()

    lineX = x2 - x1
    lineY = y2 - y1

    rads = math.atan(float(lineX) / lineY)

    # How much extra Height do we need, top and bottom?
    extraH = abs(math.sin(rads) * lineW)
    bottom = int(max(y1, y2) + extraH / 2)
    top = int(min(y1, y2) - extraH / 2)

    # How much extra width do we need, left and right?
    extraW = abs(math.cos(rads) * lineW)
    left = int(min(x1, x2) - extraW)
    right = int(max(x1, x2) + extraW)

    # What's the larger area we need? - Are we outside the image?
    pad_left, pad_right, pad_top, pad_bottom = 0, 0, 0, 0
    if left < 0:
        pad_left = abs(left)
        left = 0
    x = left
    if top < 0:
        pad_top = abs(top)
        top = 0
    y = top
    if right > sizeX:
        pad_right = right - sizeX
        right = sizeX
    w = int(right - left)
    if bottom > sizeY:
        pad_bottom = bottom - sizeY
        bottom = sizeY
    h = int(bottom - top)
    tile = (x, y, w, h)

    # get the Tile
    plane = pixels.getTile(theZ, theC, theT, tile)

    # pad if we wanted a bigger region
    if pad_left > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((data_h, pad_left), dtype=plane.dtype)
        plane = hstack((pad_data, plane))
    if pad_right > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((data_h, pad_right), dtype=plane.dtype)
        plane = hstack((plane, pad_data))
    if pad_top > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((pad_top, data_w), dtype=plane.dtype)
        plane = vstack((pad_data, plane))
    if pad_bottom > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((pad_bottom, data_w), dtype=plane.dtype)
        plane = vstack((plane, pad_data))

    pil = numpyToImage(plane)
    #pil.show()

    # Now need to rotate so that x1,y1 is horizontally to the left of x2,y2
    toRotate = 90 - math.degrees(rads)

    if x1 > x2:
        toRotate += 180
    # filter=Image.BICUBIC see
    # http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2172449/
    rotated = pil.rotate(toRotate, expand=True)
    #rotated.show()

    # finally we need to crop to the length of the line
    length = int(math.sqrt(math.pow(lineX, 2) + math.pow(lineY, 2)))
    rotW, rotH = rotated.size
    cropX = (rotW - length) / 2
    cropX2 = cropX + length
    cropY = (rotH - lineW) / 2
    cropY2 = cropY + lineW
    cropped = rotated.crop((cropX, cropY, cropX2, cropY2))
    #cropped.show()
    return asarray(cropped)
def getLineData(pixels, x1, y1, x2, y2, lineW=2, theZ=0, theC=0, theT=0):
    """
    Grabs pixel data covering the specified line, and rotates it horizontally
    so that x1,y1 is to the left,
    Returning a numpy 2d array. Used by Kymograph.py script.
    Uses PIL to handle rotating and interpolating the data. Converts to numpy
    to PIL and back (may change dtype.)

    @param pixels:          PixelsWrapper object
    @param x1, y1, x2, y2:  Coordinates of line
    @param lineW:           Width of the line we want
    @param theZ:            Z index within pixels
    @param theC:            Channel index
    @param theT:            Time index
    """

    from numpy import asarray

    sizeX = pixels.getSizeX()
    sizeY = pixels.getSizeY()

    lineX = x2-x1
    lineY = 1 if y2-y1 == 0 else y2-y1

    rads = math.atan(float(lineX) / lineY)

    # How much extra Height do we need, top and bottom?
    extraH = abs(math.sin(rads) * lineW)
    bottom = int(max(y1, y2) + extraH/2)
    top = int(min(y1, y2) - extraH/2)

    # How much extra width do we need, left and right?
    extraW = abs(math.cos(rads) * lineW)
    left = int(min(x1, x2) - extraW)
    right = int(max(x1, x2) + extraW)

    # What's the larger area we need? - Are we outside the image?
    pad_left, pad_right, pad_top, pad_bottom = 0, 0, 0, 0
    if left < 0:
        pad_left = abs(left)
        left = 0
    x = left
    if top < 0:
        pad_top = abs(top)
        top = 0
    y = top
    if right > sizeX:
        pad_right = right - sizeX
        right = sizeX
    w = int(right - left)
    if bottom > sizeY:
        pad_bottom = bottom - sizeY
        bottom = sizeY
    h = int(bottom - top)
    tile = (x, y, w, h)

    # get the Tile
    plane = pixels.getTile(theZ, theC, theT, tile)

    # pad if we wanted a bigger region
    if pad_left > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((data_h, pad_left), dtype=plane.dtype)
        plane = hstack((pad_data, plane))
    if pad_right > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((data_h, pad_right), dtype=plane.dtype)
        plane = hstack((plane, pad_data))
    if pad_top > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((pad_top, data_w), dtype=plane.dtype)
        plane = vstack((pad_data, plane))
    if pad_bottom > 0:
        data_h, data_w = plane.shape
        pad_data = zeros((pad_bottom, data_w), dtype=plane.dtype)
        plane = vstack((plane, pad_data))

    pil = numpyToImage(plane)
    # pil.show()

    # Now need to rotate so that x1,y1 is horizontally to the left of x2,y2
    toRotate = 90 - math.degrees(rads)

    if x1 > x2:
        toRotate += 180
    # filter=Image.BICUBIC see
    # http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2172449/
    rotated = pil.rotate(toRotate, expand=True)
    # rotated.show()

    # finally we need to crop to the length of the line
    length = int(math.sqrt(math.pow(lineX, 2) + math.pow(lineY, 2)))
    rotW, rotH = rotated.size
    cropX = (rotW - length)/2
    cropX2 = cropX + length
    cropY = (rotH - lineW)/2
    cropY2 = cropY + lineW
    cropped = rotated.crop((cropX, cropY, cropX2, cropY2))
    # cropped.show()
    return asarray(cropped)