using EmbedIO.WebSockets; using GeoSigma.SigmaDrawerUtil; using GeoSigmaDrawLib; using KevDrawServer.Drawer; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace KevDrawServer { /// /// 图形操作类. /// public class EventResponse { /// /// Initializes a new instance of the class. /// /// The drawer. /// The context. public EventResponse(WebDrawer drawer, IWebSocketContext context) { Drawer = drawer; Context = context; } /// /// Gets or sets 图形操作实例. /// public WebDrawer Drawer { get; set; } = null; /// /// Gets or sets 连接上下文. /// public IWebSocketContext Context { get; set; } = null; private string imageFile = "temp/K1.png"; public JsEvent ExcuteOperator(string evtentType, Dictionary keyValues) { if(this.Drawer == null) { return null; } object objDrawerWidth = null; object objDrawerHeight = null; if (keyValues != null) { keyValues.TryGetValue("width", out objDrawerWidth); keyValues.TryGetValue("height", out objDrawerHeight); } if (objDrawerWidth != null && objDrawerHeight != null) { double dDrawerWidth = 0; double dDrawerHeight = 0; double.TryParse($"{objDrawerWidth}", out dDrawerWidth); double.TryParse($"{objDrawerHeight}", out dDrawerHeight); if(dDrawerWidth>0&& dDrawerHeight > 0) { this.Drawer.DrawerSize = new Size((int)dDrawerWidth, (int)dDrawerHeight); } } JsEvent evtResult = null; switch (evtentType) { case "OpenFile": evtResult = ShowImg(); break; case "ZoomIn": evtResult = ZoomIn(keyValues); break; case "ZoomOut": evtResult = ZoomOut(keyValues); break; case "ViewAll": evtResult = ViewAll(keyValues); break; case "Refresh": evtResult = ReFresh(); break; case "Center": evtResult = DrawCenter(); break; case "ViewPan": evtResult = ViewPan(keyValues); break; case "ViewWindow": evtResult = ViewWindow(keyValues); break; case "Redraw": evtResult = Redraw(); break; case "MouseDown": //double dX = Convert.ToDouble(dictionary["x"]); //double dY = Convert.ToDouble(dictionary["y"]); //await ClickImageAsync(dX, dY); break; case "LButtonUp": double dUpX = Convert.ToDouble(keyValues["x"]); double dUpY = Convert.ToDouble(keyValues["y"]); int nKeyCode = 0; if(keyValues["keyCode"] != null) { nKeyCode = Convert.ToInt32(keyValues["keyCode"]); } evtResult = LButtonUp(dUpX, dUpY, nKeyCode); break; case "MouseMove": double dMoveX = Convert.ToDouble(keyValues["x"]); double dMoveY = Convert.ToDouble(keyValues["y"]); int nHandle = Convert.ToInt32(keyValues["handleIndex"]); evtResult = MouseMove(dMoveX, dMoveY); break; case "DragElement": double dDragX = Convert.ToDouble(keyValues["x"]); double dDragY = Convert.ToDouble(keyValues["y"]); evtResult = this.TranslateElements(dDragX, dDragY); break; case "SelectMouseDown": double dX = Convert.ToDouble(keyValues["x"]); double dY = Convert.ToDouble(keyValues["y"]); //await ClickImageAsync(dX, dY); evtResult = SelectLButtonDown(dX, dY); break; case "SelectMouseUp": double dSelectUpX = Convert.ToDouble(keyValues["x"]); double dSelectUpY = Convert.ToDouble(keyValues["y"]); int nMouseUpKeyCode = 0; if (keyValues["keyCode"] != null) { nMouseUpKeyCode = Convert.ToInt32(keyValues["keyCode"]); } evtResult = SelectMouseUp(dSelectUpX, dSelectUpY, nMouseUpKeyCode); break; case "GetElementProperty": evtResult = GetSelectElementProperty(); break; case "SetElementProperty": long elementID = 0; string strPropertyData = @""; strPropertyData = string.Empty; if (keyValues.ContainsKey("elementID")) { long.TryParse($"{keyValues["elementID"]}", out elementID); } if (keyValues.ContainsKey("data")) { strPropertyData = $"{keyValues["data"]}"; } evtResult = SetSelectElementProperty(strPropertyData); break; case "WellGroupClone": long wellGroupID = 0; if (keyValues.ContainsKey("elementID")) { long.TryParse($"{keyValues["elementID"]}", out elementID); } evtResult = SelectWellGroupClone(wellGroupID); break; case "GetWellGroupData": evtResult = SelectGetWellGroupData(); break; case "SaveFile": evtResult = SaveFile(); break; case "GetLayers": evtResult = GetLayersJson(); // GetLayers(); break; case "GetLayersNorm": evtResult = GetLayers(); // GetLayers(); break; case "GetElementsCount": evtResult = GetElementsCount(); // GetLayers(); break; case "SetLayersStatus": string strData = $"{ keyValues["layerData"]}"; evtResult = SetLayersStatus(strData); break; case "DeleteLayers": string strLayersData = $"{keyValues["layers"]}"; int nWithChilden = 1; if (keyValues.ContainsKey("widthChild")) { Int32.TryParse($"{keyValues["widthChild"]}", out nWithChilden); } evtResult = this.DeleteLayers(strLayersData, nWithChilden == 1); break; case "ClearAll": int needUndo = 0; string strNeedUndo = $"{keyValues["needUndo"]}"; if (!string.IsNullOrEmpty(strNeedUndo)) { int.TryParse(strNeedUndo, out needUndo); } evtResult = this.ClearAll(needUndo == 1 ? true : false); break; case "AddBufferData": string strBuffer = $"{ keyValues["bufferData"]}"; evtResult = AddBufferData(strBuffer); break; case "AddBasicDraw": { string strDrawBuffer = $"{ keyValues["bufferData"]}"; string strLayer = $"{ keyValues["layer"]}"; bool bCreateBlock = Convert.ToBoolean(keyValues["CreateBlock"]); evtResult = InsertDataBottom(strDrawBuffer, strLayer, bCreateBlock); } break; case "MergeFile": // 合并图件 string strFileName = $"{ keyValues["fileName"]}"; evtResult = MergeFile(strFileName); break; case "QueryRangeScreen2Real": double dScreenStartX = Convert.ToDouble(keyValues["startX"]); double dScreenEndX = Convert.ToDouble(keyValues["endX"]); double dScreenStartY = Convert.ToDouble(keyValues["startY"]); double dScreenEndY = Convert.ToDouble(keyValues["endY"]); evtResult = QueryRangeScreen2RealX(dScreenStartX, dScreenEndX, dScreenStartY, dScreenEndY); break; case "CreateFavorableArea": string strToken = $"{keyValues["token"]}"; var drawer = GlobalSession.GetData(strToken); string filename = Path.GetFileNameWithoutExtension(((WebDrawer)drawer).DrawFileName); double min = Convert.ToDouble(keyValues["min"]); double max = Convert.ToDouble(keyValues["max"]); string layer = Convert.ToString(keyValues["layer"]); string dir = keyValues["dir"].ToString(); evtResult = CreateFavorableArea(dir,filename, layer, min, max); break; case "MergeFavorableArea": strToken = $"{keyValues["token"]}"; drawer = GlobalSession.GetData(strToken); filename = Path.GetFileName(((WebDrawer)drawer).DrawFileName); dir = keyValues["dir"].ToString(); strFileName = $"{ keyValues["fileName"]}"; evtResult = MergeFavorableArea(dir, filename, strFileName); break; default: break; } return evtResult; } public JsEvent ShowImg(string file = "", int w = 0, int h = 0, bool sendContent = false) { if (this.Drawer == null) { return null; } Bitmap bmp = null; if (w != 0 && h != 0) { this.Drawer.DrawerSize = new Size(w, h); } bmp = new Bitmap(this.Drawer.DrawerSize.Width, this.Drawer.DrawerSize.Height); bmp.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution); using (Graphics g = Graphics.FromImage(bmp)) { this.Drawer.OnPaint(g); } JsEvent jsEvent = CreateImgEvent(bmp, "", sendContent); jsEvent.Success = true; return jsEvent; } public JsEvent ZoomIn(Dictionary keyValues) { if (this.Drawer == null) { return null; } this.Drawer.ZoomIn(); return ShowImg(); } public JsEvent ZoomOut(Dictionary keyValues) { //this.drawer = GetCurrentDrawer(); if (this.Drawer == null) { return null; } this.Drawer.ZoomOut(); return ShowImg(); } public JsEvent ViewAll(Dictionary keyValues) { if (this.Drawer == null) { return null; } this.Drawer.ViewAll(); return ShowImg(); } /// /// 移动浏览 /// /// public JsEvent ViewPan(Dictionary keyValues) { if (this.Drawer == null) { return null; } double dStartX = Convert.ToDouble(keyValues["startX"]); double dStartY = Convert.ToDouble(keyValues["startY"]); double dEndX = Convert.ToDouble(keyValues["endX"]); double dEndY = Convert.ToDouble(keyValues["endY"]); Bitmap bmp = null; bmp = this.Drawer.ViewOperatorPan(dStartX, dStartY, dEndX, dEndY); return CreateImgEvent(bmp); } /// /// 移动浏览 /// /// public JsEvent ViewWindow(Dictionary keyValues) { if (this.Drawer == null) { return null; } double dStartX = Convert.ToDouble(keyValues["startX"]); double dStartY = Convert.ToDouble(keyValues["startY"]); double dEndX = Convert.ToDouble(keyValues["endX"]); double dEndY = Convert.ToDouble(keyValues["endY"]); Bitmap bmp = this.Drawer.ViewOperatorWindow(dStartX, dStartY, dEndX, dEndY); return CreateImgEvent(bmp); } public JsEvent LButtonUp(double x, double y, int keyCode) { if (this.Drawer == null) { return null; ; } Bitmap bmp = this.Drawer.LButtonUp(x, y, keyCode); return CreateImgEvent(bmp); } public JsEvent MouseMove(double x, double y) { if (this.Drawer == null) { return null; } int result = 0; result = this.Drawer.MouseMove(x, y); //Console.WriteLine($"MouseMove hanle:{result}"); JsEvent responseEvent = new JsEvent("SelectHandle") { Data = result, }; return responseEvent; } public JsEvent TranslateElements(double x, double y) { if (this.Drawer == null) { return null; } try { Bitmap bmp = this.Drawer.TranslateElements(x, y); return CreateImgEvent(bmp); } catch (EmbedIO.WebSockets.WebSocketException ex) { //Console.WriteLine($"WebSocketException: {ex.Message}"); } catch (Exception ex) { //Console.WriteLine($"Exception: {ex.Message}"); } return null; } public JsEvent SelectLButtonDown(double x, double y) { if (this.Drawer == null) { return null; } Bitmap bmp = this.Drawer.OnLButtonDown(x, y); if (bmp != null) { bmp.MakeTransparent(Color.White); Point pt = this.Drawer.CacheImgLocation; string strFile = string.Empty; try { strFile = Path.Combine(WebConfig.HtmlRoot, imageFile); bmp.Save(strFile); } catch (Exception ex) { //Console.WriteLine($"SendImg: {ex.Message}"); return null; } string strEventName = "DragElement"; var responseEvent = new JsEvent(strEventName); Dictionary keyValues = new Dictionary(); keyValues.Add("Data", imageFile); keyValues.Add("ImgLeft", pt.X); keyValues.Add("ImgTop", pt.Y); responseEvent.Data = keyValues; return responseEvent; } return null; } /// /// 选中对象 /// /// public JsEvent SelectMouseUp(double endX, double endY, int keyCode) { Bitmap bmp = this.Drawer.LButtonUp(endX, endY, keyCode); return CreateImgEvent(bmp); } /// /// 井组克隆. /// /// The element i d. /// A JsEvent. public JsEvent SelectWellGroupClone(long elementID=0) { bool bSuccess = this.Drawer.SelectWellGroupClone(elementID); if (bSuccess == true) { return Redraw(); } return null; } /// /// 获得选中的井组相关数据 /// /// public JsEvent SelectGetWellGroupData() { string strWellGroupData = this.Drawer.SelectGetWellGroupData(); var responseEvent = new JsEvent("WellGroupData"); responseEvent.Data = strWellGroupData; return responseEvent; } /// /// 设置选中图元的属性 /// /// /// public JsEvent SetSelectElementProperty(string propertyData) { bool success = this.Drawer.SetElementProperty(propertyData); if(success == false) { return null; } return Redraw(); } public JsEvent GetSelectElementProperty() { string strElementData = string.Empty; long lPosition = 0; this.Drawer.GetSelectedElement(ref strElementData, ref lPosition); var responseEvent = new JsEvent("ElementProperty"); Dictionary keyValues = new Dictionary(); keyValues.Add("ElementID", lPosition); keyValues.Add("ElementData", strElementData); responseEvent.Data = keyValues; return responseEvent; } /// /// 保存图形. /// /// A JsEvent. public JsEvent SaveFile() { bool bSuccess = this.Drawer.SaveFile(); var responseEvent = new JsEvent("Save"); responseEvent.Data = bSuccess; return responseEvent; } private JsEvent CreateImgEvent(Bitmap bmp, string eventName = "", bool sendContent = false) { if(bmp == null) { return null; } byte[] image = null; string strFile = string.Empty; try { if (sendContent == false) { strFile = Path.Combine(WebConfig.HtmlRoot, imageFile); bmp.Save(strFile); } else { image = ConvertBitmapToByteArray(bmp); } } catch (Exception ex) { //Console.WriteLine($"SendImg: {ex.Message}"); return null; } string strEventName = eventName; if (string.IsNullOrEmpty(eventName)) { strEventName = "Redraw"; } var responseEvent = new JsEvent(strEventName); if (sendContent) { string base64Header = $"data:image/png;base64,"; responseEvent.Data = (base64Header + Convert.ToBase64String(image)); } else { responseEvent.Data = imageFile; } return responseEvent; } public JsEvent Redraw() { return this.ShowImg(); } /// /// Refresh-刷新 /// /// public JsEvent ReFresh() { this.Drawer.Geo.ReloadFile(); return this.ShowImg(); } /// /// ReCenter -全图居中 /// /// public JsEvent DrawCenter() { this.Drawer.Geo.ReloadFile(); return this.ShowImg(); } /// /// Gets 所有图元的数量. /// /// A JsEvent. public JsEvent GetElementsCount() { var responseEvent = new JsEvent("GetElementsCount"); int nCount = this.Drawer.Geo.GetElementCount(); responseEvent.Data = nCount; return responseEvent; } #region 图层管理 /// /// 获得图层数据.获取层位字符串(常规格式) /// /// A Task. public JsEvent GetLayers() { var responseEvent = new JsEvent("ReloadLayer") { Data = this.Drawer.LayerTree.Layers }; return responseEvent; } /// /// 获取图层,获得JSON结构化图层数据. /// /// A Task. public JsEvent GetLayersJson() { var responseEvent = new JsEvent("ReloadLayer") { Data = this.Drawer.LayerTree.LayersJson }; // responseEvent.Data = this.Drawer.LayerTree.LayersJson; return responseEvent; } /// /// Sets the layers status. /// /// The layers status. /// VIEW_EDIT = 10, /// VIEW_NOT_EDIT = 11, /// NOT_VIEW_NOT_EDIT = 12 /// A Task. public JsEvent SetLayersStatus(string layersStatus) { GeoLayerTree layerTree = this.Drawer?.LayerTree; if (layerTree.SetLayersStatus(layersStatus)) { return ShowImg(); } return null; } /// /// 删除图层 /// /// /// /// public JsEvent DeleteLayers(string layers, bool withSubLayer) { var layerArray = layers.Split(new string[] { Environment.NewLine, "," }, StringSplitOptions.RemoveEmptyEntries); int nCount = layerArray.Length; if (nCount == 0) { return null; } for (int i = 0; i < nCount; i++) { int nIndexFind = layerArray[i].IndexOf("Layer:\\", 0, StringComparison.CurrentCultureIgnoreCase); if (nIndexFind >= 0) { layerArray[i] = layerArray[i].Remove(0, 7+ nIndexFind); } } this.Drawer.DeleteLayers(layerArray, withSubLayer); return this.ShowImg(); //var responseEvent = new JsEvent("DeleteLayers") //{ // Data = string.Empty, //}; //await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(true); //await this.ShowImgAsync(); } public JsEvent ClearAll(bool needUndo) { bool bSuccess = this.Drawer.ClearAll(needUndo); var responseEvent = new JsEvent("ClearAll") { Data = bSuccess, }; return responseEvent; } #endregion #region 合并图件 /// /// 合并图件 /// /// 图件地址 /// public JsEvent MergeFile(string fileName) { DrawerConfig.StartupPath = WebConfig.StartupPath; //string strServerPath = WebConfig.MapDirectory;// 获取配置文件中的MapDirectory目录 // string strMapFile = Path.Combine(strServerPath, fileName); if (!File.Exists(fileName)) { var responseEventError = new JsEvent("MergeFile") { Data = false, }; return responseEventError; } bool isSuccess = this.Drawer.MergeFile(fileName); var responseEvent = new JsEvent("MergeFile") { Data = isSuccess, }; return responseEvent; } #endregion #region 数据操作 /// /// 添加数据. /// /// The data. /// A Task. public JsEvent AddBufferData(string data) { int nResult = this.Drawer.AddBufferData(data); var responseEvent = new JsEvent("AddBufferData") { Data = nResult, }; return responseEvent; } public JsEvent InsertDataBottom(string data, string newLayer, bool createBlock) { bool nResult = false; if (createBlock) { string strData = $"Layer M {newLayer}{Environment.NewLine}Block{Environment.NewLine}{data}{Environment.NewLine}EndBlock{Environment.NewLine}"; nResult = this.Drawer.InsertDataBottom(data, ""); } else { nResult = this.Drawer.InsertDataBottom(data, newLayer); } var responseEvent = new JsEvent("AddBasicDraw") { Data = nResult, }; return responseEvent; } #endregion #region 坐标工具 /// /// 屏幕坐标转换为实际坐标. /// /// The start x. /// /// The start y. /// /// A Task. public JsEvent QueryRangeScreen2RealX(double startX, double endX, double startY, double endY) { double dRectLeft = 0, dRectRight = 0, dRectTop = 0, dRectBottom = 0; this.Drawer.Geo.GetScreenReal((int)startX, (int)startY, (int)endX, (int)endY , ref dRectLeft, ref dRectTop, ref dRectRight, ref dRectBottom); Dictionary keyValues = new Dictionary(); keyValues.Add("left", dRectLeft); keyValues.Add("bottom", dRectBottom); keyValues.Add("right", dRectRight); keyValues.Add("top", dRectTop); var responseEvent = new JsEvent("MapRangeReal") { Data = keyValues, }; return responseEvent; } /// /// 创建有利区 /// /// 图件存储目录 /// 将创建有利区的图层,如果不存在,则会自动创建图层 /// 原文件名,不带路径 /// 最小 z 值 /// 最大 z 值 /// public JsEvent CreateFavorableArea(string dir,string sourceFileName, string layerName, double zMin, double zMax) { var drawerData = new DrawerData(); this.Drawer.Geo.CreateFavorableArea(drawerData.pXy, "有利区", zMin, zMax); string filename = $"{sourceFileName}-有利区-{DateTime.Now:yyyyMMddHHmmssff}.kev"; string strMapFile = Path.Combine(dir, filename); drawerData.SaveAs(strMapFile); var keyValues = new Dictionary() { { "filename", filename }, }; return new JsEvent("CreateFavorableArea") { Data = keyValues, }; } /// /// 合并有利区底图 /// /// 目录 /// 原图文件 /// 底层 /// public JsEvent MergeFavorableArea(string dir, string sourceFileName, string bottomFileName) { string filename = $"{Path.GetFileNameWithoutExtension(sourceFileName)}-有利区-{DateTime.Now:HHmmssff}-带底图.kev"; string sourcePath = Path.Combine(dir, sourceFileName); string targetPath = Path.Combine(dir, filename); string bottomPath = Path.Combine(dir, bottomFileName); string type = "MergeFavorableArea"; var drawerData = new DrawerData(); if (!drawerData.OpenFile(sourcePath)) { return ErrorEvent(type, $"打开原文件失败,原文件路径: {sourcePath}"); } if (!drawerData.MergeFile(bottomPath)) { return ErrorEvent(type, $"合并文件失败,合并文件路径: {bottomPath}"); } if (!drawerData.SaveAs(targetPath)) { return ErrorEvent(type, $"保存文件失败,保存文件路径: {targetPath}"); } return new JsEvent(type) { Success = true, Data = new Dictionary() { { "filename", $"{Path.GetFileName(targetPath)}" }, } }; } private JsEvent ErrorEvent(string type, string message) { return new JsEvent(type) { Success = false, Data = new Dictionary() { { "error", message }, } }; } #endregion /// /// Creates the drawer. /// /// The file. /// The w. /// The h. /// public async static Task CreateDrawerAsync(string file, int w, int h, IWebSocketContext context, string token) { DrawerConfig.StartupPath = WebConfig.StartupPath; string strServerPath = WebConfig.MapDirectory; WebDrawer drawer = new WebDrawer(w, h); string strMapFile = Path.Combine(strServerPath, file); //ImageFile = Path.Combine(strServerPath, "K1.png"); string strToken = string.Empty; await Task.Run(() => { GeoSigmaXY geo = drawer.OpenFile(strMapFile); if (geo != null) { strToken = geo.GetDrawerXy().ToInt64().ToString(); } }); if (!string.IsNullOrEmpty(strToken)) { GlobalSession.StoreData(token, drawer); //Context.Session["DrawerFile"] = file; GlobalSession.StoreData($"Lock_{token}", new SemaphoreSlim(1, 1)); } Logger.Info("CreateDrawerAsync:" + token); return strToken; } /// /// 资源销毁 /// public static async Task CloseDrawerAsync(string token, IWebSocketContext context) { SemaphoreSlim drawerLock = (SemaphoreSlim)GlobalSession.GetData($"Lock_{token}"); if(drawerLock == null) { return; } // 确保在销毁前没有其他线程访问Drawer对象 await drawerLock.WaitAsync(); try { WebDrawer drawer = (WebDrawer)GlobalSession.GetData(token); if (drawer != null) { drawer.Dispose(); // 释放资源 GlobalSession.TryRemove(token, out object objDrawer); // 从Session中移除Drawer对象 GlobalSession.TryRemove($"Lock_{token}", out object objLock); // 从Session中移除锁对象 drawer = null; } } finally { drawerLock.Release(); drawerLock.Dispose(); // 释放 SemaphoreSlim 资源 } } /// /// Converts the bitmap to byte array. /// /// The bitmap. /// An array of byte. public static byte[] ConvertBitmapToByteArray(Bitmap bitmap) { if (bitmap == null) { return null; } using (MemoryStream memoryStream = new MemoryStream()) { // 选择图像格式,可以是Png、Jpeg等 bitmap.Save(memoryStream, ImageFormat.Png); return memoryStream.ToArray(); } } } }