기본 콘텐츠로 건너뛰기

2024의 게시물 표시

이미지 크기 조절

이미지의 네 점 중 한 점($P_3$)을 이동시켜 크기를 조정하려고 합니다. 여기서 한 가지 조건이 있는데 기존의 X-Y 비율을 지켜야 한다는 것입니다. 비율은 아래와 같이 정의할 수 있습니다. $$ ratio = \frac{|\overrightarrow{P_4 - P_3}|}{|\overrightarrow{P_2 - P_1}|} $$ $P_2$의 $x$ 값을 $P$의 $x$으로 바꾸고 $length = \overrightarrow{|P_2 - P_1|}$의 길이를 구합니다. $P_4$의 $y$값은 앞서 구한 $length$에 $ratio$를 곱하여 구할 수 있습니다. $${P_4}_.y = {P_1}_.y + length * ratio$$ 위에서는 아주 특수한 경우에 대해서 생각을 했었고 우리는 일반적인 경우(회전된 경우 포함)에 대해서 처리해야만 합니다. 우선 ${P_2}^\prime$는 아래와 같이 구할 수 있습니다. $$ \begin{align} AxisX &= \frac{\overrightarrow{P_2 - P_1}}{\overrightarrow{|P_2 - P_1|}}\\ dot &= AxisX \cdot \overrightarrow{P - P_1}\\ {P_2}^\prime &= P_1 + AxisX * dot\\ \end{align} $$ 그리고 ${P_4}^\prime$는 아래와 같이 구할 수 있습니다. $$ \begin{align} AxisY &= \frac{\overrightarrow{P_4 - P_1}}{\overrightarrow{|P_4 - P_1|}}\\ {P_4}^\prime &= P_1 + AxisY * dot*ratio\\ \end{align} $$ 최종적으로 ${P_3}^\prime$는 아래와 같습니다. $$ {P_3}^\prime = P_1 + AxisX *dot + AxisY * dot * ratio $$ 이로써 기존의 비율을 유지한 채 직사각형의 크기를 바꿀

[윈도우즈 서비스] 설치 파일 만들기(WIX) - #4

이제 윈도우즈 서비스를 다 만들었기 때문에 설치 파일을 만들어 보겠습니다. 저희 같은 경우에는 불특정 다수의 PC에 설치하는 것이 아니고 서버에만 설치하면 되기 때문에 파일을 서버에 복사한 뒤 [윈도우즈 서비스] Console 실행 - #1 에서 설명한 방식대로 서비스를 등록해도 됩니다. 하지만 설치 파일을 만들면 이러한 작업을 자동으로 해주기 때문에 번거로운 작업을 하지 않아도 됩니다. WIX를 이용하여 윈도우즈 서비스를 등록하는 방법을 알아보도록 하겠습니다. How To: Install a Windows service To install a Windows service, use the  ServiceInstall  element. Other configuration can be made using the  ServiceControl  element and the  ServiceConfig  element from WixUtilExtension. Step 1: Install the service The  ServiceInstall  element contains the basic information about the service to install. This element should be the child of a  Component  element whose key path is a sibling  File  element that specifies the service executable file. Tip:  to specify a system account, such as LocalService or NetworkService, use the prefix  NT AUTHORITY . For example, use  NT AUTHORITY\LocalService  as the  Account  attribute value to run the service under this account. ServivceInstall

[윈도우즈 서비스] log4net - #3

이제 윈도우즈 서비스에서 프로세스를 이용하여 작업을 수행 할 수 있습니다. 이전 글에서도 이야기 한 것처럼 로그를 남기는 것은 중요한 부분입니다. log4net - Adding appenders programmatically log4net을 이용한 logging Dynamic log fileNames with log4net 로그를 남겨야만 프로그램이 오작동 했을 때 원인을 유추해 볼 수 있습니다. 그래서 윈도우즈 서비스와 프로세스 둘 다 로그를 남기기로 하고 설정을 했습니다. Cofiguration 예제 <?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file type="log4net.Util.PatternString" value="${programdata}\FinalService\Process\Log\"/> <appendtofile value="true"/> <datepattern value="yyyy-MM-dd'.log'"/> <staticlogfilename value="false"/>

[윈도우즈 서비스] Console 실행 - #2

윈도우즈 서비스에서 타이머를 돌려 문서 목록을 가져와 Console 프로그램(프로세스)을 실행시켜 작업을 처리하려고 합니다. 1. 프로세스를 계속 생성할 수 없으므로 지정한 갯수만큼만 생성하고, 2. 프로세스가 작업을 완료하면 문서 목록에서 문서를 삭제합니다. 이를 바탕으로 그려본 흐름도입니다. DB에서 FinalPDF를 생성할 문서 정보를 가져옴 프로세스 수가 지정된 갯수보다 작다 FinalPDF를 생성할 문서가 있을 때까지 실행중인 프로세스를 구함 프로세스 시작 END N Y 위 흐름도에서 예외 사항을 고려해보면, 오래 걸리는 작업일 경우 작업 처리 중에 타이머 시간이 돌아오면 동일한 작업을 수행하는 프로세스를 다시 실행하게 됩니다. 이런 경우를 대비하기 위해 프로세스를 실행할 때 작업 문서에 프로세스 ID를 저장합니다. 이렇게 하면 중복 작업을 막을 수 있습니다. 타이머 시간이 되면 프로세스 ID를 가진 문서는 실제 프로세스가 돌아가는지 확인하여 프로세스가 돌아가지 않는다면, 작업이 완료된 경우 : 문서 목록에서 해당 문서를 제거합니다. 작업이 완료되지 못한 경우 : 프로세스를 다시 실행시킵니다. 아래는 개선한 흐름도와 의사(PSEUDO) 코드입니다. DB에서 FinalPDF를 생성할 문서 정보를 가져옴 프로세스 수가 지정된 갯수보다 작다 FinalPDF를 생성할 문서가 있을 때까지 실행중인 프로세스를 구함 해당 문서의 프로세스가 실행 중? 프로세스 시작 END N Y N var process = Process.Start(startInfo); /// process.Id를 저장 ... private void _Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { var clone = DocumentProcessMap.ToDictionary(x => x

Diff 알고리즘 활용

실제 프로젝트에서 Diff 알고리즘을 활용한 예를 보도록 하겠습니다. 아래와 같은 목록을 가지고 3D로 알아서? 모델링하는 경우를 생각해 봅시다. CONCENTRIC, FLEXIBLE HOSE, CHECK, BUTTERFLY, GATE, FLANGE 사용자가 요구 사항 으로 목록의 항목을 더블 클릭했을때 해당하는 모델을 하이라이트하는 기능을 만들고자 합니다. 항목은 아래와 같은 Class로 정의됩니다. class Item { public string UID{get;set;} public string Type{get;set;} } 쉽게 생각해보면 모델을 생성할 때 해당 Item의 UID를 속성을 넣어 준다면, 위 기능을 구현할 수 있습니다. 하지만 외부에서 만들어진 모델(Type은 알고 있지만 UID 값을 가지지 않음)을 가지고 위 기능을 만들려면 어떻게 해야 할까요? 먼저 모델의 UID를 대응하는 Item의 UID로 업데이트하여 동기화 시켜야 합니다. 순차적으로 나타나는 Type으로 유추하면 되지 않을까 생각할지도 모르겠지만 동일한 Type이 여러개 나올 수 있다고 생각하면 올바른 방법이 아닌것 같습니다. 이때 Diff 알고리즘을 활용할 수 있을것 같습니다. 여기 서 코드를 다운받을 수 있습니다. Type을 NewLine으로 연결하여 lhstr, rhstr를 생성합니다. 그리고 나서 DiffText 함수를 호출하면 var diffs = Diff.DiffText(lhstr, rhstr, true, true, true).Reverse(); 나중에 추가, 삭제된 부분을 제거하기 위해 결과 값을 역 정렬했습니다. lhs에서는 추가된 정보를, rhs에서는 삭제된 정보를 리턴하고 있습니다. 위 예에서 lhs에서는 2개 항목이 삭제되었고, rhs에서는 4개 항목이 추가되었다고 합니다. 변경된 항목을 제거하면 즉 lhs에서 2개 항목을 삭제하고, rhs에서 4개 항목을 삭제하면, lhs, rhs의 항목의 수는

메타 퀘스트 3

2월 달 연말 정산 환급받은 돈으로 메타 퀘스트 3를 3개월 할부로 샀습니다. 제가 유일하게 이용하는 쿠팡에서 케이스와 같이 판매하는 놈으로 신용카드 결제하고 나서 며칠 뒤에 물건을 받았습니다. 퇴근하자마자 WIFI를 잡고 이것저것 세팅을 하고 있으니까 아내가 아이들과 학원을 마치고 함께 집에 왔습니다. 제가 하는 것을 물끄러미 보더니만 이거 얼마 주고 샀어? 응 쿠팡에서 00주고 샀어 그리고는 아내는 옷을 갈아입으러 안방으로 들어가고 저는 나머지 설정을 계속했습니다. 설정을 다 끝마치고 뒷정리를 하고 있는데 아내가 제 쪽으로 다가오더니 00 사이트를 보니까 이것보다 10만이나 싸던데? 가격 비교는 하고 산거지? 라고 물었습니다. 물론 쿠팡에서만 검색했지 다른 사이트와 가격 비교는 하지 않았습니다. 음.. 저는 말을 얼버무렸습니다. 아내는 한심하다는 듯 저를 쳐다보더니 10만 원이면 애들 학원을 하나 더 보낼 수 있는데 앞으로 이런 것 살 때 나한테 얘기해.. 저는 아무 말 없이 마저 뒷정리했습니다. 아내는 그 뒤로도 2번이나 같은 말을 저에게 했습니다. 물론 믿었던 쿠팡에서 10만 원이나 비싸게 주고 산 것에 마음이 쓰라렸지만, 가격 비교하고 검색하고 이것저것 비교한 후에 구매하는 것에 익숙하지 않아 이런 일들이 심심치 않게 일어나곤 합니다. 이번에도 제가 검색만 조금 했더라면 156GB가 아닌 526GB를 샀을 겁니다. 애들이 퀘스트 2에서 해보고 재미있었던지 엘리베이터를 타는 것을 설치해 달라고 해서 기기를 구매하면 제공하는 3만 크레딧으로 구매했습니다. ISLANDERS VR, Smash Drums 등을 추가로 구매하고 나니 3만 크레딧은 금방 사라지고 추가로 돈을 내야 했습니다. 3D로 구현되어서 그런지 퀘스트용 앱들은 크기가 모두 10GB 이상이 되어 앱을 몇 개 다운받으니 용량이 90%가 찼습니다. 배터리 시간도 완충하고 2시간 정도 사용하고 나면 충전을 해야 합니다. 저 같은 경우에는 게임을

[윈도우즈 서비스] Console 실행 - #1

윈도우즈 서비스에서 특정 작업을 수행할 경우, 작업이 한꺼번에 많이 몰릴 때를 대비하여 프로세스를 실행하여 작업을 처리하려고 합니다. (기존에는 서비스 내부에서 스레드(Thread)를 생성하여 처리했었는데 문제가 많이 발생했었습니다.) 이렇게 프로세스로 처리하면 작업 중에 오류가 발생하더라도 해당 프로세스만 종료되고 윈도우즈 서비스에는 아무런 영향도 미치지 않게 됩니다. 윈도우즈 서비스는 이 글 참조하여 생성하면 됩니다. 위 글에서도 나와있지만 관리자 권한으로 Command를 실행하여 서비스를 등록해야 합니다. 그렇지 않으면 아래와 같은 오류 메시지를 뿌리고 등록에 실패하게 됩니다. 서비스에 등록했으면 WIN 키( ) + R키를 눌러 services.msc 를 입력하여 윈도우즈 서비스 창을 엽니다. 하지만 서비스를 바로 실행하면 아마 아래와 같은 메시지가 뜨면서 서비스가 실행되지 않습니다. 서비스 화면에서 해당 서비스의 속성 창으로 들어가서 로그온 탭에서 계정을 로컬 시스템 계정으로 변경합니다.( '서비스와 데스크탑 상호 작용 허용' 을 체크해주세요.)  ->  다시 서비스를 실행하면 서비스가 제대로 실행됩니다. 서비스에서 실행할 Console 프로그램 서비스에서 Timer를 돌려 특정 시간마다 Console 프로그램을 실행하려고 합니다. 실행 중인 Console 프로그램의 Instance의 수를 얻어 Console 프로그램 실행 여부를 판단할 수 있습니다. string ProcessName = "ConsoleApp1"; // Get all instances of ConsoleApp1 running on the local computer. // This will return an empty array if ConsoleApp1 isn't running. Process[] ProcessByName = Process.GetProcessesByName(Proces

[윈도우즈 이벤트 로그] System.Security.SecurityException

프로그램에서 발생하는 에러를 이벤트 로그를 남기려고 아래와 같이 이벤트 로그에 접근하니 windowEventLog = Log; windowEventLog.Source = SourceName; windowEventLog.Log = LogName; if (!EventLog.SourceExists(SourceName)) EventLog.CreateEventSource(SourceName, "Application"); System.Security.SecurityException 오류가 발생했습니다. 위 5 번째 줄에서 원본 여부를 존재 여부를 확인할때 오류가 발생합니다. 검색해보니 EventLog.SourceExists 함수에서 EventLog\Security 에 접근하게 되는데 관리자 권한 이 없을 경우에 오류가 발생한다고 합니다. 이 경우에는 레지스트리에 SourceName 으로 키를 생성해주면 오류가 발생하지 않는다고 합니다. Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\SourceName] 위 내용을 .reg 파일로 생성해서 실행시켜주면 됩니다.

IronPython 활용

예전부터 응용 프로그램에 Python을 결합하여 즐겨 사용했는데, 어떤 사용자의 요구사항 때문이었습니다. 그 사용자가 사용하는 프로그램에 계산식이 있는데 계산식이 프로젝트의 특성때문에 조금씩 수정해야 한다는 것이었습니다. 프로젝트마다 계산식을 수정해서 프로그램을 배포하기가 어려워 계산식 자체를 Python 코드로 외부 파일로 빼내는 방식으로 처리했습니다. 어느날 차를 몰고 가는데 전화가 와서 이번 프로젝트에서는 factor 3을 3.5로 바꿔야 하는데 어떻게 하나요? 라고 문의가 왔습니다. Python 파일을 열어 숫자 3을 3.5로 바꾸면 된다고 답변을 해줬습니다. 이렇게 사용자는 프로젝트마다 Python에서 계산식을 수정하여 사용하면 되기 때문에 프로그램을 수정할 필요가 없어집니다. 이전 글 에서도 이야기했듯이 IronPython은 C#과 궁합이 아주 좋아 이번 프로젝트에서도 IronPython을 프로그램에 포함시켰습니다. 자동으로 생성된 배관 라인을 수정하거나 새로 생성하는 기능을 위해 IronPython을 활용했습니다. 먼저 앱 실행 경로를 IronPython 검색 경로에 추가해줍니다. 1 2 3 4 5 6 #region IronPython의 검색 경로에 앱 실행 경로를 추가 var paths  =  _IronPython.GetSearchPaths(); var ExecutePath  =   System .IO.Path.GetDirectoryName(Application.ExecutablePath); paths.Add(ExecutePath); _IronPython.SetSearchPaths(paths); #endregion Colored by Color Scripter cs 아래와 같이 C# Class를 정의하고 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public   class  MoveTo {      public  MoveTo(PythonTuple value)     {          int