mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Merge pull request #3056 from nrq6993-a11y/stream/vc-feat1-g5-art-brush-overlap
G5: Art brush Overlap option in Brush Options
This commit is contained in:
@@ -287,6 +287,8 @@ pub struct ArtBrush {
|
||||
pub width: f64,
|
||||
pub flip_along: bool,
|
||||
pub flip_across: bool,
|
||||
/// When true, art is placed on each run between sharp corners so folds do not overlap.
|
||||
pub overlap: bool,
|
||||
pub colorization: Colorization,
|
||||
}
|
||||
|
||||
@@ -304,6 +306,7 @@ impl Default for ArtBrush {
|
||||
width: 100.0,
|
||||
flip_along: false,
|
||||
flip_across: false,
|
||||
overlap: false,
|
||||
colorization: Colorization::Tints,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +152,28 @@ fn art_brush_between_guides_keeps_ends() {
|
||||
assert!(near(h.x0, 280.0, 1e-6) && near(h.x1, 300.0, 1e-6), "{h:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn art_brush_overlap_splits_at_corners() {
|
||||
let mut bp = BezPath::new();
|
||||
bp.move_to((0.0, 0.0));
|
||||
bp.line_to((100.0, 0.0));
|
||||
bp.line_to((100.0, 100.0));
|
||||
let brush = |overlap: bool| Brush {
|
||||
name: "a".into(),
|
||||
kind: BrushKind::Art(ArtBrush {
|
||||
art: rect_art(10.0, 4.0),
|
||||
scale: ArtScale::Stretch,
|
||||
overlap,
|
||||
colorization: Colorization::None,
|
||||
..Default::default()
|
||||
}),
|
||||
};
|
||||
let one = stroke_pieces(&Document::new(1.0, 1.0), &brush(false), &bp, &stroke(1.0));
|
||||
let two = stroke_pieces(&Document::new(1.0, 1.0), &brush(true), &bp, &stroke(1.0));
|
||||
assert_eq!(one.len(), 1, "one bent copy along the whole path");
|
||||
assert_eq!(two.len(), 2, "one copy per run between corners");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn art_brush_follows_curves() {
|
||||
let bp = shapes::ellipse(Rect::new(0.0, 0.0, 200.0, 200.0)).to_bezpath();
|
||||
|
||||
+51
-21
@@ -154,35 +154,65 @@ fn bend(t: &Track, art: &Node, b: Rect, along: AlongMap, cross: f64) -> Option<N
|
||||
warp_node(art, &f, flat_tol, MAX_SEG / along.max_scale(), cross.abs())
|
||||
}
|
||||
|
||||
/// Arc-length spans to place art on when [`ArtBrush::overlap`] is on: one run between each sharp
|
||||
/// corner (the whole path when it has none).
|
||||
fn art_runs(t: &Track) -> Vec<(f64, f64)> {
|
||||
let l = t.len();
|
||||
let corners = t.corner_positions();
|
||||
if corners.is_empty() {
|
||||
return vec![(0.0, l)];
|
||||
}
|
||||
if t.closed {
|
||||
let first = corners[0].1;
|
||||
let mut bounds = corners.iter().map(|c| c.1).collect::<Vec<_>>();
|
||||
bounds.push(first + l);
|
||||
return bounds.windows(2).map(|w| (w[0], w[1])).collect();
|
||||
}
|
||||
let mut bounds = vec![0.0];
|
||||
bounds.extend(corners.iter().map(|c| c.1));
|
||||
bounds.push(l);
|
||||
bounds.windows(2).map(|w| (w[0], w[1])).collect()
|
||||
}
|
||||
|
||||
fn art_on_run(a: &ArtBrush, t: &Track, s0: f64, s1: f64, art: &Node, b: Rect, cross: f64) -> Option<Node> {
|
||||
let l = s1 - s0;
|
||||
if l <= 1e-9 {
|
||||
return None;
|
||||
}
|
||||
let w = b.width();
|
||||
let (along, cross) = match a.scale {
|
||||
ArtScale::Stretch => (AlongMap::linear(w, s0, s1), cross),
|
||||
ArtScale::Proportional => {
|
||||
let k = l / w;
|
||||
(AlongMap::linear(w, s0, s1), k * a.width / 100.0)
|
||||
}
|
||||
ArtScale::BetweenGuides { start, end } => {
|
||||
let (g0, g1) = (start.clamp(0.0, 1.0) * w, end.clamp(0.0, 1.0) * w);
|
||||
let (g0, g1) = (g0.min(g1), g0.max(g1));
|
||||
let fixed = (g0 + (w - g1)) * cross;
|
||||
if fixed >= l || g1 - g0 < 1e-9 {
|
||||
(AlongMap::linear(w, s0, s1), cross)
|
||||
} else {
|
||||
(AlongMap { xs: [0.0, g0, g1, w], ss: [s0, s0 + g0 * cross, s1 - (w - g1) * cross, s1] }, cross)
|
||||
}
|
||||
}
|
||||
};
|
||||
bend(t, art, b, along, cross)
|
||||
}
|
||||
|
||||
pub(crate) fn art(a: &ArtBrush, bp: &BezPath, weight: f64) -> Vec<Node> {
|
||||
let Some((art, b)) = oriented(&a.art, a.direction, a.flip_along, a.flip_across) else { return vec![] };
|
||||
let cross = weight * a.width / 100.0;
|
||||
let mut out = vec![];
|
||||
for t in tracks(bp, 0.05) {
|
||||
let l = t.len();
|
||||
if l <= 1e-9 {
|
||||
if t.len() <= 1e-9 {
|
||||
continue;
|
||||
}
|
||||
let w = b.width();
|
||||
let (along, cross) = match a.scale {
|
||||
ArtScale::Stretch => (AlongMap::linear(w, 0.0, l), cross),
|
||||
ArtScale::Proportional => {
|
||||
let k = l / w;
|
||||
(AlongMap::linear(w, 0.0, l), k * a.width / 100.0)
|
||||
let runs = if a.overlap { art_runs(&t) } else { vec![(0.0, t.len())] };
|
||||
for (s0, s1) in runs {
|
||||
if let Some(n) = art_on_run(a, &t, s0, s1, &art, b, cross) {
|
||||
out.push(n);
|
||||
}
|
||||
ArtScale::BetweenGuides { start, end } => {
|
||||
let (g0, g1) = (start.clamp(0.0, 1.0) * w, end.clamp(0.0, 1.0) * w);
|
||||
let (g0, g1) = (g0.min(g1), g0.max(g1));
|
||||
let fixed = (g0 + (w - g1)) * cross;
|
||||
if fixed >= l || g1 - g0 < 1e-9 {
|
||||
(AlongMap::linear(w, 0.0, l), cross)
|
||||
} else {
|
||||
(AlongMap { xs: [0.0, g0, g1, w], ss: [0.0, g0 * cross, l - (w - g1) * cross, l] }, cross)
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(n) = bend(&t, &art, b, along, cross) {
|
||||
out.push(n);
|
||||
}
|
||||
}
|
||||
out
|
||||
|
||||
@@ -89,7 +89,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Brush Options…",
|
||||
[],
|
||||
None,
|
||||
"{name, params?: {…fields to change (brush.get shows them; values outside their ranges are clamped). calligraphic: angle −180..180°, roundness 0..100%, size 0..1296 pt, variation: [angle°, roundness%, size pt], modes: [fixed|random|pressure for angle, roundness, size] (pressure goes from value − variation at the lightest pen pressure to value + variation at the heaviest). scatter: size [a, b] 1..10000%, spacing [a, b] 1..10000%, scatter [a, b] −1000..1000%, rotation [a, b] −180..180°, modes: [fixed|random|pressure for size, spacing, scatter, rotation] (fixed: a; random: between a and b; pressure: a at the lightest pen pressure to b at the heaviest), rotation_relative_to_path. art: width 1..1000%, scale: {mode: proportional|stretch|betweenGuides, start, end: 0..1 of the art length}, direction: leftToRight|rightToLeft|topToBottom|bottomToTop, flip_along, flip_across. pattern: scale 1..10000%, spacing 0..10000%, fit: stretch|addSpace|approximate, flip_along, flip_across. scatter, art and pattern: colorization: {method: none|tints|tintsAndShades|hueShift, key: colour (hueShift: the art colour that becomes the stroke colour)}}, newName? (trimmed; blank: the name is kept)} edit a brush definition (strokes using it update) → {name}",
|
||||
"{name, params?: {…fields to change (brush.get shows them; values outside their ranges are clamped). calligraphic: angle −180..180°, roundness 0..100%, size 0..1296 pt, variation: [angle°, roundness%, size pt], modes: [fixed|random|pressure for angle, roundness, size] (pressure goes from value − variation at the lightest pen pressure to value + variation at the heaviest). scatter: size [a, b] 1..10000%, spacing [a, b] 1..10000%, scatter [a, b] −1000..1000%, rotation [a, b] −180..180°, modes: [fixed|random|pressure for size, spacing, scatter, rotation] (fixed: a; random: between a and b; pressure: a at the lightest pen pressure to b at the heaviest), rotation_relative_to_path. art: width 1..1000%, scale: {mode: proportional|stretch|betweenGuides, start, end: 0..1 of the art length}, direction: leftToRight|rightToLeft|topToBottom|bottomToTop, flip_along, flip_across, overlap. pattern: scale 1..10000%, spacing 0..10000%, fit: stretch|addSpace|approximate, flip_along, flip_across. scatter, art and pattern: colorization: {method: none|tints|tintsAndShades|hueShift, key: colour (hueShift: the art colour that becomes the stroke colour)}}, newName? (trimmed; blank: the name is kept)} edit a brush definition (strokes using it update) → {name}",
|
||||
has_doc,
|
||||
brush_options
|
||||
),
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
//! Scatter: per value (`size`, `spacing`, `scatter` %, `rotation` °) `…Min`, `…Max` and `…Mode`
|
||||
//! (`fixed` | `random` | `pressure`), `rotationRelativeTo` (`page` | `path`).
|
||||
//! Art: `width` (%), `scaleMode` (`proportional` | `stretch` | `betweenGuides`), `guideStart` and
|
||||
//! `guideEnd` (% of the art's length), `direction` (`leftToRight` …), `flipAlong`, `flipAcross`.
|
||||
//! `guideEnd` (% of the art's length), `direction` (`leftToRight` …), `flipAlong`, `flipAcross`,
|
||||
//! `overlap` (bend on each run between sharp corners).
|
||||
//! Pattern: `scale`, `spacing` (%), `fit` (`stretch` | `addSpace` | `approximate`), `flipAlong`,
|
||||
//! `flipAcross`, `__tiles` (slot → preview key, for the tiles the brush has).
|
||||
|
||||
@@ -96,6 +97,7 @@ pub(super) fn fields(b: &Brush, def: Value, f: &mut Map<String, Value>) {
|
||||
f.insert("direction".into(), json!(id_of(&a.direction)));
|
||||
f.insert("flipAlong".into(), json!(a.flip_along));
|
||||
f.insert("flipAcross".into(), json!(a.flip_across));
|
||||
f.insert("overlap".into(), json!(a.overlap));
|
||||
}
|
||||
BrushKind::Pattern(p) => {
|
||||
f.insert("scale".into(), json!(p.scale));
|
||||
@@ -168,6 +170,7 @@ pub(super) fn params(d: &Dialog) -> Value {
|
||||
"direction": id_of(&parse_field::<Direction>(d, "direction")),
|
||||
"flip_along": d.bool("flipAlong"),
|
||||
"flip_across": d.bool("flipAcross"),
|
||||
"overlap": d.bool("overlap"),
|
||||
})
|
||||
}
|
||||
_ => json!({
|
||||
@@ -284,6 +287,8 @@ fn art_body(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
}
|
||||
});
|
||||
flips(ui, d);
|
||||
ui.add_space(4.0);
|
||||
super::form::check(ui, d, "overlap", tl!("Overlap"));
|
||||
}
|
||||
|
||||
/// A toggle button showing an arrow pointing the way `dir` runs. Whether it was clicked.
|
||||
|
||||
@@ -2112,6 +2112,7 @@
|
||||
Output White Изходно бяло
|
||||
Output › Mode Изход › Режим
|
||||
Output: Изход:
|
||||
Overlap Застъпване
|
||||
Overlap: Застъпване:
|
||||
Overlapping Застъпващи се
|
||||
Overlay Прекриване
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1788,6 +1788,7 @@ lighting Light Světlo
|
||||
Left in Front Levý vpředu
|
||||
No document Žádný dokument
|
||||
Open a document to edit its patterns. Otevřete dokument, abyste mohli upravit jeho vzorky.
|
||||
Overlap Překrytí
|
||||
Overlap: Překrytí:
|
||||
Pattern options are available in pattern editing mode. Možnosti vzorku jsou dostupné v režimu úprav vzorku.
|
||||
Right in Front Pravý vpředu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1607,6 +1607,7 @@ lighting Light Lys
|
||||
Left in Front Venstre forrest
|
||||
No document Intet dokument
|
||||
Open a document to edit its patterns. Åbn et dokument for at redigere dets mønstre.
|
||||
Overlap Overlap
|
||||
Overlap: Overlap:
|
||||
Pattern options are available in pattern editing mode. Mønsterindstillinger er tilgængelige i mønsterredigeringstilstand.
|
||||
Right in Front Højre forrest
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2130,6 +2130,7 @@ file-filter Templates Vorlagen
|
||||
Output White Ausgabe Weiß
|
||||
Output › Mode Ausgabe › Modus
|
||||
Output: Ausgabe:
|
||||
Overlap Überlappung
|
||||
Overlap: Überlappung:
|
||||
Overlapping Überlappend
|
||||
Overlay Ineinanderkopieren
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2771,6 +2771,7 @@ theme Appearance Εμφάνιση
|
||||
Output intent profile: Προφίλ προορισμού εξόδου:
|
||||
Output White Λευκό εξόδου
|
||||
Output › Mode Έξοδος › Λειτουργία
|
||||
Overlap Επικάλυψη
|
||||
Overlap: Επικάλυψη:
|
||||
Overlapping Επικαλυπτόμενα
|
||||
Overprint Υπερεκτύπωση
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2016 and column 19.
|
@@ -2155,6 +2155,7 @@
|
||||
Output White Blanco de salida
|
||||
Output › Mode Salida › Modo
|
||||
Output: Salida:
|
||||
Overlap Superposición
|
||||
Overlap: Superposición:
|
||||
Overlapping Superpuesto
|
||||
Overlay Superponer
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1751,6 +1751,7 @@ lighting Light Valo
|
||||
Left in Front Vasen edessä
|
||||
No document Ei asiakirjaa
|
||||
Open a document to edit its patterns. Avaa asiakirja, niin voit muokata sen kuvioita.
|
||||
Overlap Limitys
|
||||
Overlap: Limitys:
|
||||
Pattern options are available in pattern editing mode. Kuvioasetukset ovat käytettävissä kuvion muokkaustilassa.
|
||||
Right in Front Oikea edessä
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2152,6 +2152,7 @@
|
||||
Output White Blanc de sortie
|
||||
Output › Mode Sortie › Mode
|
||||
Output: Sortie :
|
||||
Overlap Chevauchement
|
||||
Overlap: Chevauchement :
|
||||
Overlapping Superposés
|
||||
Overlay Incrustation
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2640,6 +2640,7 @@ file-filter Templates Sablonok
|
||||
Output › Mode Kimenet › Mód
|
||||
Output: Kimenet:
|
||||
Oval Ovális
|
||||
Overlap Átfedés
|
||||
Overlap: Átfedés:
|
||||
Overlapping Átfedő
|
||||
Overlay Átfedés
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1607,6 +1607,7 @@ lighting Light Cahaya
|
||||
Left in Front Kiri di depan
|
||||
No document Tidak ada dokumen
|
||||
Open a document to edit its patterns. Buka dokumen untuk mengedit polanya.
|
||||
Overlap Tumpang tindih
|
||||
Overlap: Tumpang tindih:
|
||||
Pattern options are available in pattern editing mode. Opsi pola tersedia dalam mode pengeditan pola.
|
||||
Right in Front Kanan di depan
|
||||
|
||||
|
@@ -2181,6 +2181,7 @@ file-filter Templates Modelli
|
||||
Output White Bianco di output
|
||||
Output › Mode Output › Modalità
|
||||
Output: Output:
|
||||
Overlap Sovrapposizione
|
||||
Overlap: Sovrapposizione:
|
||||
Overlapping Sovrapposti
|
||||
Overlay Sovrapponi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2245,6 +2245,7 @@
|
||||
Output condition: 出力条件:
|
||||
Output intent profile: 出力インテントプロファイル:
|
||||
Output: 出力:
|
||||
Overlap 重なり
|
||||
Overlap: 重なり:
|
||||
Overlapping 重なり
|
||||
Overlay オーバーレイ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1509,6 +1509,7 @@ lighting Light სინათლე
|
||||
Left in Front მარცხენა წინ
|
||||
No document დოკუმენტი არ არის
|
||||
Open a document to edit its patterns. გახსენით დოკუმენტი მისი პატერნების რედაქტირებისთვის.
|
||||
Overlap გადაფარვა
|
||||
Overlap: გადაფარვა:
|
||||
Pattern options are available in pattern editing mode. პატერნის პარამეტრები ხელმისაწვდომია პატერნის რედაქტირების რეჟიმში.
|
||||
Right in Front მარჯვენა წინ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2240,6 +2240,7 @@
|
||||
Output condition: 출력 조건:
|
||||
Output intent profile: 출력 의도 프로파일:
|
||||
Output: 출력:
|
||||
Overlap 겹침
|
||||
Overlap: 겹침:
|
||||
Overlapping 겹침
|
||||
Overlay 오버레이
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1621,6 +1621,7 @@ lighting Light Licht
|
||||
Left in Front Linkerkant vooraan
|
||||
No document Geen document
|
||||
Open a document to edit its patterns. Open een document om de patronen te bewerken.
|
||||
Overlap Overlap
|
||||
Overlap: Overlap:
|
||||
Pattern options are available in pattern editing mode. Patroonopties zijn beschikbaar in de patroonbewerkingsmodus.
|
||||
Right in Front Rechterkant vooraan
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1708,6 +1708,7 @@ lighting Light Światło
|
||||
Left in Front Lewy na wierzchu
|
||||
No document Brak dokumentu
|
||||
Open a document to edit its patterns. Otwórz dokument, aby edytować jego wzorki.
|
||||
Overlap Nakładanie
|
||||
Overlap: Nakładanie:
|
||||
Pattern options are available in pattern editing mode. Opcje wzorka są dostępne w trybie edycji wzorka.
|
||||
Right in Front Prawy na wierzchu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1770,6 +1770,7 @@
|
||||
Output condition: Condição de saída:
|
||||
Output intent profile: Perfil de intenção de saída:
|
||||
Output: Saída:
|
||||
Overlap Sobreposição
|
||||
Overlap: Sobreposição:
|
||||
Overlapping Sobreposto
|
||||
Overlay Sobrepor
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2177,6 +2177,7 @@ file-filter Templates Шаблоны
|
||||
Output White Выходной белый
|
||||
Output › Mode Вывод › Режим
|
||||
Output: Вывод:
|
||||
Overlap Перекрытие
|
||||
Overlap: Перекрытие:
|
||||
Overlapping Перекрывающийся
|
||||
Overlay Перекрытие
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2112,6 +2112,7 @@
|
||||
Output White Vitt i utgång
|
||||
Output › Mode Utgång › Läge
|
||||
Output: Utgång:
|
||||
Overlap Överlappning
|
||||
Overlap: Överlappning:
|
||||
Overlapping Överlappande
|
||||
Overlay Överlägg
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -2173,6 +2173,7 @@ file-filter Templates Шаблони
|
||||
Output White Вихідний білий
|
||||
Output › Mode Виведення › Режим
|
||||
Output: Виведення:
|
||||
Overlap Перекриття
|
||||
Overlap: Перекриття:
|
||||
Overlapping Перекривається
|
||||
Overlay Накладання
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 725 and column 40.
|
@@ -2448,6 +2448,7 @@ file-filter Templates Mẫu
|
||||
Output › Mode Đầu ra › Chế độ
|
||||
Output: Đầu ra:
|
||||
Outside Bên ngoài
|
||||
Overlap Chồng lấp
|
||||
Overlap: Chồng lấp:
|
||||
Overlapping Chồng lấp
|
||||
Overlay Phủ lên
|
||||
|
||||
|
@@ -2070,6 +2070,7 @@ file-filter Templates 模板
|
||||
Output White 输出白色
|
||||
Output › Mode 输出 › 模式
|
||||
Output: 输出:
|
||||
Overlap 重叠
|
||||
Overlap: 重叠:
|
||||
Overlapping 重叠
|
||||
Overlay 叠加
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2898,6 +2898,7 @@ file-filter Templates 範本
|
||||
Output White 輸出白色
|
||||
Output › Mode 輸出 › 模式
|
||||
Output: 輸出:
|
||||
Overlap 重疊
|
||||
Overlap: 重疊:
|
||||
Overlapping 重疊
|
||||
Overlay 覆蓋
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
Reference in New Issue
Block a user