diff --git a/crates/cad/src/lib.rs b/crates/cad/src/lib.rs index 4afe84e33..51bcd8c2a 100644 --- a/crates/cad/src/lib.rs +++ b/crates/cad/src/lib.rs @@ -277,6 +277,8 @@ pub struct DxfOptions { pub colors: ColorDepth, pub raster: RasterFormat, pub preserve: Preserve, + /// Write one zero-width centerline per stroked path, ignoring its fill and stroke outline. + pub centerline_strokes: bool, /// Alter Paths for Appearance: every stroke is written as the filled area it paints. pub alter_paths: bool, /// Type is written as glyph outlines (always with [`Preserve::Appearance`]). @@ -297,6 +299,7 @@ impl Default for DxfOptions { colors: ColorDepth::default(), raster: RasterFormat::default(), preserve: Preserve::default(), + centerline_strokes: false, alter_paths: false, outline_text: false, region: Rect::ZERO, diff --git a/crates/cad/src/scene.rs b/crates/cad/src/scene.rs index 22fb18872..5cee1b50c 100644 --- a/crates/cad/src/scene.rs +++ b/crates/cad/src/scene.rs @@ -457,21 +457,39 @@ impl<'a> Scene<'a> { if bp.elements().is_empty() { return; } + let centerline = self.o.centerline_strokes + && n.appearance + .items + .iter() + .any(|item| matches!(item, AppearanceItem::Stroke(st) if st.visible && st.width > 0.0 && st.width.is_finite())); + let mut wrote_centerline = false; for item in &n.appearance.items { match item { + AppearanceItem::Fill(_) if centerline => {} AppearanceItem::Fill(f) if f.visible => { if let Some(rgb) = self.paint_rgb(&f.paint) { let style = self.style(rgb, f.opacity, None, None); self.area(bp, rule, &style, false); } } - AppearanceItem::Stroke(st) if st.visible && st.width > 0.0 && st.width.is_finite() => self.stroke(bp, rule, st), + // One centerline per path, however many strokes it has. + AppearanceItem::Stroke(st) if st.visible && st.width > 0.0 && st.width.is_finite() && !(centerline && wrote_centerline) => { + self.stroke(bp, rule, st, centerline); + wrote_centerline |= centerline; + } _ => {} } } } - fn stroke(&mut self, bp: &BezPath, rule: FillRule, st: &StrokeLayer) { + fn stroke(&mut self, bp: &BezPath, rule: FillRule, st: &StrokeLayer, centerline: bool) { + if centerline { + let Some(rgb) = self.paint_rgb(&st.paint) else { return }; + let linetype = st.dash.as_ref().filter(|d| d.is_dashed()).map(|d| self.linetype(d)); + let style = self.style(rgb, st.opacity, Some(0.0), linetype); + self.lines(bp, &style, 0.0); + return; + } let appearance = self.o.preserve == Preserve::Appearance; if appearance && st.brush.is_some() diff --git a/crates/cad/src/tests.rs b/crates/cad/src/tests.rs index 996f6fbac..37d1dbc80 100644 --- a/crates/cad/src/tests.rs +++ b/crates/cad/src/tests.rs @@ -125,6 +125,27 @@ fn every_version_declares_its_acadver_and_is_well_formed() { assert_eq!(DxfVersion::from_id("2019"), None); } +#[test] +fn r12_viewport_has_no_duplicate_group_codes() { + let d = shapes_doc(); + let out = export(&d, &DxfOptions { version: DxfVersion::R12, ..opts(&d) }).unwrap(); + let vport = table(&out, "VPORT").into_iter().find(|o| kind(o) == "VPORT").expect("VPORT table record"); + let codes: Vec = vport.iter().map(|pair| pair.0).collect(); + let unique: std::collections::HashSet<_> = codes.iter().collect(); + assert_eq!(unique.len(), codes.len(), "R12 VPORT record has duplicate group codes: {vport:?}"); + let z = vport.iter().find(|pair| pair.0 == 36).map(|pair| pair.1.trim().parse::().unwrap()); + assert_eq!(z, Some(1.0), "the view direction looks down the z axis"); +} + +#[test] +fn centerline_strokes_write_one_line_per_stroked_path_and_no_fill() { + let d = shapes_doc(); + let out = export(&d, &DxfOptions { centerline_strokes: true, ..opts(&d) }).unwrap(); + let k = kinds(&out); + assert!(k.iter().all(|kind| kind != "HATCH"), "the stroked rectangle's fill is left out: {k:?}"); + assert_eq!(k.len(), 2, "one centerline for each of the two stroked paths: {k:?}"); +} + #[test] fn lines_are_lwpolylines_curves_splines_and_fills_hatches() { let d = shapes_doc(); diff --git a/crates/cad/src/writer.rs b/crates/cad/src/writer.rs index 2fe4ec396..665f8576f 100644 --- a/crates/cad/src/writer.rs +++ b/crates/cad/src/writer.rs @@ -441,7 +441,8 @@ impl Drawing { c.xy(13, 0.0, 0.0); c.xy(14, 1.0, 1.0); c.xy(15, 10.0, 10.0); - c.xyz(16, 0.0, 0.0); + // The view direction looks down the z axis: (0, 0, 1), each code once. + c.xy(16, 0.0, 0.0); c.num(36, 1.0); c.xyz(17, 0.0, 0.0); let (w, h) = ((x1 - x0).abs(), (y1 - y0).abs()); diff --git a/crates/engine/src/cmd/fileio/dxf.rs b/crates/engine/src/cmd/fileio/dxf.rs index c13b4fdb8..30682760a 100644 --- a/crates/engine/src/cmd/fileio/dxf.rs +++ b/crates/engine/src/cmd/fileio/dxf.rs @@ -21,7 +21,7 @@ pub fn specs() -> Vec { "Export DXF", [], None, - "{path?, version?: R12|R13|R14|2000|2004|2007|2010|2013|2018 (default), unit?: mm (default; any unit name: pt, in, cm…), scale?: 1 (drawing units per unit), scaleLineweights?: false, colors?: 8|16|256|true (default; true colour needs 2004+, else 256), rasterFormat?: png (default)|jpeg (placed images, written next to the file), preserve?: appearance (default: type as outlines; strokes a CAD line can't draw as filled outlines; brush art)|editability (type as text; every stroke a line with its lineweight and dashes), alterPaths?: false (every stroke as its filled outline), outlineText?: false, selectedOnly?: false (the selected objects, in their layers), artboard?: 0 (the origin is its bottom-left corner), useArtboards?: true (one drawing per chosen artboard, artboards?/range?, holding the art over it: {stem}-{artboard}.dxf) | false (the origin at the art's bounds)} → {path, bytes, warnings, files?, linked?: [image files]}; no path → {dataBase64, …, linked?: [{name, dataBase64}]}. Layers become DXF layers (hidden: off; locked; non-printing: not plotted); paths become polylines and splines, fills their outlines (which laser and cutter software reads) and solid hatches. Same as document.export {format: dxf}", + "{path?, version?: R12|R13|R14|2000|2004|2007|2010|2013|2018 (default), unit?: mm (default; any unit name: pt, in, cm…), scale?: 1 (drawing units per unit), scaleLineweights?: false, colors?: 8|16|256|true (default; true colour needs 2004+, else 256), rasterFormat?: png (default)|jpeg (placed images, written next to the file), preserve?: appearance (default: type as outlines; strokes a CAD line can't draw as filled outlines; brush art)|editability (type as text; every stroke a line with its lineweight and dashes), centerlineStrokes?: false (one zero-width centerline per stroked path; omits its fill), alterPaths?: false (every stroke as its filled outline), outlineText?: false, selectedOnly?: false (the selected objects, in their layers), artboard?: 0 (the origin is its bottom-left corner), useArtboards?: true (one drawing per chosen artboard, artboards?/range?, holding the art over it: {stem}-{artboard}.dxf) | false (the origin at the art's bounds)} → {path, bytes, warnings, files?, linked?: [image files]}; no path → {dataBase64, …, linked?: [{name, dataBase64}]}. Layers become DXF layers (hidden: off; locked; non-printing: not plotted); paths become polylines and splines, fills their outlines (which laser and cutter software reads) and solid hatches. Same as document.export {format: dxf}", has_doc, export_dxf )] @@ -60,6 +60,12 @@ pub(super) const OPTIONS: &[FormatOption] = &[ default: "\"appearance\"", description: "appearance (type as outlines, strokes a CAD line can't draw as filled outlines) or editability (type as text, strokes as lines)", }, + FormatOption { + name: "centerlineStrokes", + ty: "boolean", + default: "false", + description: "one zero-width centerline per stroked path; omits the path's fill and stroke outline", + }, FormatOption { name: "alterPaths", ty: "boolean", @@ -121,6 +127,7 @@ struct Params { colors: Option, raster_format: Option, preserve: Option, + centerline_strokes: Option, alter_paths: Option, outline_text: Option, } @@ -163,6 +170,7 @@ fn parse(p: &Value) -> Result<(DxfOptions, ArtboardPick)> { colors: choice("colors", q.colors.as_ref().map(text), ColorDepth::from_id, d.colors, "8, 16, 256 or true")?, raster: choice("rasterFormat", q.raster_format, RasterFormat::from_id, d.raster, "png or jpeg")?, preserve: choice("preserve", q.preserve, Preserve::from_id, d.preserve, "appearance or editability")?, + centerline_strokes: q.centerline_strokes.unwrap_or(d.centerline_strokes), alter_paths: q.alter_paths.unwrap_or(d.alter_paths), outline_text: q.outline_text.unwrap_or(d.outline_text), ..d diff --git a/crates/ui-egui/src/dialogs/dxf_options.rs b/crates/ui-egui/src/dialogs/dxf_options.rs index 3593dfe91..3ed3278d9 100644 --- a/crates/ui-egui/src/dialogs/dxf_options.rs +++ b/crates/ui-egui/src/dialogs/dxf_options.rs @@ -1,6 +1,6 @@ //! DXF Options (Export As → DXF): version, scale (1 unit of the art = N drawing units) and //! lineweights, number of colours, the format of placed images, Preserve Appearance or Maximize -//! Editability, and Export Selected Art Only, Alter Paths for Appearance and Outline Text. +//! Editability, centerline stroke output, Export Selected Art Only, Alter Paths for Appearance and Outline Text. //! //! Fields: `document.export` params (`format: dxf`, `path?`, the artboard choice) and the DXF //! options of `document.exportDxf`. OK remembers the options for next time and writes the file @@ -42,6 +42,7 @@ fn defaults() -> Map { ("colors", json!(ColorDepth::default().id())), ("rasterFormat", json!(RasterFormat::default().id())), ("preserve", json!(Preserve::default().id())), + ("centerlineStrokes", json!(false)), ("alterPaths", json!(false)), ("outlineText", json!(false)), ("selectedOnly", json!(false)), @@ -65,6 +66,18 @@ pub fn open(app: &mut VectorcraftApp, params: &Value) { } fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { + if widgets::flat_button(ui, tl!("3ds Max — R12 Linework"), 210.0).clicked() { + d.fields.insert("version".into(), json!(DxfVersion::R12.id())); + d.fields.insert("unit".into(), json!(Unit::Millimeters.label())); + d.fields.insert("scale".into(), json!(1)); + d.fields.insert("preserve".into(), json!(Preserve::Editability.id())); + d.fields.insert("centerlineStrokes".into(), json!(true)); + d.fields.insert("colors".into(), json!(ColorDepth::Aci256.id())); + d.fields.insert("outlineText".into(), json!(true)); + d.fields.insert("alterPaths".into(), json!(false)); + d.fields.insert("scaleLineweights".into(), json!(false)); + } + ui.add_space(6.0); let versions: Vec<(&str, &str)> = DxfVersion::ALL.iter().map(|v| (v.id(), v.label())).collect(); choice(ui, d, "version", tl!("Version:"), &versions); ui.add_space(4.0); @@ -99,6 +112,7 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { d.fields.insert("selectedOnly".into(), json!(!d.bool("selectedOnly"))); } check(ui, d, "alterPaths", tl!("Alter Paths for Appearance")); + check(ui, d, "centerlineStrokes", tl!("Export Strokes as Centerlines (0 width)")); // Preserve Appearance always outlines type. let appearance = preserve == Preserve::Appearance; if widgets::check(ui, tl!("Outline Text"), appearance || d.bool("outlineText"), !appearance) { @@ -107,9 +121,13 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { ui.add_space(8.0); super::form::caption( ui, - match preserve { - Preserve::Appearance => tl!("Type becomes outlines, and strokes a CAD line can't draw become filled shapes."), - Preserve::Editability => tl!("Type stays text, and every stroke is a line with its lineweight and dashes."), + if d.bool("centerlineStrokes") { + tl!("Stroked paths become one zero-width centerline; their fills are omitted.") + } else { + match preserve { + Preserve::Appearance => tl!("Type becomes outlines, and strokes a CAD line can't draw become filled shapes."), + Preserve::Editability => tl!("Type stays text, and every stroke is a line with its lineweight and dashes."), + } }, ); false diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index ea273e448..8300a8c95 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -1906,6 +1906,9 @@ lighting Light Světlo Scale to Fit Artboard Přizpůsobit pracovní ploše Scaling Měřítko Alter Paths for Appearance Upravit cesty podle vzhledu + 3ds Max — R12 Linework Čárový výkres R12 pro 3ds Max + Export Strokes as Centerlines (0 width) Exportovat tahy jako osy (tloušťka 0) + Stroked paths become one zero-width centerline; their fills are omitted. Cesty s tahem se změní na jednu osu nulové tloušťky; jejich výplně se vynechají. DXF Options Možnosti DXF Export Option Možnost exportu Export Selected Art Only Exportovat jen vybranou kresbu diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index eb44f7234..f076d4953 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -147,6 +147,9 @@ Alt Alt Alt: Alt-Text: Alter Paths for Appearance Pfade für das Aussehen anpassen + 3ds Max — R12 Linework 3ds Max — R12-Linien + Export Strokes as Centerlines (0 width) Konturen als Mittellinien exportieren (Breite 0) + Stroked paths become one zero-width centerline; their fills are omitted. Pfade mit Kontur werden zu einer Mittellinie der Breite 0; ihre Flächen entfallen. Amount Stärke Amount: Stärke: Anchor Point Ankerpunkt diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 246529126..c39a51df0 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -165,6 +165,9 @@ Alt Alt Alt: Alt: Alter Paths for Appearance Modificar trazados según la apariencia + 3ds Max — R12 Linework Trazado lineal R12 para 3ds Max + Export Strokes as Centerlines (0 width) Exportar trazos como líneas centrales (grosor 0) + Stroked paths become one zero-width centerline; their fills are omitted. Los trazados con trazo se convierten en una línea central de grosor cero; se omiten sus rellenos. Amount Cantidad Amount: Cantidad: Anchor Point Punto de ancla diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 22e4f5643..b8b7d0457 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -166,6 +166,9 @@ Alt Alt Alt: Alt : Alter Paths for Appearance Modifier les tracés selon l’aspect + 3ds Max — R12 Linework 3ds Max — Tracé linéaire R12 + Export Strokes as Centerlines (0 width) Exporter les contours en lignes médianes (épaisseur 0) + Stroked paths become one zero-width centerline; their fills are omitted. Les tracés avec contour deviennent une ligne médiane d’épaisseur nulle ; leurs fonds sont omis. Amount Quantité Amount: Quantité : Anchor Point Point d’ancrage diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 6091a6c59..99e33129d 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -252,6 +252,10 @@ Alt+Drag Alt+húzás Alt: Helyettesítő szöveg: Alter Paths for Appearance Útvonalak módosítása a megjelenés szerint + 3ds Max — R12 Linework 3ds Max — R12 vonalrajz + Export Strokes as Centerlines (0 width) Körvonalak exportálása középvonalként (0 vastagság) + Stroked paths become one zero-width centerline; their fills are omitted. A körvonalas útvonalakból egyetlen 0 vastagságú középvonal lesz; a kitöltésük elmarad. + Ambient Környezeti fény Amount Mérték Amount: Mérték: Analogous Analóg diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index aa9764b8d..3a4aaba50 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -165,6 +165,9 @@ Alt Alt Alt: Alt: Alter Paths for Appearance Modifica tracciati in base all'aspetto + 3ds Max — R12 Linework 3ds Max — Linee R12 + Export Strokes as Centerlines (0 width) Esporta tracce come linee d’asse (spessore 0) + Stroked paths become one zero-width centerline; their fills are omitted. I tracciati con traccia diventano un’unica linea d’asse a spessore zero; i riempimenti vengono omessi. Amount Quantità Amount: Quantità: Anchor Point Punto di ancoraggio diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index e2d291dc4..4008debf2 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -815,6 +815,9 @@ All the art すべてのアート Alt: 代替テキスト: Alter Paths for Appearance 外観を保つためにパスを変更 + 3ds Max — R12 Linework 3ds Max — R12 線画 + Export Strokes as Centerlines (0 width) 線を中心線として書き出し (幅 0) + Stroked paths become one zero-width centerline; their fills are omitted. 線のあるパスは幅 0 の中心線 1 本になり、塗りは省略されます。 Amount: 量: Anchor Point アンカーポイント Anchor Point Tool アンカーポイントツール diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index a643ab3bb..f5666315f 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -810,6 +810,9 @@ All the art 모든 아트워크 Alt: Alt: Alter Paths for Appearance 모양에 맞게 패스 변경 + 3ds Max — R12 Linework 3ds Max — R12 선 작업 + Export Strokes as Centerlines (0 width) 선을 중심선으로 내보내기(두께 0) + Stroked paths become one zero-width centerline; their fills are omitted. 선이 있는 패스는 두께 0인 중심선 하나가 되며 칠은 생략됩니다. Amount: 양: Anchor Point 앵커 포인트 Anchor Point Tool 앵커 포인트 도구 diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 57d42f66a..df6ed6d91 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -1851,6 +1851,9 @@ lighting Light Światło Scale to Fit Artboard Skaluj, aby dopasować do obszaru kompozycji Scaling Skalowanie Alter Paths for Appearance Zmień ścieżki dla zachowania wyglądu + 3ds Max — R12 Linework 3ds Max — linie R12 + Export Strokes as Centerlines (0 width) Eksportuj obrysy jako linie środkowe (szerokość 0) + Stroked paths become one zero-width centerline; their fills are omitted. Ścieżki z obrysem stają się jedną linią środkową o zerowej szerokości; ich wypełnienia są pomijane. DXF Options Opcje DXF Export Option Opcja eksportu Export Selected Art Only Eksportuj tylko zaznaczoną kompozycję diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 75a81dca4..68fc89486 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -175,6 +175,7 @@ All the art Toda a arte Alt: Alt: Alter Paths for Appearance Alterar Caminhos para Aparência + 3ds Max — R12 Linework Traçado em linhas R12 para 3ds Max Amount: Quantidade: Anchor Point Ponto de Ancoragem Anchor Point Tool Ferramenta Ponto de Ancoragem diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index d6e0c979d..f7f033690 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -163,6 +163,9 @@ Alt Alt Alt: Alt: Alter Paths for Appearance Изменять контуры для оформления + 3ds Max — R12 Linework 3ds Max — линии R12 + Export Strokes as Centerlines (0 width) Экспортировать обводки как осевые линии (толщина 0) + Stroked paths become one zero-width centerline; their fills are omitted. Контуры с обводкой становятся одной осевой линией нулевой толщины; заливки опускаются. Amount Количество Amount: Количество: Anchor Point Опорная точка diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index bc74406e4..897684ded 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -159,6 +159,9 @@ Alt Alt Alt: Alt: Alter Paths for Appearance Змінювати контури для оформлення + 3ds Max — R12 Linework 3ds Max — лінії R12 + Export Strokes as Centerlines (0 width) Експортувати обведення як осьові лінії (товщина 0) + Stroked paths become one zero-width centerline; their fills are omitted. Контури з обведенням стають однією осьовою лінією нульової товщини; заливки пропускаються. Amount Кількість Amount: Кількість: Anchor Point Опорна точка diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 5792d9563..985422316 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -191,6 +191,10 @@ Alt Alt Alt: Alt: Alter Paths for Appearance Sửa đường dẫn cho diện mạo + 3ds Max — R12 Linework 3ds Max — đường nét R12 + Export Strokes as Centerlines (0 width) Xuất nét thành đường tâm (độ rộng 0) + Stroked paths become one zero-width centerline; their fills are omitted. Các đường có nét trở thành một đường tâm có độ rộng 0; phần tô của chúng bị bỏ qua. + Ambient Ánh sáng môi trường Amount Mức độ Amount: Mức độ: Anchor Point Điểm neo diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 105f571bc..cdb84dff8 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -125,6 +125,9 @@ Alt Alt Alt: Alt: Alter Paths for Appearance 为外观改变路径 + 3ds Max — R12 Linework 3ds Max — R12 线稿 + Export Strokes as Centerlines (0 width) 将描边导出为中心线(宽度 0) + Stroked paths become one zero-width centerline; their fills are omitted. 带描边的路径变为一条宽度为零的中心线;其填色将被省略。 Amount 数量 Amount: 数量: Anchor Point 锚点 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 58ae40732..d880b61a4 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -134,6 +134,9 @@ Alt Alt Alt: Alt: Alter Paths for Appearance 依外觀調整路徑 + 3ds Max — R12 Linework 3ds Max — R12 線稿 + Export Strokes as Centerlines (0 width) 將筆畫轉存為中心線 (寬度 0) + Stroked paths become one zero-width centerline; their fills are omitted. 具有筆畫的路徑會變成一條寬度為零的中心線;其填色不會保留。 Amount 數量 Amount: 數量: Anchor Point 錨點 diff --git a/docs/mcp.md b/docs/mcp.md index 9e67ca42d..ccebe5607 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -2277,6 +2277,14 @@ selected objects in their layers (every export takes it), and `useArtboards: tru artboard holding the art over it. What DXF can't hold (gradients and patterns as one colour, blending, opacity masks, raster effects, clipping) comes back in `warnings`. +`centerlineStrokes: true` writes each stroked path once, as a zero-width centerline (its fill and stroke outline +are left out): the linework 3D and CAM software extrude or sweep along, instead of the outline of the stroke's +width. For linework intended for 3ds Max, Export As → DXF has a **3ds Max — R12 Linework** preset: millimetres, R12 +polylines (curves are flattened), editable strokes as centerlines, 256 colours and outlined text, the version older +CAD importers read most reliably. Review the export warnings: R12 drops images and fill interiors. Through +`document.exportDxf` the preset is `version: "R12"`, `unit: "mm"`, `preserve: "editability"`, +`centerlineStrokes: true`, `colors: 256` and `outlineText: true`. + DWG can't be written (no openly licensed writer exists): `document.formats` lists it under `unsupported` with that hint, and exporting to it answers with the hint to export DXF. PICT files are not supported either and say so when opened.