def __init__(self,parent=None, time=None, location=None): QtGui.QWidget.__init__(self,parent=parent) screen = QtGui.QDesktopWidget().screenGeometry() x,y,w,h = (0,70,500,330) #probably should be passed as argument in constructor self.sceneSize = (x,y,w,h) self.scene = QtGui.QGraphicsScene(self) self.setGeometry(QtCore.QRect(x,y,w,h)) self.view = QtGui.QGraphicsView(self.scene, self) self.setAutoFillBackground(True) p = self.palette() # for white background color p.setColor(self.backgroundRole(), QtGui.QColor("white")) self.setPalette(p) self.time = time self.location = location self.coordinateSystem = CoordinateSystem.AZEL # default coordinate system self.srt = self.parent().getSRT() #self.currentPos = (0,0) # this should always be in azel degrees self.targetPos = self.getCurrentPos()#(0,0) # likewise self.radioSources = [] # the list of radio source from radiosources.cat self.galaxy = GalacticPlane(time = self.time, location=self.location) self.clickedSource = "" # name of last clicked source
class Skymap(QtGui.QWidget): """ The skymap is a widget which plots axes and draws radio sources read in by the catalogue file. """ def __init__(self,parent=None, time=None, location=None): QtGui.QWidget.__init__(self,parent=parent) screen = QtGui.QDesktopWidget().screenGeometry() x,y,w,h = (0,70,500,330) #probably should be passed as argument in constructor self.sceneSize = (x,y,w,h) self.scene = QtGui.QGraphicsScene(self) self.setGeometry(QtCore.QRect(x,y,w,h)) self.view = QtGui.QGraphicsView(self.scene, self) self.setAutoFillBackground(True) p = self.palette() # for white background color p.setColor(self.backgroundRole(), QtGui.QColor("white")) self.setPalette(p) self.time = time self.location = location self.coordinateSystem = CoordinateSystem.AZEL # default coordinate system self.srt = self.parent().getSRT() #self.currentPos = (0,0) # this should always be in azel degrees self.targetPos = self.getCurrentPos()#(0,0) # likewise self.radioSources = [] # the list of radio source from radiosources.cat self.galaxy = GalacticPlane(time = self.time, location=self.location) self.clickedSource = "" # name of last clicked source def init_cat(self,catalogue): """ Required to set the initial pointing position, initial status and read in the contents of the source catalogue file. """ #self.currentPos = self.srt.getCurrentPos() self.readCatalogue(catalogue) #self.srt.setStatus(Status.READY) def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) self.drawRadioSources(qp) self.drawLines(qp) self.drawCurrentPosCrosshair(qp) self.drawTargetPosCrosshair(qp) self.drawGalaxy(qp) qp.end() def fetchRadioSourceCoordinates(self): """ For each loaded radio source, call its update method to calculate its most current coordinates. TODO: tracking """ for src in self.radioSources: src.update() self.galaxy.update() def updateSkymap(self): """ """ targetPos = self.getTargetPos() #if self.srt.getMode() == Mode.SIM: # self.setCurrentPos(self.srt.getCurrentPos()) #elif self.srt.getMode() == Mode.LIVE: # self.setCurrentPos(self.srt.azalt()) if self.srt.getStatus() == Status.INIT: self.setTargetPos((self.srt.drive.az_home, self.srt.drive.el_home)) targetPos = self.getTargetPos() if self.srt.drive.slewSuccess(targetPos) == True: self.srt.setStatus(Status.READY) if self.srt.getMode() == Mode.LIVE: self.setCurrentPos(self.srt.azalt()) if self.srt.getStatus() == Status.CALIBRATING: if self.srt.drive.calibrating == False: self.srt.setStatus(Status.READY) # potential problem here if the telescope never reaches its destination then the status will never be ready and a hard reset is required. if self.srt.getStatus() == Status.SLEWING: if self.srt.drive.slewSuccess(targetPos) == True: self.srt.setStatus(Status.READY) self.parent().antennaCoordsInfo.updateCoords() self.parent().antennaCoordsInfo.tick() if self.clickedSource != "" and type(self.clickedSource) != int: self.parent().sourceInfo.updateEphemLabel(self.clickedSource) if self.srt.getStatus() == Status.TRACKING: source = self.getClickedSource() self.srt.track(source) self.updateStatusBar() self.update() QtGui.QApplication.processEvents() # i _think_ this calls self.paintEvent() def updateStatusBar(self): """ Update the status bar with the current SRT status. """ status = self.srt.getStatus() if status == Status.INIT: self.parent().updateStatusBar("Status: Initialising") elif status == Status.SLEWING: self.parent().updateStatusBar("Status: Slewing") elif status == Status.PARKED: self.parent().updateStatusBar("Status: Parked") elif status == Status.CALIBRATING: self.parent().updateStatusBar("Status: Calibrating") elif status == Status.READY: self.parent().updateStatusBar("Status: Ready") elif status == Status.TRACKING: #sourceName = self.getClickedSource().getName() self.parent().updateStatusBar("Status: Tracking") def setCurrentPos(self,pos): self.srt.setCurrentPos(pos) def getCurrentPos(self): return self.srt.getCurrentPos() def setTargetPos(self,pos): if isinstance(pos, tuple): self.targetPos = pos else: print "is skycoord" now = Time.now() altazframe = AltAz(obstime=now,location=self.location) apos = pos.transform_to(altazframe) xf, yf = apos.az.value, apos.alt.value self.targetPos = (xf, yf) def getTargetPos(self): return self.targetPos def getCoordinateSystem(self): return self.coordinateSystem() def setCoordinateSystem(self, coordsys): self.coordinateSystem = coordsys def getClickedSource(self): return self.clickedSource def setClickedSource(self,src): self.clickedSource = src def checkClickedSource(self,clickedPos,r): """ Tests whether a drawn source has been clicked on. """ (x,y) = clickedPos for src in self.radioSources: (sx,sy) = src.getPos() if (abs(x - sx)) < r and (abs(y - sy)) < r: name = src.getName() return src else: check = 0 return check def mousePressEvent(self, QMouseEvent): """ Event handler for when the cursor is clicked on the skymap area. """ cursor = QtGui.QCursor() xf = self.mapFromGlobal(cursor.pos()).x() yf = self.mapFromGlobal(cursor.pos()).y() (cxf,cyf) = self.getCurrentPos() # in simulation mode, the coordinate are rounded to integers. if self.srt.getMode() == Mode.SIM: x = int(self.pixelToDegreeX(xf)) y = int(self.pixelToDegreeY(yf)) currentPos = (int(cxf),int(cyf)) elif self.srt.getMode() == Mode.LIVE: x = self.pixelToDegreeX(xf) y = self.pixelToDegreeY(yf) currentPos = (cxf,cyf) state = self.srt.getStatus() slewToggle = self.parent().commandButtons.getSlewToggle() self.clickedSource = self.checkClickedSource((x,y),4) if self.clickedSource != 0: self.parent().sourceInfo.updateEphemLabel(self.clickedSource) if slewToggle == SlewToggle.ON and state != Status.SLEWING: self.targetPos = self.clickedSource.getPos() else: if slewToggle == SlewToggle.ON and state != Status.SLEWING: self.targetPos = (x,y) if slewToggle == SlewToggle.ON: if state != Status.SLEWING: #self.targetPos = targetPos if self.targetPos == currentPos: print("Already at that position.") self.targetPos = currentPos self.srt.setStatus(Status.READY) else: print("Slewing to " + str(self.targetPos)) self.srt.setStatus(Status.SLEWING) self.updateStatusBar() self.srt.slew(self.targetPos) #self.currentPos = targetPos self.updateStatusBar() else: print("Already Slewing. Please wait until finished.") else: pass self.update() def drawCurrentPosCrosshair(self,qp): """ Wrapper function for drawing the current aimed direction crosshair. """ color = QtGui.QColor('black') self.drawCrosshair(self.getCurrentPos(),color,qp) def drawTargetPosCrosshair(self,qp): """ Wrapper function for drawing the chosen target direction crosshair. """ color = QtGui.QColor('green') self.drawCrosshair(self.targetPos,color,qp) def drawCrosshair(self,pos,color,qp): """ Draws a crosshair (a vertial and horizontal line) at a position pos in degrees. """ x,y = self.degreeToPixel(pos) d = 5 crosshairPen = QtGui.QPen(color,3,QtCore.Qt.SolidLine) qp.setPen(crosshairPen) qp.drawLine(x-d,y,x+d,y) qp.drawLine(x,y-d,x,y+d) def drawSun(self,qp): x,y,w,h = self.sceneSize d = 6 blackSunPen = QtGui.QPen(QtCore.Qt.black,5,QtCore.Qt.SolidLine) yellowSunPen = QtGui.QPen(QtCore.Qt.yellow,5,QtCore.Qt.SolidLine) qp.setPen(blackSunPen) qp.setFont(QtGui.QFont('Decorative', 6)) # temp astropy for testing acre_road = EarthLocation(lat=55.9*u.deg,lon=-4.3*u.deg,height=45*u.m) now = Time(time.time(),format='unix') altazframe = AltAz(obstime=now, location=acre_road) sunaltaz = get_sun(now).transform_to(altazframe) alt = float(sunaltaz.alt.degree) az = float(sunaltaz.az.degree) #obs = ephem.Observer() #obs.lon, obs.lat = '-4.3', '55.9' #glasgow #obs.date = ephem.now() #sun = ephem.Sun() #sun.compute(obs) #x = float(repr(sun.az))*(180/math.pi) #y = float(repr(sun.alt))*(180/math.pi) qp.drawText(self.degreeToPixelX(az+10),self.degreeToPixelY(alt),"Sun") qp.drawEllipse(self.degreeToPixelX(az),self.degreeToPixelY(alt),d,d) qp.setPen(yellowSunPen) qp.drawEllipse(self.degreeToPixelX(az),self.degreeToPixelY(alt),d-2,d-2) def drawObject(self,qp,posd,desc): """ Draws an object with description desc on the skymap at posd where posd is azalt position in degrees. All drawing must be done in pixel coordinates - use degreeToPixel() functions to convert degrees to pixel coords. """ x,y,w,h = self.sceneSize posPixels = self.degreeToPixel(posd) x,y = posPixels if desc.lower() == "sun": d = 6 blackSunPen = QtGui.QPen(QtCore.Qt.black,5,QtCore.Qt.SolidLine) yellowSunPen = QtGui.QPen(QtCore.Qt.yellow,5,QtCore.Qt.SolidLine) qp.setPen(blackSunPen) qp.setFont(QtGui.QFont('Decorative', 6)) qp.drawText(x+10,y,"Sun") qp.drawEllipse(x,y,d,d) qp.setPen(yellowSunPen) qp.drawEllipse(x,y,d-2,d-2) elif desc.lower() == "moon": d = 6 blackMoonPen = QtGui.QPen(QtCore.Qt.black,5,QtCore.Qt.SolidLine) greyMoonPen = QtGui.QPen(QtCore.Qt.gray,5,QtCore.Qt.SolidLine) qp.setPen(blackMoonPen) qp.setFont(QtGui.QFont('Decorative', 6)) qp.drawText(x+10,y,"Moon") qp.drawEllipse(x,y,d,d) qp.setPen(greyMoonPen) qp.drawEllipse(x,y,d-2,d-2) else: d = 4 objectPen = QtGui.QPen(QtGui.QColor("black"),5,QtCore.Qt.SolidLine) qp.setFont(QtGui.QFont('Decorative',6)) qp.setPen(objectPen) qp.drawText(x+10,y,desc) qp.drawEllipse(x,y,d,d) def drawRadioSources(self,qp): """ Loops through the list of previously constructed radio sources and calls drawObject() to draw them on the skymap. """ for src in self.radioSources: name = src.getName() pos = src.getPos() if src.isVisible() == True: #print("%s pos: %s" % (name,pos)) self.drawObject(qp,pos,name) else: #print(name + " is not visible currently.") pass def drawLines(self,qp): """ Draw the axes lines. """ x,y,w,h = self.sceneSize linesPen = QtGui.QPen(QtGui.QColor(0,0,10, 30),1) qp.setFont(QtGui.QFont('Decorative', 8)) qp.setPen(linesPen) qp.setRenderHint(qp.Antialiasing) if self.coordinateSystem == CoordinateSystem.RADEC: # Right Ascension for i in range(1,24): j = (i/24.0) qp.drawLine(w*j,1,w*j,h-1) qp.drawText(w*j-20,h-20,str(i)) # Declination for i in range(1,10): j = 0.1*i qp.drawLine(1,h*j,w-1,h*j) qp.drawText(w-20,h*j-20,str(i)) elif self.coordinateSystem == CoordinateSystem.AZEL: # Azimuth nlines = 18 for i in range(1,nlines+1): j = self.degreeToPixelX(i * (360.0/nlines)) qp.drawLine(j,1,j,h-1) qp.drawText(j-20,h-1,str(i*20)) # Elevation nlines = 9 for i in reversed(range(1,nlines+1)): j = self.degreeToPixelY(i * (90.0/nlines)) qp.drawLine(1,j,w-1,j) qp.drawText(w-20,j-10,str(i*10)) def drawGalaxy(self, qp): """ Draw in the galactic plane. """ linesPen = QtGui.QPen(QtGui.QColor(255, 100, 0, 255),3) qp.setFont(QtGui.QFont('Decorative', 8)) qp.setPen(linesPen) c = self.galaxy.points pix = [] for point in c: pix.append(self.degreeToPixel(point)) for i in xrange(len(pix)-1): #j = i + 1 #if pix[i][0]<pix[j][0]: continue # avoids drawing a line across the screen when the plane crosses the wrap-over. qp.drawEllipse(pix[i][0], pix[i][1],1,1) #, pix[j][0], pix[j][1]) def degreeToPixelX(self,deg): (xs,ys,w,h) = self.sceneSize return deg * (w/360.0) def pixelToDegreeX(self,pixel): (xs,ys,w,h) = self.sceneSize return pixel * (360.0/w) def degreeToPixel(self,deg): (xs,ys,w,h) = self.sceneSize x,y = deg return (x*(w/360.0),(90.0-y)*(h/90.0)) def degreeToPixelY(self,deg): (xs,ys,w,h) = self.sceneSize return (90.0-deg) * (h/90.0) def pixelToDegreeY(self,pixel): (xs,ys,w,h) = self.sceneSize return (h-pixel) * (90.0/h) def pixelToDegree(self,pixel): (xs,ys,w,h) = self.sceneSize x,y = pixel return (x*(360.0/w),(h-y)*(90.0/h)) def printSourceInfo(self): pass def printSources(self): for src in self.radioSources: print(src.getName()) def readCatalogue(self,catalogue): """ Reads radio sources from the catalogue file, constructs RadioSource class for each source, gets its coordinates and adds it to the radiosources array. """ fname = str(catalogue) fpath = "" f = open(fpath+fname,"r") print("Using catalogue file: %s" % f.name) print("Loading source information.") for line in f: name = line.rstrip() if name.lower() == "sun": src = RadioSource("Sun") src.sun() self.radioSources.append(src) print(line + " - OK.") elif name.lower() == "moon": src = RadioSource("Moon") src.moon() self.radioSources.append(src) print(line + " - OK.") else: src = RadioSource(name) chk = src.lookupAstropy() if chk == True: # found the source online if src.getExists() == True: print(line + " - OK.") self.radioSources.append(src) else: print(line + " - Fail.") else: # can't find source online - maybe internet is down - use radec coords if supplied lineList = line.rstrip().split() if len(lineList) > 1: name = lineList[0] ra = lineList[1] dec = lineList[2] print(name,ra,dec) # what if the source name ias a space e.g. cass A else: print(line + " - Fail.") f.close()