ぬの部屋(仮)
nu-no-he-ya
  • 1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • Rustでthreadpoolクレートでスレッドプールを使う

    Rustでスレッドプールを使う場合、threadpoolクレートが有名らしい。

    https://crates.io/crates/threadpool

    使用例

    [dependencies]
    threadpool = "1.8.1"
    use threadpool::ThreadPool;
    
    fn main() {
    
        // スレッドを四枚作成
        let pool = threadpool::ThreadPool::new(4);
    
        // テスト用データ
        let myarray = std::sync::Arc::new(std::sync::Mutex::new(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
    
        for i in 0..10{
    
            // myarrayは参照なので、cloneして参照を複製する
            // クロージャに渡すmoveキーワードによって、myarray2がクロージャにムーブされる
            let array2 = myarray.clone();
    
            // スレッドプールにジョブを追加
            pool.execute(move || {
    
                let mut data  = array2.lock().unwrap();
                data[i] *= 2;
    
            } );
    
        }
    
        // スレッドの終了を待つ
        pool.join();
    
        // 結果を表示
        let data = myarray.lock().unwrap();
        println!("{:?}", data);    
    
    }
    

    channel()と併用してみる

    channel()を使って各ジョブの結果を送信できる。

    use threadpool::ThreadPool;
    
    // チャンネルを使うために必要
    use std::sync::mpsc::channel;
    
    fn main() {
    
        // スレッドを四枚作成
        let pool = threadpool::ThreadPool::new(4);
    
        // スレッドで処理した結果を受け取るためのチャンネルを作成
        let (sender,receiver) = channel::<i32>();
    
        // テスト用データ
        let myarray = std::sync::Arc::new(std::sync::Mutex::new(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
    
        for i in 0..10{
    
            // myarrayは参照なので、cloneして参照を複製する
            // クロージャに渡すmoveキーワードによって、myarray2がクロージャにムーブされる
            let array2 = myarray.clone();
    
            let sender2 = sender.clone();
            // スレッドプールにジョブを追加
            pool.execute(move || {
    
                let mut data  = array2.lock().unwrap();
                data[i] *= 2;
    
                sender2.send(data[i]*10).unwrap(); // このジョブの結果をチャンネルに送信
            } );
    
        }
    
    
        // スレッドの終了を待つ
        pool.join();
    
        // 全ての処理が終わったら、チャンネルを閉じる
        drop(sender);
    
        // チャンネルから結果を受け取る
        for itr in receiver.iter(){
            print!("{} ", &itr);
        }
     
    
    }
    

    Daz Studio 4.21でフィギュアをBlenderへ移行

    Daz to Blender BridgeでBlenderへエクスポート可能だが、ポーズを正確に移行できないので、まずフィギュアだけをエクスポートし、Blender側でdufファイルをインポートする。

    導入

    Daz Studio 4.21で、[File] → [Send To] → [Daz to Blender]でエクスポートが可能だが、Blender側の準備が必要になる。一応使い方がダイアログ内に書いてある。

    ここで、使用するBlenderのバージョンを指定し、 Install Pluginをクリックする。

    Blender側では、DazToBlenderアドオンがリストにあるのでPreferenceから有効にする

    使用方法

    ポーズをプリセットから選択し、そのポーズをBlenderへエクスポートすることを考える。

    ポイントはフィギュアだけをエクスポートした後でポーズを適用すると成功する。

    Step 1. フィギュア読み込み、髪、服などの設定、エクスポート

    まずフィギュアを読み込み、服を着せ髪を乗せる。

    次に、[File] → [Send To] → [Daz to Blender]を開き、Acceptする。

    注意点として、フィギュアの頭だけ、髪だけという選択状態だと失敗する可能性があるので、何も選択しないか、フィギュア本体だけを選択しておく必要がある。

    Step 2. Blender側でインポート

    Blender側で、Daz To Blenderを有効にしていれば、画面右側にタブが増えているので、それを表示し、[Import New Genesis Figure]をクリックする

    Step 3. Daz Studio でポーズのプリセットの位置を特定

    Daz側に戻り、ポーズのプリセット一覧を表示する。使用したいポーズを見つけたら右クリックし、[Browse to File Location...]を選択、エクスプローラで表示する。

    該当ポーズがあるパスとファイル名がわかったら、Blender側に戻る。

    Step 4. Blender側でポーズをインポート

    [Import Pose]をクリックし、ファイル読み込みダイアログを開く。先ほど調べたパスへ移動し、ファイル名を探して選択、[Import Pose]をクリックする。

    テスト

    レンダリングしてみる。概ねフィットしているが服が飛び出している部分がある。

    Rustのfunction-likeマクロについて

    println!のように、関数のように呼び出すマクロをfunction-likeマクロというらしい。

    マクロを定義するとき、

    • macro_rules! マクロ名 { } で定義する
    • $引数名 で引数を表す。
    • $expr は引数の種類を表す。式を表す$exprの他に、パターンを表す$pat等たくさんある。

     

    例えばこんな感じ。

    macro_rules! マクロ名 {
        ($引数:expr) => {
            println!("引数を使う: {}", $引数);
        };
    }
    

    使用例。

    macro_rules! print_arg {
        ($arg:expr) => {
            println!("Argument: {}", $arg);
        };
    }
          
       
    fn main(){
        print_arg!(3.5);  // 出力:  Argument: 3.5
    }
    

    引数を二つ与えるとき

    macro_rules! print_arg {
    
    ($e1:expr, $e2:expr) =>{
    println!("e1: {} e2 {}", $e1,$e2);
    };
    }
    fn main(){ print_arg!(3.5 , "hello"); }

    引数を任意の個数渡すとき

    macro_rules! print_arg {
        ( $($arg:expr) , * ) => {
    
            $(
                println!("Argument: {}", $arg);
            ) *
            
        };
    }
    
    fn main(){
        print_arg!(3.5 , "hello" , 6);
        // Argument: 3.5
        // Argument: hello
        // Argument: 6
    }
    

    引数の型ごとに処理を変えたい場合

    trait MyPrint{
        fn print(&self);
    }

    impl MyPrint for i32{
        fn print(&self){
            println!("i32: {}", *self);
        }
    }
    impl MyPrint for f32{
        fn print(&self){
            println!("f32: {}", *self);
        }
    }
    
    
    macro_rules! print_arg {
        ($e:expr) =>{
            MyPrint::print(&$e);
        };
    }
    
    
    fn main(){
        print_arg!(3.5); // f32: 3.5
        print_arg!(100); // i32: 100
    }
    

    OpenGL 1.5 相当の機能でVBOありシェーダ指定なしで描画する(2) Index Bufferを使用

    Index Buffer使用時には、GL_ELEMENT_ARRAY_BUFFERをBindした後glDrawElementsを使用。

    glEnableClientStateで特別な指定をする必要はない。

    // バッファ名
    GLuint buffer[3];
    const int VTX = 0;
    const int COL = 1;
    const int IDX = 2;
    
    
    void init_data() {
    
      float v = 0.7;
      // 頂点データ
      std::vector< std::array<float,3> > vertex = {
        { 0.0f,  0.0f ,0.0f}, // 中心 (0)
        { 1.0f,  0.0f ,0.0f}, // 右中 (1)
        { 0.5f,  0.87f,0.0f}, // 右上 (2)
        {-0.5f,  0.87f,0.0f}, // 左上 (3)
        {-1.0f,  0.0f ,0.0f}, // 左中 (4)
        {-0.5f, -0.87f,0.0f}, // 左下 (5)
        { 0.5f, -0.87f,0.0f} // 右下 (6)
      };
    
      // 色データ
      std::vector< std::array<float, 3> > color = {
        {1.0f, 1.0f, 1.0f},
        {0.0f, 1.0f, 0.0f},
        {0.0f, 0.0f, 1.0f},
        {1.0f, 1.0f, 0.0f},
        {1.0f, 0.0f, 1.0f},
        {0.0f, 1.0f, 1.0f},
        {0.5f, 0.5f, 0.5f}
      };
    
      // インデックスデータ
      std::vector< std::array<GLuint, 3> > index = {
      { 0, 1, 2 },
      { 0, 2, 3 },
      { 0, 3, 4 },
      { 0, 4, 5 },
      { 0, 5, 6 },
      { 0, 6, 1 }
      };
    
      // バッファ作成
      glGenBuffers(3, &buffer[0]);
      ///////////////////////////////////////////
      // 頂点バッファの作成
      glBindBuffer(GL_ARRAY_BUFFER, buffer[VTX]);
      glBufferData(
        GL_ARRAY_BUFFER,
        sizeof(GLfloat) * 3 * vertex.size(),
        vertex[0].data(),
        GL_STATIC_DRAW);
      ///////////////////////////////////////////
      // 色バッファの作成
      glBindBuffer(GL_ARRAY_BUFFER, buffer[COL]);
      glBufferData(
        GL_ARRAY_BUFFER,
        sizeof(GLfloat) * 4 * color.size(),
        color[0].data(),
        GL_STATIC_DRAW);
      ///////////////////////////////////////////
      // インデックスバッファの作成
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[IDX]);
      glBufferData(
        GL_ELEMENT_ARRAY_BUFFER,
        sizeof(GLuint) * 3 * index.size(),
        index[0].data(),
        GL_STATIC_DRAW
      );
    
    }
    

    void render_data() {
      glEnableClientState(GL_COLOR_ARRAY);  // 色配列を有効化
      glEnableClientState(GL_VERTEX_ARRAY); // 頂点配列を有効化
    
      // 頂点配列を有効化
      glBindBuffer(GL_ARRAY_BUFFER, buffer[VTX]);
      glVertexPointer(3, GL_FLOAT, 0, 0);
    
      // 色配列を有効化
      glBindBuffer(GL_ARRAY_BUFFER, buffer[COL]);
      glColorPointer(4, GL_FLOAT, 0, 0);
    
      // インデックス配列を有効化
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[IDX]);
    
      // 描画
      glDrawElements(GL_TRIANGLES, 6*3/*6頂点。各頂点3要素*/, GL_UNSIGNED_INT, 0);
    
      // 頂点配列を無効化
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }
    

    void finalizer() {
      glDeleteBuffers(3, buffer);
    }
    

    OpenGL 1.5 相当の機能でVBOありシェーダ指定なしで描画する

    Vertex Buffer Objectが導入されたのはOpenGL 1.5からで、この時はシェーダの指定が必要なかったとのこと。別にシェーダを用意するのもテストでは面倒なのでありがたい。

    基本的な使い方

    glEnableClientStateで使用するバッファの種類を指定。glBindBufferした後glVertexPointerする。

    glVertexPointerの最後の「0」はCPUメモリ上のバッファのポインタを入れるが、0を指定すると使用する頂点バッファがバインドしたバッファになる。

    #include <Windows.h>
    #include <GL/glew.h>
    
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    #include <vector>
    #include <array>
    
    #pragma comment(lib, "opengl32.lib")
    #pragma comment(lib, "glew32.lib")
    
    //ウィンドウの幅と高さ
    int width, height;
    
    double rotate_angle = 0;
    
    // バッファ名
    GLuint buffer;
    

    void init_data() {
      glEnableClientState(GL_VERTEX_ARRAY);
    
      float v = 0.7;
      std::vector< std::array<float,3> > data;
      data.push_back({ 0.f,0.f,0.f });
      data.push_back({ -v,-v,0 });
      data.push_back({ v,-v,0 });
    
      glGenBuffers(1, &buffer);
      glBindBuffer(GL_ARRAY_BUFFER, buffer);
      glBufferData(
        GL_ARRAY_BUFFER,
        sizeof(GLfloat) * 3 * data.size(),
        data[0].data(),
        GL_STATIC_DRAW);
      glVertexPointer(3, GL_FLOAT, 0, 0);
    
    }
    

    void render_data() {
      glColor3f(1, 0, 0);
      // バッファのデータと関連づけ
      glBindBuffer(GL_ARRAY_BUFFER, buffer);
      glVertexPointer(3, GL_FLOAT, 0, 0);
      // 描画
      glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
    }
    
    //描画関数
    void disp(void) {
    
      glClearColor(0.2, 0.2, 0.2, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glViewport(0, 0, width, height);
      //カメラの設定
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective(60, width / (double)height, 0.1, 3);
      glMatrixMode(GL_MODELVIEW);//モデルビューの設定
      glLoadIdentity();
      glTranslated(0, 0, -2);
      glRotated(rotate_angle, 0, 1, 0);
    
      ////////////////////////////////////////////
      render_data();
      ////////////////////////////////////////////
    
    
      glFlush();
    }
    

    void finalizer() {
      glDeleteBuffers(1, &buffer);
    }
    
    
    //ウィンドウサイズの変化時に呼び出される
    void reshape(int w, int h) {
      width = w; height = h;
    
      disp();
    }
    
    void timer(int value)
    {
      rotate_angle += 5;
    
      disp();
      glutTimerFunc(10, timer, 0);
    }
    
    //エントリポイント
    int main(int argc, char** argv)
    {
      glutInit(&argc, argv);
      glutInitWindowPosition(100, 50);
      glutInitWindowSize(500, 500);
      glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    
      glutCreateWindow("sample");
    
      glewInit();
      init_data();
    
    
      glutDisplayFunc(disp);
      glutReshapeFunc(reshape);
      glutTimerFunc(1000, timer, 0);//タイマー
      glutMainLoop();
    
    finalizer();
    return 0; }

    頂点色も使用する例

    glBindBuffer → glVertexPointer で、バインドしたバッファを頂点座標に使用することを教える。

    glBindBuffer → glColorPointer で、バインドしたバッファを頂点色に使用することを教える。

    #include <Windows.h>
    #include <GL/glew.h>
    
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    #include <vector>
    #include <array>
    
    #pragma comment(lib, "opengl32.lib")
    #pragma comment(lib, "glew32.lib")
    
    //ウィンドウの幅と高さ
    int width, height;
    
    double rotate_angle = 0;
    
    // バッファ名
    GLuint buffer[2];
    const int VTX = 0;
    const int COL = 1;
    
    
    void init_data() {
    
      float v = 0.7;
      // 頂点データ
      std::vector< std::array<float,3> > vertex;
      vertex.push_back({ 0,0,0 });
      vertex.push_back({ -v,-v,0 });
      vertex.push_back({ v,-v,0 });
    
      // 色データ
      std::vector< std::array<float, 4> > color;
      color.push_back({ 1,0,0,1 });
      color.push_back({ 0,1,0,1 });
      color.push_back({ 0,0,1,1 });
    
      // バッファ作成
      glGenBuffers(2, &buffer[0]);
      ///////////////////////////////////////////
      glBindBuffer(GL_ARRAY_BUFFER, buffer[VTX]);
      glBufferData(
        GL_ARRAY_BUFFER,
        sizeof(GLfloat) * 3 * vertex.size(),
        vertex[0].data(),
        GL_STATIC_DRAW);
      ///////////////////////////////////////////
      glBindBuffer(GL_ARRAY_BUFFER, buffer[COL]);
      glBufferData(
        GL_ARRAY_BUFFER,
        sizeof(GLfloat) * 4 * color.size(),
        color[0].data(),
        GL_STATIC_DRAW);
      ///////////////////////////////////////////
    
    }
    

    void render_data() {
      glEnableClientState(GL_COLOR_ARRAY);  // 色配列を有効化
      glEnableClientState(GL_VERTEX_ARRAY); // 頂点配列を有効化
    
      // 頂点配列を有効化
      glBindBuffer(GL_ARRAY_BUFFER, buffer[VTX]);
      glVertexPointer(3, GL_FLOAT, 0, 0);
    
      // 色配列を有効化
      glBindBuffer(GL_ARRAY_BUFFER, buffer[COL]);
      glColorPointer(4, GL_FLOAT, 0, 0);
    
      // 有効化の設定ここまで
      glBindBuffer(GL_ARRAY_BUFFER, 0);
    
      // 描画
      glDrawArrays(GL_TRIANGLES, 0, 3);
    }
    

    //描画関数
    void disp(void) {
    
      glClearColor(0.2, 0.2, 0.2, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glViewport(0, 0, width, height);
      //カメラの設定
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective(60, width / (double)height, 0.1, 3);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glTranslated(0, 0, -2);
      glRotated(rotate_angle, 0, 1, 0);
    
      ////////////////////////////////////////////
      render_data();
      ////////////////////////////////////////////
    
    
      glFlush();
    }
    void finalizer() {
      glDeleteBuffers(2, buffer);
    }
    

    実行するとgluPerspectiveやglTranslated,glRotatedでの指定で三角形が回転する。

    参考

    算譜記録帳

    http://mklearning.blogspot.com/2014/08/opengl.html

    床井研究

    https://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20080829

    矩形をxmlで再帰的に分割(2)

    前回矩形を分割するプログラムを書いたのだが、親要素に対する割合でしか指定するように作っていなかったことに気づいた。なのでピクセル単位での指定もできるようにした。

    #include <windows.h>
    
    #include <iostream>
    #include <string>
    #include <vector>
    #include <pugixml.hpp>
    #include <functional>
    
    // 領域の計算方法
    enum class SizeType {
      RATIO, // 親要素に対する割合で指定
      PIXEL, // ピクセル数で指定
      AUTO,  // 余っているサイズから自動計算
    };
    
    // 子要素の配置方法
    enum class Arrangement {
      Horizonal,
      Vertical,
    };
    
    // 各情報を元に計算される実際のサイズ。sx,sy, ex,eyは矩形の最小、最大を表すピクセル座標
    struct Rect {
      int sx, sy;
      int ex, ey;
    };
    
    struct BOX {
      SizeType sizeType;     // この領域のサイズの指定方法
      Arrangement type;      // 子要素の配置方法
      Rect rect;         // この領域の矩形
      std::string name;      // この領域の名前
      // ratioとpixelはどちらか一方が指定される
      double ratio;        // この領域が親要素のどれだけの割合を占めるか
      int pixel;         // この領域が親要素のどれだけのピクセルを占めるか
      std::vector<BOX> children; // 子要素
    };
    
    
    // xmlファイルの内容を解析してノード作成
    void parseNode(const pugi::xml_node& xmlNode, BOX& node) {
    
      // BOXの名前を取得
      node.name = xmlNode.attribute("name").as_string("");
      // BOXの親要素に対する割合を取得。指定がない場合はNaNにしておいて、自動計算する
      node.ratio = xmlNode.attribute("ratio").as_double( std::numeric_limits<double>::quiet_NaN()   );
      node.pixel = xmlNode.attribute("pixel").as_int(-1);
    
      const auto& attr_ratio = xmlNode.attribute("ratio");
      const auto& attr_pixel = xmlNode.attribute("pixel");
      // "ratio" および "pixel" が存在しない場合はAUTO
      if (attr_ratio.empty() && attr_pixel.empty() ) {
        node.sizeType = SizeType::AUTO;
      }
      // "ratio" が存在し、かつ内容が"auto"であればAUTO
      else if (!attr_ratio.empty() && std::string(attr_ratio.as_string()) == "auto") {
        node.sizeType = SizeType::AUTO;
      }
      // "pixel" が存在し、かつ内容が"auto"であればAUTO
      else if (!attr_ratio.empty() && std::string(attr_pixel.as_string()) == "auto") {
        node.sizeType = SizeType::AUTO;
      }
      else if (!attr_ratio.empty()) {
        node.sizeType = SizeType::RATIO;
      }
      else if (!attr_pixel.empty()) {
        node.sizeType = SizeType::PIXEL;
      }
      else {
        node.sizeType = SizeType::AUTO;
      }
    
    
      // 配置方法を取得。デフォルトをverticalとしておく。
      std::string arrangement = xmlNode.attribute("arrangement").as_string("vertical");
      node.type = (arrangement == "horizonal") ? Arrangement::Horizonal : Arrangement::Vertical;
    
      // 子要素を再帰的に解析
      for (pugi::xml_node child = xmlNode.first_child(); child; child = child.next_sibling()) {
        BOX childNode;
        parseNode(child, childNode);
        node.children.push_back(childNode);
      }
    }
    

    // xmlファイルからレイアウト情報を読み込む
    BOX LoadLayout(const char* xmlfilename) {
      pugi::xml_document doc;
      pugi::xml_parse_result result = doc.load_file(xmlfilename);
    
      // ファイルが読み込めなかったら例外を投げる
      if (!result) {
        throw std::runtime_error("xmlファイルが読み込めませんでした");
      }
    
      BOX rootNode;
      pugi::xml_node root = doc.child("box");
      parseNode(root, rootNode);
    
      return rootNode;
    }
    

    // UpdateLayout関数
    void UpdateLayout(BOX& node, const Rect& parent) {
      node.rect = parent;
      int totalWidth = parent.ex - parent.sx;
      int totalHeight = parent.ey - parent.sy;
    
      int total;
      if (node.type == Arrangement::Horizonal) {
        // 水平方向に並べる場合
        total = totalWidth;
      }
      else {
        total = totalHeight;
      }
    
      /////////////////////////////////
      // 親要素を占める割合の計算
      // ratioを省略可能としている
      // ratioが省略されたときは、その領域内の残りのratioを省略されたbox数で割る
    
      int undefinedRatioCount = 0; // ratioが定義されていないboxの個数
      size_t last_item_index;
      // まず、指示のある領域のサイズを計算する
      // タイプがpixelの場合は、そのままpixelを使う
      // タイプがratioの場合は、親要素の割合を使い、ピクセルに変換する
      // タイプが指定されていない場合は、その数をカウントし、childを記憶しておく
    
      // totalから確定したサイズを引いた残りをピクセルで計算
      int remainingPixel = total;
      std::vector<int> sizes(node.children.size());
      for (size_t child_id = 0; child_id < node.children.size(); child_id++) {
        switch (node.children[child_id].sizeType) {
        case SizeType::PIXEL:
          // pixelが指定されている場合はそのまま使う
          sizes[child_id] = node.children[child_id].pixel;
          remainingPixel -= node.children[child_id].pixel; // 残りのピクセル数を計算
          break;
        case SizeType::RATIO:
          sizes[child_id] = node.children[child_id].ratio * total;
          remainingPixel -= sizes[child_id]; // 残りのピクセル数を計算
          break;
        case SizeType::AUTO:
          sizes[child_id] = -1; // 未定義の場合は-1にしておく
          undefinedRatioCount++;
          last_item_index = child_id;
          break;
        }
      }
    
      // ratioが定義されていないノードがある場合は、使用可能な割合を等分する
      if (undefinedRatioCount > 0) {
    
        // 未定義のノードに割り当てる割合を計算
        // 残っている使えるピクセル数 / サイズ未定義のノード数
        const double equaldivision = (double)remainingPixel / (double)undefinedRatioCount;
    
        int sizesum = 0;
        // 全てのノードに割り当てた場合のピクセル数を計算
        for (size_t child_id = 0; child_id < node.children.size(); child_id++) {
          if (sizes[child_id] == -1) {
            sizesum += equaldivision;
          }
          else {
            sizesum += sizes[child_id];
          }
        }
        // 最後のノードで誤差を吸収
        // 分割したピクセル数の合計が親要素のピクセル数より大きければマイナスになる
        int lastitem_error = total - sizesum;
        // 実際にサイズを与える
        for (size_t child_id = 0; child_id < node.children.size(); child_id++) {
          if (sizes[child_id] == -1) {
            sizes[child_id] = equaldivision;
          }
        }
        sizes[last_item_index] += lastitem_error;
    
      }
    
      // 計算した長さを子要素の矩形に与える
      int offset=0;
      for (size_t child_id = 0; child_id < node.children.size(); child_id++) {
        auto& child = node.children[child_id];
    
        if (child_id == 0) {
          offset=0;
        }
        else {
          offset += sizes[child_id-1];
        }
    
        if (node.type == Arrangement::Horizonal) {
          child.rect.sx = parent.sx + offset;
          child.rect.ex = child.rect.sx + sizes[child_id];
          child.rect.sy = parent.sy;
          child.rect.ey = parent.ey;
        }
        else {
          child.rect.sy = parent.sy + offset;
          child.rect.ey = child.rect.sy + sizes[child_id];
          child.rect.sx = parent.sx;
          child.rect.ex = parent.ex;
        }
    
      }
    
      // 子要素の子要素の矩形を計算する
      for (auto& child : node.children) {
        UpdateLayout(child, child.rect);
      }
    }
    
    /////////////////////////////////////////
    /////////////////////////////////////////
    /////////////////////////////////////////
    /////////////////////////////////////////
    
    
    // 領域を描画
    void drawRects(HDC hdc, const BOX& node) {
      
      RECT rect = { node.rect.sx, node.rect.sy, node.rect.ex, node.rect.ey };
      
      // ランダムな色を作成
      int r = rand() % 256;
      int g = rand() % 256;
      int b = rand() % 256;
    
      if (node.type == Arrangement::Horizonal) {
    
        HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); // 1ピクセル幅のペンを作成
        HGDIOBJ oldPen = SelectObject(hdc, hPen); // ペンを選択
    
        // 矩形を描画
        Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
    
        SelectObject(hdc, oldPen); // 元のペンに戻す
        DeleteObject(hPen); // ペンを削除
      }
      else {
        // 塗りつぶした矩形
        HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b)); // ブラシを作成
        HGDIOBJ oldBrush = SelectObject(hdc, hBrush); // ブラシ
        Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
        SelectObject(hdc, oldBrush); // 元のブラシに戻す
        DeleteObject(hBrush); // ブラシを削除
      }
    
    
    
      for (const BOX& child : node.children) {
        drawRects(hdc, child);
      }
    }
    
    BOX rootArea;
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      HDC hdc;
      PAINTSTRUCT ps;
      RECT rect;
    
      switch (msg) {
      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
      case WM_CREATE:
        GetClientRect(hwnd, &rect);
        UpdateLayout(rootArea, Rect{ 0, 0, rect.right, rect.bottom });
        InvalidateRect(hwnd, nullptr, TRUE);
        return 0;
      case WM_SIZING:
        GetClientRect(hwnd, &rect);
        UpdateLayout(rootArea, Rect{ 0, 0, rect.right, rect.bottom });
    
        InvalidateRect(hwnd,nullptr,TRUE);
        return 0;
      case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
    
        GetClientRect(hwnd, &rect);
        FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
    
        drawRects(hdc, rootArea);
    
        EndPaint(hwnd, &ps);
        return 0;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(
      HINSTANCE hInstance, 
      HINSTANCE hPrevInstance,
      PSTR lpCmdLine, 
      int nCmdShow) {
      HWND hwnd;
      WNDCLASS winc;
      MSG msg;
    
      winc.style = CS_HREDRAW | CS_VREDRAW;
      winc.lpfnWndProc = WndProc;
      winc.cbClsExtra = winc.cbWndExtra = 0;
      winc.hInstance = hInstance;
      winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      winc.hCursor = LoadCursor(NULL, IDC_ARROW);
      winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      winc.lpszMenuName = NULL;
      winc.lpszClassName = TEXT("SZL-WINDOW");
    
      if (!RegisterClass(&winc)) return 0;
    
    
      Rect rootRect{ 0, 0, 800, 300 };
      rootArea = LoadLayout(R"(C:\test\layout3.xml)");
      UpdateLayout(rootArea, rootRect);
    
    
      hwnd = CreateWindow(
        TEXT("SZL-WINDOW"), TEXT("test window"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        800, 500,
        NULL, NULL,
        hInstance, NULL
      );
    
      if (hwnd == NULL) return 0;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
      return msg.wParam;
    }
    

    layout3.xml

    <?xml version="1.0" encoding="utf8" ?>
    <box name="main" ratio="1.0" arrangement="horizonal">
      <box name="menu" pixel="300" arrangement="vertical">
    
        <box name="menu-top" pixel="50" arrangement="horizonal">
          <box name="area-a" pixel="50" arrangement="vertical"></box>
          <box name="area-b" pixel="50" arrangement="vertical"></box>
          <box name="area-c" ratio="auto" arrangement="vertical"></box>
        </box>
    
        <box name="menu-middle" ratio="0.2" arrangement="horizonal"></box>
        <box name="menu-bottom"             arrangement="horizonal"></box>
    
      </box>
        
      <box name="containts"  ratio="auto" arrangement="vertical" >
      </box>
    
    </box>
    

    実行結果

    矩形をxmlで再帰的に分割

    UIを簡易的に定義したいので、自作xmlとそれに基づいて領域を計算するコードを書く。

    XML

    まずXMLを定義。

    nameは識別子だが一意である必要はない。arrangementは子要素の配置方法。ratioは親要素に対するその要素の割合。

    <?xml version="1.0" encoding="utf8" ?>
    <box name="main" ratio="1.0" arrangement="horizonal">
      <box name="red" ratio="0.3" arrangement="vertical">
         <box name="area1"></box>
         <box name="area2"></box>
         <box name="area3" ratio="0.5"></box>
      </box>
        
      <box name="blue"  ratio="0.6" arrangement="vertical" >
         <box name="area1" ratio="0.2"></box>
         <box name="area2" ratio="0.8"></box>
      </box>
    
      <box name="green" ratio="0.1" arrangement="vertical" >
         <box name="area1" ratio="0.3"></box>
         <box name="area2" ratio="0.3"></box>
         <box name="area3" ratio="0.3"></box>
         
         <box name="area4" ratio="0.1"  arrangement="horizonal">
           <box name="target1" ratio="0.3"></box>
           <box name="target2" ></box>
         </box>
      </box>
    </box>
    

    コード

    #include <windows.h>
    
    #include <iostream>
    #include <string>
    #include <vector>
    #include <pugixml.hpp>
    #include <functional>
    
    // 子要素の配置方法
    enum class Arrangement {
        Horizonal,
        Vertical,
    };
    
    // 各情報を元に計算される実際のサイズ。sx,sy, ex,eyは矩形の最小、最大を表すピクセル座標
    struct Rect {
        int sx, sy;
        int ex, ey;
    };
    
    struct BOX {
        Arrangement type;          // 子要素の配置方法
        Rect rect;                 // この領域の矩形
        std::string name;          // この領域の名前
        double ratio;              // この領域が親要素のどれだけの割合を占めるか
        std::vector<BOX> children; // 子要素
    };
    
    
    // xmlファイルの内容を解析してノード作成
    void parseNode(const pugi::xml_node& xmlNode, BOX& node) {
    
        // BOXの名前を取得
        node.name = xmlNode.attribute("name").as_string("");
        // BOXの親要素に対する割合を取得。指定がない場合はNaNにしておいて、自動計算する
        node.ratio = xmlNode.attribute("ratio").as_double( std::numeric_limits<double>::quiet_NaN()   );
    
        // 配置方法を取得。デフォルトをverticalとしておく。
        std::string arrangement = xmlNode.attribute("arrangement").as_string("vertical");
        node.type = (arrangement == "horizonal") ? Arrangement::Horizonal : Arrangement::Vertical;
    
        // 子要素を再帰的に解析
        for (pugi::xml_node child = xmlNode.first_child(); child; child = child.next_sibling()) {
            BOX childNode;
            parseNode(child, childNode);
            node.children.push_back(childNode);
        }
    }
    
          
          
    // xmlファイルからレイアウト情報を読み込む
    BOX LoadLayout(const char* xmlfilename) {
        pugi::xml_document doc;
        pugi::xml_parse_result result = doc.load_file(xmlfilename);
    
        // ファイルが読み込めなかったら例外を投げる
        if (!result) {
            throw std::runtime_error("xmlファイルが読み込めませんでした");
        }
    
        BOX rootNode;
        pugi::xml_node root = doc.child("box");
        parseNode(root, rootNode);
    
        return rootNode;
    }
    
          
          
    // 読み込んだxmlファイルから領域を計算
    void UpdateLayout(BOX& node, const Rect& parent) {
        node.rect = parent;
        int totalWidth = parent.ex - parent.sx;
        int totalHeight = parent.ey - parent.sy;
    
        /////////////////////////////////
        // 親要素を占める割合の計算
        // ratioを省略可能としている
        // ratioが省略されたときは、その領域内の残りのratioを省略されたbox数で割る
    
        double remainingRatio = 1.0; // 1.0 = 100% parent全体の割合を1.0とする
        int undefinedRatioCount = 0; // ratioが定義されていないboxの個数
    
        for (auto& child : node.children) {
    
            if (std::isnan(child.ratio) == true) {
    
                // ratioが定義されていないノードの個数を知りたいのでここで確認する
                undefinedRatioCount++;
    
            }
            else {
                // ratioが定義されているノードの割合を引き、
                // ratio未定義のboxが使用可能な割合を計算する
                remainingRatio -= child.ratio;
            }
    
        }
    
        // ratioが定義されていないノードがある場合は、使用可能な割合を等分する
        if (undefinedRatioCount > 0) {
            // ratioが定義されていないノードは、使用可能な量を等分する
            double defaultRatio = remainingRatio / undefinedRatioCount;
    
            // ratio未定義のノードにratioを与える
            for (auto& child : node.children) {
                if (std::isnan(child.ratio) == true) {
                    child.ratio = defaultRatio;
                }
            }
        }
    
        // 子要素の矩形を計算する
        double accumRatio = 0.0;
        for (auto& child : node.children) {
            if (node.type == Arrangement::Horizonal) {
                child.rect.sx = parent.sx + totalWidth * accumRatio;
                child.rect.ex = child.rect.sx + totalWidth * child.ratio;
                child.rect.sy = parent.sy;
                child.rect.ey = parent.ey;
            }
            else {
                child.rect.sy = parent.sy + totalHeight * accumRatio;
                child.rect.ey = child.rect.sy + totalHeight * child.ratio;
                child.rect.sx = parent.sx;
                child.rect.ex = parent.ex;
            }
            accumRatio += child.ratio;
    
        }
    
        // 子要素の子要素の矩形を計算する
        for (auto& child : node.children) {
            UpdateLayout(child, child.rect);
        }
    }
    

    テストコード

    // 領域を描画
    void drawRects(HDC hdc, const BOX& node) {
    
        
        RECT rect = { node.rect.sx, node.rect.sy, node.rect.ex, node.rect.ey };
        
        // ランダムな色を作成
        int r = rand() % 256;
        int g = rand() % 256;
        int b = rand() % 256;
    
    
        HPEN hPen = CreatePen(PS_SOLID, 1, RGB(r, g, b)); // 1ピクセル幅のペンを作成
        HGDIOBJ oldPen = SelectObject(hdc, hPen); // ペンを選択
    
        // 矩形を描画
        Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
    
        SelectObject(hdc, oldPen); // 元のペンに戻す
        DeleteObject(hPen); // ペンを削除
    
    
    
        for (const BOX& child : node.children) {
            drawRects(hdc, child);
        }
    }
    
    
    BOX rootArea;
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;
    
        switch (msg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            GetClientRect(hwnd, &rect);
            FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
    
            drawRects(hdc, rootArea);// テスト用 矩形描画
    
            EndPaint(hwnd, &ps);
            return 0;
    	}
        return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(
        HINSTANCE hInstance, 
        HINSTANCE hPrevInstance,
        PSTR lpCmdLine, 
        int nCmdShow) {
        HWND hwnd;
        WNDCLASS winc;
        MSG msg;
    
        winc.style = CS_HREDRAW | CS_VREDRAW;
        winc.lpfnWndProc = WndProc;
        winc.cbClsExtra = winc.cbWndExtra = 0;
        winc.hInstance = hInstance;
        winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        winc.hCursor = LoadCursor(NULL, IDC_ARROW);
        winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        winc.lpszMenuName = NULL;
        winc.lpszClassName = TEXT("SZL-WINDOW");
    
        if (!RegisterClass(&winc)) return 0;
    
    
        Rect rootRect{ 0, 0, 800, 300 };
        rootArea = LoadLayout(R"(layout2.xml)");// レイアウト読み込み
        UpdateLayout(rootArea, rootRect);// 矩形を計算
    
    
        hwnd = CreateWindow(
            TEXT("SZL-WINDOW"), TEXT("test window"),
            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL,
            hInstance, NULL
        );
    
        if (hwnd == NULL) return 0;
    
        while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
        return msg.wParam;
    }
    

    Rustでスレッドを使ってみる

    Rustでスレッドを作成するにはspawnを使用する。よくあるように、一度作成したスレッドはハンドルを取得し、join()で待機する。スレッドとして走らせた関数の戻り値はjoin()の戻り値に入っているが、これはエラーなども扱うResultとして入っているのでunwrapして戻り値を取り出す。

    1.引数のない関数を呼び出す

    spawnには原則として引数なしの関数しか渡せない。

    // スレッドとして実行する関数
    // 引数をとることはできないが、任意の型の戻り値を返すことはできる
    fn my_sum()->i32 {
        let mut sum = 0;
        for i in 0..50 {
            println!("{}", i);
            sum += i;
        }
        return sum;
    }
    
    fn main(){
    
        // 関数が引数を一つも取らない場合、spawnに関数名を渡すだけでスレッドが作成される
        let thread_handle1 = std::thread::spawn(my_sum);
        let thread_handle2 = std::thread::spawn(my_sum);
    
        // my_sumは引数をとることはできないが、任意の型の戻り値を返すことはできる
        let result1:i32 = thread_handle1.join().unwrap();
        let result2:i32 = thread_handle2.join().unwrap();
    
        println!("results are {} , {} ", result1,result2);
    }
    

    2.引数を与えて呼び出す(マジックナンバー)

    引数を与える場合、直接spawnに与えることができないので、クロージャ(ラムダ関数のようなもの)を与える。Rustのクロージャは頭に || をつける。

    以下の例では、「myprintに'a' 'b' 50 というマジックナンバーを与えて呼び出す」という処理を行う引数なしの関数をspawnに渡している。

    // 値を表示する関数
    fn myprint(mark : char,count:i32) {
        for i in 0..count{
            println!("{} -> {}",mark,i);
        }
    }

    fn
    main() { // spawnにはクロージャ(≒ラムダ関数)を渡す。 || はクロージャを表す。 // 即ち、「myprintを引数付きで渡す」という処理を行う、引数なしの関数を渡している。 let thread_handle1 = std::thread::spawn(|| myprint( 'a',50)); let thread_handle2 = std::thread::spawn(|| myprint( 'b',50)); // 終了まで待機 thread_handle1.join().unwrap(); thread_handle2.join().unwrap(); }

    3.メインスレッドのデータを引数渡しで処理する

    メインスレッドのデータをスレッドの中で処理したい場合、メインスレッド側でデータが消えたりするとまずいので、そのまま参照を渡すことができない。

    そこでデータを参照カウンタ付きのスマートポインタArcで渡すことで、メインスレッドを含め各スレッドが処理している最中にデータが消える危険性を排除する。

    // vecの不変参照を受け取り、表示する関数
    fn myprint(input: &Vec<i32>) {
        for i in input.iter(){
            println!("i=={}",i);
        }
    }
    
    // テスト用のVecのデータを作成する関数
    fn create_data()->Vec<i32>{
        let mut data = vec![];
        for k in 0..100{
            data.push(k);
        }
    
        return data;
    }
    
    
    fn main() {
    
        // スレッドに渡すためにはArcでラップする必要がある
        let data1 = std::sync::Arc::new(create_data());
        let data2 = std::sync::Arc::new(create_data());
    
        // spawnmoveキーワードによりスレッドに変数の所有権が移ってしまうので
        // clone()で参照のコピーを作成する。Arccloneは参照カウンタが増えるだけなので負荷はほぼない
        let d1_clone = data1.clone();
        let d2_clone = data2.clone();
        let thread_handle1 = std::thread::spawn(move || myprint( &d1_clone)); // d1_cloneの所有権が移動
        let thread_handle2 = std::thread::spawn(move || myprint( &d2_clone)); // d2_cloneの所有権が移動
    
        // 終了まで待機
        thread_handle1.join().unwrap();
        thread_handle2.join().unwrap();
    
        // データの所有権は移行していないので、ここで表示できる
        println!("data: {:?}", data1);
        println!("data: {:?}", data2);
    
    
    }
    

    4.スレッドに可変な変数を渡して編集する

    スレッド内で変数を編集したい場合、さらにMutexでラップする。

    // 配列を受け取り、二倍にする関数
    fn double(input: &std::sync::Mutex<Vec<i32>>) {
        let mut vecdata = input.lock().unwrap();
        for i in vecdata.iter_mut() {
            *i *= 2;
        }
    }

    fn main() {
    
        let data1 = std::sync::Arc::new(std::sync::Mutex::new(vec![1,2,3,4,5]));
        let data2 = std::sync::Arc::new(std::sync::Mutex::new(vec![10,20,30,40,50]));
    
        let mut d1_clone = data1.clone();
        let mut d2_clone = data2.clone();
        let thread_handle1 = std::thread::spawn(move || double(&d1_clone));
        let thread_handle2 = std::thread::spawn(move || double(&d2_clone));
    
        thread_handle1.join().unwrap();
        thread_handle2.join().unwrap();
    
    
        println!("data1: {:?}", &data1);
        println!("data2: {:?}", &data2);
    
    
    }
    

    Rustでタイマー

    C言語のタイマーと違い、精度の高いタイマーが標準で使用できる。ただし精度は環境依存なので、比較的新しい環境だとマイクロ秒,ナノ秒単位で取得できるが、そうでない場合も考えられる。

    fn main() {
    
        // 時間計測開始
        let mytimer = std::time::Instant::now();
    
        use_rand();
    
        // 時間計測終了
        let elapsed = mytimer.elapsed();
    
        // 経過時間を表示
        println!("{:?}",elapsed);
    
    
    }

    fn use_rand(){
        use rand::Rng; // 乱数を使うためにrand::Rngを使用
    
        let mut rng = rand::thread_rng();
    
        let min:i32 = 0;
        let max:i32 = 20;
        
        (0..5000).for_each(|_|{
    
            let randint:i32 = rng.gen_range(min..max); // 最大・最小を指定して乱数を生成
    
            println!("{}",randint);
    
        });
    
    }
    

    Sleep時間も計測する

    CのclockなどはCPU時間なので、Sleep時間がタイマーに反映されないが、Rustのstd::timeはちゃんとSleep時間も含んだ結果が得られる。

    fn main() {
    
        // 時間計測開始
        let mytimer = std::time::Instant::now();
    
        // 5秒間スリープ
        std::thread::sleep(std::time::Duration::from_secs(5));
    
        // 時間計測終了
        let elapsed = mytimer.elapsed();
    
        // 経過時間を表示
        println!("{:?}",elapsed);
    
    
    }
    

    結果

    5.0009648s

    値の取得

    表示だけならDuration型に対して{:?}すればよいが、値を取り出す場合は以下のようにする。

        // 経過時間を表示
        println!("second i32 {}",elapsed.as_secs());
        println!("second f32 {}",elapsed.as_secs_f32());
        println!("micro second {}",elapsed.as_micros());
        println!("nano second {}",elapsed.as_nanos());
    

    結果

    second i32 5
    second f32 5.000559
    micro second 5000558
    nano second 5000558900
    

    Rustでクイックソートを書いてみる

    Rustのスライスを使ってみたくて書いた。

    クイックソートを書いたのはたぶん15年ぶりくらい。正直てこずった。

    fn my_qsort_slice(data: &mut [i32]){
    
        if data.len() <= 1{
            return;
        }
    
    
        // ピボットを求める
        let pivot =data[data.len()/2];
    
        let idmin:i32 = 0;
        let idmax:i32 = (data.len()-1) as i32;
    
        //////////////////////////////////////////////////
        // ピボットより小さいものを左に、大きいものを右に分ける
        let mut l =idmin; // 左側の探索位置。pivotより大きい値を探す
        let mut r =idmax; // 右側の探索位置。pivot未満の値を探す
    
        loop{
    
    
            // 左側の交換すべき値を探す
            while data[l as usize] < pivot {
                l += 1;
            }
    
            // 右側の交換すべき値を探す
            while data[r as usize] > pivot {
                r -= 1;
            }
    
            if l >= r{
                break;
            }
    
            // 交換
            let tmp = data[l as usize];
            data[l as usize] = data[r as usize];
            data[r as usize] = tmp;
    
    l += 1;
    r -= 1; } { // 左側のスライスを作成 let mut left = &mut data[0..l as usize]; // 左側のスライスを再帰的にソート my_qsort_slice(&mut left); } { // 右側のスライスを作成 let mut right = &mut data[ (r+1) as usize ..]; // 右側のスライスを再帰的にソート my_qsort_slice(&mut right); } }

    fn my_qsort(data : &mut Vec<i32>){
    
        my_qsort_slice(&mut data[..]);
    
    }
    

    fn main() {
    
    
        let mut data:Vec<i32> = Vec::new();
    
        data = [8,1,9,2,4,6].to_vec();
    
        my_qsort(&mut data);
    
        for i in 0..data.len(){
            println!("{}",data[i]);
        }
    
        println!("Hello, world!");
    }