スレッドを待機させるためのcondition_variableの使い方を確認中。
とりあえず使い方や注意点をまとめたコードを書いてみたがなんか何をやりたいのかよくわからないコードになったのでもう少し考える。
#include <iostream> #include <vector> #include <thread> #include <mutex> #include <condition_variable> #include <random> #include <chrono> std::vector<double> data; std::mutex mtx; std::condition_variable cv; // データが10個以上あればメインスレッドを起こすという条件を定義 // 判断中にdata.size()が変化する可能性があるので、必ずロック中に呼び出すこと bool allow_to_main_wakeup() { return data.size() >= 10; }
// 無限にデータを生成し続ける関数 // ただし、10個データが貯まったらメインスレッドで処理する要求を出す // メインスレッドがデータを移動する間、このスレッドは休止する void Factory() { // 値を生成する関数 int count = 0; auto create_value = [&count]() { return count++; }; // 無限にデータを生成してdataに追加し続ける while (true) { bool allow_to_wakeup = false; { // 仮に、先にメインスレッドでlockした場合、このスレッドはlock(mtx); でブロック中となる // メインスレッド側ですぐにcv.wait()で待機開始するため、すぐにこのブロックは解除されることが期待できる std::unique_lock<std::mutex> lock(mtx); //================================== // データ作成処理本体 data.push_back( create_value() ); //================================== // メインスレッドで処理してよいかを判断。 // data.size()が別スレッドで変化しないために、ロック中に判断する allow_to_wakeup = allow_to_main_wakeup(); // 仮に、先にFactoryでlockした場合、メインスレッドはlock(mtx); でブロック中となっている // ここでスコープを抜けてunlockすることでメインスレッドがlockできるようになり、すぐにcv.wait()で待機開始 } // 現在メインスレッドはcv.wait()で待機中となっている。 // 特定の条件を満たしたら、メインスレッドで処理するためにメインスレッドを起こす処理をする if (allow_to_wakeup == true) { // notify_oneは同じcv.waitにより待機中のスレッドを一つだけ起こす。 cv.notify_one(); // notify_one()はこのスレッドには何もしないのでここはすぐに処理される // これ以降の処理はmainスレッドとの並列処理となる } // あまり速く動いても動作確認がしづらいのでスリープを入れる std::this_thread::sleep_for(std::chrono::milliseconds(100)); } }
int main() { // Factory関数を別スレッドで実行 // 以後、別スレッドでデータが自動生成され続ける std::thread producer(Factory); std::vector<double> tmp; // while (true) { { // ここでロック。ただしFactory関数側とどちらが先にロックするかは不定 std::unique_lock<std::mutex> lock(mtx); // waitすると内部でmtx.unlock()が呼ばれる // これによりFactory側でlock(mtx)ができるようになり、データの生成が可能になる // 同時に、このスレッドはFactory側でnotify_one()が呼ばれるまでここで待機 cv.wait(lock, [] { return allow_to_main_wakeup(); }); // cv.waitのラムダ式はSpurious Wakeup対策。 // 希にwait()中に何もしていないのにスレッドが起こされることがある // そのため、起こされたときに本当に起こされるべきかを関数により確認する // ここから先はcv.notify_one()により起こされてから実行される // これ以降の処理はFactory関数との並列処理となる。 // なおwait()を抜けた時点で、lockは再びlock状態となる //================================== // 別スレッドで作成されたデータを移動 tmp = std::move(data); //================================== } std::cout << "Generated numbers: "; for (double num : tmp) { std::cout << num << " "; } std::cout << std::endl; } producer.join(); return 0; }
以下のようにコンテナを作ったらpython 3.9のインストールに一手間かかったのでメモ。
なおapt update && apt upgrade はしてある。
まずそのまま
とすると
が出てくる。ubuntu:latestで導入すると最小構成で入るのでデフォルトのレポジトリに入っていなかったりするらしい。
update-alternativesは複数バージョンあるコマンドに対して、どのバージョンを使うかを指定する。
python --version
Python 3.9.21
pip --version
pip 25.0.1 from /usr/local/lib/python3.9/dist-packages/pip (python 3.9)
SkSurfaceの使い方がずっとわからなかった。SkSurfaces::Rasterでインスタンスを作成できる。
void Test() { // #include "skia/include/core/SkSurface.h" SkImageInfo imginfo = SkImageInfo::Make(400, 400, kBGRA_8888_SkColorType, kOpaque_SkAlphaType); sk_sp<SkSurface> surface = SkSurfaces::Raster(imginfo); SkCanvas* canvas = surface->getCanvas(); // 図形の描画 SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(5); paint.setColor(SK_ColorBLUE); canvas->clear(SK_ColorWHITE); canvas->drawCircle(200, 200, 100, paint); // PNG出力 SkPixmap pixmap; if (surface->peekPixels(&pixmap)) { SkFILEWStream stream("test_sksurface.png"); SkPngEncoder::Options options; options.fZLibLevel = 9; SkPngEncoder::Encode(&stream, pixmap, options); } }
ユーザー環境変数からPATHを編集しようとしたところ、「この環境変数は大きすぎます。このダイアログで設定できる値の長さは最大2047 文字です。」が発生し、パスを追加することも削除することもできなくなった。
1.PATHの中の記述を、他の変数(例えばPATH_ANACONDA)に分離し、PATHの文字数を2047以下にする。
2.PATHには%変数名%を入れておく
これでPATHの内容を維持しつつ文字数を減らせる。
マウスの右・左・ホイールで回転、移動、スケーリングする。
#pragma once #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/dcgraph.h> #include <wx/dcbuffer.h> #include <wx/geometry.h> #include <cmath> #include <wx/gdicmn.h>
//! @brief 画像を回転させる //! @param transform 回転させる画像のアフィン変換行列 //! @param imageCoordPos 回転の中心となる画像座標系の座標 //! @param rad 回転角度(ラジアン) void RotateAroundPoint(wxAffineMatrix2D& transform, const wxPoint2DDouble& imageCoordPos, const double rad); //! @brief 画像をクライアント座標系で移動させる //! @param transform 移動させる画像のアフィン変換行列 //! @param diff 移動量(パネルのクライアント座標系) void TranslateInScreenSpace(wxAffineMatrix2D& transform, const wxPoint& diff); //! @brief クライアント座標を元画像の座標系に変換 //! @param clientPos クライアント座標 //! @param transform 画像のアフィン変換行列 //! @return 元画像の座標系の座標 wxPoint2DDouble ClientToImage(const wxPoint& clientPos, const wxAffineMatrix2D& transform); //! @brief 画像を拡大・縮小する //! @param transform 拡大・縮小する画像のアフィン変換行列 //! @param scalefactor 拡大・縮小率 //! @param clientpos 拡大・縮小の中心座標(クライアント座標系) //! @details clientposに表示されているピクセルが移動しないように拡大・縮小する //! @return なし void Zoom(wxAffineMatrix2D& transform, double scalefactor, const wxPoint clientpos); //! @brief ウィンドウサイズの変化から、拡大・縮小率を計算する //! @param oldSize リサイズ前のウィンドウサイズ //! @param newSize リサイズ後のウィンドウサイズ //! @return 拡大・縮小率 double CalcResizeScaleFactor(const wxSize& oldSize, const wxSize& newSize); //! @brief マウスドラッグによる拡大・縮小率を計算する //! @param oldpos ドラッグ開始時のマウス座標 //! @param newpos ドラッグ中のマウス座標 //! @return 拡大・縮小率 double CalcDragScaleFactor(const wxAffineMatrix2D& transform, const wxPoint& oldpos, const wxPoint& newpos, const int pixelratio); //! @brief ウィンドウサイズが変化したときに、現在画面中央に表示されているピクセルが、リサイズ後も中央に表示されるようにする //! @param oldSize リサイズ前のウィンドウサイズ //! @param newSize リサイズ後のウィンドウサイズ //! @return なし void ResizeKeepCenter(wxAffineMatrix2D& transform, const wxSize& oldSize, const wxSize& newSize); //! @brief 画像をパネルにフィットさせるためのアフィン変換行列を計算 //! @param transform アフィン変換行列 //! @param imageSize 元画像のサイズ //! @param panelSize パネルのサイズ //! @return なし void FitImage(wxAffineMatrix2D& transform, const wxSize& imageSize, const wxSize& panelSize); //! @brief 3点の座標から回転角を計算する //! @param a 1つ目の座標(始点) //! @param b 2つ目の座標(回転中心) //! @param c 3つ目の座標(終点) //! @details cを中心に、aからbへ回転した時の回転角を計算する //! @return 回転角(ラジアン) double CalculateAngle(const wxPoint& a, const wxPoint& b, const wxPoint& c);
//////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // マウスによる移動量を角度で計算するクラス class MouseDrag { bool _during; // ドラッグ中かどうか wxPoint _center; // 角度計算の中心座標 wxPoint _from; // 開始地点のマウス座標 wxPoint _to; // 現在のマウス座標 public: MouseDrag(const wxPoint center) : _during(false), _center(center) {} MouseDrag() : _during(false), _center(0, 0) {} //! @brief ドラッグの開始地点 wxPoint GetFrom()const { return _from; } //! @brief ドラッグの現在地点 wxPoint GetTo()const { return _to; } //! @brief ドラッグ開始 void Start(const wxPoint newPos) { _from = newPos; _during = true; } //! @brief ドラッグ終了 void Stop() { _during = false; } //! @brief 現在回転中かどうか bool During() { return _during; } //! @brief マウスの移動量を更新 void Update(const wxPoint& newPos) {_to = newPos;} //! @brief マウスの移動量から角度を計算 double Angle() const{return CalculateAngle(_to, _center, _from);} //! @brief マウスの移動量を取得 wxPoint Difference()const {return _to - _from;} };
class ImagePanel : public wxPanel { enum class DragMode { NONE, MOVE, ROTATE, ZOOM }; wxAffineMatrix2D _transform; //!< アフィン変換行列 wxAffineMatrix2D _transform_back; //!< 移動・回転前のアフィン変換行列のバックアップ wxSize _winsize_back; //!< ウィンドウサイズが変更されるたびに更新されるウィンドウサイズのバックアップ // ウィンドウサイズの変化に関しては、変更開始イベントを拾えないため、変化するたびに前回からの差分に基づいて計算する DragMode _drag_mode; //!< ドラッグモード MouseDrag _mov_dragging; //!< マウスドラッグ間の移動量を計算・管理 std::weak_ptr<wxBitmap> _imageBitmap;//!< 画像データ public: ImagePanel(wxWindow* parent); //! @brief イベントのバインド void EventBind(); private: //! @brief ペイントイベントハンドラ void OnPaint(wxPaintEvent& event); //! @brief イベントハンドラ(移動開始イベントにバインドする用) void OnEventMoveStart(wxMouseEvent& event); //! @brief イベントハンドラ(移動終了イベントにバインドする用) void OnEventMoveStop(wxMouseEvent& event); //! @brief イベントハンドラ(回転開始イベントにバインドする用) void OnEventRotateStart(wxMouseEvent& event); //! @brief イベントハンドラ(回転終了イベントにバインドする用) void OnEventRotateStop(wxMouseEvent& event); //! @brief イベントハンドラ(ドラッグでスケーリング開始イベントにバインドする用) void OnEventScaleStart(wxMouseEvent& event); //! @brief イベントハンドラ(ドラッグでスケーリング終了イベントにバインドする用) void OnEventScaleStop(wxMouseEvent& event); //! @brief マウス移動イベントハンドラ void OnMouseMove(wxMouseEvent& event); //! @brief イベントハンドラ(ホイール回転でスケーリングイベントにバインドする用) void OnEventScaleChange(wxMouseEvent& event); //! @brief ウィンドウサイズ変更イベントハンドラ void OnResize(wxSizeEvent& event); public: //! @brief 表示する画像をセット //! @param bitmap 表示する画像データ //! return なし void SetImage(const std::shared_ptr<wxBitmap>& bitmap); //! @brief 画像が画面に収まるように調節する void FitImageToPanel(); private: //! @brief クライアント領域の中央の座標を取得 //! @return クライアント領域のサイズの1/2 wxPoint GetClientCenter(); //! @brief ドラッグしてズーム処理の開始 //! @param pos ドラッグ開始時のマウス座標 //! @return なし void ZoomStart(const wxPoint& pos); //! @brief ドラッグしてズーム処理の終了 //! @return なし void ZoomStop(); //! @brief ドラッグ中のズーム処理 //! @param pos ドラッグ中のマウス座標 //! @return 画面更新が必要かどうか bool ZoomDuring(const wxPoint& pos); //! @brief ドラッグして移動処理の開始 //! @param pos ドラッグ開始時のマウス座標 //! @return なし void MoveStart(const wxPoint& pos); //! @brief ドラッグして移動処理の終了 //! @return なし void MoveStop(); //! @brief ドラッグして移動中の処理 //! @param pos ドラッグ中のマウス座標 //! @return 画面更新が必要かどうか bool MoveDuring(const wxPoint& pos); //! @brief ドラッグして回転処理の開始 //! @param pos ドラッグ開始時のマウス座標 //! @return なし void RotateStart(const wxPoint& pos); //! @brief ドラッグして回転処理の終了 //! @return なし void RotateStop(); //! @brief ドラッグして回転中の処理 //! @param pos ドラッグ中のマウス座標 //! @return 画面更新が必要かどうか bool RotateDuring(const wxPoint& pos); };
#include "ImagePanel.hpp" ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
void RotateAroundPoint(wxAffineMatrix2D& transform, const wxPoint2DDouble& imageCoordPos, const double rad) { // 基準点 (px, py) を原点に移動 transform.Translate(imageCoordPos.m_x, imageCoordPos.m_y); // 回転を適用 (角度はラジアン単位) transform.Rotate(rad); // 元の位置に戻す transform.Translate(-imageCoordPos.m_x, -imageCoordPos.m_y); } void TranslateInScreenSpace(wxAffineMatrix2D& transform, const wxPoint& diff) { // アフィン変換行列の現在の回転・スケーリングを取得 wxMatrix2D mat2D; wxPoint2DDouble translation; transform.Get(&mat2D, &translation); // 回転を取り除くために逆回転行列を作成 double rad = std::atan2(mat2D.m_12, mat2D.m_11); // 現在の回転角を計算(ラジアン) wxAffineMatrix2D inverseRotation; inverseRotation.Rotate(-rad); // スケーリング値を計算 double scaleX = std::sqrt(mat2D.m_11 * mat2D.m_11 + mat2D.m_21 * mat2D.m_21); double scaleY = std::sqrt(mat2D.m_12 * mat2D.m_12 + mat2D.m_22 * mat2D.m_22); // 移動量 (dx, dy) を回転の影響を受けない座標系に変換 wxPoint2DDouble adjustedMove = inverseRotation.TransformPoint(wxPoint2DDouble(diff.x, diff.y)); // 変換行列に移動を適用 transform.Translate(adjustedMove.m_x / scaleX, adjustedMove.m_y / scaleX); } wxPoint2DDouble ClientToImage(const wxPoint& clientPos, const wxAffineMatrix2D& transform) { wxAffineMatrix2D inverse = transform; inverse.Invert(); wxPoint2DDouble imagePos = inverse.TransformPoint(wxPoint2DDouble(clientPos)); return imagePos; } void Zoom(wxAffineMatrix2D& transform, double scalefactor, const wxPoint clientpos) { // クライアント座標を元画像の座標系に変換 wxPoint2DDouble imagePos = ClientToImage(clientpos, transform); // スケーリングの中心をマウス座標に固定 transform.Translate(imagePos.m_x, imagePos.m_y); transform.Scale(scalefactor, scalefactor); transform.Translate(-imagePos.m_x, -imagePos.m_y); } double CalcResizeScaleFactor(const wxSize& oldSize, const wxSize& newSize) { double diffx = newSize.GetWidth() - oldSize.GetWidth(); double diffy = newSize.GetHeight() - oldSize.GetHeight(); double scalex = newSize.GetWidth() / (double)oldSize.GetWidth(); double scaley = newSize.GetHeight() / (double)oldSize.GetHeight(); double scalefactor = 1.0; if ((int)diffy != 0) scalefactor = scaley; return scalefactor; } double CalcDragScaleFactor(const wxAffineMatrix2D& transform, const wxPoint& oldpos, const wxPoint& newpos, const int pixelratio) { // 原点からの距離を計算 double olddist = std::sqrt(oldpos.x * oldpos.x + oldpos.y * oldpos.y); double newdist = std::sqrt(newpos.x * newpos.x + newpos.y * newpos.y); double scalefactor = 1.0; if (olddist < newdist) { // 拡大 scalefactor = 1.0 + (newdist - olddist) / pixelratio; } else { // 縮小 scalefactor = 1.0 - (olddist - newdist) / pixelratio; } return scalefactor; } void ResizeKeepCenter(wxAffineMatrix2D& transform, const wxSize& oldSize, const wxSize& newSize) { wxPoint oldwndCenter = wxPoint(oldSize.GetWidth() / 2, oldSize.GetHeight() / 2); wxPoint newwndCenter = wxPoint(newSize.GetWidth() / 2, newSize.GetHeight() / 2); // リサイズ前の画面中央に表示されていた画像の座標を取得 wxPoint2DDouble oldImageCenter = ClientToImage(oldwndCenter, transform); // 画面サイズの変化に応じた新しい中央座標を取得 wxPoint2DDouble newImageCenter = ClientToImage(newwndCenter, transform); // 変位を計算し、元の画像位置を新しい中央に移動 wxPoint2DDouble shift = oldImageCenter - newImageCenter; transform.Translate(-shift.m_x, -shift.m_y); } void FitImage(wxAffineMatrix2D& transform, const wxSize& imageSize, const wxSize& panelSize) { double scaleX = static_cast<double>(panelSize.GetWidth()) / imageSize.GetWidth(); double scaleY = static_cast<double>(panelSize.GetHeight()) / imageSize.GetHeight(); double scale = std::min(scaleX, scaleY); // 中心を計算 wxPoint offset( (panelSize.GetWidth() - imageSize.GetWidth() * scale) / 2, (panelSize.GetHeight() - imageSize.GetHeight() * scale) / 2); // アフィン変換を設定 transform = wxAffineMatrix2D(); transform.Translate(offset.x, offset.y); transform.Scale(scale, scale); } double CalculateAngle(const wxPoint& a, const wxPoint& b, const wxPoint& c) { wxRealPoint ab(b.x - a.x, b.y - a.y); wxRealPoint cb(b.x - c.x, b.y - c.y); // 内積を計算 double dotProduct = ab.x * cb.x + ab.y * cb.y; // ベクトルの大きさを計算 double magnitudeAB = std::sqrt(ab.x * ab.x + ab.y * ab.y); double magnitudeCB = std::sqrt(cb.x * cb.x + cb.y * cb.y); // コサイン double cosTheta = dotProduct / (magnitudeAB * magnitudeCB); cosTheta = std::min(1.0, std::max(-1.0, cosTheta)); // 角度を計算(ラジアン) double angleRad = std::acos(cosTheta); // 外積を使って角度の符号を決定 double cross = (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x); if (cross < 0.0) angleRad = -angleRad; return angleRad;// angleRad * 180.0 / M_PI; }
////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ImagePanel::ImagePanel(wxWindow* parent) : wxPanel(parent) { SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundColour(wxColour(0, 0, 0)); _transform = wxAffineMatrix2D(); _drag_mode = DragMode::NONE; EventBind(); } void ImagePanel::OnPaint(wxPaintEvent& event) { wxAutoBufferedPaintDC dc(this); dc.Clear(); std::shared_ptr<wxBitmap> pbitmap = _imageBitmap.lock(); if (!pbitmap) return; wxGraphicsContext* gc = wxGraphicsContext::Create(dc); if (gc) { wxGraphicsMatrix matrix = gc->CreateMatrix(_transform); gc->SetTransform(matrix); gc->DrawBitmap(*pbitmap, 0, 0, pbitmap->GetWidth(), pbitmap->GetHeight()); delete gc; } } void ImagePanel::OnEventMoveStart(wxMouseEvent& event) { MoveStart(event.GetPosition()); CaptureMouse(); } void ImagePanel::OnEventMoveStop(wxMouseEvent& event) { MoveStop(); if (HasCapture()) ReleaseMouse(); } void ImagePanel::OnEventRotateStart(wxMouseEvent& event) { RotateStart(event.GetPosition()); CaptureMouse(); } void ImagePanel::OnEventRotateStop(wxMouseEvent& event) { RotateStop(); if (HasCapture()) ReleaseMouse(); } void ImagePanel::OnEventScaleStart(wxMouseEvent& event) { ZoomStart(event.GetPosition()); CaptureMouse(); } void ImagePanel::OnEventScaleStop(wxMouseEvent& event) { ZoomStop(); if (HasCapture()) ReleaseMouse(); } void ImagePanel::OnMouseMove(wxMouseEvent& event) { if (_mov_dragging.During()) { switch (_drag_mode) { case DragMode::MOVE: if (MoveDuring(event.GetPosition())) { Refresh(); } break; case DragMode::ROTATE: if (RotateDuring(event.GetPosition())) { Refresh(); } break; case DragMode::ZOOM: if (ZoomDuring(event.GetPosition())) { Refresh(); } break; } } } void ImagePanel::OnEventScaleChange(wxMouseEvent& event) { int wheelRotation = event.GetWheelRotation(); // ホイールの回転量によって拡大・縮小率を変更 double scaleFactor = (wheelRotation > 0) ? 1.1 : 0.9; // マウスのクライアント座標を取得 wxPoint clientPos = event.GetPosition(); Zoom(_transform, scaleFactor, clientPos); Refresh(); } void ImagePanel::OnResize(wxSizeEvent& event) { if (GetClientSize().GetWidth() == 0 || GetClientSize().GetHeight() == 0) return; if (_imageBitmap.lock()) { wxSize oldSize = _winsize_back; wxSize newSize = GetClientSize(); ResizeKeepCenter(_transform, oldSize, newSize); double scalefactor = CalcResizeScaleFactor(oldSize, newSize); if ((scalefactor > 0.001) && !isnan(scalefactor) && !isinf(scalefactor)) Zoom(_transform, scalefactor, GetClientCenter()); } // 旧ウィンドウサイズを記録 _winsize_back = GetClientSize(); Refresh(); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// void ImagePanel::EventBind() { Bind(wxEVT_PAINT, &ImagePanel::OnPaint, this); // 移動に割り当て Bind(wxEVT_LEFT_DOWN, &ImagePanel::OnEventMoveStart, this); Bind(wxEVT_LEFT_UP, &ImagePanel::OnEventMoveStop, this); // 回転に割り当て Bind(wxEVT_RIGHT_DOWN, &ImagePanel::OnEventRotateStart, this); Bind(wxEVT_RIGHT_UP, &ImagePanel::OnEventRotateStop, this); // ホイールドラッグによる拡大・縮小 Bind(wxEVT_MIDDLE_DOWN, &ImagePanel::OnEventScaleStart, this); Bind(wxEVT_MIDDLE_UP, &ImagePanel::OnEventScaleStop, this); /* // 拡大・縮小に割り当て Bind(wxEVT_MOUSEWHEEL, &ImagePanel::OnEventScaleChange, this); */ Bind(wxEVT_MOTION, &ImagePanel::OnMouseMove, this); Bind(wxEVT_SIZE, &ImagePanel::OnResize, this); } void ImagePanel::SetImage(const std::shared_ptr<wxBitmap>& bitmap) { _imageBitmap = bitmap; Refresh(); } void ImagePanel::FitImageToPanel() { std::shared_ptr<wxBitmap> pbitmap = _imageBitmap.lock(); if (!pbitmap) return; // スケール計算 wxSize panelSize = GetClientSize(); wxSize imageSize = pbitmap->GetSize(); FitImage(_transform, imageSize, panelSize); _winsize_back = GetClientSize(); Refresh(); } wxPoint ImagePanel::GetClientCenter() { wxSize panelSize = GetClientSize(); return wxPoint(panelSize.GetWidth() / 2, panelSize.GetHeight() / 2); } void ImagePanel::ZoomStart(const wxPoint& pos) { _drag_mode = DragMode::ZOOM; _transform_back = _transform; _mov_dragging.Start(pos); } void ImagePanel::ZoomStop() { _mov_dragging.Stop(); } bool ImagePanel::ZoomDuring(const wxPoint& pos) { _mov_dragging.Update(pos); wxPoint oldpos = _mov_dragging.GetFrom(); wxPoint newpos = _mov_dragging.GetTo(); wxPoint diff = _mov_dragging.Difference(); if (diff.x == 0 && diff.y == 0) { return false; } wxPoint winoldpos = ClientToScreen(oldpos); wxPoint winnewpos = ClientToScreen(newpos); double scalefactor = CalcDragScaleFactor(_transform, winoldpos, winnewpos, GetClientSize().GetWidth()); if (!isnan(scalefactor) && !isinf(scalefactor)) { _transform = _transform_back; Zoom(_transform, scalefactor, oldpos); } else { return false; } return true; } void ImagePanel::MoveStart(const wxPoint& pos) { _drag_mode = DragMode::MOVE; _transform_back = _transform; _mov_dragging.Start(pos); } void ImagePanel::MoveStop() { _mov_dragging.Stop(); } bool ImagePanel::MoveDuring(const wxPoint& pos) { _mov_dragging.Update(pos); wxPoint diff = _mov_dragging.Difference(); if (diff.x == 0 && diff.y == 0) return false; _transform = _transform_back; // 移動量を画面座標系で適用 TranslateInScreenSpace(_transform, diff); return true; } void ImagePanel::RotateStart(const wxPoint& pos) { _drag_mode = DragMode::ROTATE; _transform_back = _transform; // クライアント領域の中心座標を取得 wxSize panelSize = GetClientSize(); _mov_dragging = MouseDrag(GetClientCenter()); _mov_dragging.Start(pos); } void ImagePanel::RotateStop() { _mov_dragging.Stop(); } bool ImagePanel::RotateDuring(const wxPoint& pos) { _mov_dragging.Update(pos); double rad = _mov_dragging.Angle(); if (isnan(rad) || isinf(rad)) return false; _transform = _transform_back; auto imgpos = ClientToImage(GetClientCenter(), _transform); RotateAroundPoint(_transform, imgpos, rad); return true; }
// https://docs.wxwidgets.org/3.0/overview_helloworld.html // プリプロセッサに以下二つを追加 // __WXMSW__ // WXUSINGDLL // サブシステムをWindowsに設定(WinMainで呼び出すので) // Windows (/SUBSYSTEM:WINDOWS) #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/gdicmn.h> // wxPointに必要 #include <wx/frame.h> // wxFrameに必要 ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// #include <string> #include "ImagePanel.hpp" // ウィンドウ作成 class MyFrame : public wxFrame { ImagePanel* _imagePanel;// 画像表示パネル std::shared_ptr<wxBitmap> _bitmap; public: void PostCreate() { // wxImage::AddHandler(new wxPNGHandler); _bitmap = std::make_shared<wxBitmap>(); wxImage image; if (image.LoadFile(R"(C:\temp\test.png)", wxBITMAP_TYPE_PNG)) {// 画像読み込み *_bitmap = wxBitmap(image); } this->Layout(); // レイアウトの更新 _imagePanel->SetImage(_bitmap);// パネルに画像を指定 _imagePanel->FitImageToPanel(); } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); // ImagePanel作成 _imagePanel = new ImagePanel(this); // 画面いっぱいに貼り付ける wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(_imagePanel, 1, wxEXPAND); this->SetSizer(sizer); } private: }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340)); frame->Show(true); return true; } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);
libzipでファイル一覧を取得すると、元のディレクトリ構造が取得できるが、ツリーになっていない。これをツリーに変換する。
#include <iostream> #include <vector> #include <string> #include <sstream> #include <filesystem> // SetConsoleOutputCP のために必要 #include <windows.h> // libzip #include <zip.h> #pragma comment(lib,"zip.lib")
enum class FileType { Ignore, Directory, File };
struct DirTree { std::string name; FileType type; std::vector<DirTree> children; DirTree(const std::string& name, const FileType type) : name(name), type(type){} };
// 既に登録済みかどうかをチェックし、既にあるノードならイテレータを返す std::vector<DirTree>::iterator getNodeIfAlreadyRegistered(DirTree& root, const std::string& name) { return std::find_if( root.children.begin(), root.children.end(), [&](const DirTree& child) { return child.name == name; } ); }
void AddPath(DirTree& root, const std::string& path) { namespace fs = std::filesystem; std::istringstream ss(path); std::string segment; DirTree* current = &root; // 次の'/'までのパスを取得 while (std::getline(ss, segment, '/')) { // 過去にツリーに登録されたノードかどうかをチェック auto currentnode = getNodeIfAlreadyRegistered(*current, segment); // すでに登録済みなら次回以降のノードはそのノードより下に追加 if (currentnode != current->children.end()) { current = &(*currentnode); } else { // 最後の要素以外はディレクトリであることは自明なので、ディレクトリとして登録 current->children.push_back({ segment, FileType::Directory }); current = ¤t->children.back(); } } // 最後の要素はファイルの可能性があるので、pathに'/'があるかどうかで判別 bool isDir = path.back() == '/'; current->type = isDir ? FileType::Directory : FileType::File; }
// ファイルリストをツリー構造に変換 DirTree BuildDirTree(const std::vector<std::string>& files) { DirTree root( "root", FileType::Ignore); for (const auto& file : files) { AddPath(root, file); } return root; }
// ファイルツリーを表示 void printTree(const DirTree& tree, int depth = 0) { auto to_string = [](const FileType type) { switch (type) { case FileType::Ignore: return "*"; case FileType::Directory: return "[DIR]"; case FileType::File: return "[FILE]"; } return "Unknown"; }; std::string indent(depth * 2, ' '); std::cout << indent << to_string(tree.type) << tree.name << "\n"; for (const auto& child : tree.children) { printTree(child, depth + 1); } }
std::vector<std::string> FilesInZip(const char* pathname) { std::vector<std::string> files; // エラーコードを格納する変数 int error = 0; // zipファイルを読み取り専用でオープン zip_t* zipArchive = zip_open(pathname, ZIP_RDONLY, &error); if (zipArchive == nullptr) { return std::vector<std::string>(); } // zipファイル内のエントリ数を取得 zip_int64_t numEntries = zip_get_num_entries(zipArchive, 0); // 各エントリの名前を取得して表示 for (zip_uint64_t i = 0; i < static_cast<zip_uint64_t>(numEntries); ++i) { const char* entryName = zip_get_name(zipArchive, i, 0); files.emplace_back(entryName); // zipファイル内のファイル名を格納 } // zipファイルをクローズ zip_close(zipArchive); return files; }
int main() { std::vector<std::string> files = FilesInZip((const char*)u8R"(C:\test\ConsoleApplication31.zip)"); // windowsのコンソールでUTF-8を表示するために必要 SetConsoleOutputCP(CP_UTF8); // ファイルのリストをツリー構造に変換 DirTree root = BuildDirTree(files); printTree(root); for(auto& f : files) { std::cout << f << std::endl; } }
まずfilesをそのまま表示すると以下のようになる。
これをツリーにして、printTreeで出力すると以下になる。
*root [FILE]ConsoleApplication31.sln [DIR].vs [DIR]ConsoleApplication31 [DIR]copilot-chat [DIR]ff91ad84 [DIR]sessions [DIR]FileContentIndex [FILE]b5c23407-6b8a-446b-82cf-97b7abb15edd.vsidx [DIR]v17 [FILE].suo [FILE]Browse.VC.db [FILE]DocumentLayout.json