xBIM 实战03 使用WPF技术实现IFC模型的加载与浏览

  WPF应用程序在底层使用 DirectX ,无论设计复杂的3D图形(这是 DirectX 的特长所在)还是绘制简单的按钮与文本,所有绘图工作都是通过 DirectX 管线完成的。在硬件加速方面也带来了好处,DirectX 在渲染图形时会将尽可能多的工作递交给图形处理单元(GPU)去处理,GPU是显卡的专用处理器。

因为 DirectX 能理解可由显卡直接渲染的高层元素,如纹理和渐变,所以 DirectX 效率更高。而 GDI/GDI+不理解这些高层元素,因此必须将他们转换成逐像素指令,而通过现代显卡渲染这些指令更慢。

  WPF凭借着出色的3D渲染能力,使其成为在客户端加载渲染3D模型不二的选择。在3D模型查看器中加载BIM文件(.ifc格式),显示效果如下图所示:

 主要业务逻辑如下:

 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         }
 
posted @ 2019-06-12 19:49  张传宁  阅读(1619)  评论(6编辑  收藏  举报
页脚 HTML 代码