fortran66のブログ

fortran について書きます。

奥村晴彦著『C言語による 最新 アルゴリズム事典』の「フラクタルによる画像圧縮」を移植してみました。羊歯植物のパラメータを入れています。



この本のルーチンと互換性を上げるために、uhoplotに少しサブルーチンを加えました。

MODULE plotter
USE uhoplot
IMPLICIT NONE
REAL :: xpen = 0.0, ypen = 0.0
CONTAINS
!----------------------------------------------------------------
SUBROUTINE move(x, y)
IMPLICIT NONE
REAL, INTENT(IN) :: x, y
xpen = x
ypen = y
RETURN
END SUBROUTINE move
!----------------------------------------------------------------
SUBROUTINE move_rel(dx, dy)
IMPLICIT NONE
REAL, INTENT(IN) :: dx, dy
xpen = xpen + dx
ypen = ypen + dy
RETURN
END SUBROUTINE move_rel
!----------------------------------------------------------------
SUBROUTINE draw(x, y)
IMPLICIT NONE
REAL, INTENT(IN) :: x, y
CALL gr_wmove(xpen, ypen)
CALL gr_wline(x   , y   )
xpen = x
ypen = y
CALL gr_show()
RETURN
END SUBROUTINE draw
!----------------------------------------------------------------
SUBROUTINE draw_rel(dx, dy)
IMPLICIT NONE
REAL, INTENT(IN) :: dx, dy
CALL gr_wmove(xpen, ypen)
CALL gr_wline(xpen + dx, ypen + dy)
xpen = xpen + dx
ypen = ypen + dy
CALL gr_show()
RETURN
END SUBROUTINE draw_rel
!----------------------------------------------------------------
END MODULE plotter
!================================================================
PROGRAM fern
USE plotter
INTEGER, PARAMETER :: n = 4, m = n * 25
REAL :: a(4) = (/ 0.0 ,  0.85,  0.20, -0.15 /)
REAL :: b(4) = (/ 0.0 ,  0.04, -0.26,  0.28 /)
REAL :: c(4) = (/ 0.0 , -0.04,  0.23,  0.26 /)
REAL :: d(4) = (/ 0.16,  0.85,  0.22,  0.24 /)
REAL :: e(4) = (/ 0.0 ,  0.0 ,  0.0 ,  0.0  /)
REAL :: f(4) = (/ 0.0 ,  1.6 ,  1.6 ,  0.44 /)
INTEGER :: i, j, k, ir, ip(n), itable(m)
REAL :: x, y, s, t, p(n)
s = 0.0
DO i = 1, n
 p(i) = MAX(0.01, ABS( a(i) * d(i) - b(i) * c(i) ))
 s = s + p(i)
 ip(i) = i
END DO
DO i = 1, n - 1
 k = i
 DO j = i + 1, n
  IF ( p(j) < p(k) ) k = j
 END DO
 t    = p(i)
 p(i) = p(k)
 p(k) = t
 ir    = ip(i)
 ip(i) = ip(k)
 ip(k) = ir
END DO
ir = m

DO i = 1, n
 k = INT(ir * p(i) / s + 0.5)  
 s = s - p(i)
 DO WHILE ( k > 0 )
  itable(ir) = ip(i)
  k  = k  - 1
  ir = ir - 1
 END DO
END DO
CALL gr_on('fern', 640, 480)
CALL gr_axis(-5.0, 5.0, 0.0, 10.0)
x = 0.0
y = 0.0
DO i = 1, 300000
 CALL RANDOM_NUMBER(s)
 j = itable(INT(m * s) + 1)
 t = a(j) * x + b(j) * y + e(j)
 y = c(j) * x + d(j) * y + f(j)
 x = t
 IF (i > 10) CALL gr_wdot(x, y, irgb(0, 0, 0)) 
END DO
CALL gr_off()
STOP
END PROGRAM fern

uhoplot修正版
モジュール uhoplot の終わりのほうに、gr_axis, to_ixy, gr_wdot, gr_wmove, gr_wline の5つのサブルーチンを加えました。

ちなみに uhoplot は、USE ifwinXXX 等の win32 関連のモジュールの USE ifxxxx を USE dfxxxx に書き換えることで、Compaq Visual Fortran Ver6.6 でも動作します。

MODULE uho_win
USE ifwina
USE ifwinty
USE ifmt, ONLY : RTL_CRITICAL_SECTION
IMPLICIT NONE
TYPE :: t_wnd
 INTEGER (HANDLE) :: hWnd
 INTEGER (HANDLE) :: hDC
 INTEGER (LPINT)  :: hThread
 INTEGER          :: id
 INTEGER (HANDLE) :: hPen
 CHARACTER (LEN = 80) :: title = 'Fortran Plot'
 INTEGER          :: nsize_x = 320, nsize_y = 240  
 REAL             :: xmin = 0.0, xmax = 1.0, ymin = 0.0, ymax = 1.0   
END TYPE
TYPE (t_wnd) :: wnd
TYPE (RTL_CRITICAL_SECTION) :: lpCriticalSection
CONTAINS
!----------------------------------------------------------------
INTEGER FUNCTION WinMain( hInstance, hPrevInstance, lpszCmdLine, nCmdShow, wnd)
IMPLICIT NONE
INTEGER (HANDLE), INTENT(IN) :: hInstance, hPrevInstance 
INTEGER (LPSTR) , INTENT(IN) :: lpszCmdLine
INTEGER (SINT)  , INTENT(IN) :: nCmdShow
TYPE (t_wnd)    , INTENT(IN OUT) :: wnd
! Variables
LOGICAL, SAVE :: qfirst = .TRUE.
TYPE (T_WNDCLASS) :: wc
TYPE (T_MSG)      :: mesg
INTEGER (HANDLE)  :: hWndMain
INTEGER (BOOL)    :: iretb
CHARACTER (LEN = 256) :: ClassName = "Fortran"C
INTEGER :: noffset_x, noffset_y !side line = 6, title bar = 25
!  Init   Main window
noffset_x = 2 * GetSystemMetrics(SM_CXFIXEDFRAME)
noffset_y = 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION)
!
WinMain = -1 ! Error code 
IF (qfirst) THEN
wc%lpszClassName = LOC(ClassName)
wc%lpfnWndProc   = LOC(MainWndProc)               ! CALL BACK procedure name
wc%style         = IOR(CS_VREDRAW , CS_HREDRAW)
wc%hInstance     = hInstance
wc%hIcon         = NULL   
wc%hCursor       = LoadCursor( NULL, IDC_ARROW )
wc%hbrBackground = ( COLOR_WINDOW + 1 )
IF (RegisterClass(wc) == 0) RETURN
qfirst = .FALSE.
END IF
!Init instance
WinMain = -2 ! Error code 
hWndMain = CreateWindowEx(  0, ClassName,                        &
                               TRIM(wnd%title)//''C,             &
                               INT(IOR(WS_OVERLAPPED, WS_SYSMENU)), &
                               CW_USEDEFAULT, CW_USEDEFAULT,     &
                               wnd%nsize_x + noffset_x,          &
                               wnd%nsize_y + noffset_y,          &
                               0,                                &
                               0,                                &
                               hInstance,                        &
                               LOC(wnd)                           )
IF (hWndMain == 0) RETURN
iretb = ShowWindow( hWndMain, nCmdShow )
iretb = UpdateWindow( hWndMain )
! Message Loop
DO WHILE ( GetMessage (mesg, NULL, 0, 0) ) 
 iretb = TranslateMessage( mesg )
 iretb = DispatchMessage(  mesg )
END DO
WinMain = mesg%wParam
RETURN
END FUNCTION WinMain
!----------------------------------------------------------------
INTEGER*4 FUNCTION MainWndProc( hWnd, mesg, wParam, lParam ) 
!DEC$ ATTRIBUTES STDCALL, DECORATE, ALIAS : 'MainWndProc' :: MainWndProc
USE IFMT
IMPLICIT NONE
INTEGER (HANDLE) , INTENT(IN) :: hWnd
INTEGER (UINT)   , INTENT(IN) :: mesg
INTEGER (fwParam), INTENT(IN) :: wParam
INTEGER (flParam), INTENT(IN) :: lParam
!
INTEGER (HANDLE) :: hDC, hBmp
INTEGER (BOOL)   :: iretb
TYPE (T_PAINTSTRUCT)  :: ps
TYPE (T_RECT)         :: rc
!
MainWndProc = 0
SELECT CASE ( mesg )
   CASE (WM_CREATE)
     hDC      = GetDC(hWnd)
     iretb    = GetClientRect(hWnd, rc)
     hBmp     = CreateCompatibleBitmap(hDC, rc%right - rc%left, rc%bottom - rc%top)
     wnd%hWnd = hWnd
     wnd%hDC  = CreateCompatibleDC(hDC)
     iretb    = SelectObject(wnd%hDC, hBmp)
     iretb    = PatBlt(wnd%hDC, 0, 0, rc%right - rc%left, rc%bottom - rc%top, WHITENESS)
     iretb    = ReleaseDC(hWnd, hDC)
     iretb    = DeleteObject(hBmp)
   CASE (WM_DESTROY)
     iretb = DeleteObject( wnd%hDC )
     CALL PostQuitMessage( 0 )
   CASE (WM_PAINT)
     CALL EnterCriticalSection(LOC(lpCriticalSection))
     hDC    = BeginPaint(    wnd%hWnd, ps )
     iretb  = GetClientRect( wnd%hWnd, rc )
     iretb  = BitBlt(hDC, 0, 0, rc%right  - rc%left, rc%bottom - rc%top, wnd%hDC, 0, 0, SRCCOPY)
     iretb  = EndPaint( wnd%hWnd, ps )
     CALL LeaveCriticalSection(LOC(lpCriticalSection))
   CASE (WM_LBUTTONDOWN)
     WRITE(*, *) 'LBUTTON ', TRIM(wnd%title), wnd%hWnd
   CASE (WM_RBUTTONDOWN)
     WRITE(*, *) 'RBUTTON ', TRIM(wnd%title), wnd%hWnd
   CASE DEFAULT
     MainWndProc = DefWindowProc( hWnd, mesg, wParam, lParam )
END SELECT 
RETURN
END FUNCTION MainWndProc
!----------------------------------------------------------------
END MODULE uho_win
!================================================================
MODULE uhoplot
USE uho_win
CONTAINS
!----------------------------------------------------------------
INTEGER (HANDLE) FUNCTION get_DosHndl()
IMPLICIT NONE
INTERFACE
 FUNCTION GetConsoleWindow() ! non-existent in IFORTxx.MOD
 USE ifwinty
 INTEGER (HANDLE) :: GetConsoleWindow
 !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'GetConsoleWindow' :: GetConsoleWindow
 END FUNCTION
END INTERFACE
get_DosHndl = GetConsoleWindow()
RETURN
END FUNCTION get_DosHndl
!----------------------------------------------------------------
SUBROUTINE gr_on(text, nx, ny)
USE IFMT ! multithread module
IMPLICIT NONE
CHARACTER (LEN = *), INTENT(IN), OPTIONAL :: text
INTEGER            , INTENT(IN), OPTIONAL :: nx, ny
INTEGER (BOOL)    :: iretb
INTEGER (HANDLE)  :: hBmp
INTEGER (LPDWORD) :: id
TYPE (T_RECT)    :: rc
IF (PRESENT(text)) wnd%title = TRIM(text)
IF (PRESENT(nx)  ) wnd%nsize_x = nx
IF (PRESENT(ny)  ) wnd%nsize_y = ny
CALL InitializeCriticalSection(LOC(lpCriticalSection))
wnd%hThread = CreateThread(0, 0, Thread_Proc, LOC(wnd), CREATE_SUSPENDED, id)
wnd%id      = id
iretb       = SetThreadPriority(wnd%hThread, THREAD_PRIORITY_BELOW_NORMAL)
iretb       = ResumeThread(wnd%hThread)
CALL Sleep(100) ! wait for Window initialization 
iretb = GetClientRect(wnd%hWnd, rc)
hBmp  = CreateCompatibleBitmap(wnd%hDC, rc%right - rc%left, rc%bottom - rc%top)
iretb = SelectObject(wnd%hDC, hBmp)
iretb = DeleteObject(hBmp)
iretb = PatBlt(wnd%hDC, 0, 0, rc%right - rc%left, rc%bottom - rc%top, WHITENESS)
wnd%hPen = CreatePen(PS_SOLID, 1, 0)
RETURN
END SUBROUTINE gr_on
!----------------------------------------------------------------
SUBROUTINE gr_off(isec)
USE IFMT ! Module for multithread
IMPLICIT NONE
INTEGER (DWORD), INTENT(IN), OPTIONAL :: isec 
INTEGER (BOOL)  :: iretb
INTEGER (DWORD) :: iwait
IF (PRESENT(isec)) THEN
 iwait = isec * 1000
ELSE
 iwait = INFINITE
END IF 
CALL gr_show() ! 
iretb = DeleteObject(wnd%hPen) 
iretb = WaitForSingleObject(wnd%hThread, iwait)
iretb = CloseHandle(wnd%hThread)
iretb = PostMessage(wnd%hWnd, WM_DESTROY, NULL, NULL)
wnd%hThread = NULL
CALL DeleteCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_off
!----------------------------------------------------------------
INTEGER (LONG) FUNCTION Thread_Proc(lp_ThreadParameter)
!DEC$ ATTRIBUTES STDCALL, ALIAS:"_thread_proc" :: Thread_Proc
IMPLICIT NONE
INTEGER (LPINT), INTENT(IN) :: lp_ThreadParameter
INTEGER :: hInst
TYPE (t_wnd) :: wnd
POINTER (p_wnd, wnd) ! non-standard fortran
p_wnd       = lp_ThreadParameter
hInst       = GetModuleHandle(NULL) 
Thread_Proc = WinMain(hInst, NULL, NULL, SW_SHOWNORMAL, wnd)
RETURN
END FUNCTION Thread_Proc
!----------------------------------------------------------------
SUBROUTINE gr_dot(ix, iy, icol)
IMPLICIT NONE
INTEGER, INTENT(IN) :: ix, iy
INTEGER, INTENT(IN) :: icol
INTEGER (BOOL):: iretb
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = SetPixel(wnd%hDC, ix, iy, icol)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_dot
!----------------------------------------------------------------
SUBROUTINE gr_move(ix, iy)
IMPLICIT NONE
INTEGER, INTENT(IN) :: ix, iy
INTEGER (BOOL):: iretb
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = MoveToEx(wnd%hDC, ix, iy, NULL)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_move
!----------------------------------------------------------------
SUBROUTINE gr_line(ix, iy)
IMPLICIT NONE
INTEGER, INTENT(IN) :: ix, iy
INTEGER (BOOL):: iretb
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = LineTo(wnd%hDC, ix, iy)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_line
!----------------------------------------------------------------
SUBROUTINE gr_show()
IMPLICIT NONE
INTEGER (BOOL):: iretb
iretb = InvalidateRect(wnd%hWnd, NULL, FALSE)
RETURN
END SUBROUTINE gr_show
!----------------------------------------------------------------
SUBROUTINE gr_pencol(icol)
IMPLICIT NONE
INTEGER, INTENT(IN) :: icol
INTEGER :: iretb
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb    = DeleteObject(wnd%hPen) 
wnd%hPen = CreatePen(PS_SOLID, 1, icol)
iretb    = SelectObject(wnd%hDC, wnd%hPen)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_pencol
!----------------------------------------------------------------
SUBROUTINE gr_text(ix, iy, txt, icol)
IMPLICIT NONE
INTEGER, INTENT(IN) :: ix, iy
CHARACTER (LEN = *), INTENT(IN) :: txt
INTEGER, INTENT(IN), OPTIONAL :: icol
INTEGER (BOOL):: iretb
IF (PRESENT(icol)) iretb = SetTextColor(wnd%hDC, icol) 
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = TextOut(wnd%hDC, ix, iy, txt, LEN_TRIM(txt))
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_text
!----------------------------------------------------------------
INTEGER FUNCTION irgb(ir, ig, ib)
IMPLICIT NONE
INTEGER, INTENT(IN) :: ir, ig, ib
irgb = ir + (ig + (ib * 256)) * 256
RETURN
END FUNCTION irgb
!----------------------------------------------------------------
SUBROUTINE gr_axis(xmin, xmax, ymin, ymax)
IMPLICIT NONE
REAL, INTENT(IN) :: xmin, xmax, ymin, ymax
wnd%xmin = xmin
wnd%xmax = xmax
wnd%ymin = ymin
wnd%ymax = ymax
RETURN
END SUBROUTINE gr_axis
!----------------------------------------------------------------
SUBROUTINE to_ixy(x, y, ix, iy)
IMPLICIT NONE
REAL   , INTENT(IN ) :: x, y
INTEGER, INTENT(OUT) :: ix, iy 
ix =  INT( wnd%nsize_x * (x - wnd%xmin) / (wnd%xmax - wnd%xmin) )
iy = -INT( wnd%nsize_y * (y - wnd%ymin) / (wnd%ymax - wnd%ymin) ) + wnd%nsize_y
RETURN
END SUBROUTINE to_ixy
!----------------------------------------------------------------
SUBROUTINE gr_wdot(x, y, icol)
IMPLICIT NONE
REAL, INTENT(IN) :: x, y
INTEGER, INTENT(IN) :: icol
INTEGER :: ix, iy
INTEGER (BOOL):: iretb
CALL to_ixy(x, y, ix, iy)
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = SetPixel(wnd%hDC, ix, iy, icol)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_wdot
!----------------------------------------------------------------
SUBROUTINE gr_wmove(x, y)
IMPLICIT NONE
REAL, INTENT(IN) :: x, y
INTEGER (BOOL):: iretb
INTEGER :: ix, iy
CALL to_ixy(x, y, ix, iy)
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = MoveToEx(wnd%hDC, ix, iy, NULL)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_wmove
!----------------------------------------------------------------
SUBROUTINE gr_wline(x, y)
IMPLICIT NONE
REAL, INTENT(IN) :: x, y
INTEGER (BOOL):: iretb
INTEGER :: ix, iy
CALL to_ixy(x, y, ix, iy)
CALL EnterCriticalSection(LOC(lpCriticalSection))
iretb = LineTo(wnd%hDC, ix, iy)
CALL LeaveCriticalSection(LOC(lpCriticalSection))
RETURN
END SUBROUTINE gr_wline
!----------------------------------------------------------------
END MODULE uhoplot
!================================================================