図形表示ライブラリ

更新日付 2021年06月15日


《目 次》

1.図形表示ライブラリとは

2.gfortranの準備

3.図形表示ライブラリのダウンロード

4.図形表示ライブラリの使用方法

5.使用上の注意

6.図形表示ライブラリの使用例

1.図形表示ライブラリとは


図1 図形処理システムの概要

図形表示ライブラリとは,Windows 用 gfortran から利用できる図形表示ライブラリです。
図形表示ライブラリは,図1に示すように gfortran のプログラムからサブルーチンの形式で利用します。

PS(PostScript)形式の図形ファイルを作成する PsPlotG ライブラリと,図形を直接画面に表示する WinPlotG ライブラリがあります。

PsPlotG ライブラリを用いてできた PS 形式の図形ファイルは,PS プリンタがあれば直接プリンタに出力させることができます。フリーソフトの GSview プログラムを用いれば画面表示をしたり,汎用のプリンタに出力することができます(Word2007以降ではEPS形式のファイルは組み込みができなくなっているようです)。PDF ファイル形式に変換することもできます。PDF ファイル形式にした図形データを SD カードに入れておけば,コンビニエンスストアのカラープリンタに高画質印刷ができます。

一方,WinPlotG ライブラリを用いるとプログラムの実行と同時にウィンドウを開いて図形表示を行います。最後に表示されるクローズボタンウィンドウからプリンタ出力を指示することができます。Windows10 の場合は,Print to PDF も標準で用意されています。
通常,gfortran から直接ウィンドウ画面に図形表示するには,Win32/64 API を用いて難解なプログラムを書かなくてはなりません。ちょっとした計算結果を図形表示するだけでも多くの時間と労力が必要になります。WinPlotG ライブラリを用いると,幾つかのサブルーチンを CALL するだけで簡単に図形表示ができます。また,作画するのに便利なツールも用意されているので多様な用途に使用することができます。
表示図形を BMP 画像として出力することもできるので,WMF 形式に変換すれば,Word や Tex などワープロの文書に高画質の図として組み込むこともできます。WinPlotG ライブラリは Win32/64 API を用いた Windows アプリケーションです。

《補足》

画面に表示された図形をキャプチャーして,そのまま Word の文書に組み込むと,ぼやけた図面になることがあります。きれいな図を組み込むには,少し大き目の図を表示し,BMP 出力ルーチンを用いて BMP 形式のファイルを作ります。
次に,BMP 形式のファイルを Inkscape 等で WMF 形式(又は EMF 形式)に変換します。Word の図の挿入機能を用いて WMF 形式にしたファイルを組み込みます。ビットマップをベクトルに変換することにより,図の拡大縮小による画質の劣化が少なくなります。

2.gfortranの準備

図形表示ライブラリは,gfortran から利用します。従って,図形表示ライブラリを使用するには,gfortran が利用できる環境とプログラムを作成したり編集するための編集ソフトが必要です。筆者は編集ソフトに秀丸エディタを使用しています。
また,PsPlotG を用いる場合は PS 形式の図形ファイルを画面表示するために GSview があると便利です。

(1) gfortranのダウンロードは以下のサイトから可能です。
  動作確認しているのは,V8.1 です。バージョンが違うと動作しない場合があります。

  https://sourceforge.net/projects/mingw-w64/files/?source=navbar

(2) サイトに入ったら「MinGW-w64-for 32 and 64 bit Windows」というタイトルの下ほどに,
   Download Latest Version
  mingw-w64-v8.0.0.zip(15.5MB)
という項目があり,クリックすると以前はインストーラーがダウンロードされました。
現在は,ページの中程に移動し,
  MinGW-W64 Online Installer という項目の,
MinGW-W64-install.exe
をクリックするとインストーラーがダウンロードされます。
起動したインストーラーの指示に従ってインストールを進めます。
Settings の画面が出たら,64 bit モードをインストールする場合は,Architecture の項目でx86_64 を選択します。
gfortranをインストールすると,GCC と一緒に関連するコマンドやライブラリがインストールされます。

(3) Explore から gfortran をインストールしたディレクトリを開き,mingw-w64.batをダブルクリックするとコマンドビューが開きます。
mingw-w64.bat は,コマンドパスを設定する BATCH ファイルです。


図2 コマンドビュー

(4) 簡単なプログラムを作成し,gfortran でコンパイルして実行します。
エディタを用いて以下のような内容の test.f90 というファイルを作成します。
ファイル修飾子の f90 は fortran90 以降の文法とフリーフォーマット形式のプログラムであることを表します。f95,f03 も同様です。f77,for,f は fortran77 の文法と固定フォーマットであることを表します。

 write(6,*)'Hellow!'
 stop
 end

gfortran を用いてコンパイルします。プログラムにエラーがなければ a.exe が作成されます。
a.exe を実行すると,'Hellow!'という文字列が表示されます。


図3 コンパイルと実行

3.図形表示ライブラリのダウンロード

gfortran には 32bit版と 64bit版があるので,図形表示ライブラリもそれぞれ 32bit用と 64bit用があります。 使用しているシステム環境に合わせてダウンロードしてください。

gfortranのバージョンが異なるとライブラリの互換性がありません。gfortranのバージョンを確認してダウンロードしてください。
動作確認しているのは以下のバージョンです。(V7.3 では動作しないものがあります。)

tdm-gccのサイトからはFortran 2018規格に基づくV10.3のgfortranがダウンロードできますが,V8.1用の図形ライブラリが動作します。V10.3のgfortranは従来使用できた記述の一部が廃止され使用できなくなっています。

(1) 32bit用ライブラリ(V8.1用)
     
xylib32 (V07L004) (21.06.15 243 KB)

(2) 64bit用ライブラリ(V8.1用)
     xylib64 (V07L004) (21.06.15 215 KB)

(3) 32bit用ライブラリ(V6.3用)
     xylib32 (V07L004) (21.06.15 242 KB)

(4) 64bit用ライブラリ(V6.3用)
     xylib64 (V07L004) (21.06.15 270 KB)

ダウンロードしたファイルは,解凍すると32bit用又は,64bit用の WinPlotG ライブラリと PsPlotG ライブラリ,サンプルプログラム,及びサンプルプログラムを翻訳する BATCH ファイルが含まれていますので,gfortranの環境フォルダにコピーします。

※(お詫び) V07L003(21.02.22更新)のSYMBOLルーチンに誤りがありました。AXISルーチンなどSYMBOLを引用しているルーチンでエラーになる場合があります。

4.図形表示ライブラリの使用方法

図形表示ライブラリは,gfortran のプログラムからサブルーチン形式で使用します。ライブラリの指定は,インストールした gfortran の環境でコマンドラインで行います。
BATCH ファイルを作成して実行すると便利です。
使用例は,64bit版で記載しています。

ライブラリの使用方法や解説は「図形出力の手引」を参照してください。

(1) WinPlotG ライブラリを使用して実行ファイルを作成する BATCH ファイル(gfwin.bat)の例。


 gfortran sample01.f90 -fno-range-check -L. -lWinPlot64

 上記のような内容の BATCH ファイル(gfwin.bat)を作成します。

 gfortran gfortranを起動するコマンド名。
 sample01.f90 コンパイルするソースプログラムのファイル名。
 -fno-range-check 16進定数を用いるときに出る警告メッセージの抑止オプション。
 -L. WinPlotG ライブラリの存在するディレクトリを指示するパラメータ。
.(ドット)は gfortran を起動するのと同じディレクトリに存在することを指示する。
 -lWinPlot64 -l に続き,libWinPlot64.a というライブラリ名の頭の lib と後ろの .a を省略したもの。
 -static 静的 link を行う場合に指定する。実行形式ファイルを他のフォルダに移動して explorer から実行する場合に指定する。

(2) BATCH ファイルを実行し,できた実行形式ファイル a.exe を実行する。


E:\Program Files\gFortran>gfwin

E:\Program Files\gFortran>gfortran sample01.f90 -fno-range-check -L. -lWinPlot64 

E:\Program Files\gFortran>a
 *** WinPlotG(x64) Start Time = 16:19:13 ***
   * WinPlotG  XVIEWP NO. =   1 *
 *** WinPlotG(x64) End   Time = 16:21:54 ***

E:\Program Files\gFortran>

(3) WinPlotG ライブラリを用いて表示された画面の例。

WinPlotG ライブラリの XVIEWP ルーチンが呼ばれた数だけウィンドウ画面が表示され,最後に XEND ルーチンを実行すると,クローズボタンウィンドウが表示され待機状態になります。Close ボタンをクリックすると全画面が消去され,XEND が終了します。


図5 WinPlotG ライブラリを用いて表示された画面

(4) WinPlotG ライブラリを用いて表示された内容の印刷

クローズボタンウィンドウの Print ボタンをクリックすると,プリンタの選択ダイアログが表示されます。通常の手順に従って印刷処理を行います。開いているウィンドウのみ印刷されます。
但し,プリントダイアログで用紙のサイズや向きを変更しても,プログラムの XINT の指定が優先されます。特殊な用紙への出力や印刷形式を指定する場合は,設定を変更した後で,適応ボタンを押し,キャンセルボタンを押してください。


(5) PsPlotG を利用するコンパイル&リンクの BATCH ファイルの例


 gfortran sample01.f90 -fno-range-check -L. -lPsPlot64

 上記のような内容の BATCH ファイル(gf.bat)を作成します。

 gfortran gfortranを起動するコマンド名。
 sample01.f90 コンパイルするソースプログラムのファイル名。
 -fno-range-check 16進定数を用いるときに出る警告メッセージの抑止オプション。
 -L. PsPlotG ライブラリの存在するディレクトリを指示するパラメータ。
.(ドット)は gfortran を起動するのと同じディレクトリに存在することを指示します。
 -lPsPlot64 -l に続き,libPsPlot64.a というライブラリ名の頭の lib と後ろの .a を省略したもの。

(6) BATCH ファイルを実行し,できた実行形式ファイル a.exe を実行する。


E:\Program Files\gFortran>gf

E:\Program Files\gFortran>gfortran sample01.f90 -fno-range-check -L. -lPsPlot64 
E:\Program Files\gFortran>a
 *** PsPlotG(x64) START TIME = 14:15:31 ***
     PSP001  XVIEWP NO. =  1
 *** PsPlotG(x64) END   TIME = 15:15:32 ***

E:\Program Files\gFortran>


a.exe を実行すると,PS形式のテキストデータが図形出力ライブラリの XINT ルーチンで指定したファイルに作成される。

(7) GSviewを用いて図形を表示する。(GSview は別途インストールする必要があります。)


図4 GSviewを実行した画面


5.使用上の注意

(1) gfortranの仕様上の問題

gfortran ではサブルーチンの引数の受け渡しのチェックが厳しくなりました。汎用コンピュータで使用してきた図形出力ルーチンでは,引数をサブルーチン側で文字列か数値か又は配列かを受け取った側で判断して対応ができましたが,gfortran ではそのような使い方はできません。そのため,SYMBOL ルーチンのように幾つかのプログラムでは gfortran の標準仕様に合わせて引数の仕様を変更しています。
また,gfortran では変数の領域を実行時に確保します(automatic属性)。多くの FORTRAN では変数の領域は静的に確保されます(static属性)。automatic 属性のサブルーチンプログラムでは,1回目の CALL で値をセットした変数を2回目の CALL で引用すると値が未定義になってしまいます。コンパイルオプションの指定で設定することもできますが,注意してプログラムをしないと思わぬエラーの原因になります。

(2) GDIの仕様上の問題

WinPlotG ライブラリは,Windows が提供する API を使用しています。API の中にはグラフィックスを表示する GDI というインタフェースを含んでいます。
GDI の基本的なルーチンに直線を引くためのルーチンがあります。図形表示ライブラリにとってはとても重要なルーチンですが,筆者が思うところ大きな欠陥があります。
直線を引く場合,基点と終点を指定するわけですが,どういう理由か GDI は終点を描画しないのです。そのため,大きな図形では目立ちませんが小さな図形を描画するとバランスの悪い図形になってしまいます。 WinPlotG では,細い線を引く場合には終点にドットを追加してプロットするようにしています。


図6 GDIによる描画

(3) WinPlotGを用いる場合の注意

WinPlotG を用いて図形表示を行う際に,XINT のパラメータに'A4L' 又は 'A4P'などのプリント用紙の設定がされていると,印刷を前提とした処理を行います。縮小表示のために線が薄くなって画面表示されます。印刷をしない場合には,'A4L' の部分を,'WIN' に置き換えて実行すると,きれいな画面表示になります。'FILE' 指定は無視されます。一方,'WIN' 指定のまま印刷をすると解像度の悪い出力になってしまいます。

 例

   CALL XINT('A4L,FILE=TEST.PS,WIN=(900,900)')
         ↓
   CALL XINT('WIN,FILE=TEST.PS,WIN=(900,900)')
         or
   CALL XINT('WIN=(900,900)')

6.図形表示ライブラリの使用例


(例1) 多角形を描く。

図7 (例1)多角形を描く

・プログラムの解説

図形ルーチン(WinPlotG)を用いて簡単な図形を描きます。最初に XINT ルーチンで表示するウインドウのサイズを指定します。次に,XVIEWP ルーチンでユーザー座標を定義します。FRAME ルーチンはユーザー座標領域の外枠を描きます。CLRPEN ルーチンは描画するペンの色と太さを指定します。20 番の do ループで多角形の頂点数 N を変化させます。10 番の do ループでは回転公式を用いて多角形の各頂点のXY座標を順次求め,PLOT ルーチンで線を引きます。XEND ルーチンを実行すると画面に表示されます。do の範囲が分かりやすいので,文番号付きの do を使用しています。

! ************************************************************
! *   Sample Program No.1 Polygon
! ************************************************************
      call XINT('WIN=(800,800)')
      call XVIEWP(-10.0,-10.0,10.0,10.0)
      call FRAME (-10.0,-10.0,10.0,10.0)
      X = 0.0
      Y = 8.0
      do 20 N = 5,7
      TH = 3.1415926*2.0/FLOAT(N)
      CO = COS(TH)
      SI = SIN(TH)
      call CLRPEN((N-4)*10+2)
      call PLOT(X,Y,3)
      do 10 I=1,N
      XP = X*CO - Y*SI
      Y  = X*SI + Y*CO
      X  = XP
      call PLOT(X,Y,2)
   10 continue
   20 continue
      call XEND
      stop
      end


(例2) 図1の図形処理システムの概要図を表示する。

図8 (例2)図形処理システムの概要図

・プログラムの解説

サブルーチン TOOL1 はディスクやプリンタなどのパーツを描くルーチンです。各パーツは指定位置に原点移動をして作画します。大きさは FACTOR ルーチンを用いて拡大縮小を行います。
サブルーチン TOOL2 は基点と終点を指定し太めの矢印を作画します。回転公式を用いて任意の方向に作画できるようにしています。
表示領域は FLRECT ルーチンと SETIRGB ルーチンを用いて任意のカラーで塗りつぶしています。座標の位置を分かり易くする為に GRID ルーチンで座標単位幅で白抜きの格子を描いています。

! ************************************************************
! *   Sample Program No.2 FIG1
! ************************************************************
      call XINT('WIN=(800,900)')
      call XVIEWP(1.0,1.0,9.0,10.0)
      call SETIRGB(INT(Z'FFD0D0'))
      call FLRECT(1.0,1.0, 9.0,10.0)
      call CLRPEN(71)                    ! white
      call GRID(1.0,1.0,1.0,1.0,8,9)
      call PLOT(0.0,-0.5,-3)
      call CFONT(3)                      ! Helvetica
!     Display Program
      call TOOL1(1, 5.0,9.0, 1.0,2,INT(Z'FFFFE0'))
      call SYMBOL(4.4,9.2,0.24,'Fortran',0.0,7)
      call JCHAR(4.2,8.9,0.27,'プログラムの',0.0,6)
      call JCHAR(4.3,8.6,0.27,'翻訳・結合',0.0,5)
!     Disk WinPlot
      call TOOL1(2, 3.0,9.0, 0.7,11,INT(Z'A0D0FF'))
      call SYMBOL(2.4,9.0,0.18,'WinPlotG',0.0,8)
      call JCHAR(2.5,8.7,0.25,'Library',0.0,7)
!     Display Run
      call TOOL1(3, 4.0,7.0, 0.8,01,INT(Z'D0D0D0'))
      call JCHAR(3.7,7.0,0.25,'実行',0.0,2)
      call JCHAR(3.5,6.7,0.25,'画面表示',0.0,4)
!     BMP Input Output
      call TOOL1(2, 2.5,7.5, 0.5,01,INT(Z'F4FA58'))
      call JCHAR(2.2,7.4,0.18,'BMP入力',0.0,5)
      call TOOL1(2, 2.5,6.5, 0.5,01,INT(Z'F4FA58'))
      call JCHAR(2.2,6.4,0.18,'BMP出力',0.0,5)
!     Printer
      call TOOL1(4, 4.0,5.5, 0.7,01,INT(Z'80FFFF'))
      call SYMBOL(3.7,5.4,0.20,'Print',0.0,5)
!     Disk PsPlotG
      call TOOL1(2, 7.0,9.0, 0.7,31,INT(Z'A0FFA0'))
      call SETIRGB(INT(Z'00C00000'))
      call SYMBOL(6.5,9.0,0.18,'PsPlotG',0.0,7)
      call JCHAR(6.6,8.7,0.25,'Library',0.0,7)
!     Display Run
      call TOOL1(3, 6.0,7.0, 0.8,01,INT(Z'D0D0D0'))
      call JCHAR(5.8,6.9,0.25,'実行',0.0,2)
!     Disk PS file
      call TOOL1(2, 6.0,5.5, 0.7,01,INT(Z'FFA0FF'))
      call CFONT(1)
      call SYMBOL(5.4,5.5,0.20,'PostScript',0.0,10)
      call SYMBOL(5.8,5.2,0.20,'File',0.0,4)
!     Display GSview
      call TOOL1(3, 6.0,4.0, 0.8,01,INT(Z'D0D0D0'))
      call SYMBOL(5.6,3.9,0.20,'GSview',0.0,6)
!     Disk PDF
      call TOOL1(2, 7.0,2.5, 0.7,01,INT(Z'D0D0FF'))
      call SYMBOL(6.65,2.4,0.20,'PDF File',0.0,8)
!     Printer
      call CFONT(3)
      call TOOL1(4, 5.9,2.5, 0.7,01,INT(Z'80FFFF'))
      call SYMBOL(5.6,2.4,0.20,'Print',0.0,5)
!     Arrow left
      call TOOL2(1,3.7,9.0,4.0,9.0,0.6,01,INT(Z'000080'))
      call TOOL2(1,4.5,8.45,4.0,7.5,0.6,01,INT(Z'000080'))
      call TOOL2(1,4.0,6.5,4.0,5.9,0.6,01,INT(Z'000080'))
      call TOOL2(1,3.05,7.5,3.32,7.3,0.5,01,INT(Z'000080'))
      call TOOL2(1,3.32,6.7,3.05,6.5,0.5,01,INT(Z'000080'))
!     Arrow right
      call TOOL2(1,6.3,9.0,6.0,9.0,0.6,01,INT(Z'008000'))
      call TOOL2(1,5.5,8.45,6.0,7.5,0.6,01,INT(Z'008000'))
      call TOOL2(1,6.0,6.5,6.0,5.9,0.6,01,INT(Z'008000'))
      call TOOL2(1,6.0,5.1,6.0,4.5,0.6,01,INT(Z'008000'))
      call TOOL2(1,6.0,3.5,6.0,2.9,0.6,01,INT(Z'008000'))
      call XEND
      stop
      end
! ************************************************************
! *   Tool1   Display,Disk,Printer
! ************************************************************
      Subroutine TOOL1(NT,X0,Y0,S,IP,IC)
      real  DS(2,24),PR(2,14),AR(2,8)
      data  DS/  -1.0,0.5,  -0.8,0.47, -0.6,0.45, -0.2,0.43,  &
       0.2,0.43,  0.6,0.45,  0.8,0.47,  1.0,0.5,   0.8,0.53,  &
       0.6,0.55,  0.2,0.57, -0.2,0.57, -0.6,0.55, -0.8,0.53,  &
      -1.0,0.5,  -1.0,-0.5, -0.8,-0.53,-0.6,-0.55,-0.2,-0.57, &
       0.2,-0.57, 0.6,-0.55, 0.8,-0.53, 1.0,-0.5,  1.0,0.5/
      data  PR/   1.0,-0.5,  1.0,0.5,  -1.0,0.5,  -1.0,-0.5,  &
      -0.85,-0.6,-0.55,-0.7,-0.4,-0.7, -0.15,-0.6, 0.0,-0.5,  &
       0.15,-0.4, 0.4,-0.3,  0.55,-0.3, 0.85,-0.4, 1.0,-0.5/
      if (IC.ne.-1) call SETIRGB(IC)
      call PLOT(X0,Y0,-3)
      call FACTOR(S)
      go to (1,2,3,4,9),NT
    1 call FLRECT(-1.0,-0.5,1.0,0.5)
      if (IP.eq.0) go to 9
      call CLRPEN(IP)
      call FRAME(-1.0,-0.5,1.0,0.5)
      go to 9
    2 call FLPOLY(DS(1,1),15)
      call FLPOLY(DS(1,15),10)
      if (IP.eq.0) go to 9
      call CLRPEN(IP)
      call PLOT(-DS(1,1),DS(2,1),3)
      do j = 2,24
      call PLOT(-DS(1,j),DS(2,j),2)
      end do
      go to 9
    3 call FLRECT(-0.8,-0.6,0.8,0.6)
      call SETIRGB(INT(Z'FFFFFF'))
      call FLRECT(-0.7,-0.5,0.7,0.5)
      if (IP.eq.0) go to 9
      call CLRPEN(IP)
      call FRAME(-0.8,-0.6,0.8,0.6)
      call FRAME(-0.7,-0.5,0.7,0.5)
      go to 9
    4 call FLPOLY(PR(1,1),13)
      if (IP.eq.0) go to 9
      call CLRPEN(IP)
      call PLOT(PR(1,1),PR(2,1),3)
      do j = 2,14
      call PLOT(PR(1,j),PR(2,j),2)
      end do
    9 call FACTOR(1.0)
      call PLOT(-X0,-Y0,-3)
      return
! ============================================================
!     Tool2  arrow
! ============================================================
      Entry TOOL2(NT,X0,Y0,X1,Y1,S,IP,IC)
      if(IC.ne.-1)call SETIRGB(IC)
      go to (11,99),NT
   11 TT = S * 0.1
      TH = TT * 0.5
      T2 = TT * 2.0
      T3 = TT * 3.0
      T4 = TT * 4.0
      XD = X1 - X0
      YD = Y1 - Y0
      CI = 1.0 / SQRT(XD**2+YD**2)
      SR = YD * CI
      CR = XD * CI
      AR(1,1) = X1 - T3*CR + TH*SR
      AR(2,1) = Y1 - T3*SR - TH*CR
      AR(1,2) = X1 - T4*CR + T2*SR
      AR(2,2) = Y1 - T4*SR - T2*CR
      AR(1,3) = X1
      AR(2,3) = Y1
      AR(1,4) = X1 - T4*CR - T2*SR
      AR(2,4) = Y1 - T4*SR + T2*CR
      AR(1,5) = X1 - T3*CR - TH*SR
      AR(2,5) = Y1 - T3*SR + TH*CR
      AR(1,6) = X0 - TH*SR
      AR(2,6) = Y0 + TH*CR
      AR(1,7) = X0 + TH*SR
      AR(2,7) = Y0 - TH*CR
      call FLPOLY(AR(1,1),7)
   99 return
      end


(例3) ストックチャートを表示する

図9 (例3)ストックチャート

・プログラムの解説

株価チャートでよく使われる日足4本値ローソク足チャートです。5日移動平均を赤線,25日移動平均を青線で表示しています。水色の棒グラフは出来高,赤と緑は日証金の貸借株数を表示しています。(出来高によってローソクの太さが異なる表示方法は筆者の考案です。2017年5月時点で。)
右側の横向きの棒グラフは価格帯別出来高で,赤線は直近25日間の出来高です。( これも筆者の考案です。)

株価のテクニカル分析は統計処理の宝庫です。紫の線は25日移動平均に対するボリンジャーバンド±2σのラインです。(理論的には,株価の終値が±2σの範囲に収まる確率は95%ですが,このチャートの場合は86.2%でした。ここでもバンドウォークと呼ばれる現象がよく見られます。)

RSI と RCI も表示していますが,その他にも近い将来の株価予測を行うために各種の手法が考案されています。統計処理と図形処理はコンピュータが本領発揮できる最たるものです。

!*******************************************************************
!  Sample Program No.3 Stock Chart.
!     2017.05.23   Y.AKATSUKA
!*******************************************************************
module GLOBALDATA
      integer S(0:5,300),T(2,300),NU,NS
end module GLOBALDATA
!*******************************************************************
!   Main routine
!*******************************************************************
use GLOBALDATA
      OPEN(2,FILE='J:\I\9999.CSV',STATUS='OLD')
      CALL DTREAD
      NU = MAX(NU - 0, 3)               ! データの終わり位置
      NS = MAX(NU - 100, 1)             ! データの開始位置
      CALL XINT('A4L,FILE=XYTEST.PS')
      CALL DPLOT
      CALL XEND
      STOP
      END
!******************************************************************
!   DPLOT
!******************************************************************
SUBROUTINE DPLOT
use GLOBALDATA
CHARACTER DM*8,IM*2
INTEGER NP(9)/11,21,34,34,51,51,31,51,31/
INTEGER ND(9)/ 5,75,25,25,25,25,25, 1,25/
REAL*4  VOL(200)
DATA  IYMAX,IMMAX/2*0/,IYMIN,IMMIN/9000,9000/,X0,Y0/2.0,2.0/
      F(IX) = FLOAT(IX - LMIN) / FINT * 20.0 + Y0
      FR(X) = (X - FLOAT(LMIN)) / FINT * 20.0 + Y0
!
      CALL XVIEWP(0.0,0.0,36.5,25.0)
      CALL FRAME(0.0,0.0,36.5,25.0)
      CALL CFONT(1)
! =================================================
      CALL SYMBOL(13.0,23.0,1.0,'Stock Chart',0.0,11)
      XDEL  = 32.5 / FLOAT(NU - NS + 2)
      FTSZ  = XDEL * 0.7 + 0.1
      FTSZ1 = XDEL * 0.8 + 0.1
      IVDL  = 0                           ! 最大出来高
      AVOL  = 0.0
      K     = 0
      DO 10 I = NS,NU
      IF(S(4,I) == 0) GO TO 10
      IF(S(2,I) > IYMAX) IYMAX = S(2,I)
      IF(S(3,I) < IYMIN) IYMIN = S(3,I)
      IF(S(5,I) > IVDL)  IVDL  = S(5,I)
      AVOL = AVOL + FLOAT(S(5,I))
      K = K + 1
   10 CONTINUE
      AVOL = FLOAT(K) / AVOL
      IVDL = IVDL / 100
      IEMP = 10 ** IFIX(LOG10(FLOAT(IYMAX)) - 1) ! 株価単位
      IEMX = IEMP
      IEM2 = IEMP * 2
      LMAX = (IYMAX+IEM2-1)/IEM2*IEM2+IEM2
      LMIN = IYMIN/IEM2*IEM2-IEM2
      LINT = LMAX - LMIN                  ! 価格帯の幅
      ILVL = LINT / IEMP * 2              ! 目盛の数
      FINT = LINT
      do while(ILVL >= 32)                ! 目盛の数を8から32に調整
        ILVL = ILVL / 2
    	IEMP = IEMP * 2                   ! 目盛数半分なら株価目盛が倍
      end do
      do while(ILVL < 8)
        ILVL = ILVL * 2                   ! 1目盛の株価
        IEMP = IEMP / 2                   ! 株価目盛りの数
      end do
      DEL  = 20.0 / FLOAT(ILVL)           ! 1円当たりの座標長さ
      IE   = LOG10(FLOAT(IVDL))           ! 最大出来高の桁数
      IEVP = 10 ** IE
      KIVL = (IVDL+IEVP-1)/IEVP*IEVP
      KIVL = (KIVL/IEVP+4)/5*5*IEVP       ! 最大出来高の目盛
      VDL  = DEL / FLOAT(KIVL) * 20.0     ! 出来高当たりの座標長さ
! === VERTICAL LABEL ==============================
      DO 20 I = 0,ILVL
      YM = FLOAT(I) * DEL + Y0
      CALL LINEX(34.7,YM,34.5,YM)
   20 CONTINUE
      CALL PLOT(34.5,2.0,2)
      CALL PLOT(1.8,2.0,2)
      CALL PLOT(1.8,22.0,2)
      CALL CLRPEN(1)
      KMIN = (LMIN+IEM2-1)/IEM2*IEM2/IEMX ! 最小目盛りの値
      KC = MAX(1,IEMP*10/(IEMX*2))        ! 1目盛りの値
      DO 30 I = 0,ILVL,2                  ! 株価(千円単位)
      CALL NUMBER(34.8,FLOAT(I)*DEL+Y0,0.5,FLOAT(I*KC/10+KMIN),0.0,-1)
   30 CONTINUE
      CALL CLRPEN(61)                     ! 水色
      DO 40 I = 2,ILVL,2                  ! 水平目盛り線
      YS = FLOAT(I)*DEL+Y0
      CALL LINEX(1.8,YS,34.5,YS)
   40 CONTINUE
! === MONTH LABEL ==出来高=========================
      X = X0
      WRITE(IM,'(I2)')MOD(S(0,NS-1)/100,100)
      CALL CLRPEN(63)                     ! 水色
      DO 110 I = NS,NU
      Y = FLOAT(S(5,I)/100) * VDL + Y0
      CALL LINEX(X,Y0,X,Y)                ! 毎日の出来高
      WRITE(DM,'(I2)')MOD(S(0,I)/100,100) ! 月
      IF (DM == IM) GO TO 14
      IM = DM
      CALL CLRPEN(33)                     ! 青
      CALL SYMBOL(X, 1.0, 0.5, DM, 0.0, 2)
      CALL LINEX(X,1.95,X,1.75)
      CALL CLRPEN(63)                     ! 水色
   14 X = X + XDEL
  110 CONTINUE
! === CREDIT BALANCE BUY & SELL ===================
      X = X0 + 0.08
      CALL CLRPEN(13)                     ! 赤
      DO 410 I = NS,NU
      IF (T(1,I) == 0) GO TO 15
      Y = FLOAT(T(1,I)/100) * VDL * 2.0 + Y0
      CALL LINEX(X,Y0,X,Y)
   15 X = X + XDEL
  410 CONTINUE
      X = X0 + 0.17
      CALL CLRPEN(23)                     ! 緑
      DO 420 I = NS,NU
      IF (T(2,I) == 0) GO TO 16
      Y = FLOAT(T(2,I)/100) * VDL * 2.0 + Y0
      CALL LINEX(X,Y0,X,Y)
   16 X = X + XDEL
  420 CONTINUE
! === 5,25,75 DAYS ACTIVE MEAN & DIFFERENCIAL LINE ===
      DO 210 M = 1,9
      CALL CLRPEN(NP(M))
      IPEN = 3
      X  = X0
      K  = ND(M)
      DO 220 J = NS,NU
      SELECT CASE(M)
        CASE (1:2)                      ! 5,75日移動平均値(赤,緑)
          Y = FR(AM25(J,K))
        CASE (3)                        ! 25日移動平均+8%乖離(青破線)
          Y = FR(VWAP(J,K)*1.08)
        CASE (4)                        ! 25日移動平均-8%乖離(青破線)
          Y = FR(VWAP(J,K)*0.92)
        CASE (5)                        ! Bollinger Band +2σ(紫)
          AM = AM25(J,K)
          SI = SQRT(AMD25(J,K)-AM**2)*2.0                 ! 2σ
          Y = FR(VWAP(J,K)+SI)
        CASE (6)                        ! Bollinger Band -2σ(紫)
          AM = AM25(J,K)
          SI = SQRT(AMD25(J,K)-AM**2)*2.0                 ! 2σ
          Y = FR(VWAP(J,K)-SI)
        CASE (7)                        ! RCI(青)
          Y = RCI(J,9) * DEL * 0.04 + Y0                  ! RCI(9日)
        CASE (8)                        ! RSI(紫)
          Y = RSI(J,9) * DEL * 0.04 + Y0
        CASE (9)                        ! 出来高荷重移動平均(青破線)
          Y = FR(VWAP(J,K))
      END SELECT
      CALL PLOT(X,Y,IPEN)
      IPEN = 2
      X = X + XDEL
  220 CONTINUE
  210 CONTINUE
      CALL CLRPEN(NP(8))
      CALL LINEX (35.0,1.6,35.5,1.6)
      CALL SYMBOL(35.6,1.5,0.25,'RCI',0.0,3)
      CALL CLRPEN(NP(9))
      CALL LINEX (35.0,1.3,35.5,1.3)
      CALL SYMBOL(35.6,1.2,0.25,'RSI',0.0,3)
! === PRICE CANDLE =================================
      CALL CLRPEN(1)
      X = X0
      DO 120 I = NS,NU
      IF (I == NU-24) CALL CLRPEN(11)
      IF (S(4,I) == 0) GO TO 31
      Y1 = F(S(1,I))
      Y2 = F(S(2,I))
      Y3 = F(S(3,I))
      Y4 = F(S(4,I))
      DX = MAX(1.0, MIN(4.5,FLOAT(S(5,I))*AVOL))*0.07
      IF(Y1 > Y4) THEN
        CALL LINEX(X,Y2,X,Y3)
        CALL FLRECT(X-DX,Y4,X+DX,Y1)      ! 陰線(塗りつぶし)
      ELSE
        CALL FRAME(X-DX,Y1,X+DX,Y4)       ! 陽線
        CALL LINEX(X,Y1,X,Y3)
        CALL LINEX(X,Y4,X,Y2)
      END IF
   31 X = X + XDEL
      IF (I == NU-24) CALL CLRPEN(1)
  120 CONTINUE
! === VOLUME BAR ==================================
      SMAX = 0.0
      INUM = ILVL * 5                     ! 1目盛り当りの表示行数
      IPV = 10 ** (IE - 1)                ! 出来高単位
      IEP = IEMP / 10                     ! 表示区分価格(1目盛りの1/10)
      LM5 = LMIN + IEP / 2
      DO 390 K = 1,2
      NZ = NS + MAX((NU-NS-24)*(K-1),0)
      VOL = 0.0 
      DO 310 I = NZ,NU
      HI = S(2,I)                         ! 高値
      AL = S(3,I)                         ! 安値
      AM = S(5,I)                         ! 出来高
      SD = HI - AL
      IF (SD == 0.0) SD = IPV
      VM = AM / SD                        ! 出来高/単位円
      IH = (HI - LMIN) / IEP              ! 高値の位置
      IL = (AL - LMIN) / IEP              ! 安値の位置
!                                           -
      IF (IL == IH) GO TO 52              ! |  ---- S(2,I) 高値
      IF (IL +1 == IH) GO TO 51           ! -  IH
      DO 320 J = IL+1,IH-1                ! |
      VOL(J) = VOL(J) + VM * FLOAT(IEP)   ! -
      IF (SMAX .LT. VOL(J)) SMAX = VOL(J) ! |  ---- S(3,I) 安値
  320 CONTINUE                            ! -  IL
!     端数処理                              |
   51 VOL(IL) = VOL(IL)+VM*(FLOAT((IL+1)*IEP+LMIN)-AL)
      IF (SMAX .LT. VOL(IL)) SMAX = VOL(IL)
      VOL(IH) = VOL(IH)+VM*(HI-FLOAT(IH*IEP+LMIN))
      IF (SMAX .LT. VOL(IH)) SMAX = VOL(IH)
      GO TO 310
   52 VOL(IH) = VOL(IH)+VM*FLOAT(IEP)
      IF (SMAX .LT. VOL(IH)) SMAX = VOL(IH)
  310 CONTINUE
      CALL CLRPEN(23-(K-1)*10)            ! 緑,赤
      FAC = 1.9 / SMAX
      DO 330 I=1,INUM
      IF(VOL(I).EQ.0.0)GO TO 330
      YM = F(I*IEP+LM5)
      CALL LINEX(34.6,YM, VOL(I)*FAC+34.6,YM)
  330 CONTINUE
  390 CONTINUE
   99 RETURN
      END
!******************************************************************
!   DTREAD
!******************************************************************
SUBROUTINE DTREAD
use GLOBALDATA
character A,B*80
integer NULL
      T = 0
! Read the first record & get the number of object
      READ(2,*)NULL,NULL,A,NULL,NULL,NU
      IF (NU .LE. 300) GO TO 1
      DO 30 M=1,NU-300
      READ(2,*,END=9)
   30 CONTINUE
      NU = 300
! Read object data
    1 DO 10 J=1,NU
      READ(2,*,END=9)(S(I,J),I=0,5),(T(I,J),I=1,2)
      IF (S(1,J) .LT. 3000)GO TO 10
      DO 20 L=1,4
      S(L,J) = S(L,J) / 100
   20 CONTINUE
      S(5,J) = S(5,J) / 100
      T(1,J) = T(1,J) / 100
      T(2,J) = T(2,J) / 100
   10 CONTINUE
      GO TO 99
    9 NU = J -1
   99 CLOSE(2)
      RETURN
      END
!*******************************************************************
!   AM25 MEAN25 calcurate
!*******************************************************************
FUNCTION AM25(N,K)
use GLOBALDATA
      IS = MAX(N-K+1,1)
      IA25 = 0
      DO 10 J = IS,N
      IA25 = IA25 + S(4,J)
   10 CONTINUE
      AM25 = FLOAT(IA25) / FLOAT(K)         ! 移動平均値
      RETURN
      END
!*******************************************************************
!   AMD25 Square mean calcurate
!*******************************************************************
FUNCTION AMD25(N,K)
use GLOBALDATA
      IS = MAX(N-K+1,1)
      A25 = 0.0
      DO 10 J = IS,N
      A25 = A25 + FLOAT(S(4,J)) ** 2
   10 CONTINUE
      AMD25 = A25 / FLOAT(K)                ! 移動二乗平均値
      RETURN
      END
!*******************************************************************
!   VWAP Volume Weighted Average Price
!*******************************************************************
FUNCTION VWAP(N,K)
use GLOBALDATA
      IS = MAX(N-K+1,1)
      A25 = 0.0
      IV = 0
      DO 10 J = IS,N
      A25 = A25 + FLOAT(S(2,J) + S(3,J)) * FLOAT(S(5,J))
      IV = IV + S(5,J)
   10 CONTINUE
      VWAP = A25 / FLOAT(IV) * 0.5         ! 出来高荷重移動平均値
      RETURN
      END
!*******************************************************************
!   RSI calcurate
!*******************************************************************
FUNCTION RSI(N,K)
use GLOBALDATA
      IP = 0
      IM = 0
      IS = MAX(N-K+1,2)
      DO 10 I = IS,N
      ID = S(4,I) - S(4,I-1)      ! 当日終値 - 前日終値
      IF (ID) 1,10,2
    1 IM = IM - ID
      GO TO 10
    2 IP = IP + ID
   10 CONTINUE
      RSI = FLOAT(IP)/FLOAT(IP + IM) * 100.0
      RETURN
      END
!*******************************************************************
!   RCI (Rank Correlation Index) calcurate
!*******************************************************************
FUNCTION RCI(N,K)
use GLOBALDATA
INTEGER  SP(20,2)
      IS = MAX(N-K+1,1)
      L  = 1
      DO 10 J = IS,N
      SP(L,1) = L
      SP(L,2) = S(4,J)
      L = L + 1
   10 CONTINUE
      DO 20 I=1,K-1
      DO 30 J=I+1,K
      IF(SP(I,2) .LE. SP(J,2))GO TO 30
      IW = SP(I,2)
      SP(I,2) = SP(J,2)
      SP(J,2) = IW
      IW = SP(I,1)
      SP(I,1) = SP(J,1)
      SP(J,1) = IW
   30 CONTINUE
   20 CONTINUE
      JD = 0
      DO 40 I=1,K
      JD = JD + (SP(I,1) - I) ** 2
   40 CONTINUE
      RCI = 100.0 - FLOAT(JD) / FLOAT((K * K - 1) * K) * 300.0 
      RETURN
      END


(例4) 電子回路図を表示する

図10 (例4)電子回路図

・プログラムの解説

電子回路図を表示するプログラムの例です。電子部品を描くサブルーチンでは,リード線を引く向きによってパーツの向きが変わるようにプログラムしました。WHEREサブルーチンを用いてペンのカレントポジションを取得しています。

鉄道模型の自作車内灯に使用した回路図です。

!*******************************************************************
!  Sample Program No.4  Electronic circuit.
!     2018.09.01   Y.Akatsuka
!*******************************************************************
      call XINT('WIN,FILE=E:\WORK\WINPLOT.PS,WIN=(600,400)')
      call XVIEWP(0.0,2.0,10.0,8.0)
      call FRAME (0.0,2.0,10.0,8.0)
      call CFONT(1)
      call Parts(-1,0.5,6.0,'Rail',4,1.0)
      call PLOT(2.0,6.0,2)
      call Parts(-1,0.5,4.0,'Rail',4,1.0)
      call PLOT(2.0,4.0,2)

      call Bridge(2.0,4.0,3.5,6.0,1.0)

      call PLOT(3.5,6.0,3)
      call Parts(6,7.0,6.0,'CCR 20mA',8,1.0)
      call PLOT(9.0,6.0,2)
      call Parts(4,9.0,5.0,'LED',3,1.0)
      call PLOT(9.0,4.0,2)
      call PLOT(3.5,4.0,2)

      call Parts(-2,5.0,6.0,' ',0,1.0)
      call Parts( 3,5.0,5.0,'10μF',4,1.0)
      call Parts( 2,5.0,4.0,' ',0,1.0)
      call XEND
      stop
      end

      Subroutine Bridge(XL,YL,XU,YU,F)
      call Parts(-2,XL,YU,' ',0,F)
      call Parts(5,XL+F,YU,'Bridge Diode',12,1.0)   ! 1
      call Parts(2,XU,YU,'+',1,1.0)
      XD = XU-XL
      YD = YU-YL
      call PLOT(XU,YL,3)
      call Parts(5,XL+XD*0.25,YL+YD*0.75,' ',0,1.0) ! 2
      call PLOT(XL,YU,2)
      call PLOT(XL,YL,3)
      call Parts(5,XL+XD*0.35,YL+YD*0.35,' ',0,1.0) ! 3
      call PLOT(XU,YU,2)
      call Parts(-2,XU,YL,'-',1,1.0)
      call Parts(5,XL+F*0.5,YL,' ',0,1.0)           ! 4
      call Parts(2,XL,YL,' ',0,1.0)
      call CLRPEN(4)
      call FRAME(XL-F*0.5,YL-F*0.5,XU+F*0.5,YU+F*0.5)
      call CLRPEN(1)
      return
      end

      Subroutine Parts(N,XP,YP,MSG,L,F)
      character MSG*(L)
      NN = ABS(N)
      call WHERE(XO,YO,FC)
      call PLOT(XP,YP,-3)
      if (NN.ge.3) call ROTATE(ATAN2(YP-YO,XP-XO)*57.29578)
      go to (1,2,3,4,5,6),NN
    1 if (N.gt.0) call PLOT(0.0,0.0,2)
      call JTEXT(-F*0.23,-F*0.25,F*0.5,'○',0.0,1,-1)
      call JTEXT(-F*FLOAT(L)*0.04,F*0.3,F*0.2,MSG,0.0,1,L)
      call PLOT(0.0,0.0,3)
      go to 9
    2 if (N.gt.0) call PLOT(0.0,0.0,2)
      call JTEXT(-F*0.05,-F*0.06,F*0.1,'●',0.0,1,-1)
      call JTEXT(-F*0.05,0.0,F*0.3,MSG,0.0,1,L)
      call PLOT(0.0,0.0,3)
      go to 9
!     Capacita
    3 if (N.gt.0) call PLOT(-F*0.1,0.0,2)
      call NEWPEN(2)
      call LINEX(-F*0.1,-F*0.3,-F*0.1,F*0.3)
      call LINEX( F*0.1,-F*0.3, F*0.1,F*0.3)
      call NEWPEN(1)
      call JTEXT(-F*0.2,F*0.4,F*0.2,MSG,0.0,1,L)
      call PLOT(F*0.1,0.0,3)
      go to 9
!     LED
    4 if (N.gt.0) call PLOT(-F*0.3,0.0,2)
      call PLOT(0.0,0.0,3)
      call PLOT(-F*0.3,-F*0.2,2)
      call PLOT(-F*0.3,F*0.2,2)
      call PLOT(0.0,0.0,2)
      call NEWPEN(2)
      call LINEX(0.0,-F*0.2,0.0,F*0.2)
      call NEWPEN(1)
      call AROHD(-F*0.2,F*0.2,-F*0.1,F*0.5,F*0.1,F*0.1,16)
      call AROHD(-F*0.1,F*0.15,-F*0.0,F*0.45,F*0.1,F*0.1,16)
      call JTEXT(-F*0.2,F*0.5,F*0.2,MSG,0.0,1,L)
      call PLOT(0.0,0.0,3)
      go to 9
!     Diode
    5 if (N.gt.0) call PLOT(0.0,0.0,2)
      call JTEXT(F*0.05,-F*0.25,F*0.5,'▼',90.0,1,-1)
      call NEWPEN(2)
      call LINEX(0.0,F*0.2,0.0,-F*0.2)
      call NEWPEN(1)
      call JTEXT(-F*0.8,F*0.5,F*0.2,MSG,0.0,1,L)
      call PLOT(0.0,0.0,3)
      go to 9
!     CCR
    6 if (N.gt.0) call PLOT(-F*0.8,0.0,2)
      call CIRCLO(0.0,0.0,0.0,360.0,F*0.3,F*0.3,0.0)
      call FRAME(-F*0.8,-F*0.4,F*0.8,F*0.4)
      call LINEX(-F*0.2,0.0,F*0.1,0.0)
      call JTEXT(F*0.3,-F*0.1,F*0.2,'▼',90.0,1,-1)
      call LINEX(-F*0.8,0.0,-F*0.3,0.0)
      call LINEX(F*0.8,0.0,F*0.3,0.0)
      call JTEXT(-F*FLOAT(L)*0.05,F*0.5,F*0.2,MSG,0.0,1,L)
      call PLOT(F*0.8,0.0,3)
    9 call ROTATE(0.0)
      call PLOT(-XP,-YP,-3)
      if (NN.le.2) call PLOT(XP,YP,3)
      return
      end

・参考

図形ルーチンとは直接関係ありませんが,例示した電子回路を搭載した実物を紹介します。レール幅 6.5mmのNjゲージです。



TOPページに戻る