幾何問題に時間がかかるのがストレスだったので、主に自分用にライブラリを作りました。ちなみに幾何ライブラリの代表的なものでは https://ei1333.github.io/luzhiled/ があり、これにほとんどの機能が揃っているのですが、コンパイルが上手くいかなかったり、必要としている API を見つけるのに時間がかかったりすることが多かったので(自分が慣れていないせいで、このライブラリが悪いとかそういうことではないです)、自分用に機能を絞って作り直した、という感じです。
インクルード、インポートは最小限に、簡潔に記述できるものを目指して作っています。
※以下のライブラリは二次元空間用です。「外積」は、正確には外積のスカラーとして扱っています。
C++
#include <iostream>
#include <math.h>
using namespace std;
struct Point
{
double x = 0;
double y = 0;
void rot(double angle)
{
double new_x = x * cos(angle) - y * sin(angle);
double new_y = x * sin(angle) + y * cos(angle);
x = new_x;
y = new_y;
}
void rot(int degree)
{
double pi = atan(1) * 4;
double angle = double(degree) / 180 * pi;
rot(angle);
}
double norm()
{
return sqrt(x * x + y * y);
}
double arg()
{
return atan2(y, x);
}
double operator*(Point &other)
{
return x * other.x + y * other.y;
}
double operator^(Point &other)
{
return x * other.y - y * other.x;
}
Point operator+(Point &other)
{
Point ans;
ans.x = x + other.x;
ans.y = y + other.y;
return ans;
}
Point operator-(Point &other)
{
Point ans;
ans.x = x - other.x;
ans.y = y - other.y;
return ans;
}
int ccw(Point B, Point C)
{
Point A = *this;
Point AB = B - A;
Point AC = C - A;
double cross = AB ^ AC;
if (cross > 0)
{
return 1;
}
else if (cross == 0)
{
return 0;
}
else
{
return -1;
}
return true;
}
};
ostream &operator<<(ostream &os, Point p)
{
os << "(" << p.x << "," << p.y << ")";
return os;
}
説明
インクルードする必要があるライブラリは math.h
のみです。
メンバ
-
x
$x$ 座標を返します。 -
y
$y$ 座標を返します。
メソッド
-
norm()
長さを出します -
arg()
偏角を出します。 -
rot(a)
点を回転させます。double
を入力した場合はラジアンとして、int
を入力した場合は度として扱います。 -
ccw(A,B)
この点に対して、他の 2 点 $A,B$ が反時計回りに並んでいるかを検出します。1 は反時計回り、0 は同一直線上、-1 は時計回りです。
また、演算子をオーバーロードしているので、Point
同士で演算ができます。
オペレータ
-
+
それぞれの座標を足し算したものを返します。 -
-
それぞれの座標を引き算したものを返します。 -
*
Point
を作用させた場合は内積を、double
を作用させた場合はスカラー倍にしたものを返します。 -
^
外積を返します。
具体例
int main(void)
{
Point A({1, 2});
cout << A << endl; // (1,2)
A.rot(90); // int を代入しているので 90 度回転
cout << A << endl; // (-2,1)
Point B({3, 4});
cout << A + B << endl; // (1,5)
cout << A - B << endl; // (-5,3)
cout << A * B << endl; // -2 内積
cout << A * 2 << endl; // (-4,2) スカラー倍
cout << (A ^ B) << endl; // -11 外積
}
Python
from math import atan2, cos, pi, sin, sqrt
class Point:
def __init__(self, x=0.0, y=0.0) -> None:
self.x = x
self.y = y
self.norm = sqrt(self.x**2 + self.y**2)
self.arg = atan2(self.y, self.x)
def rot(self, angle) -> None: # angle is float/int
if type(angle) == int:
angle = angle/180*pi
self.x, self.y = self.x * \
cos(angle) - self.y*sin(angle), self.x * \
sin(angle) + self.y*cos(angle)
def __add__(self, other: 'Point') -> 'Point':
return Point(self.x + other.x, self.y + other.y)
def __sub__(self, other: 'Point') -> 'Point':
return Point(self.x - other.x, self.y - other.y)
def __mul__(self, other): # float/int -> Point, or Point -> float
if type(other) == float or type(other) == int:
return Point(self.x*other, self.y*other)
return self.x * other.x + self.y * other.y
def __xor__(self, other: 'Point') -> float:
return self.x * other.y - self.y * other.x
def ccw(self, B: 'Point', C: 'Point') -> int:
AB = B - self
AC = C - self
cross = AB ^ AC
if cross > 0:
return 1
elif cross == 0:
return 0
else:
return -1
def __str__(self) -> str:
return f'({self.x},{self.y})'
説明
インポートする必要があるライブラリは math
のみです。
メンバ
-
x
$x$ 座標を返します。 -
y
$y$ 座標を返します。 -
norm
長さを出します -
arg
偏角を出します。
メソッド
-
rot(a)
点を回転させます。float
を入力した場合はラジアンとして、int
を入力した場合は度として扱います。 -
ccw(A,B)
この点に対して、他の 2 点 $A,B$ が反時計回りに並んでいるかを検出します。1 は反時計回り、0 は同一直線上、-1 は時計回りです。
オペレータ
-
+
それぞれの座標を足し算したものを返します。 -
-
それぞれの座標を引き算したものを返します。 -
*
Point
を作用させた場合は内積を、double
を作用させた場合はスカラー倍にしたものを返します。 -
^
外積を返します。
具体例
A = Point(1, 2)
print(A) # (1,2)
A.rot(90) # int を代入しているので 90 度回転
print(A) # (-2.0,1.0000000000000002)
B = Point(3, 4)
print(A+B) # (1.0,5.0)
print(A-B) # (-5.0,-3.0)
print(A*B) # -1.9999999999999991 // 内積
print(A*2) # (-4.0,2.0000000000000004) // スカラー倍
print(A ^ B) # -11.0 // 外積
Validation
随時追加