아두이노프로세싱 프로그래밍

Processing 그래픽 언어에 의한 시계 코딩

coding art 2018. 6. 5. 11:31
728x90

 

________________________________________________________________________________________

 

 

어느 컴퓨터 언어를 배워도 가장 기본적인 코딩 연습 예제로 시계가 있다. 이미 아두이노에서 millis() 명령을 사용하여 시간 계산을 통해 lcd 에 의해 또는 OLED 에 의해 디스플레이를 해 보았다. 이번에는 PC에서 Processing 에 의한 시계 코드를 살펴보자. Processing 사이트에 연습을 위한 Example 코드가 있으므로 간단히 분석해 보고 실행 시켜 보도록 하자. ...

 

아래의 블로그로 넘어가서 읽으세요.

아두이노 코딩-57: Processing 그래픽 언어에 의한 시계 코딩(짤)

https://steemit.com/kr/@codingart/57-processing

 

어느 컴퓨터 언어를 배워도 가장 기본적인 코딩 연습 예제로 시계가 있다. 이미 아두이노에서 millis() 명령을 사용하여 시간 계산을 통해 lcd 에 의해 또는 OLED 에 의해 디스플레이를 해 보았다.

이번에는 PC에서 Processing 에 의한 시계 코드를 살펴보자. Processing 사이트에 연습을 위한 Example 코드가 있으므로 간단히 분석해 보고 실행 시켜 보도록 하자.

Clock.
https://processing.org/examples/clock.html

이 Processing 코드에 의한 시계 코딩을 통해 앞으로 아두이노와 인터페이스를 통해 예를 들면 온습도 데이터를 전송 받을 경우 PC 자체에서 Java Script 에서처럼 시간 데이터를 받아들이고 아두이노에서 온습도 데이터를 전달 받아 시계 자판 하나에 함께 디스플레이 해 볼 수 있는 가능성이 있다.

아래에 첨부된 Processing 시계 코드는 사이트에서 복사한 코드에서 텍스트 출력과 컬러를 입힌 시분초 바늘 부분을 약간 수정하였으니 참조하기 바란다.

setup()에서 리얼타임 시계를 구성할 수 있도록 그래픽 화면 크기를 size(640, 360)으로 정의하고 화면을 background(0) 즉 검은색으로 도배 후 선이나 경계를 그리거나 또는 텍스트 출력을 위해 stroke(255)로 흰색을 정의 하자.

그래픽 화면 내에 가능한 한 큰 원을 그릴 수 있도록 기본 정수형 반경을

int radius = min(width, height) / 2;

으로 계산한다. min() 명령은 내부 함수 명령어이다. 반경 ,radius 가 계산되면 초침, 분침 및 시침의 길이를 각각 72%, 60%, 50% 로 설정한다.

secondsRadius = radius * 0.72;
minutesRadius = radius * 0.60;
hoursRadius = radius * 0.50;

한편 나중에 필요한 시계의 직경을 반경의 1.8배로 정의하자.
clockDiameter = radius * 1.8;

아울러 시계가 포함될 그래픽 화면 크기의 가로 세로의 반값을 다음과 같이 계산해 둔다. 이 값들은 그패픽 화면의 중심에 해당하면 시계 자판의 중심과 일치하게 된다.

cx = width / 2;
cy = height / 2;

여기까지가 setup()에서 처리해야 할 부분이며 아래의 내용은 draw()에서 작성할 코드 내용이다.

background(0)는 검은 색으로서 둥근 시계가 들어갈 사각형 그래픽 화면의 밑 바탕 색을 정의한다. fill(80)은 둥근 시계판의 밑 바탕색으로 진한 회색이다. noStroke()를 선언하여 그다음에 그리려는 도형의 윤곽선을 제거한다.

그래픽 화면의 중앙 점에서 앞서 계산해 두었던 시계 반경 값을 사용하여 윤곽선이 없는 시계 판을 ellipse() 명령을 사용하여 작도한다. 타원이 아니므로 장축과 단축을 동일한 시계 반경 값을 사용한다. Processing 에서는 별도의 circle 명령이 없이 ellipse() 명령으로 대체한다.

ellipse(cx, cy, clockDiameter, clockDiameter);

second() 명령에 의해 PC 로부터 초 값을 읽어 오면 그 범위가 0∼60의 범위 값을 가지는데 이 값을 0∼2π 라디안으로 변환한다. 아울러 라디안 값이 0 이 되는 지점이 좌표계 수평 값이므로 초로는 15초, 분으로는 15분, 시간으로는 3시에 위치에 해당하므로 아예 (π/2)만큼 뺄셈을 하자.

float s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;

분 계산 시에는 minute 값과 초 값 second()를 60을 기준으로 노말라이즈하여 0∼1 사이의 소수점 값으로 환산하여 더한다. 아울러 분 값의 범위가 0∼60의 범위 값을 가지므로 이 값을 0∼2π 라디안으로 변환 후 (π/2)만큼 뺄셈을 하자.

float m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI;

시간 계산 시에는 hour()에 분 값 minute()를 24를 기준으로 노말라이즈하여 0∼1 사이의 소수점 값으로 환산하여 더한다. 아울러 시간은 0∼24의 범위 값을 가지므로 이 값을 두바퀴에 해당하는 0∼4π 라디안으로 변환 후 (π/2)만큼 뺄셈을 하자.

float h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI;

삼각함수를 사용하여 초침, 분침 및 시침을 작도하자. stroke(255)에 의해서 흰색으로 시계 침 색깔릉 설정한다. 각 침의 굵기 즉 stroleWeight()를 각각 1, 2, 3으로 설정한다.

strokeWeight(1);
line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius);
strokeWeight(2);
line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);
strokeWeight(4);
line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);

시계의 눈금을 매기자. 눈금의 굵기는 strokeWeight(2) 로 한다.

strokeWeight(2);

6도 간격으로 점을 생성해서 눈금으로 삼도록 한다. beginShape(POINTS) 명령으로 시작하여 endShpae() 으로 끝난다. for loop에서 6도씩 증가 시킨다. 이때 생성된 각도 값을 radians() 명령을 사용하여 라디안으로 변경한다. 초침 반경의 코사인 사인 값을 생성하여 시계 중심 값에 더하여 60개 점의 (x,y) 좌표를 생성 후 vertex(x,y) 로 출력한다.

beginShape(POINTS);
for (int a = 0; a < 360; a+=6) {
float angle = radians(a);
float x = cx + cos(angle) * secondsRadius;
float y = cy + sin(angle) * secondsRadius;
vertex(x, y);
}
endShape();

사실 시계 눈금은 setup() 에 위치시켜야 하지만 코드의 이 부분을 옮겨서 실행해보면 눈금을 얻을 수 없었다. 아마도 setup()에서 작동되지 않는 명령이 섞여 있지 않을까 의심해 본다. 울며 겨자 먹기로 draw()에서 매번 루프를 돌 때 마다 눈금을 그려야 할 것 같다.

초침, 분침 및 시침에 약간의 컬러를 입혀 보자.
strokeWeight() 명령 다음에 RGB 에 해당하는 명령 즉 stroke(255,0,0), stroke(0,255,0) alc stroke(0,0,255)를 넣고 눈금에서는 그대로 stroke(255) 로 처리하여 흰색으로 처리하자.

다음 짤에서 시계를 감상해 보자.

 

//Processing_RGB_Hands_clock_01

int cx, cy;
float secondsRadius;
float minutesRadius;
float hoursRadius;
float clockDiameter;

void setup() {
size(640, 360);
background(0); //black color

stroke(255); // white color

textSize(25);
text("RGB Hands Clock", 10, 30);
fill(0,102,153);

int radius = min(width, height) / 2;
secondsRadius = radius * 0.72;
minutesRadius = radius * 0.60;
hoursRadius = radius * 0.50;
clockDiameter = radius * 1.8;

cx = width / 2;
cy = height / 2; // Draw the minute ticks

}

void draw() {

// Draw the clock background
fill(0,255,0);
noStroke();
ellipse(cx, cy, clockDiameter, clockDiameter);

// Angles for sin() and cos() start at 3 o'clock;
// subtract HALF_PI to make them start at the top
float s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;
float m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI;
float h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI;

// Draw the hands of the clock
stroke(255,0,0);
strokeWeight(1);
line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius);
stroke(0,255,0);
strokeWeight(2);
line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);
strokeWeight(4);
stroke(0,0,255);
line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);

strokeWeight(4);
stroke(255);
beginShape(POINTS);
for (int a = 0; a < 360; a+=6) {
float angle = radians(a);
float x = cx + cos(angle) * secondsRadius;
float y = cy + sin(angle) * secondsRadius;
vertex(x, y);
}
endShape();
}//End