단순 덧셈 연산가능한 2차원 벡터 만들기

2d 벡터니 x, y만 가짐

덧셈 연산 구현

class Vec2():
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def add(self, v2):
        return Vec2(self.x + v2.x, self.y + v2.y)

v = Vec2(3, 4)
w = v.add(Vec2(-2, 6))
print(w.x, w.y)

 

 

 

 

2차원 벡터에 스칼라곱, 동등 비교연산 추가

스칼라 곱, 비교 연산, 덧셈 연산 추가후

벡터와 스칼라간 곱  + 덧셈 연산 결과 repr이 없어주소가 반환됨

class Vec2():
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def add(self, v2):
        return Vec2(self.x + v2.x, self.y + v2.y)

    def scale(self, scalar):
        return Vec2(scalar * self.x, scalar * self.y)
    
    def __eq__(self, other_vec : Vec2):
        return self.x == other_vec.x and self.y == other_vec.y
    
    def __add__(self, other_vec : Vec2):
        return self.add(other_vec)
    
    def __mul__(self, scalar):
        return self.scale(scalar)
    
    def __rmul__(self, scalar):
        return self.scale(scalar)

2 * Vec2(2, 0) + 5 * Vec2(0, 2)

 

 

2d 벡터 repr 추가

2d 벡터 출력시 원하는 형태로 안나오고 주소가 나옴

repr 작성해서 잘 나오도록 수정

class Vec2():
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def add(self, v2):
        return Vec2(self.x + v2.x, self.y + v2.y)

    def scale(self, scalar):
        return Vec2(scalar * self.x, scalar * self.y)
    
    def __eq__(self, other_vec : Vec2):
        return self.x == other_vec.x and self.y == other_vec.y
    
    def __add__(self, other_vec : Vec2):
        return self.add(other_vec)
    
    def __mul__(self, scalar):
        return self.scale(scalar)
    
    def __rmul__(self, scalar):
        return self.scale(scalar)
    
    def __repr__(self):
        return "Vec2({},{})".format(self.x, self.y)

2 * Vec2(2, 0) + 5 * Vec2(0, 2)

 

3차원 벡터 정의하기

2d 때랑 거의 비슷, z만 추가

class Vec3():
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    
    def add(self, v2):
        return Vec3(self.x + v2.x, self.y + v2.y, self.z + v2.z)
    
    def scale(self, scalar):
        return Vec3(self.x * scalar, self.y * scalar, self.z * scalar)

    def __add__(self, v2):
        return self.add(v2)
    
    def __eq__(self, v2):
        return self.x == v2.x and self.y == v2.y and self.z == v2.z
    
    def __mul__(self, scalar):
        return self.scale(scalar)

    def __rmul__(self, scalar):
        return self.scale(scalar)
    
    def __repr__(self):
        return "Vec3({},{},{})".format(self.x, self.y, self.z)

2.0 * (Vec3(1, 0, 0) + Vec3(0, 1, 0))

 

메타 클래스 Vector를 만들고, 상속받는 클래스 vec2 정의하기

메타 클래스 Vector에선 vec2. vec3 둘다 __mul__, __add__ 같은 연산자 함수 포함되므로 다음과 같이 정의

실제 add, scale 수행되는 과정은 vec2와 vec3은 다르므로 추상 메서드로 비워둠

추가로 차연산은 + (우측 값 x -1)을 하면 되므로 구현 

 

메타 클래스 Vector를 상속받는 Vec2를 구현하면서

산술 함수는 이미 Vector에서 구현했으므로 안해도되고,

실제 산술 동작 add, scale과 기타 필요한 함수들 구현해주면 됨 

from abc import ABCMeta, abstractmethod

class Vector(metaclass=ABCMeta):
    @abstractmethod
    def scale(self, scalar):
        pass
    @abstractmethod
    def add(self, toher):
        pass
    
    def __mul__(self, scalar):
        return self.scale(scalar)
    
    def __rmul__(self, scalar):
        return self.scale(scalar)
    
    def __add__(self, other):
        return self.add(other)
    
    def subtract(self, other):
        return self.add(-1 * other)
    
    def __sub__(self, other):
        return self.subtract(other)

class Vec2(Vector):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def add(self, other):
        return Vec2(self.x + other.x, self.y + other.y)
    
    def scale(self, scalar):
        return Vec2(self.x * scalar, self.y * scalar)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.z == other.z
    
    def __repr__(self):
        return "Vec2({},{})".format(self.x, self.y)
    
Vec2(5, 5) - Vec2(1, 3)

 

메타클래스로 vec3 만들기

구현 과정은 방금 한 vec2랑 같음, z 내용만 추가

class Vec3(Vector):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    
    def add(self, other):
        return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
    
    def scale(self, scalar):
        return Vec3(self.x * scalar, self.y * scalar, self.z * scalar)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.z == other.z

    def __repr__(self):
        return "Vec3({},{},{})".format(self.x, self.y, self.z)

vec3 = Vec3(3, 2, 1) * 3
print(vec3)

 

좌표 벡터 만들기

지금까지 2, 3차원 벡터 다루는 클래스를 만들었지만 상위 차원을 다룰수 있도록 좌표 벡터를 만들면

__init__ coordinates를 가변인자로 받아 저장

add와 scale도 구현. 실제 내용은 vectors.py에 이런식으로 구현되있음

def add(*vectors):
    return tuple(map(sum,zip(*vectors)))

def scale(scalar,v):
    return tuple(scalar * coord for coord in v)

repr도 출력 형태도 구현

추상 프로퍼티와 추상 메서드 차이는 프로퍼티는 값. 추상 메서드는 동작 의미

from abc import abstractproperty
from vectors import add, scale

class CoordinateVector(Vector):
    @abstractproperty
    def dimension(self):
        pass

    def __init__(self, *coordinates):
        self.coordinates = tuple(x for x in coordinates)
    
    def add(self, other):
        return self.__class__(*add(self.coordinates, other.coordinates))
    
    def scale(self, scalar):
        return self.__class__(*scale(scalar, self.coordinates))
    
    def __repr__(self):
        return "{}{}".format(self.__class__.__qualname__, self.coordinates)

 

좌표벡터 상속받는 vec6만들기

이미 좌표 벡터에서 내용 대부분 구현되있어서 이건 간단

추상 프로퍼티로 설정한 dimension만 구현해주면 된다.

print vec6하면 repr대로 출력

print vec6.coordinates는 튜플

print vec6.dimension은 인트값 6

덧셈 연산도 vectors.py에 구현된 add 대로 잘 동작

class Vec6(CoordinateVector):
    def dimension(self):
        return 6

print(Vec6(1, 1, 1, 1, 4, 5))
print(Vec6(1, 1, 1, 1, 4, 5).coordinates)
print(Vec6(1, 1, 1, 1, 4, 5).dimension())
Vec6(1, 1, 1, 1, 4, 5) + Vec6(1, 2, 3, 4, 5, 6)

 

영벡터를 추상 프로퍼티로 갖는 메타 클래스 벡터 만들기

지난번에 만든 벡터에 추상 프로퍼티로 추가해주면 됨

추가로 scale을 이용한 neg 연산도 추가

 

class Vector(metaclass=ABCMeta):
    @abstractmethod
    def scale(self, scalar):
        pass

    @abstractmethod
    def add(self, other):
        pass

    def __add__(self, other):
        return self.add(other)
    
    def __mul__(self, scalar):
        return self.scale(scalar)
    
    def __rmul__(self, scalar):
        return self.scale(scalar)
    
    def substract(self, other):
        return self.add(-1 * other)
    
    def __sub__(self, other):
        return self.substract(other)

    @classmethod
    @abstractproperty
    def zero():
        pass

    def __neg__(self):
        return self.scale(-1)

 

 

추상 프로퍼티 zero를 구현한 Vec2 만들기

기존의 vec2에다가 추상 프로퍼티 zero(영벡터 반환)를 구현

메타클레스에서 __neg__ 구현한 덕분에 -Vec2 연산이 가능해짐

 

class Vec2(Vector):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def scale(self, scalar):
        return Vec2(self.x * scalar, self.y * scalar)
    
    def add(self, other):
        return Vec2(self.x + other.x, self.y + other.y)
    
    def zero():
        return Vec2(0, 0)
    
    def __repr__(self):
        return "Vec2({},{})".format(self.x, self.y)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

print(Vec2.zero())
-Vec2(3, -4)

 

 

덧셈, 같은지 연산 전에 클래스 타입 확인하기

이전에 구현한 코드들은 vec2(1, 2) == vec3(1, 2, 3)은 같다로 반환하므로 

덧셈, 같음 연산전에 클래스 타입 확인하도록 수정이 필요

add와 eq 리턴 전에 assert 해주면 됨

같은 클래스면 문제없이 동작하지만 다르면 assertion error 발생

class Vec2(Vector):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def add(self, other):
        assert self.__class__ == other.__class__
        return Vec2(self.x + other.x, self.y + other.y)
    
    def scale(self, scalar):
        return Vec2(self.x * scalar, self.y *scalar)
    
    def __eq__(self, other):
        assert self.__class__ == other.__class__
        return self.x == other.x and self.y == other.y
    
    def __repr__(self):
        return "Vec2({},{})".format(self.x, self.y)
    
    def zero(self):
        return Vec2(0, 0)
 
print(Vec2(1, 2) == Vec2(1, 1))
print(Vec2(1, 2) + Vec2(3, 2))

Vec2(1, 2) == Vec3(1, 1, 1)
Vec2(1, 2) + Vec3(1, 1, 1)

 

 

메타클레스 벡터에 나누기 추가하기

추상 메서드로 덧셈, 스케일

추상 프로퍼티로 제로

그외는 덧셈, 그냥곱, 우측곱, 빼기, 부정 구현

추가된 나누기는 1.0/scalar를 곱하는 형태로 구현

 

 

class Vector(metaclass=ABCMeta):
    @abstractmethod
    def add(self, other):
        pass

    @abstractmethod
    def scale(self, scalar):
        pass

    def __add__(self, other):
        return self.add(other)

    def __mul__(self, scalar):
        return self.scale(scalar)
    
    def __rmul__(self, scalar):
        return self.scale(scalar)
    
    def substract(self, other):
        return self.add(-1 * other)
    
    def __sub__(self, other):
        return self.substract(other)

    @classmethod
    @abstractproperty
    def zero():
        pass

    def __neg__(self):
        return self.scale(-1)

    def __truediv__(self, scalar):
        return self.scale(1.0/scalar)

 

나눗셈 추가된 vec2 나누기 연산

나눗셈 연산은 vector에 추가되서 vec2에선 고칠게 없음

그냥 그대로 나눠보면 결과나옴

class Vec2(Vector):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def add(self, other):
        assert self.__class__ == other.__class__
        return Vec2(self.x + other.x and self.y + other.y)

    def __eq__(self, other):
        assert self.__class__ == other.__class__
        return self.x == other.x and self.y == other.y
    
    def scale(self, scalar):
        return Vec2(scalar * self.x, scalar * self.y)
    
    def zero():
        return Vec2(0, 0)
    
    def __repr__(self):
        return "Vec2({},{})".format(self.x, self.y)

print(Vec2(2, 3)/2)

 

1차원 벡터 정의하기

2차원 벡터때보다 더단순하다

class Vec1(Vector):
    def __init__(self, x):
        self.x = x
    
    def add(self, other):
        assert self.__class__ == other.__class__
        return Vec1(self.x + other.x)
    
    def __eq__(self, other):
        assert self.__class__ == other.__class__
        return self.x == other.x
    
    def scale(self, scalar):
        return Vec1(self.x * scalar)

    @classmethod
    def zero(cls):
        return Vec1(0)
    
    def __repr__(self):
        return "Vec1({})".format(self.x)

vec1_1 = Vec1(3)
vec1_2 = Vec1(5)
print(vec1_1)
print(vec1_1 * 3)
print(-vec1_2)
print(vec1_1/4)
print(Vec1.zero())

 

0벡터 다루기

담는 값이 없어서 더 단순

class Vec0(Vector):
    def __init__(self):
        pass

    def add(self, other):
        return Vec0()
    
    def scale(self, scalar):
        return Vec0()
    
    def __eq__(self, other):
        return self.__class__ == other.__class__ == Vec0
    
    def __repr__(self):
        return "Vec0()"
    
    @classmethod
    def zero(cls):
        return Vec0()

print(-3.14 * Vec0())
print(Vec0() + Vec0() + Vec0())

 

 

 

 

 

+ Recent posts