マルチバイトであればタグが日本語でも動作するが、Unicodeの場合タグが英語でなければ取得できない。
#include <iostream> #include <string> #include "pugixml.hpp"
const char* data() { return R"( <?xml version="1.0" encoding="Shift-JIS"?> <data date="2022-06-15"> <名前> <a>田中</a> <b>中山</b> <c>山本</c> </名前> </data> )"; }
int main() { pugi::xml_document doc; std::string txt = data(); pugi::xml_parse_result result = doc.load_buffer(txt.data(), txt.size(), 0,pugi::xml_encoding::encoding_auto); std::cout << doc.child("data").attribute("date").value() << std::endl; for (auto point : doc.child("data").children("名前")) { std::cout << point.name() << std::endl; for (auto val : point.children()) { std::cout << val.name() << " : " << val.child_value() << std::endl; } } }
#include <iostream> #include <string> #include "pugixml.hpp"
const char* data() { return u8R"( <?xml version="1.0" encoding="UTF-8"?> <data date="2022-06-15"> <names> <a>田中</a> <b>中山</b> <c>山本</c> </names> </data> )"; }
int main() { std::wcout.imbue(std::locale("")); pugi::xml_document doc; pugi::xml_parse_result result = doc.load_string(data()); std::cout << doc.child("data").attribute("date").value() << std::endl; for (auto point : doc.child("data").children("names")) { std::cout << point.name() << std::endl; for (auto val : point.children()) { std::wcout << pugi::as_wide(val.name()) << " : " << pugi::as_wide(val.child_value()) << std::endl; } } }
#include <iostream> #include <sstream> #include <fstream> #include "pugixml.hpp" int main() { pugi::xml_document doc; pugi::xml_node theroot = doc.append_child("the_root"); pugi::xml_node tag1 = theroot.append_child("tag1"); tag1.append_child(pugi::node_pcdata).set_value("This "); tag1.append_child(pugi::node_pcdata).set_value("is "); tag1.append_child(pugi::node_pcdata).set_value("a "); tag1.append_child(pugi::node_pcdata).set_value("pen "); pugi::xml_node tag2 = theroot.insert_child_after("tag2", tag1); tag2.append_child(pugi::node_pcdata).set_value("tag2item"); pugi::xml_node noclose = theroot.insert_child_after("no_close", tag1); noclose.append_attribute("text") = "abc"; noclose.append_attribute("float") = 1.1; std::stringstream ss; doc.save(ss); std::cout << ss.str() << std::endl; // 表示ならこれもできる // doc.save(std::cout); // ファイル出力 // std::ofstream outf("test.xml"); // doc.save(outf); }
MIT LicenseのXMLパーサー。
#include <iostream> #include "pugixml.hpp"
const char* data() { return R"( <?xml version="1.0"?> <data date="2022-06-15"> <point> <x>10.0</x> <y>12.0</y> <z>15.0</z> <r>255</r> <g>0</g> <b>0</b> </point> <point> <x>20.0</x> <y>22.0</y> <z>25.0</z> <r>0</r> <g>255</g> <b>0</b> </point> </data> )"; }
int main() { pugi::xml_document doc; //pugi::xml_parse_result result = doc.load_file("tree.xml"); //ファイルから読み込む場合 pugi::xml_parse_result result = doc.load_string(data()); std::cout << doc.child("data").attribute("date").value() << std::endl; for (auto point : doc.child("data").children("point")) { std::cout << point.name() << std::endl; for (auto val : point.children()) { std::cout << val.name() << " : " << val.child_value() << std::endl;// 値の取得にはtext()かchild_value()を使う } } }
前に試したBlenderのボリュームで銀河を作るやつで、テクスチャを渦巻状にしていた。
Create a Galaxy in Blender – Iridesiumを試す(1)
改めて説明しろと言われるとやりにくいのでまとめておく。
モデルにテクスチャが張り付いているとき、モデル上のある点の色は、テクスチャ上のどこかからとってきている。従って、テクスチャ座標を変換することでずらしたりできる。
テクスチャ座標をただ回転させただけでは、テクスチャが回るだけで渦巻にはならない。
テクスチャが回転するだけなのは、モデル上の全ての位置で、同じ回転量だけ変化させてテクスチャの色をとってくるからで、つまり、モデル上の場所によって回転量を変化させれば、歪んだ座標系の色が取得できる。
モデル上のある点の色を決めるとき、「テクスチャのどの位置から色をとってくるか」を求める際に、その座標をアフィン変換してやるのがmappingで、そこで回転を指定し、回転量としてGradientTextureを与えることで、場所によって回転量を変化させることができる。
クリップボードを監視する方法を調べてみたら、AddClipboardFormatListenerにウィンドウハンドルを渡しておけば、クリップボードにコピーが発生するたびにWM_CLIPBOARDUPDATEメッセージが入ってくることが分かったのでこれを使うとクリップボードを管理するようなプログラムを書ける。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: // クリップボード監視開始 AddClipboardFormatListener(hWnd); return 0; case WM_CLIPBOARDUPDATE: // クリップボードが使用されるとこのメッセージが入る if (OpenClipboard(hWnd)) { // クリップボードの内容がテキストの時だけ処理 if ((IsClipboardFormatAvailable(CF_TEXT) == TRUE)) { HGLOBAL hg = GetClipboardData(CF_TEXT); size_t size = GlobalSize(hg); LPVOID strClip = GlobalLock(hg); char* strText = new char[size]; strcpy(strText, (char*)strClip); //クリップボード後始末 GlobalUnlock(hg); CloseClipboard(); // 表示 HDC hdc = GetDC(hWnd); RECT rect{ 0,0,100,100 }; DrawTextA(hdc, (char*)strText, -1, &rect, DT_LEFT); ReleaseDC(hWnd, hdc); } } return 0; case WM_LBUTTONDOWN: return 0; case WM_DESTROY: // クリップボード監視終了 RemoveClipboardFormatListener(hWnd); PostQuitMessage(0); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
このコードは、クリップボードに文字列がコピーされると画面にその内容を表示する。
前回
Create a Galaxy in Blender – Iridesiumを試す(1)
小さな星をちりばめるテクスチャを作成。
注意:あまりに見えづらい場合は強調させて作業を進める。(動画には入っていない)
さらに、星雲にノイズを加えてよりそれらしくする
いろいろと調整して以下のように出来上がる。
https://www.youtube.com/watch?v=HCBW4fNAjBg
try-blender-tutorial-Create-a-Galaxy-in-Blender-Iridesium-2
Create a Galaxy in Blender – Iridesiumを試す(2)
最初に背景を黒にしておく。
次にCubeを追加。座標系をObjectにするのでX,Y方向にやや大きめのSphereを追加する。
ここでは30x30x2の直方体とする。
CubeにVolumeを追加し以下のように設定。
注:図ではPrincipled VolumeのEmission StrengthにつながっているがEmission Colorが正しい。
④、ここが最も重要な場所で、Gradient TextureのSpherical(=球状のグラデーション)をMappingのRotationに接続する。これによって中央から外側にかけて回転量を変化させ渦巻状を作成する。渦巻の巻き具合はGradient Textureの値に対するMathで調節する。
ここまでが基本的なアイデアとのこと。
続く。
format,typeはテクスチャとして用意したメモリの形式。
internalformatはそれをOpenGLがどのように使うかを指定する。
#include <iostream> #include <array> #include <Windows.h> // GL_BGRなどを使うにはglew.hが必要。自分で定義してもいい #include <GL/glew.h> #include <gl/GL.h> #include <gl/GLU.h> #include <gl/freeglut.h> GLuint texName; //ウィンドウの幅と高さ int width, height; //描画関数 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); //glEnable(GL_CULL_FACE); double v = 0.7; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texName); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(-0.9, -0.9); glTexCoord2f(0, 1); glVertex2f(-0.9, 0.9); glTexCoord2f(1, 1); glVertex2f(0.9, 0.9); glTexCoord2f(1, 0); glVertex2f(0.9, -0.9); glEnd(); 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); glutCreateWindow("sample"); glutDisplayFunc(disp); glutReshapeFunc(reshape); glEnable(GL_TEXTURE_2D); glGenTextures(1, &texName); glBindTexture(GL_TEXTURE_2D, texName); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); const int TEXSIZE = 2; std::array<unsigned char, 3> texrgb[TEXSIZE * TEXSIZE]; texrgb[0] = std::array<unsigned char, 3>{255, 0, 0 }; texrgb[1] = std::array<unsigned char, 3>{ 0, 255, 0 }; texrgb[2] = std::array<unsigned char, 3>{ 0, 0, 255}; texrgb[3] = std::array<unsigned char, 3>{255, 128, 0}; #if 0 // formatをGL_RGBにした場合 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, // internalformat TEXSIZE, TEXSIZE,0, GL_RGB, // format GL_UNSIGNED_BYTE, &texrgb[0] ); #else // formatをGL_BGRにした場合 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, // internalformat TEXSIZE, TEXSIZE,0, GL_BGR, // format GL_UNSIGNED_BYTE, &texrgb[0] ); #endif glutMainLoop(); return 0; }
上の例では、例えば{255,0,0}というデータを用意する。これをformatで「RGBの順にデータが並んでいますよ」と指定すると、internalformatで「RGBのテクスチャを使う」と指定してあるので、赤いドットとなる。
逆に、「BGRの順にデータが並んでいますよ」と指定すると、internalformatで「RGBのテクスチャを使う」と指定してあるので、BGRの順にデータが並んでいることを考慮し、青いドットとなる。
このように、「formatでデータの並び方を確認し、internalformatで指定した解釈でテクスチャとして利用する」ので、「formatで指定した形式からinternalformatで指定した形式に変換されている」といえる。
厄介なのがほとんどの場合この変換をしてくれないので、実質組み合わせが決まっているようなものになっている。
まず以下のプログラムを実行する。
#include <iostream> #include <pcl/common/impl/common.hpp> //getMeanStdDev #pragma comment(lib,"pcl_commond.lib") int main() { std::vector<float> v; v.push_back(-1.841658711); v.push_back(-1.449076772); v.push_back(-1.04681015); v.push_back(-0.646572888); v.push_back(-0.25920701); v.push_back(0.149769783); v.push_back(-1.883069754); v.push_back(-1.481496215); v.push_back(-1.083532453); //不偏標準偏差 double mean, stddev; pcl::getMeanStdDev(v, mean, stddev); printf("平均:%lf\n", mean); printf("不偏標準偏差%lf\n", stddev); }
Excelでは、母標準偏差(nで割る方)をSTDEV.P、不偏標準偏差(n-1で割る方)をSTDEV.Sで計算する。
母標準偏差と不偏標準偏差の違いは、母標準偏差は母集団に対して使うのに対して、不偏標準偏差は母集団の標本、つまり元データをサンプリングしたデータに対して使う。
#include <iostream> #include <vector> #include "ppmP3_read.hpp"
class Filter { //画像フィルタ std::vector< std::vector<float> > m_filter; public: //! @brief コンストラクタ //! @param [in] カーネルの一辺のサイズ Filter(const int size) { m_filter.resize(size, std::vector<float>(size, 0)); } //! @brief フィルタの数値を設定する関数 //! @param [in] row 行番号 //! @param [in] 一行分のデータ //! @return なし void set(int row, std::initializer_list<float> values) { int i = 0; for (auto v : values) { m_filter[row][i] = v; i++; } } //! @brief フィルタの全ての要素を割り算する //! @param [in] f 割る数 void operator/=(const float f) { for (auto&& row : m_filter) { for (auto&& c : row) { c /= f; } } } //! @brief フィルタのカーネルの一辺のサイズ int size() const{ return m_filter.size(); } //! @brief フィルタの要素を取得 //! @param [in] x -size()/2 から size()/2 までの整数 //! @param [in] y -size()/2 から size()/2 までの整数 float get(int x, int y)const { int sz = size() / 2; return m_filter[x + sz][y + sz]; } int posmin()const { return -size() / 2; } int posmax()const { return size() / 2; } };
struct image { unsigned char* src; int width; int height; int pixelsize; };
//! @brief 画像にフィルタを適用 //! @param [in] filter 画像フィルタ //! @param [in] x フィルタを適用する画素の座標 //! @param [in] y フィルタを適用する画素の座標 //! @param [in] src 元画像 //! @param [in] ret 結果画像 void apply(const Filter& filter,int x, int y,const image& src, unsigned char* ret) { const int posmin = filter.posmin(); const int posmax = filter.posmax(); const int pixSize = src.pixelsize; unsigned char* retp= &ret[pixSize * (y * src.width + x)]; for (int i = 0; i < pixSize; i++) { retp[i] = 0; } for (int fx = posmin; fx <= posmax; fx++) { for (int fy = posmin; fy <= posmax; fy++) { float g = filter.get(fx, fy); int yy = y + fy; int xx = x + fx; if (yy < 0 || xx < 0) continue; unsigned char* s = &src.src[pixSize * (yy * src.width + xx)]; for (int i = 0; i < pixSize; i++) { retp[i] += s[i]*g; } } } }
int main() { int width; int height; int vmax; // 画像を読み込む unsigned char * img_src = ppmP3_read( "C:\\dev\\c.ppm", &width, &height, &vmax, [](const size_t count) {return new unsigned char[count]; } ); std::vector<unsigned char> img_dst(width * height * 3); #define F1 //フィルタ作成 #ifdef F0 Filter ff(3); ff.set(0, { 1,2,1 }); ff.set(1, { 2,4,2 }); ff.set(2, { 1,2,1 }); ff /= 16.f; #elif defined(F1) Filter ff(5); ff.set(0, { 1, 4, 6, 4,1 }); ff.set(1, { 4,16,24,16,4 }); ff.set(2, { 6,24,36,24,6 }); ff.set(3, { 4,16,24,16,4 }); ff.set(4, { 1, 4, 6, 4,1 }); ff /= 256.f; #elif defined(F2) Filter ff(7); ff.set(0, { 1, 6, 15, 20, 15, 6, 1 }); ff.set(1, { 6, 36, 90,120, 90, 36, 6 }); ff.set(2, { 15, 90,225,300,225, 90, 15 }); ff.set(3, { 20,120,300,400,300,120, 20 }); ff.set(4, { 15, 90,225,300,225, 90, 15 }); ff.set(5, { 6, 36, 90,120, 90, 36, 6 }); ff.set(6, { 1, 6, 15, 20, 15, 6, 1 }); ff /= 4096.f; #endif //全てのピクセルにフィルタを適用 for (size_t x = 0; x < width; x++) { for (size_t y = 0; y < height; y++) { apply(ff,x, y, image{ img_src, width,height,3 }, img_dst.data()); } } //フィルタをかけた画像を保存 pnmP3_Write("C:\\dev\\e.ppm", 255, width, height, img_dst.data()); delete[]img_src; }