Skip to content

Commit 10c848c

Browse files
committed
first example codes: draw julia set
1 parent b3cbc39 commit 10c848c

File tree

7 files changed

+280
-0
lines changed

7 files changed

+280
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
book
2+
build
3+
*.mod

sample_codes/README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# 现代Fortran程序设计的随书代码
2+
3+
## 代码风格
4+
一般情况下,本书中的Fortran代码将遵守如下代码风格。
5+
6+
* 对module中的变量与过程通过`private`/`public`对可见性进行限定。
7+
```fortran
8+
module m
9+
implicit none
10+
private
11+
public :: a, x
12+
13+
integer, parameter :: a = 1
14+
integer, dimension(:), allocatable :: x
15+
real :: b ! b is private
16+
17+
end module
18+
```
19+
*`use`导入module时严格用`only`限定导入内容。
20+
```fortran
21+
use m, only: a
22+
```
23+
*`dimension`属性定义数组。
24+
* 定义变量时显式写出`len`/`kind`
25+
* 命名使用小写字母和下划线。
26+
* 缩进为四个空格。

sample_codes/chapter2/app/main.f90

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
program main
2+
use iso_fortran_env, only: real32
3+
use julia_set_m, only: generate_julia_set, draw_julia_set
4+
use save_julia_set_image, only: julia_set_image
5+
implicit none
6+
integer, parameter :: width = 80
7+
integer, parameter :: height = 50
8+
integer, dimension(height, width) :: julia_set
9+
complex(real32), parameter :: c = (-0.835, -0.2321)
10+
11+
call generate_julia_set(julia_set, -1.5, 1.5, -1., 1., c, 1000)
12+
13+
call draw_julia_set(julia_set)
14+
15+
call julia_set_image(julia_set)
16+
17+
end program main

sample_codes/chapter2/fpm.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name = "chapter2"
2+
version = "0.1.0"
3+
license = "license"
4+
author = "Jane Doe"
5+
maintainer = "[email protected]"
6+
copyright = "Copyright 2021, Jane Doe"
7+
[build]
8+
auto-executables = true
9+
auto-tests = true
10+
auto-examples = true
11+
[install]
12+
library = false

sample_codes/chapter2/src/bmp_m.f90

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
module bmp_m
2+
use iso_fortran_env, only: i2 => int16, i4 => int32
3+
use iso_c_binding, only: c_char
4+
implicit none
5+
private
6+
public :: save_bmp
7+
8+
integer(kind=i2), parameter :: BMP_HEADER_SIGNATURE = int(z'4D42', i2) ! 'BM' in ASCII
9+
10+
type :: bmp_file_head
11+
integer(kind=i4) :: file_size ! size of BMP file, in byte (54 + pixel array)
12+
integer(kind=i2) :: reserve1 ! not used
13+
integer(kind=i2) :: reserve2 ! not used
14+
integer(kind=i4) :: offset_pixel ! starting position of pixel array
15+
end type
16+
17+
type :: dib_head
18+
integer(kind=i4) :: dib_size ! size of DIB, 40 bytes
19+
integer(kind=i4) :: bmp_width ! image width, in pixel
20+
integer(kind=i4) :: bmp_height ! image height, in pixel
21+
integer(kind=i2) :: num_planes
22+
integer(kind=i2) :: bit_per_pixel ! only 24 is available
23+
integer(kind=i4) :: compress ! 0, do not compress
24+
integer(kind=i4) :: image_size ! size of BMP image, in byte
25+
integer(kind=i4) :: x_ppm ! x pixel per meter
26+
integer(kind=i4) :: y_ppm ! y pixel per meter
27+
integer(kind=i4) :: num_colors ! colors in color table
28+
integer(kind=i4) :: important_color
29+
end type
30+
31+
contains
32+
33+
function save_bmp(image, file_name) result(stat)
34+
character(kind=c_char), dimension(:,:,:), intent(in) :: image
35+
character(len=*), intent(in) :: file_name
36+
logical :: stat
37+
!===================================================
38+
type(bmp_file_head) :: header
39+
type(dib_head) :: dib
40+
41+
integer(kind=i4) :: row_size
42+
integer :: unit, ierr, i
43+
44+
stat = .false.
45+
46+
if (size(image, dim=1) /= 3) return
47+
48+
header%offset_pixel = 54
49+
header%reserve1 = 0
50+
header%reserve2 = 0
51+
52+
dib%bit_per_pixel = 24
53+
dib%bmp_width = size(image, dim=2)
54+
dib%bmp_height = size(image, dim=3)
55+
dib%compress = 0
56+
dib%dib_size = 40
57+
58+
dib%important_color = 0
59+
dib%num_colors = 0
60+
dib%num_planes = 1
61+
dib%x_ppm = 3780
62+
dib%y_ppm = 3780
63+
64+
row_size = ceiling(dib%bit_per_pixel * dib%bmp_width / 32., kind=i4) * 4
65+
dib%image_size = dib%bmp_height * row_size
66+
header%file_size = 54 + dib%image_size
67+
68+
open(newunit=unit, file=file_name, iostat=ierr, access="stream", &
69+
form="unformatted", action="write", status="unknown")
70+
if (ierr /= 0) return
71+
72+
write(unit) BMP_HEADER_SIGNATURE
73+
write(unit) header
74+
write(unit) dib
75+
76+
do i = 0, dib%bmp_height-1
77+
write(unit, pos=header%offset_pixel+i*row_size+1) image(:,:,i+1)
78+
end do
79+
80+
if (mod(dib%bmp_width, 4) /= 0) then
81+
write(unit, pos=header%offset_pixel+dib%bmp_height*row_size) char(0, c_char)
82+
end if
83+
84+
close(unit)
85+
86+
stat = .true.
87+
88+
end function save_bmp
89+
90+
end module bmp_m
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
module julia_set_m
2+
use iso_fortran_env, only: real32
3+
implicit none
4+
private
5+
public :: generate_julia_set, draw_julia_set
6+
7+
contains
8+
9+
function julia_point(z0, c, max_iter) result(n)
10+
complex(real32), intent(in) :: z0
11+
complex(real32), intent(in) :: c
12+
integer, intent(in) :: max_iter
13+
integer :: n
14+
15+
! local variables
16+
complex(real32) :: z
17+
18+
z = z0
19+
do n = 1, max_iter
20+
z = z**2 + c
21+
if (abs(z) > 2.) exit ! z must diverge when |z| > 2
22+
end do
23+
24+
end function julia_point
25+
26+
27+
subroutine generate_julia_set(set, xmin, xmax, ymin, ymax, c, max_iter)
28+
integer, dimension(:,:), intent(inout) :: set
29+
real(real32), intent(in) :: xmin, xmax
30+
real(real32), intent(in) :: ymin, ymax
31+
complex(real32), intent(in) :: c
32+
integer, intent(in) :: max_iter
33+
34+
! local variables
35+
integer :: i, j
36+
real(real32) :: xstep, ystep
37+
complex(real32) :: z
38+
39+
xstep = (xmax - xmin) / (size(set, dim=2) - 1)
40+
ystep = (ymax - ymin) / (size(set, dim=1) - 1)
41+
42+
do j = 1, size(set, dim=1)
43+
do i = 1, size(set, dim=2)
44+
z = complex(xmin + (i - 1) * xstep, ymin + (j - 1) * ystep)
45+
set(j, i) = julia_point(z, c, max_iter)
46+
end do
47+
end do
48+
49+
end subroutine generate_julia_set
50+
51+
52+
subroutine draw_julia_set(set)
53+
integer, dimension(:,:), intent(in) :: set
54+
55+
! local variables
56+
character(len=size(set, dim=2)) :: row
57+
integer :: i, j
58+
59+
do j = 1, size(set, dim=1)
60+
do i = 1, size(set, dim=2)
61+
select case (set(j, i))
62+
case (1)
63+
row(i:i) = ' '
64+
case (2:5)
65+
row(i:i) = '.'
66+
case (6:10)
67+
row(i:i) = ':'
68+
case (11:15)
69+
row(i:i) = '*'
70+
case (16:20)
71+
row(i:i) = 'x'
72+
case (21:)
73+
row(i:i) = '#'
74+
case default
75+
write(*, "(a)") "Error: wrong value in set"
76+
stop
77+
end select
78+
end do
79+
write(*, "(A)") row
80+
end do
81+
82+
end subroutine draw_julia_set
83+
84+
end module julia_set_m
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module save_julia_set_image
2+
use iso_fortran_env, only: int8
3+
use iso_c_binding, only: c_char
4+
use bmp_m, only: save_bmp
5+
implicit none
6+
private
7+
public :: julia_set_image
8+
9+
contains
10+
11+
subroutine julia_set_image(set)
12+
integer, dimension(:,:), intent(in) :: set
13+
14+
! local variables
15+
character(kind=c_char), dimension(:,:,:), allocatable :: image
16+
integer :: pixel
17+
integer(kind=int8) :: red, green, blue
18+
integer :: width, height
19+
integer :: i, j
20+
21+
height = size(set, dim=1)
22+
width = size(set, dim=2)
23+
24+
allocate(image(3,width,height))
25+
26+
do j = 1, height
27+
do i = 1, width
28+
! the pixel order in BMP is from left to right, from bottom to top
29+
pixel = set(height-j+1,i)
30+
if (pixel > 1000) then
31+
red = 0
32+
green = 0
33+
blue = 0
34+
else
35+
red = int(min(255, pixel*10), kind=int8)
36+
green = int(min(255, pixel*5), kind=int8)
37+
blue = int(min(255, pixel*2), kind=int8)
38+
end if
39+
image(1,i,j) = char(red, kind=c_char)
40+
image(2,i,j) = char(green, kind=c_char)
41+
image(3,i,j) = char(blue, kind=c_char)
42+
end do
43+
end do
44+
45+
if (.not. save_bmp(image, "julia_set.bmp")) write(*,*) "Error saving image"
46+
47+
end subroutine julia_set_image
48+
49+
end module save_julia_set_image

0 commit comments

Comments
 (0)