lixiaojun
8 天以前 0329c48a57f33a4c94e44c5e4d3d3c116184986f
优化HelixToolkit的方法,增加水流方向功能,进一步封装Winform控件
已删除1个文件
已重命名5个文件
已修改17个文件
已添加8个文件
1418 ■■■■■ 文件已修改
Yw.WinFrmUI.Hydro.L3d2.Core/LogicalViewerL3d2.Designer.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/LogicalViewerL3d2.cs 242 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/LogicalViewerL3d2.resx 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/Properties/PublishProfiles/FolderProfile.pubxml.user 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/ViewerL3d2.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/Yw.WinFrmUI.Hydro.L3d2.Core.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/Yw.WinFrmUI.Hydro.L3d2.Core.csproj.user 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Test.Core/Form3.Designer.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/00-core/Point3DExtensions.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/01-network/99-model/02-text/TextL3d.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/01-network/99-model/03-flow/FlowDirectionL3d.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/00-core/LogicalSelectionHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/00-core/LogicalZoomHelper.cs 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/01-visual/00-core/LogicalVisual3D.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalBillboardTextHelper.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalLeadLabelVisual3D.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/01-effect/LogicalFlowEffect3D.cs 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/01-effect/LogicalFlowEffectHelper.cs 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/01-effect/LogicalParticle3D.cs 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/02-direction/LogicalFlowDirection3D.cs 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/02-direction/LogicalFlowDirection3DGroup.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/02-direction/LogicalFlowDirectionHelper.cs 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/08-manager/LogicalEditManager.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/08-manager/LogicalManager.cs 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/09-control/LogicalEditerL3d.xaml.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/09-control/LogicalViewerL3d.xaml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/03-logical/09-control/LogicalViewerL3d.xaml.cs 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/Properties/PublishProfiles/FolderProfile.pubxml.user 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Hydro.L3d.Core/Yw.WpfUI.Hydro.L3d.Core.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Test.Core/MainWindow.xaml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WpfUI.Test.Core/MainWindow.xaml.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Yw.WinFrmUI.Hydro.L3d2.Core/LogicalViewerL3d2.Designer.cs
ÎļþÃû´Ó Yw.WinFrmUI.Hydro.L3d2.Core/ViewerL3d2.Designer.cs ÐÞ¸Ä
@@ -1,6 +1,6 @@
namespace Yw.WinFrmUI.Hydro
{
    partial class ViewerL3d2
    partial class LogicalViewerL3d2
    {
        /// <summary>
        /// Required designer variable.
Yw.WinFrmUI.Hydro.L3d2.Core/LogicalViewerL3d2.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,242 @@
using System.Windows.Forms.Integration;
namespace Yw.WinFrmUI.Hydro
{
    public partial class LogicalViewerL3d2 : UserControl
    {
        public LogicalViewerL3d2()
        {
            InitializeComponent();
        }
        #region äº‹ä»¶é›†åˆ
        /// <summary>
        /// é€‰æ‹©æ”¹å˜äº‹ä»¶
        /// </summary>
        public event Action<List<Yw.WpfUI.Hydro.VisualL3d>> SelectionChangedEvent;
        #endregion
        #region ç§æœ‰å­—段
        private Yw.WpfUI.Hydro.LogicalViewerL3d _wpfViewer = null;//wpf控件
        #endregion
        #region åˆå§‹åŒ–
        /// <summary>
        /// åˆå§‹åŒ–
        /// </summary>
        public void Initial(Yw.WpfUI.Hydro.NetworkL3d nw)
        {
            InitialWpfControl();
            _wpfViewer.Initial(nw);
        }
        //初始化wpf控件
        private void InitialWpfControl()
        {
            _wpfViewer = new WpfUI.Hydro.LogicalViewerL3d();
            _wpfViewer.SelectionChangedEvent += (visuals) => this.SelectionChangedEvent?.Invoke(visuals);
            var elementHost = new ElementHost();
            elementHost.Dock = DockStyle.Fill;
            elementHost.Child = _wpfViewer;
            this.Controls.Clear();
            this.Controls.Add(elementHost);
        }
        #endregion
        #region ç›¸æœºè§†è§’
        /// <summary>
        /// è®¾ç½®ä¸Šè§†å›¾
        /// </summary>
        public void SetTopView()
        {
            _wpfViewer?.SetTopView();
        }
        /// <summary>
        /// è®¾ç½®ä¸‹è§†å›¾
        /// </summary>
        public void SetBottomView()
        {
            _wpfViewer?.SetBottomView();
        }
        /// <summary>
        /// è®¾ç½®å·¦è§†å›¾
        /// </summary>
        public void SetLeftView()
        {
            _wpfViewer?.SetLeftView();
        }
        /// <summary>
        /// è®¾ç½®å³è§†å›¾
        /// </summary>
        public void SetRightView()
        {
            _wpfViewer?.SetRightView();
        }
        /// <summary>
        /// è®¾ç½®å‰è§†å›¾
        /// </summary>
        public void SetFrontView()
        {
            _wpfViewer?.SetFrontView();
        }
        /// <summary>
        /// è®¾ç½®åŽè§†å›¾
        /// </summary>
        public void SetBackView()
        {
            _wpfViewer?.SetBackView();
        }
        /// <summary>
        /// è¥¿å—视角
        /// ä»Žç‰©ä½“的左前下方观察
        /// </summary>
        public void SetSouthWestView()
        {
            _wpfViewer?.SetSouthWestView();
        }
        /// <summary>
        /// ä¸œå—视角
        /// ä»Žç‰©ä½“的右前下方观察
        /// </summary>
        public void SetSouthEastView()
        {
            _wpfViewer?.SetSouthEastView();
        }
        /// <summary>
        /// ä¸œåŒ—视角
        /// ä»Žç‰©ä½“的右后上方观察
        /// </summary>
        public void SetNorthEastView()
        {
            _wpfViewer?.SetNorthEastView();
        }
        /// <summary>
        /// è¥¿åŒ—视角
        /// ä»Žç‰©ä½“的左后上方观察
        /// </summary>
        public void SetNorthWestView()
        {
            _wpfViewer?.SetNorthWestView();
        }
        #endregion
        #region ç½‘格线
        /// <summary>
        /// æ˜¾ç¤ºç½‘格线
        /// </summary>
        public void ShowGridLines()
        {
            _wpfViewer?.ShowGridLines();
        }
        /// <summary>
        /// éšè—ç½‘格线
        /// </summary>
        public void HideGridLines()
        {
            _wpfViewer?.HideGridLines();
        }
        /// <summary>
        /// ç½‘格线可见性
        /// </summary>
        public bool GridLinesVisible
        {
            get
            {
                return _wpfViewer == null ? false : _wpfViewer.GridLinesVisible;
            }
            set
            {
                if (_wpfViewer != null)
                {
                    _wpfViewer.GridLinesVisible = value;
                }
            }
        }
        #endregion
        #region ç¼©æ”¾è‡³æž„ä»¶
        /// <summary>
        /// ç¼©æ”¾è‡³å¯è§æž„ä»¶
        /// </summary>
        public void ZoomToVisual(string Id)
        {
            _wpfViewer?.ZoomToVisual(Id);
        }
        /// <summary>
        /// ç¼©æ”¾è‡³å¯è§æž„ä»¶
        /// </summary>
        public void ZoomToVisual(List<string> Ids)
        {
            _wpfViewer?.ZoomToVisual(Ids);
        }
        #endregion
        #region é€‰æ‹©æž„ä»¶
        /// <summary>
        /// é€‰æ‹©æž„ä»¶
        /// </summary>
        public void SelectVisual(string Id)
        {
            _wpfViewer?.SelectVisual(Id);
        }
        /// <summary>
        /// é€‰æ‹©æž„ä»¶
        /// </summary>
        public void SelectVisual(List<string> Ids)
        {
            _wpfViewer?.SelectVisual(Ids);
        }
        #endregion
        #region ç¼©æ”¾å¹¶é€‰æ‹©æž„ä»¶
        /// <summary>
        /// ç¼©æ”¾å¹¶é€‰æ‹©æž„ä»¶
        /// </summary>
        public void ZoomAndSelectVisual(string Id)
        {
            _wpfViewer?.ZoomAndSelectVisual(Id);
        }
        /// <summary>
        /// ç¼©æ”¾å¹¶é€‰æ‹©æž„ä»¶
        /// </summary>
        public void ZoomAndSelectVisual(List<string> Ids)
        {
            _wpfViewer?.ZoomAndSelectVisual(Ids);
        }
        #endregion
    }
}
Yw.WinFrmUI.Hydro.L3d2.Core/LogicalViewerL3d2.resx
Yw.WinFrmUI.Hydro.L3d2.Core/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -2,7 +2,7 @@
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
  <PropertyGroup>
    <History>True|2025-04-03T07:07:50.7868897Z||;True|2025-04-03T14:53:27.6125391+08:00||;True|2025-04-03T14:09:06.0738035+08:00||;</History>
    <History>True|2025-04-22T07:50:06.4794535Z||;True|2025-04-03T15:07:50.7868897+08:00||;True|2025-04-03T14:53:27.6125391+08:00||;True|2025-04-03T14:09:06.0738035+08:00||;</History>
    <LastFailureDetails />
  </PropertyGroup>
</Project>
Yw.WinFrmUI.Hydro.L3d2.Core/ViewerL3d2.cs
ÎļþÒÑɾ³ý
Yw.WinFrmUI.Hydro.L3d2.Core/Yw.WinFrmUI.Hydro.L3d2.Core.csproj
@@ -8,11 +8,11 @@
    <OutputType>Library</OutputType>
    <UseWPF>True</UseWPF>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <Version>1.0.2</Version>
    <Version>1.0.3</Version>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Yw.WpfUI.Hydro.L3d.Core" Version="1.0.1" />
    <PackageReference Include="Yw.WpfUI.Hydro.L3d.Core" Version="1.0.2" />
  </ItemGroup>
</Project>
Yw.WinFrmUI.Hydro.L3d2.Core/Yw.WinFrmUI.Hydro.L3d2.Core.csproj.user
@@ -4,7 +4,7 @@
    <_LastSelectedProfileId>D:\WorkData\Module\Epanet\Yw.WinFrmUI.Hydro.L3d2.Core\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
  </PropertyGroup>
  <ItemGroup>
    <Compile Update="ViewerL3d2.cs">
    <Compile Update="LogicalViewerL3d2.cs">
      <SubType>UserControl</SubType>
    </Compile>
  </ItemGroup>
Yw.WinFrmUI.Test.Core/Form3.Designer.cs
@@ -28,7 +28,7 @@
        /// </summary>
        private void InitializeComponent()
        {
            viewerL3d21 = new Yw.WinFrmUI.Hydro.ViewerL3d2();
            viewerL3d21 = new Yw.WinFrmUI.Hydro.LogicalViewerL3d2();
            SuspendLayout();
            // 
            // viewerL3d21
@@ -52,6 +52,6 @@
        #endregion
        private Hydro.ViewerL3d2 viewerL3d21;
        private Hydro.LogicalViewerL3d2 viewerL3d21;
    }
}
Yw.WpfUI.Hydro.L3d.Core/00-core/Point3DExtensions.cs
@@ -12,5 +12,7 @@
        {
            return new PointL3d(pt.X, pt.Y, pt.Z);
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/01-network/99-model/02-text/TextL3d.cs
ÎļþÃû´Ó Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalTextL3d.cs ÐÞ¸Ä
@@ -1,9 +1,9 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡æ–‡æœ¬
    /// æ–‡æœ¬
    /// </summary>
    public class LogicalTextL3d
    public class TextL3d
    {
        /// <summary>
        /// æž„ä»¶id
Yw.WpfUI.Hydro.L3d.Core/01-network/99-model/03-flow/FlowDirectionL3d.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æ°´æµæ–¹å‘
    /// </summary>
    public class FlowDirectionL3d
    {
        /// <summary>
        /// æž„ä»¶id
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// æ­£å‘
        /// </summary>
        public bool Positive { get; set; }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/00-core/LogicalSelectionHelper.cs
@@ -130,7 +130,7 @@
        /// <summary>
        /// é€‰æ‹©Visuals
        /// </summary>
        public void SelectVisuals(List<LogicalVisual3D> visuals)
        public void SelectVisual(List<LogicalVisual3D> visuals)
        {
            ClearSelection();
            if (visuals == null || visuals.Count < 1)
Yw.WpfUI.Hydro.L3d.Core/03-logical/00-core/LogicalZoomHelper.cs
@@ -13,7 +13,7 @@
            _viewport = viewport;
        }
        private readonly HelixViewport3D _viewport;//三维组件
        private readonly HelixViewport3D _viewport;// ä¸‰ç»´ç»„ä»¶
        private readonly double _animationDuration = 0.5; // åŠ¨ç”»æŒç»­æ—¶é—´(秒)
        private readonly double _zoomFactor = 1.2; // ç¼©æ”¾å› å­(在边界框外留些空间)
@@ -52,33 +52,34 @@
        /// <summary>
        /// ç¼©æ”¾è‡³Visual
        /// </summary>
        public void ZoomToVisual(Visual3D visual)
        public void ZoomToVisual(LogicalVisual3D visual3d)
        {
            if (visual == null)
            if (visual3d == null)
            {
                return;
            }
            // èŽ·å–æ¨¡åž‹çš„è¾¹ç•Œæ¡†
            var bounds = Visual3DHelper.FindBounds(visual, Transform3D.Identity);
            var bounds = Visual3DHelper.FindBounds(visual3d, Transform3D.Identity);
            ZoomToBounds(bounds);
        }
        /// <summary>
        /// ç¼©æ”¾è‡³Visuals
        /// ç¼©æ”¾è‡³Visual
        /// </summary>
        public void ZoomToVisuals(List<Visual3D> visuals)
        public void ZoomToVisual(List<LogicalVisual3D> visual3ds)
        {
            if (visuals == null || visuals.Count < 1)
            if (visual3ds == null || visual3ds.Count < 1)
            {
                return;
            }
            // è®¡ç®—所有模型的联合边界框
            var bounds = Rect3D.Empty;
            foreach (var visual in visuals)
            foreach (var visual in visual3ds)
            {
                bounds.Union(Visual3DHelper.FindBounds(visual, Transform3D.Identity));
            }
            ZoomToBounds(bounds);
        }
Yw.WpfUI.Hydro.L3d.Core/03-logical/01-visual/00-core/LogicalVisual3D.cs
@@ -38,6 +38,15 @@
        protected readonly LogicalOverrideOpacityHelper _overrideOpacityHelper = null;//覆盖透明度辅助类
        protected readonly LogicalOverrideVisibleHelper _overrideVisibleHelper = null;//覆盖可见性辅助类
        #region äº‹ä»¶é›†åˆ
        /// <summary>
        /// çŠ¶æ€æ”¹å˜äº‹ä»¶
        /// </summary>
        public event Action VisualChangedEvent;
        #endregion
        /// <summary>
        /// Vmo
        /// </summary>
@@ -59,6 +68,7 @@
            this.UpdateMaterial();
            this.UpdateTransform();
            this.UpdateVisibility();
            this.VisualChangedEvent?.Invoke();
        }
        /// <summary>
Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalBillboardTextHelper.cs
ÎļþÃû´Ó Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalBillboardLeadLabelHelper.cs ÐÞ¸Ä
@@ -1,14 +1,14 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡å¼•线标签辅助类
    /// æŠ½è±¡å…¬å‘Šæ–‡æœ¬è¾…助类
    /// </summary>
    internal class LogicalBillboardLeadLabelHelper
    internal class LogicalBillboardTextHelper
    {
        /// <summary>
        /// 
        /// </summary>
        public LogicalBillboardLeadLabelHelper(HelixViewport3D viewport)
        public LogicalBillboardTextHelper(HelixViewport3D viewport)
        {
            _viewport = viewport;
        }
@@ -23,7 +23,7 @@
        /// <summary>
        /// è®¾ç½®
        /// </summary>
        public void Set(List<LogicalTextL3d> items)
        public void Set(List<TextL3d> items)
        {
            Clear();
            items?.ForEach(x => AddTextVisual3D(x));
@@ -47,7 +47,7 @@
        /// <summary>
        /// æ›´æ–°
        /// </summary>
        public void Update(LogicalTextL3d item)
        public void Update(TextL3d item)
        {
            if (item == null)
            {
@@ -70,14 +70,14 @@
        /// <summary>
        /// æ›´æ–°
        /// </summary>
        public void Update(List<LogicalTextL3d> items)
        public void Update(List<TextL3d> items)
        {
            items?.ForEach(x => Update(x));
        }
        //添加公告牌文本
        private void AddTextVisual3D(LogicalTextL3d item)
        private void AddTextVisual3D(TextL3d item)
        {
            if (!_cache.ContainsKey(item.Id))
            {
@@ -91,7 +91,7 @@
        }
        //创建公告牌文本
        private BillboardTextVisual3D CreateTextVisual3D(LogicalTextL3d item)
        private BillboardTextVisual3D CreateTextVisual3D(TextL3d item)
        {
            if (item == null)
            {
Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalLeadLabelVisual3D.cs
ÎļþÃû´Ó Yw.WpfUI.Hydro.L3d.Core/03-logical/03-text/LogicalBillboardLeadLabelVisual3D.cs ÐÞ¸Ä
@@ -3,7 +3,7 @@
    /// <summary>
    /// æŠ½è±¡å¼•线标签
    /// </summary>
    public class LogicalBillboardLeadLabelVisual3D : ModelVisual3D
    public class LogicalLeadLabelVisual3D : ModelVisual3D
    {
    }
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/01-effect/LogicalFlowEffect3D.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,216 @@
using System.Diagnostics;
using System.Windows.Threading;
namespace Yw.WpfUI.Hydro
{
    internal class LogicalFlowEffect3D : ModelVisual3D
    {
        public LogicalFlowEffect3D(LogicalLink3D link, LogicalMaterialHelper materialHelper)
        {
            _link = link;
            _materialHelper = materialHelper;
            this.Content = new Model3DGroup();
            InitializeParticles();
            _animationTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(16)
            };
        }
        private readonly LogicalMaterialHelper _materialHelper = null;
        private const int _max_particles = 500;//最大粒子数
        private readonly LogicalLink3D _link;//管段
        private readonly Random _random = new();//随机
        private readonly List<LogicalParticle3D> _particles = new(_max_particles);//粒子
        private readonly DispatcherTimer _animationTimer;//动画定时器
        private readonly Stopwatch _stopWatch = new();//秒表
        /// <summary>
        /// æµé€Ÿ
        /// </summary>
        public double FlowRate { get; set; } = 1.0;
        /// <summary>
        /// æ¹æµ
        /// </summary>
        public double Turbulence { get; set; } = 0.3;
        /// <summary>
        /// æ˜¯å¦è¿è¡Œ
        /// </summary>
        public bool IsRunning { get; private set; }
        #region åŸºç¡€æ–¹æ³•
        //计算最优粒子数量
        private int CalculateOptimalParticleCount()
        {
            var diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var length = (_link.EndPosition - _link.StartPosition).Length;
            double volume = Math.PI * Math.Pow(diameter / 2, 2) * length;
            int count = (int)(volume * 0.3);
            return Math.Clamp(count, 20, _max_particles);
        }
        //计算粒子尺寸
        private double CalculateParticleSize()
        {
            var diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var length = (_link.EndPosition - _link.StartPosition).Length;
            return diameter * (_random.NextDouble() * 0.3 + 0.2);
        }
        //应用湍流
        private Point3D ApplyTurbulence(Point3D position, Vector3D velocity)
        {
            double diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var normal1 = Vector3D.CrossProduct(velocity, new Vector3D(0, 0, 1));
            var normal2 = Vector3D.CrossProduct(velocity, normal1);
            double turbulence = Turbulence * diameter;
            //position += normal1 * (_random.NextDouble() - 0.5) * turbulence;
            //position += normal2 * (_random.NextDouble() - 0.5) * turbulence;
            return position;
        }
        //获取沿着管段的点
        private Point3D GetPointAlongLink(double t)
        {
            return new Point3D(
                _link.EndPosition.X + t * (_link.EndPosition.X - _link.StartPosition.X),
                _link.StartPosition.Y + t * (_link.EndPosition.Y - _link.StartPosition.Y),
                _link.StartPosition.Z + t * (_link.EndPosition.Z - _link.StartPosition.Z));
        }
        //获取基础速度
        private Vector3D GetBaseVelocity()
        {
            var direction = _link.EndPosition - _link.StartPosition;
            direction.Normalize();
            return direction;
        }
        //是否管段外部
        private bool IsOutsideLink(Point3D point)
        {
            var linkVec = _link.EndPosition - _link.StartPosition;
            var pointVec = point - _link.StartPosition;
            double dot = Vector3D.DotProduct(linkVec, pointVec);
            if (dot < 0 || dot > linkVec.LengthSquared)
            {
                return true;
            }
            double diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            double distance = (pointVec - linkVec * (dot / linkVec.LengthSquared)).Length;
            return distance > diameter * 0.6;
        }
        //重置粒子
        private void ResetParticle(LogicalParticle3D particle)
        {
            double t = _random.NextDouble();
            particle.Position = GetPointAlongLink(t);
            particle.Velocity = GetBaseVelocity() * (_random.NextDouble() * 0.4 + 0.8);
            particle.Age = 0;
            var position = particle.Position;
            particle.Position = ApplyTurbulence(position, particle.Velocity);
            particle.Update();
        }
        #endregion
        //初始化粒子
        private void InitializeParticles()
        {
            var modelGroup = (Model3DGroup)this.Content;
            modelGroup.Children.Clear();
            int particleCount = CalculateOptimalParticleCount();
            for (int i = 0; i < particleCount; i++)
            {
                var particle = new LogicalParticle3D(_materialHelper);
                particle.Position = _link.StartPosition;
                particle.Size = CalculateParticleSize();
                particle.Color = Colors.Green;
                particle.Lifetime = _random.NextDouble() * 10 + 5;
                particle.Age = _random.NextDouble() * 10;
                ResetParticle(particle);
                _particles.Add(particle);
                modelGroup.Children.Add(particle.Content);
            }
        }
        /// <summary>
        /// å¼€å§‹åŠ¨ç”»
        /// </summary>
        public void Play()
        {
            if (IsRunning)
            {
                return;
            }
            _animationTimer.Tick += OnAnimationFrame;
            _animationTimer.Start();
            _stopWatch.Start();
            this.IsRunning = true;
        }
        /// <summary>
        /// åœæ­¢åŠ¨ç”»
        /// </summary>
        public void Stop()
        {
            if (!IsRunning)
            {
                return;
            }
            _animationTimer.Tick -= OnAnimationFrame;
            _animationTimer.Stop();
            _stopWatch.Stop();
            this.IsRunning = false;
        }
        private void OnAnimationFrame(object sender, EventArgs e)
        {
            double deltaTime = _stopWatch.Elapsed.TotalSeconds;
            _stopWatch.Restart();
            double speedFactor = this.FlowRate * deltaTime * 2;
            foreach (var particle in _particles)
            {
                particle.Age += deltaTime;
                if (particle.Age > particle.Lifetime)
                {
                    ResetParticle(particle);
                    continue;
                }
                particle.Position += particle.Velocity * speedFactor;
                if (IsOutsideLink(particle.Position))
                {
                    ResetParticle(particle);
                    continue;
                }
                if (_random.NextDouble() < 0.1)
                {
                    particle.Position = ApplyTurbulence(particle.Position, particle.Velocity);
                }
                particle.Update();
            }
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/01-effect/LogicalFlowEffectHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡æ°´æµåŠ¨ç”»è¾…åŠ©ç±»
    /// </summary>
    internal class LogicalFlowEffectHelper
    {
        /// <summary>
        ///
        /// </summary>
        public LogicalFlowEffectHelper(HelixViewport3D viewport, LogicalMaterialHelper materialHelper)
        {
            _viewport = viewport;
            _materialHelper = materialHelper;
        }
        private readonly HelixViewport3D _viewport;//三维组件
        private readonly LogicalMaterialHelper _materialHelper;//材质辅助类
        private readonly Dictionary<LogicalLink3D, LogicalFlowEffect3D> _cache = new();//缓存
        public void Load()
        {
        }
        public void Unload()
        {
        }
        public void Update()
        {
        }
        public void Clear()
        {
        }
        /// <summary>
        /// è®¾ç½®æµé€Ÿ
        /// </summary>
        public void SetFlowRate(LogicalLink3D link, double flowRate)
        {
            if (link.Vmo.Id == "918437")
            {
                if (_cache.TryGetValue(link, out var flowEffect))
                {
                    flowEffect.FlowRate = Math.Clamp(flowRate, 0, 2);
                    flowEffect.Turbulence = 0.2 + flowRate * 0.15;
                }
                else
                {
                    flowEffect = new LogicalFlowEffect3D(link, _materialHelper);
                    flowEffect.FlowRate = Math.Clamp(flowRate, 0, 2);
                    flowEffect.Turbulence = 0.2 + flowRate * 0.15;
                    _viewport.Children.Add(flowEffect);
                    flowEffect.Play();
                }
            }
        }
        public void StartAllAnimations()
        {
            foreach (var system in _cache.Values)
            {
                system.Play();
            }
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/01-effect/LogicalParticle3D.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,122 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡3D粒子
    /// </summary>
    internal class LogicalParticle3D
    {
        /// <summary>
        ///
        /// </summary>
        public LogicalParticle3D(LogicalMaterialHelper materialHelper)
        {
            _materialHelper = materialHelper;
        }
        private readonly LogicalMaterialHelper _materialHelper = null;
        /// <summary>
        /// ä½ç½®
        /// </summary>
        public Point3D Position { get; set; }
        /// <summary>
        /// æµé€Ÿ
        /// </summary>
        public Vector3D Velocity { get; set; }
        /// <summary>
        /// é¢œè‰²
        /// </summary>
        public Color Color { get; set; }
        /// <summary>
        /// å°ºå¯¸
        /// </summary>
        public double Size { get; set; }
        /// <summary>
        /// å¹´é¾„
        /// </summary>
        public double Age { get; set; }
        /// <summary>
        /// ç”Ÿå‘½å‘¨æœŸ
        /// </summary>
        public double Lifetime { get; set; }
        /// <summary>
        /// å†…容
        /// </summary>
        public GeometryModel3D Content
        {
            get
            {
                if (_content == null)
                {
                    _content = new GeometryModel3D()
                    {
                        Material = GetMaterial(this.Color),
                        Geometry = CreateGeometry(this.Size),
                        Transform = CreateTransform()
                    };
                }
                return _content;
            }
        }
        private GeometryModel3D _content;
        //获取材质
        private Material GetMaterial(Color color)
        {
            return _materialHelper.GetMaterial(color);
        }
        //获取材质
        private Material GetMaterial(Color color, double opacity)
        {
            return _materialHelper.GetMaterial(color, opacity);
        }
        //创建几何图形
        private MeshGeometry3D CreateGeometry(double radius)
        {
            var builder = new MeshBuilder();
            builder.AddSphere(new Point3D(0, 0, 0), radius, 12, 12);
            return builder.ToMesh();
        }
        //创建转换
        private TranslateTransform3D CreateTransform()
        {
            return new TranslateTransform3D()
            {
                OffsetX = this.Position.X,
                OffsetY = this.Position.Y,
                OffsetZ = this.Position.Z
            };
        }
        /// <summary>
        /// æ›´æ–°
        /// </summary>
        public void Update()
        {
            var content = this.Content;
            double lifeRatio = this.Age / this.Lifetime;
            if (lifeRatio > 0.8)
            {
                var opacity = 1.0 - (lifeRatio - 0.8) * 5;
                content.Material = GetMaterial(this.Color, opacity);
            }
            content.Geometry = CreateGeometry(this.Size);
            var transform = content.Transform as TranslateTransform3D;
            transform.OffsetX = this.Position.X;
            transform.OffsetY = this.Position.Y;
            transform.OffsetZ = this.Position.Z;
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/02-direction/LogicalFlowDirection3D.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,101 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡3D水流方向
    /// </summary>
    internal class LogicalFlowDirection3D : MeshGeometryVisual3D, IDisposable
    {
        /// <summary>
        ///
        /// </summary>
        public LogicalFlowDirection3D
            (
                LogicalLink3D link,
                LogicalMaterialHelper materialHelper,
                bool positive = true
            )
        {
            _link = link;
            _link.VisualChangedEvent += OnVisualChanged;
            _materialHelper = materialHelper;
            _positive = positive;
            UpdateVisual();
        }
        private readonly LogicalLink3D _link;//管段
        private readonly LogicalMaterialHelper _materialHelper;//材质辅助类
        /// <summary>
        /// æ­£å‘
        /// </summary>
        public bool Positive
        {
            get { return _positive; }
            set { _positive = value; }
        }
        private bool _positive = true;
        /// <summary>
        /// æ›´æ–°æè´¨
        /// </summary>
        public void UpdateMaterial()
        {
            this.Material = _materialHelper.GetMaterial(Colors.Green);
        }
        /// <summary>
        /// æ›´æ–°å‡ ä½•图形
        /// </summary>
        public void UpdateGeometry()
        {
            var diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var center = _link.StartPosition + (_link.EndPosition - _link.StartPosition) / 2d;
            var start = _link.StartPosition + (center - _link.StartPosition) / 2d;
            var end = center + (_link.EndPosition - center) / 2d;
            var builder = new MeshBuilder();
            if (this.Positive)
            {
                builder.AddArrow(start, end, diameter);
            }
            else
            {
                builder.AddArrow(end, start, diameter);
            }
            var geometry = builder.ToMesh();
            this.MeshGeometry = geometry;
        }
        /// <summary>
        /// æ›´æ–°å¯è§æ€§
        /// </summary>
        public void UpdateVisibility()
        {
            this.Visible = _link.Visible;
        }
        /// <summary>
        /// æ›´æ–°å¯è§å…ƒç´ 
        /// </summary>
        public void UpdateVisual()
        {
            this.UpdateMaterial();
            this.UpdateGeometry();
            this.UpdateVisibility();
        }
        //处理可见事件
        private void OnVisualChanged()
        {
            this.UpdateVisual();
        }
        /// <summary>
        /// é‡Šæ”¾
        /// </summary>
        public void Dispose()
        {
            _link.VisualChangedEvent -= OnVisualChanged;
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/02-direction/LogicalFlowDirection3DGroup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡3D水流方向组
    /// </summary>
    internal class LogicalFlowDirection3DGroup : ModelVisual3D
    {
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/06-flow/02-direction/LogicalFlowDirectionHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡
    /// </summary>
    internal class LogicalFlowDirectionHelper
    {
        /// <summary>
        ///
        /// </summary>
        public LogicalFlowDirectionHelper
            (
                HelixViewport3D viewport,
                LogicalMaterialHelper materialHelper
            )
        {
            _viewport = viewport;
            _materialHelper = materialHelper;
        }
        private readonly HelixViewport3D _viewport;//三维组件
        private readonly LogicalMaterialHelper _materialHelper;//材质辅助类
        private readonly LogicalFlowDirection3DGroup _group = new();//方向组
        private readonly Dictionary<LogicalLink3D, LogicalFlowDirection3D> _cache = new();//缓存
        /// <summary>
        /// è®¾ç½®
        /// </summary>
        public void Set(List<LogicalLink3D> allLinkList)
        {
            Clear();
            if (allLinkList == null || allLinkList.Count < 1)
            {
                return;
            }
            foreach (var link in allLinkList)
            {
                var direction = new LogicalFlowDirection3D(link, _materialHelper);
                _cache.Add(link, direction);
                _group.Children.Add(direction);
            }
            Append();
        }
        /// <summary>
        /// è®¾ç½®
        /// </summary>
        public void Set(Dictionary<LogicalLink3D, bool> dict)
        {
            Clear();
            if (dict == null || dict.Count < 1)
            {
                return;
            }
            foreach (var item in dict)
            {
                var direction = new LogicalFlowDirection3D(item.Key, _materialHelper, item.Value);
                _cache.Add(item.Key, direction);
                _group.Children.Add(direction);
            }
            Append();
        }
        /// <summary>
        /// æ¸…除
        /// </summary>
        public void Clear()
        {
            if (_cache.Count > 0)
            {
                foreach (var item in _cache)
                {
                    item.Value.Dispose();
                }
                _cache.Clear();
            }
            _group.Children.Clear();
        }
        //附加
        private void Append()
        {
            var group = _viewport.Children.OfType<LogicalFlowDirection3DGroup>().FirstOrDefault();
            if (group == null)
            {
                _viewport.Children.Add(_group);
            }
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/08-manager/LogicalEditManager.cs
@@ -820,5 +820,6 @@
        #endregion
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/08-manager/LogicalManager.cs
@@ -1,6 +1,4 @@
using System.Windows.Controls;
namespace Yw.WpfUI.Hydro
namespace Yw.WpfUI.Hydro
{
    /// <summary>
    /// æŠ½è±¡ç®¡ç†å™¨
@@ -20,8 +18,9 @@
            _highlightHelper = new LogicalHighlightHelper(_viewport);
            _selectionHelper = new LogicalSelectionHelper(_viewport);
            _zoomHelper = new LogicalZoomHelper(_viewport);
            _billboardTextHelper = new LogicalBillboardLeadLabelHelper(_viewport);
            _billboardTextHelper = new LogicalBillboardTextHelper(_viewport);
            _cameraHelper = new LogicalCameraHelper(_viewport);
            _flowDirectionHelper = new LogicalFlowDirectionHelper(_viewport, _materialHelper);
        }
        #region äº‹ä»¶é›†åˆ
@@ -46,8 +45,9 @@
        protected readonly LogicalHighlightHelper _highlightHelper = null;//高亮辅助类
        protected readonly LogicalSelectionHelper _selectionHelper = null;//选择辅助类
        protected readonly LogicalZoomHelper _zoomHelper = null;//缩放辅助类
        protected readonly LogicalBillboardLeadLabelHelper _billboardTextHelper = null;//公告版文字辅助类
        protected readonly LogicalBillboardTextHelper _billboardTextHelper = null;//公告版文字辅助类
        protected readonly LogicalCameraHelper _cameraHelper = null;//相机辅助类
        protected readonly LogicalFlowDirectionHelper _flowDirectionHelper = null;//水流方向辅助类
        #endregion
@@ -436,6 +436,45 @@
        #endregion
        #region å¿«æ·æ–¹æ³•
        //获取Visual3D
        protected virtual LogicalVisual3D GetVisual3D(string Id)
        {
            if (!Initialized)
            {
                return default;
            }
            var id = Id?.Trim();
            if (string.IsNullOrEmpty(id))
            {
                return default;
            }
            if (_allVisualL3dDict.ContainsKey(id))
            {
                var visual = _allVisualL3dDict[Id];
                if (_allVisualLogicalDict.ContainsKey(visual))
                {
                    var visual3d = _allVisualLogicalDict[visual];
                    return visual3d;
                }
            }
            return default;
        }
        //获取Visual3D
        protected virtual List<LogicalVisual3D> GetVisual3D(List<string> Ids)
        {
            if (!Initialized)
            {
                return default;
            }
            var list = Ids?.Select(x => GetVisual3D(x)).Where(x => x != null).ToList();
            return list;
        }
        #endregion
        #region è§†è§’
        /// <summary>
@@ -710,12 +749,110 @@
        #endregion
        #region ç¼©æ”¾
        /// <summary>
        /// ç¼©æ”¾è‡³å¯è§æž„ä»¶
        /// </summary>
        public virtual void ZoomToVisual(string Id)
        {
            if (!Initialized)
            {
                return;
            }
            var visual3d = GetVisual3D(Id);
            if (visual3d != null)
            {
                _zoomHelper.ZoomToVisual(visual3d);
            }
        }
        /// <summary>
        /// ç¼©æ”¾è‡³å¯è§æž„ä»¶
        /// </summary>
        public virtual void ZoomToVisual(List<string> Ids)
        {
            if (!Initialized)
            {
                return;
            }
            var visual3ds = GetVisual3D(Ids);
            if (visual3ds != null && visual3ds.Count > 0)
            {
                _zoomHelper.ZoomToVisual(visual3ds);
            }
        }
        #endregion
        #region é€‰æ‹©
        /// <summary>
        /// é€‰æ‹©å¯è§æž„ä»¶
        /// </summary>
        public virtual void SelectVisual(string Id)
        {
            if (!Initialized)
            {
                return;
            }
            var visual3d = GetVisual3D(Id);
            _selectionHelper.SelectVisual(visual3d);
        }
        /// <summary>
        /// é€‰æ‹©å¯è§æž„ä»¶
        /// </summary>
        public virtual void SelectVisual(List<string> Ids)
        {
            if (!Initialized)
            {
                return;
            }
            var visual3ds = GetVisual3D(Ids);
            _selectionHelper.SelectVisual(visual3ds);
        }
        #endregion
        #region ç¼©æ”¾å¹¶é€‰æ‹©
        /// <summary>
        /// ç¼©æ”¾å¹¶é€‰æ‹©å¯è§æž„ä»¶
        /// </summary>
        public virtual void ZoomAndSelectVisual(string Id)
        {
            if (!Initialized)
            {
                return;
            }
            var visual3d = GetVisual3D(Id);
            _zoomHelper.ZoomToVisual(visual3d);
            _selectionHelper.SelectVisual(visual3d);
        }
        /// <summary>
        /// ç¼©æ”¾å¹¶é€‰æ‹©å¯è§æž„ä»¶
        /// </summary>
        public virtual void ZoomAndSelectVisual(List<string> Ids)
        {
            if (!Initialized)
            {
                return;
            }
            var visual3ds = GetVisual3D(Ids);
            _zoomHelper.ZoomToVisual(visual3ds);
            _selectionHelper.SelectVisual(visual3ds);
        }
        #endregion
        #region å…¬å‘Šæ¿æ–‡æœ¬
        /// <summary>
        /// è®¾ç½®å…¬å‘Šæ¿æ–‡æœ¬
        /// </summary>
        public virtual void SetBillboardText(List<LogicalTextL3d> items)
        public virtual void SetBillboardText(List<TextL3d> items)
        {
            if (!Initialized)
            {
@@ -727,7 +864,7 @@
        /// <summary>
        /// æ›´æ–°å…¬å‘Šæ¿æ–‡æœ¬
        /// </summary>
        public virtual void UpdateBillboardText(LogicalTextL3d item)
        public virtual void UpdateBillboardText(TextL3d item)
        {
            if (!Initialized)
            {
@@ -739,7 +876,7 @@
        /// <summary>
        /// æ›´æ–°å…¬å‘Šæ¿æ–‡æœ¬
        /// </summary>
        public virtual void UpdateBillboardText(List<LogicalTextL3d> items)
        public virtual void UpdateBillboardText(List<TextL3d> items)
        {
            if (!Initialized)
            {
@@ -791,7 +928,50 @@
        #endregion
        #region æ°´æµæ–¹å‘
        /// <summary>
        /// æ˜¾ç¤ºæ°´æµæ–¹å‘
        /// </summary>
        public void ShowFlowDirection()
        {
            var allLinkList = _allVisualLogicalDict.Values.Where(x => x is LogicalLink3D).Select(x => x as LogicalLink3D).ToList();
            _flowDirectionHelper.Set(allLinkList);
        }
        /// <summary>
        /// è®¾ç½®æ°´æµæ–¹å‘
        /// </summary>
        public void SetFlowDirection(List<FlowDirectionL3d> list)
        {
            var dict = new Dictionary<LogicalLink3D, bool>();
            list?.ForEach(x =>
            {
                if (_allVisualL3dDict.ContainsKey(x.Id))
                {
                    var visual = _allVisualL3dDict[x.Id];
                    if (_allVisualLogicalDict.ContainsKey(visual))
                    {
                        var visual3d = _allVisualLogicalDict[visual];
                        if (visual3d is LogicalLink3D link3d)
                        {
                            dict.Add(link3d, x.Positive);
                        }
                    }
                }
            });
            _flowDirectionHelper.Set(dict);
        }
        /// <summary>
        /// æ¸…除水流方向
        /// </summary>
        public void ClearFlowDirection()
        {
            _flowDirectionHelper.Clear();
        }
        #endregion
    }
Yw.WpfUI.Hydro.L3d.Core/03-logical/09-control/LogicalEditerL3d.xaml.cs
@@ -148,7 +148,7 @@
        #region å…¬å‘Šæ¿æ–‡æœ¬
        public void SetBillboardText(List<LogicalTextL3d> items)
        public void SetBillboardText(List<TextL3d> items)
        {
            _manager.SetBillboardText(items);
        }
@@ -248,5 +248,11 @@
        }
        #endregion
        public void ShowFlowDirection()
        {
            _manager.ShowFlowDirection();
        }
    }
}
Yw.WpfUI.Hydro.L3d.Core/03-logical/09-control/LogicalViewerL3d.xaml
@@ -14,7 +14,7 @@
            x:Name="viewport"
            ShowCoordinateSystem="True"
            ZoomExtentsWhenLoaded="True">
            <hx:DefaultLights />
            <hx:SunLight />
        </hx:HelixViewport3D>
    </Grid>
</UserControl>
Yw.WpfUI.Hydro.L3d.Core/03-logical/09-control/LogicalViewerL3d.xaml.cs
@@ -40,6 +40,8 @@
        #endregion
        #region åˆå§‹åŒ–
        /// <summary>
        /// åˆå§‹åŒ–
        /// </summary>
@@ -50,5 +52,196 @@
            _manager.SelectionChangedEvent += (List<VisualL3d> visuals) => this.SelectionChangedEvent?.Invoke(visuals);
        }
        #endregion
        #region ç›¸æœºè§†è§’
        /// <summary>
        /// è®¾ç½®ä¸Šè§†å›¾
        /// </summary>
        public void SetTopView()
        {
            _manager?.SetTopView();
        }
        /// <summary>
        /// è®¾ç½®ä¸‹è§†å›¾
        /// </summary>
        public void SetBottomView()
        {
            _manager?.SetBottomView();
        }
        /// <summary>
        /// è®¾ç½®å·¦è§†å›¾
        /// </summary>
        public void SetLeftView()
        {
            _manager?.SetLeftView();
        }
        /// <summary>
        /// è®¾ç½®å³è§†å›¾
        /// </summary>
        public void SetRightView()
        {
            _manager?.SetRightView();
        }
        /// <summary>
        /// è®¾ç½®å‰è§†å›¾
        /// </summary>
        public void SetFrontView()
        {
            _manager?.SetFrontView();
        }
        /// <summary>
        /// è®¾ç½®åŽè§†å›¾
        /// </summary>
        public void SetBackView()
        {
            _manager?.SetBackView();
        }
        /// <summary>
        /// è¥¿å—视角
        /// ä»Žç‰©ä½“的左前下方观察
        /// </summary>
        public void SetSouthWestView()
        {
            _manager?.SetSouthWestView();
        }
        /// <summary>
        /// ä¸œå—视角
        /// ä»Žç‰©ä½“的右前下方观察
        /// </summary>
        public void SetSouthEastView()
        {
            _manager?.SetSouthEastView();
        }
        /// <summary>
        /// ä¸œåŒ—视角
        /// ä»Žç‰©ä½“的右后上方观察
        /// </summary>
        public void SetNorthEastView()
        {
            _manager?.SetNorthEastView();
        }
        /// <summary>
        /// è¥¿åŒ—视角
        /// ä»Žç‰©ä½“的左后上方观察
        /// </summary>
        public void SetNorthWestView()
        {
            _manager?.SetNorthWestView();
        }
        #endregion
        #region ç½‘格线
        /// <summary>
        /// æ˜¾ç¤ºç½‘格线
        /// </summary>
        public void ShowGridLines()
        {
            _manager?.ShowGridLines();
        }
        /// <summary>
        /// éšè—ç½‘格线
        /// </summary>
        public void HideGridLines()
        {
            _manager?.HideGridLines();
        }
        /// <summary>
        /// ç½‘格线可见性
        /// </summary>
        public bool GridLinesVisible
        {
            get
            {
                return _manager == null ? false : _manager.GridLinesVisible;
            }
            set
            {
                if (_manager != null)
                {
                    _manager.GridLinesVisible = value;
                }
            }
        }
        #endregion
        #region ç¼©æ”¾è‡³æž„ä»¶
        /// <summary>
        /// ç¼©æ”¾è‡³å¯è§æž„ä»¶
        /// </summary>
        public void ZoomToVisual(string Id)
        {
            _manager?.ZoomToVisual(Id);
        }
        /// <summary>
        /// ç¼©æ”¾è‡³å¯è§æž„ä»¶
        /// </summary>
        public void ZoomToVisual(List<string> Ids)
        {
            _manager?.ZoomToVisual(Ids);
        }
        #endregion
        #region é€‰æ‹©æž„ä»¶
        /// <summary>
        /// é€‰æ‹©æž„ä»¶
        /// </summary>
        public void SelectVisual(string Id)
        {
            _manager?.SelectVisual(Id);
        }
        /// <summary>
        /// é€‰æ‹©æž„ä»¶
        /// </summary>
        public void SelectVisual(List<string> Ids)
        {
            _manager?.SelectVisual(Ids);
        }
        #endregion
        #region ç¼©æ”¾å¹¶é€‰æ‹©æž„ä»¶
        /// <summary>
        /// ç¼©æ”¾å¹¶é€‰æ‹©æž„ä»¶
        /// </summary>
        public void ZoomAndSelectVisual(string Id)
        {
            _manager?.ZoomAndSelectVisual(Id);
        }
        /// <summary>
        /// ç¼©æ”¾å¹¶é€‰æ‹©æž„ä»¶
        /// </summary>
        public void ZoomAndSelectVisual(List<string> Ids)
        {
            _manager?.ZoomAndSelectVisual(Ids);
        }
        #endregion
    }
}
Yw.WpfUI.Hydro.L3d.Core/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -2,7 +2,7 @@
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
  <PropertyGroup>
    <History>True|2025-04-03T06:51:22.5389895Z||;True|2025-04-03T13:39:16.2049845+08:00||;</History>
    <History>True|2025-04-22T07:43:19.8599243Z||;True|2025-04-03T14:51:22.5389895+08:00||;True|2025-04-03T13:39:16.2049845+08:00||;</History>
    <LastFailureDetails />
  </PropertyGroup>
</Project>
Yw.WpfUI.Hydro.L3d.Core/Yw.WpfUI.Hydro.L3d.Core.csproj
@@ -7,7 +7,7 @@
        <UseWPF>true</UseWPF>
        <ImplicitUsings>enable</ImplicitUsings>
        <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
        <Version>1.0.1</Version>
        <Version>1.0.2</Version>
    </PropertyGroup>
    <ItemGroup>
@@ -21,7 +21,7 @@
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="HelixToolkit.Core.Wpf" Version="2.26.0" />
        <PackageReference Include="HelixToolkit.Core.Wpf" Version="2.27.0" />
        <PackageReference Include="Yw.Newtonsoft.Core" Version="3.0.0" />
        <PackageReference Include="Yw.Untity.Core" Version="3.0.6" />
    </ItemGroup>
Yw.WpfUI.Test.Core/MainWindow.xaml
@@ -130,6 +130,7 @@
                Checked="ckBackgroud_Checked"
                Content="背景"
                Unchecked="ckBackgroud_Unchecked" />
            <Button Click="FlowEffect_Click" Content="水流动画" />
        </ToolBar>
        <local:LogicalEditerL3d Name="editer" Grid.Row="1" />
    </Grid>
Yw.WpfUI.Test.Core/MainWindow.xaml.cs
@@ -170,7 +170,7 @@
        private void BillboardText_Click(object sender, RoutedEventArgs e)
        {
            var list = _nw.Visuals.Select(x => new LogicalTextL3d()
            var list = _nw.Visuals.Select(x => new TextL3d()
            {
                Id = x.Id,
                Text = x.Id
@@ -238,6 +238,11 @@
        {
            this.editer.EndEdit();
        }
        private void FlowEffect_Click(object sender, RoutedEventArgs e)
        {
            this.editer.ShowFlowDirection();
        }
    }