/
docNemo
/
clothes-graph
Обзор
Документация
Войти
/
docNemo
/
clothes-graph
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/ClothesGraph.App/PrintService.cs
123 строки
5 KB
docNemo
Запрос на слияние 'interface-to-spec' (
#1
) из interface-to-spec в main
09 авг 2026, 20:28
Верифицирован
09 авг 2026, 20:28
1bbc436
Код
Авторство
О чём код?
using System; using System.Diagnostics; using System.IO; using ClothesGraph.Geometry; using ClothesGraph.Model; using ClothesGraph.Model.Pieces; using ClothesGraph.Printing; namespace ClothesGraph.App; /// <summary> /// Подготовка выкройки к выводу: пересчёт деталей и экспорт листов. /// </summary> /// <remarks> /// Печать на принтер выполняется тем же документом, что и экспорт в файл. /// Отдельного пути отрисовки на принтер нет намеренно: два независимых пути /// неизбежно разошлись бы, и напечатанное перестало бы совпадать с файлом. /// </remarks> public sealed class PrintService { /// <summary>Собирает содержимое для вывода из деталей документа.</summary> public PrintContent BuildContent(PatternDocument document, string? size = null) { var chosen = size ?? document.Sizes.BaseSize; var (evaluation, values) = document.Evaluate(chosen); var content = new PrintContent { Title = document.Pieces.Count == 1 ? document.Pieces[0].Name : "Выкройка", Size = chosen }; // Детали, которые пользователь не двигал, раскладываются в ряд с // промежутком. Плотная раскладка относится к отдельному изменению, // но накладывать детали друг на друга нельзя — их не вырезать. var cursor = Length.Zero; var gap = Length.FromMillimetres(20); foreach (var piece in document.Pieces) { // Исключённые детали не попадают на лист: печатать всё подряд // значит расходовать бумагу на то, что уже вырезано. if (document.Print.ExcludedFromPrint.Contains(piece.Id)) continue; var geometry = PieceBuilder.Build(piece, evaluation, values, document.FormulaUnit); if (geometry.Outline.Count < 3) continue; var placed = new PlacedPiece(piece, geometry); if (document.Print.Placements.TryGetValue(piece.Id, out var placement)) { // Заданное пользователем положение сохраняется при любом // пересчёте: смена формата листа не должна сбрасывать // раскладку, над которой он только что работал. placed.Offset = placement.Offset; placed.RotationDegrees = placement.RotationDegrees; } else { var (min, max) = placed.Bounds(); placed.Offset = new Offset2(cursor - min.X, Length.Zero); cursor += max.X - min.X + gap; } content.Add(placed); } return content; } public SheetGrid Export(PatternDocument document, PageLayout layout, string path, string? size = null) => new PdfExporter().Export(BuildContent(document, size), layout, path); /// <summary> /// Отправляет выкройку на печать через системный обработчик PDF. /// </summary> /// <remarks> /// Возвращает false, если в системе не назначена программа для печати PDF. /// Управлять настройками этой программы приложение не может, поэтому /// контрольный отрезок масштаба на листе остаётся единственным способом /// убедиться, что печать прошла без вписывания в страницу. /// </remarks> public bool Print(PatternDocument document, PageLayout layout, string? size = null) { var path = Path.Combine(Path.GetTempPath(), $"clothes-graph-{DateTime.Now:yyyyMMdd-HHmmss}.pdf"); Export(document, layout, path, size); try { using var process = Process.Start(new ProcessStartInfo(path) { Verb = "print", UseShellExecute = true }); return process is not null; } catch (Exception) { // Обработчик печати не назначен: открываем файл, чтобы пользователь // напечатал его сам, а не остаёмся с молчаливым отказом. try { using var fallback = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); return false; } catch (Exception) { return false; } } } }