三參數坐標轉換 Helmert Transformation

 三參數坐標轉換

多年前寫的坐標轉換程式,上週同學告知有bug,當年是以Lahey Fortran編寫程式碼,沒想到Lahey公司2022年底宣布關門,頓時不知如何面對江東父老。

高階語言最麻煩的是處理Unicode,如果編譯器不支援就只能以英文I/O。想破頭兩星期終於找到出路。

       PROGRAM HELMERT3B
!      =========================================================
!      = Modify 2000.12.30 固定輸出入檔案之檔名                                                   =
!      =        2001.5.24  修改計算模式                                                                          =
!      =        90.05.29.  修改轉換參數之輸出有效位數(蕭欽霖之貢獻)                    =
!      =        90.10.14.  輸出轉換參數值, 以供AutoCAD程式使用                            =
!      =        91.05.09.  修改不符值輸出順序錯誤                                                      =
!      =        2004.12.15 compiled by Lahey Fortran 95  for Windows XP                  =
!      =        2014.01.28 將旋轉中心(0,0)移至測區中央                                            =
!      =                   適用於兩坐標系統均為二度分帶系統                                       =
!      =        2023.02.19 修正度分秒副程式之bug                                                     =
!      =                   以GNU Fortran Compile                                                              =
!      ========================================================
       IMPLICIT REAL(8)(A-H,O-Z)
       REAL(8) XF,YF,XI,YI
       CHARACTER INFILE*60,OUTFILE*60,CORFILE*60,JOB*70,PARFILE*60
       CHARACTER*10 NAME,PNAME
       INTEGER idt(8)
       CHARACTER*10 date,time,zone
       COMMON AVEX1,AVEY1,AVEX2,AVEY2
!      CALL GETDAT(IYEAR,IMONTH,IDAY)
!      CALL GETTIM(IHOUR,IMIN,ISEC,I100H)
       CALL date_and_time(date,time,zone,idt)
       WRITE(*,1000)
 1000  FORMAT(20X,'***************************************'/&
              20X,'*      HELMERT 三參數相似轉換         *'/&
      20X,'*        形心對形心坐標轉換                   *'/&
              20X,'*      compiler GNU Fortran 95               *'/&
      20X,'*        program by ChinaTom                  *'/& 
              20X,'*        Version 3.0  2023.5.                      *'/&
              20X,'***************************************')
       WRITE(*,1002)
 1002  FORMAT(/10X,'本程式適用於兩坐標系統均為二度分帶系統,且將旋轉中心'&
                   '(0,0)移至測區中央')
       WRITE(*,1010)
 1010  FORMAT(/10X,'輸入資料檔名 <<主檔名即可>>: '$)
       READ(*,1020) INFILE
 1020  FORMAT(A60)
       NN=LEN_TRIM(INFILE)
       ICHK=INDEX(INFILE,'.')
       IF(ICHK.NE.0) THEN
          WRITE(*,1030)
 1030     FORMAT(/10X,'<< 輸入錯誤 : 檔名中含附加檔名 >> 程式中止!')
!         PAUSE '            程式中止! 按 ENTER 鍵離開'
          STOP
       END IF
       OUTFILE=INFILE
       CORFILE=INFILE
       PARFILE=INFILE
       INFILE(NN+1:NN+4)= '.DAT'
       OUTFILE(NN+1:NN+4)='.DOC'
       CORFILE(NN+1:NN+4)='.COD'
       PARFILE(NN+1:NN+4)='.PA3'
       OPEN(1,FILE=INFILE,STATUS='OLD',IOSTAT=ICHK)
!      IF(ICHK.EQ.6416) THEN
       IF(ICHK.GT.0) THEN
          WRITE(*,1040) INFILE
 1040     FORMAT(/10X,'<<錯誤>> : 找不到資料檔 ',A,'  程式中止!')
!         PAUSE '                 程式中止! 按 ENTER 鍵離開'
          STOP
       END IF
       OPEN(2,FILE=OUTFILE,STATUS='UNKNOWN')
       OPEN(3,FILE=CORFILE,STATUS='UNKNOWN')
       OPEN(4,FILE='AA.TMP',STATUS='UNKNOWN',FORM='UNFORMATTED')
       OPEN(5,FILE='BB.TMP',STATUS='UNKNOWN',FORM='UNFORMATTED')
       OPEN(8,FILE=PARFILE,STATUS='UNKNOWN')
       WRITE(2,1000)
       NUM=1
       NUMRJ=0
       READ(1,'(A70)') JOB
   10  READ(1,1050,END=20) IC,NAME,YI,XI,YF,XF
 1050  FORMAT(I5,A10,4F15.0)
!      =============================================================
!      =  IC    : >0 POINT NOT USED, =-99 END OF CONTROL POINTS    =
!      =  NAME  : POINT NAME                                       =
!      =  XI,YI : (X,Y) OF ORIGINAL COORDS. SYSTEM                 =
!      =  XF,YF : (X,Y) OF DESTINATION COORDS. SYSTEM              =
!      =============================================================
       IF(IC.GT.0) THEN
         WRITE(5) NAME,XI,YI,XF,YF
         NUMRJ=NUMRJ+1
         GOTO 10
       END IF
       IF(IC.EQ.-99) GOTO 20
       WRITE(4) NAME,XI,YI,XF,YF
       NUM=NUM+1
       GOTO 10
   20  NUM=NUM-1
       IF(NUM.LE.1) THEN
         WRITE(*,1060)
 1060    FORMAT(//10X,'錯誤:控制點點數少於 2點 !')
         STOP
       END IF
       WRITE(2,1070) TRIM(JOB)
 1070  FORMAT(/5X,'資料名稱 : ',A)
       WRITE(2,1080) TRIM(INFILE)
 1080  FORMAT( 5X,'檔案名稱 : ',A)
!      WRITE(2,1090) IYEAR,IMONTH,IDAY,IHOUR,IMIN
!1090  FORMAT( 5X,'計算日期時間 : ',I4,'/',I2,'/',I2,2X,I2,':',I2)
       WRITE(2,1090) IDT(1),IDT(2),IDT(3),IDT(5),IDT(6),IDT(7)
 1090  FORMAT(5X,'計算日期 : ',I4,'/',I2,'/',I2,4X,'時間: ',I2,':',I2,':',I2)
       IF(NUMRJ.NE.0) THEN
         REWIND 5
         WRITE(2,1100)
 1100    FORMAT(/1X,'[未加入轉換之已知坐標點位]'/&
              11X,'點 名',11X,'轉換前(N,E)坐標',12X,'轉換後(N,E)坐標'/&
               3X,72(1H=))
         DO 22 I=1,NUMRJ
         READ(5) NAME,XI,YI,XF,YF
         WRITE(2,1110) I,NAME,YI,XI,YF,XF
 1110    FORMAT(4X,I3,3X,A10,2(3X,F11.3,2X,F11.3))
   22    CONTINUE
       END IF
       CALL PARA3(X04,Y04,ANG4,NUM)
!      IF(EOF(1)) GOTO 40
       WRITE(*,1120)
       WRITE(2,1120)
 1120  FORMAT(//1X,'[未 知 點 轉 換 成 果]'/&
               11X,'點 名',11X,'轉換前(N,E)坐標',12X,'轉換後(N,E)坐標'/&
               8X,67(1H=))
   30  READ(1,1130,END=40) IC,PNAME,Y,X
 1130  FORMAT(I5,A10,2F15.0)
       IF(IC.GT.0) GOTO 30
       CALL TR3(X,Y,X04,Y04,ANG4,XX,YY)
       WRITE(*,1140) PNAME,Y,X,YY,XX
       WRITE(2,1140) PNAME,Y,X,YY,XX
 1140  FORMAT(10X,A10,2(3X,F11.3,2X,F11.3))
       WRITE(3,1150) PNAME,YY,XX
 1150  FORMAT(A10,2F15.3)
       GOTO 30
   40  CONTINUE
       CLOSE(4,STATUS='DELETE')
       CLOSE(5,STATUS='DELETE')
   CLOSE(8)
       END
       SUBROUTINE PARA3(X0,Y0,ANG,NUM)
!      ===========================================================
!      =      PROGRAM :  3-PARAMETER TRANSFORMATION              =
!      =        (X,Y)-SHIFT, ROTATION                            =
!      =---------------------------------------------------------=
!      =      X2=X1*COS(ang)-Y1*SIN(ang)+X0                      =
!      =      Y2=X1*SIN(ang)+Y1*COS(ang)+Y0                      =
!      ===========================================================
       IMPLICIT REAL(8)(A-H,O-Z)
       REAL(8) N(6),U(3)
       CHARACTER SIGN*1,NAME*10
       DATA IFL3/4/
       COMMON AVE_X,AVE_Y
       SIGN='+'
       PI=4.D0*DATAN(1.D0)
       ANG=0.
       X0=0.
       Y0=0.
       AVE_X=0.
       AVE_Y=0.
       REWIND IFL3
!      === 求第一坐標系統之形心位置
       DO I=1,NUM
       READ(IFL3) NAME,X1,Y1,X2,Y2
       AVE_X=AVE_X+X1
       AVE_Y=AVE_Y+Y1
       END DO
       AVE_X=AVE_X/NUM
       AVE_Y=AVE_Y/NUM
       WRITE(*,900) AVE_Y,AVE_X
       WRITE(2,900) AVE_Y,AVE_X
  900  FORMAT(/10X,'旋轉中心坐標',2X,'AVE_N=',F13.3,5X,'AVE_E=',F13.3)
       DO 40 ITER=1,20
!      WRITE(*,1004) ITER
 1004  FORMAT(/2X,'#### ITERATION  ',I2,' #### ')
       DO 10 I=1,6
       N(I)=0.
  10   CONTINUE
       DO 20 I=1,3
       U(I)=0.
  20   CONTINUE
!      === 法方程式 Normal Equations
       REWIND IFL3
       DO 30 I=1,NUM
       READ(IFL3) NAME,X1,Y1,X2,Y2
       A1=-(X1-AVE_X)*DSIN(ANG)-(Y1-AVE_Y)*DCOS(ANG)
       A2= (X1-AVE_X)*DCOS(ANG)-(Y1-AVE_Y)*DSIN(ANG)
       N(1)=N(1)+A1*A1+A2*A2
       N(2)=N(2)+A1
       N(3)=N(3)+1.0
       N(4)=N(4)+A2
       N(6)=N(6)+1.0
       B1=(X2-AVE_X)-(X1-AVE_X)*DCOS(ANG)+(Y1-AVE_Y)*DSIN(ANG)-X0
       B2=(Y2-AVE_Y)-(X1-AVE_X)*DSIN(ANG)-(Y1-AVE_Y)*DCOS(ANG)-Y0
       U(1)=U(1)+A1*B1+A2*B2
       U(2)=U(2)+B1
       U(3)=U(3)+B2
  30   CONTINUE
       CALL SINV(N,3,1.D-9,IER)
!      WRITE(*,1002) IER
 1002  FORMAT(2X,'IER=',I2)
       IF(IER.EQ.-1) THEN
         WRITE(*,1200)
 1200    FORMAT(//10X,'錯誤 : 法係數矩陣奇異解(singular) ! 程式終止 !')
         STOP
       END IF
!      WRITE(*,1000) N(1),N(2),N(4),N(3),N(5),N(6)
 1000  FORMAT(/5X,'INVERSE OF NORMAL EQ.'/&
              8X,3(E14.8,2X)/24X,2(E14.8,2X)/40X,1(E14.8,2X))
       COEF1=N(2)/DSQRT(N(1)*N(3))
       COEF2=N(4)/DSQRT(N(1)*N(6))
       COEF3=N(5)/DSQRT(N(3)*N(6))
!      WRITE(*,1010) 1.,COEF1,COEF2,1.,COEF3,1.
 1010  FORMAT(/5X,'法係數矩陣之相關係數 CORRELATION COEFFICIENT'/&
               8X,3(E14.8,2X)/24X,2(E14.8,2X)/40X,1(E14.8,2X))
       DANG=N(1)*U(1)+N(2)*U(2)+N(4)*U(3)
       DX0 =N(2)*U(1)+N(3)*U(2)+N(5)*U(3)
       DY0 =N(4)*U(1)+N(5)*U(2)+N(6)*U(3)
       ANG=ANG+DANG
       X0=X0+DX0
       Y0=Y0+DY0
!      IF(DABS(DANG).LE.1.D-6) GOTO 50
!      IF((DABS(DANG).LE.(0.00001/206265.D0)).AND.(DABS(DX0).LE.0.0001)
!    $   .AND.(DABS(DY0).LE.0.0001)) GOTO 50
   40  CONTINUE
   50  PVV=0.
       REWIND IFL3
       WRITE(*,1020)
       WRITE(2,1020)
 1020  FORMAT(/1x,'[控 制 點 轉 換 平 差 成 果]'/&
               5X,'點   名',8X,'轉換前(N,E)坐標',9X,'轉換後(N,E)坐標',&
               7X,'不符值(dN,dE)'/80(1H=))
       DO 60 I=1,NUM
       READ(IFL3) NAME,X1,Y1,X2,Y2
       VX=(X1-AVE_X)*DCOS(ANG)-(Y1-AVE_Y)*DSIN(ANG)+X0-(X2-AVE_X)
       VY=(X1-AVE_X)*DSIN(ANG)+(Y1-AVE_Y)*DCOS(ANG)+Y0-(Y2-AVE_Y)
       WRITE(*,1030) I,NAME,Y1,X1,Y2,X2,VY,VX
       WRITE(2,1030) I,NAME,Y1,X1,Y2,X2,VY,VX
 1030  FORMAT(I3,2X,A10,2(2X,F11.3,1X,F10.3),2X,F7.3,1X,F7.3)
       PVV=PVV+VX*VX+VY*VY
   60  CONTINUE
       IDF=2*NUM-3
       IF(IDF.EQ.0) THEN
          SIGMA=0.
       ELSE
          SIGMA=DSQRT(PVV/IDF)
          SA=SIGMA*DSQRT(N(1))
          SB=SIGMA*DSQRT(N(3))
          SC=SIGMA*DSQRT(N(6))
          TANG=ABS(ANG/SA)
          TX0=ABS(X0/SB)
          TY0=ABS(Y0/SC)
       END IF
       CALL DEGREE(ANG,IDEG,MIN,SEC)
       IF(ANG.LT.0.) SIGN='-'
       WRITE(*,1040) SIGN,ABS(IDEG),MIN,SEC,SA,TANG,Y0,SC,TY0,&
                     X0,SB,TX0,SIGMA,ITER-1,IDF
       WRITE(2,1040) SIGN,ABS(IDEG),MIN,SEC,SA,TANG,Y0,SC,TY0,&
                     X0,SB,TX0,SIGMA,ITER-1,IDF
 1040  FORMAT(/10X,'旋轉量   = ',A1,I3,'d',I2,'m',F8.5,'s',&
            2X,'中誤差=',E10.4,2X,'t=',E8.2/&
            10X,'N軸平移量= ',F17.4,2X,'中誤差=',E10.4,2X,'t=',E8.2/&
            10X,'E軸平移量= ',F17.4,2X,'中誤差=',E10.4,2X,'t=',E8.2/&
            10X,'單位權中誤差=',F8.5,9X,'漸近次數=',I3,7X,'自由度=',I5)
       WRITE(2,1050) 1.,COEF1,COEF2,1.,COEF3,1.
 1050  FORMAT(/10X,'法係數矩陣之相關係數Correlation Coefficient Matrix'/&
               10x,'rotation',8X,3(E10.4,2X)/&
               10x,'x0      ',20X,2(E10.4,2X)/&
               10x,'y0      ',32X,1(E10.4,2X))
       WRITE(8,*) AVE_Y
       WRITE(8,*) AVE_X
       WRITE(8,*) (ANG*180.d0/pi)
       WRITE(8,*) X0
       WRITE(8,*) Y0
       RETURN
       END
       SUBROUTINE TR3(X,Y,X0,Y0,ANG,XX,YY)
       IMPLICIT REAL(8) (A-H,O-Z)
       COMMON AVE_X,AVE_Y
       XX=(X-AVE_X)*DCOS(ANG)-(Y-AVE_Y)*DSIN(ANG)+X0+AVE_X
       YY=(X-AVE_X)*DSIN(ANG)+(Y-AVE_Y)*DCOS(ANG)+Y0+AVE_Y
       RETURN
       END
       SUBROUTINE DEGREE(RAD,IDEG,MIN,SEC)
!      ================================================================
!      =  PROGRAM : TRANSFORM RADIAN TO DEGREE-MINUTE-SECOND          =
!      = modify PI  2023.5.12                                         =
!      = 更正 IF(KEY.EQ.1) IDEG=-IDEG 位置                            =
!      ================================================================
       IMPLICIT REAL(8) (A-H,O-Z)
!      PI=0.31415926536D01
       PI=4.D0*DATAN(1.D0)
   KEY=0
       DEG=RAD*180.D0/PI
       IF(DEG.LT.0.) THEN
          DEG=-DEG
          KEY=1
       END IF
       IDEG=INT(DEG)
       SMIN=(DEG-IDEG)*60.D0
       MIN=INT(SMIN)
       SEC=(SMIN-MIN)*60.D0
   IF(KEY.EQ.1) IDEG=-IDEG
       RETURN
       END
       
       SUBROUTINE SINV(A,N,EPS,IER)
       IMPLICIT REAL(8) (A-H,O-Z)
       REAL(8)  A(1),DIN,WORK,DPIV,DSUM
       IF(N-1) 12,1,1
  1    IER=0
       KPIV=0
       DO 11 K=1,N
       KPIV=KPIV+K
       IND=KPIV
       LEND=K-1
       TOL=DABS(EPS*(A(KPIV)))
       DO 11 I=K,N
       DSUM=0.D0
       IF(LEND) 2,4,2
  2    DO 3 L=1,LEND
       LANF=KPIV-L
       LIND=IND-L
  3    DSUM=DSUM+(A(LANF)*A(LIND))
  4    DSUM=A(IND)-DSUM
       IF(I-K) 10,5,10
  5    IF(DSUM-TOL) 6,6,9
  6    IF(DSUM) 12,12,7
  7    IF(IER) 8,8,9
  8    IER=K-1
  9    DPIV=DSQRT(DSUM)
       A(KPIV)=DPIV
       DPIV=1.0/DPIV
       GO TO 11
 10    A(IND)=DSUM*DPIV
 11    IND=IND+I
       GO TO 13
 12    IER=-1
 13    IF(IER) 22,14,14
 14    IPIV=N*(N+1)/2
       IND=IPIV
       DO 19 I=1,N
       DIN=1.0/A(IPIV)
       A(IPIV)=DIN
       MIN=N
       KEND=I-1
       LANF=N-KEND
       IF(KEND) 18,18,15
 15    J=IND
       DO 17 K=1,KEND
       WORK=0.0
       MIN=MIN-1
       LHOR=IPIV
       LVER=J
       DO 16 L=LANF,MIN
       LVER=LVER+1
       LHOR=LHOR+L
 16    WORK=WORK+(A(LVER)*A(LHOR))
       A(J)=-WORK*DIN
 17    J=J-MIN
 18    IPIV=IPIV-MIN
 19    IND=IND-1
       DO 21 I=1,N
       IPIV=IPIV+I
       J=IPIV
       DO 21 K=I,N
       WORK=0.0
       LHOR=J
       DO 20 L=K,N
       LVER=LHOR+K-I
       WORK=WORK+(A(LHOR)*A(LVER))
 20    LHOR=LHOR+L
       A(J)=WORK
 21    J=J+K
 22    RETURN
       END

留言

這個網誌中的熱門文章

測量平差法概論