프로젝트

일반

사용자정보

통계
| 개정판:

hytos / ID2.Manager / ID2.Manager.Compare / Controls / Verification.cs @ 1f75c4f0

이력 | 보기 | 이력해설 | 다운로드 (73.2 KB)

1
using devDept.Eyeshot;
2
using devDept.Eyeshot.Entities;
3
using devDept.Eyeshot.Translators;
4
using devDept.Geometry.Entities;
5
using System;
6
using System.Collections.Generic;
7
using System.ComponentModel;
8
using System.Data;
9
using System.Drawing;
10
using System.IO;
11
using System.Linq;
12
using System.Runtime.InteropServices;
13
using System.Text;
14
using System.Threading.Tasks;
15
using System.Windows.Forms;
16
using Telerik.WinControls;
17
using Telerik.WinControls.UI;
18
using Telerik.Windows.Documents.Fixed.FormatProviders.Pdf;
19
using Telerik.Windows.Documents.Fixed.Model;
20
using Telerik.Windows.Documents.Fixed.Model.Editing;
21

    
22
namespace ID2.Manager.Controls
23
{
24
    public partial class Verification : UserControl
25
    {
26
        readonly string IniFilePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 
27
            Application.ProductName, $"{Application.ProductName}.ini");
28

    
29
        #region 기본값
30
        private static string AutoCADLayer { get; } = "AutoCAD";
31
        private static Color AutoCADColor = Color.FromArgb(44, 44, 44);
32
        private static string AVEVALayer { get; } = "AVEVA";
33
        private static Color AVEVAColor = Color.FromArgb(44, 44, 44);
34
        private static string RevCloudLayer { get; } = "RevCloud";
35
        private static Color RevCloudColor = Color.Magenta;
36
        private static Color DiffColor = Color.Yellow;
37
        
38
        private static double Tolerance = 0;
39
        private static double LengthToleranceRatio { get; set; } = 0.1;
40
        #endregion
41

    
42
        private RadProgressBarElement _progressBar = null;
43

    
44
        public Verification(RadProgressBarElement progressBar)
45
        {
46
            InitializeComponent();
47

    
48
            this.Load += Verification_Load;
49
            this.radSpinEditorTolerance.ValueChanged += RadSpinEditorTolerance_ValueChanged;
50
            this.radColorBoxAutoCADColor.ValueChanged += RadColorBoxAutoCADColor_ValueChanged;
51
            this.radColorBoxAVEVAColor.ValueChanged += RadColorBoxAVEVAColor_ValueChanged;
52
            this.radColorBoxDiffColor.ValueChanged += RadColorBoxDiffColor_ValueChanged;
53
            this.radColorBoxRevCloudColor.ValueChanged += RadColorBoxRevCloudColor_ValueChanged;
54

    
55
            this.designAutoCAD.ActionMode = actionType.SelectVisibleByPickDynamic;
56
            this.designAutoCAD.ActiveViewport.CoordinateSystemIcon.Visible = false;
57
            this.designAutoCAD.Selection.ColorDynamic = Color.FromArgb(80, Color.OrangeRed);
58
            this.designAutoCAD.Selection.HaloInnerColor = Color.FromArgb(255, Color.OrangeRed);
59
            this.designAutoCAD.Selection.HaloOuterColor = Color.FromArgb(64, Color.OrangeRed);
60
            this.designAutoCAD.Selection.HaloWidthPolygons = 4;
61
            this.designAutoCAD.Selection.HaloWidthWires = 2;
62
            this.designAutoCAD.ActiveViewport.OriginSymbol.Visible = false;
63

    
64
            this.designAVEVA.ActionMode = actionType.SelectVisibleByPickDynamic;
65
            this.designAVEVA.ActiveViewport.CoordinateSystemIcon.Visible = false;
66
            this.designAVEVA.ActiveViewport.OriginSymbol.Visible = false;
67
            this.designCompare.ActionMode = actionType.SelectVisibleByPickDynamic;
68
            this.designCompare.ActiveViewport.CoordinateSystemIcon.Visible = false;
69
            this.designCompare.ActiveViewport.OriginSymbol.Visible = false;
70

    
71
            this.radCheckBoxAutoCAD.CheckStateChanged += RadCheckBoxAutoCAD_CheckStateChanged;
72
            this.radCheckBoxAVEVA.CheckStateChanged += RadCheckBoxAVEVA_CheckStateChanged;
73
            this.radCheckBoxRevCloud.CheckStateChanged += RadCheckBoxRevCloud_CheckStateChanged;
74

    
75
            _progressBar = progressBar;
76

    
77
            #region Camera Sync
78
            this.designAutoCAD.ActiveViewport.Rotate.Enabled = false;
79
            this.designAVEVA.ActiveViewport.Rotate.Enabled = false;
80
            this.designCompare.ActiveViewport.Rotate.Enabled = false;
81

    
82
            this.designAutoCAD.ActiveViewport.ViewCubeIcon.Visible = false;
83
            this.designAVEVA.ActiveViewport.ViewCubeIcon.Visible = false;
84
            this.designCompare.ActiveViewport.ViewCubeIcon.Visible = false;
85

    
86
            this.designAutoCAD.AnimateCamera = false;
87
            this.designAVEVA.AnimateCamera = false;
88
            this.designCompare.AnimateCamera = false;
89

    
90
            this.designAutoCAD.CameraChangedFrequency = 200;
91
            this.designAVEVA.CameraChangedFrequency = 200;
92
            this.designCompare.CameraChangedFrequency = 200;
93

    
94
            this.designAutoCAD.CameraChanged += CameraChanged;
95
            this.designAVEVA.CameraChanged += CameraChanged;
96
            this.designCompare.CameraChanged += CameraChanged;
97
            #endregion
98
        }
99

    
100
        private void RadCheckBoxRevCloud_CheckStateChanged(object sender, EventArgs e)
101
        {
102
            var layer = this.designCompare.Layers.FirstOrDefault(x => x.Name.ToUpper() == Verification.RevCloudLayer.ToUpper());
103
            if (layer != null) layer.Visible = (sender as RadCheckBox).Checked;
104
            this.designCompare.Invalidate();
105
        }
106

    
107
        private void RadCheckBoxAVEVA_CheckStateChanged(object sender, EventArgs e)
108
        {
109
            var layer = this.designCompare.Layers.FirstOrDefault(x => x.Name.ToUpper() == Verification.AVEVALayer.ToUpper());
110
            if (layer != null) layer.Visible = (sender as RadCheckBox).Checked;
111
            this.designCompare.Invalidate();
112
        }
113

    
114
        private void RadCheckBoxAutoCAD_CheckStateChanged(object sender, EventArgs e)
115
        {
116
            var layer = this.designCompare.Layers.FirstOrDefault(x => x.Name.ToUpper() == Verification.AutoCADLayer.ToUpper());
117
            if (layer != null) layer.Visible = (sender as RadCheckBox).Checked;
118
            this.designCompare.Invalidate();
119
        }
120

    
121
        /// <summary>
122
        /// Cloud Mark의 색상을 설정한다.
123
        /// </summary>
124
        /// <param name="sender"></param>
125
        /// <param name="e"></param>
126
        private void RadColorBoxRevCloudColor_ValueChanged(object sender, EventArgs e)
127
        {
128
            Verification.RevCloudColor = this.radColorBoxRevCloudColor.Value;
129
            string color = $"{Verification.RevCloudColor.R},{Verification.RevCloudColor.G},{Verification.RevCloudColor.B}";
130
            Classes.ID2Helper.IniWriteValue(IniFilePath, "Verification", "RevCloudColor", color);
131
        }
132

    
133
        /// <summary>
134
        /// 두 도면을 비교하여 결과를 PDF로 출력한다.
135
        /// </summary>
136
        /// <param name="sender"></param>
137
        /// <param name="e"></param>
138
        public void CompareDrawings(IList<Document> docs, bool Save = false)
139
        {
140
            string FileFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 
141
                Application.ProductName, "Compare");
142
            if (!System.IO.Directory.Exists(FileFolder)) System.IO.Directory.CreateDirectory(FileFolder);
143

    
144
            try
145
            {
146
                Size? size = new Size();
147
                RadFixedDocument FixedDoc = null;
148
                if (Save)
149
                {
150
                    size = new Size(1920 * 2, 1080 * 2);
151
                    FixedDoc = new RadFixedDocument();
152

    
153
                    designCompare.ActiveViewport.Background.BottomColor = Color.White;
154
                    designCompare.ActiveViewport.Background.TopColor = Color.White;
155
                }
156

    
157
                _progressBar.Maximum = docs.Count();
158
                _progressBar.Value1 = 0;
159
                foreach (var doc in docs)
160
                {
161
                    _progressBar.Text = doc.DocumentNo;
162
                    CompareDrawing(doc, Save);
163

    
164
                    if (Save)
165
                    {
166
                        using (var bmp = this.designCompare.RenderToBitmap(size.Value))
167
                        {
168
                            string FilePath = System.IO.Path.Combine(FileFolder, $"{doc.DocumentNo}.jpg");
169
                            bmp.Save(FilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
170

    
171
                            var page = FixedDoc.Pages.AddPage();
172
                            page.Size = new Telerik.Documents.Primitives.Size(size.Value.Width, size.Value.Height);
173
                            var editor = new FixedContentEditor(page);
174
                            using (FileStream fs = new FileStream(FilePath, FileMode.Open))
175
                            {
176
                                editor.DrawImage(fs);
177
                            }
178
                        }
179
                    }
180

    
181
                    _progressBar.Value1 += 1;
182
                    Application.DoEvents();
183
                }
184

    
185
                if (Save)
186
                {
187
                    RadSaveFileDialog saveFileDialog = new RadSaveFileDialog()
188
                    {
189
                        Filter = "PDF files (*.pdf)|*.pdf",
190
                        RestoreDirectory = true
191
                    };
192
                    if (System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog())
193
                    {
194
                        string selectedFileName = saveFileDialog.FileName;
195

    
196
                        // If you are working in a .NET Core application, you will need to also provide an image resolver. You can use the default implementation provided in Telerik.Documents.ImageUtils: 
197
                        Telerik.Documents.ImageUtils.ImagePropertiesResolver defaultImagePropertiesResolver = new Telerik.Documents.ImageUtils.ImagePropertiesResolver();
198
                        Telerik.Windows.Documents.Extensibility.FixedExtensibilityManager.ImagePropertiesResolver = defaultImagePropertiesResolver;
199

    
200
                        var provider = new PdfFormatProvider();
201
                        File.WriteAllBytes(selectedFileName, provider.Export(FixedDoc));
202

    
203
                        RadMessageBox.Show("Comparing document is done");
204
                    }
205
                }
206
            }
207
            catch(Exception ex)
208
            {
209
                RadMessageBox.Show(ex.Message);
210
            }
211
            finally
212
            {
213
                designCompare.ActiveViewport.Background.BottomColor = Color.Black;
214
                designCompare.ActiveViewport.Background.TopColor = Color.Black;
215
            }
216
        }
217

    
218
        /// <summary>
219
        /// 서로 다른 엔터티의 색상을 설정한다.
220
        /// </summary>
221
        /// <param name="sender"></param>
222
        /// <param name="e"></param>
223
        private void RadColorBoxDiffColor_ValueChanged(object sender, EventArgs e)
224
        {
225
            Verification.DiffColor = this.radColorBoxDiffColor.Value;
226
            string color = $"{Verification.DiffColor.R},{Verification.DiffColor.G},{Verification.DiffColor.B}";
227
            Classes.ID2Helper.IniWriteValue(IniFilePath, "Verification", "DiffColor", color);
228
        }
229

    
230
        /// <summary>
231
        /// AutoCAD 엔터티의 색상을 설정한다.
232
        /// </summary>
233
        /// <param name="sender"></param>
234
        /// <param name="e"></param>
235
        private void RadColorBoxAutoCADColor_ValueChanged(object sender, EventArgs e)
236
        {
237
            Verification.AutoCADColor = this.radColorBoxAutoCADColor.Value;
238
            string color = $"{Verification.AutoCADColor.R},{Verification.AutoCADColor.G},{Verification.AutoCADColor.B}";
239
            Classes.ID2Helper.IniWriteValue(IniFilePath, "Verification", "AutoCADColor", color);
240
        }
241

    
242
        /// <summary>
243
        /// AVEVA 엔터티의 색상을 설정한다.
244
        /// </summary>
245
        /// <param name="sender"></param>
246
        /// <param name="e"></param>
247
        private void RadColorBoxAVEVAColor_ValueChanged(object sender, EventArgs e)
248
        {
249
            Verification.AVEVAColor = this.radColorBoxAVEVAColor.Value;
250
            string color = $"{Verification.AVEVAColor.R},{Verification.AVEVAColor.G},{Verification.AVEVAColor.B}";
251
            Classes.ID2Helper.IniWriteValue(IniFilePath, "Verification", "AVEVAColor", color);
252
        }
253

    
254
        /// <summary>
255
        /// 수정한 Tolerance를 시스템에 반영한다.
256
        /// </summary>
257
        /// <param name="sender"></param>
258
        /// <param name="e"></param>
259
        private void RadSpinEditorTolerance_ValueChanged(object sender, EventArgs e)
260
        {
261
            double toler = Convert.ToDouble(this.radSpinEditorTolerance.Value);
262
            Classes.ID2Helper.IniWriteValue(IniFilePath, "Verification", "Tolerance", toler.ToString());
263
            Verification.Tolerance = toler;
264
        }
265

    
266
        private void Verification_Load(object sender, EventArgs e)
267
        {
268
            string Toler = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "Tolerance");
269
            if (!string.IsNullOrEmpty(Toler))
270
            {
271
                this.radSpinEditorTolerance.Value = Convert.ToDecimal(Toler);
272
                Verification.Tolerance = Convert.ToDouble(this.radSpinEditorTolerance.Value);
273
            }
274

    
275
            string _AutoCADColor = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "AutoCADColor");
276
            if (!string.IsNullOrEmpty(_AutoCADColor))
277
            {
278
                var tokens = _AutoCADColor.Split(',');
279
                if (tokens.Length == 3)
280
                {
281
                    this.radColorBoxAutoCADColor.Value =
282
                         Color.FromArgb(Convert.ToInt32(tokens[0]), Convert.ToInt32(tokens[1]), Convert.ToInt32(tokens[2]));
283
                }
284
            }
285

    
286
            string _AVEVAColor = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "AVEVAColor");
287
            if (!string.IsNullOrEmpty(_AVEVAColor))
288
            {
289
                var tokens = _AVEVAColor.Split(',');
290
                if (tokens.Length == 3)
291
                {
292
                    this.radColorBoxAVEVAColor.Value =
293
                        Color.FromArgb(Convert.ToInt32(tokens[0]), Convert.ToInt32(tokens[1]), Convert.ToInt32(tokens[2]));
294
                }
295
            }
296

    
297
            string _DiffColor = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "DiffColor");
298
            if (!string.IsNullOrEmpty(_DiffColor))
299
            {
300
                var tokens = _DiffColor.Split(',');
301
                if (tokens.Length == 3)
302
                {
303
                    this.radColorBoxDiffColor.Value =
304
                        Color.FromArgb(Convert.ToInt32(tokens[0]), Convert.ToInt32(tokens[1]), Convert.ToInt32(tokens[2]));
305
                }
306
            }
307

    
308
            string _RevCloudColor = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "RevCloudColor");
309
            if (!string.IsNullOrEmpty(_RevCloudColor))
310
            {
311
                var tokens = _RevCloudColor.Split(',');
312
                if (tokens.Length == 3)
313
                {
314
                    this.radColorBoxRevCloudColor.Value =
315
                        Color.FromArgb(Convert.ToInt32(tokens[0]), Convert.ToInt32(tokens[1]), Convert.ToInt32(tokens[2]));
316
                }
317
            }
318

    
319
            string _LengthToleranceRatio = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "Length Tolerance Ratio");
320
            if (!string.IsNullOrEmpty(_LengthToleranceRatio))
321
            {
322
                LengthToleranceRatio = Convert.ToDouble(_LengthToleranceRatio);
323
            }
324

    
325
            #region Except Layer를 로딩한다.
326
            LoadLayerSettings();
327
            #endregion
328
        }
329

    
330
        /// <summary>
331
        /// 레이어 설정을 읽는다.
332
        /// </summary>
333
        public void LoadLayerSettings()
334
        {
335
            Forms.ExceptLayer.ExceptLayers.Clear();
336
            Forms.ExceptLayer.LineLayers.Clear();
337

    
338
            string _ExceptLayers = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "Except Layers");
339
            if (!string.IsNullOrEmpty(_ExceptLayers))
340
            {
341
                Forms.ExceptLayer.ExceptLayers.AddRange(_ExceptLayers.Split(',').ToList().ConvertAll(x => new Forms.ExceptLayer.Layer(x)));
342

    
343
                string _ExceptLayersVisible = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "Except Layers Visible");
344
                if (!string.IsNullOrEmpty(_ExceptLayersVisible))
345
                {
346
                    var tokens = _ExceptLayersVisible.Split(',').ToList().ConvertAll(x => Convert.ToBoolean(x));
347
                    for (int i = 0; i < Forms.ExceptLayer.ExceptLayers.Count; ++i)
348
                    {
349
                        if (i < tokens.Count)
350
                        {
351
                            Forms.ExceptLayer.ExceptLayers[i].Visible = tokens[i];
352
                        }
353
                    }
354
                }
355
            }
356

    
357
            string _LineLayers = Classes.ID2Helper.IniReadValue(IniFilePath, "Verification", "Line Layers");
358
            if (!string.IsNullOrEmpty(_LineLayers))
359
            {
360
                Forms.ExceptLayer.LineLayers.AddRange(_LineLayers.Split(',').ToList().ConvertAll(x => new Forms.ExceptLayer.Layer(x)));
361
            }
362
        }
363

    
364
        /// <summary>
365
        /// 엔터티들의 색상을 바꾼다.
366
        /// </summary>
367
        /// <param name="design"></param>
368
        /// <param name="list"></param>
369
        public void ColorEntities(Design design, IList<Entity> list, Color color, colorMethodType colorMethod=colorMethodType.byEntity, bool ChangeBlkColor=true)
370
        {
371
            foreach (Entity ent in list)
372
            {
373
                ColorEntity(design, ent, color, colorMethod, ChangeBlkColor);
374
            }
375
        }
376

    
377
        /// <summary>
378
        /// 엔터티의 색상을 변경한다.
379
        /// </summary>
380
        /// <param name="design"></param>
381
        /// <param name="entity"></param>
382
        /// <param name="color"></param>
383
        private void ColorEntity(Design design, Entity entity, Color color, colorMethodType colorMethod = colorMethodType.byEntity, 
384
            bool ChangeBlkColor = true)
385
        {
386
            if (entity is BlockReference blkref)
387
            {
388
                blkref.Color = color;
389
                blkref.ColorMethod = colorMethod;
390

    
391
                if (ChangeBlkColor)
392
                {
393
                    var blk = design.Blocks.FirstOrDefault(x => x.Name == blkref.BlockName);
394
                    if (blk != null)
395
                    {
396
                        ColorEntities(design, blk.Entities, color, colorMethodType.byParent);
397
                        foreach (var attr in blkref.Attributes.Values)
398
                        {
399
                            attr.Color = color;
400
                            attr.ColorMethod = colorMethodType.byParent;
401
                        }
402
                    }
403
                }
404
            }
405
            else
406
            {
407
                entity.Color = color;
408
                entity.ColorMethod = colorMethod;
409
            }
410
        }
411

    
412
        /// <summary>
413
        /// 블럭 참조를 깨어 블럭의 구성 요소들을 리트스트 리턴한다.
414
        /// </summary>
415
        /// <param name="design"></param>
416
        /// <param name="blkref"></param>
417
        /// <param name="LayerName"></param>
418
        /// <param name="color"></param>
419
        /// <returns></returns>
420
        private List<Entity> ExplodeBlockReference(BlockKeyedCollection Blocks, BlockReference blkref, string LayerName, Color color)
421
        {
422
            var res = new List<Entity>();
423

    
424
            var entities = blkref.Explode(Blocks);
425
            entities.ToList().ForEach(y =>
426
            {
427
                if (y is LinearPath lp)
428
                {
429
                    int count = Convert.ToInt32(lp.Vertices.Length);
430
                    for (int i = 0; i < count - 1; ++i)
431
                    {
432
                        var line = new devDept.Eyeshot.Entities.Line(lp.Vertices[i], lp.Vertices[i + 1])
433
                        {
434
                            LayerName = lp.LayerName,
435
                            LineWeight = lp.LineWeight,
436
                            LineTypeMethod = colorMethodType.byEntity,
437
                            Color = lp.Color,
438
                            ColorMethod = colorMethodType.byEntity
439
                        };
440
                        res.Add(line);
441
                    }
442
                }
443
                /// PORT 블럭은 제외
444
                else if(y is BlockReference subblkref && (subblkref.BlockName != "PORT" && !subblkref.BlockName.StartsWith("ARROW")))
445
                {
446
                    res.AddRange(ExplodeBlockReference(Blocks, subblkref, LayerName, color));
447
                }
448
            });
449

    
450
            var attributes = blkref.Attributes;
451
            foreach (var ent in entities.Where(y => y is devDept.Eyeshot.Entities.Attribute attr && !attr.Invisible))
452
            {
453
                var txt = ent as devDept.Eyeshot.Entities.Attribute;
454
                #region 텍스트가 뒤집어지는 것을 방지하기 위해 평면을 교체
455
                txt.Plane = new devDept.Geometry.Plane(txt.Plane.Origin, devDept.Geometry.Vector3D.AxisX, devDept.Geometry.Vector3D.AxisY);
456
                #endregion
457
                txt.LayerName = LayerName;
458
                txt.Color = color;
459
                txt.ColorMethod = colorMethodType.byEntity;
460
                KeyValuePair<string, AttributeReference>? kp = attributes.FirstOrDefault(z => z.Key == txt.TextString);
461
                if (kp.HasValue) txt.TextString = (kp.Value.Value) != null ? kp.Value.Value.Value : string.Empty;
462
            }
463

    
464
            res.AddRange(entities.Where(y =>
465
            {
466
                if (y is devDept.Eyeshot.Entities.Attribute attr && (string.IsNullOrEmpty(attr.TextString) || attr.Invisible)) return false;
467
                if (y is devDept.Eyeshot.Entities.Text text && string.IsNullOrEmpty(text.TextString)) return false;
468
                if (y is BlockReference subblkref && subblkref.BlockName == "PORT") return false;
469
                if (y is LinearPath) return false;
470
                if (y.LayerName.ToUpper() == "AS_PORT") return false;
471
                return true;
472
            }));
473

    
474
            #region 제외 레이어에 속한 항목은 포함하지 않는다.
475
            res.RemoveAll(x =>
476
            {
477
                return Forms.ExceptLayer.ExceptLayers.Exists(y => y.Name.ToUpper() == x.LayerName.ToUpper() && !y.Visible);
478
            });
479
            #endregion
480
            foreach (var ent in res) ent.LayerName = LayerName;
481

    
482
            blkref.Attributes.Clear();
483
            ///blkref.UpdateBoundingBox(new TraversalParams(design));
484

    
485
            return res;
486
        }
487

    
488
        /// <summary>
489
        /// 주어진 도면의 원본과 AVEVA를 비교한다.
490
        /// </summary>
491
        private void CompareDrawing(Document doc, bool ResultOnly = false)
492
        {
493
            /// AutoCAD P&ID 파일을 화면에 표시한다.
494
            void ShowAutoCADFile(string FilePath, Design design, bool clear = true)
495
            {
496
                if (clear) design.Clear();
497
                var AddEntities = new List<Entity>();
498

    
499
                if (System.IO.File.Exists(FilePath))
500
                {
501
                    try
502
                    {
503
                        #region 다른 프로세스에서 파일을 열고 있는 경우 처리
504
                        using (var fs = File.Open(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
505
                        #endregion
506

    
507
                        {
508
                            devDept.Eyeshot.Translators.ReadAutodesk ra = new devDept.Eyeshot.Translators.ReadAutodesk(fs);
509
                            ra.DoWork();
510
                            var min = ra.Min;
511
                            if (!ra.Layers.Contains(Verification.AutoCADLayer)) ra.Layers.Add(Verification.AutoCADLayer, Verification.AutoCADColor);
512
                            foreach (var ent in ra.Entities)
513
                            {
514
                                /// 도면을 원점으로 맞춘다.
515
                                if (min.X != 0 && min.Y != 0) ent.Translate(-min.X, -min.Y);
516

    
517
                                if (ent is BlockReference blkref && !blkref.BlockName.StartsWith("ARROW"))
518
                                {
519
                                    AddEntities.AddRange(ExplodeBlockReference(ra.Blocks, blkref, Verification.AutoCADLayer, Verification.AutoCADColor));
520
                                }
521
                            }
522
                            ra.AddToScene(design);
523
                        }
524
                    }
525
                    catch (Exception ex)
526
                    {
527
                        RadMessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, RadMessageIcon.Error);
528
                        return;
529
                    }
530

    
531
                    #region LinearPath를 Line으로 분할한다.
532
                    design.Entities.ForEach(x =>
533
                    {
534
                        if (x is LinearPath lp)
535
                        {
536
                            int count = Convert.ToInt32(lp.Vertices.Length);
537
                            for (int i = 0; i < count - 1; ++i)
538
                            {
539
                                AddEntities.Add(new devDept.Eyeshot.Entities.Line(lp.Vertices[i], lp.Vertices[i + 1])
540
                                {
541
                                    LayerName = lp.LayerName,
542
                                    LineWeight = lp.LineWeight,
543
                                    LineTypeMethod = colorMethodType.byEntity
544
                                });
545
                            }
546
                        }
547
                    });
548
                    design.Entities.RemoveAll(x => (x is LinearPath));
549
                    #endregion
550

    
551
                    design.Entities.AddRange(AddEntities);
552

    
553
                    #region 브랜치가 생성되는 부분에서 파이프 라인을 분할
554
                    var queue = design.Entities.Where(x => x is Line && 
555
                    Forms.ExceptLayer.LineLayers.Exists(y => y.Name.ToUpper() == x.LayerName.ToUpper())).ToList();
556
                    while (queue.Any())
557
                    {
558
                        var line1 = queue.First() as Line;
559
                        var dir1 = line1.Direction;
560
                        dir1.Normalize();
561
                        queue.Remove(line1);
562
                        for (int i = 0; i < queue.Count; ++i)
563
                        {
564
                            var line2 = queue.ElementAt(i) as Line;
565
                            var dir2 = line2.Direction;
566
                            dir2.Normalize();
567
                            if (devDept.Geometry.Vector3D.AreOrthogonal(dir1, dir2))
568
                            {
569
                                var intersects = line1.IntersectWith(line2);
570
                                if (intersects.Count() == 1)
571
                                {
572
                                    if (line1.StartPoint.DistanceTo(intersects[0]) > 0.1 && line1.EndPoint.DistanceTo(intersects[0]) > 0.1)
573
                                    {
574
                                        var split1 = new devDept.Eyeshot.Entities.Line(line1.StartPoint, intersects[0])
575
                                        {
576
                                            LayerName = line1.LayerName,
577
                                            LineWeight = line1.LineWeight,
578
                                            LineTypeMethod = colorMethodType.byEntity
579
                                        };
580
                                        var split2 = new devDept.Eyeshot.Entities.Line(intersects[0], line1.EndPoint)
581
                                        {
582
                                            LayerName = line1.LayerName,
583
                                            LineWeight = line1.LineWeight,
584
                                            LineTypeMethod = colorMethodType.byEntity
585
                                        };
586
                                        design.Entities.Add(split1);
587
                                        design.Entities.Add(split2);
588
                                        design.Entities.Remove(line1);
589

    
590
                                        queue.Add(split1);
591
                                        queue.Add(split2);
592

    
593
                                        break;
594
                                    }
595

    
596
                                    if (line2.StartPoint.DistanceTo(intersects[0]) > 0.1 && line2.EndPoint.DistanceTo(intersects[0]) > 0.1)
597
                                    {
598
                                        var split1 = new devDept.Eyeshot.Entities.Line(line2.StartPoint, intersects[0])
599
                                        {
600
                                            LayerName = line2.LayerName,
601
                                            LineWeight = line2.LineWeight,
602
                                            LineTypeMethod = colorMethodType.byEntity
603
                                        };
604
                                        var split2 = new devDept.Eyeshot.Entities.Line(intersects[0], line2.EndPoint)
605
                                        {
606
                                            LayerName = line2.LayerName,
607
                                            LineWeight = line2.LineWeight,
608
                                            LineTypeMethod = colorMethodType.byEntity
609
                                        };
610
                                        design.Entities.Add(split1);
611
                                        design.Entities.Add(split2);
612
                                        design.Entities.Remove(line2);
613

    
614
                                        queue.Remove(line2);
615
                                        queue.Add(split1);
616
                                        queue.Add(split2);
617
                                    }
618
                                }
619
                            }
620
                        }
621
                    }
622
                    #endregion
623

    
624
                    #region 레이어 변경
625
                    foreach (var ent in design.Entities)
626
                    {
627
                        ent.Color = Verification.AutoCADColor;
628
                        ent.ColorMethod = colorMethodType.byEntity;
629
                        if (!Forms.ExceptLayer.ExceptLayers.Exists(x => x.Name.ToUpper() == ent.LayerName.ToUpper()))
630
                        {
631
                            ent.LayerName = Verification.AutoCADLayer;
632
                        }
633
                    }
634
                    #endregion
635

    
636
                    #region 블럭이거나 제외 레이어에 속한 항목은 제거
637
                    design.Entities.RemoveAll(x => (x is BlockReference) || Forms.ExceptLayer.ExceptLayers.Exists(y => y.Name.ToUpper() == x.LayerName.ToUpper() && !y.Visible));
638
                    #endregion
639

    
640
                    #region 눈에 보이지 않는 라인은 제거
641
                    design.Entities.RemoveAll(x => x is Line line && line.Length() < 0.001);
642
                    #endregion
643

    
644
                    ColorEntities(design, design.Entities, Verification.AutoCADColor);
645

    
646
                    // Sets the view as Top
647
                    design.SetView(viewType.Top);
648
                    design.ZoomFit();
649
                    design.Invalidate();
650
                }
651
            }
652

    
653
            /// AVEVA P&ID 파일을 화면에 표시한다.
654
            void ShowAVEVAPIDFile(string FilePath, Design design, bool clear = true)
655
            {
656
                if (clear) design.Clear();
657
                if (System.IO.File.Exists(FilePath))
658
                {
659
                    var AddEntities = new List<Entity>();
660

    
661
                    #region 다른 프로세스에서 파일을 열고 있는 경우 처리
662
                    using (var fs = File.Open(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
663
                    #endregion
664
                    {
665
                        devDept.Eyeshot.Translators.ReadAutodesk ra = new devDept.Eyeshot.Translators.ReadAutodesk(fs);
666
                        ra.DoWork();
667

    
668
                        if (!ra.Layers.Contains(Verification.AVEVALayer)) ra.Layers.Add(Verification.AVEVALayer, Verification.AVEVAColor);
669
                        var min = ra.Min;
670
                        foreach (var ent in ra.Entities)
671
                        {
672
                            /// 도면을 원점으로 맞춘다.
673
                            if (min.X != 0 && min.Y != 0) ent.Translate(-min.X, -min.Y);
674

    
675
                            #region 멀티 라인들을 분할하여 추가한다.
676
                            if (ent is Mesh mesh && (mesh.LayerName == "AS_PIPE" || mesh.LayerName == "AS_INST"))
677
                            {
678
                                int count = Convert.ToInt32(mesh.Vertices.Length * 0.5);
679
                                for (int i = 0; i < count - 1; ++i)
680
                                {
681
                                    AddEntities.Add(new devDept.Eyeshot.Entities.Line(mesh.Vertices[i], mesh.Vertices[i + 1])
682
                                    {
683
                                        LayerName = Verification.AVEVALayer,
684
                                        LineWeight = 3.0f,
685
                                        LineTypeMethod = colorMethodType.byEntity,
686
                                        Color = Verification.AVEVAColor,
687
                                        ColorMethod = colorMethodType.byEntity
688
                                    });
689
                                }
690
                            }
691
                            else if (ent is TabulatedSurface tf && (tf.LayerName == "AS_PIPE" || tf.LayerName == "AS_INST"))
692
                            {
693
                                int count = Convert.ToInt32(tf.ControlPoints.Length * 0.5);
694
                                for (int i = 0; i < count - 1; ++i)
695
                                {
696
                                    AddEntities.Add(
697
                                        new devDept.Eyeshot.Entities.Line(
698
                                        new devDept.Geometry.Point3D(tf.ControlPoints[i, 0].X, tf.ControlPoints[i, 0].Y, 0),
699
                                        new devDept.Geometry.Point3D(tf.ControlPoints[i + 1, 0].X, tf.ControlPoints[i + 1, 0].Y, 0))
700
                                        {
701
                                            LayerName = Verification.AVEVALayer,
702
                                            LineWeight = 3.0f,
703
                                            LineTypeMethod = colorMethodType.byEntity,
704
                                            Color = Verification.AVEVAColor,
705
                                            ColorMethod = colorMethodType.byEntity
706
                                        }
707
                                    );
708
                                }
709
                            }
710
                            else if (ent is LinearPath lp)
711
                            {
712
                                int count = Convert.ToInt32(lp.Vertices.Length);
713
                                for (int i = 0; i < count - 1; ++i)
714
                                {
715
                                    AddEntities.Add(new devDept.Eyeshot.Entities.Line(lp.Vertices[i], lp.Vertices[i + 1])
716
                                    {
717
                                        LayerName = Verification.AVEVALayer,
718
                                        LineWeight = lp.LineWeight,
719
                                        Color = Verification.AVEVAColor,
720
                                        LineTypeMethod = colorMethodType.byEntity
721
                                    });
722
                                }
723
                            }
724
                            #endregion
725
                            else if (ent is BlockReference blkref)
726
                            {
727
                                if (blkref.BlockName != "LBRK" && blkref.BlockName != "PSNODE" && blkref.BlockName != "PENODE" &&
728
                                    !blkref.BlockName.StartsWith("ARROW"))
729
                                {
730
                                    AddEntities.AddRange(ExplodeBlockReference(ra.Blocks, blkref, Verification.AVEVALayer, Verification.AVEVAColor));
731
                                }
732
                            }
733

    
734
                            ent.Color = Verification.AVEVAColor;
735
                            ent.ColorMethod = colorMethodType.byEntity;
736
                            if (!Forms.ExceptLayer.ExceptLayers.Exists(x => x.Name.ToUpper() == ent.LayerName.ToUpper()))
737
                            {
738
                                ent.LayerName = Verification.AVEVALayer;
739
                            }
740
                        }
741
                        ra.AddToScene(design);
742
                    }
743

    
744
                    #region 불필요한 블럭들은 제거
745
                    design.Entities.RemoveAll(x => x is BlockReference);
746
                    #endregion
747

    
748
                    #region 블럭을 깸
749
                    design.Entities.Where(x => x.LayerName == Verification.AVEVALayer).ToList().ForEach(x =>
750
                    {
751
                        if(x is BlockReference blkref)
752
                        {
753
                            AddEntities.AddRange(ExplodeBlockReference(design.Blocks, blkref, Verification.AVEVALayer, Verification.AVEVAColor));
754
                        }
755
                    });
756
                    design.Entities.RemoveAll(x =>
757
                    ((x is Mesh || x is TabulatedSurface) && (x.LayerName == Verification.AVEVALayer)) ||
758
                    (x is LinearPath && x.LayerName == Verification.AVEVALayer) || (x is BlockReference) ||
759
                    Forms.ExceptLayer.ExceptLayers.Exists(y => y.Name.ToUpper() == x.LayerName.ToUpper() && !y.Visible));
760
                    design.Entities.AddRange(AddEntities);
761
                    #endregion
762

    
763
                    #region 눈에 보이지 않는 라인은 제거
764
                    design.Entities.RemoveAll(x => x is Line line && line.Length() < 0.001);
765
                    #endregion
766

    
767
                    ColorEntities(design, design.Entities.Where(x => x.LayerName == Verification.AVEVALayer).ToList(), Verification.AVEVAColor);
768

    
769
                    design.SetView(viewType.Top);
770
                    design.ZoomFit();
771
                    design.Invalidate();
772
                }
773
            }
774

    
775
            string dwgExtension = ".dwg";
776
            string ID2DrawingFolder = Program.AutoCADFolder;
777
            string dwgFilePath = System.IO.Path.Combine(ID2DrawingFolder, $"{doc.DocumentNo}{dwgExtension}");
778
            if (!ResultOnly) ShowAutoCADFile(dwgFilePath, this.designAutoCAD);
779
            ShowAutoCADFile(dwgFilePath, this.designCompare);
780

    
781
            string AVEVAPIDFolder = Program.AVEVAPIDFolder;
782
            string AVEVAPIDFilePath = string.Empty;
783
            if (AVEVAPIDFolder != null)
784
            {
785
                AVEVAPIDFilePath = System.IO.Path.Combine(AVEVAPIDFolder, $"{doc.DocumentNo}{dwgExtension}");
786
                if (!ResultOnly) ShowAVEVAPIDFile(AVEVAPIDFilePath, this.designAVEVA);
787
                ShowAVEVAPIDFile(AVEVAPIDFilePath, this.designCompare, false);
788
            }
789

    
790
            if (System.IO.File.Exists(dwgFilePath) && System.IO.File.Exists(AVEVAPIDFilePath))
791
            {
792
                var AutoCADEntities = this.designCompare.Entities.Where(x => x.LayerName == Verification.AutoCADLayer).ToList();
793
                var AVEVAtities = this.designCompare.Entities.Where(x => x.LayerName == Verification.AVEVALayer).ToList();
794
                CompareAndMark(this.designCompare, AutoCADEntities, this.designCompare, AVEVAtities);
795
                this.designCompare.Entities.ForEach(x => 
796
                {
797
                    if (x.LayerName != Verification.AVEVALayer && x.LayerName != Verification.AutoCADLayer &&
798
                    x.LayerName != Verification.RevCloudLayer) x.LayerName = Verification.AutoCADLayer;
799
                });
800
            }
801
        }
802

    
803
        /// <summary>
804
        /// 주어진 두 엔터티 리스트를 비교하여 틀린 엔터티의 색상을 설정한 색상으로 변경한다.
805
        /// </summary>
806
        /// <param name="entList1"></param>
807
        /// <param name="entList2"></param>
808
        private void CompareAndMark(Design design1, IList<Entity> AutoCADEntities, Design design2, IList<Entity> AVEVAEntities)
809
        {
810
            var DiffRegions = new List<devDept.Eyeshot.OrientedBoundingRect>();
811

    
812
            bool[] equalEntitiesInV2 = new bool[AVEVAEntities.Count];
813
            var EqualIndices = new List<int>();
814

    
815
            /// 서로 검사 가능한 타입인지 확인한다.
816
            bool CheckType(Entity ent1, Entity ent2)
817
            {
818
                return ent1.GetType() == ent2.GetType() ||
819
                    (ent1.GetType() == typeof(devDept.Eyeshot.Entities.Text) && ent2.GetType() == typeof(devDept.Eyeshot.Entities.MultilineText)) ||
820
                    (ent1.GetType() == typeof(devDept.Eyeshot.Entities.MultilineText) && ent2.GetType() == typeof(devDept.Eyeshot.Entities.Text)) ||
821
                    (ent1.GetType() == typeof(devDept.Eyeshot.Entities.Line) && ent2.GetType() == typeof(devDept.Eyeshot.Entities.TabulatedSurface)) ||
822
                    (ent1.GetType() == typeof(devDept.Eyeshot.Entities.Attribute) && ent2.GetType() == typeof(devDept.Eyeshot.Entities.Text)) ||
823
                    (ent1.GetType() == typeof(devDept.Eyeshot.Entities.Attribute) && ent2.GetType() == typeof(devDept.Eyeshot.Entities.MultilineText));
824
            }
825

    
826
            try
827
            {
828
                for (int i = 0; i < AutoCADEntities.Count(); i++)
829
                {
830
                    Entity entVp1 = AutoCADEntities[i];
831
                    EqualIndices.Clear();
832

    
833
                    for (int j = 0; j < AVEVAEntities.Count(); j++)
834
                    {
835
                        Entity entVp2 = AVEVAEntities[j];
836

    
837
                        if (entVp2 is BlockReference blkref && (blkref.BlockName == "PSNODE" || blkref.BlockName == "PENODE")) continue;
838
                        if (!equalEntitiesInV2[j] && CheckType(entVp1, entVp2) && 
839
                            CompareIfEqual(design1, entVp1, design2, entVp2))
840
                        {
841
                            EqualIndices.Add(j);
842
                        }
843
                    }
844

    
845
                    #region 임계값 안에 들어오는 항목이 여러개 있을 경우 가장 가까운 항목을 유사 항목으로 선택한다.
846
                    if (EqualIndices.Any())
847
                    {
848
                        var ordered = EqualIndices.ConvertAll(x => AVEVAEntities[x]).OrderBy(x =>
849
                        {
850
                            return x.BoxMin.DistanceTo(entVp1.BoxMin);
851
                        });
852

    
853
                        int idx = AVEVAEntities.ToList().FindIndex(x => x == ordered.First());
854
                        equalEntitiesInV2[idx] = true;
855
                    }
856
                    #endregion
857

    
858
                    if (!EqualIndices.Any())
859
                    {
860
                        ColorEntity(design1, AutoCADEntities[i], Verification.DiffColor, colorMethodType.byEntity, false);
861

    
862
                        #region 틀린 엔터티의 BoundingBox를 구함
863
                        var origin = new devDept.Geometry.Point2D(entVp1.BoxMin.X - 1, entVp1.BoxMin.Y - 1);
864
                        double width = entVp1.BoxMax.X - entVp1.BoxMin.X;
865
                        double height = entVp1.BoxMax.Y - entVp1.BoxMin.Y;
866
                        if (Math.Abs(width) != double.PositiveInfinity && Math.Abs(height) != double.PositiveInfinity)
867
                        {
868
                            var rect = new devDept.Eyeshot.OrientedBoundingRect(origin, width + 2, height + 2);
869
                            DiffRegions.Add(rect);
870
                        }
871
                        #endregion
872
                    }
873
                }
874

    
875
                for (int j = 0; j < AVEVAEntities.Count; j++)
876
                {
877
                    if (!equalEntitiesInV2[j])
878
                    {
879
                        ColorEntity(design2, AVEVAEntities[j], Verification.DiffColor, colorMethodType.byEntity, false);
880

    
881
                        #region 틀린 엔터티의 BoundingBox를 구함 
882
                        var origin = new devDept.Geometry.Point2D(AVEVAEntities[j].BoxMin.X - 1, AVEVAEntities[j].BoxMin.Y - 1);
883
                        double width = AVEVAEntities[j].BoxMax.X - AVEVAEntities[j].BoxMin.X;
884
                        double height = AVEVAEntities[j].BoxMax.Y - AVEVAEntities[j].BoxMin.Y;
885
                        if (Math.Abs(width) != double.PositiveInfinity && Math.Abs(height) != double.PositiveInfinity)
886
                        {
887
                            var rect = new devDept.Eyeshot.OrientedBoundingRect(origin, width + 2, height + 2);
888
                            DiffRegions.Add(rect);
889
                        }
890
                        #endregion
891
                    }
892
                }
893

    
894
                #region 인접한 영역을 하나로 합친다.
895
                var queue = new List<devDept.Eyeshot.OrientedBoundingRect>(DiffRegions);
896
                DiffRegions.Clear();
897
                while (queue.Any())
898
                {
899
                    var first = queue[0];
900
                    var FirstMin = first.GetOrigin();
901
                    var FirstMax = FirstMin + first.GetAxis()[0] * first.Size.X + first.GetAxis()[1] * first.Size.Y;
902

    
903
                    queue.Remove(first);
904
                    bool overlap = false;
905
                    for (int i = 0; i < queue.Count; ++i)
906
                    {
907
                        var second = queue[i];
908
                        overlap = devDept.Eyeshot.OrientedBoundingRect.DoOverlapOrTouch(first, second);
909
                        if (overlap)
910
                        {
911
                            var SecondMin = second.GetOrigin();
912
                            var SecondMax = SecondMin + second.GetAxis()[0] * second.Size.X + second.GetAxis()[1] * second.Size.Y;
913

    
914
                            var min = new devDept.Geometry.Point2D(Math.Min(FirstMin.X, SecondMin.X), Math.Min(FirstMin.Y, SecondMin.Y));
915
                            var max = new devDept.Geometry.Point2D(Math.Max(FirstMax.X, SecondMax.X), Math.Max(FirstMax.Y, SecondMax.Y));
916
                            double width = max.X - min.X;
917
                            double height = max.Y - min.Y;
918

    
919
                            #region 두 영역을 합친다.(작업 완료된 영역도 다시 queue에 넣는다.)
920
                            var rect = new devDept.Eyeshot.OrientedBoundingRect(min, width, height);
921
                            queue.Add(rect);
922
                            queue.AddRange(DiffRegions);
923
                            DiffRegions.Clear();
924
                            queue.Remove(second);
925
                            #endregion
926
                            break;
927
                        }
928
                    }
929

    
930
                    if (!overlap) DiffRegions.Add(first);
931
                }
932
                #endregion
933

    
934
                if (!design2.Layers.Contains(Verification.RevCloudLayer))
935
                    design2.Layers.Add(Verification.RevCloudLayer.ToUpper(), Verification.RevCloudColor);
936
                DiffRegions.ForEach(x => DrawRevCloud(design2, x));
937
            }
938
            catch(Exception ex)
939
            {
940
                Console.Write($"Error : {ex.Message}");
941
            }
942
        }
943

    
944
        /// <summary>
945
        /// Revision mark를 그린다.
946
        /// </summary>
947
        /// <param name="design"></param>
948
        /// <param name="obr"></param>
949
        private void DrawRevCloud(Design design, devDept.Eyeshot.OrientedBoundingRect obr)
950
        {
951
            IList<IGCurve> DrawRevCloudLine(devDept.Geometry.Point2D start, devDept.Geometry.Point2D end)
952
            {
953
                var res = new List<IGCurve>();
954

    
955
                var AxisX = new devDept.Geometry.Vector3D(end.X - start.X, end.Y - start.Y);
956
                AxisX.Normalize();
957
                var AxisY = devDept.Geometry.Vector3D.Cross(devDept.Geometry.Vector3D.AxisZ, AxisX);
958

    
959
                double step = 10;
960
                double dist = start.DistanceTo(end);
961
                int count = Convert.ToInt32(dist / step);
962
                if (count == 0 && dist > 0)
963
                {
964
                    var tmp = (start + end) * 0.5;
965

    
966
                    var center = new devDept.Geometry.Point3D(tmp.X, tmp.Y, 0);
967
                    var plane = new devDept.Geometry.Plane(center, AxisX, AxisY);
968
                    GArc arc = new GArc(plane, center, start.DistanceTo(end) * 0.5, Math.PI, Math.PI * 2);
969
                    res.Add(arc);
970
                }
971
                else
972
                {
973
                    for (int i = 0; i < count; ++i)
974
                    {
975
                        var _start = (start + AxisX * i * step);
976
                        var _end = (start + AxisX * (i + 1) * step);
977
                        if (i == count - 1) _end = end;
978
                        var tmp = (_start + _end) * 0.5;
979

    
980
                        var center = new devDept.Geometry.Point3D(tmp.X, tmp.Y, 0);
981
                        var plane = new devDept.Geometry.Plane(center, AxisX, AxisY);
982
                        GArc arc = new GArc(plane, center, _start.DistanceTo(_end) * 0.5, Math.PI, Math.PI * 2);
983
                        res.Add(arc);
984
                    }
985
                }
986

    
987
                return res;
988
            }
989

    
990
            GCompositeCurve profile = new GCompositeCurve();
991

    
992
            var vertices = obr.GetVertices();
993
            for(int i = 0;i < vertices.Length;++i)
994
            {
995
                var curves = DrawRevCloudLine(vertices[i], vertices[(i + 1) % vertices.Length]);
996
                profile.CurveList.AddRange(curves);
997
            }
998

    
999
            var revcloud = new devDept.Eyeshot.Entities.CompositeCurve(profile);
1000
            revcloud.LayerName = Verification.RevCloudLayer;
1001
            revcloud.Color = Verification.RevCloudColor;
1002
            revcloud.ColorMethod = colorMethodType.byEntity;
1003
            revcloud.LineWeight = 3;
1004
            revcloud.LineWeightMethod = colorMethodType.byEntity;
1005
            design.Entities.Add(revcloud);
1006
        }
1007

    
1008
        /// <summary>
1009
        /// 주어진 두 엔터티를 비교한다.
1010
        /// </summary>
1011
        /// <param name="entVp1"></param>
1012
        /// <param name="entVp2"></param>
1013
        /// <returns></returns>
1014
        private bool CompareIfEqual(Design design1, Entity entVp1, Design design2, Entity entVp2)
1015
        {
1016
            return AreEqual(design1, entVp1, design2, entVp2);
1017
        }
1018

    
1019
        private bool CompareGEntityIfEqual(GEntity entVp1, GEntity entVp2)
1020
        {
1021
            return AreGEntityEqual(entVp1, entVp2);
1022
        }
1023

    
1024
        /// <summary>
1025
        /// 그래픽적으로 두 엔터티가 유사한지 검사한다.
1026
        /// </summary>
1027
        /// <param name="design1"></param>
1028
        /// <param name="ent1"></param>
1029
        /// <param name="design2"></param>
1030
        /// <param name="ent2"></param>
1031
        /// <returns></returns>
1032
        private bool AreEqual(Design design1, Entity ent1, Design design2, Entity ent2)
1033
        {
1034
            if (ent1 is CompositeCurve cc1 && ent2 is CompositeCurve cc2)
1035
            {
1036
                if (cc1.CurveList.Count == cc2.CurveList.Count)
1037
                {
1038
                    int equalCurvesInListCount = 0;
1039
                    foreach (var entC in cc1.CurveList)
1040
                    {
1041
                        foreach (var entC2 in cc2.CurveList)
1042
                        {
1043
                            if (entC.GetType() == entC2.GetType())
1044
                            {
1045
                                if (entC is Entity && entC2 is Entity && CompareIfEqual(design1, entC as Entity, design2, entC2 as Entity))
1046
                                {
1047
                                    equalCurvesInListCount++;
1048
                                    break;
1049
                                }
1050
                                else if (entC is GEntity && entC2 is GEntity && CompareGEntityIfEqual(entC as GEntity, entC2 as GEntity))
1051
                                {
1052
                                    equalCurvesInListCount++;
1053
                                    break;
1054
                                }
1055
                            }
1056
                        }
1057
                    }
1058

    
1059
                    if (cc1.CurveList.Count == equalCurvesInListCount)
1060
                    {
1061
                        return true;
1062
                    }
1063
                }
1064
            }
1065
            else if (ent1 is LinearPath lp1 && ent2 is LinearPath lp2)
1066
            {
1067
                if (lp1.Vertices.Length == lp2.Vertices.Length)
1068
                {
1069
                    for (int i = 0; i < lp1.Vertices.Length; i++)
1070
                    {
1071
                        if (lp1.Vertices[i].DistanceTo(lp2.Vertices[i]) > Verification.Tolerance)
1072
                            return false;
1073
                    }
1074

    
1075
                    return true;
1076
                }
1077
            }
1078
            else if (ent1 is PlanarEntity && ent2 is PlanarEntity)
1079
            {
1080
                if (ent1 is Arc arc1 && ent2 is Arc arc2)
1081
                {
1082
                    if (
1083
                        arc1.Center.DistanceTo(arc2.Center) <= Verification.Tolerance &&
1084
                        Math.Abs(arc1.Radius - arc2.Radius) <= Verification.Tolerance &&
1085
                        Math.Abs(arc1.Domain.Min - arc2.Domain.Min) <= Verification.Tolerance &&
1086
                        Math.Abs(arc1.Domain.Max - arc2.Domain.Max) <= Verification.Tolerance
1087
                        )
1088
                    {
1089
                        return true;
1090
                    }
1091
                }
1092
                else if (ent1 is Circle c1 && ent2 is Circle c2)
1093
                {
1094
                    if (
1095
                        c1.Center.DistanceTo(c2.Center) <= Verification.Tolerance &&
1096
                        Math.Abs(c1.Radius - c2.Radius) <= Verification.Tolerance
1097
                        )
1098
                    {
1099
                        return true;
1100
                    }
1101
                }
1102
                else if (ent1 is EllipticalArc e1 && ent2 is EllipticalArc e2)
1103
                {
1104
                    if (
1105
                        e1.Center.DistanceTo(e2.Center) <= Verification.Tolerance &&
1106
                        Math.Abs(e1.RadiusX - e2.RadiusX) <= Verification.Tolerance &&
1107
                        Math.Abs(e1.RadiusY - e2.RadiusY) <= Verification.Tolerance &&
1108
                        Math.Abs(e1.Domain.Low - e2.Domain.Low) <= Verification.Tolerance &&
1109
                        Math.Abs(e1.Domain.High - e2.Domain.High) <= Verification.Tolerance
1110
                    )
1111
                    {
1112
                        return true;
1113
                    }
1114
                }
1115
                else if (ent1 is Ellipse el1 && ent2 is Ellipse el2)
1116
                {
1117
                    if (
1118
                        el1.Center.DistanceTo(el2.Center) <= Verification.Tolerance &&
1119
                        Math.Abs(el1.RadiusX - el2.RadiusX) <= Verification.Tolerance &&
1120
                        Math.Abs(el1.RadiusY - el2.RadiusY) <= Verification.Tolerance
1121
                    )
1122
                    {
1123
                        return true;
1124
                    }
1125
                }
1126
                #region 해치는 중점만 비교
1127
                else if (ent1 is Hatch hatch1 && ent2 is Hatch hatch2)
1128
                {
1129
                    var center1 = (hatch1.BoxMin + hatch1.BoxMax) * 0.5;
1130
                    center1.Z = 0;
1131
                    var center2 = (hatch2.BoxMin + hatch2.BoxMax) * 0.5;
1132
                    center2.Z = 0;
1133
                    return center1.DistanceTo(center2) < Verification.Tolerance;
1134
                }
1135
                #endregion
1136
                else if (ent1 is Text)
1137
                {
1138
                    if (ent1 is Dimension dim1 && ent2 is Dimension dim2)
1139
                    {
1140
                        if (
1141
                            dim1.InsertionPoint.DistanceTo(dim2.InsertionPoint) <= Verification.Tolerance &&
1142
                            dim1.DimLinePosition.DistanceTo(dim2.DimLinePosition) <= Verification.Tolerance
1143
                            )
1144
                        {
1145
                            if (ent1 is AngularDim ad1 && ent2 is AngularDim ad2)
1146
                            {
1147
                                if (
1148
                                    ad1.ExtLine1.DistanceTo(ad2.ExtLine1) <= Verification.Tolerance &&
1149
                                    ad1.ExtLine2.DistanceTo(ad2.ExtLine2) <= Verification.Tolerance &&
1150
                                    Math.Abs(ad1.StartAngle - ad2.StartAngle) <= Verification.Tolerance &&
1151
                                    Math.Abs(ad1.EndAngle - ad2.EndAngle) <= Verification.Tolerance &&
1152
                                    Math.Abs(ad1.Radius - ad2.Radius) <= Verification.Tolerance
1153
                                    )
1154
                                {
1155
                                    return true;
1156
                                }
1157
                            }
1158
                            else if (ent1 is LinearDim ld1 && ent2 is LinearDim ld2)
1159
                            {
1160
                                if (
1161
                                    ld1.ExtLine1.DistanceTo(ld2.ExtLine1) <= Verification.Tolerance &&
1162
                                    ld1.ExtLine2.DistanceTo(ld2.ExtLine2) <= Verification.Tolerance
1163
                                    )
1164
                                {
1165
                                    return true;
1166
                                }
1167
                            }
1168
                            else if (ent1 is DiametricDim dd1 && ent2 is DiametricDim dd2)
1169
                            {
1170
                                if (
1171
                                    Math.Abs(dd1.Distance - dd2.Distance) <= Verification.Tolerance &&
1172
                                    Math.Abs(dd1.Radius - dd2.Radius) <= Verification.Tolerance &&
1173
                                    Math.Abs(dd1.CenterMarkSize - dd2.CenterMarkSize) <= Verification.Tolerance
1174
                                )
1175
                                {
1176
                                    return true;
1177
                                }
1178
                            }
1179
                            else if (ent1 is RadialDim rd1 && ent2 is RadialDim rd2)
1180
                            {
1181
                                if (
1182
                                    Math.Abs(rd1.Radius - rd2.Radius) <= Verification.Tolerance &&
1183
                                    Math.Abs(rd1.CenterMarkSize - rd2.CenterMarkSize) <= Verification.Tolerance
1184
                                )
1185
                                {
1186
                                    return true;
1187
                                }
1188
                            }
1189
                            else if (ent1 is OrdinateDim od1 && ent2 is OrdinateDim od2)
1190
                            {
1191
                                if (
1192
                                    od1.DefiningPoint.DistanceTo(od2.DefiningPoint) <= Verification.Tolerance &&
1193
                                    od1.Origin.DistanceTo(od2.Origin) <= Verification.Tolerance &&
1194
                                    od1.LeaderEndPoint.DistanceTo(od2.LeaderEndPoint) <= Verification.Tolerance
1195
                                )
1196
                                {
1197
                                    return true;
1198
                                }
1199
                            }
1200
                            else
1201
                            {
1202
                                Console.Write("Type " + ent1.GetType() + " not implemented.");
1203
                                return true;
1204
                            }
1205
                        }
1206
                    }
1207

    
1208
                    else if (ent1 is devDept.Eyeshot.Entities.Attribute att1 && ent2 is devDept.Eyeshot.Entities.Attribute att2)
1209
                    {
1210
                        if (
1211
                            att1.Value == att2.Value &&
1212
                            att1.InsertionPoint.DistanceTo(att2.InsertionPoint) <= Verification.Tolerance
1213
                            )
1214
                        {
1215
                            return true;
1216
                        }
1217
                    }
1218
                    else
1219
                    {
1220
                        Text tx1 = (Text)ent1;
1221
                        Text tx2 = (Text)ent2;
1222

    
1223
                        #region 대소문자, 공백을 무시하여 비교
1224
                        string string1 = tx1.TextString.Trim().ToUpper();
1225
                        string string2 = tx2.TextString.Trim().ToUpper();
1226
                        string1 = System.Text.RegularExpressions.Regex.Replace(string1, @"\s+", "");
1227
                        string2 = System.Text.RegularExpressions.Regex.Replace(string2, @"\s+", "");
1228
                        if (
1229
                            tx1.BoxMin.DistanceTo(tx2.BoxMin) <= Verification.Tolerance &&
1230
                            string1 == string2 &&
1231
                            Math.Abs(tx1.WidthFactor - tx2.WidthFactor) <= Verification.Tolerance &&
1232
                            Math.Abs(tx1.Height - tx2.Height) <= Verification.Tolerance
1233
                            )
1234
                        {
1235
                            return true;
1236
                        }
1237
                        #endregion
1238
                    }
1239
                }
1240
            }
1241
            else if (ent1 is Line line1 && ent2 is Line line2)
1242
            {
1243
                var dir1 = line1.Direction;
1244
                dir1.Normalize();
1245
                var dir2 = line2.Direction;
1246
                dir2.Normalize();
1247
                if (devDept.Geometry.Vector3D.AreParallel(dir1, dir2, 0.1) &&
1248
                    Math.Abs(line1.Length() - line2.Length()) <= line1.Length() * LengthToleranceRatio &&
1249
                    line1.MidPoint.DistanceTo(line2.MidPoint) <= Verification.Tolerance
1250
                )
1251
                {
1252
                    return true;
1253
                }
1254
            }
1255
            else if (ent1 is Line && ent2 is devDept.Eyeshot.Entities.TabulatedSurface lwpolyline && lwpolyline.ControlPoints.Length == 4)
1256
            {
1257
                line1 = ent1 as Line;
1258
                var start = new devDept.Geometry.Point3D(lwpolyline.ControlPoints[0, 0].X, lwpolyline.ControlPoints[0, 0].Y, 0);
1259
                var end = new devDept.Geometry.Point3D(lwpolyline.ControlPoints[1, 0].X, lwpolyline.ControlPoints[1, 0].Y, 0);
1260
                var vec = new devDept.Geometry.Vector3D(start, end);
1261
                vec.Normalize();
1262
                var dir = line1.Direction.Clone() as devDept.Geometry.Vector3D;
1263
                dir.Normalize();
1264

    
1265
                if (
1266
                    devDept.Geometry.Vector3D.AreParallel(dir, vec) &&
1267
                    line1.StartPoint.DistanceTo(start) <= Verification.Tolerance &&
1268
                    line1.EndPoint.DistanceTo(end) <= Verification.Tolerance
1269
                )
1270
                {
1271
                    return true;
1272
                }
1273
            }
1274
            else if (ent1 is devDept.Eyeshot.Entities.Point point1 && ent2 is devDept.Eyeshot.Entities.Point point2)
1275
            {
1276
                if (point1.Position.DistanceTo(point2.Position) <= Verification.Tolerance)
1277
                {
1278
                    return true;
1279
                }
1280
            }
1281
            else if (ent1 is Curve cu1 && ent2 is Curve cu2)
1282
            {
1283
                if (
1284
                    cu1.ControlPoints.Length == cu2.ControlPoints.Length &&
1285
                    cu1.KnotVector.Length == cu2.KnotVector.Length &&
1286
                    cu1.Degree == cu2.Degree
1287
                    )
1288
                {
1289
                    for (int k = 0; k < cu1.ControlPoints.Length; k++)
1290
                    {
1291
                        if (cu1.ControlPoints[k].DistanceTo(cu2.ControlPoints[k]) > Verification.Tolerance)
1292
                        {
1293
                            return false;
1294
                        }
1295
                    }
1296

    
1297
                    for (int k = 0; k < cu1.KnotVector.Length; k++)
1298
                    {
1299
                        if (cu1.KnotVector[k] != cu2.KnotVector[k])
1300
                        {
1301
                            return false;
1302
                        }
1303
                    }
1304

    
1305
                    return true;
1306
                }
1307
            }
1308
            else if (ent1 is Mesh m1 && ent2 is Mesh m2 && m1.Vertices.Count() == m2.Vertices.Count())
1309
            {
1310
                for (int i = 0; i < m1.Vertices.Count(); ++i)
1311
                {
1312
                    if (m1.Vertices[i].DistanceTo(m2.Vertices[i]) > Verification.Tolerance) return false;
1313
                }
1314

    
1315
                return true;
1316
            }
1317
            else if (ent1 is BlockReference blkref1 && ent2 is BlockReference blkref2)
1318
            {
1319
                int equalCurvesInEntityList = 0;
1320

    
1321
                #region Point, Attribute, Text 제거 및 LinePath를 라인으로 분리
1322
                var entities1 = blkref1.Explode(design1.Blocks).Where(x => x.LayerName != "AS_PORT" && !(x is devDept.Eyeshot.Entities.Point) &&
1323
                !(x is devDept.Eyeshot.Entities.Attribute) && !(x is devDept.Eyeshot.Entities.Text)).ToList();
1324
                var coll1 = new List<Entity>();
1325
                entities1.ForEach(x =>
1326
                {
1327
                    if (x is LinearPath lp)
1328
                    {
1329
                        for (int i = 0; i < lp.Vertices.Length - 1; ++i)
1330
                        {
1331
                            if (lp.Vertices[i].DistanceTo(lp.Vertices[i + 1]) < 0.1) continue;
1332
                            coll1.Add(new Line(lp.Vertices[i], lp.Vertices[i + 1]));
1333
                        }
1334
                    }
1335
                    else
1336
                    {
1337
                        coll1.Add(x);
1338
                    }
1339
                });
1340
                #endregion
1341

    
1342
                #region Point 및 Nesting Block 제거 및 LinePath를 라인으로 분리
1343
                var entities2 = blkref2.Explode(design2.Blocks).Where(x => 
1344
                !(x is devDept.Eyeshot.Entities.BlockReference blkref && blkref.BlockName == "PORT") && !(x is devDept.Eyeshot.Entities.Point)).ToList();
1345
                var coll2 = new List<Entity>();
1346
                entities2.ForEach(x =>
1347
                {
1348
                    if (x is LinearPath lp)
1349
                    {
1350
                        for (int i = 0; i < lp.Vertices.Length - 1; ++i)
1351
                        {
1352
                            if (lp.Vertices[i].DistanceTo(lp.Vertices[i + 1]) < 0.1) continue;
1353
                            coll2.Add(new Line(lp.Vertices[i], lp.Vertices[i + 1]));
1354
                        }
1355
                    }
1356
                    else if (x is devDept.Eyeshot.Entities.Attribute attr)
1357
                    {
1358
                        if (!attr.Invisible) coll2.Add(attr);
1359
                    }
1360
                    else if (x.GetType().Name == "AttributeReferenceData")
1361
                    {
1362
                    }
1363
                    else
1364
                    {
1365
                        coll2.Add(x);
1366
                    }
1367
                });
1368
                #endregion
1369

    
1370
                if (coll1.Count != coll2.Count) return false;
1371

    
1372
                foreach (var entC in coll1)
1373
                {
1374
                    foreach (var entC2 in coll2)
1375
                    {
1376
                        if (entC.GetType() == entC2.GetType())
1377
                        {
1378
                            if (entC is Entity && entC2 is Entity && CompareIfEqual(design1, entC as Entity, design2, entC2 as Entity))
1379
                            {
1380
                                equalCurvesInEntityList++;
1381
                                break;
1382
                            }
1383
                        }
1384
                    }
1385
                }
1386

    
1387
                if (coll1.Count == equalCurvesInEntityList)
1388
                {
1389
                    return true;
1390
                }
1391
            }
1392
            else
1393
            {
1394
                Console.Write("Type " + ent1.GetType() + " not implemented.");
1395
                return false;
1396
            }
1397

    
1398
            return false;
1399
        }
1400

    
1401
        private bool AreGEntityEqual(GEntity ent1, GEntity ent2)
1402
        {
1403
            if (ent1 is GCompositeCurve cc1 && ent2 is GCompositeCurve cc2)
1404
            {
1405
                if (cc1.CurveList.Count == cc2.CurveList.Count)
1406
                {
1407
                    int equalCurvesInListCount = 0;
1408
                    foreach (var entC in cc1.CurveList)
1409
                    {
1410
                        foreach (var entC2 in cc2.CurveList)
1411
                        {
1412
                            if (entC.GetType() == entC2.GetType())
1413
                            {
1414
                                if (entC is GEntity && entC2 is GEntity && CompareGEntityIfEqual(entC as GEntity, entC2 as GEntity))
1415
                                {
1416
                                    equalCurvesInListCount++;
1417
                                    break;
1418
                                }
1419
                            }
1420
                        }
1421
                    }
1422

    
1423
                    if (cc1.CurveList.Count == equalCurvesInListCount)
1424
                    {
1425
                        return true;
1426
                    }
1427
                }
1428
            }
1429
            else if (ent1 is GLinearPath lp1 && ent2 is GLinearPath lp2)
1430
            {
1431
                if (lp1.Vertices.Length == lp2.Vertices.Length)
1432
                {
1433
                    for (int i = 0; i < lp1.Vertices.Length; i++)
1434
                    {
1435
                        if (lp1.Vertices[i].DistanceTo(lp2.Vertices[i]) > Verification.Tolerance)
1436
                            return false;
1437
                    }
1438
                    return true;
1439
                }
1440
            }
1441

    
1442
            else if (ent1 is GPlanarEntity pe1 && ent2 is GPlanarEntity pe2)
1443
            {
1444
                if (
1445
                    pe1.Plane.AxisZ == pe2.Plane.AxisZ &&
1446
                    pe1.Plane.AxisX == pe2.Plane.AxisX
1447
                    )
1448
                {
1449
                    if (ent1 is GArc arc1 && ent2 is GArc arc2)
1450
                    {
1451
                        if (
1452
                            arc1.Center.DistanceTo(arc2.Center) <= Verification.Tolerance &&
1453
                            Math.Abs(arc1.Radius - arc2.Radius) <= Verification.Tolerance &&
1454
                            Math.Abs(arc1.Domain.Min - arc2.Domain.Min) <= Verification.Tolerance &&
1455
                            Math.Abs(arc1.Domain.Max - arc2.Domain.Max) <= Verification.Tolerance
1456
                            )
1457
                        {
1458
                            return true;
1459
                        }
1460
                    }
1461
                    else if (ent1 is GCircle c1 && ent2 is GCircle c2)
1462
                    {
1463
                        if (c1.Center.DistanceTo(c2.Center) <= Verification.Tolerance && 
1464
                            Math.Abs(c1.Radius - c2.Radius) <= Verification.Tolerance)
1465
                        {
1466
                            return true;
1467
                        }
1468
                    }
1469
                    else if (ent1 is GEllipticalArc e1 && ent2 is GEllipticalArc e2)
1470
                    {
1471
                        if (
1472
                            e1.Center.DistanceTo(e2.Center) <= Verification.Tolerance &&
1473
                            Math.Abs(e1.RadiusX - e2.RadiusX) <= Verification.Tolerance &&
1474
                            Math.Abs(e1.RadiusY - e2.RadiusY) <= Verification.Tolerance &&
1475
                            Math.Abs(e1.Domain.Low - e2.Domain.Low) <= Verification.Tolerance &&
1476
                            Math.Abs(e1.Domain.High - e2.Domain.High) <= Verification.Tolerance
1477
                        )
1478
                        {
1479
                            return true;
1480
                        }
1481
                    }
1482
                    else if (ent1 is GEllipse el1 && ent2 is GEllipse el2)
1483
                    {
1484
                        if (
1485
                            el1.Center.DistanceTo(el2.Center) <= Verification.Tolerance &&
1486
                            Math.Abs(el1.RadiusX - el2.RadiusX) <= Verification.Tolerance &&
1487
                            Math.Abs(el1.RadiusY - el2.RadiusY) <= Verification.Tolerance
1488
                        )
1489
                        {
1490
                            return true;
1491
                        }
1492
                    }
1493
                    else
1494
                    {
1495
                        Console.Write("Type " + ent1.GetType() + " not implemented.");
1496
                        return true;
1497
                    }
1498
                }
1499
            }
1500

    
1501
            else if (ent1 is GLine line1 && ent2 is GLine line2)
1502
            {
1503
                if (line1.StartPoint.DistanceTo(line2.StartPoint) <= Verification.Tolerance && 
1504
                    line1.EndPoint.DistanceTo(line2.EndPoint) <= Verification.Tolerance
1505
                )
1506
                {
1507
                    return true;
1508
                }
1509
            }
1510
#if NURBS
1511
            else if (ent1 is Curve)
1512
            {
1513
                Curve cu1 = (Curve)ent1;
1514
                Curve cu2 = (Curve)ent2;
1515

    
1516
                if (
1517
                    cu1.ControlPoints.Length == cu2.ControlPoints.Length &&
1518
                    cu1.KnotVector.Length == cu2.KnotVector.Length &&
1519
                    cu1.Degree == cu2.Degree
1520
                    )
1521
                {
1522
                    for (int k = 0; k < cu1.ControlPoints.Length; k++)
1523
                    {
1524
                        if (cu1.ControlPoints[k] != cu2.ControlPoints[k])
1525
                        {
1526
                            return false;
1527
                        }
1528
                    }
1529

    
1530
                    for (int k = 0; k < cu1.KnotVector.Length; k++)
1531
                    {
1532
                        if (cu1.KnotVector[k] != cu2.KnotVector[k])
1533
                        {
1534
                            return false;
1535
                        }
1536
                    }
1537

    
1538
                    return true;
1539
                }
1540
            }
1541
#endif
1542

    
1543
            else
1544
            {
1545
                Console.Write("Type " + ent1.GetType() + " not implemented.");
1546
                return true;
1547
            }
1548
            return false;
1549
        }
1550

    
1551
        #region Camera Sync
1552
        private void CameraChanged(object sender, devDept.Eyeshot.Workspace.CameraMoveEventArgs e)
1553
        {
1554
            if (sender == this.designAutoCAD)
1555
            {
1556
                SyncCamera(this.designAutoCAD, this.designAVEVA);
1557
                SyncCamera(this.designAutoCAD, this.designCompare);
1558
            }
1559
            else if (sender == this.designAVEVA)
1560
            {
1561
                SyncCamera(this.designAVEVA, this.designAutoCAD);
1562
                SyncCamera(this.designAVEVA, this.designCompare);
1563
            }
1564
            else
1565
            {
1566
                SyncCamera(this.designCompare, this.designAutoCAD);
1567
                SyncCamera(this.designCompare, this.designAVEVA);
1568
            }
1569
        }
1570

    
1571
        private void SyncCamera(Design designMovedCamera, Design designCameraToMove)
1572
        {
1573
            Camera savedCamera;
1574
            designMovedCamera.SaveView(out savedCamera);
1575

    
1576
            // restores the camera to the other model
1577
            designCameraToMove.RestoreView(savedCamera);
1578
            designCameraToMove.AdjustNearAndFarPlanes();
1579
            designCameraToMove.Invalidate();
1580
        }
1581
        #endregion
1582
    }
1583
}
클립보드 이미지 추가 (최대 크기: 500 MB)