# Alan Seçim (Selection Trap) Sistemi — Uygulama Spec'i

fikatia-local (native C++23 / Vulkan / ImGui) için CATIA V5 tarzı **alan seçimi**
(selection trap / marquee). Boş alana sol-tık basılı tut + sürükle → ekran-uzayı
kare/poligon/fırça izi seçim bölgesi. Kullanıcı isteği: CATIA'daki **bütün trap
çeşitleri** kurulacak.

> Bu belge doğrudan implementasyon ajanına verilebilir netliktedir. Kod yazılmadan
> önce §7 "Uygulama Adımları" sırasıyla izlenmeli.

---

## 0. Araştırma özeti

**CATIA V5 Select Toolbar** yedi araç barındırır (kaynak: catiadoc / catiahelp /
3dcs blog — §8): Select, Selection Trap (dikdörtgen), Intersecting Trap, Polygon
Trap, Paint Stroke Selection, Outside Trap, Outside Intersecting Trap. Varsayılan
davranış: sol-drag = **Rectangle Trap** (yalnız tamamen-içinde). Modlar dışlayıcı
(aynı anda tek mod aktif); mod değişince öncekini kapatır. Çoklu seçim `Ctrl+tık`.

**fikoyt web** (fikoyt-sistem `.../fiko-three-js/`): kutu/marquee alan seçimi
**YOK**. `FikoSecililer.ts`'te `THREE.Frustum` yalnız görünürlük culling'i için
kullanılıyor (`_frustum.setFromProjectionMatrix` → `containsPoint` ile ekran-dışı
nesneleri atlama; satır 79, 5084-5131, 6228-6256). Referans alınacak bir marquee
implementasyonu yok — sıfırdan kurulacak. (Not: three.js `SelectionBox` helper'ı da
projede kullanılmıyor.)

**Native mevcut altyapı** (incelendi):
- `motor/render/secim_gpu.{hpp,cpp}` — GPU pick: kimlikler `R32G32_UINT` tam-çözünürlük
  görsele (`kimlikGorsel_`) çizilir, **ama yalnız imleç 1×1 pikseli** scissor'lanıp
  (`gecisBasla`) tek piksel geri okunur (`gecisBitir` → `vkCmdCopyImageToBuffer`
  `imageExtent={1,1,1}`). **Kritik bulgu: tam-çözünürlük ID görseli zaten mevcut**;
  bölgesel okuma için scissor'ı genişletip dikdörtgen bir bölge kopyalamak yeterli.
- `motor/sahne/secim_sistemi.{hpp,cpp}` — `SecimSistemi`: filtre bayrakları
  (`fYuz/fKenar/fNokta/fGovde`, public), `pickGecisiKaydet` (açık türleri tek geçişte
  çizer), `hoverCozumle` (1 kare gecikmeli pick sonucu → `sahne.vurgu`), `tikla(coklu)`
  (vurgu türüne göre `SecimKip` ayarla + `sahne.sec`).
- `motor/sahne/sahne.hpp` — `Sahne::sec(SecimOge, coklu)`, `secimTemizle()`,
  `seciliMi`, `secililer()`, `kip()/kipAyarla()`, `SecimKip{Govde,Yuz,Kenar,Nokta}`.
  Her `Dugum`: `dunyaMerkez()`, `dunyaYaricap()`, `yerelSinir` (Aabbf), `cpuKonum`/
  `cpuIndeks` (CPU üçgen kopyası — yerel uzay), `matris()`, `agacGorunur(kimlik)`.
- `uygulama/fikocad/main.cpp` — fare dispatch (satır 2130-2416). **Kritik bulgu:
  sol-drag şu an kamerayı DÖNDÜRMÜYOR.** Kamera: Orta+Sağ(6)=döndür, Sol+Sağ(3)=zoom,
  Orta(4)=pan, veya A/S/D+drag. Boş-alan sol-drag slotu **boş** → trap için ideal.
  `fare.kameraKullandi` bir sürüklemenin kamerayı oynatıp oynatmadığını izler; sol-tık
  seçimi yalnız `kayma<6px && sure<0.45s` ise ateşlenir (drag zaten tık'tan ayrı).
- `ekrana(worldPoint, ImVec2&)` lambda (main.cpp ~1484): dünya→ekran projeksiyonu
  (`vp` = `kamera.izdusum(enBoy)*kamera.gorunum()`, NDC→viewport pikseli, w<=0 clip).
  AABB/köşe ön-eleme ve CPU tam-içinde testi bununla kurulur.
- `motor/cekirdek/olay.hpp` — olay p/s. Enum `OlayTuru` **SAYAC'tan önce** genişletilir;
  POD struct + `static constexpr tur()`. Yüksek frekans olmayan → diske yazılır
  (kalıcı). Makro/eklenti erişimi olaya abonelikle bedavaya gelir (mimari anayasa).

---

## 1. Trap çeşitleri tablosu

| # | Tip | Bölge şekli | Seçim davranışı | CATIA erişimi | Native öncelik |
|---|-----|-------------|-----------------|---------------|----------------|
| 1 | **Dikdörtgen (İçinde)** `Rectangle` | Kare sürükle | Aday **tamamen** bölge içindeyse seç | Varsayılan drag | P0 — ilk kurulacak |
| 2 | **Kesen Dikdörtgen** `Intersecting` | Kare sürükle | Bölgeye **değen veya içindeki** seç | Intersecting Trap düğmesi | P0 |
| 3 | **Poligon** `Polygon` | Çoklu tık + çift-tık/Enter kapat | Tamamen poligon içindeyse seç | Polygon Trap düğmesi | P1 |
| 4 | **Fırça İzi** `PaintStroke` | Serbest sürükle (çizgi izi) | İz **çizgisinin geçtiği** adayları seç (kesen mantığı) | Paint Stroke düğmesi | P1 |
| 5 | **Dışında (İçinde)** `OutsideRectangle` | Kare sürükle | Aday tamamen bölge **dışındaysa** seç (tersine) | Outside Trap düğmesi | P2 |
| 6 | **Dışında Kesen** `OutsideIntersecting` | Kare sürükle | Bölgeye **değmeyen** (tamamen dışında) seç | Outside Intersecting düğmesi | P2 |

**Ortak modifier'lar (tüm tipler):** varsayılan = mevcut seçimi değiştir (replace);
`Ctrl` = seçime **ekle**; `Shift` = seçimden **çıkar** (CATIA'da çıkarma Ctrl+ikinci
trap ile yapılır; native'de Shift daha nettir — kullanıcı isteği: Ctrl=ekle/Shift=çıkar);
`ESC` = sürükleme/poligon iptal. Nokta türü için (CATIA kuralı): **noktanın orta/merkez
noktası** bölge içindeyse sayılır (kesen modda da) — native'de nokta düğümü tek merkez
olarak test edilir.

**Aktif seçim kipi trap'e uygulanır:** `SecimKip` (Govde/Yüz/Kenar/Nokta) ne ise trap
o türde adayları toplar (mevcut `secimSis.f*` filtreleri). Yani "Yüz kipi + kesen trap"
= bölgeye değen tüm yüzleri seçer.

---

## 2. Native mimari — `motor/sahne/alan_secim.{hpp,cpp}`

Yeni sınıf `AlanSecim`. **Salt ekran-uzayı geometrisi + aday testi mantığı** burada;
GPU bölgesel okuma `SecimGpu`'ya küçük bir ek API ile eklenir; UI çizimi + girdi
main.cpp'de bağlanır (mevcut mimari deseni: `SecimSistemi` cephesine yakın durur).

### 2.1 Trap tipi + durum enum'ları

```cpp
// alan_secim.hpp
namespace fiko {

enum class TrapTip : u8 {
  Dikdortgen, KesenDikdortgen, Poligon, FircaIzi, DisRadikdortgen, DisKesen
};
// Kolay döngü (Görünüm toolbar'ı sırayla döner)
inline TrapTip sonrakiTrap(TrapTip t) { /* Dikdortgen→...→DisKesen→Dikdortgen */ }

enum class TrapModifier : u8 { Degistir, Ekle, Cikar };  // replace / Ctrl / Shift

class Sahne; class SecimGpu; class OlayGunlugu;

class AlanSecim {
public:
  AlanSecim(Sahne& sahne, SecimGpu& gpu, OlayGunlugu& olaylar)
    : sahne_(sahne), gpu_(gpu), olaylar_(olaylar) {}

  TrapTip tip = TrapTip::Dikdortgen;   // aktif trap (UI'dan bağlanır, public)

  // --- Sürükleme yaşam döngüsü (main.cpp fare akışından çağrılır) ---
  void basla(f32 ekranX, f32 ekranY);           // sol-basış boş alanda
  void guncelle(f32 ekranX, f32 ekranY);        // sürükleme (dikdörtgen köşe / iz noktası biriktir)
  void poligonNokta(f32 x, f32 y);              // Poligon: her sol-tık bir köşe
  void bitir(const Mat4f& vp, f32 vpX, f32 vpY, // sol-bırakış → adayları hesapla + uygula
             f32 vpG, f32 vpY_, TrapModifier m, VkCommandBuffer* kb = nullptr);
  void iptal();                                  // ESC

  bool aktifMi() const { return aktif_; }
  bool poligonKipMi() const { return tip == TrapTip::Poligon; }

  // --- UI çizimi (ImDrawList) — main.cpp overlay'inden çağrılır ---
  void ciz(ImDrawList* dl, f32 vpMinX, f32 vpMinY) const;

private:
  Sahne& sahne_; SecimGpu& gpu_; OlayGunlugu& olaylar_;
  bool aktif_ = false;
  ImVec2 bas_{}, son_{};                 // dikdörtgen köşeleri (ekran-yerel)
  std::vector<ImVec2> iz_;               // FircaIzi / Poligon köşeleri
};

}
```

### 2.2 Aday testi — iki katman

Trap'in "adayları" aktif `SecimKip`'e göre değişir: Gövde/Yüz/Kenar/Nokta. İki
katmanlı strateji (hız + hassasiyet):

**Katman A — hızlı gövde-AABB ekran ön-eleme (CPU, her zaman):**
Her görünür düğüm için `dunyaMerkez()`/`dunyaYaricap()` veya `yerelSinir` 8 köşesini
`ekrana()` ile projekte et → düğümün ekran-uzayı AABB'si. Trap dikdörtgeniyle
kesişmeyen düğümü tamamen ele (kesen ve içinde modlar için). Bu, N düğüm × 8 köşe
projeksiyonu — önemsiz maliyet. Sonuç: aday düğüm alt-kümesi.

**Katman B — hassas test (kip'e ve trap tipine göre iki yol):**

**(B1) GPU bölgesel ID okuma — "kesen" (intersecting) traplar için ideal, piksel-hassas.**
Mevcut `SecimGpu` altyapısı buna **uygun**: `kimlikGorsel_` zaten tam-çözünürlükte
çiziliyor; tek eksik scissor+kopya bölgesinin genişletilmesi.

`SecimGpu`'ya eklenecek minimal API (piksel-hassas kesen test):
```cpp
// secim_gpu.hpp — mevcut sınıfa ek
void bolgeGecisBasla(VkCommandBuffer kb, VkRect2D bolge);  // scissor = bölge (1x1 yerine)
void bolgeGecisBitir(VkCommandBuffer kb, VkRect2D bolge);  // o dikdörtgeni okuma tamponuna kopyala
// Okuma: bölgedeki tüm piksellerde geçen benzersiz (govde,tur,alt) kümesi
void bolgeSonucOku(u32 kareIndeks, VkRect2D bolge,
                   std::vector<SecimVurusu>& benzersiz);
```
Uygulama notu: `gecisBasla`/`gecisBitir`'i parametrik bölgeye genelle (mevcut 1×1
onların özel hali). Okuma tamponu bölge alanı kadar büyütülür (host-visible; VMA
`HOST_ACCESS_RANDOM`). CPU tarafta piksel taranıp benzersiz `(govde,tur,alt)`
`std::unordered_set`'e toplanır → bölgeye **değen** her topoloji. Bu doğrudan
"Kesen Dikdörtgen" (#2) ve "Fırça İzi" (#4, iz AABB'si + izgara örnekleme) sonucudur.
Poligon (#3, kesen değil ama poligon-içi): bölge = poligon AABB, piksel-tarama
sırasında piksel merkezinin poligon-içinde-mi (even-odd) ek testi.
Derinlik: pick geçişi z-test yaptığından **yalnız görünür** (öndeki) topoloji okunur —
CATIA "arkada kalan görünmez geometri seçilmez" davranışıyla uyumlu (trap'in üstteki
geometriyi seçmesi istenirse ayrı bir "arkayı da al" opsiyonu ileride eklenebilir;
ilk sürümde görünür-yüzey yeterli).

**(B2) CPU üçgen/köşe projeksiyon — "tamamen içinde" (containment) traplar için.**
"İçinde" mantığı (#1, #5 dış-içinde, poligon-içinde-tam) piksel okumayla güvenilir
değil (arkadaki pikseller görünmez). Bunun için CPU testi:
- **Gövde kipi:** düğümün `yerelSinir` 8 köşesi → `matris()` ile dünya → `ekrana()`.
  8 köşe de dikdörtgen/poligon içindeyse "tamamen içinde". (AABB köşesi konservatif;
  isteğe bağlı hassasiyet için `cpuKonum` örneklem köşeleri kullanılabilir ama AABB
  yeterli ve ucuz.)
- **Yüz kipi:** yüz ordinaline ait üçgenler `cpuIndeks`/`cpuKonum`'dan alınır
  (yüz→üçgen eşlemesi mevcut mesh üretiminde var; yoksa yüz ordinali başına üçgen
  aralığı gerekir — mevcut per-face renk/pick altyapısıyla eşleşir). Yüzün tüm
  köşeleri içindeyse seç.
- **Kenar/Nokta kipi:** kenar iki ucu / nokta tek merkezi projekte → içinde mi.
- **Dışında traplar (#5/#6):** aynı test, "içinde" koşulu tersine (#5: tamamen dışında;
  #6: bölgeye hiç değmeyen = AABB kesişmiyor).

**Nokta-içinde-dikdörtgen** basit min/max karşılaştırması; **nokta-içinde-poligon**
even-odd (ray casting) — `alan_secim.cpp` içinde saf fonksiyon (§6 test edilebilir).

### 2.3 Kip entegrasyonu + modifier uygulama

`bitir()` sonunda aday `SecimOge` listesi hazırdır. Uygulama:
```
if (m == Degistir && aday boş değilse) sahne_.secimTemizle();
for (oge : adaylar) {
  if (m == Cikar) sahne_.sec(oge, /*coklu*/true)  → aslında seçimden çıkar
                  (seciliMi ise sil; yardımcı gerekebilir: Sahne'ye secimCikar(oge)
                   eklenmeli — mevcut sec() yalnız ekler/toggle değil; NOT §7.4)
  else            sahne_.sec(oge, /*coklu*/true);  // ekle
}
olaylar_.yayinla(AlanSecimYapildi{(u32)tip, (u32)adaylar.size()});
```
`Sahne::sec` mevcut davranış: kip farklıysa temizler + ekler; `coklu=true` çoklu birikim.
Trap tek türde adaylar üretir (aktif kip), dolayısıyla kip tutarlı. **`secimCikar`
yardımcısı** Shift için eklenmeli (bkz §7.4).

---

## 3. UI

### 3.1 Sürükleme çizimi (`AlanSecim::ciz`, ImDrawList)

CATIA görsel dili — trap tipine göre stil:

| Tip | Kenar | Dolgu |
|-----|-------|-------|
| Dikdörtgen (içinde) | **düz** ince beyaz/açık-mavi | %8 yarı saydam mavi |
| Kesen Dikdörtgen | **kesikli** yeşil | %8 yarı saydam yeşil |
| Poligon | düz mavi çizgiler + köşe noktaları; kapanış ön-izlemesi imlece kadar | kapanınca %8 dolgu |
| Fırça İzi | kalın (~4px) turuncu serbest polyline | dolgu yok |
| Dışında (içinde) | düz kırmızı | dış bölge %6 kırmızı vurgu (opsiyonel) |
| Dışında Kesen | kesikli kırmızı | — |

Uygulama: `ImDrawList::AddRectFilled` + `AddRect` (kesikli için elle segment veya
`AddPolyline` kısa parçalar), `AddPolyline`/`AddConvexPolyFilled` poligon, iz için
`AddPolyline(iz_)`. Koordinatlar ekran-yerel + `vpMinX/Y` ofset. Overlay
`ImGui::GetWindowDrawList()` üzerine (mevcut ölçüm overlay'i ile aynı katman,
main.cpp ~1478 bloğunun yakınına).

### 3.2 Trap tipi seçimi — Görünüm toolbar'ı + kısayol

- **Toolbar düğme grubu:** mevcut "Görünüm" toolbar penceresine 6 küçük ikon düğme
  (aktif olan vurgulu). `alan.tip` doğrudan bağlanır (public üye deseni, `secimSis.f*`
  gibi).
- **Kısayol döngüsü:** `T` tuşu → `alan.tip = sonrakiTrap(alan.tip)` + HUD bildirimi
  (`bilgiVer("Alan seçimi: Kesen Dikdörtgen")`). CATIA'da modlar dışlayıcı → tek aktif.
- **Durum HUD:** viewport üst-orta (mevcut `bilgiVer`/ref etiketi deseni) aktif trap
  adını gösterir; sürükleme sırasında aday sayısı canlı ("12 yüz").

---

## 4. Girdi çakışma çözümü (main.cpp entegrasyonu)

### 4.1 Öncelik sırası (mevcut sol-bırakış zinciri, satır 2210-2377)

Mevcut sıra: sketcher → hizliYonSecim → refSecim → CAM seçim → ölçüm → `secimSis.tikla`.
Bu zincir **hareketsiz tık** (`kayma<6px`) için. Trap **sürükleme**dir → ayrı slot.

**Karar (CATIA davranışı + kullanıcı isteği): trap yalnız SERBEST seçim bağlamında
aktif.** Yani sketcher / yönSeç / refSecim / CAM-seçim / ölçüm modları aktifken trap
**devre dışı** (bu modlar tek-tık akışları; CATIA'da da bu araç-modları trap'i
ezmez). Sadece hiçbir özel mod yokken (son `else secimSis.tikla` dalına denk gelen
durum) boş-alan sol-drag = trap.

**Kapı koşulu (tek satırlık predikat):**
```cpp
const bool trapUygun =
    !(sketchNesne() && cekirdek.workbenchler().aktif()=="sketcher")
    && hizliYonSecim==0 && !refSecim.aktif()
    && !camSis.secim().aktif()
    && !(olcum.acik && olcum.kip!=OlcumKip::Ayarlar);
```

### 4.2 Sol-basış (satır 2156 bloğu içine)

```cpp
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
  fare.sol=true; fare.solBasX=lx; ...
  if (trapUygun) {
    if (alan.poligonKipMi()) { if (!alan.aktifMi()) alan.basla(lx,ly); else alan.poligonNokta(lx,ly); }
    else alan.basla(lx,ly);   // dikdörtgen/iz: basış = başlangıç köşesi
  }
}
```

### 4.3 Sürükleme (kamera sürüşünden ÖNCE, satır ~2194'ten önce)

Trap aktifse **kamerayı besleme** (etkinKip'i baskıla). Zaten sol-drag kamerayı
döndürmüyor (btn=1 → `kipEsle(1) = -1`), dolayısıyla çakışma yok; yalnız iz/köşe
biriktir:
```cpp
if (alan.aktifMi() && hareket) alan.guncelle(lx,ly);  // dikdörtgen köşe / iz noktası
```
`fare.uzunBasIslendi` (Hızlı-3D long-press, satır 2200) ile çakışma: trap aktif +
kayma>6px olduğunda long-press zaten iptal olur (`kayma<6.0f` koşulu). Trap
sürüklemesi long-press'i doğal olarak dışlar. **Ek güvence:** `if (alan.aktifMi())
long-press bloğunu atla`.

### 4.4 Sol-bırakış (satır 2210 bloğunun EN BAŞINA, seçim zincirinden önce)

```cpp
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
  if (alan.aktifMi() && !alan.poligonKipMi()) {
    const f32 kayma = |lx-solBasX|+|ly-solBasY|;
    if (kayma >= 6.0f) {                       // gerçek sürükleme → trap uygula
      const TrapModifier m = io.KeyShift?Cikar : io.KeyCtrl?Ekle : Degistir;
      alan.bitir(vp, vpRectMinX, vpRectMinY, avail.x, avail.y, m, &kb?);
      // NOT: bitir GPU okuma yapacaksa bir sonraki kareye bakması gerekebilir
      //      (pick 1 kare gecikmeli). Bkz §5.2 senkronizasyon.
      fare.sol=false; goto trapBitti;          // normal tık seçim zincirini ATLA
    } else { alan.iptal(); }                    // mikro-sürükleme → normal tık'a düş
  }
  ... mevcut tık seçim zinciri ...
  trapBitti:;
}
```
Poligon: bırakışta bitmez; **çift-tık veya Enter** ile `alan.bitir` (poligon kapatma).
Sağ-tık veya ESC → `alan.iptal()`.

### 4.5 ESC (mevcut ESC işleyiciye)

`if (alan.aktifMi()) { alan.iptal(); }` — diğer ESC davranışlarından önce.

---

## 5. GPU bölgesel okuma senkronizasyonu (kritik detay)

### 5.1 Mevcut akış
`pickGecisiKaydet` her kare imleç 1×1 pikselini çizip kopyalıyor; `hoverCozumle`
**bir sonraki kare** `sonucOku` ile okuyor (1 kare gecikme, `okumaGecerli_` çift
tampon).

### 5.2 Trap bölgesel okuma seçenekleri
İki yol — **B2 (CPU) tercih edilen ilk sürüm**, B1 (GPU) opsiyonel hızlandırma:

- **CPU yolu (B2) — senkron, kare-içi, ilk sürüm:** `bitir()` tamamen CPU'da
  (`ekrana` projeksiyonu + üçgen/köşe testi) → GPU beklemesi YOK, 1 kare gecikme yok,
  `SecimGpu` değişikliği gerekmez. Büyük sahnede N düğüm × yüz köşeleri; katman-A AABB
  ön-elemesi çoğu düğümü atar. Bu **"tamamen içinde" ve "dışında" traplar için zaten
  tek doğru yol**. Kesen/fırça için de CPU üçgen-dikdörtgen kesişimi yapılabilir
  (biraz daha maliyetli ama doğru).

- **GPU yolu (B1) — kesen/fırça'da piksel-hassas, opsiyonel:** `bitir()`, trap
  dikdörtgenini `SecimGpu`'ya bir sonraki kare bölgesel çizim için kaydeder; sonuç 1
  kare sonra okunur → seçim 1 kare gecikmeli uygulanır (kullanıcıya görünmez). Küçük
  bir durum makinesi: `trapBekleyen_ = bölge; trapKare_ = kareIndeks`. Bu, yüz-içi
  delik/karmaşık kesişimlerde CPU üçgen testinden daha doğru ("değen"i piksel
  düzeyinde bilir) ama daha çok Vulkan işi.

**Öneri:** İlk sürümde **B2 (CPU) tüm tipler için**; kesen/fırça'da üçgen-AABB
kesişimi (üçgenin herhangi köşesi bölgede VEYA üçgen kenarı bölge kenarını kesiyor).
GPU B1 ikinci dalgada performans gerekirse. Böylece `SecimGpu` dokunulmaz, risk düşük.

---

## 6. Test önerisi (birim testlenebilir matematik)

`motor/sahne/test/test_alan_secim.cpp` (mevcut test deseni: `FIKO_KONTROL`).
Ekran-projeksiyon + containment saf fonksiyonlardır → kameradan bağımsız test:

1. **Bilinen VP + AABB → içinde/dışında:** sabit ortho/perspektif `vp`, eksen-hizalı
   kutu; köşeleri projekte et; bilinen bir ekran dikdörtgeni için "tamamen içinde"
   true, kutu kısmen taşınca false.
2. **Kesen test:** kutu bölgeye değiyor ama tamamen içinde değil → içinde-trap false,
   kesen-trap true.
3. **Dışında trap:** kutu bölge dışında → #5 true; bölgeye değiyor → #5 false.
4. **Nokta-içinde-poligon (even-odd):** konveks + konkav poligon, sınır/iç/dış noktalar.
5. **Nokta-içinde-dikdörtgen:** min/max sınır dahil/hariç.
6. **Fırça izi kesişim:** iz segmenti kutu ekran-AABB'sini kesiyor → true.

Projeksiyon lambda'sı (`ekrana`) `alan_secim.cpp` içine saf `ekranProjekte(vp, world,
vpMin, vpBoyut, ImVec2&)` olarak çıkarılıp hem main.cpp hem test paylaşır (mevcut
main.cpp lambda'sı ile aynı matematik — kod tekrarı olmasın, merkezileştir).

---

## 7. Uygulama adımları

1. **`alan_secim.hpp/.cpp` oluştur** (§2): `TrapTip`/`TrapModifier` enum, `AlanSecim`
   sınıfı, saf `ekranProjekte` + `noktaPoligonda`/`aabbDikdortgende`/`ucgenKesisiyor`
   yardımcıları. CMake `motor/sahne` hedefine ekle.
2. **`OlayTuru`'na `AlanSecimYapildi` ekle** — `olay.hpp` enum'da **SAYAC'tan önce**
   (mevcut son eleman `CamOpYoluHesaplandi`'dan sonra); POD struct
   `{u32 tip; u32 adet;}` + `static constexpr tur()`; `olay.cpp` `olayTuruAdi`
   switch'ine case. Diske yazılır (kalıcı; yüksek frekans değil).
3. **`AlanSecim` örneğini main.cpp'de kur** (SecimSistemi ile aynı yerde: `sahne, gpu,
   olaylar`). `alan.tip` public — Görünüm toolbar düğmeleri + `T` kısayolu bağla (§3.3).
4. **`Sahne::secimCikar(SecimOge)` ekle** (Shift/çıkar için) — mevcut `secililer_`
   vektöründen sil + `SecimDegisti` yayınla. (Mevcut `sec` yalnız ekler/kip yönetir.)
5. **main.cpp fare akışına entegre et** (§4): `trapUygun` predikatı; sol-basış/sürükleme/
   bırakış/ESC dallarına trap çağrıları; tık seçim zincirini trap uygulandığında atla.
6. **Overlay çizimi** (§3.1): main.cpp overlay bloğunda (`ImGui::GetWindowDrawList()`)
   `alan.ciz(dl, vpRectMinX, vpRectMinY)`; sürükleme sırasında canlı aday sayısı HUD.
7. **Testler** (§6): `test_alan_secim.cpp`; CMake test hedefine ekle; `ctest` yeşil.
8. **(Opsiyonel, 2. dalga)** GPU bölgesel okuma B1: `SecimGpu::bolgeGecisBasla/Bitir/
   bolgeSonucOku` + main.cpp'de 1-kare-gecikmeli trap durum makinesi (§5.2). Yalnız
   büyük sahnede kesen/fırça performansı gerekirse.

**Makro/eklenti erişimi (mimari anayasa):** `AlanSecimYapildi` olayı yayınlandığı an
Lua makro (`fiko.olay.dinle("AlanSecimYapildi", ...)`) ve DLL eklentileri
(`olaylar.abone<AlanSecimYapildi>`) bedavaya erişir — ek iş yok. Trap tipini makrodan
tetiklemek istenirse ileride `fiko.sahne.alanSecimTip(...)` API'si eklenebilir (bu
dalgada zorunlu değil).

---

## 8. Kaynaklar

- CATIA V5 Selection Traps — resmi doküman: <http://catiadoc.free.fr/online/mpsug_C2/mpsugwd0200.htm> (Select Toolbar) ve <http://catiadoc.free.fr/online/basug_C2/basugbt0602.htm>
- Selecting Using the Selection Traps — <https://catiahelp.azurewebsites.net/English/ComUserMap/com-t-Select-SelectionTrap.htm>
- CATIA V5 Selection Trap (3DCS blog) — <https://blog.3dcs.com/Blog/bid/75402/CATIA-V5-Selection-Trap-Get-to-Those-Hard-to-Reach-Places>
- Selection modes (exclusive, rectangle default) — <https://maruf.ca/files/catiahelp/cfyugprcsim_C2/cfyugprcsimut0400.htm>
- Selection methods overview — <https://www.technia.com/en/faqs/methods-for-selecting-elements/>
