aboutsummaryrefslogtreecommitdiff
path: root/sys/mwcs/iwewcs.x
blob: 1f5ca72a2412baf7600d0889a658c3ae63cb74af (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include	<error.h>
include	<syserr.h>
include	<ctype.h>
include	<imhdr.h>
include	<imio.h>
include	<math.h>
include	"mwcs.h"
include	"imwcs.h"

# IW_ENTERWCS -- Enter a WCS as represented in an IMWCS (FITS oriented)
# wcs descriptor into an MWCS descriptor.  This routine is called by MW_LOADIM
# after IW_RFITS has been called to scan a FITS image header to build the
# IMWCS descriptor used as input here.

procedure iw_enterwcs (mw, iw, ndim)

pointer	mw			#I pointer to MWCS descriptor
pointer	iw			#I pointer to IMWCS descriptor
int	ndim			#I system dimension

double	theta
char	ctype[8]
bool	have_ltm, have_ltv, have_wattr
int	axes[2], axis, npts, ch, ip, raax, decax, ax1, ax2, i, j, ea_type
double	maxval
pointer	sp, r, o_r, cd, ltm, cp, rp, bufp, pv, wv, o_cd, o_ltm, str

bool	streq()
pointer	iw_gbigfits(), iw_findcard()
int	strncmp(), ctod(), strldxs(), envgeti()
errchk	mw_swtermd, iw_gbigfits, malloc, mw_swtype, mw_swsampd
define	samperr_ 91

begin
	call smark (sp)
	call salloc (r, ndim, TY_DOUBLE)
	call salloc (o_r, ndim, TY_DOUBLE)
	call salloc (cd, ndim*ndim, TY_DOUBLE)
	call salloc (ltm, ndim*ndim, TY_DOUBLE)
	call salloc (o_cd, ndim*ndim, TY_DOUBLE)
	call salloc (o_ltm, ndim*ndim, TY_DOUBLE)
	call salloc (str, SZ_LINE, TY_CHAR)

	raax = 1
	decax = 2

	# Set any nonlinear functions on the axes.
	do axis = 1, ndim {
	    rp = IW_CTYPE(iw,axis)
	    if (rp == NULL)
		next

	    # Get the value of CTYPEi.  Ignore case and treat '_' and '-'
	    # as equivalent.

	    do i = 1, 8 {
		ch = Memc[rp+i-1]
		if (ch == EOS || ch == ' ' || ch == '\'')
		    break
		else if (IS_UPPER(ch))
		    ch = TO_LOWER(ch)
		else if (ch == '_')
		    ch = '-'
		ctype[i] = ch
	    }
	    ctype[i] = EOS

	    # Determine the type of function on this axis.
	    if (streq (ctype, "linear")) {
		;   # Linear is the default.

	    } else if (streq (ctype, "sampled")) {
		# A sampled WCS is an array of [P,W] points.

		bufp = iw_gbigfits (iw, TY_WSVDATA, axis)
		npts = IW_WSVLEN(iw,axis)
		call malloc (pv, npts, TY_DOUBLE)
		call malloc (wv, npts, TY_DOUBLE)

		ip = 1
		do i = 1, npts {
		    if (ctod (Memc[bufp], ip, Memd[pv+i-1]) <= 0)
			goto samperr_
		    if (ctod (Memc[bufp], ip, Memd[wv+i-1]) <= 0) {
samperr_		call eprintf (
			    "Image %s, axis %d: Cannot read sampled WCS\n")
			    call pargstr (IM_NAME(IW_IM(iw)))
			    call pargi (axis)
			break
		    }
		}

		call mw_swtype (mw, axis, 1, "sampled", "")
		call mw_swsampd (mw, axis, Memd[pv], Memd[wv], npts)

		call mfree (wv, TY_DOUBLE)
		call mfree (pv, TY_DOUBLE)
		call mfree (bufp, TY_CHAR)

	    } else if (strncmp (ctype, "ra--", 4) == 0) {
		# The projections are restricted to two axes and are indicated
		# by CTYPEi values such as, e.g., "RA---TAN" and "DEC--TAN"
		# for the TAN projection.

		raax = axis

		# Locate the DEC axis.
		decax = 0
		do j = 1, ndim {
		    cp = IW_CTYPE(iw,j)
		    if (cp != NULL)
			if (Memc[cp+3] == '-' || Memc[cp+3] == '_')
			    if (strncmp (Memc[cp], "DEC", 3) == 0 ||
				strncmp (Memc[cp], "dec", 3) == 0) {
				decax = j
				break
			    }
		}

		# Did we find it?
		if (decax == 0) {
		    call eprintf (
			"Image %s, axis %d: Cannot locate dec-%s axis\n")
			call pargstr (IM_NAME(IW_IM(iw)))
			call pargi (axis)
			call pargstr (ctype[5])
		}

		# Get the function type.
		ip = strldxs ("-", ctype) + 1

		# Assign the function to the two axes.
		axes[1] = axis
		axes[2] = decax
		call mw_swtype (mw, axes, 2, ctype[ip],
		    "axis 1: axtype=ra axis 2: axtype=dec")

	    } else if (strncmp (ctype, "dec-", 4) == 0) {
		;   # This case is handled when RA-- is seen.

	    } else if (strncmp (ctype[2], "lon-", 4) == 0) {
		# The projections are restricted to two axes and are indicated
		# by CTYPEi values such as, e.g., "xLON-TAN" and "xLAT-TAN"
		# for the TAN projection. The letter x may be any character
		# but must be the same for both the longitude and latitude
		# axes. The standard values of x are G/g for galactic, E/e
		# for ecliptic, and S/s for supergalactic coordinates.

		raax = axis

		# Locate the corresponding LAT axis.
		decax = 0
		do j = 1, ndim {
		    cp = IW_CTYPE(iw,j)
		    if (cp != NULL) {
			if (Memc[cp+4] == '-' || Memc[cp+4] == '_') {
			    if (strncmp (Memc[cp+1], "LAT", 3) == 0 ||
			        strncmp (Memc[cp+1], "lat", 3) == 0) {
			        decax = j
			        break
			    }
			}
		    }
		}

		# Did we find it?
		if (decax == 0) {
		    call eprintf (
		        "Image %s, axis %d: Cannot locate %clat%s axis\n")
		        call pargstr (IM_NAME(IW_IM(iw)))
		        call pargi (axis)
			call pargc (ctype[1])
		        call pargstr (ctype[5])
		}

		# Get the function type.
		ip = strldxs ("-", ctype) + 1

		# Assign the function to the two axes.
		axes[1] = axis
		axes[2] = decax
		call sprintf (Memc[str], SZ_LINE,
		    "axis 1: axtype=%clon axis 2: axtype=%clat")
		    call pargc (ctype[1])
		    call pargc (ctype[1])
		call mw_swtype (mw, axes, 2, ctype[ip], Memc[str])

	    } else if (strncmp (ctype[2], "lat-", 4) == 0) { 
		;   # This case is handled when xLON is seen.

	    } else if (strncmp (ctype, "multispec", 8) == 0) {
		# Multispec format image.  Axis 1,2 are coupled.
		if (axis == 1) {
		    axes[1] = 1;  axes[2] = 2
		    call mw_swtype (mw, axes, 2, "multispec", "")
		}

	    } else {
		# Since we have to be able to read any FITS header, we have
		# no control over the value of CTYPEi.  If the value is
		# something we don't know about, assume a LINEAR axis, using
		# the given value of CTYPEi as the default axis label.

		call mw_swattrs (mw, axis, "label", ctype)
	    }
	}

	# Compute the CD matrix, or verify that one was read.  Either the
	# CD matrix was input, the CROTA/CDELT representation was input,
	# or nothing was input, in which case we have the identity matrix.

	if (iw_findcard (iw, TY_CD, ERR, 0) == NULL) {
	    # Initialize CD matrix to the identity matrix.  Can't use mw_mkidm
	    # here as IW_CD is not dimensioned ndim.

	    do j = 1, ndim {
		do i = 1, ndim
		    IW_CD(iw,i,j) = 0.0
		IW_CD(iw,j,j) = 1.0
	    }

	    # Convert CDELT/CROTA to CD matrix.
	    if (iw_findcard (iw, TY_CDELT, ERR, 0) != NULL) {
		theta = DEGTORAD(IW_CROTA(iw))
		ax1 = raax
		ax2 = decax
		IW_CD(iw,ax1,ax1) =  IW_CDELT(iw,ax1) * cos(theta)
		IW_CD(iw,ax1,ax2) =  IW_CDELT(iw,ax1) * sin(theta)
		IW_CD(iw,ax2,ax1) = -IW_CDELT(iw,ax2) * sin(theta)
		IW_CD(iw,ax2,ax2) =  IW_CDELT(iw,ax2) * cos(theta)
	    }

	    do j = 1, ndim {
		if (j == raax || j == decax)
		    next
		IW_CD(iw,j,j) =  IW_CDELT(iw,j)
	    }
	}

	# Set axes with no scales to unit scales.  Issue a warning by
	# default but use "wcs_matrix_err" to allow setting other error
	# actions.

	do i = 1, ndim {
	    maxval = 0D0
	    do j = 1, ndim
		maxval = max (maxval, abs(IW_CD(iw,i,j)))
	    if (maxval == 0D0) {
		iferr (ea_type = envgeti ("wcs_matrix_err"))
		    ea_type = EA_WARN
		iferr {
		    switch (ea_type) {
		    case EA_FATAL, EA_ERROR:
			call sprintf (Memc[str], SZ_FNAME, 
			    "CD keywords for axis %d undefined")
			    call pargi (i)
			call error (SYS_MWMISSAX, Memc[str])
		    case EA_WARN:
			IW_CD(iw,i,i) = 1D0
			call sprintf (Memc[str], SZ_LINE, 
			    "setting CD%d_%d to %.4g")
			    call pargi (i)
			    call pargi (i)
			    call pargd (IW_CD(iw,i,i))
			call error (SYS_MWMISSAX, Memc[str])
		    default:
			IW_CD(iw,i,i) = 1D0
		    }
		} then
		    call erract (ea_type)
	    }
	}

	# Extract an NDIM submatrix from LTM and CD.
	do j = 1, ndim
	    do i = 1, ndim {
		Memd[o_cd+(j-1)*ndim+(i-1)] = IW_CD(iw,i,j)
		Memd[o_ltm+(j-1)*ndim+(i-1)] = IW_LTM(iw,i,j)
	    }

	# Set the linear portion of the Wterm.  First we have to transform
	# it from the FITS logical->world representation to the MWCS
	# physical->world form, by separating out the Lterm.  We have
	# CD = CD' * LTM and R = inv(LTM) * (R' - LTV), where CD' and R' are
	# the FITS versions of the MWCS CD matrix and R vector (CRPIX), and
	# LTM and LTV are the Lterm rotation matrix and translation vector.

	# First, determine if either LTM or LTV was specified in the header.
	have_ltm = (iw_findcard (iw, TY_LTM, ERR, 0) != NULL)
	have_ltv = (iw_findcard (iw, TY_LTV, ERR, 0) != NULL)

	# Compute CD = CD' * LTM.
	if (have_ltm)
	    call mw_mmuld (Memd[o_cd], Memd[o_ltm], Memd[cd], ndim)
	else
	    call amovd (Memd[o_cd], Memd[cd], ndim*ndim)

	# Compute R = inv(LTM) * (R' - LTV).
	if (have_ltm || have_ltv) {
	    call asubd (IW_CRPIX(iw,1), IW_LTV(iw,1), Memd[o_r], ndim)
	    if (have_ltm) {
		call mw_invertd (Memd[o_ltm], Memd[ltm], ndim)
		call mw_vmuld (Memd[ltm], Memd[o_r], Memd[r], ndim)
	    } else
		call amovd (Memd[o_r], Memd[r], ndim)
	} else
	    call amovd (IW_CRPIX(iw,1), Memd[r], ndim)

	# Set the Wterm.
	call mw_swtermd (mw, Memd[r], IW_CRVAL(iw,1), Memd[cd], ndim)
	# Process in any axis attributes.  The pseudo-axis 0 is used by
	# any global WCS attributes.

	do axis = 0, ndim {
	    # Is there any attribute data for axis J?
	    have_wattr = false
	    do i = 1, IW_NCARDS(iw) {
		cp = IW_CARD(iw,i)
		if (C_TYPE(cp) == TY_WATDATA && C_AXIS(cp) == axis) {
		    have_wattr = true
		    break
		}
	    }

	    # Reconstruct the attribute list and enter into MWCS.
	    if (have_wattr) {
		bufp = iw_gbigfits (iw, TY_WATDATA, axis)
		call mw_swtype (mw, axis, 1, "", Memc[bufp])
		call mfree (bufp, TY_CHAR)
	    }
	}

	call sfree (sp)
end