| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// é¿åº¦ |
| | | /// </summary> |
| | | public float LengthSquared() |
| | | { |
| | | return X * X + Y * Y + Z * Z; |
| | | } |
| | | public float Length => MathF.Sqrt(X * X + Y * Y + Z * Z); |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public float Length() |
| | | { |
| | | return (float)Math.Sqrt(LengthSquared()); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// 缩æ¾å°åä½é¿åº¦ |
| | | /// </summary> |
| | | public void Normalize() |
| | | { |
| | | float length = Length(); |
| | | var length = Length; |
| | | if (length > 0) |
| | | { |
| | | X /= length; |
| | | Y /= length; |
| | | Z /= length; |
| | | float num = 1f / Length; |
| | | X *= num; |
| | | Y *= num; |
| | | Z *= num; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 缩æ¾å°åä½é¿åº¦ |
| | | /// </summary> |
| | | public PointL3d Normalized() |
| | | { |
| | | var result = this; |
| | | result.Normalize(); |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// - è¿ç® |
| | | /// </summary> |
| | | public static PointL3d operator -(PointL3d a, PointL3d b) |
| | |
| | |  |
| | | using OpenTK.Mathematics; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// |
| | |
| | | return _parters.Exists(x => x.Id == id); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åå
å´ç |
| | | /// </summary> |
| | | public BoundingBoxL3d GetBoundingBox() |
| | | { |
| | | var minX = float.MaxValue; |
| | | var minY = float.MaxValue; |
| | | var minZ = float.MaxValue; |
| | | var maxX = float.MinValue; |
| | | var maxY = float.MinValue; |
| | | var maxZ = float.MinValue; |
| | | |
| | | foreach (var node in this.Nodes) |
| | | { |
| | | minX = Math.Min(minX, node.Position.X); |
| | | minY = Math.Min(minY, node.Position.Y); |
| | | minZ = Math.Min(minZ, node.Position.Z); |
| | | maxX = Math.Max(maxX, node.Position.X); |
| | | maxY = Math.Max(maxY, node.Position.Y); |
| | | maxZ = Math.Max(maxZ, node.Position.Z); |
| | | } |
| | | |
| | | return new BoundingBoxL3d() |
| | | { |
| | | Min = new PointL3d(minX, minY, minZ), |
| | | Max = new PointL3d(maxX, maxY, maxZ) |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åä¸å¿ç¹ |
| | | /// </summary> |
| | | public PointL3d GetCenter(BoundingBoxL3d boundingBox) |
| | | { |
| | | if (boundingBox == null) |
| | | { |
| | | boundingBox = GetBoundingBox(); |
| | | } |
| | | return boundingBox.GetCenter(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç»å¶2d |
| | | /// </summary> |
| | | public void Draw2d() |
| | | { |
| | | this.Links?.ForEach(x => x.Draw2d()); |
| | | this.Nodes?.ForEach(x => x.Draw2d()); |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | public VisualL3d(VisualL3d rhs) : base(rhs) { } |
| | | |
| | | /// <summary> |
| | | /// ç¶æ |
| | | /// æ¯å¦æ¬å |
| | | /// </summary> |
| | | internal eVisualState State { get; set; } |
| | | public bool IsHovered { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 2dç»å¶ |
| | | /// æ¯å¦éæ© |
| | | /// </summary> |
| | | public abstract void Draw2d(); |
| | | public bool IsSelected { get; set; } |
| | | |
| | | /// <summary> |
| | | /// è·åä½ç½® |
| | | /// </summary> |
| | | public abstract List<PointL3d> GetPositions(); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | |  |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// èç¹ |
| | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public NodeL3d() { } |
| | | public NodeL3d() |
| | | { |
| | | this.Style2d = new StyleNode2dL3d() |
| | | { |
| | | Normal = new StylePoint2dL3d(3f, Color.Red), |
| | | Hovered = new StylePoint2dL3d(6f, "#00BFFF"), |
| | | Selected = new StylePoint2dL3d(4f, "#008000") |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | |
| | | public NodeL3d(NodeL3d rhs) : base(rhs) |
| | | { |
| | | this.Position = new PointL3d(rhs.Position); |
| | | this.Style2d = new StyleNode2dL3d(rhs.Style2d); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | public PointL3d Position { get; set; } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// 2dæ ·å¼ |
| | | /// </summary> |
| | | public override void Draw2d() |
| | | public StyleNode2dL3d Style2d { get; set; } |
| | | |
| | | /// <summary> |
| | | /// è·åä½ç½® |
| | | /// </summary> |
| | | public override List<PointL3d> GetPositions() |
| | | { |
| | | switch (this.State) |
| | | { |
| | | case eVisualState.Normal: DrawPoint2dHelper.Draw(5f, Color.Red, this.Position); break; |
| | | case eVisualState.Hovered: DrawPoint2dHelper.Draw(6f, ColorTranslator.FromHtml("#00BFFF"), this.Position); break; |
| | | case eVisualState.Selected: DrawPoint2dHelper.Draw(7f, ColorTranslator.FromHtml("#008000"), this.Position); break; |
| | | default: break; |
| | | } |
| | | return new List<PointL3d>() { this.Position }; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | } |
| | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public LinkL3d() { } |
| | | public LinkL3d() |
| | | { |
| | | this.Style2d = new StyleLink2dL3d() |
| | | { |
| | | Normal = new StyleLine2dL3d(2f, Color.Blue), |
| | | Hovered = new StyleLine2dL3d(5f, "#00BFFF"), |
| | | Selected = new StyleLine2dL3d(3f, "#800080") |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | |
| | | { |
| | | this.StartPosition = new PointL3d(rhs.StartPosition); |
| | | this.EndPosition = new PointL3d(rhs.EndPosition); |
| | | this.Style2d = new StyleLink2dL3d(rhs.Style2d); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | public PointL3d EndPosition { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä½ç½®å表 |
| | | /// 2dæ ·å¼ |
| | | /// </summary> |
| | | public virtual List<PointL3d> Positions |
| | | { |
| | | get |
| | | { |
| | | return new List<PointL3d>() { this.StartPosition, this.EndPosition }; |
| | | } |
| | | } |
| | | public StyleLink2dL3d Style2d { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç»å¶ |
| | | /// è·åä½ç½® |
| | | /// </summary> |
| | | public override void Draw2d() |
| | | public override List<PointL3d> GetPositions() |
| | | { |
| | | switch (this.State) |
| | | { |
| | | case eVisualState.Normal: DrawLine2dHelper.Draw(2f, Color.Blue, this.StartPosition, this.EndPosition); break; |
| | | case eVisualState.Hovered: DrawLine2dHelper.Draw(3f, ColorTranslator.FromHtml("#00BFFF"), this.StartPosition, this.EndPosition); break; |
| | | case eVisualState.Selected: DrawLine2dHelper.Draw(3.5f, ColorTranslator.FromHtml("#800080"), this.StartPosition, this.EndPosition); break; |
| | | default: break; |
| | | } |
| | | return new List<PointL3d>() { this.StartPosition, this.EndPosition }; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// 2dæ ·å¼ |
| | | /// </summary> |
| | | public class Style2dL3d |
| | | { |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public class StyleLink2dL3d : Style2dL3d |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleLink2dL3d() { } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleLink2dL3d(StyleLink2dL3d rhs) |
| | | { |
| | | this.Normal = new StyleLine2dL3d(rhs.Normal); |
| | | this.Hovered = new StyleLine2dL3d(rhs.Hovered); |
| | | this.Selected = new StyleLine2dL3d(rhs.Selected); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£å¸¸ |
| | | /// </summary> |
| | | public StyleLine2dL3d Normal { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¬å |
| | | /// </summary> |
| | | public StyleLine2dL3d Hovered { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éæ© |
| | | /// </summary> |
| | | public StyleLine2dL3d Selected { get; set; } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public class StyleNode2dL3d : Style2dL3d |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleNode2dL3d() { } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleNode2dL3d(StyleNode2dL3d rhs) |
| | | { |
| | | this.Normal = new StylePoint2dL3d(rhs.Normal); |
| | | this.Hovered = new StylePoint2dL3d(rhs.Hovered); |
| | | this.Selected = new StylePoint2dL3d(rhs.Selected); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£å¸¸ |
| | | /// </summary> |
| | | public StylePoint2dL3d Normal { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¬å |
| | | /// </summary> |
| | | public StylePoint2dL3d Hovered { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éæ© |
| | | /// </summary> |
| | | public StylePoint2dL3d Selected { get; set; } |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// 2dç¹æ ·å¼ |
| | | /// </summary> |
| | | public class StylePoint2dL3d |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StylePoint2dL3d() { } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StylePoint2dL3d(float radiu, Color color) |
| | | { |
| | | this.Radiu = radiu; |
| | | this.Color = color; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StylePoint2dL3d(float radiu, string htmlColor) |
| | | { |
| | | this.Radiu = radiu; |
| | | this.Color = ColorTranslator.FromHtml(htmlColor); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StylePoint2dL3d(StylePoint2dL3d rhs) |
| | | { |
| | | this.Radiu = rhs.Radiu; |
| | | this.Color = rhs.Color; |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// åå¾ |
| | | /// </summary> |
| | | public float Radiu { get; set; } |
| | | |
| | | /// <summary> |
| | | /// é¢è² |
| | | /// </summary> |
| | | public Color Color { get; set; } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public class StyleLine2dL3d |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleLine2dL3d() { } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleLine2dL3d(float width, Color color) |
| | | { |
| | | this.Width = width; |
| | | this.Color = color; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleLine2dL3d(float width, string htmlColor) |
| | | { |
| | | this.Width = width; |
| | | this.Color = ColorTranslator.FromHtml(htmlColor); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public StyleLine2dL3d(StyleLine2dL3d rhs) |
| | | { |
| | | this.Width = rhs.Width; |
| | | this.Color = rhs.Color; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 线宽 |
| | | /// </summary> |
| | | public float Width { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çº¿è² |
| | | /// </summary> |
| | | public Color Color { get; set; } |
| | | |
| | | } |
| | | } |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// å
å´ç |
| | | /// </summary> |
| | | internal struct BoundingBox3 |
| | | internal class BoundingBox3 |
| | | { |
| | | /// <summary> |
| | | /// |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// å
å´çç¼åè¾
å©ç±» |
| | | /// </summary> |
| | | internal class BoundingBox32dCacheHelper |
| | | { |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public BoundingBox32dCacheHelper(NetworkL3d nw, Vector32dCacheHelper vc) |
| | | { |
| | | _nw = nw; |
| | | _vc = vc; |
| | | Initial(); |
| | | } |
| | | |
| | | private NetworkL3d _nw = null; |
| | | private Vector32dCacheHelper _vc = null; |
| | | private Dictionary<string, BoundingBox3> _dict = new(); |
| | | |
| | | //åå§å |
| | | private void Initial() |
| | | { |
| | | if (_nw == null) |
| | | { |
| | | return; |
| | | } |
| | | if (_vc == null) |
| | | { |
| | | return; |
| | | } |
| | | _dict.Clear(); |
| | | _nw.Nodes.ForEach(x => |
| | | { |
| | | var pts = _vc.GetPositions(x.Id); |
| | | if (pts != null && pts.Count > 0) |
| | | { |
| | | var bx = BoundingBox3Helper.CalcuPointBoundingBox(pts[0], x.Style2d.Normal.Radiu); |
| | | _dict.Add(x.Id, bx); |
| | | } |
| | | }); |
| | | _nw.Links.ForEach((Action<LinkL3d>)(x => |
| | | { |
| | | var pts = _vc.GetPositions(x.Id); |
| | | if (pts != null && pts.Count > 0) |
| | | { |
| | | var bx = BoundingBox3Helper.CalcuLineBoundingBox(pts[0], pts[1], x.Style2d.Normal.Width); |
| | | _dict.Add(x.Id, bx); |
| | | } |
| | | })); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åå
å´ç |
| | | /// </summary> |
| | | public BoundingBox3 GetBoundingBox(string id) |
| | | { |
| | | if (_dict.ContainsKey(id)) |
| | | { |
| | | return _dict[id]; |
| | | } |
| | | return default; |
| | | } |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using OpenTK.Mathematics; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// å
å´çè¾
å©ç±» |
| | | /// </summary> |
| | | internal class BoundingBox3Helper |
| | | { |
| | | |
| | | /// <summary> |
| | | /// 计ç®åç¹å
å´ç |
| | | /// </summary> |
| | | /// <param name="pt">åç¹</param> |
| | | /// <param name="radius">åå¾</param> |
| | | /// <returns></returns> |
| | | public static BoundingBox3 CalcuPointBoundingBox(Vector3 pt, float radius) |
| | | { |
| | | var min = pt - new Vector3(radius); |
| | | var max = pt + new Vector3(radius); |
| | | return new BoundingBox3(min, max); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 计ç®åæ±ä½ç轴对é½å
å´çï¼AABBï¼ |
| | | /// </summary> |
| | | public static BoundingBox3 CalcuLineBoundingBox(Vector3 start, Vector3 end, float width) |
| | | { |
| | | var radius = width / 2f; |
| | | Vector3 dir = (end - start).Normalized(); |
| | | float dirX = dir.X, dirY = dir.Y, dirZ = dir.Z; |
| | | |
| | | // 计ç®åè½´ç端ç¹åæ©å±é |
| | | float minX = Math.Min(start.X, end.X); |
| | | float maxX = Math.Max(start.X, end.X); |
| | | float extensionX = radius * (float)MathF.Sqrt(1f - dirX * dirX); |
| | | minX -= extensionX; |
| | | maxX += extensionX; |
| | | |
| | | float minY = Math.Min(start.Y, end.Y); |
| | | float maxY = Math.Max(start.Y, end.Y); |
| | | float extensionY = radius * (float)MathF.Sqrt(1f - dirY * dirY); |
| | | minY -= extensionY; |
| | | maxY += extensionY; |
| | | |
| | | float minZ = Math.Min(start.Z, end.Z); |
| | | float maxZ = Math.Max(start.Z, end.Z); |
| | | float extensionZ = radius * (float)MathF.Sqrt(1f - dirZ * dirZ); |
| | | minZ -= extensionZ; |
| | | maxZ += extensionZ; |
| | | |
| | | return new BoundingBox3(new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ)); |
| | | } |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using OpenTK.Graphics.OpenGL; |
| | | using OpenTK.Mathematics; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// ç»å¶2dè¾
å©ç±» |
| | | /// </summary> |
| | | internal class Draw2dHelper |
| | | { |
| | | |
| | | /// <summary> |
| | | /// ç»å¶ç¹ |
| | | /// </summary> |
| | | /// <param name="size">ç¹å¤§å°</param> |
| | | /// <param name="color">ç¹é¢è²</param> |
| | | /// <param name="pt">ç¹ä½ç½®</param> |
| | | public static void DrawPoint(float size, Color color, PointL3d pt) |
| | | { |
| | | GL.PointSize(size); |
| | | GL.Begin(PrimitiveType.Points); |
| | | GL.Color3(color); |
| | | GL.Vertex3(pt.X, pt.Y, pt.Z); |
| | | GL.End(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç»å¶ç¹ |
| | | /// </summary> |
| | | /// <param name="size">ç¹å¤§å°</param> |
| | | /// <param name="color">ç¹é¢è²</param> |
| | | /// <param name="pt">ç¹ä½ç½®</param> |
| | | public static void DrawPoint(float size, Color color, Vector3 pt) |
| | | { |
| | | GL.PointSize(size); |
| | | GL.Begin(PrimitiveType.Points); |
| | | GL.Color3(color); |
| | | GL.Vertex3(pt.X, pt.Y, pt.Z); |
| | | GL.End(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç»å¶çº¿ |
| | | /// </summary> |
| | | /// <param name="width">线宽</param> |
| | | /// <param name="color">线è²</param> |
| | | /// <param name="spt">å¼å§ç¹</param> |
| | | /// <param name="ept">ç»æç¹</param> |
| | | public static void DrawLine(float width, Color color, PointL3d spt, PointL3d ept) |
| | | { |
| | | GL.LineWidth(width); |
| | | GL.Begin(PrimitiveType.Lines); |
| | | GL.Color3(color); |
| | | GL.Vertex3(spt.X, spt.Y, spt.Z); |
| | | GL.Vertex3(ept.X, ept.Y, ept.Z); |
| | | GL.End(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ç»å¶ |
| | | /// </summary> |
| | | /// <param name="width">线宽</param> |
| | | /// <param name="color">线è²</param> |
| | | /// <param name="spt">å¼å§ç¹</param> |
| | | /// <param name="ept">ç»æç¹</param> |
| | | public static void DrawLine(float width, Color color, Vector3 spt, Vector3 ept) |
| | | { |
| | | GL.LineWidth(width); |
| | | GL.Begin(PrimitiveType.Lines); |
| | | GL.Color3(color); |
| | | GL.Vertex3(spt.X, spt.Y, spt.Z); |
| | | GL.Vertex3(ept.X, ept.Y, ept.Z); |
| | | GL.End(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | internal static class Network2dExtensions |
| | | { |
| | | /// <summary> |
| | | /// ç»å¶2d |
| | | /// </summary> |
| | | public static void Draw2d(this NetworkL3d nw) |
| | | { |
| | | if (nw == null) |
| | | { |
| | | return; |
| | | } |
| | | nw.Links.ForEach(x => |
| | | { |
| | | if (!x.IsSelected && !x.IsHovered) |
| | | { |
| | | Draw2dHelper.DrawLine(x.Style2d.Normal.Width, x.Style2d.Normal.Color, x.StartPosition, x.EndPosition); |
| | | } |
| | | else |
| | | { |
| | | if (x.IsHovered) |
| | | { |
| | | Draw2dHelper.DrawLine(x.Style2d.Hovered.Width, x.Style2d.Hovered.Color, x.StartPosition, x.EndPosition); |
| | | } |
| | | else |
| | | { |
| | | Draw2dHelper.DrawLine(x.Style2d.Selected.Width, x.Style2d.Selected.Color, x.StartPosition, x.EndPosition); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | nw.Nodes.ForEach(x => |
| | | { |
| | | if (!x.IsSelected && !x.IsHovered) |
| | | { |
| | | Draw2dHelper.DrawPoint(x.Style2d.Normal.Radiu * 2, x.Style2d.Normal.Color, x.Position); |
| | | } |
| | | else |
| | | { |
| | | if (x.IsHovered) |
| | | { |
| | | Draw2dHelper.DrawPoint(x.Style2d.Hovered.Radiu * 2, x.Style2d.Hovered.Color, x.Position); |
| | | } |
| | | else |
| | | { |
| | | Draw2dHelper.DrawPoint(x.Style2d.Selected.Radiu * 2, x.Style2d.Selected.Color, x.Position); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¬å2d |
| | | /// </summary> |
| | | public static void Hover2d(this NetworkL3d nw, Ray3 ray, BoundingBox32dCacheHelper bxcache) |
| | | { |
| | | nw.Visuals.ForEach(x => x.IsHovered = false); |
| | | var visual = ray.CastingClosest(nw, bxcache); |
| | | if (visual != null) |
| | | { |
| | | visual.IsHovered = true; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 鿩2d |
| | | /// </summary> |
| | | public static void Select2d(this NetworkL3d nw, Ray3 ray, BoundingBox32dCacheHelper bxcache) |
| | | { |
| | | nw.Visuals.ForEach(x => x.IsSelected = false); |
| | | var visual = ray.CastingClosest(nw, bxcache); |
| | | if (visual != null) |
| | | { |
| | | visual.IsSelected = true; |
| | | return; |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using OpenTK.GLControl; |
| | | using OpenTK.Graphics.OpenGL; |
| | | using OpenTK.Mathematics; |
| | | using System.Transactions; |
| | | using System.Windows.Forms; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// æ£äº¤ç¸æºè¾
å©ç±» |
| | | /// </summary> |
| | | internal class OrthoCamera2dHelper |
| | | { |
| | | |
| | | /// <summary> |
| | | /// è¾
å©ç±» |
| | | /// </summary> |
| | | public OrthoCamera2dHelper() { } |
| | | |
| | | /// <summary> |
| | | /// åå§å |
| | | /// </summary> |
| | | public void Initial(GLControl gl, NetworkL3d nw) |
| | | { |
| | | _gl = gl; |
| | | _nw = nw; |
| | | _veccache = new Vector32dCacheHelper(nw); |
| | | var pts = _veccache.GetPositions(); |
| | | _bx = new BoundingBox3(pts); |
| | | _bxcache = new BoundingBox32dCacheHelper(nw, _veccache); |
| | | _mc = (_bx.Max + _bx.Min) * 0.5f; |
| | | _radius = (_bx.Max - _bx.Min).Length / 2f; |
| | | UpdateModelMatrix(); |
| | | UpdateViewMatrix(); |
| | | UpdateProjectionMatrix(); |
| | | } |
| | | |
| | | // åºç¡åæ° |
| | | private GLControl _gl = null;//glæ§ä»¶ |
| | | private NetworkL3d _nw = null;//ç®¡ç½æ¨¡å |
| | | private Vector32dCacheHelper _veccache = null;//ä½ç½®è¾
å©ç±» |
| | | private BoundingBox3 _bx = null;//å
å´ç |
| | | private BoundingBox32dCacheHelper _bxcache = null;//å
å´çç¼å |
| | | private Vector3 _mc; //模åä¸å¿ |
| | | private float _radius = 100f;//å
å´çåå¾ |
| | | private float _pw = 10f;//æå½±å®½åº¦ |
| | | private float _ph = 10f;//æå½±é«åº¦ |
| | | private Quaternion _rotation = Quaternion.Identity;//æè½¬åå
æ° |
| | | private Vector3 _translation = Vector3.Zero;//平移é |
| | | private Matrix4 _modelMatrix;//模åç©éµ |
| | | private Matrix4 _viewMatrix;//è§å¾ç©éµ |
| | | private Matrix4 _projMatrix;//æå½±ç©éµ |
| | | private Vector3 _forward; |
| | | |
| | | /// <summary> |
| | | /// ç¼©æ¾ |
| | | /// </summary> |
| | | public float Zoom |
| | | { |
| | | get => _zoom; |
| | | set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // éå¶ç¼©æ¾èå´ |
| | | } |
| | | private float _zoom = 1.0f; // å½å缩æ¾ç³»æ°ï¼1表示åå§å¤§å°ï¼ |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦åå§å |
| | | /// </summary> |
| | | public bool Initialized |
| | | { |
| | | get |
| | | { |
| | | if (_nw == null) |
| | | { |
| | | return false; |
| | | } |
| | | if (_gl == null) |
| | | { |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | |
| | | //æ´æ°æ¨¡åç©éµ |
| | | private void UpdateModelMatrix() |
| | | { |
| | | _modelMatrix = Matrix4.CreateTranslation(_translation * this.Zoom); |
| | | } |
| | | |
| | | //æ´æ°è§å¾ç©éµ |
| | | private void UpdateViewMatrix() |
| | | { |
| | | var eye = new Vector3(_mc.X, _mc.Y, _mc.Z + _radius * 2); |
| | | var target = _mc; |
| | | var up = Vector3.UnitY; |
| | | var matrix = Matrix4.CreateFromQuaternion(_rotation); |
| | | matrix.Invert(); |
| | | eye = Vector3.TransformPosition(eye, matrix); |
| | | up = Vector3.TransformPosition(up, matrix); |
| | | _viewMatrix = Matrix4.LookAt(eye, target, up); |
| | | _forward = target - eye; |
| | | _forward.Normalize(); |
| | | } |
| | | |
| | | //æ´æ°æå½±ç©éµ |
| | | private void UpdateProjectionMatrix() |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | var aspect = _gl.AspectRatio; |
| | | var size = _radius * 2; |
| | | _pw = size; |
| | | _ph = size; |
| | | |
| | | if (aspect > 1) |
| | | { |
| | | _pw *= aspect; |
| | | } |
| | | else |
| | | { |
| | | _ph /= aspect; |
| | | } |
| | | _projMatrix = Matrix4.CreateOrthographic(_pw * this.Zoom, _ph * this.Zoom, _radius, _radius * 3); |
| | | } |
| | | |
| | | #region é¼ æ äº¤äº |
| | | |
| | | private bool _isDragging = false;//æ¯å¦å¢å¨æå¨ |
| | | private bool _isRotating = false;//æ¯å¦æ£å¨æè½¬ |
| | | private Point _lastMousePos;//æè¿ä¸æ¬¡é¼ æ ä½ç½® |
| | | |
| | | /// <summary> |
| | | /// å¤ç大尿¹å |
| | | /// </summary> |
| | | public void HandleResize() |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | _gl.MakeCurrent(); |
| | | GL.Viewport(0, 0, _gl.Width, _gl.Height); |
| | | UpdateProjectionMatrix(); |
| | | _gl.Invalidate(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çç»å¶ |
| | | /// </summary> |
| | | public void HandleRender() |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | _gl.MakeCurrent(); |
| | | GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit); |
| | | //æå½±ç©éµ |
| | | GL.MatrixMode(MatrixMode.Projection); |
| | | GL.LoadMatrix(ref _projMatrix); |
| | | |
| | | //è§å¾ç©éµ |
| | | GL.MatrixMode(MatrixMode.Modelview); |
| | | var viewMatrix = _viewMatrix * _modelMatrix; |
| | | GL.LoadMatrix(ref viewMatrix); |
| | | |
| | | _nw.Draw2d(); |
| | | |
| | | //var code = GL.GetError(); |
| | | |
| | | _gl.SwapBuffers(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çé¼ æ æ»è½® |
| | | /// </summary> |
| | | public void HandleMouseWheel(MouseEventArgs e) |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | this.Zoom *= e.Delta > 0 ? 0.9f : 1.1f; |
| | | UpdateModelMatrix(); |
| | | UpdateViewMatrix(); |
| | | UpdateProjectionMatrix(); |
| | | _gl.Invalidate(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çé¼ æ æä¸ |
| | | /// </summary> |
| | | public void HandleMouseDown(MouseEventArgs e) |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | _lastMousePos = e.Location; |
| | | if (e.Button == MouseButtons.Right) |
| | | { |
| | | _isDragging = true; |
| | | _gl.Cursor = Cursors.SizeAll; // ä¿®æ¹å
æ æ ·å¼ |
| | | } |
| | | else if (e.Button == MouseButtons.Left) |
| | | { |
| | | _isRotating = true; |
| | | _gl.Cursor = Cursors.SizeAll; // ä¿®æ¹å
æ æ ·å¼ |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çé¼ æ 弹起 |
| | | /// </summary> |
| | | public void HandleMouseUp(MouseEventArgs e) |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | _lastMousePos = e.Location; |
| | | if (e.Button == MouseButtons.Right) |
| | | { |
| | | _isDragging = false; |
| | | _gl.Cursor = Cursors.Default; |
| | | } |
| | | else if (e.Button == MouseButtons.Left) |
| | | { |
| | | _isRotating = false; |
| | | _gl.Cursor = Cursors.Default; |
| | | } |
| | | |
| | | _gl.Invalidate(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çé¼ æ ç§»å¨ |
| | | /// </summary> |
| | | public void HandleMouseMove(MouseEventArgs e) |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | float dx = e.X - _lastMousePos.X; |
| | | float dy = e.Y - _lastMousePos.Y; |
| | | |
| | | if (_isRotating) |
| | | { |
| | | // æ ¹æ®é¼ æ ç§»å¨éè®¡ç®æè½¬è§åº¦ |
| | | Quaternion rotationX = Quaternion.FromAxisAngle(Vector3.UnitX, dy / _radius); |
| | | Quaternion rotationY = Quaternion.FromAxisAngle(Vector3.UnitY, dx / _radius); |
| | | |
| | | // æ´æ°åå
æ° |
| | | _rotation = rotationY * rotationX * _rotation; |
| | | _rotation = Quaternion.Normalize(_rotation); |
| | | UpdateViewMatrix(); |
| | | } |
| | | else if (_isDragging) |
| | | { |
| | | float xratio = _pw / _gl.Width; |
| | | float yratio = _ph / _gl.Height; |
| | | _translation.X += dx * xratio; |
| | | _translation.Y -= dy * yratio; |
| | | UpdateModelMatrix(); |
| | | } |
| | | else |
| | | { |
| | | var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height); |
| | | var ray = OrthoTransformHelper.CreateRay(e.X, e.Y, depth, _forward, _modelMatrix, _viewMatrix, _projMatrix, _gl.Width, _gl.Height); |
| | | if (ray != null) |
| | | { |
| | | _nw.Hover2d(ray, _bxcache); |
| | | } |
| | | } |
| | | |
| | | _lastMousePos = e.Location; |
| | | _gl.Invalidate(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çé¼ æ ç¹å» |
| | | /// </summary> |
| | | public void HandleMouseClick(MouseEventArgs e) |
| | | { |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çé¼ æ åå» |
| | | /// </summary> |
| | | public void HandleMouseDoubleClick(MouseEventArgs e) |
| | | { |
| | | var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height); |
| | | var world = OrthoTransformHelper.ScreenToWorld(e.X, e.Y, depth, _viewMatrix * _modelMatrix, _projMatrix, _gl.Width, _gl.Height); |
| | | MessageBox.Show($"x:{world.X},y:{world.Y},z:{world.Z}"); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using OpenTK.Graphics.OpenGL; |
| | | using OpenTK.Mathematics; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// æ£äº¤è½¬æ¢è¾
å©ç±» |
| | | /// </summary> |
| | | internal class OrthoTransformHelper |
| | | { |
| | | |
| | | |
| | | /// <summary> |
| | | /// å±å¹åæ To NDCåæ |
| | | /// </summary> |
| | | /// <param name="screenX">å±å¹Xåæ ï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="screenY">å±å¹Yåæ ï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="depth">深度å¼ï¼èå´[0, 1]ï¼å¯éï¼</param> |
| | | /// <param name="viewportWidth">è§å£å®½åº¦</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | /// <returns></returns> |
| | | public static Vector3 ScreenToNDC(float screenX, float screenY, float depth, int viewportWidth, int viewportHeight) |
| | | { |
| | | // å½ä¸åå° [0, 1] |
| | | float normalizedX = screenX / viewportWidth; |
| | | float normalizedY = screenY / viewportHeight; |
| | | |
| | | // æ å°å° [-1, 1] |
| | | float ndcX = 2.0f * normalizedX - 1.0f; |
| | | float ndcY = 1.0f - 2.0f * normalizedY; // 翻转Y轴 |
| | | float ndcZ = 2.0f * depth - 1.0f; // 深度å¼è½¬æ¢ |
| | | |
| | | return new Vector3(ndcX, ndcY, ndcZ); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// NDCåæ To å±å¹åæ |
| | | /// </summary> |
| | | /// <param name="ndc">NDCåæ ï¼X,Y â [-1, 1], Z â [-1, 1]ï¼</param> |
| | | /// <param name="viewportWidth">è§å£å®½åº¦</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | /// <returns></returns> |
| | | public static Vector2 NDCToScreen(Vector3 ndc, int viewportWidth, int viewportHeight) |
| | | { |
| | | // Xè½´ï¼[-1, 1] â [0, viewportWidth] |
| | | float screenX = (ndc.X + 1.0f) * 0.5f * viewportWidth; |
| | | |
| | | // Yè½´ï¼[-1, 1] â [0, viewportHeight]ï¼ç¿»è½¬Yè½´ï¼ |
| | | float screenY = (1.0f - (ndc.Y + 1.0f) * 0.5f) * viewportHeight; |
| | | |
| | | // Zè½´ï¼å¯éï¼ï¼[-1, 1] â [0, 1] |
| | | float screenZ = (ndc.Z + 1.0f) * 0.5f; |
| | | |
| | | return new Vector2(screenX, screenY); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 读åé¼ æ ä½ç½®å¯¹åºçæ·±åº¦å¼ |
| | | /// </summary> |
| | | /// <param name="mouseX">å±å¹åæ Xï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="mouseY">å±å¹åæ Yï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | /// <returns>深度å¼ï¼èå´[0, 1]ï¼</returns> |
| | | public static float GetScreenPointDepth(int mouseX, int mouseY, int viewportHeight) |
| | | { |
| | | // è°æ´Yåæ ï¼å±å¹åæ ç³»ï¼å·¦ä¸åç¹ï¼ â OpenGLè§å£åæ ç³»ï¼å·¦ä¸åç¹ï¼ |
| | | int glY = viewportHeight - mouseY; |
| | | |
| | | // è¯»åæ·±åº¦å¼ |
| | | float[] depth = new float[1]; |
| | | GL.ReadPixels( |
| | | mouseX, // é¼ æ Xåæ |
| | | glY, // è°æ´åçYåæ |
| | | 1, 1, // 读å1x1åç´ |
| | | PixelFormat.DepthComponent, // åç´ æ ¼å¼ä¸ºæ·±åº¦åé |
| | | PixelType.Float, // æ°æ®ç±»åä¸ºæµ®ç¹æ° |
| | | depth // åå¨ç»æçæ°ç» |
| | | ); |
| | | |
| | | return depth[0]; |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// å±å¹åæ To ä¸çåæ |
| | | /// </summary> |
| | | /// <param name="mouseX">å±å¹åæ Xï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="mouseY">å±å¹åæ Yï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="depth">深度å¼ï¼èå´[0, 1]ï¼å¯éï¼</param> |
| | | /// <param name="mview">è§å¾ç©éµ</param> |
| | | /// <param name="proj">æå½±ç©éµ</param> |
| | | /// <param name="viewportWidth">è§å£å®½åº¦</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | /// <returns></returns> |
| | | public static Vector3 ScreenToWorld(float mouseX, float mouseY, float depth, Matrix4 mview, Matrix4 proj, int viewportWidth, int viewportHeight) |
| | | { |
| | | var ndc = ScreenToNDC(mouseX, mouseY, depth, viewportWidth, viewportHeight); |
| | | var matrix = mview * proj; |
| | | var invert = matrix.Inverted(); |
| | | // å°NDCåæ è½¬æ¢ä¸ºä¸çåæ |
| | | var wp = Vector4.TransformRow(new Vector4(ndc, 1f), invert); |
| | | wp /= wp.W; // éè§é¤æ³ |
| | | return new Vector3(wp.X, wp.Y, wp.Z); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä¸çåæ To å±å¹åæ |
| | | /// </summary> |
| | | /// <param name="wp">ä¸çåæ </param> |
| | | /// <param name="mview">è§å¾ç©éµ</param> |
| | | /// <param name="proj">æå½±ç©éµ</param> |
| | | /// <param name="wiewportWidth">è§å£å®½åº¦</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | /// <returns></returns> |
| | | public static Vector2 WorldToScreen(Vector3 wp, Matrix4 mview, Matrix4 proj, int wiewportWidth, int viewportHeight) |
| | | { |
| | | // 转æ¢ä¸ºé½æ¬¡åæ |
| | | var wph = new Vector4(wp, 1.0f); |
| | | //åºç¨ç©éµ |
| | | var mvp = mview * proj; |
| | | //è£åªåæ |
| | | var clip = Vector4.TransformRow(wph, mvp); |
| | | //NDC |
| | | clip /= clip.W; |
| | | return NDCToScreen(clip.Xyz, wiewportWidth, viewportHeight); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å建å°çº¿ |
| | | /// </summary> |
| | | /// <param name="mouseX">å±å¹åæ Xï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="mouseY">å±å¹åæ Yï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="depth">深度å¼ï¼èå´[0, 1]ï¼å¯éï¼</param> |
| | | /// <param name="forward">è§å¯æ¹å</param> |
| | | /// <param name="model">模åç©éµ</param> |
| | | /// <param name="view">è§å¾ç©éµ</param> |
| | | /// <param name="proj">æå½±ç©éµ</param> |
| | | /// <param name="viewportWidth">è§å£å®½åº¦</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | public static Ray3 CreateRay |
| | | ( |
| | | float mouseX, |
| | | float mouseY, |
| | | float depth, |
| | | Vector3 forward, |
| | | Matrix4 model, |
| | | Matrix4 view, |
| | | Matrix4 proj, |
| | | int viewportWidth, |
| | | int viewportHeight |
| | | ) |
| | | { |
| | | var mview = view * model; |
| | | var origins = ScreenToWorld(mouseX, mouseY, depth, mview, proj, viewportWidth, viewportHeight); |
| | | return new Ray3(origins, forward); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å建å°çº¿ |
| | | /// </summary> |
| | | /// <param name="mouseX">å±å¹åæ Xï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="mouseY">å±å¹åæ Yï¼å·¦ä¸è§ä¸ºåç¹ï¼</param> |
| | | /// <param name="model">模åç©éµ</param> |
| | | /// <param name="view">è§å¾ç©éµ</param> |
| | | /// <param name="proj">æå½±ç©éµ</param> |
| | | /// <param name="viewportWidth">è§å£å®½åº¦</param> |
| | | /// <param name="viewportHeight">è§å£é«åº¦</param> |
| | | public static Ray3 CreateRay2 |
| | | ( |
| | | float mouseX, |
| | | float mouseY, |
| | | Matrix4 model, |
| | | Matrix4 view, |
| | | Matrix4 proj, |
| | | int viewportWidth, |
| | | int viewportHeight |
| | | ) |
| | | { |
| | | var mview = view * model; |
| | | var near = ScreenToWorld(mouseX, mouseY, 0f, mview, proj, viewportWidth, viewportHeight); |
| | | var far = ScreenToWorld(mouseX, mouseY, 1f, mview, proj, viewportWidth, viewportHeight); |
| | | var direction = (far - near).Normalized(); |
| | | return new Ray3(near, direction); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using OpenTK.Mathematics; |
| | | using System.Windows.Forms; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// å°çº¿ç»æä½ |
| | | /// </summary> |
| | | internal class Ray3 |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public Ray3() { } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public Ray3(Vector3 origin, Vector3 direction) |
| | | { |
| | | Origin = origin; |
| | | Direction = direction.Normalized(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åç¹ |
| | | /// </summary> |
| | | public Vector3 Origin { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¹å |
| | | /// </summary> |
| | | public Vector3 Direction { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æå° |
| | | /// </summary> |
| | | /// <param name="bx">å
å´ç</param> |
| | | /// <param name="distance">交ç¹ä¸åç¹çè·ç¦»</param> |
| | | /// <returns>æ¯å¦ç¸äº¤</returns> |
| | | public bool Casting(BoundingBox3 bx, out float distance) |
| | | { |
| | | distance = float.MaxValue; |
| | | float tmin = float.MinValue; |
| | | float tmax = float.MaxValue; |
| | | |
| | | // æ£æ¥ X æ¹åçé¢ |
| | | if (Math.Abs(this.Direction.X) < float.Epsilon) |
| | | { |
| | | if (this.Origin.X < bx.Min.X || this.Origin.X > bx.Max.X) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | float tx1 = (bx.Min.X - this.Origin.X) / this.Direction.X; |
| | | float tx2 = (bx.Max.X - this.Origin.X) / this.Direction.X; |
| | | |
| | | tmin = Math.Max(tmin, Math.Min(tx1, tx2)); |
| | | tmax = Math.Min(tmax, Math.Max(tx1, tx2)); |
| | | |
| | | if (tmax < tmin) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // æ£æ¥ Y æ¹åçé¢ |
| | | if (Math.Abs(this.Direction.Y) < float.Epsilon) |
| | | { |
| | | if (this.Origin.Y < bx.Min.Y || this.Origin.Y > bx.Max.Y) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | float ty1 = (bx.Min.Y - this.Origin.Y) / this.Direction.Y; |
| | | float ty2 = (bx.Max.Y - this.Origin.Y) / this.Direction.Y; |
| | | |
| | | tmin = Math.Max(tmin, Math.Min(ty1, ty2)); |
| | | tmax = Math.Min(tmax, Math.Max(ty1, ty2)); |
| | | |
| | | if (tmax < tmin) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // æ£æ¥ Z æ¹åçé¢ |
| | | if (Math.Abs(this.Direction.Z) < float.Epsilon) |
| | | { |
| | | if (this.Origin.Z < bx.Min.Z || this.Origin.Z > bx.Max.Z) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | float tz1 = (bx.Min.Z - this.Origin.Z) / this.Direction.Z; |
| | | float tz2 = (bx.Max.Z - this.Origin.Z) / this.Direction.Z; |
| | | |
| | | tmin = Math.Max(tmin, Math.Min(tz1, tz2)); |
| | | tmax = Math.Min(tmax, Math.Max(tz1, tz2)); |
| | | |
| | | if (tmax < tmin) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | if (tmin >= 0) |
| | | { |
| | | distance = tmin; |
| | | } |
| | | else if (tmax >= 0) |
| | | { |
| | | distance = tmax; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Collections.Generic; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// å°çº¿ç¢°æ |
| | | /// </summary> |
| | | internal static class Ray3Caster |
| | | { |
| | | |
| | | /// <summary> |
| | | /// æå° |
| | | /// </summary> |
| | | /// <param name="ray">å°çº¿</param> |
| | | /// <param name="visuals">å¯è§æä»¶å表</param> |
| | | /// <param name="bxcache">å
å´çç¼å</param> |
| | | public static List<VisualL3d> Casting(this Ray3 ray, List<VisualL3d> visuals, BoundingBox32dCacheHelper bxcache) |
| | | { |
| | | if (ray == null) |
| | | { |
| | | return default; |
| | | } |
| | | if (visuals == null || visuals.Count < 1) |
| | | { |
| | | return default; |
| | | } |
| | | if (bxcache == null) |
| | | { |
| | | return default; |
| | | } |
| | | var list = new List<VisualL3d>(); |
| | | foreach (var visual in visuals) |
| | | { |
| | | var bx = bxcache.GetBoundingBox(visual.Id); |
| | | if (ray.Casting(bx, out float distance)) |
| | | { |
| | | list.Add(visual); |
| | | } |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå°æè¿æä»¶ |
| | | /// </summary> |
| | | /// <param name="ray">å°çº¿</param> |
| | | /// <param name="visuals">å¯è§æä»¶å表</param> |
| | | /// <param name="bxcache">å
å´çç¼å</param> |
| | | public static VisualL3d CastingClosest(this Ray3 ray, List<VisualL3d> visuals, BoundingBox32dCacheHelper bxcache) |
| | | { |
| | | if (ray == null) |
| | | { |
| | | return default; |
| | | } |
| | | if (visuals == null || visuals.Count < 1) |
| | | { |
| | | return default; |
| | | } |
| | | if (bxcache == null) |
| | | { |
| | | return default; |
| | | } |
| | | VisualL3d closest = null; |
| | | float minDistance = float.MaxValue; |
| | | foreach (var visual in visuals) |
| | | { |
| | | var bx = bxcache.GetBoundingBox(visual.Id); |
| | | if (ray.Casting(bx, out float distance)) |
| | | { |
| | | if (distance <= minDistance) |
| | | { |
| | | minDistance = distance; |
| | | closest = visual; |
| | | } |
| | | } |
| | | } |
| | | return closest; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå°æè¿æä»¶ |
| | | /// </summary> |
| | | /// <param name="ray">å°çº¿</param> |
| | | /// <param name="nw">管ç½</param> |
| | | /// <param name="bxcache">å
å´çç¼å</param> |
| | | /// <returns></returns> |
| | | public static VisualL3d CastingClosest(this Ray3 ray, NetworkL3d nw, BoundingBox32dCacheHelper bxcache) |
| | | { |
| | | var visuals = nw?.Visuals; |
| | | return CastingClosest(ray, visuals, bxcache); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | using OpenTK.Mathematics; |
| | | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// ä¸ç»´ç¹ç¼åè¾
å©ç±» |
| | | /// </summary> |
| | | internal class Vector32dCacheHelper |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public Vector32dCacheHelper(NetworkL3d nw) |
| | | { |
| | | _nw = nw; |
| | | Initial(); |
| | | } |
| | | |
| | | private NetworkL3d _nw = null; |
| | | private Dictionary<string, List<Vector3>> _dict = new(); |
| | | |
| | | //åå§å |
| | | private void Initial() |
| | | { |
| | | if (_nw == null) |
| | | { |
| | | return; |
| | | } |
| | | foreach (var visual in _nw.Visuals) |
| | | { |
| | | var pts = visual.GetPositions(); |
| | | var vpts = pts.Select(x => new Vector3(x.X, x.Y, x.Z)).ToList(); |
| | | _dict.Add(visual.Id, vpts); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åä½ç½® |
| | | /// </summary> |
| | | public List<Vector3> GetPositions() |
| | | { |
| | | if (_dict.Count < 1) |
| | | { |
| | | return default; |
| | | } |
| | | return _dict.SelectMany(x => x.Value).ToList(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åä½ç½® |
| | | /// </summary> |
| | | public List<Vector3> GetPositions(string id) |
| | | { |
| | | if (_dict.ContainsKey(id)) |
| | | { |
| | | return _dict[id]; |
| | | } |
| | | return default; |
| | | } |
| | | |
| | | |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace Yw.WinFrmUI.Hydro |
| | | { |
| | | /// <summary> |
| | | /// è§å¾çªå£ |
| | | /// </summary> |
| | | internal class ViewPort3 |
| | | { |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public ViewPort3() { } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public ViewPort3(int x, int y, int width, int height) |
| | | { |
| | | this.X = x; |
| | | this.Y = y; |
| | | this.Width = width; |
| | | this.Height = height; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// x |
| | | /// </summary> |
| | | public float X { get; set; } |
| | | |
| | | /// <summary> |
| | | /// y |
| | | /// </summary> |
| | | public float Y { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 宽度 |
| | | /// </summary> |
| | | public float Width { get; set; } |
| | | |
| | | /// <summary> |
| | | /// é«åº¦ |
| | | /// </summary> |
| | | public float Height { get; set; } |
| | | |
| | | |
| | | } |
| | | } |
| | |
| | | { |
| | | InitializeComponent(); |
| | | this.glControl1.Load += glControl_Load; |
| | | this.glControl1.Paint += glControl_Paint; |
| | | this.glControl1.Resize += glControl_Resize; |
| | | this.glControl1.Paint += glControl_Paint; |
| | | this.glControl1.MouseWheel += OnMouseWheel; |
| | | this.glControl1.MouseDown += OnMouseDown; |
| | | this.glControl1.MouseUp += OnMouseUp; |
| | | this.glControl1.MouseMove += OnMouseMove; |
| | | this.glControl1.MouseClick += OnMouseClick; |
| | | this.glControl1.MouseDoubleClick += GlControl1_MouseDoubleClick; |
| | | } |
| | | |
| | | private NetworkL3d _nw = null; |
| | | private OrthoCameraHelper _orthoHelper = null; |
| | | private OrthoCamera2dHelper _orthoHelper = null; |
| | | |
| | | /// <summary> |
| | | /// åå§åç®¡ç½ |
| | |
| | | public void InitialNetwork(NetworkL3d nw) |
| | | { |
| | | _nw = nw; |
| | | var pts = _nw.Nodes.Select(x => new Vector3(x.Position.X, x.Position.Y, x.Position.Z)).ToList(); |
| | | _orthoHelper = new OrthoCameraHelper(); |
| | | _orthoHelper.Initial(pts); |
| | | _orthoHelper = new OrthoCamera2dHelper(); |
| | | _orthoHelper.Initial(this.glControl1, _nw); |
| | | } |
| | | |
| | | //å è½½äºä»¶ |
| | | private void glControl_Load(object sender, EventArgs e) |
| | | { |
| | | GL.ClearColor(Color.Black); // èæ¯é¢è² |
| | | if (_nw == null) |
| | | { |
| | | return; |
| | | } |
| | | if (_orthoHelper == null) |
| | | { |
| | | return; |
| | | } |
| | | GL.ClearColor(Color.Transparent); // èæ¯é¢è² |
| | | GL.ShadeModel(ShadingModel.Smooth); |
| | | GL.Enable(EnableCap.DepthTest);//深度æµè¯ |
| | | GL.DepthMask(true); // å
许åå
¥æ·±åº¦ç¼å²åº |
| | | GL.DepthMask(true); |
| | | GL.Enable(EnableCap.PointSmooth);//å¯ç¨ç¹å¹³æ» |
| | | GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest); |
| | | GL.Enable(EnableCap.LineSmooth);//å¯ç¨çº¿å¹³æ» |
| | | GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest); |
| | | |
| | | GL.PointSize(5); |
| | | GL.LineWidth(3); |
| | | |
| | | ResizeGL(); |
| | | _orthoHelper.HandleResize(); |
| | | } |
| | | |
| | | // 尺寸æ¹å |
| | | private void glControl_Resize(object sender, EventArgs e) |
| | | { |
| | | ResizeGL(); |
| | | if (_nw == null) |
| | | { |
| | | return; |
| | | } |
| | | if (_orthoHelper == null) |
| | | { |
| | | return; |
| | | } |
| | | _orthoHelper.HandleResize(); |
| | | } |
| | | |
| | | // ç»å¶ |
| | | private void glControl_Paint(object sender, PaintEventArgs e) |
| | | { |
| | | RenderGL(); |
| | | _orthoHelper.HandleRender(); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | // 渲æ |
| | | private void RenderGL() |
| | | { |
| | | if (_nw == null) |
| | | { |
| | | return; |
| | | } |
| | | this.glControl1.MakeCurrent(); |
| | | GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit); |
| | | |
| | | //æå½±ç©éµ |
| | | GL.MatrixMode(MatrixMode.Projection); |
| | | var projectionMatrix = _orthoHelper.ProjectionMatrix; |
| | | GL.LoadMatrix(ref projectionMatrix); |
| | | |
| | | //è§å¾ç©éµ |
| | | GL.MatrixMode(MatrixMode.Modelview); |
| | | var viewMatrix = _orthoHelper.ViewMatrix * _orthoHelper.ModelMatrix; |
| | | GL.LoadMatrix(ref viewMatrix); |
| | | |
| | | |
| | | _nw.Draw2d(); |
| | | var code = GL.GetError(); |
| | | |
| | | this.glControl1.SwapBuffers(); |
| | | } |
| | | |
| | | // è°æ´å¤§å° |
| | | private void ResizeGL() |
| | | { |
| | | this.glControl1.MakeCurrent(); |
| | | _orthoHelper.UpdateViewport(this.glControl1.Width, this.glControl1.Height); |
| | | this.glControl1.Invalidate(); |
| | | } |
| | | |
| | | |
| | | |
| | | #region é¼ æ äº¤äº |
| | | |
| | | |
| | | //é¼ æ æ»è½® |
| | | private void OnMouseWheel(object sender, MouseEventArgs e) |
| | | { |
| | | _orthoHelper?.HandleMouseWheel(this.glControl1, e); |
| | | _orthoHelper?.HandleMouseWheel(e); |
| | | } |
| | | |
| | | // é¼ æ æä¸ |
| | | private void OnMouseDown(object sender, MouseEventArgs e) |
| | | { |
| | | _orthoHelper?.HandleMouseDown(this.glControl1, e); |
| | | _orthoHelper?.HandleMouseDown(e); |
| | | } |
| | | |
| | | //é¼ æ 弹起 |
| | | private void OnMouseUp(object sender, MouseEventArgs e) |
| | | { |
| | | _orthoHelper?.HandleMouseUp(this.glControl1, e); |
| | | _orthoHelper?.HandleMouseUp(e); |
| | | } |
| | | |
| | | //é¼ æ ç§»å¨ |
| | | private void OnMouseMove(object sender, MouseEventArgs e) |
| | | { |
| | | _orthoHelper?.HandleMouseMove(this.glControl1, e); |
| | | _orthoHelper?.HandleMouseMove(e); |
| | | } |
| | | |
| | | #endregion |
| | | //é¼ æ ç¹å» |
| | | private void OnMouseClick(object sender, MouseEventArgs e) |
| | | { |
| | | _orthoHelper?.HandleMouseClick(e); |
| | | } |
| | | |
| | | //é¼ æ åå» |
| | | private void GlControl1_MouseDoubleClick(object sender, MouseEventArgs e) |
| | | { |
| | | _orthoHelper.HandleMouseDoubleClick(e); |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | /// </summary> |
| | | private void InitializeComponent() |
| | | { |
| | | splitContainer1 = new SplitContainer(); |
| | | propertyGrid2 = new PropertyGrid(); |
| | | propertyGrid1 = new PropertyGrid(); |
| | | propertyGrid3 = new PropertyGrid(); |
| | | ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); |
| | | splitContainer1.Panel1.SuspendLayout(); |
| | | splitContainer1.SuspendLayout(); |
| | | SuspendLayout(); |
| | | // |
| | | // splitContainer1 |
| | | // |
| | | splitContainer1.Dock = DockStyle.Fill; |
| | | splitContainer1.Location = new Point(0, 0); |
| | | splitContainer1.Name = "splitContainer1"; |
| | | // |
| | | // splitContainer1.Panel1 |
| | | // |
| | | splitContainer1.Panel1.Controls.Add(propertyGrid3); |
| | | splitContainer1.Panel1.Controls.Add(propertyGrid2); |
| | | splitContainer1.Panel1.Controls.Add(propertyGrid1); |
| | | splitContainer1.Size = new Size(1084, 674); |
| | | splitContainer1.SplitterDistance = 311; |
| | | splitContainer1.TabIndex = 0; |
| | | // |
| | | // propertyGrid2 |
| | | // |
| | | propertyGrid2.Dock = DockStyle.Top; |
| | | propertyGrid2.Location = new Point(0, 223); |
| | | propertyGrid2.Name = "propertyGrid2"; |
| | | propertyGrid2.Size = new Size(311, 262); |
| | | propertyGrid2.TabIndex = 1; |
| | | // |
| | | // propertyGrid1 |
| | | // |
| | | propertyGrid1.Dock = DockStyle.Top; |
| | | propertyGrid1.Location = new Point(0, 0); |
| | | propertyGrid1.Name = "propertyGrid1"; |
| | | propertyGrid1.Size = new Size(311, 223); |
| | | propertyGrid1.TabIndex = 0; |
| | | // |
| | | // propertyGrid3 |
| | | // |
| | | propertyGrid3.Dock = DockStyle.Top; |
| | | propertyGrid3.Location = new Point(0, 485); |
| | | propertyGrid3.Name = "propertyGrid3"; |
| | | propertyGrid3.Size = new Size(311, 186); |
| | | propertyGrid3.TabIndex = 2; |
| | | // |
| | | // MainForm |
| | | // |
| | | AutoScaleDimensions = new SizeF(7F, 17F); |
| | | AutoScaleMode = AutoScaleMode.Font; |
| | | ClientSize = new Size(800, 450); |
| | | ClientSize = new Size(1084, 674); |
| | | Controls.Add(splitContainer1); |
| | | Name = "MainForm"; |
| | | Text = "MainForm"; |
| | | splitContainer1.Panel1.ResumeLayout(false); |
| | | ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); |
| | | splitContainer1.ResumeLayout(false); |
| | | ResumeLayout(false); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | private SplitContainer splitContainer1; |
| | | private PropertyGrid propertyGrid2; |
| | | private PropertyGrid propertyGrid1; |
| | | private PropertyGrid propertyGrid3; |
| | | } |
| | | } |
| | |
| | | private void MainForm_Load(object sender, EventArgs e) |
| | | { |
| | | var nw = LoadEpaNetwork(); |
| | | var tank = nw.Tanks[0]; |
| | | this.propertyGrid1.SelectedObject = new PointL3d(tank.Position.X, tank.Position.Y, tank.GetElev()); |
| | | var cooling = nw.Junctions.Find(x => x.Id == "452584"); |
| | | this.propertyGrid2.SelectedObject = new PointL3d(cooling.Position.X, cooling.Position.Y, cooling.GetElev()); |
| | | |
| | | var nw3d = Get3dNetwork(nw); |
| | | var openGLControl = new OrthoDrawer2d(); |
| | | openGLControl.Dock = DockStyle.Fill; |
| | | openGLControl.InitialNetwork(nw3d); |
| | | this.Controls.Add(openGLControl); |
| | | this.splitContainer1.Panel2.Controls.Add(openGLControl); |
| | | } |
| | | |
| | | |
| | | |
| | | private Yw.Epanet.Network LoadEpaNetwork() |
| | | { |
| | | var fileName = "wh.inp"; |