ぬの部屋(仮)
nu-no-he-ya
  • 1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        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      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      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
           
       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
           
  • ガウシアンフィルタについて(1)

    二次元画像のぼかしフィルタのガウシアンフィルタについて。検索すると3x3のフィルタとして以下が出てくる。

    それとは別に以下の式が出てくる。

    この式でどんな数字が出来上がるのかが気になったのでExcelで計算してみる。

    Excelを開き、C5→I1に式を張り付ける。例えばC6の式は以下のようになる。

    =(1/(2*PI()*$B$2*$B$2))*EXP(-(C$4*C$4+$B6*$B6)/(2*$B$2*$B$2))

    ※B2にρ、B3に分母を入れておく。

    3x3の場合

    上図左で得られた結果は最終結果なので、分数にしたときに1/16,2/16,...になっているはずなので、16倍する。そのうえで四捨五入すると上図右の結果となる。

    5x5の場合

    上の結果は検索して出てくる下のような5x5のフィルタと違う。

    結論、7x7くらいまでは検索してすぐ出てくるフィルタを直打ちして使う、より大きなフィルタや個性的なフィルタを使いたい場合は式から作成する

    主成分分析(PCA)の前にデータを標準化する(Eigenライブラリ版)

    C++のEigenライブラリで標準化までやってみる。本当はPCAもやりたいしEigenSolverを使えばいい事まではわかっているが結果の確認ができないので今はやらない。

    #include <iostream>
    #include <vector>
    #include <Eigen/Dense>
    
    int main()
    {
      std::vector<std::array<float, 3> > cloud;
      cloud.push_back({ -1.841658711, 0.324050009, 1.041258931 });
      cloud.push_back({-1.449076772, 0.431593835, 0.987673104 });
      cloud.push_back({-1.04681015, 0.415599823, 1.049820662 });
      cloud.push_back({-0.646572888, 0.42549479, 1.087714672 });
      cloud.push_back({-0.25920701, 0.599574149, 0.971796691 });
      cloud.push_back({0.149769783, 0.497985959, 1.114130974 });
      cloud.push_back({-1.883069754, 0.6849733, 1.249212146 });
      cloud.push_back({-1.481496215, 0.677821219, 1.303076267 });
      cloud.push_back({-1.083532453, 0.716715276, 1.313803315 });
    
      Eigen::MatrixXf mat(9,3);
      for (size_t i = 0; i < cloud.size();i++) {
        mat.row(i) << cloud[i][0] , cloud[i][1] , cloud[i][2];
      }
    
      // センタリングしたデータを作成
      Eigen::MatrixXf centered = mat.rowwise() - mat.colwise().mean();
    
      std::cout << "---" << std::endl;
    
    // センタリングされたデータに対して、列ごとに標準偏差を求め、各列の要素を標準偏差で割る for (int c = 0; c < 3; c++) { auto col = mat.col(c).array(); double std_dev = sqrt((col - col.mean()).square().sum() / col.size()); centered.col(c) /= std_dev; }
    std::cout << std::endl << centered << std::endl;// 表示 std::cout << std::endl << std::endl; ////////////////////// // 分散共分散行列 Eigen::MatrixXf cov = (centered.adjoint() * centered) / double(centered.rows());
    std::cout << cov << std::endl;// 表示 return 0; }

    計算結果

    Excelと同じ結果が出ている。

    解説

    センタリング

    データのセンタリングは、データの平均値を0にすることなので、全てのデータから平均値を引けばよい。

    rowwise()-colwise().mean()で行える。

     

      // センタリングしたデータを作成
      Eigen::MatrixXf centered = mat.rowwise() - mat.colwise().mean();
    
    

    rowwise(),colwise()は全ての行に対して、あるいは全ての列に対して処理をしたい時に使う演算子みたいなもの。

    例えばmean()は平均を計算する関数なので、colwise().mean()で各列の平均値を求めることができる

    Eigen::MatrixXf mat(2, 3);
    
    mat.row(0) << 1, 3, 5;
    mat.row(1) << 2, 4, 6;
    
    std::cout << mat.colwise().mean() << std::endl;
    

    結果:

    1.5  3.5  5.5

    つまり、各行の値に対して、これらを引けばよいので、

    mat.rowwise().operator-()

    を呼び出す。

    標準偏差

    標準偏差は、全ての列のデータに対して、平均値を引いてそれを二乗したものを合計するわけだが、その計算をcolwise()で(なぜか)行えないので、一度arrayに変換する必要がある。

    auto col = mat.col(c).array();
    

    arrayに変換したら、arrayの各要素に対して演算を行える関数が用意されているので、それを駆使して列ごとに標準偏差を求める。

    double std_dev = sqrt(
      (col/*各要素から*/ - col.mean()/*全要素の平均を引き*/)
        .square()/*それぞれ二乗して*/
          .sum()/*全て合計して*/
            / col.size()/*要素数で割り*/
    )/*平方根をとる*/;
    

    各列の要素を、標準偏差で割る。

    centered.col(c) /= std_dev;
    

    分散共分散行列

    さっぱりわからん

    おまけ PCA

    主成分分析はEigenSolverに上記で計算した分散共分散行列のcovを入れて行うらしい。

    //Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> es(cov);
    Eigen::EigenSolver<Eigen::MatrixXf> es(cov);
    Eigen::MatrixXcf eigen_vectors = es.eigenvectors();
    Eigen::VectorXcf eigen_values = es.eigenvalues();
    

    最後に

    そもそもcovは分散共分散行列というヤツなのか?私は主成分分析をするにはそれにする必要があるらしいので、それに用いることができるならそれであろうという認識であって数学的な事は何一つ理解していないのだが。

    主成分分析(PCA)の計算をする前にデータを標準化しないといけないらしい

    厳密には、したほうがいい場合としないほうがいい場合があるらしい。

    標準化の式は以下。各値から値全体の平均を引き、その値を標準偏差で割る。これをすべての値に対して行う。

    Excelで計算

    エクセルにはSTANDARDIZEという関数がある。ただしこれを使うためには平均と標準偏差をそれぞれ別途計算する必要がある。

    検証

    自前実装したコードと上記Excelで半自動計算したものと比較。同じ値が出ている。

    サンプルコード

    #include <iostream>
    #include <vector>
    #include <array>
    
    using vector3f = std::vector<std::array<float, 3>>;
    
    
    //! @brief データの平均を求める
    //! @param [in] vec データの配列
    //! @return 各要素の平均
    std::array<float, 3> Average(const vector3f& vec) {
    
      // 初期化
      std::array<float, 3> ave;
      ave[0] = 0;
      ave[1] = 0;
      ave[2] = 0;
    
      // 各要素平均
      for (size_t i = 0; i < vec.size(); i++) {
        ave[0] += vec[i][0];
        ave[1] += vec[i][1];
        ave[2] += vec[i][2];
      }
      ave[0] /= vec.size();
      ave[1] /= vec.size();
      ave[2] /= vec.size();
    
      return ave;
    
    }
    
          
    //分散
    std::array<float, 3> Distributed(const std::array<float, 3>& average, const vector3f& vec) {
      int n = vec.size();
      std::array<float, 3> s2{ 0,0,0 };
      for (int j = 0; j < 3; j++) {
        for (const auto& v : vec) {
          s2[j] += std::pow(v[j] - average[j], 2);
        }
        s2[j] = 1.f / n * s2[j];
      }
      return s2;
    }
    
          
    //標準偏差
    std::array<float, 3> StandardDeviation(const std::array<float, 3>& average, const vector3f& vec) {
    
      std::array<float, 3> d = Distributed(average, vec);
      d[0] = sqrt(d[0]);
      d[1] = sqrt(d[1]);
      d[2] = sqrt(d[2]);
    
      return d;
    }
    
          
    //標準化 平均を引いて標準偏差で割る
    // average 平均
    // sd 標準偏差
    void Standardization(vector3f& src, const std::array<float, 3>& average, const std::array<float, 3>& sd) {
      for (auto&& p : src) {
        p[0] = (p[0] - average[0]) / sd[0];
        p[1] = (p[1] - average[1]) / sd[1];
        p[2] = (p[2] - average[2]) / sd[2];
      }
    }
    
    int main()
    {
      vector3f data;
    
      data.push_back({ -1.841658711,0.324050009,1.041258931 });
      data.push_back({-1.449076772,0.431593835,0.987673104 });
      data.push_back({-1.04681015,0.415599823,1.049820662 });
      data.push_back({-0.646572888,0.42549479,1.087714672 });
      data.push_back({-0.25920701,0.599574149,0.971796691 });
      data.push_back({ 0.149769783,0.497985959,1.114130974 });
      data.push_back({-1.883069754,0.6849733,1.249212146 });
      data.push_back({-1.481496215,0.677821219,1.303076267 });
      data.push_back({-1.083532453,0.716715276,1.313803315 });
    
    
      std::array<float, 3> _s = Average(data);
      std::array<float, 3> sd = StandardDeviation(_s, data);
    
      Standardization(data, _s, sd);
    
      for (size_t i = 0; i < data.size(); i++) {
        printf("%lf , %lf , %lf\n", data[i][0], data[i][1], data[i][2]);
      }
    
    }
    

    ICUライブラリのutf16.hで定義されているU16系マクロの実例をいくつか U16_NEXT_UNSAFE

    U16_NEXT_UNSAFEを使ってutf16文字列を一文字ずつ処理する。

    #include <cstdio>
    
    #pragma warning(disable:4996)
    
    #include <unicode/utf16.h>
    
    #include <locale>
    int main()
    {
      std::setlocale(LC_CTYPE, "");
    
      const char16_t* str = u"い👨‍👦は";
    
      const char16_t* p = str;
      int i = 0;
      while (p[i]) {
    
        bool bs = U16_IS_SURROGATE(p[i]);//サロゲートペアかどうか
    
        int iback = i;
        char32_t u32c;
        U16_NEXT_UNSAFE(p, i,u32c);
    
        if (bs==false) {
          if (p[iback] == 0x200d) {//サロゲートペアではないが、結合文字
            printf("[%x] Combine string\n", p[iback]);
          }
          else {//一文字
            printf("%s [%x] (%lc) -> %x\n",
              " true ",
              p[iback],
              p[iback],
              u32c
            );
          }
        }
        else {//サロゲートペア
          printf("%s [%x,%x] -> %x ",
            " false",
            U16_LEAD(u32c),//u32からサロゲートペアを求める
            U16_TRAIL(u32c),
            u32c
          );
          printf(" * [%x,%x]", p[iback], p[iback + 1]);//u16のサロゲートペアを表示
          puts("");
        }
      }
    
    }
    
    true [3044] (い) -> 3044
    false [d83d,dc68] -> 1f468 * [d83d,dc68]
    [200d] Combine string
    false [d83d,dc66] -> 1f466 * [d83d,dc66]
    true [306f] (は) -> 306f

    [雑談] DreamStudioを試した感想

    DreamStudioは今話題の、、流行りのAIでキーワードから画像を生成するサービスで、現時点でかなり性能の高いものらしい。人類の歴史が動く!!と興奮する者さえいる。

    AIを作る場合、今主流のDeepLearningなんかだと、たくさん教えるほど精度が上がる。資料が少ないものほど精度が落ちる。つまり資料(ネット上に落ちていた画像)の量と質で結果に偏りが生じるはず。

    使い方

    利用にはユーザー登録が必要。

    https://beta.dreamstudio.ai/

    登録出来たらログインし、画面下のテキストフィールドにキーワードを入力して[Dream]ボタンを押す。

    使ってみた感想

    率直に言うと、

    1.景観、植物などはそのまま使っても問題ないほど優れたものが出てくる。

    2.動物などは時々はずれが出る。

    3.人間は結構気持ち悪いのが生成される。

    4.開発者の文化圏の影響がなんとなくわかる

    tree

    まずは「tree」。かなり綺麗。大体はそのまま使ってしまえそうなものが出てくる。

    owl

    「owl」フクロウについて詳しくないのでどこかおかしくてもよくわからない。

    woman blonde

    「woman blonde」ここまで整ったものが出来上がる確率は低いが、それでも結構きれいなものが出てくる。というかなんか見たことある気がする。

    ただし次で言うように、日本人の脳はブロンドの見分けがそんなに得意ではないので、おかしくても気づいていないだけかもしれない。

    woman asian

    「woman asian」blondeとの差が傾向として出てしまう…。

    日本人であれば、脳がアジア系の顔の見分けに最適化されているはずなので、どうしても粗が見えやすくなるはず。

    man asian

    「man asian」男性で整った顔が出る確率は結構低い。つまりそういうことorz。

    Manju

    「Manju」饅頭。たこ焼きの間違いでは。

    Hamburger

    「Hamburger」さすがにこいつの精度は高い。

    onigiri

    「onigiri」どう見ても巻き寿司。

    rice ball

    「rice ball」イメージと違う。嘘は言ってない、みたいな結果になる。

    butter

    「butter」バターの精度は高い。

    所感

    単語だけでやってみたが、多分ある程度長い文で出したほうがずっと面白いものができる。

    「christmas night tree in snow」

    ただし、人間、動物、昆虫などはメンタルが強くないならお勧めできない。あたりを引くまでに何度も生成を繰り返すことになるが悪夢になりかねない。

    あと集合体恐怖症への配慮はない。これは本当にきつい。

    雑談

    著者は今ゼノブレイド3をやっていてガチで記事を書く時間がないのだがそもそもネタがなくてやばい。

    [メモ] Blender 3でMesh to VolumeとVolume to Mesh

    Mesh to Volume

    まずはモデルを読み込む。

    [Shift+A]→[Volume]→[Empty] でボリュームを追加。

    モディファイアの設定で、Objectにモデルを選択する。

    Volume to Mesh

    上記方法でボリュームを作った後、これをメッシュ化する。

    [Shift+A]→[Mesh]→[Cube]で立方体を追加する。

    Cubeに対してVolume to Meshモディファイアを適用。

    ObjectにVolumeを選択し、Applyする。

    UPDATED Realistic Procedural Starfield Blender 2.9 を試す

    このチュートリアルは解像度が低いこともあり正確に数字が取れない(し、取れてもたいていうまくいかない)のでざっくりとやってみる。

    まず以下が基本となる。他はすべて、以下のコピーとなる。

    上をコピーして、色を変える。さらにMappingのLocationを6.5にする。

    そしてそれをAdd Shaderする。

    上記二つをコピーし、計四つにする。Voronoi Textureのsizeを60に設定。他はいじらない。

    Voronoiのscaleが60のものを一つだけコピーし、Locationを変更。あと色を変更。

    上記をコピーし三つ作成する。scaleを上から120,180,320に設定。

    結果

    FTGLで改行する

    OpenGLの描画内にFreeType2で簡単に文字列を描画できるFTGLだが改行がやや面倒。

    概要

    FTGLのFTPixmapFontオブジェクトからBBoxメンバ関数を呼び出す。

    この関数はテキストを与えるとそのテキストのバウンディングボックスを返すので、これで一行の高さが分かる。

    ただし、このサイズは単位がピクセルらしいので、表示中のワールド座標系に変換してやる必要がある。

     

    #include <iostream>
    
    #include <Windows.h>
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    #include <FTGL/ftgl.h>
    
    #pragma comment(lib,"opengl32.lib")
    #pragma comment(lib,"freeglut.lib")
    #pragma comment(lib,"ftgl.lib")
    
    //ウィンドウの幅と高さ
    int width, height;
    
    
    // FTGLを管理しやすくするクラス
    struct CFtglObject {
      const char* FONT_PATHNAME = "C:\\Windows\\Fonts\\msgothic.ttc";
      FTPixmapFont* g_pFont;
      unsigned long g_ulFontSize;  // フォントサイズ
    
      ~CFtglObject() {
        delete g_pFont;
      }
    
    
      // フォントの初期化
      void init(const unsigned long fontsize) {
    
        g_ulFontSize = fontsize;
    
        if (!g_pFont) {
          g_pFont = new FTPixmapFont(FONT_PATHNAME);
          if (g_pFont->Error()) {
            delete g_pFont;
            g_pFont = nullptr;
          }
          else {
            g_pFont->FaceSize(g_ulFontSize);
          }
        }
      }
    
      // FTGLで文字列を描画
      void print(const std::wstring& wstr, float x, float y) {
    
        if (g_pFont) {
          glRasterPos2f(x, y);
          g_pFont->Render(wstr.c_str());
        }
    
      }
      FTPixmapFont& get_font() { return *g_pFont; }
    };
    
    
          
    CFtglObject ftglo;
    
    //描画関数
    void disp(void) {
    
      glViewport(0, 0, width, height);
    
      glClearColor(0.2, 0.2, 0.2, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(-1, 1, -1, 1, 1, -1);
    
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
    
    
      glEnable(GL_CULL_FACE);
      double v = 0.7;
    
    
      glBegin(GL_QUADS);
      glColor3d(0, 0, 1);
      glVertex2d(-v, -v);
      glColor3d(1, 0, 1);
      glVertex2d(v, -v);
      glColor3d(1, 1, 1);
      glVertex2d(v, v);
      glColor3d(0, 1, 1);
      glVertex2d(-v, v);
      glEnd();
    
      glLineWidth(2);
      glBegin(GL_LINES);
      glColor3d(1, 1, 0);
      glVertex2d(-v, 0);
      glColor3d(1, 1, 1);
      glVertex2d(v, 0);
    
      glColor3d(1, 1, 0);
      glVertex2d(0, -v);
      glColor3d(1, 1, 1);
      glVertex2d(0, v);
      glEnd();
    
      /////////////////////////////////
      /////////////////////////////////
      /////////////////////////////////
    
      const wchar_t* text;
    
      text = L"いろはに";
      ftglo.print(text, 0, 0);
      FTBBox bbox = ftglo.get_font().BBox(text);
      float BoxHeightPixel = bbox.Upper().Yf() - bbox.Lower().Yf();//文字列の高さを求める
    
      // BoxHeightの単位がピクセルらしいので、これを現在の文字幅に修正する。
      // 現在は -1 ~ 1の範囲を0~height-1ピクセルで表示しているので、
      float ratioh = 2.f/height;
      float pixelh = ratioh * BoxHeightPixel;
    
      text = L"ほへと";
      ftglo.print(text, 0, pixelh);
    
      glFlush();
    }
    
    //ウィンドウサイズの変化時に呼び出される
    void reshape(int w, int h) {
      width = w; height = h;
    
      disp();
    }
    
    
    
    //エントリポイント
    int main(int argc, char** argv)
    {
      glutInit(&argc, argv);
      glutInitWindowPosition(100, 50);
      glutInitWindowSize(500, 500);
      glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    
      ftglo.init(32);
    
      glutCreateWindow("sample");
      glutDisplayFunc(disp);
      glutReshapeFunc(reshape);
      glutMainLoop();
    
      return 0;
    }
    

    二次元の三角形の内外判定で誤差を指定する

    二次元の、ある点が三角形の内側にあるか外側にあるかを判定するコードを以前紹介したのだが、点が三角形の境界ぎりぎりにある場合問題を起こすことがある。

    判定方法はs,tを計算し、それが0~1に収まっていれば内側と判断するので、この範囲を0.1~0.9などに変更すると誤差を指定することができるようになる。

    誤差指定版

    //https://suzulang.com/2d-triangle-in-out-check/
    template<typename real_t>
    inline bool isInTheTriangle(
      real_t px, real_t py,
      real_t p0x, real_t p0y,
      real_t p1x, real_t p1y,
      real_t p2x, real_t p2y
    ) {
      real_t Area = 0.5 * (-p1y * p2x + p0y * (-p1x + p2x) + p0x * (p1y - p2y) + p1x * p2y);
    
      real_t s = 1.0 / (2.0 * Area) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
      real_t t = 1.0 / (2.0 * Area) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
    
    
      real_t e = 0.05;
      real_t tmin = 0.0 - e;
      real_t tmax = 1.0 + e;
    
      if (
    
        (tmin < s) && (s < tmax) &&
        (tmin < t) && (t < tmax) &&
        (tmin < (1 - s - t)) &&
        ((1 - s - t) < tmax)
    
        ) {
        return true;
      }
      else {
        return false;
      }
    }
    

    呼び出し例

      auto p0 = glm::vec3(-0.913841, 0.999223, 0);
      auto p1 = glm::vec3(0.032665, -0.787554, 0);
      auto p2 = glm::vec3(0.853559, 0.974719, 0);
    
      glBegin(GL_TRIANGLES);
      glVertex2fv(glm::value_ptr(p0));
      glVertex2fv(glm::value_ptr(p1));
      glVertex2fv(glm::value_ptr(p2));
      glEnd();
    
      glPointSize(5);
      glBegin(GL_POINTS);
      for (float x = -2.f; x < 2.f; x += 0.1f) {
          for (float y = -2.f; y < 2.f; y += 0.1f) {
    
        bool hit = isInTheTriangle(
            x, y,
            p0.x, p0.y,
            p1.x, p1.y,
            p2.x, p2.y
        );
    
        if (hit)
            glColor3d(1, 0, 0);
        else
            glColor3d(0.7, 0.7, 0.7);
    
        glVertex2f(x,y);
    
    
          }
      }
      glEnd();
    

    ICUライブラリのutf16.hで定義されているU16系マクロの実例をいくつか

    ICUライブラリでのutf16の扱い方を調べていてマクロがあることを知ったのでいくつか列挙しておきたい。

    参考

    ICU 71.1:utf16.h File Reference

    https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/utf16_8h.html

    マクロの例

    U16_GET_UNSAFE

    utf16文字からコードポイントを得る

    #pragma warning(disable:4996)
    
    #include <iostream>
    
    #include <unicode/utf16.h>
    
    int main()
    {
      const char16_t* u16c = u"あいう";
    
      char32_t u32c;
    
      FILE* fp = fopen("test.txt", "w");
      U16_GET_UNSAFE(u16c, 0, u32c);
      fwrite(&u32c, 4, 1, fp);
    
      U16_GET_UNSAFE(u16c, 2, u32c);
      fwrite(&u32c, 4, 1, fp);
    
    
      fclose(fp);
    }
    

    U16_LENGTH

    与えられたコードポイントが、utf16で何要素になるかを返す。返却値は 1 または 2。

        std::u32string cc;
        // U16_LENGTH 与えられたu32がu16で何要素になるか
        int len;
        cc = U"a";
        len = U16_LENGTH(cc[0]);
        printf("--- %d\n", len); // 1 utf16一文字
        cc = U"あ";
        len = U16_LENGTH(cc[0]);
        printf("--- %d\n", len); // 1 utf16一文字
        cc = U"👨‍👩‍👧‍👦";
        len = U16_LENGTH(cc[0]);
        printf("--- %d\n", len); // 2 結合文字の最初の一文字
        cc = U"𠀋";
        len = U16_LENGTH(cc[0]);
        printf("--- %d\n", len); // 2 サロゲートペア
        cc = U"𠀋𡚴";
        len = U16_LENGTH(cc[0]);
        printf("--- %d\n", len); // 2 最初の一文字がサロゲートペア
    

    U16_IS_SINGLE , U16_IS_SURROGATE , U16_IS_SURROGATE_LEAD , U16_IS_SURROGATE_TRAIL

    U16_IS_SINGLE(c)  utf16文字cが、サロゲートペアでなければtrue。

    U16_IS_SURROGATE(c) utf16文字cが、サロゲートペアであればtrue。

    U16_IS_SURROGATE_LEAD(c) utf16文字cが、上位サロゲートであればtrue。ただし、cがサロゲートペアであることが分かっている必要がある。

    U16_IS_SURROGATE_TRAIL(c) utf16文字cが、下位サロゲートであればtrue。ただし、cがサロゲートペアであることが分かっている必要がある。


    U16_IS_SINGLE U16_IS_SURROGATE U16_IS_SURROGATE_LEAD U16_IS_SURROGATE_TRAIL
    u"a"[0] true false true false
    u"あ"[0] true false true false
    u"👨‍👩‍👧‍👦"[0] false true true false
    u"𠀋"[0] false true true false
    u"a"[1] true false true false
    u"あ"[1] true false true false
    u"👨‍👩‍👧‍👦"[1] false true false true
    u"𠀋"[1] false true false true

    U16_LEAD , U16_TRIAL

    コードポイントから上位サロゲート(lead)、下位サロゲート(trail)を算出する

    #pragma warning(disable:4996)
    #include <iostream>
    #include <unicode/utf16.h>
    int main()
    {
      // UTF32
      //char32_t u32c = U'あ';
      char32_t u32c = U'𠀋';
      
      // char32->char16に変換したとき何文字になるかをチェック
      if (U16_LENGTH(u32c) == 2){
    
        // utf16に変換したときサロゲートペアになる場合は上下サロゲートを算出
        char16_t aa[2];
        aa[0] = U16_LEAD(u32c);  // 上位サロゲート
        aa[1] = U16_TRAIL(u32c); // 下位サロゲート
        // ファイル出力
        FILE* fp = fopen("test.txt", "w");
        fwrite(aa, 2, 2, fp);
        fclose(fp);

    } else {
        //サロゲートペアに変換する必要がなければコードユニット値がutf16文字
    
    char16_t u16 = char16_t(u32c); // ファイル出力 FILE* fp = fopen("test.txt", "w"); fwrite(&u16, 2, 1, fp); fclose(fp);

    } }