블로그 이미지
진연
3차원 CAD프로그램인 UGS에서 지원하는 API를 이용하여 프로그램하는 방법등을 소개하는 블로그입니다. 혹시 연락이 필요하신분은 youni7311@hanmail.net로 메일 보내주세요..

calendar

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

4. 마우스로 라인그리기(2)

안녕하세요.. 4번째 시간 입니다.. 오늘은 집에 일찍 들어와서 집에서 작업하네요..
어떻게 도움이 되시는지 모르겠습니다... 큰 도움이 되길 바라며 또 산 하나 넘으러 가죠..^^

저번 강좌 마지막에 말씀 드렸듯이 라인그리는 기능을 좀더 보강해 보죠.. 오늘은 새로 사용하는 함수가 아주 조금 많습니다.. 또 사람에 따라서 조금 어려울수도 있습니다... 오늘 코드 역시 마우스로 선택한 포인트 좌표를 받아 라인을 그립니다.


그러나, 저번 강좌와 다른점은 고무줄(Rubberband)기능을 구현해 보았습니다.

Rubberband기 모냐구요..? 라인그릴 때 한점 찍고, 다음 점 찍으려고 움직일때 라인이 마우스를 따라다니면서 미리 보여주는 기능입니다. 그리고, 같은 위치에 마우스를 더블 클릭하면 라인 그리기가 종료됩니다. 나중에 만들어서 보시면 아하!! 하실 겁니다..

그럼 늘 하던대로 원본 소스 코드부터 나갑니다.

/*****************************************************************************
**
** basic_line.cpp
**
** Description:
** Contains Unigraphics entry points for the application.
**
*****************************************************************************/

#if ! defined ( __hp9000s800 ) && ! defined ( __sgi ) && ! defined ( __sun )
# include <strstream>
# include <iostream>
using std::ostrstream;
using std::endl;
using std::ends;
using std::cerr;
#else
# include <strstream.h>
# include <iostream.h>
#endif

#include <uf.h>
#include <uf_ui.h>
#include <uf_exit.h>
#include <uf_curve.h>
#include <uf_ui.h>

#include <uf_disp.h>
#include <uf_vec.h>
#include <uf_modl.h>

#define UF_CALL(X) (report_error( __FILE__, __LINE__, #X, (X)))

static int report_error( char *file, int line, char *call, int irc)
{
   if (irc)
   {
      char err[133], msg[133];

      UF_get_fail_message(irc, err);
      sprintf(msg, "error %d at line %d in %s", irc, line, file);

      if (!UF_UI_open_listing_window())
      {
          UF_UI_write_listing_window(err);
          UF_UI_write_listing_window("\n");
          UF_UI_write_listing_window(msg);
          UF_UI_write_listing_window("\n");
          UF_UI_write_listing_window(call);
          UF_UI_write_listing_window(";\n\n");
      }
      else {}
   }
   return(irc);
}

return(irc);
}

void motion_callback(double screen_pos[3],UF_UI_motion_cb_data_p_t motion_cb_data,  
                              void  *user_data)
{
    double* start_pts = (double*)user_data;
    UF_DISP_display_ogp_line (motion_cb_data->view_tag, start_pts, screen_pos);
    return;
}

extern DllExport void ufsta( char *param, int *returnCode, int rlen )
{
   int rtn;

   UF_CURVE_line_t line_coords;
   tag_t line_tag;

   double cp[3];

   int is_equal;
   double distance_tolerence;
   tag_t view_tag;

   UF_OBJ_disp_props_t disp_prop = {1, 0, UF_OBJ_NOT_BLANKED,  
                                               UF_OBJ_WIDTH_NORMAL, UF_OBJ_FONT_SOLID, FALSE};

   if( UF_CALL(UF_initialize()) ) return;

   UF_UI_specify_screen_position ("Select start point", NULL, NULL, cp, &view_tag, &rtn);
   if(rtn == UF_UI_BACK || rtn == UF_UI_CANCEL) goto END_SUB;

   line_coords.start_point[0] = cp[0];
   line_coords.start_point[1] = cp[1];
   line_coords.start_point[2] = cp[2];

   disp_prop.color = UF_OBJ_WHITE;
   UF_DISP_display_temporary_point (NULL, UF_DISP_USE_WORK_VIEW,
                                   line_coords.start_point, &disp_prop, UF_DISP_ASTERISK);


   while(1) {

       UF_UI_specify_screen_position ("Select end point", motion_callback, (void*)
                                                      line_coords.start_point, cp, &view_tag, &rtn);
       if(rtn == UF_UI_BACK || rtn == UF_UI_CANCEL) break;

       line_coords.end_point[0] = cp[0];
       line_coords.end_point[1] = cp[1];
       line_coords.end_point[2] = cp[2];

       disp_prop.color = UF_OBJ_WHITE;
       UF_DISP_display_temporary_point (NULL, UF_DISP_USE_WORK_VIEW,
                                        line_coords.end_point, &disp_prop, UF_DISP_ASTERISK);

       UF_MODL_ask_distance_tolerance (&distance_tolerence);
       UF_VEC3_is_equal (line_coords.start_point, line_coords.end_point,
                                    distance_tolerence, &is_equal);
       if(is_equal == 1) break;

       rtn = UF_CALL(UF_CURVE_create_line (&line_coords, &line_tag));

       line_coords.start_point[0] = line_coords.end_point[0];
       line_coords.start_point[1] = line_coords.end_point[1];
       line_coords.start_point[2] = line_coords.end_point[2];
   }

END_SUB:
    UF_CALL(UF_terminate());
}

extern int ufusr_ask_unload( void )
{
    return( UF_UNLOAD_UG_TERMINATE );
}

오늘은 웬지 길어보입니다..TT 그래도, 한번 내려가 볼까요..?

- 오늘 추가된 Header File입니다.
#include <uf_disp.h> - Display 관련
#include <uf_vec.h> - Vector 관련
#include <uf_modl.h> - Modeling 관련

- 아래 함수는 콜백함수(Callback) 입니다. 콜백함수는 어떠한 사건이 일어났을 때 동작하는 함수를 말합니다. 아래의 콜백함수는 UF_UI_specify_screen_position 함수와 같이 사용하는데 마우스가 움직일 때 이 함수가 실행됩니다. 자세한 설명은 UG Documentation을 참조하시기 바랍니다.
void motion_callback(double screen_pos[3],UF_UI_motion_cb_data_p_t motion_cb_data,
                               void *user_data)
{
   double* start_pts = (double*)user_data;

   UF_DISP_display_ogp_line (motion_cb_data->view_tag, start_pts, screen_pos);
   return;
}


- 추가된 변수들 입니다.
int is_equal;
double distance_tolerence;
tag_t view_tag;


- Display 속성을 정의하는 구조체 입니다. {layer, color, blank_status, line_width, font, highlight_status}
UF_OBJ_disp_props_t disp_prop = {1, 0, UF_OBJ_NOT_BLANKED,
                                         UF_OBJ_WIDTH_NORMAL, UF_OBJ_FONT_SOLID, FALSE};

- 아 함수 역시 마우스로 선택한 한 점의 좌표를 가져오는 함수입니다. cu1616과 달리 옵션기능은 없지만, 콜백함수를 등록해서 사용할 수 있습니다. 그러나 아래 코드는 콜백함수가 필요없기 때문에 NULL값으로 처리했고, 단순히 마우스로 선택한 좌표를 cp에 담아서 리턴 해줍니다.
UF_UI_specify_screen_position ("Select start point", NULL, NULL, cp, &view_tag, &rtn);
if(rtn == UF_UI_BACK || rtn == UF_UI_CANCEL) goto END_SUB;

- Temporary point를 그리는 함수입니다.(Refresh를 하면 없어지는 포인트)
disp_prop.color = UF_OBJ_WHITE;
UF_DISP_display_temporary_point (NULL, UF_DISP_USE_WORK_VIEW,
                                   line_coords.start_point, &disp_prop, UF_DISP_ASTERISK);

- 이 구문은 아래에서 콜백함수와 설명하겠습니다.
UF_UI_specify_screen_position ("Select end point", motion_callback, (void*)
                                              line_coords.start_point, cp, &view_tag, &rtn);
if(rtn == UF_UI_BACK || rtn == UF_UI_CANCEL) break;

- 위에서 설명했죠..^^
disp_prop.color = UF_OBJ_WHITE;
UF_DISP_display_temporary_point (NULL, UF_DISP_USE_WORK_VIEW,
                                 line_coords.end_point, &disp_prop, UF_DISP_ASTERISK);

- UG에 설정되어 있는 Distance Tolerance 값을 받아옵니다.
UF_MODL_ask_distance_tolerance (&distance_tolerence);

- 두 점이 Distance Tolerance안에서 동할한 좌표인지를 확인하는 함수입니다.
만약, 사용자가 실수로 라인의 시작점과 끝점을 동일하게 선택 하면 UF_CURVE_create_line 함수에서 error가 발생합니다. 이러한 경우를 예외처리하기 위해 아래과 같이 두점이 동일한 좌표인지 판단하는 코드가 필요합니다.
UF_VEC3_is_equal (line_coords.start_point, line_coords.end_point,
                           distance_tolerence, &is_equal);
if(is_equal == 1) break;

rtn = UF_CALL(UF_CURVE_create_line (&line_coords, &line_tag));

휴!! 이상으로 변경된 코드에 대해 설명했는데... 점점 설명이 어려워 지네요..^^

아!! 아까 그냥 넘어간 부분이 있죠..? 아래 합쳐서 다시한번 써보겠습니다.

void motion_callback(double screen_pos[3],UF_UI_motion_cb_data_p_t motion_cb_data, void *user_data)
{
   double* start_pts = (double*)user_data;
  
UF_DISP_display_ogp_line (motion_cb_data->view_tag, start_pts, screen_pos);
   return;
}

UF_UI_specify_screen_position ("Select end point", motion_callback, (void*)
 line_coords.start_point, cp, &view_tag, &rtn);
if(rtn == UF_UI_BACK || rtn == UF_UI_CANCEL) break;

위 코드의 동작은 이렇습니다. UF_UI_specify_screen_position 함수를 실행 시키는 순간 한 점을 선택할 수 있는 Dialog가 실행되고, motion_callback 함수가 콜백함수로 등록됩니다.
그리고, 마우스를 움직일때 마다 motion_callback함수가 실행되고, 첫번째 파라메터인 double screen_pos[3]에 현재 움직이고 있는 마우스의 위치좌표를 실시간으로 리턴해줍니다. 이러한 동작을 응용해서 RubberBand 효과를 얻을 수 있습니다. 말로 설명하려니 힘드네요.. 직접 코딩하시고, 디버그 모드에서 어떻게 동작하는지 테스트 해보시기 바랍니다. 한번 해보시면 금방 이해 됩니다.

이번에는 웬지 설명이 지루해 보이네요... 한번 보면서 설명하면 아무것도 아닌데 글로 표현하려니 너무 어렵네요... 그래서 오늘은 여기까지 하겠습니다... 좀 길어보여보 만들어 보시면 결과가 재미있습니다...

100번을 강조해도 지나침이 없습니다.. 꼭 직접 코딩하시고 결과 보세요...안해보시면 절대 이해 못하십니다..^^

posted by 진연