개요
모든 엔티티는 자신을 그리기 위해 AcGi 라이브러리에 포한된 폴리라인, 원, 호와 같은 그래픽 기본 요소를 호출 한다. AcDbEntity에서 파생된 모든 클래스는 자신을 그리는 데 사용하는 그래픽 시스템(GS)에서 마커를 연결 할 수 있다.
AcDb3dSolid에서 파생된 솔리드 객체는 정점(Vertex), 모서리(Edge) 및 면(Face)으로 구성된다. 이러한 각 요소는 GS 마커로 식별 할 수 있다. 엔티티 클래스 생성자는 엔티티에 가장 적합한 위치를 고려하여 GS 마커를 삽입 할 위치를 결정한다. 예를 들어, Box는 상자를 그리는 데 사용된 각 선에 대해 GS 마커를 생성하고, 원 기둥은 윗면, 아랫면 및 바깥쪽 면에 하나씩, 총 세 개의 GS 마커를 생성한다.
GS Marker 란
AcGiSubEntityTraits
AcGiWorldDraw
AcGiViewportDraw
과정에서 그래픽 primitive에 부여하는 정수 ID이다.
엔티티는 정점, 모서리 또는 면과 같은 하위 엔티티로 구성된다. 현재 하위 엔티티를 지원하는 엔티티는 다음과 같다.
- Bodies
- Regions
- Solids
- Mlines
- Polyline
- Custom Entity
특정 GS 마커와 연결된 하위 엔티티의 경로를 얻으려면 getSubentPathsAtGsMarker() 함수를 사용하면 된다. 하나의 마커에 둘 이상의 하위 엔티티가 연결 될 수 있다. 예를 들어, 아래 그림과 같은 Box의 경우 마커 4는 상자의 앞쪽 아래 모서리를 나타낸다.
이 마커와 연결된 정점을 요청하면 이 선의 양 끝점을 이루는 두 정점이 반환된다. 또한 이 마커와 연결된 모서리를 요청하면 선이라는 하나의 엔티티가 반환되고 이 마커와 연결된 면을 요청하면 Box의 앞면과 아랫면에 대한 데이터가 반환된다.

주의:
오토캐드의 2D 그래픽 시스템은 하위 요소가 여러 레이어에 있는 도면 객체에 선택 마커를 사용하는 것을 지원하지 않는다. 도면 객체에 선택 마커를 사용하려면 해당 객체의 모든 그래픽 하위 요소는 단일 레이어에 있어야 한다. 객체의 하위 요소에 여러 레이어를 사용해야 하는 경우에는 선택 마커를 사용해서는 않된다.
GS Marker의 구성 성분
- Vertex (정점)
- Edge (모서리)
- Face (면)
GS 마커 용도
GS 마커는 주로 엔티티의 객체 스냅 구현에 유용하다. 객체 스냅을 위해 엔티티가 선택되면, 선택된 엔티티 부분의 GS 마커가 반환되어 반환될 점을 지정한다.
GS 마커는 acedSSGet() 및 acedSSNameX() 함수와 함께 사용하여 애플리케이션에서 사용자 정의 엔티티 객체의 임의 영역을 펀집하거나 조작 할 수 있도록 한다. 사용자 정의 객체(커스텀 엔티티)는 마커를 사용하여 엔티티의 임의 영역 집합을 식별할 수 있게 한다. AcGiSubEntityTraits 함수의 setSelectionMarker()를 호출하고 엔티티 객체에 고유한 마커 번호(0이 아닌)를 지정하여 식별한다.
Custom Entity의 GS Marker
커스텀 엔티티를 만들기 위해서는 필수적으로 Overriding 되어야 하는 함수들이 있다. 그 중에 커스텀 엔티티에서 GS 마커를 붙이고 싶다면 반드시 다음 3개의 함수를 재정의 해서 구현 해야한다.
- getSubentPathsAtGsMarker()
- getGsMarkerAtSubentPath()
- subentPtr()
GS 마커를 활용한 Subentity의 하이라이트
선택한 엔티티의 하위 엔티티 경로를 얻었다면 이 과정에서 가장 어려운 부분은 끝났다. 다음 예제 코드는 엔티티를 선택하고, 하위 엔티티 경로를 얻고, GS 마커와 연결된 하위 엔티티를 강조 표시하는 단계를 보여준다.
virtual AcDbEntity*
AcDbEntity::subentPtr(const AcDbFullSubentPath& id) const;
이 함수는 지정된 Path의 하위 엔티티의 복사본에 대한 포인터를 반환하고 이 포인터를 데이터베이스에 추가 할 수 있다.
AcDbEntity의 새로운 하위 클래스를 생성 할 때는 getetSubentPathsAtGsMarker(), getGsMarkersAtSubentPath(), subentPtr() 함수에 대한 자체 구현을 제공해야 한다. 이를 위해 각각 해당 가상 함수인 subGetSubentPathsAtGsMarker(), subGetGsMarkersAtSubentPath(), subSubentPtr()를 재정의해야 한다. 그러나 highlight() 함수는 AcDbEntity 수준에서 구현되므로 일반적으로 재정의할 필요가 없다. 하지만 재정의하는 경우, 이 함수의 새로운 구현은 하이라이팅을 수행하기 위해 AcDbEntity::highlight()를 호출해야 한다.
다음 함수는 getObjectAndGsMarker() 함수를 호출하여 솔리드의 객체 ID와 해당 GS 마커를 가져온다. 그런 다음 highlightEdge(), highlightFaces(), highlightAll() 함수를 호출하여 선택된 모서리, 해당 모서리를 둘러싼 모든 면, 그리고 마지막으로 전체 솔리드를 강조 표시한다.
highlightTest()
{
AcDbObjectId objId;
int marker;
if (getObjectAndGsMarker(objId, marker) != Acad::eOk)
return;
highlightEdge(objId, marker);
highlightFaces(objId, marker);
highlightAll(objId);
}
다음 함수는 acedSSGet() 함수를 사용하여 사용자가 단일 엔티티를 선택할 수 있도록 한다. 그런 다음 선택된 엔티티 집합을 acedSSNameX() 함수에 전달하여 GS 마커를 가져온다. 마지막으로, 선택된 엔티티 집합의 엔티티 이름을 사용하여 선택된 엔티티의 객체 ID를 얻는 코드이다.
Acad::ErrorStatus
getObjectAndGsMarker(AcDbObjectId& objId, int& marker)
{
ads_name sset;
if (acedSSGet("_:S", NULL, NULL, NULL, sset) != RTNORM) {
acutPrintf("\nacedSSGet has failed");
return Acad::eInvalidAdsName;
}
// Get the entity from the selection set and its
// subentity ID. This code assumes that the user
// selected only one item, a solid.
//
struct resbuf *pRb;
if (acedSSNameX(&pRb, sset, 0) != RTNORM) {
acedSSFree(sset);
return Acad::eAmbiguousOutput;
}
acedSSFree(sset);
// Walk the list to the third item, which is the selected
// entity's entity name.
//
struct resbuf *pTemp;
int i;
for (i=1, pTemp = pRb;i<3;i++, pTemp = pTemp->rbnext)
{ ; }
ads_name ename;
ads_name_set(pTemp->resval.rlname, ename);
// Move on to the fourth list element, which is the gsmarker.
//
pTemp = pTemp->rbnext;
marker = pTemp->resval.rint;
acutRelRb(pRb);
acdbGetObjectId(objId, ename);
return Acad::eOk;
}
다음 함수는 객체 ID와 gsmarker를 인수로 받는다. 객체를 열고, GS 마커를 사용하여 AcDbFullSubentIdPath를 가져온 다음, 이 경로를 사용하여 객체를 선택하는 데 사용된 모서리를 강조 표시하거나 강조 표시 해제한다.
다음으로, 객체의 subentPtr() 함수를 사용하여 모서리의 복사본을 가져오고 이 복사본을 데이터베이스에 추가한다. 마지막으로 객체를 닫는다.
하위 엔티티의 복사본이 새로운 AcDbLine 엔티티로 데이터베이스에 추가되었으므로, 명령이 종료된 후에도 도면 편집기에 계속 표시되며 AutoCAD LIST 명령에 보고된다.
void
highlightEdge(const AcDbObjectId& objId, const int marker)
{
char dummy[133]; // space for acedGetString pauses below
AcDbEntity *pEnt;
acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
// Get the subentity ID for the edge that is picked
//
AcGePoint3d pickpnt;
AcGeMatrix3d xform;
int numIds;
AcDbFullSubentPath *subentIds;
pEnt->getSubentPathsAtGsMarker(AcDb::kEdgeSubentType,
marker, pickpnt, xform, numIds, subentIds);
// At this point the subentId's variable contains the
// address of an array of AcDbFullSubentPath objects.
// The array should be one element long, so the picked
// edge's AcDbFullSubentPath is in subentIds[0].
//
// For objects with no edges (such as a sphere), the
// code to highlight an edge is meaningless and must
// be skipped.
//
if (numIds > 0) {
// Highlight the edge.
//
pEnt->highlight(subentIds[0]);
// Pause to let user see the effect.
//
acedGetString(0, "\npress <RETURN> to continue...",
dummy);
// Unhighlight the picked edge.
//
pEnt->unhighlight(subentIds[0]);
// Get a copy of the edge, and add it to the database.
//
AcDbEntity *pEntCpy = pEnt->subentPtr(subentIds[0]);
AcDbObjectId objId;
addToModelSpace(objId, pEntCpy);
}
delete []subentIds;
pEnt->close();
}
다음 함수는 객체 ID와 GS 마커를 인수로 받는다. 객체를 열고, GS 마커를 사용하여 AcDbFullSubentIdPath를 가져온 다음, 이 경로를 사용하여 객체를 선택하는 데 사용된 모서리를 공유하는 면을 강조 표시하거나 강조 표시 해제한다. 그런 다음 객체를 닫는다.
highlightFaces(const AcDbObjectId& objId, const int marker)
{
char dummy[133];
AcDbEntity *pEnt;
acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
// Get the subentIds for the faces.
//
AcGePoint3d pickpnt;
AcGeMatrix3d xform;
int numIds;
AcDbFullSubentPath *subentIds;
pEnt->getSubentPathsAtGsMarker(AcDb::kFaceSubentType,
marker, pickpnt, xform, numIds, subentIds);
// Walk the subentIds list, highlighting each face subentity.
//
for (int i = 0;i < numIds; i++) {
pEnt->highlight(subentIds[i]); // Highlight face.
// Pause to let the user see the effect.
//
acedGetString(0, "\npress <RETURN> to continue...",
dummy);
pEnt->unhighlight(subentIds[i]);
}
delete []subentIds;
pEnt->close();
}
void highlightAll(const AcDbObjectId& objId)
{
char dummy[133];
AcDbEntity *pEnt;
acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
// Highlight the whole solid.
//
pEnt->highlight();
// Pause to let user see the effect.
//
acedGetString(0, "\npress <RETURN> to continue...",
dummy);
pEnt->unhighlight();
pEnt->close();
}
Acad::ErrorStatus addToModelSpace(AcDbObjectId &objId, AcDbEntity* pEntity)
{
AcDbBlockTable *pBlockTable;
AcDbBlockTableRecord *pSpaceRecord;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);
pBlockTable->getAt(ACDB_MODEL_SPACE, pSpaceRecord,
AcDb::kForWrite);
pSpaceRecord->appendAcDbEntity(objId, pEntity);
pBlockTable->close();
pEntity->close();
pSpaceRecord->close();
return Acad::eOk;
}
intersectWidth()의 GS 마커
virtual Acad::ErrorStatus
AcDbEntity::intersectWith(
const AcDbEntity* ent,
AcDb::Intersect intType,
AcGePoint3dArray& points,
int thisGsMarker = 0,
int otherGsMarker = 0) const;
intersectWith() 함수의 두 버전 모두 선택적으로 GS 마커를 제공하여 함수의 성능을 최적화 할 수 있다. 엔티티의 intersectWith() 함수가 GS 마커 사용을 구현한 경우, GS 마커를 제공하면 교차 영역을 특정하고 테스트 속도를 높일 수 있다. 예를 들어, 다음 그림에서 사용자가 다각형의 한 변을 선택하고 해당 변에 대한 GS 마커를 전달하면 다각형의 나머지 다섯 변을 테스트할 필요가 없어진다.

'ObjectARX 강좌' 카테고리의 다른 글
| [ObjectARX] 7. Selection Set (1) | 2026.03.28 |
|---|---|
| [ObjectARX] 6. Dictionary (0) | 2026.03.27 |
| [ObjectARX] 4. Symbol Table (0) | 2026.03.22 |
| [ObjectARX] 3. Entity (0) | 2026.03.21 |
| [ObjectARX] 2. Database (0) | 2026.03.19 |