Initial commit
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Memory Index
|
||||
|
||||
- [Würth plato-backend ist strikt read-only](wuerth-plato-backend-read-only.md) — niemals Änderungen in /home/marcuh/git/wuerth/fahrzeugeinrichtung-plato-backend
|
||||
- [adesso-cpq Verbau-Architektur](cpq-verbau-architektur.md) — Product/Modell/Graph, BLAST-Validierung, Speedmaxx-Quelle; morgen früh zuerst: BLAST-Entities + Converter
|
||||
- [Keine Spekulation/Unterstellung](feedback-keine-intent-unterstellung.md) — keine „vermutlich"-Sätze über Absichten Dritter oder technische Ursachen; bei Unklarheit „weiß ich nicht"
|
||||
- [adesso-cpq MR-Ziel](cpq-branching-mr-ziel.md) — MRs künftig auf development/Integration statt main; Branch bald einrichten
|
||||
- [Kein nextTick](feedback-kein-nexttick.md) — Vue nextTick hartes Verbot; Timing reaktiv über watch/v-if lösen
|
||||
- [cpq Storybook starten](cpq-storybook-start.md) — pnpm --filter @ad-cpq/common-frontend storybook (Port 6006)
|
||||
- [Git nur Fast-Forward](feedback-git-nur-fast-forward.md) — kein rebase/merge/force; bei Divergenz melden statt auflösen
|
||||
- [fire-visual Placement-Mode](fire-visual-placement-mode.md) — Reverse-Engineering-Kopie fremden Codes (NICHT unser Code, nicht ändern); Build = @ad/fire/geko-fire; snap-to-point, processInput, PMI-DropPoints
|
||||
- [cpq Verbau 90° am Steher](cpq-verbau-90grad-steher.md) — Rotation ist im GroupProcessor-Replay angekommen (Edge.rot/computeLayout); fachliche 90°-Klärung läuft noch
|
||||
- [cpq Configurator Modul-Registry](cpq-configurator-modul-registry.md) — GEKO-76/16: Registry in configurator/modules, Hook nach replay(), Heilung=Ableitung, Overrides=Events
|
||||
- [Suche nur in Projektordnern](feedback-suche-nur-projektordner.md) — find/grep nie über ~ oder den ganzen Rechner, nur im konkreten erlaubten Verzeichnis
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: cpq-branching-mr-ziel
|
||||
description: "adesso-cpq MRs sollen künftig nicht auf main zielen, sondern auf einen Integrations-/development-Branch"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 00f129fd-620a-465c-8fdf-02b2ba4c3ba6
|
||||
---
|
||||
|
||||
In adesso-cpq (git.heron.at/pzm/geko/adesso-cpq) sollen Merge Requests **nicht direkt auf `main`** zielen. Der User will einen Integrations-/`development`-Branch als MR-Ziel — existiert noch nicht (Stand 2026-06-24).
|
||||
|
||||
**Why:** Bei MR #12 (chore/dev-tooling-and-hygiene → main) hat der User explizit gesagt, dass ihm `main` als Ziel nicht gefällt. Nicht sofort ändern, aber bald einrichten.
|
||||
|
||||
**How to apply:** Bei neuen MRs nachfragen/prüfen, ob schon ein development-Branch existiert, und dann dorthin statt auf `main` zielen. Default `origin/HEAD → main` nicht blind übernehmen.
|
||||
|
||||
Bezug: [[cpq-verbau-architektur]]
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: cpq-configurator-modul-registry
|
||||
description: "GEKO-76/16-Konzept: Modul-Registry im cpq-Configurator — Injection über DefaultCommandProcessor, Hook nach replay(), Heilung = Ableitung, Overrides = Events"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 8d7f85b8-4927-4426-9e04-a8be7def3b5e
|
||||
---
|
||||
|
||||
Konzept-Entscheidung (2026-07-03) für die cpq/geko-Abgrenzung der Schutzzaun-Tickets GEKO-76 (Steher-Logik) und GEKO-16 (Zaun zwischen zwei Punkten):
|
||||
|
||||
- **Registry-Ort:** `packages/frontend/src/configurator/` (neues Verzeichnis `modules/`), kein neues Package. cpq bleibt domänen-agnostisch; geko liefert Module (Steher, Zaun-Zug) von außen.
|
||||
- **Injection:** Konstruktor des `DefaultCommandProcessor`; `Fire3D.vue` nimmt bereits `props.processor` entgegen — die geko-App baut den Processor mit ihren Modulen und reicht ihn durch.
|
||||
- **Zentraler Hook:** nach `groups.replay(...)` in `DefaultCommandProcessor.replay()` — einziger Engpass für Live, Undo/Redo und Placement; Module können Live/Replay nicht auseinanderlaufen lassen.
|
||||
- **Semantik:** Selbstheilung (Bauform A–G, Höhe) ist reine Ableitung aus der Topologie (`occupiedPmis()`, `Edge.rot`) und landet nie im EventStore; manuelle Detailmenü-Overrides sind echte, undo-bare Events (Modul-eigene Event-Typen).
|
||||
- **Mit aufzuräumen:** hartkodierte `.name-CS_EIN_*`-Selektoren im `DefaultCommandProcessor` → Placement-Konfiguration des Moduls; Löschen ist im Processor noch unbehandelt → Kaskaden-Hook von Anfang an als Modul-Vertrag entwerfen.
|
||||
- Ticket-Quellen lokal: `~/claude-projects/robotunits/GEKO-76.xml`, `GEKO-16.xml`; DrawIO-Abgrenzung: `GEKO-76-steher-cpq-geko.drawio`.
|
||||
|
||||
Siehe [[cpq-verbau-architektur]], [[cpq-verbau-90grad-steher]].
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: cpq-storybook-start
|
||||
description: Befehl zum Starten von Storybook im adesso-cpq Projekt
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 277ae1d7-4a4d-4f24-ae53-60e743d26171
|
||||
---
|
||||
|
||||
Storybook in adesso-cpq starten:
|
||||
|
||||
```
|
||||
pnpm --filter @ad-cpq/common-frontend storybook
|
||||
```
|
||||
|
||||
Paket liegt unter `packages/frontend` (Name `@ad-cpq/common-frontend`), Script `storybook dev -p 6006`, Port 6006. Monorepo nutzt pnpm. Siehe [[cpq-verbau-architektur]].
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: cpq-verbau-90grad-steher
|
||||
description: "90°-Anbau am Steher: Rotation ist im GroupProcessor-Replay angekommen (Edge.rot, computeLayout) — fachliche 90°-Klärung läuft noch"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: e3d54daa-eb88-474f-9e99-62bfe83821b2
|
||||
---
|
||||
|
||||
Ziel: an den Stehern im 90°-Winkel anbauen können, genau wie der Links/Rechts-Verbau.
|
||||
|
||||
**Stand 2026-07-03 (verifiziert im Code):** Der frühere Blocker — translation-only-Replay im cpq-`GroupProcessor` — ist behoben. `packages/frontend/src/configurator/model/GroupProcessor.ts`:
|
||||
- `Edge` trägt `rot?: Quat` (relative Rotation pro Dock-Kante).
|
||||
- `computeLayout` komponiert Rotationen über den ungerichteten Kantengraphen (Quaternionen, vorwärts `R_to = R_from ∘ edge.rot`, rückwärts invers); mit Identity-Rotationen reduziert es sich exakt auf den alten translation-only-Solver.
|
||||
- `dockRotation` leitet `Edge.rot` aus den PMI-Frame-Orientierungen ab (`pmiRotation` liest `properties.rotation` als Euler ZYX Grad → Quat).
|
||||
- Placement nutzt die `CS_EIN_VORNE`/`CS_EIN_HINTEN`-Selektoren (hart im `DefaultCommandProcessor` — Kandidat für Modul-Konfiguration).
|
||||
|
||||
Die fachliche Klärung der 90°-Frage (GEKO-Seite) läuft laut Marcus noch separat.
|
||||
|
||||
Siehe [[cpq-verbau-architektur]], [[fire-visual-placement-mode]], [[cpq-configurator-modul-registry]].
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: cpq-verbau-architektur
|
||||
description: "adesso-cpq Verbau/Modell-Architektur (Product/Modell/Graph, BLAST-Validierung) + nächster Schritt für morgen früh"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: d789290f-6631-426e-9639-e7ea7a60e8f9
|
||||
---
|
||||
|
||||
Stand der Architektur-Diskussion adesso-cpq (Schutzzaun-Konfigurator). Repos: ~/projects/adesso-cpq (frontend/CPQ), ~/projects/geko-core (Speedmaxx-Backend). Constraint-Typen folgen noch; jetzt erst Infrastruktur.
|
||||
|
||||
## Kernmodell (erarbeitet, trägt)
|
||||
- **Product = zweigeteilt:** (1) Graph mit PMIs/Collidern/Transforms = der „wertlose" Graph (keine Autorität, nur Darstellung + Approximationsdaten); (2) Variablen = Config + Constraints.
|
||||
- **Product = Entity** (BaseEntity, BLAST-validiert). **Konstrukt aus Produkten = auch Entity = Modell.** Rekursiv: Modell = Produkt (Blatt) | Konstrukt aus Modellen. Aus den Entities wird am Ende der wertlose Graph projiziert.
|
||||
- **Quellen (mehrere!):** Speedmaxx ist führend (~60%), daneben eigene Modelle (optimaler gestaltbar) + weitere Lieferanten. Darum muss BLAST gegen ein **normalisiertes** Modell validieren, nicht gegen Quell-Spezifika oder den rohen Graphen. Im Zweifel ein **Converter**, der Speedmaxx & whatever normalisiert.
|
||||
|
||||
## Speedmaxx-Realität (Quelle der Wahrheit, NICHT der cpq-Mock)
|
||||
- Branch geko-core `feature/get-scene-from-speedmaxx`: `executeCommand` → `ExecuteCommandResponse { ui: Record<string,SpeedmaxxVariable>, viewing, error }`.
|
||||
- `ui` = Config+Constraints: `domain.{min,max,step,valuelist,default}`, `required/visible/editable/multivalue/datatype/unit/...`. Hier stecken „≤6m / ≤10 Teile".
|
||||
- `viewing` = die Szene (wertloser Graph). Controller `loadScene` ruft `combo1_cmd`, ProductCategory "Schutzzaun", Variables wizard → gibt `result.viewing`.
|
||||
- Format des Graphen (= Alttool = `assets/scenes/zaun.json`): `sceneGraph_entity { handles[] }`; Hierarchie flach über `component_transform.key/parentKey` (root → asm_root → produkt-node → ~50 Blatt-Teile); `component_pmi` (z.B. CS_SVS/CS_BASIS am Produkt-Knoten) = Andockpunkte; `component_collider`; Länge teils in `scale.z` eingebacken.
|
||||
- **FALSCH in cpq:** `packages/frontend/src/util/speedMaxx2Visual.ts` erfindet `{environmentId, nodes:[{id,label}]}` — gibt es bei Speedmaxx nicht. Muss korrigiert werden.
|
||||
|
||||
## Validierung / BLAST (entschieden)
|
||||
- Variablen → BLAST direkt (per-Produkt + Querregeln).
|
||||
- Geometrie-Constraints (≤10 Teile, Gesamtlänge, PMI-Kompatibilität, Platz/Kollision) stehen NICHT in Variablen → ergeben sich aus PMIs/Collidern/Transforms.
|
||||
- Geometrie-RECHNUNG läuft in der Engine (nicht im BLAST-Kern, der ist geometrie-agnostisch). Aber: **Engine wird AUS BLAST getriggert.** BLAST ist der Orchestrator und reaktiv (Änderung → sofort wirksam), Cache sparse pro Entity-ID → Engine läuft nur für den betroffenen Bauzug.
|
||||
- Zwei Topos-Ebenen: per Einzelteil + konsolidiert (Bauzug). Konsolidierter Topos ruft die Engine, holt Verdikt, validiert.
|
||||
- Hebel = Abhängigkeitsschärfe (welcher Topos hängt woran). Wird über Constraint-Typen geregelt (kommt noch).
|
||||
- Roher Graph geht NIE nach BLAST; nur Variablen + destillierte Graph-Fakten/Verdikte.
|
||||
|
||||
## Schichten (Zielbild)
|
||||
- **UI** spricht nur mit dem **Scene/Model-Service** (Name noch offen), gibt dessen Ergebnis als Graph/Commands an fire.
|
||||
- **Scene/Model-Service** (core): hält Modell/Bauzüge, PMI-Verbindungen, rechnet Constraints, projiziert Modell → Graph. Intern getrennt: Modell/Constraint (entscheidet, kennt Platz) vs. Projektion (stumpf, entscheidet nichts).
|
||||
- **ProductService** (gehört nach **core**, FE-agnostisch): getProduct/updateProduct, liefert nur Einzelteile, **quelle-agnostisch** über die Asset-Abstraktion (datamanager-Connectors in environment.config.json: path+typeKey-Templates; dev=Assets, live=Server). Darf NICHT wissen, woher.
|
||||
- **fire/Graph**: rendert, ist außerhalb unserer Engine interaktiv und arbeitet mit Näherungen (Collider). Wir haben das letzte Wort; nach jeder Interaktion **Vollaustausch** des Graphen.
|
||||
- **Gemeinsame Constraint-Sprache nötig** (3x bestätigt): zwischen zwei gemeldeten Interaktionen handelt fire autonom; es braucht dieselben Constraints. Lösung: **deklarative Daten im Graph** (Collider/PMI/Grenzen), kein geteilter Code. Offen: diese deklarativen Constraints und die exakten BLAST-Regeln müssen aus EINER Quelle stammen, sonst Drift.
|
||||
|
||||
## Bestand an Typen (adesso-cpq)
|
||||
- shared: `BaseEntity { id }`. core: nur `EntityStore`, keine Typen.
|
||||
- blast: `ObjectSchema<T extends BaseEntity>`, `ToposKey`, `BehaviourResolver`, `HintResolver`, `Diagnostic`, `Severity('error'|'warn'|'info')`, `Behaviours`, `Hint`, `FieldState`, `ItemResult`, `BlastValidator`.
|
||||
- visual-runtime: `Visual3D` (setScene/execute/subscribe/camera), `CameraTransformation{translation,rotation,scale}`, `ConnectorConfig`, `Visual3DConfig`, `Observable<T>`.
|
||||
- **Szenegraph-Format-Typen (SceneGraph/Handle/Component, component_transform/pmi/collider) sind HEIMATLOS** — nur in `utils/sceneMerger.ts` (fliegt raus) und als `any` in Fire3D.vue/DefaultCommandProzessor/SceneReplayProcessor. Brauchen EINEN Besitzer (Fundament für Product/Scene/fire).
|
||||
- `utils/sceneMerger.ts`: addProductInstance/mergeScene/generateUniqueIds/positionScene/calculateNextPosition — fliegt raus (falscher Ort `utils`, zu groß, vermischt Mechanik/Platzierung/Instanz). generateUniqueIds vom User als „Mist" markiert.
|
||||
|
||||
## Offene Baustelle aus dieser Session
|
||||
- `packages/frontend/src/services/product-service.ts` habe ich angelegt (getProduct/updateProduct, AssetLoader, lokaler SceneGraph-Typ). User-Kritik: zu nah an UI (gehört nach core), zuviel vorab definiert (Interfaces/Typen ohne Plan). Morgen entscheiden: behalten/verschieben/löschen. NICHT eigenmächtig Typen streuen.
|
||||
|
||||
## MORGEN FRÜH ZUERST
|
||||
1. GENAU auf die **Entities für BLAST** schauen: was ist exakt die normalisierte Entity (Product, Modell). Wahrscheinlich ein **Converter** rein, der Speedmaxx (ui+viewing) und andere Quellen normalisiert. Das MUSS sitzen, sonst Schmerzen.
|
||||
2. Dann Infrastruktur/Schichten verorten (ProductService → core, Format-Typen-Heimat).
|
||||
3. Constraint-Typen erst danach.
|
||||
|
||||
## Arbeitsregeln des Users (hart)
|
||||
- Sehr knapp, exakt das Gefragte, KEINE ungefragten Optionen/Vorschläge/Typen. Eins nach dem anderen, langsam. Nicht 3 Schritte vorausbauen. Keine Antwort mit Rückfrage/Angebot beenden. Kein Claude-Hinweis in Commits. Vor verändernden Aktionen kurz Plan + Go abwarten.
|
||||
- Branch+MR-Workflow (adesso-CLAUDE.md); frontend→core ist paketübergreifend → nur mit explizitem Go. Git-Remotes heron.at: HTTPS+Token (osxkeychain), SSH (Port 22) ist geblockt.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: feedback-git-nur-fast-forward
|
||||
description: Git-Sync nur Fast-Forward; bei Divergenz melden statt rebase/merge
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 277ae1d7-4a4d-4f24-ae53-60e743d26171
|
||||
---
|
||||
|
||||
Beim Committen/Pushen: **nur Fast-Forward**. Kein `pull --rebase`, kein Merge, kein Force.
|
||||
|
||||
**Why:** Rebase/Merge verändert Historie bzw. löst Divergenzen automatisch auf — das will der User nicht ungefragt.
|
||||
|
||||
**How to apply:** Ablauf = `git add` → `git commit` → `git push`. Schlägt der Push fehl, weil er nicht fast-forward ist (Remote divergiert), **melden** und stoppen, nicht selbst auflösen. Verwandt: [[feedback-keine-intent-unterstellung]].
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: feedback-kein-nexttick
|
||||
description: "Hartes Verbot: niemals Vue nextTick verwenden"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 26b7ea78-4681-479e-b73a-64b2ce89a046
|
||||
---
|
||||
|
||||
`nextTick` (Vue) ist verboten — niemals verwenden.
|
||||
|
||||
**Why:** Der User hat sehr deutlich reagiert, als ich ein Timing-Problem (Fire3D liest `props.config` einmalig beim Mount) mit `await nextTick()` gelöst habe. nextTick gilt als Symptombehandlung statt sauberer reaktiver Lösung.
|
||||
|
||||
**How to apply:** Reihenfolge-/Mount-Timing reaktiv lösen — `watch` auf Template-Refs, `v-if`-Gating, eigene ready-Signale. Eingetragen in globaler CLAUDE.md (# Code) und adesso-cpq/CLAUDE.md (### Kein nextTick).
|
||||
|
||||
Bezug: [[cpq-verbau-architektur]]
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: feedback-keine-intent-unterstellung
|
||||
description: "Keine Vermutungen/Spekulationen anhängen — weder über Personen-Absichten noch über technische Ursachen; nur Fakten, sonst „weiß ich nicht\""
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 00f129fd-620a-465c-8fdf-02b2ba4c3ba6
|
||||
---
|
||||
|
||||
Keine „vermutlich"-Sätze. Gilt zweifach: (1) nicht raten, was ein Dritter (PL, Kollege, fire-Team) „eigentlich meint/will" — Aussagen des Users wörtlich nehmen; (2) keine spekulative Ursache anhängen (z. B. „dein Node liegt vermutlich hinter einem Versionsmanager"). Wenn die Ursache unklar ist: „weiß ich nicht", Punkt.
|
||||
|
||||
**Why:** Zweimal scharf korrigiert in einer Session. Einmal: „der Punkt, den die PL vermutlich meint, ist X" — PL meinte exakt das schon Gesagte. Einmal: nach „node nicht im PATH" eine geratene Begründung angehängt. Beides als Unterstellung empfunden.
|
||||
|
||||
**How to apply:** Frage auf Basis der gegebenen Aussage / der gemessenen Fakten beantworten. Keinen Absatz anhängen, der Intention oder Ursache rekonstruiert/rät. Geht über „Kompetenz unterstellen" hinaus: auch wohlwollende/plausible Spekulation unterlassen. Unklarheit ehrlich als Unklarheit benennen.
|
||||
|
||||
Bezug: [[cpq-verbau-architektur]]
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: feedback-suche-nur-projektordner
|
||||
description: "Suchen/find/grep nur innerhalb der erlaubten Projektverzeichnisse, nie über ~ oder den ganzen Rechner"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 8d7f85b8-4927-4426-9e04-a8be7def3b5e
|
||||
---
|
||||
|
||||
Such-Befehle (find, grep, ls …) nur innerhalb der erlaubten Arbeitsverzeichnisse des jeweiligen Projekts ausführen — nicht über `/Users/marcus.hinz`, nicht über breite Pfad-Listen quer durch `~/projects`, nicht über den ganzen Rechner.
|
||||
|
||||
**Why:** Marcus erlaubt Zugriff gezielt pro Projektordner; breite Sweeps über Home verletzen diese Abgrenzung, auch wenn sie technisch funktionieren.
|
||||
|
||||
**How to apply:** Vor einem Such-Befehl den konkretesten bekannten Pfad wählen (z. B. das genannte Repo oder `~/claude-projects/robotunits`). Liegt das Ziel dort nicht, melden statt den Suchraum eigenmächtig auszuweiten. Gilt zusätzlich zu [[feedback-keine-intent-unterstellung]]s Grundregel „nur suchen, wenn angewiesen".
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
name: fire-visual-placement-mode
|
||||
description: "fire-visual Placement-Mode (snap-to-point) — Architektur, Settings, Algorithmus, DropPoints, Commands; Pfade im threed/interaction- und threed/pmi-Modul"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 733f7054-ac76-49cd-ba04-516ef015d4f3
|
||||
---
|
||||
|
||||
**WICHTIG: `fire-visual` ist KEIN eigener Code.** Es ist eine Kopie fremden Codes (Drittanbieter), die nur zum Reverse Engineering / Verstehen dient — nicht ändern, nicht als unser Produkt behandeln. Daraus gebaut wird das Paket `@ad/fire` (Repo `~/projects/geko-fire`, Remote `git.heron.at/pzm/geko/geko-fire.git`, nur Build: `browser/index.js` + `types/`, u.a. `import-fire-visual-modules.d.ts`). `fire-visual` selbst ist kein Git-Repo. adesso-cpq konsumiert `@ad/fire` als Dependency (`packages/frontend/package.json: "@ad/fire": "^1.0.6"`). Änderungen an der Visualisierung/Placement gehören NICHT hier hinein.
|
||||
|
||||
Placement-Mode = snap-to-point-Platzierung eines Subjects über Drag-Points/Drop-Points. Teil des Moduls `@fire-visual/interaction`. Quelle: `~/projects/fire-visual`.
|
||||
|
||||
## Pfade
|
||||
- Mode: `threed/interaction/module/src/interactionMode/placementMode.ts`
|
||||
- Verdrahtung/Command: `threed/interaction/module/src/feature/interactionFeature.ts` (ab Zeile 259)
|
||||
- Options-Typen: `threed/interaction/module/src/options/modeOptions.ts`
|
||||
- Modul-Doku: `threed/interaction/MODULE.md`
|
||||
- Test: `threed/interaction/module/tests/placementMode.test.ts`
|
||||
- DropPoint-Implementierungen (PMI): `threed/pmi/module/src/dropPoint/{pmiDropPoint,planeDropPoint,pointDropPoint,lineDropPoint}.ts`
|
||||
- DropPoint-Factory: `threed/pmi/module/src/component/pmiComponent.ts` → `getDropPoint()` (Zeile 422)
|
||||
|
||||
## Grundbegriffe
|
||||
- **Subject**: das zu platzierende Objekt (`Handle`).
|
||||
- **Drag-Point**: Punkt am Subject (lokaler `transform: Matrix4_4`), an dem „angefasst" wird. Visualisiert als Kugel (Sphere). Aktiv = gelb, inaktiv = blau.
|
||||
- **Drop-Point**: Ziel-Snap-Geometrie in der Szene; liefert über `assessRay` eine Bewertung. Implementiert Interface `DropPoint`.
|
||||
- **activeDragPointIndex**: aktiver Drag-Point; `-1` = „alle Drag-Points" (nur erlaubt wenn `allowAllDragPoints !== false`). Start: `-1`, oder `0` falls `allowAllDragPoints === false`.
|
||||
|
||||
## PlacementModeSettings
|
||||
- `camera: CameraComponent`, `subject: Handle`
|
||||
- `dragPoints[]`: je `{ transform, dropPoints: Partial<DropPointProvider>[], selector? }`
|
||||
- `defaultCursorTransform?` (Fallback = `dragPoints[0].transform`)
|
||||
- `allowAllDragPoints?` (Default true) — false: Index -1 verboten, Cycling hält immer einen konkreten DP aktiv
|
||||
- `allowDragPointCycling?` (Default true) — false: User kann aktiven DP nicht ändern, „alle DP" bleibt aktiv
|
||||
- `maxJumpDistance?` — überschreibt globalen Wert aus `ModeOptionProvider`
|
||||
|
||||
## Globale Optionen (ModeOptionProvider.options.placement, Typ PlacementModeOptions)
|
||||
`maxJumpDistance`, `highlightColor` (Default Color.yellow), `dragPointActiveColor` (Default yellow), `dragPointInactiveColor` (Default blue), `dragPointRadius` (Default 0.1). Plus `gizmoScale` (Default 1) skaliert Kugelradius.
|
||||
|
||||
## Algorithmus processInput(input) je Frame
|
||||
Input: `pointerNormalizedPosition`, `nextDragPoint`, `previousDragPoint`, `interactionClick`.
|
||||
1. Ohne Pointer/Camera → false.
|
||||
2. **Grab-Gating**: Rising edge von `interactionClick` setzt `_grabActive = true`. Solange nicht grab-aktiv: nur prevClick merken, return true (Subject bewegt sich nicht).
|
||||
3. Cycling: bei `nextDragPoint`/`previousDragPoint` Index zyklen (wenn Cycling erlaubt).
|
||||
4. Alle Drop-Point-Visualisierungen zurücksetzen (erst `false`+Highlight null), dann die zum aktiven DP gehörenden aktivieren (Index -1 ⇒ alle).
|
||||
5. Ray von Kamera durch Pointer; Schnitt mit XZ-Ebene (`Plane` durch Ursprung, Normale up) → `intersectionPoint`.
|
||||
6. Für jeden aktiven Drag-Point × dessen Drop-Points: Ray um `dropPoint.predictDragPointRotation(ray) * (dragPoint.transform⁻¹ * cursorTransform) * 0` versetzen, dann `dropPoint.assessRay(offsetRay)` → RayAssessment.
|
||||
7. Beste Assessment über `betterRayAssessment`: kleinste `jumpDistance`; bei Gleichstand (Toleranz 0.05) kleinste `rayDistance`.
|
||||
8. Wenn `best.jumpDistance < maxJumpDistance`: Drop-Point highlighten und Subject snappen: `subject.matrix = compose(best.position, best.rotation, 1) * dragPointTransform⁻¹`. Sonst: Subject auf `intersectionPoint` auf XZ-Ebene setzen (`* cursorTransform⁻¹`), rotation identity.
|
||||
9. `_lastPlacement` (PlacementUpdateData) merken: position, rotation, dragPointSelector, dropPointSelector (jeweils null bei XZ-Fallback).
|
||||
10. Drag-Point-Kugeln neu positionieren (`subjectMatrix * dragPoint.transform * 0`), Material gelb/blau je aktiv.
|
||||
11. **Falling edge** von `interactionClick`: `_grabActive = false`, `_lastPlacement` per `emitUpdateEvent` (subject als selectorElementReferenceRepresentation) ausgeben.
|
||||
|
||||
## Cycling-Logik
|
||||
- allowAllDragPoints true: Reihenfolge … last → -1 (alle) → 0 → … (wrap über -1).
|
||||
- allowAllDragPoints false: -1 wird übersprungen, Wrap last → 0.
|
||||
|
||||
## Lifecycle
|
||||
- `startMode`: Drop-Points je Drag-Point aus Providern extrahieren (`getDropPoint()`), Drag-Point-Visuals (Sphere-Handles, BasicMaterial transparent opacity 0.75) per `addInteractionScene` erzeugen, Handles via `find('.drag-point-i')`.
|
||||
- `stopMode`: dropPoints/dragPointHandles leeren.
|
||||
|
||||
## Command (Environment): start_placement_mode(params)
|
||||
params: `subject: string`, `cursorTransform?`, `allowAllDragPoints?`, `allowDragPointCycling?`, `maxJumpDistance?`, `dragPoints: Array<{ selector?, transform?:{position,rotation}, dropPoints: string[] }>`.
|
||||
Auflösung in interactionFeature:
|
||||
- Subject-Selector → Handle (wirft wenn nicht gefunden).
|
||||
- Pro Drag-Point: `dropPoints`-Selektoren via `selectorEngine.findAll` → DropPointProvider.
|
||||
- Ohne `selector`: ein Drag-Point mit `transform` (aus position/rotation, sonst identity), selector undefined.
|
||||
- Mit `selector`: `findAll(selector, subjectHandle)` → je Sub-Entity ein Drag-Point mit `transform = subject.LTW⁻¹ * dpe.LTW * transform`, selector = `selectorEngine.selector(dpe)`.
|
||||
Weitere Commands: `placement_mode_next_drag_point`, `placement_mode_previous_drag_point` (werfen TypeError wenn aktueller Mode kein PlacementMode), `stop_interaction_mode`, `observe_interaction_events`.
|
||||
|
||||
## DropPoint-Interface
|
||||
`assessRay(ray): RayAssessment {jumpDistance, rayDistance, position, rotation}`, `predictDragPointRotation(ray): Matrix4_4`, `setVisualization(state)`, `setVisualizationHighlight(color|null)`, `selector(): string|null`.
|
||||
|
||||
PMI-Implementierungen (`PmiDropPoint` Basis, hält `LTW`, `dragPointRotation = decompose(LTW)[1]`, predictRotation = konstant):
|
||||
- **PointDropPoint** (PMIType point/matrix): position = LTW·0; jumpDistance = Abstand Punkt↔nächster Punkt auf Strahl.
|
||||
- **LineDropPoint** (line): Segment LTW·0 → parentLTW·endpoint; closest segment-on-line.
|
||||
- **PlaneDropPoint** (plane): Ebene aus LTW; Ray-Schnitt, in Ebenen-Koords auf `size`/2 geclampt, zurück nach Welt; jumpDistance = clampedPoint↔rayPoint.
|
||||
`PMIComponent.getDropPoint()` mappt PMIType → Klasse (point/matrix→Point, line→Line, plane→Plane, sonst null).
|
||||
|
||||
Verwandt: [[cpq-verbau-architektur]] (CPQ-seitige Verbau/Platzierung).
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: wuerth-plato-backend-read-only
|
||||
description: /home/marcuh/git/wuerth/fahrzeugeinrichtung-plato-backend ist strikt read-only — niemals Änderungen dort machen
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: e3bfa548-0bcc-4bf3-80f4-4360920c38ac
|
||||
---
|
||||
|
||||
Das Verzeichnis `/home/marcuh/git/wuerth/fahrzeugeinrichtung-plato-backend` darf ausschließlich gelesen werden. Keine Edits, Writes, git-Operationen oder sonstige Änderungen dort — unter keinen Umständen.
|
||||
|
||||
**Why:** Ausdrückliche, nachdrückliche Anweisung des Users (2026-06-10): "dort KEINE ÄNDERUNGEN MACHEN!!!!!!!! - HART NUR LESEN". Vermutlich Kunden-/Fremdrepo (Würth).
|
||||
|
||||
**How to apply:** In diesem Verzeichnis nur Read/Grep/Glob bzw. lesende Bash-Befehle verwenden. Erkenntnisse daraus dürfen genutzt werden, um Code in [[adesso-cpq]] oder geko-core zu schreiben.
|
||||
Reference in New Issue
Block a user