7.1 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| fire-visual-placement-mode | fire-visual Placement-Mode (snap-to-point) — Architektur, Settings, Algorithmus, DropPoints, Commands; Pfade im threed/interaction- und threed/pmi-Modul |
|
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
assessRayeine Bewertung. Implementiert InterfaceDropPoint. - activeDragPointIndex: aktiver Drag-Point;
-1= „alle Drag-Points" (nur erlaubt wennallowAllDragPoints !== false). Start:-1, oder0fallsallowAllDragPoints === false.
PlacementModeSettings
camera: CameraComponent,subject: HandledragPoints[]: 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 aktivallowDragPointCycling?(Default true) — false: User kann aktiven DP nicht ändern, „alle DP" bleibt aktivmaxJumpDistance?— überschreibt globalen Wert ausModeOptionProvider
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.
- Ohne Pointer/Camera → false.
- Grab-Gating: Rising edge von
interactionClicksetzt_grabActive = true. Solange nicht grab-aktiv: nur prevClick merken, return true (Subject bewegt sich nicht). - Cycling: bei
nextDragPoint/previousDragPointIndex zyklen (wenn Cycling erlaubt). - Alle Drop-Point-Visualisierungen zurücksetzen (erst
false+Highlight null), dann die zum aktiven DP gehörenden aktivieren (Index -1 ⇒ alle). - Ray von Kamera durch Pointer; Schnitt mit XZ-Ebene (
Planedurch Ursprung, Normale up) →intersectionPoint. - Für jeden aktiven Drag-Point × dessen Drop-Points: Ray um
dropPoint.predictDragPointRotation(ray) * (dragPoint.transform⁻¹ * cursorTransform) * 0versetzen, danndropPoint.assessRay(offsetRay)→ RayAssessment. - Beste Assessment über
betterRayAssessment: kleinstejumpDistance; bei Gleichstand (Toleranz 0.05) kleinsterayDistance. - Wenn
best.jumpDistance < maxJumpDistance: Drop-Point highlighten und Subject snappen:subject.matrix = compose(best.position, best.rotation, 1) * dragPointTransform⁻¹. Sonst: Subject aufintersectionPointauf XZ-Ebene setzen (* cursorTransform⁻¹), rotation identity. _lastPlacement(PlacementUpdateData) merken: position, rotation, dragPointSelector, dropPointSelector (jeweils null bei XZ-Fallback).- Drag-Point-Kugeln neu positionieren (
subjectMatrix * dragPoint.transform * 0), Material gelb/blau je aktiv. - Falling edge von
interactionClick:_grabActive = false,_lastPlacementperemitUpdateEvent(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) peraddInteractionSceneerzeugen, Handles viafind('.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 viaselectorEngine.findAll→ DropPointProvider. - Ohne
selector: ein Drag-Point mittransform(aus position/rotation, sonst identity), selector undefined. - Mit
selector:findAll(selector, subjectHandle)→ je Sub-Entity ein Drag-Point mittransform = 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).