Apache2 설치

위 명령어를 입력하시면 apache2를 설치하게 됩니다.


그리고 라즈베리 파이에서는 127.0.0.1, Lan 통신망 내에서는 라즈베리파이의 ip주소(192.168.x.x)를 웹브라우저로 접속하시면 아래의 창이 뜨게 됩니다.


페이지 디렉토리 설정

/var/www/html/

 페이지의 기본 경로는 /var/www/html입니다. 페이지를 수정하고 싶으시면 이 경로에 index.html을 수정하던 파일을 추가하던 하시면 됩니다.

 하지만 경로를 변경하고 싶다면!

/etc/apache2/apache2.conf와 /etc/apache2/sites-available/000-default.conf를 변경해주시면 됩니다.


Apache2.conf 변경

 해당 파일에서 쭈욱 내려가다보면

1
2
3
4
5
6
<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>
 
cs
이 코드가 나오는데 이것을

1
2
3
4
5
6
<Directory /your/webpage/directory/>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>
 
cs

이렇게 변경해주시면 됩니다. html 상위 폴더여야합니다.


000-default.conf 변경

해당 파일을 열면

1
2
        DocumentRoot /var/www/html
 
cs

가 나옵니다. 이것을

1
2
        DocumentRoot /your/webpage/directory/html
 
cs

로 변경해주시면 됩니다. html폴더까지 적어주셔야합니다.


발생가능한 문제

Forbidden

You don't have permission to access / on this server.

라는 문제가 발생하실 수 있습니다.


권한관련된 에러이고, 저같은 경우는 아래의 방법으로 해결했습니다.

sudo chown -R www-data:www-data /your/webpage/directory 
sudo chmod -R 775 /your/webpage/directory 


Javascript로 구현한 Hanoi tower


하노이 탑은 세개의 기둥과 n개의 크기가 다른 원판이 크기가 큰 순서대로 첫번째 기둥에 꽂혀있습니다. 그리고 다음의 규칙에 맞게 세번째 기둥에 옮기면 되는 퍼즐의 일종이다.
첫번째, 한번에 하나의 원판을 옮길 수 있다.
두번째, 크기가 작은 원판 위에 큰 원판이 올 수 없다.

원판이 n개일 때, 번 이동하게 됩니다.

하노이 탑 설화
인도 베나레스에 있는 한 사원에는 세상의 중심을 나타내는 큰 돔이 있고 그 안에 세 개의 다이아몬드 바늘이 동판 위에 세워져 있습니다. 바늘의 높이는 1큐빗이고 굵기는 벌의 몸통만 합니다. 바늘 가운데 하나에는 신이 64개의 순금 원판을 끼워 놓았습니다. 가장 큰 원판이 바닥에 놓여 있고, 나머지 원판들이 점점 작아지며 꼭대기까지 쌓아 있습니다. 이것은 신성한 브라흐마의 탑입니다. 브라흐마의 지시에 따라 승려들은 모든 원판을 다른 바늘로 옮기기 위해 밤낮 없이 차례로 제단에 올라 규칙에 따라 원판을 하나씩 옮깁니다. 이 일이 끝날 때, 탑은 무너지고 세상은 종말을 맞이하게 됩니다.




알고리즘의 구성
기본적으로 하노이탑 알고리즘은 재귀호출을 이용하여 해결하는 구조입니다.

1
2
3
4
5
6
7
8
9
10
11
HanoiTower.prototype.move = function(count, from, by, to)
{
    if(count==1)
        this.columns[to].addNode(this.columns[from].pop());
    else
    {
        this.move(count-1, from, to, by);
        this.columns[to].addNode(this.columns[from].pop());
        this.move(count-1, by, from, to);
    }
}
cs


1
HanoiTower.prototype.move = function(count, from, by, to)
cs

 이 함수는 count만큼의 원판을 from기둥에서부터 to기둥까지 by기둥을 이용해서 옮기라는 함수입니다.


1
2
if(count==1)
    this.columns[to].addNode(this.columns[from].pop());
cs

 원판이 한개일때는 그냥 해당 장소로 옮기면 됩니다. column은 스택구조로 돼있고, 제일 위에 있는 것은 가장 작은 것이므로 어디로든 옮길 수 있습니다.


1
2
3
4
5
6
else
{
    this.move(count-1, from, to, by);
    this.columns[to].addNode(this.columns[from].pop());
    this.move(count-1, by, from, to);
}
cs

 이제 중요한 것은 위의 코드입니다.


1
this.move(count-1, from, to, by);
cs

일단 to로 이동을 시키려면 가장 큰 것(가장 아래에 있는 것)이 먼저 to기둥으로 들어가야하기 때문에 일단 그 위에 있는 것들을 by기둥으로 옮겨야 합니다. 그림으로 이해해주시면 좋을 것 같습니다.



1
this.columns[to].addNode(this.columns[from].pop());
cs

위에 있는 원판들의 이동이 끝났으면 가장 아래에 있는 원판을 To원판으로 옮겨줍니다.



1
this.move(count-1, by, from, to);
cs

그럼 이제 by로 옮겨놨던 원판들을 to로 옮겨줍니다.


이렇게 되면 아래의 그림처럼 이동이 완료되는 형태입니다.


 이미지에서는 여러개를 묶어서 이동하는 것처럼 표현했지만, 그런것이 아니라 해당 묶음을 재귀호출을 통해 1개 단위로 거슬러 올라가서 이동하는 형태입니다.



Javascript로 구현한 Merge sort


오늘은 분할 정복 알고리즘의 기초인 MergeSort에 대해 알아보겠습니다.

MergeSort는 원소의 개수가 1개가 될때까지 나눈 후, 역순으로 2개의 그룹을 병합 정렬해 가는 알고리즘입니다. 시간 복잡도는 로 원소들의 상태에 영향을 받지 않고 안정적으로 정렬하며 정렬 전의 순서와 정렬 후의 순서가 동일함을 보장하는 stable sort입니다. 하지만 원소 개수만큼의 임시 배열을 만들어 줘야하는 단점이 있습니다.


오늘은 동영상으로 어떻게 병합정렬이 진행되는지 봅시다.



재귀로 작성한 코드

1
2
3
4
5
6
7
8
9
10
11
12
MergeSort.prototype.mergeSort = function(first, last)
{
    if(first < last)
    {
        var mid = Math.floor((last + first) * 0.5);
        this.mergeSort(first, mid);
        this.mergeSort(mid + 1, last);
 
        this.merge(first, mid, last);
    }
}
 
cs

5~6번째 줄은 앞부분과 뒷부분으로 나누는 부분입니다.

해당 함수에서는 또 앞부분과 뒷부분으로 나누면서 first<last 될때까지 나누게 될 것입니다.

그렇게 나뉘면 작은 부분부터 차례대로 merge()함수를 실행하며 올라올 것 입니다.

소그룹 정렬 => 중그룹 정렬 => 대그룹 정렬

위에 보이는 동영상처럼요.


두 그룹을 병합하는 부분(first ~ mid, mid+1 ~ last)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
MergeSort.prototype.merge = function(first, mid, last)
{
    var a = first;
    var b = mid + 1;
 
    for(var i = first ; i <= last ; ++i)
    {
        if(a > mid)
        {
            this.tempArr[i] = this.nodes[b];
            b += 1;
            continue;
        }
        else if(b > last)
        {
            this.tempArr[i] = this.nodes[a];
            a += 1;
            continue;
        }
 
 
        if(this.nodes[a].value.size < this.nodes[b].value.size)
        {
            this.tempArr[i] = this.nodes[a];
            a += 1;
        }
        else
        {
            this.tempArr[i] = this.nodes[b];
            b += 1;
        }
    }
 
    for(var i = first ; i <= last ; ++i)
    {
        this.nodes[i] = this.tempArr[i];
        this.nodes[i].value.x = 5 + i * 55;
    }
}
 
cs

두 그룹의 병합은 아주 간단합니다.

각 그룹의 첫번째 인자를 비교하여 정렬 순서대로 미리 준비한 임시 배열에 넣어줍니다.

배열에 넣은 그룹은 인덱스를 1상승시킵니다.

한쪽 그룹에 더 이상 비교할 게 없다면 나머지 한쪽 그룹을 순서대로 넣어줍니다.

모든 그룹을 임시 배열에 넣어줬다면 그것을 현재 배열에 적용합니다.


위 코드에서 임시배열은 tempArr이고, 현재 배열은 nodes입니다.

a는 first ~ mid 그룹 인덱스고, b는 mid+1 ~ last 그룹 인덱스입니다.


조심할 부분이 있다면 해당 코드는 자바스크립트라는 점입니다.

자바스크립트는 노드를 그대로 사용하면 값을 복사하기 때문에 상당히 비효율적입니다. 그래서 해당 노드를 object에 넣어서 사용해줬습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MergeSort.prototype.createNodes = function()
{
    this.nodes = [];
    for(var i = 0 ; i < this.count ; ++i)
    {
        var node = new SortNode(i, Math.ceil(Math.random() * this.maxSize) + 1);
        node.position.x = 5 + i * 55;
        node.position.y = 600;
        this.addChild(node);
 
        this.nodes.push({value:node});
    }
}
 
cs

11번째 줄을 보시면 nodes라는 array에 {value:node}가 보이실겁니다. 이렇게 사용하시면 call by reference로 사용할 수 있다고 합니다.


For문으로 작성한 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
MergeSort.prototype.sort = function*()
{
    var stack = [];
    stack.push([0, this.count-1]);
 
    for(var i = 0 ; i < stack.length ; ++i)
    {
        var lastData = stack[i];
 
        var first = lastData[0];
        var last = lastData[1];
 
        var mid = Math.floor((last + first) * 0.5);
        if(first < mid)
            stack.push([first, mid]);
        if(mid + 1 < last)
            stack.push([mid + 1, last]);
    }
 
    while(stack.length !== 0)
    {
        var data = stack.pop();
 
        this.setGroupLine(data[0], data[1]);
        yield true;
        var mid = Math.floor((data[0] + data[1]) * 0.5);
        this.merge(data[0], mid, data[1]);
        yield true;
    }
 
    this.groupLine.clear();
    yield false;
}
 
cs

위에 코드는 재귀가 아닌 For문으로 작성한 코드입니다.

작성한 이유는 다름아닌 저 동영상을 generator를 이용해 만들고 있기 때문입니다!

코드를 보시면 재귀하는 부분을 stack을 이용해 해결하였습니다. 차례대로 2등분하여 쌓아줍니다.

그리고 마지막부터 역순으로 병합해주는 형태입니다.

Javascript로 구현한 Select sort


주어진 배열 이외에 다른 저장공간을 필요로 하지 않는 제자리 정렬 알고리즘의 하나로 시간 복잡도는  입니다. 어떤 상황에서든 에 비례하는 시간이 걸립니다.



1 5 6 8 7 4 3 9 2


1 5 6 8 7 4 3 9 2

1 2 6 8 7 4 3 9 5


1 2 6 8 7 4 3 9 5

1 2 3 8 7 4 6 9 5


1 2 3 8 7 4 6 9 5

1 2 3 4 7 8 6 9 5


1 2 3 4 7 8 6 9 5

1 2 3 4 5 8 6 9 7


1 2 3 4 5 8 6 9 7

1 2 3 4 5 6 8 9 7


1 2 3 4 5 6 8 9 7

1 2 3 4 5 6 7 9 8


1 2 3 4 5 6 7 9 8

1 2 3 4 5 6 7 8 9


소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
for(var i = 0 ; i < this.nodes.length - 1 ; ++i)
{
    var min = i;
 
    for(var j = i + 1 ; j < this.nodes.length ; ++j)
    {
        if(this.nodes[min].getSize() > this.nodes[j].getSize())
            min = j;
    }
 
    if(min == i)
        continue;
 
    var temp = this.nodes[i];
    this.nodes[i] = this.nodes[min];
    this.nodes[min] = temp;
 
    this.nodes[i].x = 5 + i * 55;
    this.nodes[min].x = 5 + min * 55;
}
 
cs

안쪽 포문에서는 그 자리에 해당하는 최소값을 찾고 바깥쪽 포문에서는 딱 한번 swap 해줍니다. swap이 조금 일어나기때문에 거품정렬에 비해 속도가 빠릅니다. (그래도 ...)


Javascript로 구현한 Bubble sort



거품 정렬이란?
인접한 두 원소를 비교하여 정렬하는 방법입니다.
거품이 수면위로 떠오르는 것 처럼 보여서 붙혀진 이름이라고 합니다.
시간 복잡도는  입니다.


예시

1 5 6 8 7 4 3 9 2

1 5 6 8 7 4 3 9 2

1 5 6 8 7 4 3 9 2

1 5 6 8 7 4 3 9 2

1 5 6 8 7 4 3 9 2

1 5 6 7 8 4 3 9 2

1 5 6 7 8 4 3 9 2

1 5 6 7 4 8 3 9 2

1 5 6 7 4 8 3 9 2

1 5 6 7 4 3 8 9 2

1 5 6 7 4 3 8 9 2

1 5 6 7 4 3 8 9 2

1 5 6 7 4 3 8 2 9   첫번째 이터레이션 종료


1 5 6 7 4 3 8 2 9

1 5 6 7 4 3 8 2 9

1 5 6 7 4 3 8 2 9

1 5 6 7 4 3 8 2 9

1 5 6 4 7 3 8 2 9

1 5 6 4 7 3 8 2 9

1 5 6 4 3 7 8 2 9

1 5 6 4 3 7 8 2 9

1 5 6 4 3 7 8 2 9

1 5 6 4 3 7 2 8 9 두번째 이터레이션 종료


1 5 6 4 3 7 2 8 9

1 5 6 4 3 7 2 8 9

1 5 6 4 3 7 2 8 9

1 5 4 6 3 7 2 8 9

1 5 4 6 3 7 2 8 9

1 5 4 3 6 7 2 8 9

1 5 4 3 6 7 2 8 9

1 5 4 3 6 7 2 8 9

1 5 4 3 6 2 7 8 9 세번째 이터레이션 종료


1 5 4 3 6 2 7 8 9

1 5 4 3 6 2 7 8 9

1 4 5 3 6 2 7 8 9

1 4 5 3 6 2 7 8 9

1 4 3 5 6 2 7 8 9

1 4 3 5 6 2 7 8 9

1 4 3 5 6 2 7 8 9

1 4 3 5 2 6 7 8 9 네번째 이터레이션 종료


1 4 3 5 2 6 7 8 9

1 4 3 5 2 6 7 8 9

1 3 4 5 2 6 7 8 9

1 3 4 5 2 6 7 8 9

1 3 4 5 2 6 7 8 9

1 3 4 2 5 6 7 8 9 다섯번째 이터레이션 종료


1 3 4 2 5 6 7 8 9

1 3 4 2 5 6 7 8 9

1 3 4 2 5 6 7 8 9

1 3 2 4 5 6 7 8 9 여섯번째 이터레이션 종료


1 3 2 4 5 6 7 8 9

1 3 2 4 5 6 7 8 9

1 2 3 4 5 6 7 8 9 일곱번째 이터레이션 종료


1 2 3 4 5 6 7 8 9 여덟번째 이터레이션 종료


이터레이션 단위에서는 작은 수들은 앞으로 한칸씩 밀려오고 비교 단위에서는 큰 수들이 뒤로 한칸씩 밀려나는 형태입니다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for(var i = 0 ; i < this.nodes.length - 1 ; ++i)
{
    for(var j = 0 ; j < this.nodes.length - 1 - i ; ++j)
    {
        if(this.nodes[j].getSize() > this.nodes[j+1].getSize())
        {
            var temp = this.nodes[j];
            this.nodes[j] = this.nodes[j+1];
            this.nodes[j+1] = temp;
 
            this.nodes[j].x = 5 + j * 55;
            this.nodes[j+1].x = 5 + (j+1) * 55;
        }
    }
}
 
cs


 가장 큰 값을 뒤로 밀어낸다고 보시면 됩니다. 뒤에서 부터 정렬된 값이 쌓이기 때문에 3번째 줄의 for문은 length - 1 - i만큼만 돌게 됩니다. length - 1은 j와 j+1을 비교하기 때문에 넣어줍니다.



외장하드 장치 정보 얻기

현재 하드디스크들의 파일시스템 정보를 얻어옵니다.

sudo blkid

Seagate Expansion Drive가 보입니다. 그럼 /dev/sda1가 외장하드 파일입니다.

여기서 추가적인 설명을 덧붙이면,

/dev 폴더는 장치파일들(device files)을 모아놓은 곳이고, sda1은 두번째 하드디스크라는 소리입니다.(첫번째 하드디스크는 sda, 위의 /dev/mmcblk0p들은 sda의 파티션) 기본적으로 저 파일은 Directory가 아니라서 접근이 불가능합니다. 그리고 이것을 접근할 수 있도록 하는 것이 mount 명령어입니다.

이제 다음 명령어를 입력해봅시다.

sudo fdisk -l

 fdisk 명령어는 파티션을 관리하는 명령어입니다. 다른 정보들은 지금 저희에게는 별로 중요하지 않으니 패스하고 마지막줄의 /dev/sda1를 확인해주세요. 현재 /dev/sda1의 정보를 확인할 수 있습니다.


외장하드 마운트

/dev/sda1을 ~sda1로 마운트하겠습니다.

sudo mount /dev/sda1 ~/FTP/sda1


다음으로 마운트한 폴더에 접근 권한을 부여합니다.

sudo chmod 775 ~/sda1

~/폴더에 sda1폴더가 생성된 것을 확인할 수 있을 것입니다.


이제 마운트 정보를 기억하고 재부팅 시, 자동 마운트할 수 있도록 설정해봅시다.

sudo vim /etc/fstab

/etc/fstab은 하드디스크의 마운트 정보를 담고 있는 설정파일입니다.

마지막줄에 아래의 정보를 입력해봅시다.

/dev/sda1 /home/pi/FTP/sda1 ntfs defaults 0 0

위와같이 입력을 완료하시면 :wq로 저장 후 종료를 하시면 재부팅시에도 계속 마운트돼있는 것을 확인하실 수 있을 것입니다.


아래의 명령어로 마운트를 해제하실 수 있습니다.

sudo umount ~/FTP/sda1



저는 라즈베리파이 Documentation에 있는 자료를 참고하여 구축했기 때문에 PURE-FTPD를 기반으로 설명해드리겠습니다.

https://www.raspberrypi.org/documentation/remote-access/ftp.md


PURE_FTPD 설치

다음 문장을 터미널에 입력해 apt-get을 설치합니다.

sudo apt-get install pure-ftpd


기본 설정

기본적으로 리눅스에서 ftp를 위한 그룹을 만들고 ftp에서 사용할 유저를 추가해주어야합니다.

groupadd ftpgroup
useradd ftpuser -g ftpgroup -s /sbin/nologin -d /dev/null

groupadd [groupname]

[groupname]라는 사용자 그룹을 추가하는 리눅스 명령어입니다.

useradd [username]

[username]라는 사용자를 추가하는 리눅스 명령어입니다.

-g [groupname] [groupname]그룹에 유저를 추가합니다.

-s [authorization] [authorization]권한을 유저에게 부여합니다.

/sbin/nologin

쉘 권한이 없어서 SSH접속을 하지 못하도록 하는 명령

-d [home_directory] [home_directory]위치에 사용자 계정의 홈 디렉토리를 생성합니다.

/dev/null

홈디렉토리를 생성하지 않습니다.


FTP 홈 디렉토리, 가상유저와 유저 그룹

FTP용 디렉토리를 추가합니다.

sudo mkdir /home/pi/FTP

ftpuser에게 FTP용 디렉토리 접근 권한을 부여합니다.

sudo chown -R ftpuser:ftpgroup /home/pi/FTP

ftp에 upload라는 가상 유저를 만들어 ftpgroup에 있는 ftpuser를 매핑합니다.

pure-pw useradd 명령이 실행되고 나면 곧바로 password를 입력할 수 있게됩니다.

sudo pure-pw useradd upload -u ftpuser -g ftpgroup -d /home/pi/FTP -m

pure-pw useradd [username]

[username]이라는 ftp 가상 유저를 추가합니다.

-u [system_username]

시스템에 있는 유저이름을 넣어줍니다.(해당 유저의 권한과 같은 설정을 매핑하는데 사용됩니다.)

-g [system_usergroup]

시스템에 있는 유저그룹을 넣어줍니다.(해당 유저의 권한과 같은 설정을 매핑하는데 사용됩니다.)

-d [directory]

해당 유저의 ftp 루트 디렉토리

-m

??? 아시는분 있으면 댓글 좀ㅠㅠ


이제 다음으로는 user database를 생성해줍니다.(신규유저 추가 및 비밀번호 변경등의 행동을 하면 db갱신을 위해 반드시 호출해줘야합니다.)

sudo pure-pw mkdb

이제 생성된 db를 인증을 위해 /etc/pure-ftpd/auth/폴더에 소프트 링크해줍니다.

ln -s /etc/pure-ftpd/conf/PureDB /etc/pure-ftpd/auth/60puredb


pure-ftpd를 재시작합니다.

sudo service pure-ftpd restart


세팅 끝


https://download.pureftpd.org/pub/pure-ftpd/doc/README.Virtual-Users

다른 명령어는 위의 페이지를 참조해주세요.

Javascript로 구현한 선분충돌



투영을 통한 선분충돌

1번

2번

하지만 2번 이미지에서 초록 선분도 투영 결과는 같지만 충돌하지는 않은 상태입니다.
그렇기 때문에 파랑 선분의 직교 벡터에도 똑같이 투영을 하여 같은 결과가 나오는지 확인해주어야 합니다.


3번

3번 이미지는 파랑 선분의 직교 벡터인 파랑 직교 벡터에 투영을 한 결과입니다.
보라 선분은 아까와 같은 결과이지만 초록 선분은 그렇지 않습니다.


예외 : 두 선분의 벡터가 같은 방향을 가지고 있을 때,

4번


4번 이미지는 두 선분의 벡터가 같은 방향을 가지고 있을 때를 보여주는 이미지입니다.
해당 경우에는 직교 벡터에서 한 점에 투영이 됩니다.
이 경우에는 선분의 벡터에 투영하여 빨강 선분의 각 점 중 하나라도 파랑 선분의 사이에 있다면 충돌 된 것입니다.

보라 선분의 직교 벡터인 보라 직교벡터에 세 점을 투영하면 위와 같은 결과가 나옵니다.


이제 코드를 보겠습니다.

1
2
3
4
5
6
7
var myP1 = new PIXI.Vector(this.points[0].position.x, this.points[0].position.y);
var myP2 = new PIXI.Vector(this.points[1].position.x, this.points[1].position.y);
var otherP1 = new PIXI.Vector(other.points[0].position.x, other.points[0].position.y);
var otherP2 = new PIXI.Vector(other.points[1].position.x, other.points[1].position.y);
 
var myN = new PIXI.Vector(myP2.y - myP1.y, myP1.x - myP2.x);    
var otherN = new PIXI.Vector(otherP2.y - otherP1.y, otherP1.x - otherP2.x);
cs

각 네점은 myP1, myP2, otherP1, otherP2 입니다.

myN과 otherN이 각 선분의 직교벡터입니다. 2차원 벡터의 직교벡터를 구하는 방법은 복소평면에서의 회전을 참고해주시면 좋을 것 같습니다.


1
2
3
4
5
6
7
var myDot = myN.dot(myP1);
var myDotA = myN.dot(otherP1) - myDot;
var myDotB = myN.dot(otherP2) - myDot;
 
if(myDotA * myDotB > 0)
    return false;
 
cs

myN 벡터에 각 점을 투영하여 my가 other의 각 점 사이에 있는지 체크해줍니다.

투영은 벡터의 내적을 통해 얻을 수 있습니다.


1
2
3
4
5
6
7
var otherDot = otherN.dot(otherP1);
var otherDotA = otherN.dot(myP1) - otherDot;
var otherDotB = otherN.dot(myP2) - otherDot;
 
if(otherDotA * otherDotB > 0)
    return false;
 
cs

똑같이 otherN벡터에 각 점을 투영하여 other가 my의 각 점 사이에 있는지 체크해줍니다.


두 선분의 벡터가 같은 방향을 가지고 있을 때 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// when vector same,
if(myDotA == 0 && myDotB == 0)
{
    var dir = myP2.clone().sub(myP1);
 
    var myP1Dot = dir.dot(myP1);
    var myP2Dot = dir.dot(myP2);
    var otherP1Dot = dir.dot(otherP1);
    var otherP2Dot = dir.dot(otherP2);
 
    if((myP1Dot - otherP1Dot) * (myP1Dot - otherP2Dot) < 0)
    {
        joint.x = myP1.x;
        joint.y = myP1.y;
        return true;
    }
    else if((myP2Dot - otherP1Dot) * (myP2Dot - otherP2Dot) < 0)
    {
        joint.x = myP2.x;
        joint.y = myP2.y;
        return true;
    }
}
 
cs

my의 방향 벡터에 네 점을 투영하여 충돌을 검출합니다.


마지막으로 충돌 지점을 계산합니다.

1
2
3
4
5
6
7
8
var ratio = Math.abs(myDotA) / Math.abs(myDotB - myDotA);
 
var bPoint1 = otherP1.clone();
var bDelta = otherP2.clone().sub(otherP1).multiplyScalar(ratio);
var result = bPoint1.add(bDelta);
joint.x = result.x;
joint.y = result.y;
 
cs

투영한 점의 비율을 계산하여 충돌 지점을 계산할 수 있습니다.


아래는 전체 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
SegmentLine.prototype.getJoint = function (other, joint)
{
    var myP1 = new PIXI.Vector(this.points[0].position.x, this.points[0].position.y);
    var myP2 = new PIXI.Vector(this.points[1].position.x, this.points[1].position.y);
    var otherP1 = new PIXI.Vector(other.points[0].position.x, other.points[0].position.y);
    var otherP2 = new PIXI.Vector(other.points[1].position.x, other.points[1].position.y);
 
    var myN = new PIXI.Vector(myP2.y - myP1.y, myP1.x - myP2.x);    
    var otherN = new PIXI.Vector(otherP2.y - otherP1.y, otherP1.x - otherP2.x);

    var myDot = myN.dot(myP1);
    var myDotA = myN.dot(otherP1) - myDot;
    var myDotB = myN.dot(otherP2) - myDot;
 
    // when vector same,
    if(myDotA == 0 && myDotB == 0)
    {
        var dir = myP2.clone().sub(myP1);
        var myP1Dot = dir.dot(myP1);
        var myP2Dot = dir.dot(myP2);
        var otherP1Dot = dir.dot(otherP1);
        var otherP2Dot = dir.dot(otherP2);
        if((myP1Dot - otherP1Dot) * (myP1Dot - otherP2Dot) < 0)
        {
            joint.x = myP1.x;
            joint.y = myP1.y;
            return true;
        }
        else if((myP2Dot - otherP1Dot) * (myP2Dot - otherP2Dot) < 0)    
        {
            joint.x = myP2.x;
            joint.y = myP2.y;
            return true;
        }
    }
 
    if(myDotA * myDotB > 0)
        return false;
 
    var otherDot = otherN.dot(otherP1);
    var otherDotA = otherN.dot(myP1) - otherDot;    
    var otherDotB = otherN.dot(myP2) - otherDot;    
 
    if(otherDotA * otherDotB > 0)
        return false;
 
     // calculate intersection
    var ratio = Math.abs(myDotA) / Math.abs(myDotB - myDotA);
    var bPoint1 = otherP1.clone();
    var bDelta = otherP2.clone().sub(otherP1).multiplyScalar(ratio);
    var result = bPoint1.add(bDelta);
    joint.x = result.x;
    joint.y = result.y;
    return true;
}
cs




'Notes > Algorithm' 카테고리의 다른 글

[자료구조] 이진 힙(binary heap) 그리고 힙 정렬(heap sort)  (0) 2016.06.07
하노이 탑(Tower of Hanoi)  (0) 2016.05.24
병합 정렬 (Merge Sort)  (0) 2016.05.15
선택 정렬 (Select Sort)  (0) 2016.05.11
거품 정렬 (Bubble Sort)  (0) 2016.05.08

유동아이피

 - DHCP로부터 할당받은 IP.
해당 mac adress를 기억하여 일정시간(iptime에서는 IP 대여 시간이라고 부름) 이상 네트워크에 접속하지 않으면 다른 주소로 재할당 받게 됨


고정아이피

자신이 설정한 주소로 할당받는 IP
(설정을 취소하지 않는 한 변하지 않음)

굳이 외부에서 접속할일이 없는 경우에는 관리의 편리함을 위해 유동아이피를 사용하겠지만 그 반대의 경우에는 IP가 바뀔때마다 설정을 바꾸는 것은 매우 비효율적이니 고정아이피를 사용해야합니다.


일단 vim을 설치합니다.

(vi에 경우 원격접속시 버그가...)


그 다음에는 /etc/network/interfaces를 수정해야합니다.



Before


After


위에서 아래로 수정을 하셔야합니다.

저는 192.168.0.240으로 할당받았습니다.


간단하게 몇가지만 설명해드리겠습니다.

iface eth0 inet manual이 있습니다.

주목해주실 부분은 iface eth0 inet manual(혹은 dhcp)입니다.

inet manual은 ip를 정의하지 않고 네트워크 인터페이스를 생성하는 설정입니다. 보통 vlan이나 link aggression 같은 곳에서 사용된다고 합니다.

dhcp는 DHCP로부터 IP를 할당받게 하는 설정입니다.


고정아이피를 사용할 것이니 이부분을 inet static으로 변경합니다.

static ip 즉, 고정 아이피를 정의하겠다는 소리입니다.


이하, 추가적인 설정입니다.

address (고정아이피 주소)
netmask (서브넷 마스크)
network (네트워크 아이디)
broadcast (브로드캐스트 마스크)
gateway (게이트웨이 주소)


설정이 끝났으면 저장한 후 네트워크를 재시작합니다.

그리고 재부팅을 합니다.


ifconfig를 이용해 설정한 아이피로 변경 됐는지 확인해주세요.

드디어 라즈베리파이2 모델B를 구매했습니다!


웬만한 NAS 서버보다 성능이 좋은 라즈베리파이2 모델B입니다.

생각보다 훨씬 작더라구요.



Micro SD card는 Samsung EVO UHS 등급1 32G을 사용하였습니다.

(sd card performance 비교. http://elinux.org/RPi_SD_cards#SD_card_performance)


설치도 아주 간략하게 바뀌었습니다.

기존에는 홈페이지에서 raspbian 다운 받고, image writer 설치해서 sd card에다 image write 하고 꼽아서 사용했었는데 이제는 noobs 하나면 설치가 끝납니다.


https://www.raspberrypi.org/downloads/noobs/

위 사이트에서 noobs 다운받고 압축 풀어서 안의 내용물을 sd card에다가 옮기면 끝!

(noobs는 라즈비안을 간편하게 설치해주는 소프트웨어입니다.)


이제 1A 이상인 Micro 5pin 충전기를 꼽아주면 부팅이 됩니다. 부팅버튼이 따로 없습니다.


그렇게 실행을 시켜주면

(id : pi, pw : raspberry, 나중에 passwd 명령으로 바꾸시면됩니다.)


 

라즈베리파이가 설치됐네요