모듈 7: Examples & Samples - 예제 프로젝트 활용

학습 목표

  • examples/ 폴더의 구조와 역할을 이해한다
  • snippets와 전체 예제 프로젝트의 차이를 설명할 수 있다
  • AI가 예제를 어떻게 활용하는지 이해한다
  • 새 예제를 추가하여 팀 코드베이스를 확장할 수 있다

examples/ 폴더 구조

examples/
├── EGViewportSample/          # 완전한 WPF 프로젝트 (뷰포트 기능 전시)
│   ├── ViewModels/            # 각 기능별 ViewModel
│   │   ├── MainViewModel.cs
│   │   ├── CrossSectionViewModel.cs
│   │   ├── CameraViewModel.cs
│   │   ├── LightViewModel.cs
│   │   └── ... (총 10개)
│   └── Views/                 # XAML 뷰
│
├── HmModelSample/             # 모델 조작 전용 프로젝트
│   └── MainViewModel.cs
│
├── snippets/                  # 단일 기능 코드 조각
│   ├── AddBox.cs
│   ├── AddSphere.cs
│   └── ZoomExtents.cs
│
└── categories/                # 카테고리별 샘플 문서
    └── basic-shapes.md

두 가지 예제 레이어

Layer 1: snippets/ - 단일 기능 코드 조각

특정 HmEG API 하나를 사용하는 최소한의 예제입니다.

// examples/snippets/AddBox.cs
// Category: Basic Shapes, API: AddShapeBox
 
public static void CreateBasicBox(EGViewport viewport)
{
    if (viewport?.RootSpace == null) return;
 
    viewport.RootSpace.AddShapeBox(
        new HmPoint3D(0, 0, 0),  // 중심점
        50,                       // width (X축)
        50,                       // height (Y축)
        50,                       // depth (Z축)
        Colors.Blue               // 색상
    );
}

AI가 이것을 읽으면:

  • AddShapeBox의 정확한 파라미터 순서 학습
  • HmPoint3D 타입으로 좌표 지정하는 패턴 학습
  • null 체크 패턴 학습

Layer 2: EGViewportSample/ - 완전한 MVVM 구현

실제 프로덕션에 가까운 전체 기능 구현입니다.

// examples/EGViewportSample/ViewModels/CrossSectionViewModel.cs
public class CrossSectionViewModel : ViewportViewModel
{
    private double sliderX;
    public double SliderX
    {
        get => sliderX;
        set
        {
            if (Set(ref sliderX, value))
                OnSliderXChanged();
        }
    }
 
    private void OnSliderXChanged()
    {
        var boundingBox = _viewport.GetBoundingBox();
        var x = boundingBox.Minimum.X + boundingBox.Size.X * SliderX;
        var newPlane = new HmPlane3D(new HmPoint3D(x, 0, 0), HmVector3D.AxisX);
 
        if (_viewport.CrossSectionPlane1 == null)
            _viewport.CrossSectionPlane1 = new CrossSectionPlane(newPlane) { ShowIntersection = true };
        else
            _viewport.CrossSectionPlane1.CutPlane = newPlane;
    }
}

AI가 이것을 읽으면:

  • MVVM 패턴의 실제 적용 방법 학습
  • GetBoundingBox() + CrossSectionPlane 연계 패턴 학습
  • 기존 Plane 재사용 vs 신규 생성 분기 패턴 학습

examples/가 AI에게 하는 역할

역할 1: 코드 패턴 제공

사용자: "3D 구 추가해줘"

AI (examples/snippets/AddSphere.cs 참조):
viewport.RootSpace.AddShapeSphere(
    new HmPoint3D(0, 0, 0),
    radius: 25,
    Colors.Green
);
// AddBox.cs와 동일한 패턴 -> 올바른 코드 생성

역할 2: MVVM 구조 가이드

사용자: "카메라 제어 ViewModel 만들어줘"

AI (examples/EGViewportSample/ViewModels/CameraViewModel.cs 참조):
public class CameraViewModel : ViewportViewModel
{
    // 기존 패턴: ObservableObject 상속 대신 ViewportViewModel 상속
    // 기존 패턴: EGViewport를 생성자로 주입
    // 기존 패턴: RaisePropertyChanged 사용
}

역할 3: 통합 패턴 제공

// MainViewModel.cs를 보면:
// EGViewport 하나를 여러 ViewModel이 공유하는 패턴을 학습
public void OnViewportLoadComplete(EGViewport viewport)
{
    CrossSectionViewModel = new(viewport);
    LightViewModel = new(viewport);
    CameraViewModel = new(viewport);
    // ...
}

snippets 파일 작성 규칙

// ============================================================================
// HmEG Sample: [기능명] (ID: [번호])
// Category: [카테고리]
// API: [주요 API명]
// ============================================================================
 
// 1. 헤더 주석: 카테고리, ID, API 명시
// 2. 네임스페이스: HmEGSamples (일관성)
// 3. 클래스: static - 인스턴스 불필요
// 4. 메서드: 입력은 EGViewport만
// 5. null 체크: viewport?.RootSpace == null 패턴
// 6. 마지막: Usage Examples 주석

좋은 snippet 예시

// ============================================================================
// HmEG Sample: Camera Zoom Extents (ID: 20)
// Category: Camera Control
// API: ZoomExtents
// ============================================================================
 
using HmEG;
 
namespace HmEGSamples
{
    public static class ZoomExtentsSample
    {
        /// <summary>
        /// 모든 오브젝트가 보이도록 카메라 자동 조정
        /// </summary>
        public static void FitAll(EGViewport viewport)
        {
            if (viewport == null) return;
 
            viewport.ZoomExtents();
        }
 
        /// <summary>
        /// 특정 오브젝트 기준으로 카메라 조정
        /// </summary>
        public static void FitToObject(EGViewport viewport, HmModel model)
        {
            if (viewport == null || model == null) return;
 
            viewport.ZoomExtents(model.BoundingBox);
        }
    }
}
 
// ============================================================================
// Usage:
// ZoomExtentsSample.FitAll(viewport);
// ZoomExtentsSample.FitToObject(viewport, selectedModel);

data/HmEGSample/ - 사내 공식 샘플

회사 내 HmEG 엔진 팀이 제공하는 공식 샘플 프로젝트들입니다:

data/HmEGSample/
├── ACIColoringSample/          # AutoCAD 색상 체계 적용
├── AllocateViewerSample/       # 뷰어 동적 할당
├── BillboardSample/            # 빌보드 객체 (항상 카메라를 향함)
├── BlockSample/                # 블록 참조 객체
├── CameraAnimationSample/      # 카메라 애니메이션
├── ContourMesh_CSD/            # 등고선 메시 (토목 특화)
├── DimensionSample/            # 치수선
├── LayerSample/                # 레이어 관리
├── LegendSample/               # 범례
├── ModelKeyframeAnimationSample/ # 키프레임 애니메이션
└── ... (총 30+ 샘플)

토목 엔지니어 관련 샘플

샘플설명주요 API
ContourMesh_CSD등고선 메시ContourMeshData
DimensionSample치수선/치수 표시DimensionEntity
LayerSample레이어 제어LayerTable
LegendSample범례 표시LegendControl
ACIColoringSampleACI 색상 체계ACIColor

generate-prp에서 examples 활용

/generate-prp PRPs/INITIAL.md

generate-prp가 자동으로 수행:

  1. examples/ 디렉토리 전체 스캔
  2. 요청된 기능과 관련된 기존 예제 식별
  3. PRP에 참조 파일 목록 포함
# 생성된 PRP 내 예제 참조 섹션
## All Needed Context
 
### Code Patterns to Follow
- file: examples/EGViewportSample/ViewModels/CrossSectionViewModel.cs
  why: CrossSectionPlane 생성 및 BoundingBox 기반 offset 계산 패턴
 
- file: examples/EGViewportSample/ViewModels/MainViewModel.cs
  why: ViewportViewModel 초기화 및 자식 ViewModel 연결 패턴
 
- file: examples/snippets/AddBox.cs
  why: RootSpace.AddShape* 계열 API 호출 패턴

examples 폴더 확장 가이드

팀원이 새 패턴을 발견했을 때:

Step 1: snippet 추가

// examples/snippets/ApplyTransparency.cs
 
// ============================================================================
// HmEG Sample: Apply Transparency (ID: 30)
// Category: Materials
// API: HmModel.Transparency
// ============================================================================
 
public static void SetModelTransparency(HmModel model, float transparency)
{
    // transparency: 0.0 (불투명) ~ 1.0 (완전 투명)
    if (model == null) return;
    model.Transparency = Math.Clamp(transparency, 0f, 1f);
}

Step 2: categories 문서 업데이트

// examples/categories/materials-rendering.md에 추가
 
| ID | Name | API | 난이도 |
|----|------|-----|--------|
| 30 | Apply Transparency | HmModel.Transparency | ⭐ |

Step 3: hmeg-api Skill 코퍼스 업데이트 (필요시)

새 API가 HmEG.md에 없다면:

python setup_store.py upload --path data/HmEG_transparency.md

예제 활용 실습

실습 1: 기존 패턴으로 새 기능 구현

CrossSectionViewModel.cs를 참조하여 HitTest 기능 구현하기:

참조: examples/EGViewportSample/ViewModels/HitTestViewModel.cs

패턴 확인:
1. ViewportViewModel 상속
2. EGViewport.RayCast 또는 HitTest API 사용
3. 선택된 모델 강조 표시
4. ICommand 패턴으로 UI 바인딩

실습 2: snippet 작성

다음 기능의 snippet을 작성해보세요:

  • 기능: 모든 모델 선택 해제
  • API: [API 조회 필요: EGViewport.ClearSelection]
  • 카테고리: Selection Control

핵심 정리

  • examples/snippets/: 단일 API 사용법 - AI의 패턴 학습 자료
  • examples/EGViewportSample/: 완전한 MVVM 구현 - AI의 구조 학습 자료
  • data/HmEGSample/: 공식 사내 샘플 - 고급 기능 참조
  • generate-prp가 자동으로 관련 예제를 찾아 PRP에 포함
  • 팀이 좋은 패턴을 발견하면 즉시 snippet으로 추가 AI가 다음 기회에 활용
  • snippets는 짧고 명확하게 + 헤더 주석으로 검색 가능하게 작성