ObjectARX 강좌

[ObjectARX] 11. Overrule

matesoft 2026. 5. 31. 10:20
반응형

개요

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