xBIM 实战03 使用WPF技术实现IFC模型的加载与浏览
因为 DirectX 能理解可由显卡直接渲染的高层元素,如纹理和渐变,所以 DirectX 效率更高。而 GDI/GDI+不理解这些高层元素,因此必须将他们转换成逐像素指令,而通过现代显卡渲染这些指令更慢。
主要业务逻辑如下:
1 /// <summary> 2 /// 加载模型文件 3 /// </summary> 4 /// <param name="modelFileName"></param> 5 public void LoadAnyModel(string modelFileName) 6 { 7 var fInfo = new FileInfo(modelFileName); 8 if (!fInfo.Exists) 9 return; 10 11 if (fInfo.FullName.ToLower() == GetOpenedModelFileName()) 12 return; 13 14 // 没有撤回功能;如果在这一点之后失败,那么应该关闭当前文件。 15 CloseAndDeleteTemporaryFiles(); 16 SetOpenedModelFileName(modelFileName.ToLower()); 17 ProgressStatusBar.Visibility = Visibility.Visible; 18 SetWorkerForFileLoad(); 19 20 var ext = fInfo.Extension.ToLower(); 21 switch (ext) 22 { 23 case ".ifc": // Ifc 文件 24 case ".ifcxml": // IfcXml 文件 25 case ".ifczip": // zip 文件,包含 xbim 或者 ifc 文件 26 case ".zip": // zip 文件,包含 xbim 或者 ifc 文件 27 case ".xbimf": 28 case ".xbim": 29 _loadFileBackgroundWorker.RunWorkerAsync(modelFileName); 30 break; 31 default: 32 Logger.LogWarning("Extension '{extension}' has not been recognised.", ext); 33 break; 34 } 35 }
其中调用的主要方法如下:
1 /// <summary> 2 /// 整理所有打开的文件并关闭所有打开的模型 3 /// </summary> 4 private void CloseAndDeleteTemporaryFiles() 5 { 6 try 7 { 8 if (_loadFileBackgroundWorker != null && _loadFileBackgroundWorker.IsBusy) 9 { 10 _loadFileBackgroundWorker.CancelAsync(); //通知线程取消操作 11 } 12 13 SetOpenedModelFileName(null); 14 if (Model != null) 15 { 16 Model.Dispose(); 17 ModelProvider.ObjectInstance = null; 18 ModelProvider.Refresh(); 19 } 20 21 if (!(DrawingControl.DefaultLayerStyler is SurfaceLayerStyler)) 22 { 23 SetDefaultModeStyler(null, null); 24 } 25 } 26 finally 27 { 28 if (!(_loadFileBackgroundWorker != null && _loadFileBackgroundWorker.IsBusy && _loadFileBackgroundWorker.CancellationPending)) //它仍然在运行,但已经取消了 29 { 30 if (!string.IsNullOrWhiteSpace(_temporaryXbimFileName) && File.Exists(_temporaryXbimFileName)) 31 { 32 File.Delete(_temporaryXbimFileName); 33 } 34 _temporaryXbimFileName = null; 35 } 36 else 37 { 38 //它将在工作线程中清除 39 } 40 } 41 }
1 private void SetOpenedModelFileName(string ifcFilename) 2 { 3 _openedModelFileName = ifcFilename; 4 // 尝试通过用于多线程的委托更新窗口标题 5 Dispatcher.BeginInvoke(new Action(delegate 6 { 7 Title = string.IsNullOrEmpty(ifcFilename) 8 ? "Xbim Xplorer" 9 : "Xbim Xplorer - [" + ifcFilename + "]"; 10 })); 11 }
1 private void SetWorkerForFileLoad() 2 { 3 _loadFileBackgroundWorker = new BackgroundWorker 4 { 5 WorkerReportsProgress = true, 6 WorkerSupportsCancellation = true 7 }; 8 _loadFileBackgroundWorker.ProgressChanged += OnProgressChanged; 9 _loadFileBackgroundWorker.DoWork += OpenAcceptableExtension; 10 _loadFileBackgroundWorker.RunWorkerCompleted += FileLoadCompleted; 11 }
1 private void OnProgressChanged(object s, ProgressChangedEventArgs args) 2 { 3 if (args.ProgressPercentage < 0 || args.ProgressPercentage > 100) 4 return; 5 6 Application.Current.Dispatcher.BeginInvoke( 7 DispatcherPriority.Send, 8 new Action(() => 9 { 10 ProgressBar.Value = args.ProgressPercentage; 11 StatusMsg.Text = (string)args.UserState; 12 })); 13 14 }
1 private void OpenAcceptableExtension(object s, DoWorkEventArgs args) 2 { 3 var worker = s as BackgroundWorker; 4 var selectedFilename = args.Argument as string; 5 6 try 7 { 8 if (worker == null) 9 throw new Exception("Background thread could not be accessed"); 10 _temporaryXbimFileName = Path.GetTempFileName(); 11 SetOpenedModelFileName(selectedFilename); 12 var model = IfcStore.Open(selectedFilename, null, null, worker.ReportProgress, FileAccessMode); 13 if (_meshModel) 14 { 15 // 匹配直接模型 16 if (model.GeometryStore.IsEmpty) 17 { 18 try 19 { 20 var context = new Xbim3DModelContext(model); 21 22 if (!_multiThreading) 23 context.MaxThreads = 1; 24 #if FastExtrusion 25 context.UseSimplifiedFastExtruder = _simpleFastExtrusion; 26 #endif 27 SetDeflection(model); 28 // 升级到新的几何图形表示,使用默认的三维模型 29 context.CreateContext(worker.ReportProgress, App.ContextWcsAdjustment); 30 } 31 catch (Exception geomEx) 32 { 33 var sb = new StringBuilder(); 34 sb.AppendLine($"Error creating geometry context of '{selectedFilename}' {geomEx.StackTrace}."); 35 var newException = new Exception(sb.ToString(), geomEx); 36 Logger.LogError(0, newException, "Error creating geometry context of {filename}", selectedFilename); 37 } 38 } 39 40 // 匹配引用 41 foreach (var modelReference in model.ReferencedModels) 42 { 43 // 根据需要创建联合几何体上下文 44 Debug.WriteLine(modelReference.Name); 45 if (modelReference.Model == null) 46 continue; 47 if (!modelReference.Model.GeometryStore.IsEmpty) 48 continue; 49 var context = new Xbim3DModelContext(modelReference.Model); 50 if (!_multiThreading) 51 context.MaxThreads = 1; 52 #if FastExtrusion 53 context.UseSimplifiedFastExtruder = _simpleFastExtrusion; 54 #endif 55 SetDeflection(modelReference.Model); 56 // 升级到新的几何图形表示,使用默认的三维模型 57 context.CreateContext(worker.ReportProgress, App.ContextWcsAdjustment); 58 } 59 if (worker.CancellationPending) 60 // 如果已请求取消,则不要打开结果文件 61 { 62 try 63 { 64 model.Close(); 65 if (File.Exists(_temporaryXbimFileName)) 66 { 67 File.Delete(_temporaryXbimFileName); 68 } 69 70 _temporaryXbimFileName = null; 71 SetOpenedModelFileName(null); 72 } 73 catch (Exception ex) 74 { 75 Logger.LogError(0, ex, "Failed to cancel open of model {filename}", selectedFilename); 76 } 77 return; 78 } 79 } 80 else 81 { 82 Logger.LogWarning("Settings prevent mesh creation."); 83 } 84 args.Result = model; 85 } 86 catch (Exception ex) 87 { 88 var sb = new StringBuilder(); 89 sb.AppendLine($"Error opening '{selectedFilename}' {ex.StackTrace}."); 90 var newException = new Exception(sb.ToString(), ex); 91 Logger.LogError(0, ex, "Error opening {filename}", selectedFilename); 92 args.Result = newException; 93 } 94 }
1 private void FileLoadCompleted(object s, RunWorkerCompletedEventArgs args) 2 { 3 if (args.Result is IfcStore) 4 { 5 // 这将触发将模型加载到视图中的事件 6 ModelProvider.ObjectInstance = args.Result; 7 ModelProvider.Refresh(); 8 ProgressBar.Value = 0; 9 StatusMsg.Text = "Ready"; 10 AddRecentFile(); 11 } 12 else 13 { 14 var errMsg = args.Result as string; 15 if (!string.IsNullOrEmpty(errMsg)) 16 { 17 MessageBox.Show(this, errMsg, "Error Opening File", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.None, MessageBoxOptions.None); 18 } 19 20 var exception = args.Result as Exception; 21 if (exception != null) 22 { 23 var sb = new StringBuilder(); 24 25 var indent = ""; 26 while (exception != null) 27 { 28 sb.AppendFormat("{0}{1}\n", indent, exception.Message); 29 exception = exception.InnerException; 30 indent += "\t"; 31 } 32 MessageBox.Show(this, sb.ToString(), "Error Opening Ifc File", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.None, MessageBoxOptions.None); 33 } 34 ProgressBar.Value = 0; 35 StatusMsg.Text = "Error/Ready"; 36 SetOpenedModelFileName(""); 37 } 38 FireLoadingComplete(s, args); 39 }
1 /// <summary> 2 /// 模型文件加载完成事件 3 /// </summary> 4 public event LoadingCompleteEventHandler LoadingComplete; 5 6 private void FireLoadingComplete(object s, RunWorkerCompletedEventArgs args) 7 { 8 if (LoadingComplete != null) 9 { 10 LoadingComplete(s, args); 11 } 12 }
成在管理,败在经验;嬴在选择,输在不学! 贵在坚持!
个人作品
BIMFace.SDK.NET
开源地址:https://gitee.com/NAlps/BIMFace.SDK
系列博客:https://www.cnblogs.com/SavionZhang/p/11424431.html
系列视频:https://www.cnblogs.com/SavionZhang/p/14258393.html
技术栈
1、Visual Studio、.NET Core/.NET、MVC、Web API、RESTful API、gRPC、SignalR、Java、Python
2、jQuery、Vue.js、Bootstrap、ElementUI
3、数据库:分库分表、读写分离、SQLServer、MySQL、PostgreSQL、Redis、MongoDB、ElasticSearch、达梦DM
4、架构:DDD、ABP、SpringBoot、jFinal
5、环境:跨平台、Windows、Linux、Nginx
6、移动App:Android、IOS、HarmonyOS、微信小程序、钉钉、uni-app、MAUI
分布式、高并发、云原生、微服务、Docker、CI/CD、DevOps、K8S;Dapr、RabbitMQ、Kafka、RPC、Elasticsearch。
欢迎关注作者头条号 张传宁IT讲堂,获取更多IT文章、视频等优质内容。
出处:www.cnblogs.com/SavionZhang
作者:张传宁 技术顾问、培训讲师、微软MCP、系统架构设计师、系统集成项目管理工程师、科技部创新工程师。
专注于企业级通用开发平台、工作流引擎、自动化项目(代码)生成器、SOA 、DDD、 云原生(Docker、微服务、DevOps、CI/CD);PDF、CAD、BIM 审图等研究与应用。
多次参与电子政务、图书教育、生产制造等企业级大型项目研发与管理工作。
熟悉中小企业软件开发过程:可行调研、需求分析、架构设计、编码测试、实施部署、项目管理。通过技术与管理帮助中小企业实现互联网转型升级全流程解决方案。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如有问题,可以通过邮件905442693@qq.com联系。共同交流、互相学习。
如果您觉得文章对您有帮助,请点击文章右下角【推荐】。您的鼓励是作者持续创作的最大动力!