trafo_Trafo.py 7.46 KB
title = "Coordinate Transformation"
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 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):
            system = ChoiceItem("System", (("Equatorial J2000", "Equatorial J2000"),
                                           ("Equatorial B1950", "Equatorial B1950"),
                                           ("Galactic", "Galactic")))
            #proj = ChoiceItem("Projection", (("CAR", "CAR"), (("DES", "DES")), ("ARC", "ARC"), 
            proj = ChoiceItem("Projection", (("CAR", "CAR"), #("ARC", "ARC"), 
                                             ("SIN", "SIN"), 
                                             ("TAN", "TAN"), ("NCP", "NCP"), ("SFL", "SFL"),
                                             ("AIT", "AIT")))
            #zero = BoolItem("Refere to (0, 0)", default=False)
            angle = FloatItem("RotAngle", default=0.0, min=-180.0, max=180.0)
            size = ChoiceItem("MapSize", (("same size", "same size"), ("automatic", "automatic"),
                                       ("user defined", "user defined")), default = "same size")
            dremove = BoolItem("Remove dummy cols/rows", default=True)
        name = title.replace(" ", "")
        if args == {}:
           param = FuncParam(_(title), "Your choise:")
        else:
           param = self.parent.ScriptParameter(name, args)
        param.zero = False

        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']+1)/2.0, (header['NAXIS2']+1)/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 check_projparm(self, header, proj):
        for key in header.keys():
            #if key.find("POLE") > 0 and proj == "CAR":
            #   header.pop(key)
            if key.find("POLE") > 0 and proj == "CAR":
               if key == "LONPOLE": header[key] = 0.0
               if key == "LATPOLE": header[key] = 90.0
            else:
               if key == "LONPOLE": header[key] = 180.0
               if key == "LATPOLE": header[key] = header['CRVAL2']
        return header

    def newHeaderAndSize(self, header, newproj, newcoord):
        newheader = header.copy()
        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 []
        #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.0/abs(header['CDELT1']))
        #naxis2 = min(int((pymax-pymin+0.99)*1.5), 181.0/abs(header['CDELT2']))
        if newcoord:
           naxis1 = np.sqrt(header['NAXIS1']**2 + header['NAXIS2']**2)
           naxis2 = np.sqrt(header['NAXIS1']**2 + header['NAXIS2']**2)
           newheader['NAXIS1'], newheader['NAXIS2'] = naxis1, naxis2
           newheader['CRPIX1'], newheader['CRPIX2'] = (naxis1+1)/2.0, (naxis2+1)/2.0
        return newheader

    def polarisation(self, maptype, coords):
        n, rows, cols = np.shape(coords)
        world = proj2.toworld((coords[0].ravel(), coords[1].ravel()))

    def function(self, m, p):
        naxis = m.header['NAXIS']
        if p.system[0] == "E":
           pl = "RA---"
           pb = "DEC--"
        else:
           pl = "GLON-"
           pb = "GLAT-"
        pl += p.proj 
        pb += p.proj 
        header = m.header.copy()
        header['NAXIS'] = 2
        # for the moment no other choise
        header['CTYPE1'] = header['CTYPE1'].replace("DES", "CAR")
        header['CTYPE2'] = header['CTYPE2'].replace("DES", "CAR")
        # usually not necessary
        if header['CTYPE2'][:3] != pb[:3]:
           newcoord = True
           header = self.setRefPoint(header)
        elif "CROTA2" in header and abs(header["CROTA2"] - p.angle) > 1.0:
           newcoord = True
        else:
           newcoord = False
        proj1 = wcs.Projection(header)                 # source projection
        if p.system == "Galactic": 
           self.trans = wcs.Transformation(proj1.skysys, skyout=wcs.galactic)
        elif p.system == "Equatorial J2000":
           header['EPOCH'] = (2000.0, "Equinox of coordinate system.")
           self.trans = wcs.Transformation(proj1.skysys, skyout=(wcs.equatorial, wcs.fk5, 'J2000.0'))
        elif p.system == "Equatorial B1950":
           header['EPOCH'] = (1950.0, "Equinox of coordinate system.")
           self.trans = wcs.Transformation(proj1.skysys, skyout=(wcs.equatorial, wcs.fk4, 'B1950.0'))
        if p.size == "automatic":
           try:
              newheader = self.newHeaderAndSize(header, (pl, pb), newcoord) 
           except:
              self.Error("transfomation not possible,\ntry 'same size'")
              return [], p
        else:
           newheader = header.copy()
           newheader['CTYPE1'], newheader['CTYPE2'] = pl, pb
           newheader['CRVAL1'], newheader['CRVAL2'] = self.trans((header['CRVAL1'],header['CRVAL2']))
        if newheader == []:
           return [], p
        newheader['CROTA2'] = p.angle
        newheader = self.check_projparm(newheader, p.proj)
        proj2 = wcs.Projection(newheader)                   # destination projection
        coords = wcs.coordmap(proj1, proj2)
        m.header = newheader
        # TODO:
        if "xMAPTYPE" in m.header and m.header['MAPTYPE'] in ("U", "Q", "PA"):
           m.data = self.polarisation(m.header['MAPTYPE'], coords)
        m.data = map_interpolate(m.data, coords[1], coords[0])
        if not p.size == "user defined":
           if p.dremove:
              m = self.parent.removeNANedges(m)
        m.header['NAXIS'] = naxis
        return m, p