「技術」カテゴリーアーカイブ

【数学】【PYTHON】行列の足し算・引き算を行う

【数学】【PYTHON】法線ベクトル(ベクトルの外積)を求める | 自分、ぼっちですが何か? (taki-lab.site)

NumPyのmatrix()を使用すれば、行列も簡単に扱うことができるようになります。

たとえば、こんな行列の計算を行う場合、

>>> import numpy as np
>>> A = np.matrix([[50, 40],[10, 10]])
>>> B = np.matrix([[30, 100],[20, 15]])
>>> A+B
matrix([[ 80, 140],
        [ 30,  25]])

DOCKERでRUNコマンドを仕込んでみる。

Dockerでコンテナ作成の勉強をする。 | 自分、ぼっちですが何か? (taki-lab.site)

DockerでRUNコマンドを使用し、パッケージをインストールするパターンです。

ファイル構成はこんな感じ。

Dockerfileの内容。

FROM php:7.4-apache

RUN apt-get update && apt-get install -y \
    tzdata \
    && rm -rf /var/lib/apt/lists/*

ENV TZ=Asia/Tokyo

WORKDIR /usr/local/etc/php

COPY php.ini ${PWD}

ARG wdir

WORKDIR $wdir

RUNで&&で区切ることによって、Buildの速度を上げるための施策らしい。

そして、最後のrmコマンドはapt-getコマンドのキャッシュを削除することによって、イメージサイズを小さくしているらしい。

これはお決まりのパターンってことだね。

php.ini

[Date]
date.timezone = Asia/Tokyo

[mbstring]
mbstring.language = Japanese

phpinfo.php

<h1>ようこそ! PHP!</h1>
ただいまの日時は、<?php echo date("Y-m-d H:i:s") ?> です。

<?php
echo phpinfo()
?>

イメージのビルド

~/dockerenv/ex02$ docker image build --build-arg wdir=/var/www/html -t ex02/php:1.0 .

イメージの実行

~/dockerenv/ex02$ docker container run --name ex02_php -d --rm -p 8080:80 --mount type=bind,src=$(pwd)/src,dst=/var/www/html ex02/php:1.0

Dockerでコンテナ作成の勉強をする。

これまで一生懸命Dockerを避けてきたのですが、

どうもすでにDockerでサービスを運用することがトレンドになっているらしいので、

これはもうやらざるを得ないかと。

そもそも前のプロジェクトでは、AWSのECS、ECRを使ってコンテナイメージをデプロイして運用するのですが、

AWS以外では、Kubernetes+Dockerで運用するのが一般的らしい。

OSを仮想化するのはVMでもできるけど、

Dockerの方が最小限のリソースで複数稼働させることができます。

デプロイ時にコンテナイメージを作成してしまえば、

スケールイン、アウトも簡単にできてしまいます。

ということで、まずはPHPを動かすだけのDockerを使ってみる。

使用した環境はWSL環境。

Dockerデスクトップインストール済み。

WSLにログインして、ディレクトリ作成。

~/dockerenv/ex01$ 

Dockerfileを作成。

FROM php:7.4-apache

LABEL maintainer="username@hogehoge.com"
LABEL version="1.0"
LABEL description="シンプルなPHPイメージです。"

WORKDIR /tmp/mydir

イメージをビルド

~/dockerenv/ex01$ docker image build -t ex01/php:1.0 .

Dockerを起動し、Docker内のbashを起動

~/dockerenv/ex01$ docker container run -it --rm ex01/php:1.0 /bin/bash

Docker内のphpのバージョン表示、現在ディレクトリ表示、Dockerを抜ける

root@212df36f6268:/tmp/mydir# php -v
PHP 7.4.33 (cli) (built: Nov 15 2022 06:03:30) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
root@212df36f6268:/tmp/mydir# pwd
/tmp/mydir
root@212df36f6268:/tmp/mydir# exit
exit

イメージの情報表示

~/dockerenv/ex01$ docker image inspect ex01/php:1.0 

LabelsブロックにDockerfileの内容が表示されていればOK

"Labels": {
                "description": "シンプルなPHPイメージです。",
                "maintainer": "username@hogehoge.com",
                "version": "1.0"
            },

【数学】【PYTHON】法線ベクトル(ベクトルの外積)を求める

法線ベクトルとは、2つのベクトルから計算されるベクトルで、

その向きは2つのベクトルの表現される面とは垂直のベクトルとなり、

その向きは「右ねじの法則」と呼ばれる法則によって決まります。

>>> import numpy as np
>>> a = np.array([0, 1, 2])
>>> b = np.array([2, 0, 0])
>>> np.cross(a, b)
array([ 0,  4, -2])

法線ベクトルの計算はcross()関数で求めることができます。

便利。

法線ベクトルはCGの世界では、法線ベクトルと光りのベクトルによって、

画面に表示する色や明るさなどを計算するのに使用されます。

【DIRECTX】DIRECT2Dを試す、その6(楕円を描く)

【DirectX】DIRECT2Dを試す、その5(直線を引く) | 自分、ぼっちですが何か? (taki-lab.site)

今回は楕円を描きます。

これまで通り、D2D_drawing()を修正します。

void D2D_drawing(ID2D1HwndRenderTarget* pRT)
{
	pRT->BeginDraw();
	pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));

	ID2D1SolidColorBrush* mybrush;
	pRT->CreateSolidColorBrush(
		D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
		&mybrush);
	D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(100.0f, 100.0f), 75.0f, 10.0f);
	pRT->SetTransform(D2D1::Matrix3x2F::Translation(0, 0));
	pRT->FillEllipse(ellipse, mybrush);
	pRT->SetTransform(D2D1::Matrix3x2F::Translation(200, 10));
	pRT->DrawEllipse(ellipse, mybrush, 1.0f);

	pRT->EndDraw();
}

まず、構造体D2D1_ELLIPSEなんですが、このように定義されています。

typedef struct D2D1_ELLIPSE {
    D2D1_POINT_2F point;
    float radiusX;
    float radiusY;
} D2D1_ELLIPSE;

この構造体は、中心座標 (point) と、 X 方向と Y 方向の半径 (radiusXradiusY) を表しています。X 方向と Y 方向の半径が等しい場合は、円を表します。

楕円を描くときは、DrawEllipse()を、塗りつぶした楕円を描くときはFillEllipse()を使用します。

void DrawEllipse(
  const D2D1_ELLIPSE &ellipse,
  ID2D1Brush *brush,
  FLOAT strokeWidth = 1.0f,
  ID2D1StrokeStyle *strokeStyle = NULL
);
  • ellipse: 描画する楕円を表す D2D1_ELLIPSE 構造体の参照。
  • brush: 描画に使用するブラシのポインタ。このブラシを使用して、楕円の塗りつぶし色を指定します。
  • strokeWidth (省略可能): 楕円の輪郭線の太さを表す浮動小数点値。デフォルト値は 1.0 です。
  • strokeStyle (省略可能): 楕円の輪郭線のスタイルを指定するための ID2D1StrokeStyle インタフェースへのポインタ。デフォルト値は NULL です。
HRESULT FillEllipse(
  D2D1_ELLIPSE ellipse,
  ID2D1Brush *brush,
  FLOAT strokeWidth = 1.0f,
  ID2D1StrokeStyle *strokeStyle = NULL
);

パラメータはDrawEllipse()と同じですね。

SetTransform()は図形の表示位置を設定しています。

第二パラメータにTranslation()の値を入れることで、平行移動変換マトリクスを作成して、それを使用して座標変換して表示してくれています。

【数学】【PYTHON】2つのベクトルのなす角度を求める。

この公式で求めることができます。

このケースを解いてみると、

>>> import math
>>> import numpy as np
>>> a = np.array([2,7])
>>> b = np.array([6,1])
>>> c = np.array([2,3])
>>> d = np.array([6,5])
>>>
>>> va = b - a
>>> vb = d - c
>>>
>>> norm_a = np.linalg.norm(va)
>>> norm_b = np.linalg.norm(vb)
>>>
>>> dot_ab = np.dot(va, vb)
>>>
>>> cos_th = dot_ab / (norm_a * norm_b)
>>> rad = math.acos(cos_th)
>>> deg = math.degrees(rad)
>>> print(deg)
82.8749836510982
>>>

変数a,b,c,dは各座標の値を示しています。

va,vbはベクトルの成分を計算しています。

引き算で計算できるのは便利。

np.linalg.norm()でベクトルの大きさを求めています。

ベクトルの各成分を2乗した和の平方根を計算してくれます。

np.dot()はベクトルの内積を求めています。

cos_thには上の公式を使用した計算結果が入ります。

これをcosの逆関数を計算し、ラジアンを角度に変換すると、

およそ83度という計算結果となります。

【DirectX】DIRECT2Dを試す、その5(直線を引く)

今回は画面に直線を引きます。

変更する箇所は、前回のソースコードのD2D_drawing()の中身。

void D2D_drawing(ID2D1HwndRenderTarget* pRT)
{
	pRT->BeginDraw();
	pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
	ID2D1SolidColorBrush* mybrush;
	pRT->CreateSolidColorBrush(
		D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
		&mybrush);
	pRT->DrawLine(
		D2D1::Point2F(10.0f, 50.0f),
		D2D1::Point2F(250.0f, 100.0f),
		mybrush,
		10.0f
	);
	pRT->EndDraw();
}

線を引くには、DrawLine()というメソッドを使います。

引数はこうなってます。

第一引数、第二引数は直線の始点と終点ですね。

第三引数のブラシは、CreateSolidColorBrush()で作成したデータです。

第四引数は線の太さですね。

第五引数は特に説明無かった。

【数学】【PYTHON】ベクトルの演算

ベクトルの演算を行うときは、成分同士を足したり引いたりして計算するんですが、

Numpyの配列を使えば、そういった演算もライブラリでやってくれます。

便利。

>>> import numpy as np
>>> a = np.array([2, 2])
>>> b = np.array([2, -1])
>>> a+b
array([4, 1])
>>> a-b
array([0, 3])
>>> 2*a
array([4, 4])
>>>

DIRECT2Dを試す、その4

前回まではWebで見つけたコードを試しに動かしてみる、と言うのをやったのですが、

今回からはちゃんと書籍を買いました。

英語です。

全部理解していなくてもコードを見れば解る(ハズ

というわけで、Windowを作成して、長方形を描画するサンプルコードです。

#include <windows.h>
#include <d2d1.h>
#include <d2d1helper.h>
#pragma comment(lib, "d2d1")

ID2D1Factory* pD2DFactory = NULL;
ID2D1HwndRenderTarget* pRT = NULL;

#define HIBA_00 TEXT("Error:Program initialisation process.")
HINSTANCE hInstGolb;
int SajatiCmdShow;
char szClassName[] = "WindowsApp";
HWND Form1;

LRESULT CALLBACK WndProc0(HWND, UINT, WPARAM, LPARAM);
void D2D_drawing(ID2D1HwndRenderTarget*);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("StdWinClassName");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass0;
	SajatiCmdShow = iCmdShow;
	hInstGolb = hInstance;

	wndclass0.style = CS_HREDRAW | CS_VREDRAW;
	wndclass0.lpfnWndProc = WndProc0;
	wndclass0.cbClsExtra = 0;
	wndclass0.cbWndExtra = 0;
	wndclass0.hInstance = hInstance;
	wndclass0.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass0.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass0.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	wndclass0.lpszMenuName = NULL;
	wndclass0.lpszClassName = TEXT("WIN0");

	if (!RegisterClass(&wndclass0))
	{
		MessageBox(NULL, HIBA_00, TEXT("Program Start"), MB_ICONERROR);
		return 0;
	}

	Form1 = CreateWindow(TEXT("WIN0"),
		TEXT("Form1"),
		(WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX),
		50,
		50,
		800,
		600,
		NULL,
		NULL,
		hInstance,
		NULL);

	ShowWindow(Form1, SajatiCmdShow);
	UpdateWindow(Form1);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

LRESULT CALLBACK WndProc0(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;

	switch (message)
	{
	case WM_CREATE:
		D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
		pD2DFactory->CreateHwndRenderTarget(
			D2D1::RenderTargetProperties(),
			D2D1::HwndRenderTargetProperties(
				hwnd, D2D1::SizeU(800, 600)),
			&pRT);
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		EndPaint(hwnd, &ps);
		D2D_drawing(pRT);
		return 0;

	case WM_CLOSE:
		pRT->Release();
		pD2DFactory->Release();
		DestroyWindow(hwnd);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}

void D2D_drawing(ID2D1HwndRenderTarget* pRT)
{
	D2D1_RECT_F myrectangle;
	myrectangle.left = 100;
	myrectangle.top = 100;
	myrectangle.right = 500;
	myrectangle.bottom = 500;
	ID2D1SolidColorBrush* mybrush;
	pRT->CreateSolidColorBrush(
		D2D1::ColorF(D2D1::ColorF::Green, 1.0f),
		&mybrush
	);
	pRT->BeginDraw();
	pRT->Clear(D2D1::ColorF(D2D1::ColorF::Black));
	pRT->FillRectangle(&myrectangle, mybrush);
	pRT->EndDraw();
}

コードがだいぶシンプルになった分、どこで何しているのかがとてもわかりやすいです。

以下の様なmain関数でビルドエラーが出る場合は、プロジェクトのプロパティの設定がおかしい場合があります。

LNK2019	未解決の外部シンボル main が関数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) で参照されました

線で囲った箇所を上の設定に合わせれば解決できるかも。

【数学】【PYTHON】ベクトルの方向を求める

ベクトルが示す座標(x,y)からベクトルの角度θを求めます。

計算式は、tanの逆関数を使います。

これをPythonで計算させます。

>>> import math
>>> rad = math.atan2(3,2)
>>> th = math.degrees(rad)
>>> th
56.309932474020215

atan2(x,y)でtanの逆関数の計算結果をラジアンで取得することができます。

ラジアンから角度の変換はdegrees()を使用します。

ベクトルの終端の座標が(3,2)ならば、角度はおよそ56度となります。