🐛 Keep inherited root orientation through a variant switch

Use the root's effective touched groups after the reference-chain merge
when preserving its orientation. A near main may author the rotation
while the selected copy remains untouched. Checking only the selected
shape drops that inherited override during the switch.

The portable regression fails before the fix and passes four assertions
afterwards. Focused swap and generated checks pass 42 tests and 165
assertions.

Benchmark vs Phase 1e: main 10/100/1000 0.56/0.58/0.67; levels 0.61;
chain 0.57; library 0.53; many shapes 0.69; switch 0.70. No flags.

AI-assisted-by: GPT-6
This commit is contained in:
alonso.torres 2026-10-23 20:01:22 +02:00
parent 9f10e5e7c3
commit f01b260f74
2 changed files with 22 additions and 1 deletions

View File

@ -422,7 +422,8 @@
changes
pairs)
changes (cond-> changes
(ctk/touched-group? original-shape :geometry-group)
(some #(and (= (:id %) (:id original-shape))
(ctk/touched-group? % :geometry-group)) orig-touched)
(keep-orientation-override original-shape new-shape page
(or (get-in libraries [(:component-file new-shape) :data]) ldata)
(:component-id new-shape)))]

View File

@ -749,3 +749,23 @@
(t/is (ctk/touched-group? head :geometry-group))
(t/is (mth/close? 45 (:rotation head) 0.001))
(t/is (= (orientation file :card-star) (orientation full :card-star)))))
(t/deftest switch-keeps-root-orientation-authored-in-a-near-main
(let [initial (reduce #(tm/apply-to %2 %1) (setups/empty-situation)
[(n/create-component "variant" setups/labeled-fill :size 100)
(n/make-variant-container "variants"
[["a" setups/labeled-fill]
["b" setups/labeled-fill]] :size 100)
(n/make-nested-component-with-variant "variant" "variants" "a")
(n/make-nested-component "variant" 1)])
source (n/nested-head-of "variant" 0)
target (n/nested-head-of "variant" 1)
before (-> initial (r/step (n/rotate source 45)) r/settle)
swapped (-> before (r/step (n/switch-variant target "b")) r/settle)
head (tm/shape-by-id swapped (target swapped))
file (tm/file swapped)
full (:file (r/sync-cascade file {} (keys (get-in file [:data :components]))))]
(t/is (nil? (:touched (tm/shape-by-id before (target before)))))
(t/is (ctk/touched-group? head :geometry-group))
(t/is (mth/close? 45 (:rotation head) 0.001))
(t/is (gsh/close-attrs? :points (:points head) (:points (ths/get-shape-by-id full (:id head))) 0.001))))