1
C @(#)perspec.for 13.1.1.1 (ES0-DMD) 06/02/98 18:20:55
2
C===========================================================================
3
C Copyright (C) 1995 European Southern Observatory (ESO)
5
C This program is free software; you can redistribute it and/or
6
C modify it under the terms of the GNU General Public License as
7
C published by the Free Software Foundation; either version 2 of
8
C the License, or (at your option) any later version.
10
C This program is distributed in the hope that it will be useful,
11
C but WITHOUT ANY WARRANTY; without even the implied warranty of
12
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
C GNU General Public License for more details.
15
C You should have received a copy of the GNU General Public
16
C License along with this program; if not, write to the Free
17
C Software Foundation, Inc., 675 Massachusetss Ave, Cambridge,
20
C Corresponding concerning ESO-MIDAS should be addressed as follows:
21
C Internet e-mail: midas@eso.org
22
C Postal address: European Southern Observatory
23
C Data Management Division
24
C Karl-Schwarzschild-Strasse 2
25
C D 85748 Garching bei Muenchen
27
C===========================================================================
31
C++++++++++++++++++++++++++++++++++++++++++++++++++
34
C program PERSP version 1.00 920103
35
C K. Banse ESO - Garching
36
C 1.10 930512 2.00 940104
39
C perspective, rebinning
42
C the following keywords are used:
44
C IN_A/C/1/60 input frame
45
C OUT_A/C/1/60 output frame
46
C INPUTR/1/2 rotation angle in degrees, in [0,360]
47
C tilt angle in degrees in [0,90]
51
C 1.10 STKWRR had 1 param. too many !
52
C 2.00 add z-perspective plot
54
C--------------------------------------------------
58
INTEGER IAV,N,NAXISA,NAXISC
59
INTEGER*8 PNTRA,PNTRB,PNTRC
60
INTEGER IMNOA,IMNOB,IMNOC,STAT
61
INTEGER NPIXA(3),NPIXB(2),NPIXC(2),KZ,KNO
62
INTEGER N1,N2,NSIZ,NPERSP,DIM3C,KDIFF,PLANES(20)
63
INTEGER UNI(1),NULO,MADRID(1)
66
CHARACTER*60 FRAMEA,FRAMEB
67
CHARACTER CUNITA*64,IDENTA*72,STR*80
69
DOUBLE PRECISION STEPA(3),STARTA(3),STARTB(2),STEPB(2),STEPC(2)
70
DOUBLE PRECISION ST(2)
73
REAL ANGDEG,ANGLE,AC,AS,X1,X2,X3,Y1,Y2,Y3,X4,Y4
75
REAL PIXROT(2),ROTOFF(2),EN(2),RST(2)
76
REAL QUOT,RQUOT,R1,R2,RROT(4),CUTS(4)
77
REAL FACTO,RBUF(20),ZCUTS(2)
81
INCLUDE 'MID_INCLUDE:ST_DEF.INC'
83
EQUIVALENCE (X2,RBUF(1)),(Y2,RBUF(2)),(X4,RBUF(3)),(Y4,RBUF(4))
84
EQUIVALENCE (X3,RBUF(5)),(Y3,RBUF(6)),(X1,RBUF(7)),(Y1,RBUF(8))
86
DATA FACTO /0.0174533/ ! Pi / 180.
88
DATA IDENTA /' '/, CUNITA /' '/ !necessary ... !!!
90
INCLUDE 'MID_INCLUDE:ST_DAT.INC'
95
C get input frame + map it
96
CALL STKRDC('IN_A',1,1,60,IAV,FRAMEA,UNI,NULO,STAT)
97
CALL STIGET(FRAMEA,D_R4_FORMAT,F_I_MODE,F_IMA_TYPE,3,
98
+ NAXISA,NPIXA,STARTA,STEPA,
99
+ IDENTA,CUNITA,PNTRA,IMNOA,STAT)
101
+ CALL STETER(1,'We need a 2-dim image ...')
102
IF ((NPIXA(1).EQ.1) .OR. (NPIXA(2).EQ.1))
103
+ CALL STETER(1,'We need a 2-dim image ...')
104
CALL STDRDR(IMNOA,'LHCUTS',1,4,IAV,CUTS,UNI,NULO,STAT)
107
RNULL = CUTS(3) - 0.01*(CUTS(4)-CUTS(3)) !null val < min
114
C get name of output frame + plane no.s (or action code)
115
CALL STKRDC('OUT_A',1,1,60,IAV,FRAMEB,UNI,NULO,STAT)
116
CALL STKRDC('INPUTC',1,1,80,IAV,STR,UNI,NULO,STAT)
118
C get rotation angle + perspective angle + (scaling size)
119
CALL STKRDR('INPUTR',1,4,IAV,RROT,UNI,NULO,STAT)
120
IF (STR(1:4).EQ.'zper') THEN
124
ISCAL = NINT(RROT(3))
126
+ CALL STETER(1,'Invalid scaling size (should be > 0)...')
128
IF (ZCUTS(2).LE.ZCUTS(1)) CALL STETER(1,
129
+ 'Invalid scale limit (should be > LHCUTS(3))...')
131
C get planes to work on
132
ELSE IF ((STR(1:1).EQ.'A') .OR. (STR(1:1).EQ.'a')) THEN
133
PLANES(1) = -1 !indicate all planes
134
KNO = NPIXA(3) - 1 !no. of planes - 1
136
CALL GENCNV(STR,1,20,PLANES,QUOT,STEPC,IAV)
138
+ CALL STETER(5,'Invalid planes specified ...')
139
IF ((PLANES(1).LE.0).OR.(PLANES(1).GT.NPIXA(3)))
140
+ CALL STETER(6,'specified plane outside limits... ')
141
N = PLANES(1) - 1 !update pointer
142
KNO = IAV - 1 !no. of planes - 1
143
PNTRA = PNTRA + N*NPIXA(1)*NPIXA(2)
145
PLANES(IAV) = 0 !mark the end
151
ANGLE = ANGDEG * FACTO
152
N = (NPIXA(1) + 1) / 2 !use center pixel
154
N = (NPIXA(2) + 1) / 2 !use center pixel
159
IF ((ANGDEG.LT.0.1).OR.(ANGDEG.GT.359.9)) THEN
160
NPIXB(1) = NPIXA(1) !no rotation
162
STARTB(1) = STARTA(1)
163
STARTB(2) = STARTA(2)
182
C to get size of output frame, rotate corners around lower left corner
185
CALL ROTA1(R1,R2,AC,AS,X1,Y1) !(NX-1,NY-1)
186
CALL ROTA1(0.,R2,AC,AS,X2,Y2) !(0,NY-1)
187
CALL ROTA1(R1,0.,AC,AS,X3,Y3) !(NX-1,0)
189
Y4 = 0. !rotation point stays fixed
191
C get result frame "corners"
192
ST(1) = MIN(0.,X1,X2,X3) !rotated x-start
193
EN(1) = MAX(0.,X1,X2,X3) !rotated x-end
194
ST(2) = MIN(0.,Y1,Y2,Y3) !rotated y-start
195
EN(2) = MAX(0.,Y1,Y2,Y3) !rotated y-end
197
C from coords. of rotation point determine shift after rotation
199
ROTOFF(1) = PIXROT(1)*QUOT + PIXROT(2)*AS
200
ROTOFF(2) = PIXROT(2)*QUOT - PIXROT(1)*AS
201
CALL ROTA1(PIXROT(1),PIXROT(2),AC,AS,RROT(1),RROT(2))
203
C choose corners such, that rotation point is hit ...
206
QUOT = RROT(N) - ST(N) !distance of fixed p. to rotation p.
207
RQUOT = FLOAT(INT(QUOT)) + 1. !is forced to multiples of steps
208
ST(N) = RROT(N) - RQUOT
209
QUOT = EN(N) - ST(N) !distance of start to end point
210
RQUOT = FLOAT(INT(QUOT)) + 1. !in multiples of steps
211
EN(N) = ST(N) + RQUOT
212
NPIXB(N) = NINT(RQUOT) + 1 !no. of points in new image
215
C now update start of rotated image, so that rotation point stays fixed
216
RST(1) = ST(1) + ROTOFF(1)
217
RST(2) = ST(2) + ROTOFF(2)
218
STARTB(1) = STARTA(1) + ( RST(1)*STEPA(1) ) !we work in 0,0 space
219
STARTB(2) = STARTA(2) + ( RST(2)*STEPA(2) )
221
RBUF(N) = RBUF(N) - ST(1) !relate to new frame
222
RBUF(N+1) = RBUF(N+1) - ST(2)
225
C create and map intermediate frame
227
3000 NSIZ = NPIXB(1) * NPIXB(2)
232
CALL STFCRE('midpersp',D_R4_FORMAT,F_X_MODE,1,NSIZ,
234
CALL STFMAP(IMNOB,F_X_MODE,1,NSIZ,IAV,PNTRB,STAT)
236
CALL ROTA2(MADRID(PNTRA),MADRID(PNTRB),NPIXA,NPIXB,
240
C create result frame
244
IF (PCDEG.LE.0.1) THEN !no tilt at all ...
248
ELSE IF (PCDEG.GT.89.5) THEN !total side view => single line
254
PC = COS(PCDEG * FACTO)
255
NPIXC(2) = INT (NPIXB(2) * PC)
257
STEPC(2) = STEPB(2) * PC
260
C move corners to world coords.
262
RBUF(N) = STARTB(1) + (RBUF(N)*STEPC(1))
263
IAV = INT (RBUF(N+1)*PC)
264
IF (IAV.GE.NPIXC(2)) IAV = NPIXC(2) - 1
265
RBUF(N+1) = STARTB(2) + (IAV*STEPC(2))
267
IF (KNO.GT.0) THEN !if more than one plane
268
QUOT = STEPC(2) * ((NPERSP+KDIFF)*KNO)
269
RBUF(9) = RBUF(2) + QUOT
270
RBUF(10) = RBUF(4) + QUOT
271
RBUF(11) = RBUF(6) + QUOT
272
RBUF(12) = RBUF(8) + QUOT
273
RBUF(13) = KNO + 1 !no. of planes
275
RBUF(15) = STEPC(2) * KDIFF
276
RBUF(16) = STEPC(2) * (NPERSP+KDIFF)
279
NPIXC(2) = (KNO+1)*NPIXC(2) + KNO*KDIFF
280
RQUOT = STARTB(2) + (NPIXC(2)-1)*STEPC(2) !y-end
281
IF (STEPC(2).GT.0.) THEN
282
IF (RBUF(9).GT.RQUOT) RBUF(9) = RQUOT
283
IF (RBUF(10).GT.RQUOT) RBUF(10) = RQUOT
284
IF (RBUF(11).GT.RQUOT) RBUF(11) = RQUOT
285
IF (RBUF(12).GT.RQUOT) RBUF(12) = RQUOT
287
IF (RBUF(9).LT.RQUOT) RBUF(9) = RQUOT
288
IF (RBUF(10).LT.RQUOT) RBUF(10) = RQUOT
289
IF (RBUF(11).LT.RQUOT) RBUF(11) = RQUOT
290
IF (RBUF(12).LT.RQUOT) RBUF(12) = RQUOT
296
CALL STKWRR('OUTPUTR',RBUF,1,20,UNI,STAT)
297
IF (STR(1:4).EQ.'zper') THEN
298
IDENTA(1:) = 'perspective z-plot of input frame '
300
NPIXC(2) = NPIXC(2)+ISCAL
301
NPERSP = NPIXC(2) !in case we reset it later on
304
+ 'perspective plot of selected planes of input frame '
306
CALL STIPUT(FRAMEB,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,
307
+ NAXISC,NPIXC,STARTB,STEPC,
308
+ IDENTA,CUNITA,PNTRC,IMNOC,STAT)
311
C and do the perspective rebinning
312
IF (N2.EQ.1) THEN !real job
313
NPIXC(2) = NPERSP !reset to original value (3-dim)
315
IF (STR(1:4).EQ.'zper') THEN
316
CALL JPERSP(MADRID(PNTRB),MADRID(PNTRC),
317
+ NPIXB,NPIXC,PC,RNULL,ZCUTS,ISCAL)
318
CALL STDWRI(IMNOC,'NPIX',NPIXC(2),2,1,UNI,STAT)
320
CALL KPERSP(MADRID(PNTRB),MADRID(PNTRC),
324
IF (STR(1:4).EQ.'zper') THEN
325
CALL JPERSP(MADRID(PNTRA),MADRID(PNTRC),
326
+ NPIXB,NPIXC,PC,RNULL,ZCUTS,ISCAL)
327
CALL STDWRI(IMNOC,'NPIX',NPIXC(2),2,1,UNI,STAT)
329
CALL KPERSP(MADRID(PNTRA),MADRID(PNTRC),
333
ELSE IF (N2.EQ.0) THEN !just rotated image
335
CALL COPYF(MADRID(PNTRB),MADRID(PNTRC),NSIZ)
337
CALL COPYF(MADRID(PNTRA),MADRID(PNTRC),NSIZ)
341
CALL COPYF(MADRID(PNTRB),MADRID(PNTRC),NPIXB(1))
343
CALL COPYF(MADRID(PNTRA),MADRID(PNTRC),NPIXB(1))
347
C check for 3-dim case
349
IF (PLANES(1).EQ.-1) THEN
350
IF (DIM3C.GT.NPIXA(3)) THEN
356
IF (PLANES(DIM3C).EQ.0) THEN
359
IF ((PLANES(DIM3C).LE.0).OR.(PLANES(DIM3C).GT.NPIXA(3)))
360
+ CALL STETER(6,'specified plane outside limits... ')
361
KZ = PLANES(DIM3C) - PLANES(DIM3C-1)
364
PNTRA = PNTRA + (NPIXA(1)*NPIXA(2))*KZ
365
PNTRC = PNTRC + (NPIXC(1) * (NPIXC(2) + KDIFF))
368
9000 CALL STDWRR(IMNOC,'LHCUTS',CUTS,1,4,UNI,STAT)
372
SUBROUTINE ROTA1(X,Y,AC,AS,XOUT,YOUT)
376
REAL X,Y,AC,AS,XOUT,YOUT
384
SUBROUTINE KPERSP(A,B,NPIXA,NPIXB,AC)
388
C do "backward" perspective
395
INTEGER INDXB,KSTX,KY
397
INTEGER NX,NY,SIZEA,XDIMA,YDIMA
398
INTEGER NPIXA(2),NPIXB(2)
403
DOUBLE PRECISION RYAC,ACINV
408
SIZEA = XDIMA * YDIMA
414
C loop through result lines
415
DO 3000, NY=1,NPIXB(2)
416
DO 1000, NX=1,NPIXB(1)
417
INDXB = INDXB + 1 !loop along result line
419
KSTX = XDIMA*KY !get 1. pixel in this line - 1
420
NO1 = NX + KSTX !get pixel close to integer part of
421
NO3 = NO1 + XDIMA !get low pixel in next line up
422
IF (NO3.GT.SIZEA) THEN !are we out of grid in y?
426
B(INDXB) = A(NO1) + (YFRAC * (A(NO3) - A(NO1)))
435
SUBROUTINE JPERSP(A,B,NPIXA,NPIXB,AC,ZNULL,FMINMA,ISCAL)
438
C do "backward" z-perspective
443
C Z = YPERS * ISCAL => XPERS,YPERS+n = Z
444
C XPERS,YPERS+n-1 = ...
450
INTEGER INDXB,KSTX,KY,ISCAL
452
INTEGER NX,NY,SIZEA,XDIMA,YDIMA,XDIMB
453
INTEGER NPIXA(2),NPIXB(2)
454
INTEGER KSCAL,IZ,KNDXB,KK
457
REAL AC,FMINMA(2),ZNULL
459
REAL Z,DZ,SCALF,CMIN,FF
462
DOUBLE PRECISION RYAC,ACINV
467
SIZEA = XDIMA * YDIMA
473
INDXB = NPIXB(1)*NPIXB(2)
475
SCALF = KSCAL / (RMAX-RMIN)
477
KK = NPIXB(2)-ISCAL !reserved space for spikes of last line
479
C loop through result lines
480
DO 300, NY=NPIXB(2),KK+1,-1
483
INDXB = INDXB - 1 !loop along result line
492
KSTX = XDIMA*KY !get 1. pixel in this line - 1
493
NO1 = NX + KSTX !get pixel close to integer part of
494
NO3 = NO1 + XDIMA !get low pixel in next line up
495
IF (NO3.GT.SIZEA) THEN !are we out of grid in y?
499
Z = A(NO1) + (YFRAC * (A(NO3) - A(NO1)))
501
IF (Z .GT. RMAX) Z = RMAX
503
C get height from intensity
509
KNDXB = INDXB + XDIMB
514
KNDXB = KNDXB + XDIMB
520
INDXB = INDXB - 1 !loop along result line
526
C get rid of superfluous lines in the end
527
INDXB = NPIXB(1)*NPIXB(2)
528
DO 4000, NY=NPIXB(2),KK+1,-1
530
IF (B(INDXB) .GT. ZNULL) THEN
541
SUBROUTINE ROTA2(A,B,NPIXA,NPIXB,START,AC,AS,ZNULL)
543
C K. Banse 861029, 880902, 910204
545
C do "backward" rotation, i.e. solve the system XROT = X*AC - Y*AS
546
C YROT = X*AS + Y*AC for X,Y
547
C to yield X = XROT*AC + YROT*AS
548
C Y = YROT*AC - XROT*AS which takes AC**2 + AS**2 = 1 into account....
552
INTEGER INDXB,KX,KY,KSTX
553
INTEGER NO1,NO2,NO3,NO4
554
INTEGER NX,NY,SIZEA,XDIMA,YDIMA
555
INTEGER NPIXA(2),NPIXB(2)
559
REAL XT,YT,XFRAC,YFRAC,XLAST,YLAST
562
DOUBLE PRECISION START(2)
563
DOUBLE PRECISION RYAC,RYAS
571
SIZEA = XDIMA * YDIMA
574
RYAS = START(2) * AS !init RYAS,RYAC according to start-y
577
C loop through result lines
578
DO 3000, NY=1,NPIXB(2)
579
RX = XF !init RX to start-x
581
DO 1000, NX=1,NPIXB(1)
582
INDXB = INDXB + 1 !loop along result line
584
IF ((XT.LT.0.).OR.(XT.GT.XLAST)) THEN
589
IF ((YT.LT.0.).OR.(YT.GT.YLAST)) THEN
595
XT = XT + 1. !adjust 0,0 to 1,1 ...
599
KSTX = XDIMA*(KY-1) !get 1. pixel in this line - 1
600
NO1 = KX + KSTX !get pixel close to int. part of real pixel
602
NO2 = NO1 + 1 !get next pixel in x-direction
603
CC IF ((NO2-KSTX).GT.XDIMA) THEN !are we out of grid in x?
604
IF (KX.GE.XDIMA) THEN !are we out of grid in x?
605
IF (NO2.GT.SIZEA) THEN !also out in y?
606
B(INDXB) = A(NO1) !yes.
608
NO3 = NO1 + XDIMA !no.
610
B(INDXB) = A(NO1) + ( YFRAC * (A(NO3) - A(NO1)) )
614
NO3 = NO1 + XDIMA !get low pixel in next line up
615
IF (NO3.GT.SIZEA) THEN !are we out of grid in y?
616
B(INDXB) = A(NO1) + ( XFRAC * (A(NO2) - A(NO1)) )
621
+ XFRAC * (A(NO2) - A(NO1)) +
622
+ YFRAC * (A(NO3) - A(NO1)) +
623
+ XFRAC * YFRAC * (A(NO1) - A(NO2) - A(NO3) + A(NO4))
627
1000 RX = RX + 1.0 !move to next x-coord
629
RYAS = RYAS + AS !move to next y-coord.