블로그

  • TinyXML

    http://hanburn.tistory.com/6
    http://hanburn.tistory.com/7
    http://hanburn.tistory.com/8

     

    TinyXML은 간단하고 작은 C++ XML 파서 입니다.
    사용하기가 편리하고 다른 프로그램으로 이식하기도 수월한 편입니다.

    온라인 도움말 : http://www.grinninglizard.com/tinyxmldocs/index.html
    소스를 받는곳 : http://sourceforge.net/projects/tinyxml/

    설치하려면.. 일단 소스 받는곳에서 소스를 환경에 맞게 받는다.
    윈도우 버전으로 받으면 VC++6.0 작업화일과 VS.NET 용 솔루션 파일이 포함되어 있다.

    사용하는 방법은 2가지로 나눌수 있다.  ( 그리고 각각 STL을 사용하는 버전과 아닌 버전으로 되어 있다. )

    1. 해당 소스를 컴파일 하여 생성되는 Tinyxml.lib와 헤더파일을 이용하는 방법
    – 이방법은 제공되는 솔루션 파일( tinyxml.sln) 을 열어서 빌드만 하면 된다.
    – 사용하는 프로젝트가 멀티 쓰레드이면 런타임 라이브러리를 멀티 쓰레드로 변경해야 한다.
    (기본 설정은 싱글 쓰레드로 되어 있다.
    – tinyXml.lib 는 스태틱 라이브러리로 컴파일시에 exe에 포함되므로 따로 배포를 않해도 된다.

    2. 소스를 직접 포함시켜서 사용하는 방법.
    – 필요한 파일을 프로젝트에 파일 추가로 등록한다.
    (tinystr.h(cpp), tinyxml.h(cpp), tinyxmlerror.cpp, tinyxmlparse.cpp 총 6개다 )
    – 컴파일을 하려고 하면 precompile header 관련하여 에러가 난다.
    – 프로젝트 설정에서 cpp의 (3개 파일) precompile header 사용을 빼버린면 된다.

    사용자 삽입 이미지

    어떻게 보면 거의 같은 방법이다. ㅎㅎ
    개인적으로 2번째 방법을 선호한다. 개발중에 cpp 소스를 가끔 보게 되므로..
    그럼 다음 글에서는 간단한 사용법들을 알아보자.

     

    XML에 대해서는 이미 알고 있다고 가정합니다.
    (모르면 공부하고 다시 오세요 ^^)

    일단 XML을 파일에서 읽을수도 있고 문자열로 읽을 수도 있다.
    아래 예에서 사용할 xml 파일은 다음과 같다.

    <?xml version=”1.0″ ?>
    <MyApp>
    <!– Settings for MyApp –>
    <Messages>
    <Welcome>Welcome to MyApp</Welcome>
    <Farewell>Thank you for using MyApp</Farewell>
    </Messages>
    <Windows>
    <Window name=”MainFrame” x=”5″ y=”15″ w=”400″ h=”250″ />
    </Windows>
    <Connection ip=”192.168.0.1″ timeout=”123.456000″ />
    </MyApp>

    먼저 파일에서 읽을때는,

    TiXmlDocument document;
    document.LoadFile(_File_Name_);

    문자열로 읽을때는,

    TiXmlDocument document;
    document.Parse(szXML);

    너무 쉽다. 그런 다음에는 원하는 값을 찾아오면 된다.
    먼저 노드와 엘리먼트를 가지고 오는 방법을 알아보자.
    ( 노드는 자식을 가지고 있는 것이고 엘리먼트는 마지막에 있는 놈이다. )

    TiXmlElement* pRoot = document.FirstChildElement(“MyApp”);
    if( NULL == pRoot ) return FALSE;   // 해당 Element가 없으면 널이므로.. 체크해주는게 좋다.

    그럼, <Welcome> 태그로 가서 데이터를 가지고 와보자.

    pElement = pRoot->FirstChildElement(“Message”);
    pElement = pElement->FirstChildElement(“Welcome”);
    char* pAA = pElement->Value();                 // pAA 은  “Welcome” 이다.
    pAA = pElement->GetText();                       // pAA 은  “Welcome to MyApp” 이다.

    이번에는 다음에 windows 태그로 가서 name 속성을 읽어 와보자.

    pElement = pRoot->FirstChildElement(“Windows”);
    char* pAA = pElement->Attribute(“name”);   // pAA에 “MainFrame”이 들어온다.
    int x;
    pElement->Attribute(“x”, &x);                    // x 에 숫자 5가 들어온다.

    그다음에는 루프를 돌면서 child 노드를 순환하는 방법이다.

    pNode = pRoot->FirstChild(“sub_node”);
    for( pNode ; pNode ; pNode = pNode->NextSibling())
    {
    pAA = pNode->Value();

    pElement = pNode->FirstChildElement(“item”);
    pAA = pElement->GetText();
    }

    앞에서는 xml 파일이나 xml문자열에서 파싱을 해서 원하는 정보를 뽑아오는 것을 해보았다.
    그러면 이제는 반대로 설정이나 원하는 정보를 xml 형식으로 만들어 보자.
    앞에서 사용한 xml을 만들어 보도록 하자

    <?xml version=”1.0″ ?>
    <MyApp>
    <!– Settings for MyApp –>
    <Messages>
    <Welcome>Welcome to MyApp</Welcome>
    <Farewell>Thank you for using MyApp</Farewell>
    </Messages>
    <Windows>
    <Window name=”MainFrame” x=”5″ y=”15″ w=”400″ h=”250″ />
    </Windows>
    <Connection ip=”192.168.0.1″ timeout=”123.456000″ />
    </MyApp>

    일단 xml 의 형식선언부터 시작해 보자..

    TiXmlDocument doc;
    TiXmlElement* msg;
    TiXmlDeclaration* decl = new TiXmlDeclaration( “1.0”, “”, “” );
    doc.LinkEndChild( decl );

    이렇게 하면 <?xml version=”1.0″ ?> 이 생성된다.
    다음으로는, 서브 노드를 추가해보자.

    TiXmlElement * root = new TiXmlElement( “MyApp” );
    doc.LinkEndChild( root );

    간단하다. 그리고 new로 생성한 TiXmlElement를 해제할 필요가 없다. 내부에서 자동으로 삭제를 해주기 때문이다. (편리하군~ ^^)
    그런 다음 주석문장을 추가해 보자.

    TiXmlComment * comment = new TiXmlComment();
    comment->SetValue(” Settings for MyApp ” );
    root->LinkEndChild( comment );

    주석은 TiXmlComment 클래스를 사용하면 된다. 편리하군..
    다음으로는  Message 서브노드와 하위 노드및 데이터를 추가해보자

    TiXmlElement * msgs = new TiXmlElement( “Messages” );
    root->LinkEndChild( msgs );

    msg = new TiXmlElement( “Welcome” );
    msg->LinkEndChild( new TiXmlText( “Welcome to MyApp” ));
    msgs->LinkEndChild( msg );

    msg = new TiXmlElement( “Farewell” );
    msg->LinkEndChild( new TiXmlText( “Thank you for using MyApp” ));
    msgs->LinkEndChild( msg );

    역시 쉽니다. 다음에는 노드를 추가하고 Attribute를 설정해보자
    레벨을 맞추기 위해서 root의 하위로 추가 한것을 주의 깊게 봐야 한다.

    TiXmlElement * windows = new TiXmlElement( “Windows” );
    root->LinkEndChild( windows );

    TiXmlElement * window;
    window = new TiXmlElement( “Window” );
    windows->LinkEndChild( window );
    window->SetAttribute(“name”, “MainFrame”);
    window->SetAttribute(“x”, 5);
    window->SetAttribute(“y”, 15);
    window->SetAttribute(“w”, 400);
    window->SetAttribute(“h”, 250);

    다음은 마지막으로 Double 값 (소수점 값) 을 설정하는 예를 보자

    TiXmlElement * cxn = new TiXmlElement( “Connection” );
    root->LinkEndChild( cxn );
    cxn->SetAttribute(“ip”, “192.168.0.1”);
    cxn->SetDoubleAttribute(“timeout”, 123.456); // floating point attrib

    이렇게 하면 우리가 원하는 xml이 doc에 만들어 졌다. 이것을 파일로 저장할 수도 있고 xml 문자열로 만들수도 있다. 방법은 아래를..

    // 파일로 저장
    doc.SaveFile(“text.xml”);

    //문자열로..
    TiXmlPrinter printer;
    printer.SetStreamPrinting();
    Doc.Accept( &printer );
    char* pAA = printer.CStr();                    // char* 를 반환한다.
    std::string str = printer.Str();                  // std::string으로 반환한다.

    이로써 간단하게 TinyXML의 사용법을 마칠까 한다.

  • 보색(Complementary color) 변환 (RGB/HSL 변환)

    http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=7249&page=45

    보색이란 색상휠에서 색조(hue) 값이 180도 반대방향에 위치한다고 합니다.
    (어렴풋 예전 미술 시간에 배웠던 것도 같습니다.)
    즉 RGB를 HSL값으로 변환한 후 HSL에서 색조(hue)를 180도 돌려준 후 이 HSL 값을 RGB 값으로 다시 변환하면 됩니다.

    – 보색 구하는 함수

    [code language=”cpp”]
    //
    // Calculate complementary color
    //
    // @param clr : [in] COLORREF, input RGB color from which
    // complementary color is calculated
    //
    // @return RGB color value of complementary color of input RGB color

    COLORREF CalcComplemental(COLORREF clr)
    {
    long hsl_h = 0, hsl_s = 0, hsl_l = 0;
    RGB2HSL_(clr, hsl_h, hsl_s, hsl_l); // CONV RGB to HSL
    hsl_h += 0x200; // HUE, ADD 180 deg (0x200 = 0x400 / 2)
    hsl_h &= 0x7ff; // HUE, MOD 360 deg to HUE
    return HSL2RGB_(hsl_h, hsl_s, hsl_l); // CONV HSL to RGB
    }
    [/code]

    – RGB 에서 HSL 변환하는 함수

    [code language=”cpp”]
    //
    // RGB to HSL conversion
    //
    // @param clr : [in] COLORREF, input RGB value to be converted
    // @param hue : [out] double &, converted hue value (0 ~ 2*PI)
    // @param saturation : [out] double &, converted saturation value (0%~ 100%)
    // @param lightness : [out] double &, converted lightness value (0% ~ 100%)
    void RGB2HSL( COLORREF clr,
    double & hue,
    double & saturation,
    double & lightness)
    {
    long hsl_h = 0, hsl_s = 0, hsl_l = 0;
    RGB2HSL_(clr, hsl_h, hsl_s, hsl_l);

    // long to double
    hue = 2.0 * 3.141592 * (double)hsl_h / 1024.0;
    saturation = (double)hsl_s / 1024.0;
    lightness = (double)hsl_l / 1024.0;
    }
    [/code]

    – HSL 에서 RGB 변환하는 함수

    [code language=”cpp”]
    //
    // HSL to RGB conversion
    //
    // @param hue : [in] double, input hue value (0 ~ 2*PI)
    // @param saturation : [in] double, input saturation value (0% ~ 100%)
    // @param lightnelss : [in] double, input lightness value (0% ~ 100%)
    //
    // @return converted RGB color value from the input HSL value
    COLORREF HSL2RGB(double hue, double saturation, double lightness)
    {
    // double to long
    const long hsl_h = (long)(hue / 2.0 / 3.141592 * 1024.0);
    const long hsl_s = (long)(saturation * 1024.0);
    const long hsl_l = (long)(lightness * 1024.0);

    return HSL2RGB_(hsl_h, hsl_s, hsl_l);
    }
    [/code]

    – 옵티마이징

    [code language=”cpp”]
    //
    // Integer version with 2^10(1024) resolution
    //
    // @param hsl_h : [out] long &, hue, 0 ~ 1024
    // @param hsl_s : [out] long &, saturation, 0 ~ 1024
    // @param hsl_l : [out] long &, lightness, 0 ~ 1024
    void RGB2HSL_(COLORREF clr, long & hsl_h, long & hsl_s, long & hsl_l)
    {
    const long var_r = GetRValue(clr) << 2;
    const long var_g = GetGValue(clr) << 2;
    const long var_b = GetBValue(clr) << 2;

    const long var_min = min(var_r, min(var_g, var_b));
    const long var_max = max(var_r, max(var_g, var_b));
    const long del_max = var_max – var_min;

    hsl_l = (var_max + var_min) >> 1;

    if(del_max == 0)
    {
    hsl_h = hsl_s = 0;
    }else
    {
    if(hsl_l < 512)
    hsl_s = (del_max << 10) / (var_max + var_min);
    else
    hsl_s = (del_max << 10) / (2048 – var_max – var_min);
    }

    const long temp = (var_max << 9) / 3 / del_max + (del_max << 9) / del_max;

    const long del_r = temp – ((var_r << 9) / 3) / del_max;
    const long del_g = temp – ((var_g << 9) / 3) / del_max;
    const long del_b = temp – ((var_b << 9) / 3) / del_max;

    if(var_r == var_max)
    hsl_h = del_b – del_g;
    else if(var_g == var_max)
    hsl_h = (1024 / 3) + del_r – del_b;
    else if(var_b == var_max)
    hsl_h = (2048 / 3) + del_g – del_r;

    if(hsl_h < 0)
    hsl_h += 1024;
    else if(hsl_h > 1024)
    hsl_h -= 1024;
    }

    //
    // Integer version with 2^10(1024) resolution
    //
    // @param hsl_h : [in] long, hue, 0 ~ 1024
    // @param hsl_s : [in] long, saturation, 0 ~ 1024
    // @param hsl_l : [in] long, lightness, 0 ~ 1024
    COLORREF HSL2RGB_(long hsl_h, long hsl_s, long hsl_l)
    {
    BYTE clrR = 0, clrG = 0, clrB = 0;
    long var_1 = 0, var_2 = 0;

    const long var_h = hsl_h;
    const long var_s = hsl_s;
    const long var_l = hsl_l;

    if(hsl_s == 0)
    clrR = clrG = clrB = (BYTE)(var_l >> 2);
    else
    {
    if(var_l < 512)
    var_2 = var_l + ((var_l * var_s) >> 10);
    else
    var_2 = var_l + var_s – ((var_l * var_s) >> 10);

    var_1 = (var_l << 1) – var_2;

    clrR = (BYTE)(HUE2RGB_(var_1, var_2, var_h + (1024 / 3)) >> 2);
    clrG = (BYTE)(HUE2RGB_(var_1, var_2, var_h) >> 2);
    clrB = (BYTE)(HUE2RGB_(var_1, var_2, var_h – (1024 / 3)) >> 2);
    }

    return RGB(clrR, clrG, clrB);
    }

    long HUE2RGB_(long var_1, long var_2, long var_h)
    {
    if(var_h < 0)
    var_h += 1024;
    else if(var_h > 1024)
    var_h -= 1024;

    const long temp1 = 3 * var_h;

    if(temp1 < 512)
    return (var_1 + (((3 * var_2 * var_h) >> 9) –
    ((3 * var_1 * var_h) >> 9)));
    else if(var_h < 512)
    return var_2;
    else if(temp1 < 2048)
    {
    const long temp2 = 4096 – (temp1 << 1);
    return (var_1 + ((var_2 * temp2 – var_1 * temp2) >> 10));
    }

    return var_1;
    }
    [/code]