fortran66のブログ

fortran について書きます。

【メモ帳】Rust でも阿部さん

Rust で BMP

阿部さんを描くまで拡張したが、未だ引数寿命の指定を求められていないので、まだ入り口にも達しない。

関数型言語は一般に型に神経質で混合演算を許さないが、Rust もその流れを汲むので FORTRAN66 以前に戻ったような趣き。王莽が周礼によって政治を行おうとするがごときか。子曰、周監於二代、郁郁乎文哉、吾從周。(八佾篇 第十四章)

郁郁乎といえば阿素湖素子。

やけくそ天使 (1) (秋田文庫)

やけくそ天使 (1) (秋田文庫)

やけくそ天使 (2) (秋田文庫)

やけくそ天使 (2) (秋田文庫)

やけくそ天使 (3) (秋田文庫)

やけくそ天使 (3) (秋田文庫)

一般論として、rust 的な変数ロックの掛け方だと、task parallel には向いているが、Fortran でやるような超大きい配列を手分けして計算する data parallel には向いていないような感じを受ける。まぁ何とかなるだろうが、気持ち自然にはいかない気がする(よく考えていないw)。

追記:R3-4-30 配列を排他的な領域のスライスに分けることで、同時アクセス可能だそうです。ヘリはどうするのか、なんかあるんでしょうね。

Rustプログラミング入門

Rustプログラミング入門

実行結果

f:id:fortran66:20210417215304p:plain

プログラム

use std::fs::File;
use std::io::{Write, BufWriter};
use std::io;

struct BmpFileHeader {
    bf_type: i16,       //'BM'
    bf_size: i32,       // file size in bytes
    bf_reserved1: i16,
    bf_reserved2: i16,
    bf_off_bits: i32
}

struct  BmpInfoHeader{
    bi_size: i32,             // Z'28' ! size of bmp_info_header ; 40bytes 
    bi_width: i32,
    bi_height: i32,
    bi_planes: i16,           // = 1 ! always 1
    bi_bit_count: i16,
    bi_compression: i32,      // = 0 ! 0:nocompression, 1:8bitRLE, 2:4bitRLE, 3:bitfield
    bi_size_image: i32,
    bi_x_pels_per_meter: i32, // = 3780 ! 96dpi
    bi_y_pels_per_meter: i32, // = 3780 ! 96dpi 
    bi_clr_used: i32,         // = 0
    bi_clr_important: i32     // = 0    
}

trait Wr {
   fn wr(&self, writer: &mut BufWriter<File>) -> io::Result<()>;
}

impl Wr for BmpFileHeader {
    fn wr(&self, writer: &mut BufWriter<File>) -> io::Result<()> {
        writer.write_all(&self.bf_type.to_le_bytes()      )?;
        writer.write_all(&self.bf_size.to_le_bytes()      )?;
        writer.write_all(&self.bf_reserved1.to_le_bytes() )?;
        writer.write_all(&self.bf_reserved2.to_le_bytes() )?;
        writer.write_all(&self.bf_off_bits.to_le_bytes()  )?;
        Ok(())
    }    
}

impl Wr for BmpInfoHeader{
    fn wr(&self, writer: &mut BufWriter<File>) -> io::Result<()> {
        writer.write_all(&self.bi_size.to_le_bytes()             )?;
        writer.write_all(&self.bi_width.to_le_bytes()            )?;
        writer.write_all(&self.bi_height.to_le_bytes()           )?;
        writer.write_all(&self.bi_planes.to_le_bytes()           )?;
        writer.write_all(&self.bi_bit_count.to_le_bytes()        )?;
        writer.write_all(&self.bi_compression.to_le_bytes()      )?;
        writer.write_all(&self.bi_size_image.to_le_bytes()       )?;
        writer.write_all(&self.bi_x_pels_per_meter.to_le_bytes() )?;
        writer.write_all(&self.bi_y_pels_per_meter.to_le_bytes() )?;
        writer.write_all(&self.bi_clr_used.to_le_bytes()         )?;
        writer.write_all(&self.bi_clr_important.to_le_bytes()    )?;
        Ok(())
    }
}


#[derive(Clone, Copy)]
struct Rgb {
    b: u8,
    g: u8,
    r: u8
}

struct Bmp {
    width: usize,
    height: usize,
    data: Box<[Rgb]>
}


impl Bmp {
    fn point(&mut self, ix: usize, iy: usize, color: Rgb) {
        let nx = self.width; 
        self.data[nx * iy + ix] = color;
    }

    fn line0(&mut self, ix0:i32, iy0:i32, ix1:i32, iy1:i32) {
        let nx = ix1 - ix0;
        let ny = iy1 - iy0;
        if nx.abs() < ny.abs() {
            let d = nx as f32 / ny as f32;
            for i in 0..ny.abs() {
                let x = ix0 as f32 + i as f32 * d * ny.signum() as f32; 
                let ix = x.round() as usize;
                let iy = (iy0 + i * ny.signum()) as usize;
                self.point(ix, iy, Rgb{r:0, g:0, b:0})
            } 
        } else {
            let d = ny as f32 / nx as f32;
            for i in 0..nx.abs() {
                let y = iy0 as f32 + i as f32 * d * nx.signum() as f32; 
                let iy = y.round() as usize;
                let ix = (ix0 + i * nx.signum()) as usize;
                self.point(ix, iy, Rgb{r:0, g:0, b:0})
            } 
        }
    }

    fn line(&mut self, x: f32, y: f32, ipen: i32) {
        static mut IX0: i32 = 0;
        static mut IY0: i32 = 0;
    
        const XN: f32 = 250.0;
        const YN: f32 = 180.0;
        const  F: f32 = 4.0;
        let ix = (F * x + XN) as i32;
        let iy = (F * y + YN) as i32;
        unsafe {
            if ipen == 1 {
                let jx = IX0;
                let jy = IY0;
                self.line0(jx, jy, ix, iy);
            }
            IX0 = ix;
            IY0 = iy;
        }
    }
}

trait Wri {
    fn wri(&self, filename: &str) -> io::Result<()>;
}
 
impl Wri for Bmp {
    fn wri(&self, filename: &str) -> io::Result<()> {
        let nx = self.width as i32;
        let ny = self.height as i32;
    
        let bfile_header = BmpFileHeader {bf_type: 0x4d42, bf_size: 14 + 40 + 0 + (3 * nx + (ny % 4)) * ny, bf_reserved1: 0, bf_reserved2: 0, bf_off_bits: 14 + 40};
        let binfo_header = BmpInfoHeader {bi_size: 0x28, bi_width: nx, bi_height: ny, bi_planes: 1, bi_bit_count: 24, bi_compression: 0,
                                          bi_size_image: (3 * nx + (ny % 4)) * ny, 
                                          bi_x_pels_per_meter: 3780, bi_y_pels_per_meter: 3780, bi_clr_used: 0, bi_clr_important: 0};

        let mut writer = BufWriter::new(File::create(filename)?);

        bfile_header.wr(&mut writer)?;
        binfo_header.wr(&mut writer)?; 
        for iy in 0..ny {
            for ix in 0..nx {
                let a = self.data[(nx * iy + ix) as usize];
                writer.write(&[a.b])?;
                writer.write(&[a.g])?;
                writer.write(&[a.r])?;
            }
        } 
        println!("write {}: {} x {}", &filename, nx, ny);
        Ok(())
    }
}


fn main() -> std::io::Result<()>  {
    const NX:usize = 500;
    const NY:usize = 600;
 
    let data = [Rgb{r:255, g:255, b:255}; NX * NY];
    let mut bmp = Bmp {
        width: NX,
        height: NY,
        data: Box::new(data)
    };

    // chin chin
    bmp.line(  0.0,  11.0, 0);
    bmp.line(  0.0,   8.0, 1);    

    bmp.line( -8.0, -26.5, 0);
    bmp.line(-11.0, -24.0, 1);
    bmp.line(  8.0, -26.5, 0);
    bmp.line( 11.0, -24.0, 1);    

    bmp.line(  5.5, -26.0, 0);
    bmp.line(  2.0, -36.0, 1);
    bmp.line( -5.5, -26.0, 0);
    bmp.line( -2.0, -36.0, 1);    

    bmp.line( 20.0, -18.0, 0);
    bmp.line(  8.5, -19.0, 1);
    bmp.line(  4.0, -21.5, 1);
    bmp.line(  0.0, -23.0, 1);
    bmp.line( -4.0, -21.5, 1);
    bmp.line( -8.5, -19.0, 1);
    bmp.line(-20.0, -18.0, 1);    

    bmp.line( 12.0, -16.0, 0);
    bmp.line( 22.0,  14.0, 1);
    bmp.line(-12.0, -16.0, 0);
    bmp.line(-22.0,  14.0, 1);
     
    bmp.line( 53.0,  -9.0, 0);
    bmp.line( 28.5,   1.0, 1);
    bmp.line( 28.5, -14.0, 0);
    bmp.line( 28.5,  25.0, 1);
    bmp.line( 28.5,  33.0, 0);
    bmp.line( 28.5,  76.0, 1);
    bmp.line( -2.5,  76.0, 1);
    bmp.line( -2.5,  72.0, 1);
    bmp.line( -0.5,  68.0, 1);
    bmp.line(  1.0,  66.0, 1);
    bmp.line( -1.5,  67.0, 1);
    bmp.line( -4.0,  72.0, 1);
    bmp.line( -4.0,  76.0, 1);
    bmp.line(-28.5,  76.0, 1);
    bmp.line(-28.5,  33.0, 1);    

    bmp.line(-28.5,  25.0, 0);
    bmp.line(-28.5, -14.0, 1);
    bmp.line(-53.0,  -9.0, 0);
    bmp.line(-28.5,   1.0, 1);     

    bmp.line(  0.0,   0.0, 0);
    bmp.line(  6.5,   0.0, 1);
    bmp.line( 10.0,   3.0, 1);
    bmp.line( 15.0,   7.0, 1);
    bmp.line( 22.0,  14.0, 1);
    bmp.line( 28.5,  25.0, 1);
    bmp.line( 31.0,  26.0, 1);
    bmp.line( 35.0,  34.0, 1);
    bmp.line( 38.0,  44.0, 1);
    bmp.line( 38.0,  53.0, 1);
    bmp.line( 36.0,  55.0, 1);
    bmp.line( 32.0,  55.0, 1);
    bmp.line( 28.5,  51.0, 1);    

    bmp.line(  0.0,   0.0, 0);
    bmp.line( -6.5,   0.0, 1);
    bmp.line(-10.0,   3.0, 1);
    bmp.line(-15.0,   7.0, 1);
    bmp.line(-22.0,  14.0, 1);
    bmp.line(-28.5,  25.0, 1);
    bmp.line(-31.0,  26.0, 1);
    bmp.line(-35.0,  34.0, 1);
    bmp.line(-38.0,  44.0, 1);
    bmp.line(-38.0,  53.0, 1);
    bmp.line(-36.0,  55.0, 1);
    bmp.line(-32.0,  55.0, 1);
    bmp.line(-28.5,  51.0, 1);    

    bmp.line( 34.0,  55.0, 0);
    bmp.line( 34.0,  76.0, 1);
    bmp.line( 31.0,  82.0, 1);
    bmp.line( 26.0,  87.0, 1);
    bmp.line( 21.0,  91.0, 1);
    bmp.line( 15.0,  95.0, 1);
    bmp.line(  0.0,  95.0, 1);    

    bmp.line(-34.0,  55.0, 0);
    bmp.line(-34.0,  76.0, 1);
    bmp.line(-31.0,  82.0, 1);
    bmp.line(-26.0,  87.0, 1);
    bmp.line(-21.0,  91.0, 1);
    bmp.line(-15.0,  95.0, 1);
    bmp.line(  0.0,  95.0, 1);    

    // nose
    bmp.line( -5.0, 41.0, 0);
    bmp.line( -4.0, 40.0, 1);
    bmp.line(  0.0, 40.0, 1);
    bmp.line(  2.0, 42.0, 1);
    bmp.line(  3.0, 42.0, 1);
    bmp.line(  5.5, 37.0, 1);
    bmp.line(  5.0, 37.0, 1);
    bmp.line(  4.0, 38.5, 1);
    bmp.line(  0.5, 38.5, 1);
    bmp.line(  0.0, 37.0, 1);
    bmp.line( -2.0, 37.0, 1);
    bmp.line( -3.0, 38.5, 1);
    bmp.line( -7.0, 38.5, 1);
    bmp.line( -8.0, 37.0, 1);
    bmp.line( -8.5, 40.0, 1);
    bmp.line( -4.0, 45.0, 1);
    bmp.line( -4.0, 54.0, 1);
    bmp.line( -5.0, 55.0, 1);    

    bmp.line( -6.0, 53.0, 0);
    bmp.line( -5.0, 53.0, 1);
    bmp.line( -5.0, 47.0, 1);
    bmp.line( -7.5, 46.0, 1);
    bmp.line( -6.0, 53.0, 1);    

    // left eye
    bmp.line(-24.0, 55.0, 0);
    bmp.line(-22.0, 53.0, 1);
    bmp.line(-17.0, 54.5, 1);
    bmp.line( -8.0, 55.0, 1);
    bmp.line( -7.0, 55.5, 1);
    bmp.line( -8.5, 56.5, 1);
    bmp.line(-24.0, 55.0, 1);    

    bmp.line( -8.0, 54.5, 0);
    bmp.line(-12.0, 52.5, 1);    

    bmp.line(-23.0, 56.0, 0);
    bmp.line(-21.5, 57.0, 1);
    bmp.line(-10.0, 58.0, 1);
    bmp.line( -9.0, 57.0, 1);    

    // left eyebrow
    bmp.line(-27.5, 56.5, 0);
    bmp.line(-24.0, 59.0, 1);
    bmp.line(-11.0, 59.5, 1);
    bmp.line( -7.0, 61.0, 1);
    bmp.line( -4.0, 65.0, 1);
    bmp.line( -9.0, 63.0, 1);
    bmp.line(-25.0, 62.0, 1);
    bmp.line(-27.5, 56.5, 1);    

    // right eyebrow
    bmp.line( 27.5, 56.5, 0);
    bmp.line( 24.0, 59.0, 1);
    bmp.line( 11.0, 59.5, 1);
    bmp.line(  7.0, 61.0, 1);
    bmp.line(  4.0, 65.0, 1);
    bmp.line(  9.0, 63.0, 1);
    bmp.line( 25.0, 62.0, 1);
    bmp.line( 27.5, 56.5, 1);    

    // right eye
    bmp.line( 19.0, 53.0, 0);
    bmp.line( 23.0, 55.0, 1);
    bmp.line( 16.0, 55.0, 1);
    bmp.line(  9.0, 56.0, 1);
    bmp.line(  9.5, 55.0, 1);
    bmp.line( 19.0, 53.0, 1);    

    bmp.line(  9.0, 58.0, 0);
    bmp.line( 12.0, 58.0, 1);
    bmp.line( 19.0, 56.0, 1);
    bmp.line( 21.5, 56.0, 1);    

    bmp.line(  0.0, 29.0, 0);
    bmp.line(  5.0, 29.0, 1);
    bmp.line( 11.0, 27.0, 1);
    bmp.line(  6.0, 32.0, 1);
    bmp.line(  0.0, 30.0, 1);
    bmp.line( -6.0, 32.0, 1);
    bmp.line(-11.0, 27.0, 1);
    bmp.line( -5.0, 29.0, 1);
    bmp.line(  0.0, 29.0, 1);    

    bmp.line(-6.5, 21.5, 0);
    bmp.line(-3.5, 20.0, 1);
    bmp.line( 3.5, 20.0, 1);
    bmp.line( 6.5, 21.5, 1);
    bmp.line(-5.0, 21.0, 0);
    bmp.line( 5.0, 21.0, 1);

    let filename = "test.bmp";
    bmp.wri(filename)
}