using DrawFigureLibrary; using DrawFigureLibrary.Figures; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; namespace Main { public partial class MainWindow : Window { private RenderTargetBitmap? _renderTarget ; private int _polyExpected ; private List _polyPoints = new List() ; private DrawFigureLibrary.Figure? _mouseSelected ; private bool _isDragging ; private Point _lastMouse ; private int CanvasW => _renderTarget?.PixelWidth ?? 800; private int CanvasH => _renderTarget?.PixelHeight ?? 400; private void ClickAddRectangle(object sender, RoutedEventArgs e) { try { if (!TryReadName(RectName, out string name)) return; if (!TryReadInt(RectX.Text, "X", 0, CanvasW - 1, out int x)) return; if (!TryReadInt(RectY.Text, "Y", 0, CanvasH - 1, out int y)) return; if (!TryReadInt(RectW.Text, "W", 1, CanvasW, out int w)) return; if (!TryReadInt(RectH.Text, "H", 1, CanvasH, out int h)) return; if (x + w > CanvasW || y + h > CanvasH) { MessageBox.Show("Фигура не помещается в область рисования."); return; } ShapeContainer.AddFigure(new RectangleFigure(name, x, y, w, h)); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickAddSquare(object sender, RoutedEventArgs e) { try { if (!TryReadName(SquareName, out string name)) return; if (!TryReadInt(SquareX.Text, "X", 0, CanvasW - 1, out int x)) return; if (!TryReadInt(SquareY.Text, "Y", 0, CanvasH - 1, out int y)) return; int maxSide = Math.Min(CanvasW, CanvasH); if (!TryReadInt(SquareSide.Text, "Side", 1, maxSide, out int side)) return; if (x + side > CanvasW || y + side > CanvasH) { MessageBox.Show("Фигура не помещается в область рисования."); return; } ShapeContainer.AddFigure(new SquareFigure(name, x, y, side)); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickAddEllipse(object sender, RoutedEventArgs e) { try { if (!TryReadName(EllipseName, out string name)) return; if (!TryReadInt(EllipseX.Text, "X", 0, CanvasW - 1, out int x)) return; if (!TryReadInt(EllipseY.Text, "Y", 0, CanvasH - 1, out int y)) return; if (!TryReadInt(EllipseW.Text, "W", 1, CanvasW, out int w)) return; if (!TryReadInt(EllipseH.Text, "H", 1, CanvasH, out int h)) return; if (x + w > CanvasW || y + h > CanvasH) { MessageBox.Show("Фигура не помещается в область рисования."); return; } ShapeContainer.AddFigure(new EllipseFigure(name, x, y, w, h)); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickAddCircle(object sender, RoutedEventArgs e) { try { if (!TryReadName(CircleName, out string name)) return; if (!TryReadInt(CircleX.Text, "X", 0, CanvasW - 1, out int x)) return; if (!TryReadInt(CircleY.Text, "Y", 0, CanvasH - 1, out int y)) return; int maxD = Math.Min(CanvasW, CanvasH); if (!TryReadInt(CircleD.Text, "Диаметр", 1, maxD, out int d)) return; if (x + d > CanvasW || y + d > CanvasH) { MessageBox.Show("Фигура не помещается в область рисования."); return; } ShapeContainer.AddFigure(new CircleFigure(name, x, y, d)); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickPolyStart(object sender, RoutedEventArgs e) { try { if (!TryReadName(PolyName, out string name)) return; if (!TryReadInt(PolyCount.Text, "Кол-во вершин", 3, 50, out _polyExpected)) return; _polyPoints = new List(); PolyCount.IsEnabled = false; PolyX.IsEnabled = true; PolyY.IsEnabled = true; PolyAddPointBtn.IsEnabled = true; PolyFinishBtn.IsEnabled = false; PolyStatus.Text = $"Точек: 0 / {_polyExpected}"; } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickPolyAddPoint(object sender, RoutedEventArgs e) { try { if (!TryReadInt(PolyX.Text, "X точки", 0, CanvasW - 1, out int x)) return; if (!TryReadInt(PolyY.Text, "Y точки", 0, CanvasH - 1, out int y)) return; if (_polyPoints.Count >= _polyExpected) { MessageBox.Show("Все точки уже введены."); return; } _polyPoints.Add(new Point(x, y)); PolyStatus.Text = $"Точек: {_polyPoints.Count} / {_polyExpected}"; if (_polyPoints.Count == _polyExpected) { PolyAddPointBtn.IsEnabled = false; PolyFinishBtn.IsEnabled = true; } } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickPolyFinish(object sender, RoutedEventArgs e) { try { if (!TryReadName(PolyName, out string name)) return; if (_polyPoints.Count != _polyExpected) { MessageBox.Show("Не все точки введены."); return; } if (_polyPoints.Count < 3) { MessageBox.Show("Минимум 3 точки."); return; } ShapeContainer.AddFigure(new PolygonFigure(name, _polyPoints.ToArray())); Upd(); PolyCount.IsEnabled = true; PolyX.IsEnabled = false; PolyY.IsEnabled = false; PolyAddPointBtn.IsEnabled = false; PolyFinishBtn.IsEnabled = false; PolyStatus.Text = ""; } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickAddTriangle(object sender, RoutedEventArgs e) { try { if (!TryReadName(TriName, out string name)) return; if (!TryReadInt(Ax.Text, "Ax", 0, CanvasW - 1, out int ax)) return; if (!TryReadInt(Ay.Text, "Ay", 0, CanvasH - 1, out int ay)) return; if (!TryReadInt(Bx.Text, "Bx", 0, CanvasW - 1, out int bx)) return; if (!TryReadInt(By.Text, "By", 0, CanvasH - 1, out int by)) return; if (!TryReadInt(Cx.Text, "Cx", 0, CanvasW - 1, out int cx)) return; if (!TryReadInt(Cy.Text, "Cy", 0, CanvasH - 1, out int cy)) return; var a = new Point(ax, ay); var b = new Point(bx, by); var c = new Point(cx, cy); ShapeContainer.AddFigure(new Triangle(name, a, b, c)); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickAddTerrainPointSunPointHumanPointText(object sender, RoutedEventArgs e) { try { if (!TryReadName(SceneName, out string name)) return; if (!TryReadInt(SceneX.Text, "X", 0, CanvasW - 1, out int x)) return; if (!TryReadInt(SceneY.Text, "Y", 0, CanvasH - 1, out int y)) return; if (!TryReadInt(SceneW.Text, "W", 1, CanvasW, out int sceneW)) return; if (!TryReadInt(SceneH.Text, "H", 1, CanvasH, out int sceneH)) return; if (x + sceneW > CanvasW || y + sceneH > CanvasH) { MessageBox.Show("Сцена не помещается в область рисования."); return; } ShapeContainer.AddFigure(new TerrainPointSunPointHumanPointText(name, x, y, sceneW, sceneH)); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickMoveSelected(object sender, RoutedEventArgs e) { try { var fig = GetSelectedFigureOrThrow(); if (!TryReadInt(MoveDx.Text, "dX", -CanvasW, CanvasW, out int dx)) return; if (!TryReadInt(MoveDy.Text, "dY", -CanvasH, CanvasH, out int dy)) return; if (fig.MoveByChecked(dx, dy)) Redraw(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void ClickDeleteSelected(object sender, RoutedEventArgs e) { try { var fig = GetSelectedFigureOrThrow(); bool ok = ShapeContainer.RemoveFigure(fig); if (!ok) throw new Exception("Фигура для удаления не найдена."); Upd(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { Init.DrawingImage = DrawingImage; int width = (int)DrawingImage.Width; int height = (int)DrawingImage.Height; if (width <= 0) width = 800; if (height <= 0) height = 400; _renderTarget = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); DrawingImage.Source = _renderTarget; ImgBorder.Width = width; ImgBorder.Height = height; Upd(); } private void Redraw() { if (_renderTarget == null) return; DrawingVisual drawVis = new DrawingVisual(); using (var ctx = drawVis.RenderOpen()) { foreach (var fig in ShapeContainer.FigureList) { fig.Draw(ctx); } } _renderTarget.Clear(); _renderTarget.Render(drawVis); DrawingImage.Source = _renderTarget; } private void RefreshCombo() { FigureCombo.ItemsSource = null; FigureCombo.ItemsSource = ShapeContainer.FigureList.Select(f => f.Name); if (FigureCombo.Items.Count > 0 && FigureCombo.SelectedIndex < 0) { FigureCombo.SelectedIndex = 0; } } private void Upd() { Redraw(); RefreshCombo(); } private Figure GetSelectedFigureOrThrow() { if (FigureCombo.SelectedItem == null) throw new Exception("Фигура не выбрана."); string name = FigureCombo.SelectedItem.ToString()!; var fig = ShapeContainer.FindByName(name); if (fig == null) throw new Exception("Фигура для операции не найдена."); return fig; } private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var p = e.GetPosition(DrawingImage); _mouseSelected = ShapeContainer.FigureList .AsEnumerable() .Reverse() .FirstOrDefault(f => f.HitTest(p)); if (_mouseSelected != null) { FigureCombo.SelectedItem = _mouseSelected.Name; _isDragging = true; _lastMouse = p; DrawingImage.CaptureMouse(); e.Handled = true; } } private void MouseMove(object sender, MouseEventArgs e) { if (!_isDragging || _mouseSelected == null) return; if (e.LeftButton != MouseButtonState.Pressed) return; var p = e.GetPosition(DrawingImage); int dx = (int)Math.Round(p.X - _lastMouse.X); int dy = (int)Math.Round(p.Y - _lastMouse.Y); if (dx == 0 && dy == 0) return; if (_mouseSelected.MoveByChecked(dx, dy)) { _lastMouse = p; Redraw(); } e.Handled = true; } private void MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (!_isDragging) return; _isDragging = false; _mouseSelected = null; DrawingImage.ReleaseMouseCapture(); e.Handled = true; } private bool TryReadInt(string raw, string field, int min, int max, out int value) { if (!int.TryParse(raw?.Trim(), out value)) { MessageBox.Show($"Поле \"{field}\": нужно целое число."); return false; } if (value < min || value > max) { MessageBox.Show($"Поле \"{field}\": допустимо [{min}..{max}]."); return false; } return true; } private bool TryReadName(TextBox tb, out string name) { name = (tb.Text ?? "").Trim(); if (string.IsNullOrWhiteSpace(name)) { MessageBox.Show("Имя фигуры не должно быть пустым."); return false; } if (name.Length > 40) { MessageBox.Show("Имя фигуры слишком длинное (максимум 40 символов)."); return false; } string kostil = name; if (ShapeContainer.FigureList.Any(f => string.Equals(f.Name, kostil, StringComparison.OrdinalIgnoreCase))) { MessageBox.Show("Фигура с таким именем уже существует."); return false; } return true; } } }