이번시간에는 행렬(Matrix)을 이용해 가공하는 좌표데이타 위치를 이동, 회전 등의 변환을 쉽게 하는 방법을 설명드리겠습니다.
IRtc 인터페이스 내부에는 행렬스택(MatrixStack)이라는 자료구조를 가지고 있는데, 쉽게 말해 변환을 넣고, 빼는 (Push/Pop) 것에 따라 실제 가공시 이 행렬의 최종 연산값과 가공해야할 좌표값이 서로 연산되어 최종 가공 위치가 자동 계산되는 방식을 제공합니다.

static void Main(string[] args)
{
SpiralLab.Core.Initialize();
var rtc = new Rtc5(0); //create Rtc5 controller
float fov = 60.0f; // scanner field of view : 60mm
float kfactor = (float)Math.Pow(2, 20) / fov; // k factor (bits/mm) = 2^20 / fov
var correctionFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "correction", "cor_1to1.ct5");
rtc.Initialize(kfactor, LaserMode.Yag1, correctionFile);
rtc.CtlFrequency(50 * 1000, 2); // laser frequency : 50KHz, pulse width : 2usec
rtc.CtlSpeed(100, 100); // default jump and mark speed : 100mm/s
rtc.CtlDelay(10, 100, 200, 200, 0); // scanner and laser delays
ILaser laser = new LaserVirtual(0, "virtual", 20);
ConsoleKeyInfo key;
do
{
Console.WriteLine("Testcase for spirallab.sirius.");
Console.WriteLine("");
Console.WriteLine("'R' : draw rectangle with rotate");
Console.WriteLine("'L' : draw lines with rotate");
Console.WriteLine("'Q' : quit");
Console.WriteLine("");
Console.Write("select your target : ");
key = Console.ReadKey(false);
if (key.Key == ConsoleKey.Q)
break;
Console.WriteLine("\r\nWARNING !!! LASER IS BUSY ...");
Console.WriteLine("");
var timer = Stopwatch.StartNew();
switch (key.Key)
{
case ConsoleKey.R: // 회전하는 사각형 모양 가공 (가로 10, 세로 10 크기, 0 ~360 각도의 회전 형상)
DrawRectangle(laser, rtc, 10, 10, 0, 360);
break;
case ConsoleKey.L: //회전하는 직선 모양 가공
DrawLinesWithRotate(laser, rtc, 0, 360);
break;
}
rtc.ListExecute(true);
Console.WriteLine($"processing time = {timer.ElapsedMilliseconds / 1000.0:F3}s");
} while (true);
rtc.Dispose();
}
private static void DrawRectangle(ILaser laser, IRtc rtc, double width, double height, double angleStart, double angleEnd)
{
rtc.ListBegin(laser);
for (double angle = angleStart; angle <= angleEnd; angle += 1)
{
//회전 각도를 행렬 스택에 push
rtc.MatrixStack.Push(angle);
rtc.ListJump(new Vector2((float)-width / 2, (float)height / 2));
rtc.ListMark(new Vector2((float)width / 2, (float)height / 2));
rtc.ListMark(new Vector2((float)width / 2, (float)-height / 2));
rtc.ListMark(new Vector2((float)-width / 2, (float)-height / 2));
rtc.ListMark(new Vector2((float)-width / 2, (float)height / 2));
//이전에 push 된 행렬값을 pop 하여 삭제
rtc.MatrixStack.Pop();
}
rtc.ListEnd();
}
private static void DrawLinesWithRotate(ILaser laser, IRtc rtc, double angleStart, double angleEnd)
{
rtc.ListBegin(laser);
rtc.MatrixStack.Push(2, 4); // x=2mm, y=4mm 만큼 이동
for (double angle = angleStart; angle <= angleEnd; angle += 1)
{
rtc.MatrixStack.Push(angle);
rtc.ListJump(new Vector2(-10, 0));
rtc.ListMark(new Vector2(10, 0));
rtc.MatrixStack.Pop();
}
rtc.MatrixStack.Pop();
rtc.ListEnd();
}