bookmark_borderDirectX 선그리기

DirectX 선그리기…

VertexBuffer 말고 다른 방법으로 선을 그리고 싶었다…

ID3DXLine 이란것이 있었따!!
D3DXVECTOR3 p[3];
p[0].x =0; p[0].y = 0; p[0].z = 0.0f;
p[1].x =0.1; p[1].y = 1; p[1].z = 0.0f;
p[2].x =2; p[2].y = 0; p[2].z = 0.0f;
p는 오브젝트의 월드공간에 있어야함
—————————————————————————-
Device->BeginScene();
ID3DXLine *Line;
D3DXCreateLine(Device, &Line);
Line->SetWidth(width);
Line->SetAntialias(true);
Line->Begin();
Line->DrawTransform(p, 3, &(worldMat*viewMat*projMat), D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));    //이때의 행렬은 전체월드행렬*뷰*프로젝션 행렬을 넘겨줘야함
Line->End();
Line->Release();
Device->EndScene();

bookmark_borderUp2Bottom and Left2Right Sorting Algorithm

// ========================================================
// Up2Bottom and Left2Right Sorting Algorithm
// addressing (weakly) sparse rectangles
// —
// Usage: Select the objects, then run the script
// Target: InDesign CS4/CS5/CS6/CC
// ========================================================

const CS = +CoordinateSpaces.SPREAD_COORDINATES,
AP_MIN = +AnchorPoint.TOP_LEFT_ANCHOR,
AP_CENTER = +AnchorPoint.CENTER_ANCHOR,
AP_MAX = +AnchorPoint.BOTTOM_RIGHT_ANCHOR;

var sel = app.properties.selection || null,
data = [],
r, i, j, k, t, n, w, vMax;

if( sel && 1 < (n=sel.length) ) { // Collect coordinates and IDs // --> {min:[xLeft, yTop], weight:[x,y], max:[xRight,yBottom], id}[]
for(i=0 ; i < n && (t=sel[i]) ; ++i ) { data[i] = { min: t.resolve(AP_MIN,CS)[0], weight: t.resolve(AP_CENTER,CS)[0], max: t.resolve(AP_MAX,CS)[0], id: t.id }; } // Find rows and columns [i.e. y-weights and x-weights] // --- for( j=0 ; j < 2 ; ++j ) { // Sort by center coordinate // --- data.sort(function(a,b){return a.weight[j] - b.weight[j]}); // min > max ==> w++
// —
for(vMax=(t=data[0]).max[j], t.weight[j]=(w=0), i=1 ; (i < n)&&(t=data[i]) ; ++i ) { if( t.min[j] > vMax ){ ++w; vMax=t.max[j]; }
t.weight[j] = w;
}
}

// Compute final weights, clean up data, create ID-to-weight access
// —
for( i=0 ; (i < n)&&(t=data[i]) ; ++i ) { w = n*t.weight[1] + t.weight[0]; // final weight (y first) k = '_'+t.id; // ID key (t.min.length=0)||(t.weight.length=0)||(t.max.length=0); delete t.min; delete t.weight; delete t.max; delete t.id; delete data[i]; data[k] = w; // ID-to-weight } // Apply sort --> r
// —
r = sel.sort(function(a,b){return data[‘_’+a.id]-data[‘_’+b.id];});

// Show the resulting order
// —
for( i=0 ; i < n ; ++i ) { app.select(r[i]); $.sleep(1000); } }

bookmark_border[MFC] CTreeCtrl 자식 아이템 체크/ 해제

CTreeCtrl 을 사용해서 체크박스를 단후 체크박스를 체크 하면 자식들도 모두 체크 하거나 체크 해제 하고 싶을 경우가 있는데. 이럴때 다음과 같은 방법으로 자식 노드를 재귀호출하여 체크/해제 할수 있다.

먼저 클릭 이벤트를 만들다. 핸들러는 TVN 게열과 NM 계열이 있는데 . 해당 체크 박스를 좌클릭 했을때 자식아이템을 쳌,/ 해제 하기를 원하기 때문에 NM_CLICK 이벤트를 선택한다.

코드는 다음과 같이 한다.

[cpp]
//
// CTreeCtrl에 왼쪽 마우스 이벤트가 발생했을 경우
// 이벤트가 발생한 좌표에 트리아이템이 존재하고 체크박스가 체크된 경우
// 정해진 작업을 수행한다.
//
void [CMainClass]::OnNMClickTreeDevices(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = 0;

CPoint point;
UINT nFlags = 0;

GetCursorPos(&point);
::ScreenToClient(m_ctrlTree.m_hWnd, &point);

HTREEITEM hItem = m_ctrlTree.HitTest(point, &nFlags);

// 아이템이 존재하고 체크박스에 이벤트가 발생했다면
if (hItem != NULL && (nFlags & TVHT_ONITEMSTATEICON) != 0)
{
// 해당 아이템이 체크되어 있다면
if (m_ctrlTree.GetCheck(hItem))
{
UnCheckChildItems(hItem);
}
// 해당 아이템이 체크되어 있지 않다면
else
{
CheckChildItems(hItem);
}
}
}

[/cpp]
[cpp]
//
//
// 입력받은 트리아이템의 자식아이템들을 모두 체크한다.
//
void [CMainClass]::CheckChildItems(HTREEITEM hItem)
{
HTREEITEM hChildItem = m_ctrlTree.GetChildItem(hItem);

while (hChildItem != NULL)
{
m_ctrlTree.SetCheck(hChildItem, TRUE);

if (m_ctrlTree.ItemHasChildren(hChildItem))
{
CheckChildItems(hChildItem);
}

hChildItem = m_ctrlTree.GetNextItem(hChildItem, TVGN_NEXT);
}
}

[/cpp]
[cpp]
//
//
// 입력받은 트리아이템의 자식아이템들을 모두 체크 해제한다.
//
void [CMainClass]::UnCheckChildItems(HTREEITEM hItem)
{
HTREEITEM hChildItem = m_ctrlTree.GetChildItem(hItem);

while (hChildItem != NULL)
{
m_ctrlTree.SetCheck(hChildItem, FALSE);

if (m_ctrlTree.ItemHasChildren(hChildItem))
{
UnCheckChildItems(hChildItem);
}

hChildItem = m_ctrlTree.GetNextItem(hChildItem, TVGN_NEXT);
}
}

[/cpp]

bookmark_borderAutoCAD명령내리기 acedCommand() , acedCmd() 이해와 사용법

이번 강좌는 AutoCAD 명령을 내리기 위한 방법을 알아봅시다.

리습에서 프로그램을 작성하다보면 명령어로 많은 작업을 하게 됩니다. 이때 많이 사용되는 함수가 (command)함수이죠.
바로 이 명령과 동일한 역할을 하는 함수가 ObjectARX에서 acedCommand()와 acedCmd()임니다.
만약 가지고 있는 리습을 Arx로 바꾸고자 하신다면 이 명령들을 잘 아셔야 겠죠.^.^;

=============================================================================================
1. acedCommand()

int acedCommand( int rtype, …);
이 함수는 가변인자를 가지는데 AutoCAD는 인자를 쌍으로 취급함으로써 명령을 수행합니다. 쌍중 첫번째는 다음에 올 인자의 타입을 표시하고, 두번째가 실제데이타를 포함하고 있습니다. 리스트의 마지막은 하나의 인자로 0 또는 RTNONE이 오는데 명령리스트 끝을 의미합니다..

일반적으로 첫번째 파라미터는 RTSTR(String을 말함)이라는 result type codes가 오고 두번째 데이터 파라미터는 실행할 명령 문자열이 오는 경우가 많은데 꼭 그런건 아니고 명령을 문자열로 전달할 경우만 해당됩니다. 보통 변수에 담아서 명령을 실행하는 경우는 해당되는 타입을 써주어야 겠죠.
각 타입은 ADSCODES.H에 정의되어 있는 result type codes들중의 하나입니다.

아래 원을 그리는 명령을 보시면 이해가 잘 되실겁니다.
acedCommand(RTSTR, “circle”, // AutoCAD Command
RTSTR, “5, 5, 0”, // center point
RTSTR, “2,24086”, radius
RTNONE // end of list
);

다른 예를 하나 볼까요.
int docmd()
{
ads_point p1;
ads_real rad;

if( acedCommand(RTSTR, “circle”, RTSTR, “0,0”, RTSTR, “3,3”, 0) != RTNORM)
retrun BAD;

if( acedCommand(RTSTR, “setvar”, RTSTR, “thickness”, RTSHORT, 1, 0) != RTNORM)
retrun BAD;

p1[X] = 1.0; p1[Y] = 1.0; p1[Z] = 3.0;
rad = 4.5;
if( acedCommand(RTSTR, “circle”, RT3DPOINT, p1, rad, 0) != RTNORM)
retrun BAD;

return GOOD;
}
같은 circle 명령이라도 문자열로 점을 전달할수도 있고 정수로도 전달할수 있습니다.

여기서 RTSTR은 뒤에 나오는 실제데이터 유형과 값을 일치하는 Result Type code를 사용해야 합니다. 이것때문에 리습에서 사용하는 (command)루틴과 인자가 틀리게 되므로 주의하셔야 됩니다.

————————————————
참고 Result Type Codes
————————————————
RTNONE No result value
RTREAL Real (floating-point) value
RTPOINT 2D point (X and Y; Z == 0.0)
RTSHORT Short (16-bit) integer
RTANG Angle
RTSTR String
RTENAME Entity name
RTPICKS Selection set name
RTORINT Orientation
RT3DPOINT 3D point (X, Y, and Z)
RTLONG Long (32-bit) integer
RTVOID void (blank) symbol
RTLB List begin (for nested list)
RTLE List end (for nested list)
RTDOTE Dot (for dotted pair)
RTT AutoLISP t (true)
RTNIL AutoLISP nil
RTDXF0 Group code zero for DXF lists(used only with aculBulidList())
——————————————————————————-

=============================================================================================
2.acedCmd() 함수

acedCmd()함수는 acedCommand() 함수와 동등하지만 결과 버터 리스트 형태로 AutoCAD에 값을 전달합니다.
이것은 acedCommand()명령과 비교해서 명령리스트를 구성하는데 복잡한 논리가 필요한 경우에 유용합니다.

원형은 int acedCmd(struct resbuf *rbp); 입니다.
인자에 주목해 주세요. 왠 구조체 포인터가 인자로 들어있네요. 이 resbuf(Result buffer)가 어디서 부터 오냐하면 acutBildList()함수에서 미리 명령리스트를 구성한것을 받아 오는 것입니다. 이렇게 함으로써 명령리스트가 컴파일시 고정되지 않고 런타임시 수정될 수 있는 장점을 가지고 있습니다. 이걸 위해서 이렇게 하는 거죠^.^;
하지만 단점은 실행시 약간 acedCommand() 명령보다 길어집니다.

이 명령을 이해하기 위해서 좀 복잡한 이야기를 하겠습니다. 이 명령이 어떻게 동작하는지를 이해하려면
resbuf구조체와 acutBuildList()함수를 드리고 어떻게 사용하는지 살펴보죠.

==============
resbuf 구조체
===============
result buffer는 직역하면 결과버퍼인데 엔티티나 테이블을 억세스하거나 iteration 또는 acedCommand(), acedCmd(), acutBuildList()등에 사용된다.
쉽게 설명하면 여러분이 AutoCAD에서 마우스로 엔티티들을 선택하였다고 하자.
화면에서는 여러분이 선택한 엔티티들이 점선으로 변화지만 AutoCAD에서는 내부적으로 이것들을 링크드리스트(linked list) 자료구조를 형성하여 담아둡니다.

struct resbuf
{
struct resbuf * rbnext; /* Linked list pointer */
short restype;
union ads_u_val resval;

}
첫번째 rbnext는 연결된 resbuf 구조체를 가리키고 두번째 restype은 실제 저장될 resval 데이타 종류가 어떠한 것인지를 가르키죠..

실제 저장되는 ads_u_val 정의는 아래를 참고하세요.

union ads_u_val
{
ads_real rreal;
ads_real rpoint[3];
short rint;
char * rstring
long rlname;
long rlong;
struct ads_binary rbinary;
}

갑자기 많은 이야기를 해서 복잡해 졌는데 정리하면 위에서 복잡한 논리적 명령리스트라고 구성하는데 이것들을 사용한다고 했는데 대표적인 경우가 사용자가 어떤 대상들을 선택하여 원하는 작업을 수행하고자 할때 resbuf라는 링크드리스트 자료구조를 이용해서 엔티티의 선택같은 논리적 명령리스트를 작성할 수 있다는 이야기 입니다.

그럼 result buffer lists를 사용해서 어떻게 엔티티를 선택하는지 알아보죠.

리습을 사용해본적인 있다면 Entity를 선택하는 명령인 Entsel을 알것이다.
ADS에서도 acedEntSel() 함수를 사용해서 엔티티를 선택할수 있다. 그리고 엔티티의 근원적인 데이타를 얻어내기 위해서 acdbEntGet()

을 사용한다. 물론 Lisp명령으로는 EntGet()이 있다.
이와 같이 거의 대부분의 Lisp명령어와 ARX명령어는 클래스 소속+ 리습함수로 이로어진 경우가 많으니 알아두시길.
여기서 중요한 것은 acdbEntGet() 함수가 리턴값으로 취하는 것이 연결리스트 구조인 rebuf 라는 점이다.

다음은 result buffer에 “Circle” 엔티티 정보가 들어가 있는 예입니다.

——— ——— ———
result ——-> ———-> ———-> ———->
——— ——— ———
-1 0 8
——— ——— ———
ename “circle” “0”
——— ——— ———

——— ——— ———
———-> ———-> ———->
——— ——— ———
10 40 210
——— ——— ———
5.0 0.0
5.0 2.24086 0.0
0.0 1.0
——— ——— ———

DXF code를 이해하고 있다면 그림을 좀더 쉽게 알아볼수 있는데 중간값은 DXF 그룹코드로써
-1은 도면 요소의 이름, 0은 도면 요소 유형 8은 레이어, 10은 1차 점; 선 또는 문자 도면요소, 원의 중심 등의 시작점등을 나타냅니다.

자 그러면 result buffers 포인터 두개를 만들어서 어떻게 사용하는지 보죠.

resbuf *rb1, *tb1;

그리고 acedEntSel()과 acdbEntGet()함수를 사용한후 *rb1이 result buffer을 가졌다면.

tb1 = rb1; tb1은 연결리스트에서 처음을 가르킨다.
이제 *tb1을 이동시키면서 연결리스트를 조회할 수 있는데 다음으로 이동하기 위해서는

tb1 = tb1->rbnext;

우리가 rad변수에 위 그림에 저장된 원의 반경을 담아내려면. 원의 반경 DXF 코드가 40이므로 아래와 같이 할수 있습니다.

ads_real rad;
.
.
.
if (tb->restype == 40)
{
// We have the radius field of the entity
rad = rb1->resval.rreal;
}

ObjectARX에서는 result buffers를 사용하는 방법을 알아보았다. 그러나 이를 너무 깊게 알려고 할 필요는 없다.
이는 ADS 시절에 주로 쓰이는 방법이고 현재 ObjectARX에서는 엔티티 접근과 변경 생성, 심볼테이블접근등에 더 나은 메커니즘을 제공 합니다.
하지만 여전히 ObjectARX에서 엔티티와 심볼, 그리고 위에 살펴본 acedCommand(), acedCmd(), acutBuildList()에 사용되므로 아셔야 겠죠.^.^;

이제 다시 acedCmd()로 돌아가서. acedCmd() 명령을 수행하기 위해서 acutBuildList()함수에서 result buffers 링트드리스트를 먼저 만들어야 한다고 했죠. 그럼 acutBuildList() 함수를 살펴봅시다.

struct resbuf *acutBuildList(int rtype, …) ;

함수수행의 결과로 rsbuf* 를 리턴하고 있다. 그런데 만약 이 함수가 실패한다면 무엇을 리턴할까…
답은 NULL

다음은 acedCmd() 명령을 이용해서 현재 AutoCAD 그리픽 화면에 REDRAW 명령을 수행하는 예입니다.

struct resbuf *cmdlist;
cmdlist = acutBuildList(RTSTR, “redraw”, 0);

if (cmdlist == NULL)
{
acdbFail(“Could not create list\n”);
return BAD;
}

acedCmd(cmdlist);
acutRelRb(cmdlist);

또 아래 예제는 라인을 생성하는 예이다.

resbuf *rb;
// struct resbuf *rb; // if you prefer

if(( rb = acutBuildList(RTSTR, “line”,
RTSTR, “1,1”,
RTSTR, “2,2”,
RTSTR, “”, // ENTER Key
RTNONE)) != NULL)

{
if(acedCmd(rb) = RTNORM)
{
//acedCmd worked
}
else
{
// acedCmd failed
}
else
{
// acedBuildList failed
}
if (rb != NULL)
{
acutRebRb(rb);
}

}

참고로 위에 예제들을 보면 마지막에 acutRelRb() 함수가 보일것이다 이 함수는 result buffer나 링크드리스트 result buffer 메모리를 해제시켜는 기능을 합니다.

자 이제 acedCommand()함수와 acedCmd()함수에 대한 설명을 마칩니다. 잘 이해가 갔는지 모르겠네요.
눈으로만 으로 이해했다고 하지말고 AutoCAD 어떤 명령이라도 한번 위에 명령들을 활용해서 구현해 보시길. 백문이 불여일타라고 100번 보는것 보다 한번 고민하면서 작성해보는게 공부가 됩니다…

그럼 이번 강좌는 여기서 줄이겠습니다. ^.^;;

bookmark_borderVC++ warning C4482: 해결

warning C4482: 비표준 확장이 사용되었습니다. 정규화된 이름에 ‘…’ 열거형을 사용했습니다.

이 경고 메세지는 형식 내부(클래스, 구조체, 네임스페이스 등)에 선언된 이름있는 enum(열거형)을 사용하게 되었을 때 나타나는 증상입니다.

– 해결 방법
잘못된 방법 : classname::enumname::__temp
잘된 방법 : classname::__temp