From a6c4a967ad8a37aac9f522ac31ca10241a6d03ea Mon Sep 17 00:00:00 2001 From: backuppc Date: Fri, 24 Oct 2025 15:56:49 +0900 Subject: [PATCH] feat: Improve path preview visualization in UnifiedAGVCanvas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced path drawing with better visibility: 1. Arrow improvements: - Changed from line-based arrows to filled triangle shapes - Increased arrow size by 1.5x for better visibility - Added polygon fill with outline for clearer identification 2. Path line improvements: - Added 50% transparency to purple path color (Alpha: 128) - Increased line thickness by 2x (from 4 to 8 pixels) - Improved visual contrast and clarity 3. Bidirectional path detection: - Detect routes that traverse the same segment multiple times - Display bidirectional paths with higher opacity (darker color, Alpha: 200) - Visual distinction helps identify round-trip routes Changes in UnifiedAGVCanvas.Events.cs: - Modified DrawDirectionArrow() to use FillPolygon instead of DrawLine - Enhanced DrawPath() with transparency, thickness, and bidirectional detection - Added System.Collections.Generic using statement Result: Much better visual identification of calculated paths in HMI ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Controls/UnifiedAGVCanvas.Events.cs | 64 +++++++++++++++++-- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs index 8efe2bb..42b9d6b 100644 --- a/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs +++ b/Cs_HMI/AGVLogic/AGVNavigationCore/Controls/UnifiedAGVCanvas.Events.cs @@ -2,6 +2,7 @@ using AGVNavigationCore.Models; using AGVNavigationCore.PathFinding; using AGVNavigationCore.PathFinding.Core; using System; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; @@ -153,28 +154,42 @@ namespace AGVNavigationCore.Controls private void DrawDirectionArrow(Graphics g, Point point, double angle, AgvDirection direction) { - var arrowSize = CONNECTION_ARROW_SIZE; + var arrowSize = CONNECTION_ARROW_SIZE * 1.5; // ํ™”์‚ดํ‘œ ํฌ๊ธฐ ์ฆ๊ฐ€ var arrowAngle = Math.PI / 6; // 30๋„ var cos = Math.Cos(angle); var sin = Math.Sin(angle); + // ํ™”์‚ดํ‘œ ๋์  (๋ฐฉํ–ฅ) + var arrowTipPoint = new Point( + (int)(point.X + arrowSize * Math.Cos(angle)), + (int)(point.Y + arrowSize * Math.Sin(angle)) + ); + + // ํ™”์‚ดํ‘œ ์ขŒ์ธก ์  var arrowPoint1 = new Point( (int)(point.X - arrowSize * Math.Cos(angle - arrowAngle)), (int)(point.Y - arrowSize * Math.Sin(angle - arrowAngle)) ); + // ํ™”์‚ดํ‘œ ์šฐ์ธก ์  var arrowPoint2 = new Point( (int)(point.X - arrowSize * Math.Cos(angle + arrowAngle)), (int)(point.Y - arrowSize * Math.Sin(angle + arrowAngle)) ); var arrowColor = direction == AgvDirection.Forward ? Color.Blue : Color.Red; - var arrowPen = new Pen(arrowColor, 2); + var arrowBrush = new SolidBrush(arrowColor); - g.DrawLine(arrowPen, point, arrowPoint1); - g.DrawLine(arrowPen, point, arrowPoint2); + // ์‚ผ๊ฐํ˜•์œผ๋กœ ํ™”์‚ดํ‘œ ๊ทธ๋ฆฌ๊ธฐ (๋‚ด๋ถ€ ์ฑ„์›€) + var trianglePoints = new Point[] { arrowTipPoint, arrowPoint1, arrowPoint2 }; + g.FillPolygon(arrowBrush, trianglePoints); + // ์œค๊ณฝ์„  ๊ทธ๋ฆฌ๊ธฐ + var arrowPen = new Pen(arrowColor, 1.5f); + g.DrawPolygon(arrowPen, trianglePoints); + + arrowBrush.Dispose(); arrowPen.Dispose(); } @@ -204,20 +219,55 @@ namespace AGVNavigationCore.Controls { if (path?.Path == null || path.Path.Count < 2) return; - var pathPen = new Pen(color, 4) { DashStyle = DashStyle.Dash }; + // ํ˜„์žฌ ์„ ํƒ๋œ ๊ฒฝ๋กœ์ธ ๊ฒฝ์šฐ ๋ณด๋ผ์ƒ‰ + ํˆฌ๋ช…๋„ 50% + ์„  ๋‘๊ป˜ 2๋ฐฐ + Color lineColor = color; + float lineThickness = 4; + + if (color == Color.Purple) + { + // ํˆฌ๋ช…๋„ 50% (Alpha = 128 / 255) + lineColor = Color.FromArgb(128, color.R, color.G, color.B); + lineThickness = 8; // 2๋ฐฐ ์ฆ๊ฐ€ + } + + var pathPen = new Pen(lineColor, lineThickness) { DashStyle = DashStyle.Dash }; + + // ์™•๋ณต ๊ฒฝ๋กœ ๊ฐ์ง€: ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ ์ถ”์  + var visitedSegments = new Dictionary(); for (int i = 0; i < path.Path.Count - 1; i++) { var currentNodeId = path.Path[i]; var nextNodeId = path.Path[i + 1]; + // ์™•๋ณต ๊ตฌ๊ฐ„ ํ‚ค ์ƒ์„ฑ (์–‘๋ฐฉํ–ฅ ๋ชจ๋‘ ๊ฐ™์€ ํ‚ค) + var segmentKey = string.Compare(currentNodeId, nextNodeId) < 0 + ? $"{currentNodeId}_{nextNodeId}" + : $"{nextNodeId}_{currentNodeId}"; + + if (!visitedSegments.ContainsKey(segmentKey)) + visitedSegments[segmentKey] = 0; + visitedSegments[segmentKey]++; + var currentNode = _nodes?.FirstOrDefault(n => n.NodeId == currentNodeId); var nextNode = _nodes?.FirstOrDefault(n => n.NodeId == nextNodeId); if (currentNode != null && nextNode != null) { - // ๊ฒฝ๋กœ ์„  ๊ทธ๋ฆฌ๊ธฐ - g.DrawLine(pathPen, currentNode.Position, nextNode.Position); + // ์™•๋ณต ๊ฒฝ๋กœ๋ฉด ๋” ์ง„ํ•œ ์ƒ‰์ƒ์œผ๋กœ ํ‘œ์‹œ + if (visitedSegments[segmentKey] > 1 && color == Color.Purple) + { + // ์™•๋ณต ๊ฒฝ๋กœ๋Š” ํˆฌ๋ช…๋„๋ฅผ ๋‚ฎ์ถค (๋” ์ง„ํ•˜๊ฒŒ) + var darkPathColor = Color.FromArgb(200, color.R, color.G, color.B); + var darkPathPen = new Pen(darkPathColor, lineThickness) { DashStyle = DashStyle.Dash }; + g.DrawLine(darkPathPen, currentNode.Position, nextNode.Position); + darkPathPen.Dispose(); + } + else + { + // ์ผ๋ฐ˜ ๊ฒฝ๋กœ ์„  ๊ทธ๋ฆฌ๊ธฐ + g.DrawLine(pathPen, currentNode.Position, nextNode.Position); + } // ๊ฒฝ๋กœ ๋ฐฉํ–ฅ ํ‘œ์‹œ (๊ณ„์‚ฐ๋œ ๊ฒฝ๋กœ์˜ ๊ฒฝ์šฐ์—๋งŒ ๋ฐฉํ–ฅ ํ™”์‚ดํ‘œ ํ‘œ์‹œ) var midPoint = new Point(