개요
ObjectARX 플러그인에서 기존 AutoCAD 엔티티의 동작을 바꾸는 방법은 크게 두 가지입니다. Protocol Extension(PE) 은 클래스에 새 기능을 추가하고, Overrule 은 클래스의 기존 동작을 런타임에 가로채서 교체합니다. 즉, 커스텀 엔티티를 만들지 않고도 기존 클래스(AcDbLine, AcDbCircle 등)의 동작을 런타임에 바꿀 수 있습니다.
AutoCAD 내부 호출 → Overrule 체인 → Overrule::worldDraw base 호출 → 원래 subWorldDraw
| 클래스 | 가로채는 기능 | 관련 헤더 |
| AcGiDrawableOverrule | 그리기 (worldDraw, viewportDraw) | drawable.h |
| AcDbGripOverrule | 그립 포인트 | dbentityoverrule.h |
| AcDbOsnapOverrule | 스냅 포인트 | dbentityoverrule.h |
| AcDbGeometryOverrule | 교차/범위 계산 | dbentityoverrule.h |
| AcDbTransformOverrule | 이동 / 회전 / Explode | dbentityoverrule.h |
| AcDbVisibilityOverrule | 가시성 | dbentityoverrule.h |
| AcDbObjectOverrule | open/close/clone | dbentityoverrule.h |
| AcDbPropertiesOverrule | LIST 명령 출력 등 | dbentityoverrule.h |
등록 / 해제 API (rxoverrule.h)
// 등록: pClass 타입 객체에 대해 pOverrule 활성화
AcRxOverrule::addOverrule(AcRxClass* pClass, AcRxOverrule* pOverrule, bool bAddAtLast = false);
// 해제
AcRxOverrule::removeOverrule(AcRxClass* pClass, AcRxOverrule* pOverrule);
// 전역 스위치 (false면 등록된 모든 overrule 일시 정지)
AcRxOverrule::setIsOverruling(bool bIsOverruling);
// 쿼리
bool AcRxOverrule::hasOverrule(const AcRxObject* pSubject, AcRxClass* pOverruleClass);
Protocol Extension과의 차이점
| 항목 | Protoco Extension | Overrule |
| 목적 | 기존 클래스에 새 메서드 추가 | 기존 클래스의 동작 교체/확장 |
| 대상 메서드 | 존재하지 않던 새 기능 | 이미 있는 worldDraw, getGripPoints 등 |
| 호출 방식 | ACRX_X_CALL(pEnt, MyPE)->myMethod(pEnt) 명시적 호출 | AutoCAD 내부가 자동으로 Overrule 체인 통과 |
| ACRX 매크로 | 필수 (ACRX_DECLARE_MEMBERS 등) | 불필요 (단순 C++ 상속) |
| 원본 메서드 | 관계없음 (새 메서드) | AcGiDrawableOverrule::worldDraw() 호출로 원본 위임 |
| 스택/순서 | 클래스당 1개만 연결 | 클래스당 여러 개 순서대로 체인 |
| 전역 on/off | 없음 | setIsOverruling() 으로 일괄 제어 |
| 사용 시점 | 새 커맨드가 엔티티별로 다른 연산 수행 시 | 기존 AutoCAD 동작을 투명하게 수정할 때 |
비유로 이해하기
Protocol Extension = "확장 슬롯" , AcDbLine에 "온도 계산"이라는 새 슬롯을 달고, 내 코드에서 명시적으로 꺼내 씀.
Overrule = "미들웨어", AcDbLine::worldDraw() 파이프라인에 끼어들어 AutoCAD가 선을 그릴 때마다 자동으로 내 코드가 실행됨.
사용 예 - LINE 명령 드래그 중 길이 실시간 표시

Line 명령으로 시작점을 찍고 커서를 움직이는 동안, 미리보기 선 위에 L=123.45 형태의 길이를 실시간으로 표시하는 예제입니다. AcGiDrawableOverrule을 AcDbLine에 등록해서 worldDraw를 가로 채는 방식입니다.
LineLengthOverrule.h
#pragma once
#include "StdAfx.h"
#include "drawable.h" // AcGiDrawableOverrule
class CLineLengthOverrule : public AcGiDrawableOverrule
{
public:
// 이 Overrule이 적용될 대상을 필터링
virtual bool isApplicable(const AcRxObject* pSubject) const override;
// 핵심: 그리기 가로채기
virtual Adesk::Boolean worldDraw(
AcGiDrawable* pSubject,
AcGiWorldDraw* wd) override;
};
LineLengthOverrule.cpp
#include "StdAfx.h"
#include "LineLengthOverrule.h"
#include <tchar.h>
bool CLineLengthOverrule::isApplicable(const AcRxObject* pSubject) const
{
// AcDbLine 또는 그 파생 클래스에만 적용
return AcDbLine::cast(pSubject) != nullptr;
}
Adesk::Boolean CLineLengthOverrule::worldDraw(
AcGiDrawable* pSubject,
AcGiWorldDraw* wd)
{
// ① 원래 선 그리기 위임 (이걸 빠뜨리면 선이 사라짐)
Adesk::Boolean result = AcGiDrawableOverrule::worldDraw(pSubject, wd);
AcDbLine* pLine = AcDbLine::cast(pSubject);
if (!pLine)
return result;
AcGePoint3d ptStart = pLine->startPoint();
AcGePoint3d ptEnd = pLine->endPoint();
double len = ptStart.distanceTo(ptEnd);
if (len < 1e-10)
return result; // 길이 0이면 텍스트 표시 불필요
// ② 텍스트 위치: 선의 중간점
AcGePoint3d ptMid = ptStart + (ptEnd - ptStart) * 0.5;
// ③ 텍스트 방향: 선 방향
AcGeVector3d vDir = (ptEnd - ptStart).normalize();
// ④ 법선 벡터 (텍스트가 놓일 평면의 법선)
AcGeVector3d vNormal = pLine->normal();
// ⑤ 텍스트 높이: 선 길이의 3% (줌에 따라 비례)
double textHeight = len * 0.03;
// ⑥ 길이 문자열 포맷
ACHAR buf[64];
_stprintf_s(buf, _countof(buf), _T("L=%.2f"), len);
// ⑦ 텍스트 그리기
// text(위치, 법선, 방향, 높이, 폭비율, 기울기, 문자열)
wd->geometry().text(ptMid, vNormal, vDir, textHeight, 1.0, 0.0, buf);
return result;
}
등록 및 해제
acrxEntryPoint.cpp - 등록/해제
virtual AcRx::AppRetCode On_kInitAppMsg(void* pkt) override
{
AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
// AcDbLine의 worldDraw를 Overrule로 가로채기 시작
AcRxOverrule::addOverrule(
AcDbLine::desc(), // 대상 클래스
&g_lineLengthOverrule, // 내 Overrule 인스턴스
false // false = 체인 앞쪽에 삽입 (우선순위 높음)
);
AcRxOverrule::setIsOverruling(true);
return retCode;
}
virtual AcRx::AppRetCode On_kUnloadAppMsg(void* pkt) override
{
// 반드시 해제 (안 하면 AutoCAD 크래시)
AcRxOverrule::removeOverrule(AcDbLine::desc(), &g_lineLengthOverrule);
return AcRxArxApp::On_kUnloadAppMsg(pkt);
}
정리
Overrule을 언제 쓰나
- AutoCAD 내장 엔티티(AcDbLine, AcDbCircle 등)의 그리기·스냅·그립 동작을 수정할 때
- 커스텀 엔티티 없이 기존 엔티티에 시각적 장식을 추가할 때 (치수 주석, 색상 강조 등)
- setIsOverruling(false) 한 줄로 일시 비활성화가 필요할 때
반드시 지켜야 할 규칙
| 규칙 | 이유 |
| On_kUnloadAppMsg에서 반드시 removeOverrule | 미해제 시 AutoCAD 크래시 |
| worldDraw 안에서 반드시 base 클래스 worldDraw 호출 | 원본 지우기 방지 |
| 전역/static 인스턴스 사용 | addOverrule은 포인터만 저장, 소유권 이전 없음 |
| 여러 Overrule 스택 시 순서 인식 | bAddAtLast 파라미터로 체인 위치 제어 |
Protocol Extension vs Overrule 선택 기준
새 기능 추가 (기존 메서드와 무관)?
→ Protocol Extension
기존 draw/snap/grip 동작 교체·보강?
→ Overrule
'ObjectARX 강좌' 카테고리의 다른 글
| [ObjectARX] 10. Binary Chunk (0) | 2026.04.10 |
|---|---|
| [ObjectARX] 9. Demand Loading (1) | 2026.04.07 |
| [ObjectARX] 8. Proxy (0) | 2026.04.06 |
| [ObjectARX] 7. Selection Set (1) | 2026.03.28 |
| [ObjectARX] 6. Dictionary (0) | 2026.03.27 |