trafo_Rotate.py 5.34 KB
title = "Map Rotation"
tip = "regrids a map of projection and coordinate system into a different one"
onein = True

import numpy as np
from kapteyn import wcs
from kapteyn.interpolation import map_coordinates
from nodmath import map_interpolate
from nodmath import extract

from guidata.qt.QtGui import QMessageBox
from guidata.dataset.datatypes import DataSet
from guidata.dataset.dataitems import (IntItem, StringItem, ChoiceItem, FloatItem, BoolItem)
from guiqwt.config import _

def nint(x):
    if x > 0: return int(x+0.5)
    else: return int(x-0.5)

class NOD3_App:

    def __init__(self, parent):
        self.parent = parent
        self.parent.activateWindow()

    def compute_app(self, **args):
        class FuncParam(DataSet):
              lon = StringItem('RA  [hh:mm:ss.ss]')
              lat = StringItem('Dec [dd:mm:ss.s]')
              angle = FloatItem("RotAngle", default=0.0, min=-360.0, max=360.0)
        name = title.replace(" ", "")
        if args == {}:
           param = FuncParam(_(title), "Define your coordinate center:")
        else:
           param = self.parent.ScriptParameter(name, args)

        self.parent.compute_11(name, lambda m, p: self.function(m, p), param, onein) 

    def Error(self, msg):
        QMessageBox.critical(self.parent.parent(), title,
                              _(u"Error:")+"\n%s" % str(msg))

    def setRefPoint(self, header):
        # set ref point to map center
        proj1 = wcs.Projection(header)                      # source projection
        Naxis1, Naxis2 = header['NAXIS1'], header['NAXIS2']
        newvals = proj1.toworld((header['NAXIS1']/2.0, header['NAXIS2']/2.0))
        header['CRVAL1'], header['CRVAL2'] = newvals
        header['CRPIX1'], header['CRPIX2'] = (Naxis1+1)/2.0, (Naxis2+1)/2.0
        return header

    def newEdges(self, header):
        edges = []
        proj1 = wcs.Projection(header)                 # source projection
        lam, bet = proj1.toworld((0.0, 0.0))
        edges.append(self.trans((lam, bet)))
        lam, bet = proj1.toworld((0.0, header['NAXIS2']))
        edges.append(self.trans((lam, bet)))
        lam, bet = proj1.toworld((header['NAXIS1'], header['NAXIS2']))
        edges.append(self.trans((lam, bet)))
        lam, bet = proj1.toworld((header['NAXIS1'], 0.0))
        edges.append(self.trans((lam, bet)))
        return np.array(edges)

    def newHeaderAndSize(self, header, newproj, angle):
        newheader = header.copy()
        newheader['CROTA2'] = (newheader['CROTA2'] - angle)
        newheader['CTYPE1'], newheader['CTYPE2'] = newproj
        newheader['CRVAL1'], newheader['CRVAL2'] = self.trans((header['CRVAL1'],header['CRVAL2']))
        try: 
           edges = self.newEdges(header)
        except: 
           self.Error("impossible determin new map size\nplease use 'same size' option")
           return [], p
        proj2 = wcs.Projection(newheader)
        px, py = proj2.topixel(edges).T
        pxmin, pxmax = min(px), max(px)
        pymin, pymax = min(py), max(py)
        naxis1 = int((pxmax-pxmin+0.99)*1.5)
        naxis2 = int((pymax-pymin+0.99)*1.5)
        #naxis1 = min(int((pxmax-pxmin+0.99)*1.5), 361*abs(header['CDELT1']))
        #naxis2 = min(int((pymax-pymin+0.99)*1.5), 181*abs(header['CDELT2']))
        newheader['NAXIS1'], newheader['NAXIS2'] = naxis1, naxis2
        newheader['CRPIX1'], newheader['CRPIX2'] = (naxis1+1)/2.0, (naxis2+1)/2.0
        return newheader

    def todeg(self, coord):
        if coord.strip().find("-") == 0:
           s = -1
        else:
           s = 1
        dms = coord.split(":")
        d = float(dms[0]) + float(dms[1])/60.0 + float(dms[2])/3600.0
        return s*d

    def check_header(self, header):
        import xml2nod3
        Nod3 = xml2nod3.NOD3_Fits()
        keys, nod3header = Nod3.NOD3Header()
        for key in header.keys():
            if not key in keys:
               del header[key]
        return header

    def function(self, m, p):
        nod3header = self.check_header(m.header) 
        p.size = "no automatic"
        header = nod3header.copy()
        NAXIS = 1*header['NAXIS']
        header['NAXIS'] = 2
        pl = 15*self.todeg(p.lon)
        pb = self.todeg(p.lat)
        #header['CRVAL1'] = pl
        #header['CRVAL2'] = pb
        # for the moment no other choise
        header['CTYPE1'] = header['CTYPE1'].replace("DES", "CAR")
        header['CTYPE2'] = header['CTYPE2'].replace("DES", "CAR")
        if not 'CROTA1' in header:
           header['CROTA1'] = 0.0 
        if not 'CROTA2' in header:
           header['CROTA2'] = 0.0 
        header = self.setRefPoint(header)
        proj1 = wcs.Projection(header)                 # source projection
        newheader = header.copy()
        newheader['CRVAL1'] = pl
        newheader['CRVAL2'] = pb
        newheader['CROTA1'] = p.angle
        newheader['CROTA2'] = p.angle
        proj2 = wcs.Projection(newheader)                   # destination projection
        proj2.skysys = proj1.skysys
        x, y = wcs.coordmap(proj1, proj2)
        m.header = newheader
        m.data = map_interpolate(m.data, y, x)
        #m.header['CTYPE1'] = m.header['CTYPE1'][:-3] + "DES"
        #m.header['CTYPE2'] = m.header['CTYPE2'][:-3] + "DES"
        #m.data = map_coordinates(m.data, (x, y), order=1, cval=np.NaN)
        if p.size == "automatic":
        #if not p.size == "user defined":
           m = self.parent.removeNANedges(m)
        return m, p