mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-30 04:37:29 -06:00
Merge pull request #2227 from Messhias/fix/1910-reflect-axis
fix(G11): Reflect X/Y flip the correct axes (#1910)
This commit is contained in:
@@ -76,7 +76,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Transform Each…",
|
||||
["Object", "Transform"],
|
||||
Some("Cmd+Alt+Shift+D"),
|
||||
"{scaleH?: % (100), scaleV?: % (100), moveH?: pt, moveV?: pt (down = +), rotate?: deg (counter-clockwise), reflectX?: bool (flip vertically), reflectY?: bool (flip horizontally), random?: bool, seed?: n, reference?: 0..8 (9-point grid, 4 = centre), copy?: bool, strokes?: bool (Scale Strokes & Effects), corners?: bool (Scale Corners; both default to the preferences), objects?: bool (Transform Objects, default true; false: the art stays and, with patterns, only its pattern tiles transform), patterns?: bool (Transform Patterns; default: prefs transformPatternTiles)} transform every selected object about its own reference point → {ids}",
|
||||
"{scaleH?: % (100), scaleV?: % (100), moveH?: pt, moveV?: pt (down = +), rotate?: deg (counter-clockwise), reflectX?: bool (flip left-right, as Reflect X in the Transform Each dialog), reflectY?: bool (flip top-bottom, as Reflect Y), random?: bool, seed?: n, reference?: 0..8 (9-point grid, 4 = centre), copy?: bool, strokes?: bool (Scale Strokes & Effects), corners?: bool (Scale Corners; both default to the preferences), objects?: bool (Transform Objects, default true; false: the art stays and, with patterns, only its pattern tiles transform), patterns?: bool (Transform Patterns; default: prefs transformPatternTiles)} transform every selected object about its own reference point → {ids}",
|
||||
has_selection,
|
||||
transform_each
|
||||
),
|
||||
@@ -363,7 +363,9 @@ fn transform_each_as(s: &mut Session, p: &Value, label: &str) -> Result<Value> {
|
||||
k_rot = rot * (rng.next() * 2.0 - 1.0);
|
||||
}
|
||||
let o = vectorcraft_geom::reference_point(b, refi);
|
||||
let refl = Affine::scale_non_uniform(if ry { -1.0 } else { 1.0 }, if rx { -1.0 } else { 1.0 });
|
||||
// Reflect X / Reflect Y match Object › Transform › Transform Each and Effect › Distort › Transform:
|
||||
// Reflect X flips left-right (negate x), Reflect Y flips top-bottom (negate y).
|
||||
let refl = Affine::scale_non_uniform(if rx { -1.0 } else { 1.0 }, if ry { -1.0 } else { 1.0 });
|
||||
let m = Affine::translate((k_mh, k_mv))
|
||||
* about(o, Affine::rotate(-k_rot.to_radians()) * refl * Affine::scale_non_uniform(k_sh / 100.0, k_sv / 100.0));
|
||||
if let Some(n) = d.node_mut(*id) {
|
||||
|
||||
@@ -357,6 +357,36 @@ fn transform_each_random_is_deterministic_with_seed() {
|
||||
assert!(x.x0.abs() <= 50.0 && x.width() == 100.0);
|
||||
}
|
||||
|
||||
/// #1910: Transform Each's Reflect X flips left-right; Reflect Y flips top-bottom (same as
|
||||
/// Effect › Distort › Transform and Illustrator's Transform Each checkboxes).
|
||||
#[test]
|
||||
fn transform_each_reflect_x_flips_left_right_reflect_y_flips_top_bottom() {
|
||||
let mut s = session();
|
||||
// A right-pointing triangle: tip at x=100, base on the left.
|
||||
let id =
|
||||
id_of(&s.execute("path.create", &json!({"anchors": [{"x": 0, "y": 0}, {"x": 100, "y": 50}, {"x": 0, "y": 100}], "closed": true})).unwrap());
|
||||
sel(&mut s, &[id]);
|
||||
s.execute("object.transformEach", &json!({"reflectX": true})).unwrap();
|
||||
let tip_x = match &node(&s, id).kind {
|
||||
// The tip is the only vertex at y=50; Reflect X about the centre maps (100, 50) → (0, 50).
|
||||
NodeKind::Path { path, .. } => path.subpaths[0].anchors.iter().find(|a| (a.p.y - 50.0).abs() < 1e-6).map(|a| a.p.x).unwrap_or(f64::NAN),
|
||||
_ => panic!("expected a path"),
|
||||
};
|
||||
assert!((tip_x - 0.0).abs() < 1e-6, "reflectX must move the tip from x=100 to x=0, got {tip_x}");
|
||||
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
// A down-pointing tip at (50, 100); Reflect Y about the centre (50, 50) maps it to (50, 0).
|
||||
let id2 =
|
||||
id_of(&s.execute("path.create", &json!({"anchors": [{"x": 0, "y": 0}, {"x": 100, "y": 0}, {"x": 50, "y": 100}], "closed": true})).unwrap());
|
||||
sel(&mut s, &[id2]);
|
||||
s.execute("object.transformEach", &json!({"reflectY": true})).unwrap();
|
||||
let tip_y = match &node(&s, id2).kind {
|
||||
NodeKind::Path { path, .. } => path.subpaths[0].anchors.iter().find(|a| (a.p.x - 50.0).abs() < 1e-6).map(|a| a.p.y).unwrap_or(f64::NAN),
|
||||
_ => panic!("expected a path"),
|
||||
};
|
||||
assert!((tip_y - 0.0).abs() < 1e-6, "reflectY must move the tip from y=100 to y=0, got {tip_y}");
|
||||
}
|
||||
|
||||
/// Transform Each with its default values, or with any values that move nothing (both scales 100%,
|
||||
/// no move, rotation or reflection, Random or not), records no undo step and replies with the
|
||||
/// objects. With only a layer selected there is no object to transform: with Copy or without, it
|
||||
|
||||
@@ -1083,8 +1083,6 @@
|
||||
Flattener Preview Преглед на сплескването
|
||||
Flip Across Обръщане напречно
|
||||
Flip Along Обръщане надлъжно
|
||||
Flip Along Horizontal Axis Обръщане по хоризонталната ос
|
||||
Flip Along Vertical Axis Обръщане по вертикалната ос
|
||||
Flip Horizontal Хоризонтално обръщане
|
||||
Flip Row Order Обръщане реда на редовете
|
||||
Flip Vertical Вертикално обръщане
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1642,8 +1642,6 @@ lighting Light Světlo
|
||||
Arrange: Bring to Front Uspořádat: přenést do popředí
|
||||
Draw: Kreslení:
|
||||
Edit Artboards Upravit pracovní plochy
|
||||
Flip Along Horizontal Axis Překlopit podle vodorovné osy
|
||||
Flip Along Vertical Axis Překlopit podle svislé osy
|
||||
Hyphenate Dělit slova
|
||||
Isolate Group Izolovat skupinu
|
||||
Landscape Na šířku
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1079,8 +1079,6 @@
|
||||
Flattener Preview Reduzierungsvorschau
|
||||
Flip Across Quer spiegeln
|
||||
Flip Along Längs spiegeln
|
||||
Flip Along Horizontal Axis An horizontaler Achse spiegeln
|
||||
Flip Along Vertical Axis An vertikaler Achse spiegeln
|
||||
Flip Horizontal Horizontal spiegeln
|
||||
Flip Row Order Zeilenreihenfolge umkehren
|
||||
Flip Vertical Vertikal spiegeln
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1096,8 +1096,6 @@
|
||||
Flattener Preview Vista previa del acoplador
|
||||
Flip Across Voltear a través
|
||||
Flip Along Voltear a lo largo
|
||||
Flip Along Horizontal Axis Voltear sobre el eje horizontal
|
||||
Flip Along Vertical Axis Voltear sobre el eje vertical
|
||||
Flip Horizontal Voltear horizontalmente
|
||||
Flip Row Order Invertir orden de filas
|
||||
Flip Vertical Voltear verticalmente
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1095,8 +1095,6 @@
|
||||
Flattener Preview Aperçu de l’aplatissement
|
||||
Flip Across Retourner en travers
|
||||
Flip Along Retourner dans la longueur
|
||||
Flip Along Horizontal Axis Retourner selon l’axe horizontal
|
||||
Flip Along Vertical Axis Retourner selon l’axe vertical
|
||||
Flip Horizontal Retourner horizontalement
|
||||
Flip Row Order Inverser l’ordre des lignes
|
||||
Flip Vertical Retourner verticalement
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1384,8 +1384,6 @@
|
||||
Flip Tükrözés
|
||||
Flip Across Tükrözés keresztben
|
||||
Flip Along Tükrözés hosszában
|
||||
Flip Along Horizontal Axis Tükrözés a vízszintes tengelyre
|
||||
Flip Along Vertical Axis Tükrözés a függőleges tengelyre
|
||||
Flip Horizontal Vízszintes tükrözés
|
||||
Flip Row Order Sorok sorrendjének megfordítása
|
||||
Flip Vertical Függőleges tükrözés
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1095,8 +1095,6 @@
|
||||
Flattener Preview Anteprima appiattimento
|
||||
Flip Across Capovolgi trasversalmente
|
||||
Flip Along Capovolgi longitudinalmente
|
||||
Flip Along Horizontal Axis Capovolgi sull'asse orizzontale
|
||||
Flip Along Vertical Axis Capovolgi sull'asse verticale
|
||||
Flip Horizontal Capovolgi orizzontalmente
|
||||
Flip Row Order Inverti ordine delle righe
|
||||
Flip Vertical Capovolgi verticalmente
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1423,8 +1423,6 @@
|
||||
Flattener preset: 分割・統合プリセット:
|
||||
Flip Across 反転 (横方向)
|
||||
Flip Along 反転 (縦方向)
|
||||
Flip Along Horizontal Axis 水平軸に沿って反転
|
||||
Flip Along Vertical Axis 垂直軸に沿って反転
|
||||
Flip Horizontal 左右反転
|
||||
Flip Row Order 行の順序を反転
|
||||
Flip Vertical 上下反転
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1418,8 +1418,6 @@
|
||||
Flattener preset: 병합 프리셋:
|
||||
Flip Across 기준으로 뒤집기
|
||||
Flip Along 축을 따라 뒤집기
|
||||
Flip Along Horizontal Axis 가로 축 기준 뒤집기
|
||||
Flip Along Vertical Axis 세로 축 기준 뒤집기
|
||||
Flip Horizontal 가로로 뒤집기
|
||||
Flip Row Order 행 순서 뒤집기
|
||||
Flip Vertical 세로로 뒤집기
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1554,8 +1554,6 @@ lighting Light Światło
|
||||
Arrange: Bring to Front Ułóż: przenieś na wierzch
|
||||
Draw: Rysuj:
|
||||
Edit Artboards Edytuj obszary kompozycji
|
||||
Flip Along Horizontal Axis Odbij względem osi poziomej
|
||||
Flip Along Vertical Axis Odbij względem osi pionowej
|
||||
Hyphenate Dziel wyrazy
|
||||
Isolate Group Izoluj grupę
|
||||
Landscape Pozioma
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -964,8 +964,6 @@
|
||||
Flattener preset: Predefinido de achatamento:
|
||||
Flip Across Inverter na Horizontal
|
||||
Flip Along Inverter ao Longo
|
||||
Flip Along Horizontal Axis Inverter ao Longo do Eixo Horizontal
|
||||
Flip Along Vertical Axis Inverter ao Longo do Eixo Vertical
|
||||
Flip Horizontal Espelhar Horizontalmente
|
||||
Flip Row Order Inverter Ordem das Linhas
|
||||
Flip Vertical Espelhar Verticalmente
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1093,8 +1093,6 @@
|
||||
Flattener Preview Предварительный просмотр объединения
|
||||
Flip Across Отразить поперёк
|
||||
Flip Along Отразить вдоль
|
||||
Flip Along Horizontal Axis Отразить по горизонтальной оси
|
||||
Flip Along Vertical Axis Отразить по вертикальной оси
|
||||
Flip Horizontal Отразить по горизонтали
|
||||
Flip Row Order Изменить порядок строк
|
||||
Flip Vertical Отразить по вертикали
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1089,8 +1089,6 @@
|
||||
Flattener Preview Попередній перегляд зведення
|
||||
Flip Across Відобразити поперек
|
||||
Flip Along Відобразити вздовж
|
||||
Flip Along Horizontal Axis Відобразити по горизонтальній осі
|
||||
Flip Along Vertical Axis Відобразити по вертикальній осі
|
||||
Flip Horizontal Відобразити по горизонталі
|
||||
Flip Row Order Змінити порядок рядків
|
||||
Flip Vertical Відобразити по вертикалі
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 713 and column 40.
|
@@ -1261,8 +1261,6 @@
|
||||
Flip Lật
|
||||
Flip Across Lật qua
|
||||
Flip Along Lật theo
|
||||
Flip Along Horizontal Axis Lật theo trục ngang
|
||||
Flip Along Vertical Axis Lật theo trục dọc
|
||||
Flip Horizontal Lật ngang
|
||||
Flip Row Order Đảo thứ tự hàng
|
||||
Flip Vertical Lật dọc
|
||||
|
||||
|
@@ -1046,8 +1046,6 @@
|
||||
Flattener Preview 拼合预览
|
||||
Flip Across 跨轴翻转
|
||||
Flip Along 沿轴翻转
|
||||
Flip Along Horizontal Axis 沿水平轴翻转
|
||||
Flip Along Vertical Axis 沿垂直轴翻转
|
||||
Flip Horizontal 水平翻转
|
||||
Flip Row Order 反转行顺序
|
||||
Flip Vertical 垂直翻转
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1070,8 +1070,6 @@
|
||||
Flattener Preview 平面化預視
|
||||
Flip Across 跨軸翻轉
|
||||
Flip Along 沿軸翻轉
|
||||
Flip Along Horizontal Axis 沿水平軸翻轉
|
||||
Flip Along Vertical Axis 沿垂直軸翻轉
|
||||
Flip Horizontal 水平翻轉
|
||||
Flip Row Order 反轉列順序
|
||||
Flip Vertical 垂直翻轉
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -454,12 +454,12 @@ pub fn transform_section(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
app.run("object.rotate", json!({"angle": a, "absolute": true})).ok();
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
// Lucide's flip icons are named for their mirror line: flip-vertical-2 draws a vertical
|
||||
// line (the left-right flip), flip-horizontal-2 a horizontal one (top-bottom).
|
||||
if widgets::icon_button(ui, "flip-vertical-2", tl!("Flip Along Horizontal Axis"), false, 24.0).clicked() {
|
||||
// Same mapping as the Transform panel (#1910): Lucide flip-vertical-2 is the vertical
|
||||
// mirror line (Flip Horizontal / left-right); flip-horizontal-2 is Flip Vertical.
|
||||
if widgets::icon_button(ui, "flip-vertical-2", tl!("Flip Horizontal"), false, 24.0).clicked() {
|
||||
app.run("object.reflect", json!({"axis": "vertical"})).ok();
|
||||
}
|
||||
if widgets::icon_button(ui, "flip-horizontal-2", tl!("Flip Along Vertical Axis"), false, 24.0).clicked() {
|
||||
if widgets::icon_button(ui, "flip-horizontal-2", tl!("Flip Vertical"), false, 24.0).clicked() {
|
||||
app.run("object.reflect", json!({"axis": "horizontal"})).ok();
|
||||
}
|
||||
// More Options: the Transform panel's Scale Corners and Scale Strokes & Effects, open
|
||||
|
||||
@@ -151,6 +151,9 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
closed, the document left modified (#1865, #1685).
|
||||
- **Done:** the Shape Builder offers the empty areas closed shapes enclose as regions, such as the middle of four
|
||||
circles that touch, and merges them with the regions around them (#1691). Gap Detection is still missing.
|
||||
- **Done (#1910):** Transform Each's Reflect X flips left-right and Reflect Y flips top-bottom (aligned with
|
||||
Effect › Distort › Transform). Properties flip buttons use the same Flip Horizontal / Flip Vertical labels as
|
||||
the Transform panel.
|
||||
- **Missing (noted for reporters, 2026-10-14):** deleting an interior anchor of an open path joins across the gap,
|
||||
where the documented behaviour removes the point and its connecting segments. Inside the estimate below.
|
||||
- **Missing:** Shape Builder misses planar regions and targets whole shapes (#937); Transform effect dialog's invisible checkboxes and missing options (#885);
|
||||
@@ -292,6 +295,7 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-15 | minor | G11: Transform Each Reflect X/Y and Properties flip labels match left-right / top-bottom (#1910). Estimates unchanged. |
|
||||
| 2026-10-14 | minor | Quick Image Trace presets reveal the adjustment panel with Advanced open; Properties reopens it. Sliders keep their preset row until release so the re-trace is committed. UI regressions added; scores and remaining estimates unchanged. |
|
||||
| 2026-10-14 | minor | Revolve: automatic smooth vector shading, default-on Cap with continuous curved rims, and bounded seam joins; angular cut sides remain open. Scores and hour estimates unchanged at this rounding |
|
||||
| 2026-10-14 | minor | No entry closed. G8 and G11 record the later merges of 2026-10-14 (#1852, #1862–#1865, #1871–#1873, #1839, #1840, #1856); #1683 (Dim Images) and #1685 (failed-save dialog) are done by #1864 and #1865. Gaps noted for reporters: G1 Effect › Warp through Warp Options (#1760), Color Picker Tab order (#1692), aligning to a key anchor (#1636; the public Align page does not say how the key anchor is chosen); G7 custom toolbars (#1759), workspace panel widths (#1753); G11 Shape Builder regions between closed shapes (#1691), deleting an interior anchor of an open path; G13 Intertwine (#1763), gradient mesh from an embedded image (#1676), Image Trace radial gradients (draft #1849). Average and Join with a corner or smooth choice was already listed (G1). G12: a line two merges had left twice is there once, without Appearance of Black for output, which acts since #1750. Estimates unchanged |
|
||||
|
||||
Reference in New Issue
Block a user