WinCreateSpace.xaml.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Input;
  9. using System.Windows.Media;
  10. using System.Windows.Shapes;
  11. using Autodesk.Revit.DB;
  12. using DevExpress.Mvvm.Native;
  13. using SAGA.DotNetUtils.Extend;
  14. using SAGA.RevitUtils.Extends;
  15. using WPolyline = System.Windows.Shapes.Polyline;
  16. using Point = System.Windows.Point;
  17. using System.Windows.Media.Animation;
  18. using System.Windows.Threading;
  19. using Autodesk.Revit.UI;
  20. using SAGA.MBI.DataArrange;
  21. using SAGA.MBI.Model;
  22. using SAGA.MBI.WinView.ModeInfoMaintenance;
  23. using SAGA.RevitUtils;
  24. using SAGA.RevitUtils.Windows;
  25. using Visibility = System.Windows.Visibility;
  26. //TODO:1.目前存在的问题,如果只选两个已有的端点画线不能实现
  27. //TODO:2.画图过程中,ESC可取消当前画图
  28. //TODO:3.切换楼层检测是否有需要保存的数据,如果有则提示是否保存
  29. namespace SAGA.MBI.WinView.Space
  30. {
  31. /// <summary>
  32. /// 空间管理
  33. /// </summary>
  34. public partial class WinCreateSpaces : WinBase
  35. {
  36. public WinCreateSpaces()
  37. {
  38. this.IsLoadHistroyData = false;
  39. InitializeComponent();
  40. tv.ItemsSource = Items;
  41. this.Loaded += MainWindow_Loaded;
  42. this.Closed += WinCreateSpaces_Closed;
  43. }
  44. /// <summary>
  45. /// 窗体关闭,同时关闭空间属性窗
  46. /// </summary>
  47. /// <param name="sender"></param>
  48. /// <param name="e"></param>
  49. private void WinCreateSpaces_Closed(object sender, EventArgs e)
  50. {
  51. WinModeInfoMaintenance.GetWindow().Close();
  52. }
  53. /*
  54. 颜色分类:墙为黑色,
  55. 已有空间分隔符为绿色,
  56. 柱为蓝色
  57. 新的空间分隔符为红色
  58. */
  59. private List<List<XYZ>> m_wallsData;
  60. private List<PointPair> m_virXyzs;
  61. private List<XYZ> m_columnsLocation;
  62. public List<int> DeletedPolylines = new List<int>();//被删除的已存在的虚拟墙的Id
  63. //建筑与楼层列表数据
  64. private ObservableCollection<TreeNodeItem> items;
  65. //最大值X
  66. double m_minX = double.MaxValue;
  67. double m_maxX = 0.0;
  68. double m_minY = double.MaxValue;
  69. double m_maxY = 0.0;
  70. //初始缩放比例
  71. double m_scale = 15 / 1.5d;
  72. //起始点
  73. Point m_previousMousePoint = new Point(0, 0);
  74. //当前线段
  75. private Polyline m_polyline;
  76. //是否开始画线
  77. bool m_flag = false;
  78. //建筑与楼层列表数据
  79. public ObservableCollection<TreeNodeItem> Items
  80. {
  81. get => new ObservableCollection<TreeNodeItem>(DalModeFileManange.GetMissFileFloors(false));
  82. set => items = value;
  83. }
  84. private void MainWindow_Loaded(object sender, RoutedEventArgs e)
  85. {
  86. CanvasDefaultTips();
  87. }
  88. /// <summary>
  89. /// 初始化画布,并在画图上画出相关数据
  90. /// </summary>
  91. private void InitData()
  92. {
  93. //获取边界值
  94. GetBoundary();
  95. //获取缩放比例
  96. m_scale = Math.Min((canvas.ActualWidth - 40) / (m_maxX - m_minX), (canvas.ActualHeight - 40) / (m_maxY - m_minY));
  97. //虚拟墙
  98. m_virXyzs?.ForEach(line =>
  99. {
  100. var pline = CreateDefaultPolyLine(line.Point, Brushes.Green, 2);
  101. pline.Tag = line.ElementId;
  102. });
  103. //墙
  104. m_wallsData.Select(row => row.Select(xyz => xyz.ToW2DPoint()).ToList()).ForEach(line =>
  105. {
  106. CreateDefaultPolyLine(line, Brushes.Black, 4);
  107. });
  108. //画柱
  109. DrawColumns();
  110. var spaces =CurrentContext.Document.GetElements<SpatialElement>().Where(s => s is Autodesk.Revit.DB.Mechanical.Space && s.Area > 0).ToList();
  111. //创建空间轮廓,这里必须放在初始化之后创建
  112. CreateAllSpaceSeq(spaces);
  113. //创建右侧空间树
  114. ShowSpacesListFrowServer(spaces);
  115. }
  116. /// <summary>
  117. /// 获取数据的边界值
  118. /// </summary>
  119. void GetBoundary()
  120. {
  121. //Revit坐标与wpf的Y坐标相反,WPF Y向下
  122. var xs = new List<double>();
  123. var ys = new List<double>();
  124. this.m_wallsData.ForEach(list =>
  125. {
  126. list.ForEach((xyz) =>
  127. {
  128. xs.Add(xyz.X);
  129. ys.Add(xyz.Y);
  130. });
  131. });
  132. this.m_virXyzs.ForEach(list =>
  133. {
  134. list.Point.ForEach((point) =>
  135. {
  136. xs.Add(point.X);
  137. ys.Add(point.Y);
  138. });
  139. });
  140. this.m_columnsLocation.ForEach(point =>
  141. {
  142. xs.Add(point.X);
  143. ys.Add(point.Y);
  144. });
  145. if (xs.Count == 0 || ys.Count == 0) return;
  146. m_maxX = xs.Max();
  147. m_minX = xs.Min();
  148. m_maxY = ys.Max();
  149. m_minY = ys.Min();
  150. }
  151. /// <summary>
  152. /// 平移坐标点,使其更适应界面
  153. /// </summary>
  154. /// <param name="point"></param>
  155. /// <returns></returns>
  156. Point MovePoint(Point point)
  157. {
  158. var newPoint = new Point((point.X - m_minX) * m_scale, -(point.Y - m_maxY) * m_scale);
  159. newPoint.Offset(20, 20);
  160. return newPoint;
  161. }
  162. /// <summary>
  163. /// 画柱子
  164. /// </summary>
  165. void DrawColumns()
  166. {
  167. foreach (var xyz in m_columnsLocation)
  168. {
  169. var point = MovePoint(new Point(xyz.X, xyz.Y));
  170. var line = new WPolyline
  171. {
  172. Stroke = Brushes.Blue,
  173. StrokeThickness = 2,
  174. Tag = new Point(point.X, point.Y)
  175. };
  176. //这里为了方便后边计算,在线上记录柱中心
  177. var offset = 7;
  178. //左上角
  179. point.Offset(-offset, -offset);
  180. line.Points.Add(point);
  181. point.Offset(0, 2 * offset);
  182. line.Points.Add(point);
  183. point.Offset(2 * offset, 0);
  184. line.Points.Add(point);
  185. point.Offset(0, -2 * offset);
  186. line.Points.Add(point);
  187. point.Offset(-2 * offset, 0);
  188. line.Points.Add(point);
  189. this.canvas.Children.Add(line);
  190. }
  191. }
  192. /// <summary>
  193. /// 鼠标移动,实时显示虚拟墙动态
  194. /// </summary>
  195. /// <param name="sender"></param>
  196. /// <param name="e"></param>
  197. private void canvas_MouseMove(object sender, MouseEventArgs e)
  198. {
  199. if (m_flag == false)
  200. return;
  201. if (m_isDraw == true)
  202. {
  203. m_polyline.Points[m_polyline.Points.Count - 1] = e.GetPosition(canvas);
  204. Console.WriteLine("Move: " + m_polyline.Points[m_polyline.Points.Count - 1]);
  205. }
  206. }
  207. /// <summary>
  208. /// 开始画虚拟墙
  209. /// </summary>
  210. /// <param name="sender"></param>
  211. /// <param name="e"></param>
  212. private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  213. {
  214. if (m_isDraw != true) return;
  215. var point = e.GetPosition(canvas);
  216. if (m_polyline == null)
  217. {
  218. // if (flag == false) {
  219. m_polyline = new Polyline
  220. {
  221. Stroke = Brushes.Red,
  222. StrokeThickness = 2,
  223. FillRule = FillRule.EvenOdd
  224. };
  225. this.canvas.Children.Add(m_polyline);
  226. //如果是第一个点,则自动附着到现有的线段上
  227. point = GeometryHelper.ConvertOnLinePoint(point, this.canvas, m_polyline);
  228. }
  229. m_polyline.Points.Add(point);
  230. if (m_polyline.Points.Count == 1)
  231. m_polyline.Points.Add(e.GetPosition(canvas));
  232. m_flag = true;
  233. this.btnSave.IsEnabled = true;
  234. Console.WriteLine("Left Down: " + e.GetPosition(canvas));
  235. }
  236. /// <summary>
  237. /// 缩放画布
  238. /// </summary>
  239. /// <param name="scale"></param>
  240. /// <param name="center"></param>
  241. private void MoveElement(double scale, Point center, bool isReset = false)
  242. {
  243. //foreach (UIElement s in canvas.Children)
  244. {
  245. if (canvas.RenderTransform is TransformGroup tg)
  246. {
  247. //缩放
  248. if (tg.Children.FirstOrDefault(tr => tr is ScaleTransform) is ScaleTransform stf)
  249. {
  250. //重置
  251. if (isReset)
  252. {
  253. stf.ScaleX = 1;
  254. stf.ScaleY = 1;
  255. return;
  256. }
  257. //缩放的大小不能太小
  258. stf.ScaleX = Math.Max(stf.ScaleX + scale, 0.3);
  259. stf.ScaleY = Math.Max(stf.ScaleY + scale, 0.3);
  260. //if (center.X <= 0 || center.Y <= 0) {
  261. // return;
  262. //}
  263. // stf.CenterX = center.X;
  264. // stf.CenterY = center.Y;
  265. }
  266. else
  267. {
  268. scale = Math.Max(scale, 1);
  269. ScaleTransform scaleTransform = new ScaleTransform
  270. {
  271. ScaleX = scale,
  272. ScaleY = scale
  273. };
  274. tg.Children.Add(scaleTransform);
  275. }
  276. }
  277. else
  278. {
  279. TransformGroup transformGroup = new TransformGroup();
  280. ScaleTransform scaleTransform = new ScaleTransform();
  281. scaleTransform.ScaleX = 1;
  282. scaleTransform.ScaleY = 1;
  283. transformGroup.Children.Add(scaleTransform);
  284. canvas.RenderTransform = transformGroup;
  285. }
  286. }
  287. }
  288. /// <summary>
  289. /// TranslateTransform是平移画布
  290. /// </summary>
  291. /// <param name="dx"></param>
  292. /// <param name="dy"></param>
  293. private void MoveElement(double dx, double dy, bool isReset = false)
  294. {
  295. //foreach (UIElement s in canvas.Children)
  296. {
  297. if (canvas.RenderTransform is TransformGroup tg)
  298. {
  299. //平移
  300. if (tg.Children.FirstOrDefault(tr => tr is TranslateTransform) is TranslateTransform ttf)
  301. {
  302. var anim1 = new DoubleAnimation(ttf.X,
  303. (isReset ? 0 : (ttf.X + dx)),
  304. TimeSpan.FromSeconds(.01))
  305. { EasingFunction = new SineEase() };
  306. var anim2 = new DoubleAnimation(ttf.Y, (isReset ? 0 : (ttf.Y + dy)), TimeSpan.FromSeconds(.01)) { EasingFunction = new SineEase() };
  307. ttf.BeginAnimation(TranslateTransform.XProperty, anim1);
  308. ttf.BeginAnimation(TranslateTransform.YProperty, anim2);
  309. }
  310. else
  311. {
  312. TranslateTransform ttfNew = new TranslateTransform
  313. {
  314. // X = dx,
  315. // Y = dy
  316. };
  317. var anim1 = new DoubleAnimation(0, dx, TimeSpan.FromSeconds(.2)) { EasingFunction = new SineEase() };
  318. var anim2 = new DoubleAnimation(0, dy, TimeSpan.FromSeconds(.2)) { EasingFunction = new SineEase() };
  319. ttfNew.BeginAnimation(TranslateTransform.XProperty, anim1);
  320. ttfNew.BeginAnimation(TranslateTransform.YProperty, anim2);
  321. tg.Children.Add(ttfNew);
  322. }
  323. }
  324. else
  325. {
  326. TransformGroup transformGroup = new TransformGroup();
  327. TranslateTransform translateTransform = new TranslateTransform();
  328. //translateTransform.X = dx;
  329. //translateTransform.Y = dy;
  330. var anim1 = new DoubleAnimation(0, dx, TimeSpan.FromSeconds(.1)) { EasingFunction = new SineEase() };
  331. var anim2 = new DoubleAnimation(0, dy, TimeSpan.FromSeconds(.1)) { EasingFunction = new SineEase() };
  332. translateTransform.BeginAnimation(TranslateTransform.XProperty, anim1);
  333. translateTransform.BeginAnimation(TranslateTransform.YProperty, anim2);
  334. transformGroup.Children.Add(translateTransform);
  335. ScaleTransform scaleTransform = new ScaleTransform
  336. {
  337. ScaleX = 1,
  338. ScaleY = 1
  339. };
  340. // transformGroup.Children.Add(scaleTransform);
  341. canvas.RenderTransform = transformGroup;
  342. }
  343. }
  344. }
  345. /// <summary>
  346. /// 选择并删除虚拟墙
  347. /// </summary>
  348. /// <param name="sender"></param>
  349. /// <param name="e"></param>
  350. private void canvas_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  351. {
  352. Point point = e.GetPosition(canvas);
  353. if (m_isDraw == false)//擦除线
  354. {
  355. foreach (var canvasChild in this.canvas.Children)
  356. {
  357. if (canvasChild is WPolyline line)
  358. {
  359. for (int i = 0; i < line.Points.Count - 1; i++)
  360. {
  361. if (PointIsInLine(point, line.Points[i], line.Points[i + 1], 4))
  362. {
  363. //黑线与蓝线不能删除,红线直接删除,绿线删除需记录
  364. if (line.Stroke == Brushes.Red)
  365. {
  366. canvas.Children.Remove(line);
  367. btnSave.IsEnabled = true;
  368. }
  369. else if (line.Stroke == Brushes.Green)
  370. {
  371. DeletedPolylines.Add((int)line.Tag);
  372. canvas.Children.Remove(line);
  373. btnSave.IsEnabled = true;
  374. }
  375. return;
  376. }
  377. }
  378. }
  379. }
  380. }
  381. }
  382. private bool? m_isDraw = null;
  383. /// <summary>
  384. /// 开始画图
  385. /// </summary>
  386. /// <param name="sender"></param>
  387. /// <param name="e"></param>
  388. private void btnDraw_Click(object sender, RoutedEventArgs e)
  389. {
  390. if (m_isDraw != true)
  391. {
  392. m_isDraw = true;
  393. this.Cursor = Cursors.Pen;
  394. }
  395. else
  396. {
  397. m_isDraw = null;
  398. this.Cursor = Cursors.Hand;
  399. }
  400. }
  401. /// <summary>
  402. ///
  403. /// 开始删除操作
  404. /// </summary>
  405. /// <param name="sender"></param>
  406. /// <param name="e"></param>
  407. private void btnClear_Click(object sender, RoutedEventArgs e)
  408. {
  409. m_isDraw = false;
  410. this.Cursor = Cursors.Cross;
  411. }
  412. /// <summary>
  413. /// 判断点是否在直线上
  414. /// </summary>
  415. /// <param name="pf"></param>
  416. /// <param name="p1"></param>
  417. /// <param name="p2"></param>
  418. /// <param name="range"></param>
  419. /// <returns></returns>
  420. public static bool PointIsInLine(Point pf, Point p1, Point p2, double range = 0)
  421. {
  422. //range 判断的的误差,不需要误差则赋值0
  423. //点在线段首尾两端之外则return false
  424. double cross = (p2.X - p1.X) * (pf.X - p1.X) + (p2.Y - p1.Y) * (pf.Y - p1.Y);
  425. if (cross <= 0) return false;
  426. double d2 = (p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y);
  427. if (cross >= d2) return false;
  428. double r = cross / d2;
  429. double px = p1.X + (p2.X - p1.X) * r;
  430. double py = p1.Y + (p2.Y - p1.Y) * r;
  431. //判断距离是否小于误差
  432. return Math.Sqrt((pf.X - px) * (pf.X - px) + (py - pf.Y) * (py - pf.Y)) <= range;
  433. }
  434. /// <summary>
  435. /// 创建虚拟墙
  436. /// </summary>
  437. /// <param name="xyzs"></param>
  438. /// <param name="brush"></param>
  439. /// <param name="thinkness"></param>
  440. /// <returns></returns>
  441. Polyline CreateDefaultPolyLine(List<Point> xyzs, Brush brush, double thinkness = 2)
  442. {
  443. var pl = new Polyline
  444. {
  445. Stroke = brush,
  446. StrokeThickness = thinkness,
  447. StrokeStartLineCap = PenLineCap.Flat,
  448. StrokeEndLineCap = PenLineCap.Flat,
  449. StrokeLineJoin = PenLineJoin.Round
  450. };
  451. this.AddPoints(xyzs, pl);
  452. canvas.Children.Add(pl);
  453. return pl;
  454. }
  455. /// <summary>
  456. /// 添加虚拟墙的点
  457. /// </summary>
  458. /// <param name="lstPt"></param>
  459. /// <param name="pl"></param>
  460. void AddPoints(IEnumerable<Point> lstPt, Polyline pl)
  461. {
  462. foreach (var pt in lstPt)
  463. {
  464. pl.Points.Add(MovePoint(new Point(pt.X, pt.Y)));
  465. }
  466. }
  467. /// <summary>
  468. /// 将画布坐标转换为Revit坐标
  469. /// </summary>
  470. /// <param name="point"></param>
  471. /// <returns></returns>
  472. XYZ WpfPointToReivt(Point point)
  473. {
  474. return new XYZ(((point.X - 20) / m_scale + m_minX), ((point.Y - 20) / (-m_scale) + (m_maxY)), 0);
  475. }
  476. /// <summary>
  477. /// 获取上传确认窗口
  478. /// </summary>
  479. /// <returns></returns>
  480. private Window GetUploadConfirm()
  481. {
  482. WinConfirm confirm = new WinConfirm()
  483. {
  484. ShowMessage = "空间已发生变化,是否现在就上传模型并计算空间?",
  485. TTitle = "空间计算确认",
  486. BtnSure = "上传模型并计算空间",
  487. BtnCancel = "暂不计算",
  488. Owner = this,
  489. };
  490. return confirm;
  491. }
  492. /// <summary>
  493. /// 保存所画的线
  494. /// </summary>
  495. /// <param name="sender"></param>
  496. /// <param name="e"></param>
  497. private void btnSave_Click(object sender, RoutedEventArgs e)
  498. {
  499. SaveFloor();
  500. ExecuteCmd.ExecuteCommandOnce(() =>
  501. {
  502. if (tv.SelectedItem is TreeNodeItem item && item.Item is MFloor floor)
  503. {
  504. InitFloor(floor);
  505. }
  506. return Result.Succeeded;
  507. }, () => { return Result.Succeeded; });
  508. }
  509. /// <summary>
  510. /// 离开画布,改变鼠标样式
  511. /// </summary>
  512. /// <param name="sender"></param>
  513. /// <param name="e"></param>
  514. private void canvas_MouseLeave(object sender, MouseEventArgs e)
  515. {
  516. this.Cursor = Cursors.Arrow;
  517. }
  518. /// <summary>
  519. /// 鼠标进入画布,改变鼠标样式
  520. /// </summary>
  521. /// <param name="sender"></param>
  522. /// <param name="e"></param>
  523. private void canvas_MouseEnter(object sender, MouseEventArgs e)
  524. {
  525. if (m_isDraw == true)
  526. {
  527. this.Cursor = Cursors.Pen;
  528. }
  529. else if (m_isDraw == false)
  530. {
  531. this.Cursor = Cursors.Cross;
  532. }
  533. else
  534. {
  535. this.Cursor = Cursors.Hand;
  536. }
  537. }
  538. /// <summary>
  539. /// 鼠标右键,结束画线
  540. /// </summary>
  541. /// <param name="sender"></param>
  542. /// <param name="e"></param>
  543. private void canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
  544. {
  545. if (m_polyline == null || m_isDraw != true) return;
  546. //结束,调整最后一个点,让其自动附着
  547. m_polyline.Points[m_polyline.Points.Count - 1] = GeometryHelper.ConvertOnLinePoint(m_polyline.Points[m_polyline.Points.Count - 1], canvas, m_polyline);
  548. m_polyline = null;
  549. m_flag = false;
  550. }
  551. private void viewer_MouseWheel(object sender, MouseWheelEventArgs e)
  552. {
  553. double val = (double)e.Delta / 2000; //描述鼠标滑轮滚动
  554. // scaleValue += val;
  555. var center = e.GetPosition(this.canvas);
  556. //if (center.X <= 0 || center.Y <= 0) {
  557. // return;
  558. //}
  559. MoveElement(val, center);
  560. }
  561. /// <summary>
  562. /// 鼠标up事件,获取鼠标抬起的位置,并根据移动距离平移画布
  563. /// </summary>
  564. /// <param name="sender"></param>
  565. /// <param name="e"></param>
  566. private void viewer_MouseUp(object sender, MouseButtonEventArgs e)
  567. {
  568. //如果按下的是中键
  569. if (e.ChangedButton == MouseButton.Middle)
  570. {
  571. Point position = e.GetPosition(viewer);
  572. var tempx = position.X - this.m_previousMousePoint.X;
  573. var tempy = position.Y - this.m_previousMousePoint.Y;
  574. //平移画布
  575. MoveElement(tempx, tempy);
  576. }
  577. }
  578. /// <summary>
  579. /// 鼠标down事件,获取点击初始位置
  580. /// </summary>
  581. /// <param name="sender"></param>
  582. /// <param name="e"></param>
  583. private void viewer_MouseDown(object sender, MouseButtonEventArgs e)
  584. {
  585. if (e.ChangedButton == MouseButton.Middle)
  586. {
  587. m_previousMousePoint = e.GetPosition(viewer);
  588. btnSave.IsEnabled = true;
  589. }
  590. }
  591. /// <summary>
  592. /// 鼠标中键滚轮事件,控制canvas的缩放
  593. /// </summary>
  594. /// <param name="sender"></param>
  595. /// <param name="e"></param>
  596. private void viewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
  597. {
  598. double val = (double)e.Delta / 2000; //描述鼠标滑轮滚动
  599. var center = e.GetPosition(this.canvas);
  600. MoveElement(val, center);
  601. }
  602. public FloorSpaceContext CurrentContext;
  603. /// <summary>
  604. /// 楼层切换
  605. /// </summary>
  606. /// <param name="sender"></param>
  607. /// <param name="e"></param>
  608. private void Tv_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
  609. {
  610. try
  611. {
  612. //检测是否有未保存的数据,数据分两部分:新建的空间分隔符,删除的空间分隔符
  613. #region 切换前节点处理
  614. if (DeletedPolylines.Count > 0 || this.canvas.Children.OfType<UIElement>().Any(el => (el is WPolyline line && line.Stroke == Brushes.Red)))
  615. {
  616. WinConfirm confirm = new WinConfirm()
  617. {
  618. ShowMessage = "尚未保存空间变化,确认放弃修改?",
  619. TTitle = "空间修改确认",
  620. BtnSure = "保存并更改模型",
  621. BtnCancel = "放弃修改",
  622. Owner = this
  623. };
  624. var result = confirm.ShowDialog();
  625. if (result == true)
  626. {
  627. SaveFloor();
  628. //return;
  629. }
  630. }
  631. #endregion
  632. //异步造成执行顺序混乱的情况,所以使用idling排队
  633. ExecuteCmd.ExecuteCommandOnce(() =>
  634. {
  635. if (tv.SelectedItem is TreeNodeItem item && item.Item is MFloor floor)
  636. {
  637. InitFloor(floor);
  638. }
  639. return Result.Succeeded;
  640. }, () => { return Result.Succeeded; });
  641. }
  642. catch (Exception ex)
  643. {
  644. MessageShow.Show(ex);
  645. }
  646. }
  647. public void InitFloor(MFloor floor)
  648. {
  649. try
  650. {
  651. //保存按钮不可用
  652. this.btnSave.IsEnabled = false;
  653. DeletedPolylines.Clear();
  654. //关闭空间属性窗
  655. WinModeInfoMaintenance.GetWindow().Hide();
  656. this.canvas.Children.Clear();
  657. this.canvas.IsEnabled = false;
  658. this.lbSpaces.ItemsSource = null;
  659. #region 数据整理
  660. FloorSpaceContext context = new FloorSpaceContext(floor);
  661. CurrentContext = context;
  662. var doc = context.Document;
  663. var view = doc.GetUseView();
  664. if (view == null)
  665. {
  666. MessageBox.Show("无法找到名称以-saga结尾的视图!");
  667. return;
  668. }
  669. bool result = LoadData();
  670. if (!result)
  671. {
  672. MessageBox.Show("模型文件没有找到相关数据!");
  673. return;
  674. }
  675. ExecuteCmd.ExecuteCommand(() =>
  676. {
  677. context.CreateSpaces();
  678. #region 初始化界面
  679. this.canvas.IsEnabled = true;
  680. btnOrigin_Click(null, null);
  681. InitData();
  682. #endregion
  683. return Result.Succeeded;
  684. });
  685. #endregion
  686. }
  687. catch (Exception ex)
  688. {
  689. MessageBox.Show(ex.Message);
  690. }
  691. }
  692. private List<PointPair> GetPoints()
  693. {
  694. List<PointPair> saveDatas = new List<PointPair>();
  695. for (var j = 0; j < this.canvas.Children.Count; j++)
  696. {
  697. var child = this.canvas.Children[j];
  698. if (child is WPolyline line && line.Stroke == Brushes.Red)
  699. {
  700. for (int i = 0; i < line.Points.Count - 1; i++)
  701. {
  702. //创建新的虚拟墙
  703. var newLine = new Polyline()
  704. {
  705. Stroke = Brushes.Green,
  706. StrokeThickness = 2,
  707. };
  708. newLine.Points.Add(line.Points[i]);
  709. newLine.Points.Add(line.Points[i + 1]);
  710. //将现有坐标转化
  711. saveDatas.Add(new PointPair()
  712. {
  713. RPoint = new List<XYZ>() { WpfPointToReivt(line.Points[i]), WpfPointToReivt(line.Points[i + 1]) },
  714. ShowLine = newLine
  715. });
  716. this.canvas.Children.Add(newLine);
  717. }
  718. //删除现有的虚拟墙
  719. this.canvas.Children.Remove(line);
  720. j = -1;
  721. }
  722. }
  723. return saveDatas;
  724. }
  725. private void SaveFloor()
  726. {
  727. //禁用界面,防止重复提交
  728. this.IsEnabled = false;
  729. m_isDraw = null;
  730. //需要保存的分隔符数据
  731. List<PointPair> saveDatas = GetPoints();
  732. bool flagExecuteSuccess = true; //本应在回调函数里传值,目前代码不支持
  733. #region 扩展事件处理相关
  734. EventCommand updateCommand = new EventCommand(new ExternalEventHandler((app) => {
  735. try
  736. {
  737. var document = CurrentContext.Document;
  738. document.Save();
  739. if (!flagExecuteSuccess)
  740. {
  741. return;
  742. }
  743. SpaceManager.UploadModel(document);
  744. }
  745. catch (Exception ex)
  746. {
  747. MessageShow.Show(ex);
  748. }
  749. }));
  750. #endregion
  751. ExecuteCmd.ExecuteCommandOnce(() =>
  752. {
  753. try
  754. {
  755. updateCommand.Register();
  756. #region 创建空间
  757. using (TransactionGroup group = new TransactionGroup(CurrentContext.Document, "保存空间修改"))
  758. {
  759. group.Start();
  760. CurrentContext.UpdateSpaceSeqaration(saveDatas
  761. .Select(points => new SpaceSeparation(points.RPoint[0], points.RPoint[1])).ToList(),
  762. DeletedPolylines);
  763. DeletedPolylines.Clear();
  764. var createSuccess = CurrentContext.CreateSpaces();
  765. if (!createSuccess)
  766. {
  767. flagExecuteSuccess = false;
  768. group.RollBack();
  769. MessageShow.Infomation("保存楼层空间失败");
  770. return Result.Succeeded;
  771. }
  772. group.Assimilate();
  773. }
  774. #endregion
  775. #region 上传模型选择
  776. Window confirm = GetUploadConfirm();
  777. var result = confirm.ShowDialog();
  778. //选择以后界面可用
  779. this.IsEnabled = true;
  780. if (result == true)
  781. {
  782. // 由于上传需要关闭所有模型,所以这里需要对所有数据进行清空
  783. this.canvas.Children.Clear();
  784. //添加默认提示
  785. CanvasDefaultTips();
  786. lbSpaces.ItemsSource = new ObservableCollection<MISpace>();
  787. WinModeInfoMaintenance.GetWindow().Hide();
  788. }
  789. else
  790. {
  791. flagExecuteSuccess = false;
  792. }
  793. #endregion
  794. }
  795. finally
  796. {
  797. this.IsEnabled = true;
  798. }
  799. return Result.Succeeded;
  800. }, () =>
  801. {
  802. #region 代码中包含事务,不能再回调线程中使用
  803. //try
  804. //{
  805. // var document = CurrentContext.Document;
  806. // document.Save();
  807. // if (!flagExecuteSuccess)
  808. // {
  809. // return Result.Succeeded;
  810. // }
  811. // SpaceManager.UploadModel(document);
  812. //}
  813. //catch (Exception ex)
  814. //{
  815. // MessageShow.Show(ex);
  816. //}
  817. #endregion
  818. updateCommand.Raise();
  819. return Result.Succeeded;
  820. });
  821. }
  822. /// <summary>
  823. /// 创建边线
  824. /// </summary>
  825. /// <param name="spaces"></param>
  826. void CreateAllSpaceSeq(List<SpatialElement> spaces)
  827. {
  828. //清除已有的空间边线
  829. for (int i = 0; i < this.canvas.Children.Count; i++)
  830. {
  831. if (this.canvas.Children[i] is WPolyline line && line.Tag is Autodesk.Revit.DB.Mechanical.Space)
  832. {
  833. this.canvas.Children.RemoveAt(i);
  834. i -= 1;
  835. }
  836. }
  837. spaces.ForEach(s => CreateSpaceBoundary(s as Autodesk.Revit.DB.Mechanical.Space));
  838. }
  839. /// <summary>
  840. /// 获取所有空间对应的服务器端的信息
  841. /// </summary>
  842. /// <param name="spaces"></param>
  843. private void ShowSpacesListFrowServer(List<SpatialElement> spaces)
  844. {
  845. var datas = CurrentContext.GetPhysicalSpaces(spaces.Select(t => t.Id.IntegerValue.ToString()).ToList());
  846. var localSpace = spaces.Where(t => !datas.Any(s => s.BimID.Split(':')[1] == t.Id.ToString()))
  847. .Select(t => new MISpace("", $"{Guid.NewGuid()}:{t.Id.ToString()}") { Name = t.Name });
  848. datas.AddRange(localSpace);
  849. //List<string> dd;
  850. //dd.AddRange();
  851. lbSpaces.ItemsSource = new ObservableCollection<MISpace>(datas);
  852. }
  853. /// <summary>
  854. /// 加载模型数据
  855. /// </summary>
  856. private bool LoadData()
  857. {
  858. var doc = CurrentContext.Document;
  859. //读取墙数据
  860. List<Wall> walls = doc.FilterElements<Wall>().ToList();
  861. if (walls.Count == 0) return false;
  862. //获取虚拟墙(空间分隔符或者房间分隔符)
  863. var wallData = walls.Select(t => t.GetCurve().Tessellate().ToList()).ToList();
  864. var virWalls = doc.FilterElements<CurveElement>((line) =>
  865. {
  866. var categoryId = line.Category.Id.IntegerValue;
  867. return categoryId == (int)BuiltInCategory.OST_MEPSpaceSeparationLines ||
  868. categoryId == (int)BuiltInCategory.OST_RoomSeparationLines;
  869. }).Where(line => line is ModelLine).Select(line =>
  870. {
  871. var ml = line as ModelLine;
  872. var mlLine = ml.Location.GetLine();
  873. return
  874. new PointPair(ml.Id.IntegerValue, new List<System.Windows.Point>()
  875. {
  876. mlLine.StartPoint().ToW2DPoint(),
  877. mlLine.EndPoint().ToW2DPoint()
  878. });
  879. }).ToList();
  880. //获取所有建筑柱子
  881. var columns = doc.GetElements<FamilyInstance>(BuiltInCategory.OST_Columns);
  882. //结构柱
  883. var stColumns = doc.GetElements<FamilyInstance>(BuiltInCategory.OST_StructuralColumns);
  884. columns.AddRange(stColumns);
  885. m_columnsLocation = columns.Select(c => c.Location.GetPoint())
  886. .Where(t => !t.IsEqual(new XYZ(0, 0, 0), 0.000001)//TODO:临时处理
  887. ).ToList();
  888. this.m_wallsData = wallData;
  889. this.m_virXyzs = virWalls;
  890. return true;
  891. }
  892. /// <summary>
  893. /// 切换空间,亮显空间
  894. /// </summary>
  895. /// <param name="sender"></param>
  896. /// <param name="e"></param>
  897. private void lbSpaces_SelectionChanged(object sender, SelectionChangedEventArgs e)
  898. {
  899. try
  900. {
  901. #region 核心代码
  902. if (lbSpaces.SelectedItems.Count == 0) return;
  903. var space = lbSpaces.SelectedItems[0] as MISpace;
  904. var bimId = space.BimID.Split(':')[1];
  905. foreach (var polyline in this.canvas.Children.OfType<WPolyline>())
  906. {
  907. if (polyline.Tag is Autodesk.Revit.DB.Mechanical.Space s)
  908. {
  909. if (s.Id.ToString() == (bimId))
  910. {
  911. polyline.Fill = Brushes.Aquamarine;
  912. //显示属性窗口
  913. ShowSpaceProperty(s);
  914. }
  915. else if (polyline.Fill == Brushes.Aquamarine)
  916. {
  917. polyline.Fill = Brushes.Transparent;
  918. }
  919. }
  920. }
  921. #endregion
  922. }
  923. catch (Exception ex)
  924. {
  925. MessageShow.Show(ex);
  926. }
  927. }
  928. /// <summary>
  929. /// 显示空间属性窗体
  930. /// </summary>
  931. /// <param name="space"></param>
  932. private static void ShowSpaceProperty(Autodesk.Revit.DB.Mechanical.Space space)
  933. {
  934. MRevitEquipBase equipment = DalCommon.GetEquipmentQueryId(space);
  935. ShowSpaceProperty(equipment);
  936. }
  937. private static void ShowSpaceProperty(MRevitEquipBase equipment)
  938. {
  939. try
  940. {
  941. if (equipment != null)
  942. {
  943. var win = WinModeInfoMaintenanceForSpace.GetWindow();
  944. win.Topmost = true;
  945. win.Show(equipment);
  946. win.Visibility = Visibility.Visible;
  947. }
  948. }
  949. catch (Exception e)
  950. {
  951. MessageBox.Show("显示属性窗口出错" + e.Message, "系统提示");
  952. }
  953. }
  954. /// <summary>
  955. /// 创建空间边缘轮廓
  956. /// </summary>
  957. /// <param name="space"></param>
  958. private void CreateSpaceBoundary(Autodesk.Revit.DB.Mechanical.Space space)
  959. {
  960. if (space == null) return;
  961. //过滤未放置空间
  962. if (space.Area.IsEqual(0, 0.0001)) return;
  963. //取出边缘
  964. var mySegments = space.GetBoundarySegments(new SpatialElementBoundaryOptions());
  965. var seg = mySegments.FirstOrDefault();
  966. if (seg == null)
  967. {
  968. MessageBox.Show(space.Id.IntegerValue + "");
  969. return;
  970. }
  971. List<Point> datas = new List<Point>();
  972. foreach (BoundarySegment segment in seg)
  973. {
  974. datas.AddRange(segment.GetCurve().Tessellate().Select(xyz => xyz.ToW2DPoint()).ToList());
  975. }
  976. var polyLine = this.CreateDefaultPolyLine(datas, Brushes.Transparent);
  977. polyLine.Tag = space;//此处比较重要,这个是判断曲线是否为轮廓线的关键
  978. polyLine.Fill = Brushes.Transparent;
  979. polyLine.MouseLeftButtonDown += PolyLine_MouseDown;
  980. }
  981. /// <summary>
  982. /// 空间轮廓点击事件
  983. /// </summary>
  984. /// <param name="sender"></param>
  985. /// <param name="e"></param>
  986. private void PolyLine_MouseDown(object sender, MouseButtonEventArgs e)
  987. {
  988. if ((sender is WPolyline line) && m_isDraw == null)
  989. {
  990. //找到已亮显的空间
  991. var showSpaces = this.canvas.Children.OfType<WPolyline>().FirstOrDefault(t => t is WPolyline l && l.Fill == Brushes.Aquamarine);
  992. //先清除
  993. if (showSpaces != null) showSpaces.Fill = Brushes.Transparent;
  994. line.Fill = Brushes.Aquamarine;
  995. //MessageBox.Show(line.Tag+"");
  996. if (line.Tag is Autodesk.Revit.DB.Mechanical.Space space)
  997. {
  998. //反选右侧树
  999. for (int i = 0; i < lbSpaces.Items.Count; i++)
  1000. {
  1001. var showSpace = lbSpaces.Items[i] as MISpace;
  1002. var spaceId = showSpace.BimID.Split(':')[1];
  1003. if (spaceId == space.Id.ToString())
  1004. {
  1005. lbSpaces.SelectedIndex = i;
  1006. break;
  1007. }
  1008. }
  1009. //显示属性板
  1010. ShowSpaceProperty(space);
  1011. }
  1012. }
  1013. }
  1014. private void btnZoomIn_Click(object sender, RoutedEventArgs e)
  1015. {
  1016. MoveElement(-0.1, new Point());
  1017. }
  1018. private void btnOrigin_Click(object sender, RoutedEventArgs e)
  1019. {
  1020. MoveElement(0.1, new Point(), isReset: true);
  1021. MoveElement(0, 0, isReset: true);
  1022. }
  1023. private void btnZoomOut_Click(object sender, RoutedEventArgs e)
  1024. {
  1025. MoveElement(0.1, new Point());
  1026. }
  1027. //创建定时器,以检测所有操作是否全部保存完成
  1028. private DispatcherTimer timer;
  1029. private void CanvasDefaultTips()
  1030. {
  1031. string tips = "请选择一个需要进行空间管理的楼层";
  1032. TextBlock txtTips = new TextBlock
  1033. {
  1034. FontSize = 21,
  1035. Width = 345,
  1036. Height = 40,
  1037. Text = tips,
  1038. Foreground = Brushes.LightCyan
  1039. };
  1040. this.canvas.Children.Add(txtTips);
  1041. Canvas.SetLeft(txtTips, this.canvas.ActualWidth / 2.0d - 160);
  1042. Canvas.SetTop(txtTips, canvas.ActualHeight / 2.0d);
  1043. }
  1044. }
  1045. /// <summary>
  1046. /// 已有空间分割线的数据实体
  1047. /// </summary>
  1048. public class PointPair
  1049. {
  1050. //空间分割线的端点(WPF)
  1051. public List<Point> Point { get; set; }
  1052. //空间分割线的端点(Revit)
  1053. public List<XYZ> RPoint { get; set; } = new List<XYZ>();
  1054. //空间分割线的Id
  1055. public int ElementId { set; get; }
  1056. //WPF中显示的线
  1057. public Polyline ShowLine { get; set; }
  1058. public PointPair()
  1059. {
  1060. }
  1061. public PointPair(int elemId, List<Point> point)
  1062. {
  1063. this.Point = point;
  1064. this.ElementId = elemId;
  1065. }
  1066. }
  1067. }