source: trunk/CrypPlugins/WorkspaceManager/View/VisualComponents/CryptoLineView/CryptoLineView.cs @ 1931

Last change on this file since 1931 was 1931, checked in by matkovic, 11 years ago

-changed data structures, should improve the performance

File size: 23.0 KB
Line 
1using System;
2using System.ComponentModel;
3using System.Windows;
4using System.Windows.Media;
5using System.Windows.Input;
6using System.Windows.Controls;
7using System.Windows.Shapes;
8using System.Reflection;
9using System.Windows.Threading;
10using WorkspaceManager.View.Interface;
11using WorkspaceManager.Model;
12using System.Windows.Documents;
13using System.Collections.Generic;
14using System.Threading;
15using WorkspaceManager.View.Container;
16using System.Collections;
17using WorkspaceManager.View.VisualComponents.StackFrameDijkstra;
18
19namespace WorkspaceManager.View.VisualComponents
20{
21        public sealed class CryptoLineView : Shape, IConnection, IUpdateableView
22    {
23        #region Variables
24
25        private IntersectPoint intersectPoint;
26        private List<FromTo> pointList = new List<FromTo>();
27        public HashSet<CryptoLineView> UpdateList = new HashSet<CryptoLineView>();
28
29        private ConnectionModel model;
30        public ConnectionModel Model
31        {
32            get { return model; }
33            private set { model = value; }
34        }
35        private static double offset = 6;
36
37        #endregion
38
39        #region Dependency Properties
40
41        public static readonly DependencyProperty StartPointProperty = DependencyProperty.Register("StartPoint", typeof(Point), typeof(CryptoLineView), new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
42        public static readonly DependencyProperty EndPointProperty = DependencyProperty.Register("EndPoint", typeof(Point), typeof(CryptoLineView), new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
43
44                #endregion
45
46                #region CLR Properties
47
48        public Point StartPoint
49        {
50            get { return (Point)GetValue(StartPointProperty); }
51            set 
52            {
53                SetValue(StartPointProperty, value);
54            }
55        }
56
57        public Point EndPoint
58        {
59            get { return (Point)GetValue(EndPointProperty); }
60            set 
61            {
62                SetValue(EndPointProperty, value);
63            }
64        }
65
66                #endregion
67
68        public CryptoLineView()
69        {
70            Stroke = Brushes.Black;
71            StrokeThickness = 2;
72        }
73
74        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
75        {
76            base.OnPropertyChanged(e);
77            foreach (CryptoLineView line in UpdateList)
78            {
79                line.InvalidateVisual();
80            }
81
82            Panel p = (this.Parent as Panel);
83            if (p == null)
84                return;
85            foreach (UIElement shape in p.Children)
86            {
87                if (shape is CryptoLineView)
88                    shape.InvalidateVisual();
89            }
90        }
91
92        protected override void OnMouseDown(MouseButtonEventArgs args)
93        {
94            if (args.RightButton == MouseButtonState.Pressed)
95            {
96                if (this.model != null && !this.model.WorkspaceModel.WorkspaceManagerEditor.isExecuting())
97                {
98                    this.model.WorkspaceModel.deleteConnectionModel(this.model);
99                }
100            }           
101        }
102
103        public CryptoLineView(ConnectionModel connectionModel) : this()
104        {
105            this.Model = connectionModel;
106            Color color = ColorHelper.GetColor(connectionModel.ConnectionType);
107            Stroke = new SolidColorBrush(color);
108            StrokeThickness = 2;
109        }
110
111                #region Overrides
112
113                protected override Geometry DefiningGeometry
114                {
115                        get
116                        {
117                                StreamGeometry geometry = new StreamGeometry();
118                                geometry.FillRule = FillRule.EvenOdd;
119
120                                using (StreamGeometryContext context = geometry.Open())
121                                {
122                    internalGeometryDraw(context);
123                                }
124
125                                geometry.Freeze();
126                                return geometry;
127                        }
128                }               
129
130                #endregion
131
132                #region Privates
133        private bool isBetween(double min, double max, double between)
134        {
135            return min <= between && between <= max;
136        }
137
138        private bool findIntersection(Point StartPoint, Point EndPoint, Point StartPointSec, Point EndPointSec)
139        {
140            if (StartPoint.X != EndPoint.X &&
141                StartPoint.Y != EndPoint.Y)
142            {
143                return false;
144            }
145            if (StartPointSec.X != EndPointSec.X &&
146                StartPointSec.Y != EndPointSec.Y)
147            {
148                return false;
149            }
150
151            // parallel, also overlapping case
152            if (StartPoint.X == EndPoint.X && StartPointSec.X == EndPointSec.X ||
153                StartPoint.Y == EndPoint.Y && StartPointSec.Y == EndPointSec.Y)
154            {
155                return false;
156            }
157            else
158            {
159                // orthogonal but maybe not intersected
160                Point up, down, left, right;
161                if (StartPoint.X == EndPoint.X)
162                {
163                    up = StartPoint;
164                    down = EndPoint;
165                    left = StartPointSec;
166                    right = EndPointSec;
167                }
168                else
169                {
170                    up = StartPointSec;
171                    down = EndPointSec;
172                    left = StartPoint;
173                    right = EndPoint;
174                }
175
176                if (up.Y < down.Y)
177                {
178                    double swap = up.Y;
179                    up.Y = down.Y;
180                    down.Y = swap;
181                }
182
183                if (left.X > right.X)
184                {
185                    double swap = left.X;
186                    left.X = right.X;
187                    right.X = swap;
188                }
189                 //check if is intersected at all
190                if(isBetween(down.Y, up.Y, left.Y) && isBetween(left.X, right.X, up.X))
191                {
192                    if (up.Y == left.Y ||
193                        down.Y == left.Y ||
194                        left.X == up.X || right.X == up.X)
195                    {
196                        intersectPoint = new IntersectPoint(new Point(up.X, left.Y), IntersectPointMode.InnerIntersect);
197                    }
198                    else
199                    {
200                        intersectPoint = new IntersectPoint(new Point(up.X, left.Y), IntersectPointMode.NormalIntersect);
201                    }
202                    return true;
203                }
204                return false;
205            }
206        }
207
208                private void internalGeometryDraw(StreamGeometryContext context)
209                {
210            makeOrthogonalPoints();
211            foreach (var element in (Parent as Panel).Children)
212            {
213                if (element is CryptoLineView && !element.Equals(this))
214                {
215                    CryptoLineView result = element as CryptoLineView;
216                    foreach (FromTo fromTo in pointList)
217                    {
218                        foreach (FromTo resultFromTo in result.pointList)
219                        {
220                            if (findIntersection(fromTo.From, fromTo.To, resultFromTo.From, resultFromTo.To))
221                            {
222                                fromTo.Intersection.Add(intersectPoint);
223
224                                if (fromTo.DirSort == DirSort.Y_ASC || fromTo.DirSort == DirSort.Y_DESC)
225                                    this.UpdateList.Add(result);
226                            }
227                        }
228                    }
229                }
230            }
231
232            context.BeginFigure(StartPoint, true, false);
233
234            foreach (FromTo fromTo in pointList)
235            {
236                if (fromTo.Intersection.Count > 0)
237                {
238                    foreach (IntersectPoint interPoint in fromTo.Intersection)
239                    {
240                        switch (fromTo.DirSort)
241                        {
242                            case DirSort.X_ASC:
243                                if (interPoint.Mode == IntersectPointMode.NormalIntersect)
244                                {
245                                    context.LineTo(new Point(interPoint.Point.X - offset, interPoint.Point.Y), true, true);
246                                    context.QuadraticBezierTo(new Point(interPoint.Point.X, interPoint.Point.Y - offset), new Point(interPoint.Point.X + offset, interPoint.Point.Y), true, true);
247                                }
248                                else if (interPoint.Mode == IntersectPointMode.InnerIntersect)
249                                {
250                                    context.LineTo(new Point(interPoint.Point.X - 4, interPoint.Point.Y), true, true);
251                                    context.QuadraticBezierTo(new Point(interPoint.Point.X, interPoint.Point.Y - 5), new Point(interPoint.Point.X + 4, interPoint.Point.Y), true, true);
252                                    context.QuadraticBezierTo(new Point(interPoint.Point.X, interPoint.Point.Y + 5), new Point(interPoint.Point.X - 4, interPoint.Point.Y), true, true);
253                                }
254                                break;
255                            case DirSort.X_DESC:
256                                if (interPoint.Mode == IntersectPointMode.NormalIntersect)
257                                {
258                                    context.LineTo(new Point(interPoint.Point.X + offset, interPoint.Point.Y), true, true);
259                                    context.QuadraticBezierTo(new Point(interPoint.Point.X, interPoint.Point.Y - offset), new Point(interPoint.Point.X - offset, interPoint.Point.Y), true, true);
260                                }
261                                else if (interPoint.Mode == IntersectPointMode.InnerIntersect)
262                                {
263                                    context.LineTo(new Point(interPoint.Point.X + 4, interPoint.Point.Y), true, true);
264                                    context.QuadraticBezierTo(new Point(interPoint.Point.X, interPoint.Point.Y - 5), new Point(interPoint.Point.X - 4, interPoint.Point.Y), true, true);
265                                    context.QuadraticBezierTo(new Point(interPoint.Point.X, interPoint.Point.Y + 5), new Point(interPoint.Point.X + 4, interPoint.Point.Y), true, true);
266                                }
267                                break;
268                            //case DirSort.Y_ASC:
269                            //    context.LineTo(new Point(interPoint.X, interPoint.Y - offset), true, true);
270                            //    context.QuadraticBezierTo(new Point(interPoint.X + offset, interPoint.Y), new Point(interPoint.X, interPoint.Y + offset), true, true);
271                            //    break;
272                            //case DirSort.Y_DESC:
273                            //    context.LineTo(new Point(interPoint.X, interPoint.Y + offset), true, true);
274                            //    context.QuadraticBezierTo(new Point(interPoint.X + offset, interPoint.Y), new Point(interPoint.X, interPoint.Y - offset), true, true);
275                            //    break;
276                        }
277                    }
278                    context.LineTo(fromTo.To, true, true);
279                }
280                else
281                {
282                    context.LineTo(fromTo.To, true, true);
283                }
284            }
285        }
286
287
288
289        //private bool isConnectionPossible(Point p1, Point p2, QuadTreeLib.QuadTree<FakeNode> quad)
290        //{
291        //    if (p1.X != p2.X && p1.Y != p2.Y)
292        //        throw new ArgumentException("only 90° allowed");
293
294        //    if (p1.Y != p2.Y)
295        //    {
296        //        Point up = p2.Y < p1.Y ? p2 : p1;
297        //        Point down = p2.Y < p1.Y ? p1 : p2;
298
299        //        Panel parent = (Parent as Panel);
300        //        foreach (var element in parent.Children)
301        //        {
302        //            PluginContainerView plug1 = element as PluginContainerView;
303        //            if (plug1 == null)
304        //                continue;
305        //            Point pos = new Point((plug1.RenderTransform as TranslateTransform).X, (plug1.RenderTransform as TranslateTransform).Y);
306
307        //            if (!isBetween(pos.X, pos.X + plug1.ActualWidth, up.X))
308        //                continue;
309
310        //            // case 1: one point is inside the plugin
311        //            if (isBetween(pos.Y, pos.Y + plug1.ActualHeight, up.Y) ||
312        //                isBetween(pos.Y, pos.Y + plug1.ActualHeight, down.Y))
313        //            {
314        //                return false;
315        //            }
316
317        //            // case 2: goes through
318        //            if (pos.Y > up.Y && pos.Y + plug1.ActualHeight < down.Y)
319        //            {
320        //                return false;
321        //            }
322        //        }
323        //    }
324        //    else
325        //    {
326        //        Point left = p2.X < p1.X ? p2 : p1;
327        //        Point right = p2.X < p1.X ? p1 : p2;
328
329        //        Panel parent = (Parent as Panel);
330        //        foreach (var element in parent.Children)
331        //        {
332        //            PluginContainerView plug1 = element as PluginContainerView;
333        //            if (plug1 == null)
334        //                continue;
335        //            Point pos = new Point((plug1.RenderTransform as TranslateTransform).X, (plug1.RenderTransform as TranslateTransform).Y);
336
337        //            if (!isBetween(pos.Y, pos.Y + plug1.ActualHeight, left.Y))
338        //                continue;
339
340        //            // case 1: one point is inside the plugin
341        //            if (isBetween(pos.X, pos.X + plug1.ActualWidth, left.X) ||
342        //                isBetween(pos.X, pos.X + plug1.ActualWidth, right.X))
343        //            {
344        //                return false;
345        //            }
346
347        //            // case 2: goes through
348        //            if (pos.X > left.X && pos.X + plug1.ActualWidth < right.X)
349        //            {
350        //                return false;
351        //            }
352        //        }
353        //    }
354
355        //    return true;
356        //}
357
358        private bool isConnectionPossible(Point p1, Point p2, QuadTreeLib.QuadTree<FakeNode> quadTree)
359        {
360            if (p1.X != p2.X && p1.Y != p2.Y)
361                throw new ArgumentException("only 90° allowed");
362
363            System.Drawing.RectangleF queryRect;
364            if (p1.Y != p2.Y)
365            {
366                Point up = p2.Y < p1.Y ? p2 : p1;
367                Point down = p2.Y < p1.Y ? p1 : p2;
368
369                queryRect = new System.Drawing.RectangleF((float)up.X, (float)up.Y, 1, (float)(down.Y - up.Y));
370            }
371            else
372            {
373                Point left = p2.X < p1.X ? p2 : p1;
374                Point right = p2.X < p1.X ? p1 : p2;
375
376                queryRect = new System.Drawing.RectangleF((float)left.X, (float)left.Y, (float)(right.X - left.X), 1);
377            }
378
379            return !quadTree.QueryAny(queryRect);
380        }
381
382        private bool performOrthogonalPointConnection(Node n1, Point p2, Node n3, List<Node> nodeList, QuadTreeLib.QuadTree<FakeNode> quadTree)
383        {
384            if (isConnectionPossible(n1.Point, p2, quadTree) && isConnectionPossible(p2, n3.Point, quadTree))
385            {
386                Node n2 = new Node() { Point = p2 };
387                n1.Vertices.Add(n2);
388
389                n2.Vertices.Add(n1);
390                n2.Vertices.Add(n3);
391
392                n3.Vertices.Add(n2);
393
394                nodeList.Add(n2);
395                return true;
396            }
397            return false;
398        }
399
400        private void performOrthogonalPointConnection(Node p1, Node p2, QuadTreeLib.QuadTree<FakeNode> quadTree)
401        {
402            if (isConnectionPossible(p1.Point, p2.Point, quadTree))
403            {
404                p1.Vertices.Add(p2);
405                p2.Vertices.Add(p1);
406            }
407        }
408        internal class FakeNode : QuadTreeLib.IHasRect
409        {
410            public System.Drawing.RectangleF Rectangle { get; set; }
411        }
412        private void makeOrthogonalPoints()
413        {
414            List<Node> nodeList = new List<Node>();
415            Panel parent = (Parent as Panel);
416
417            // add start and end. Index will be 0 and 1
418            Node startNode = new Node() { Point = StartPoint },
419                endNode = new Node() { Point = EndPoint };
420            nodeList.Add(startNode);
421            nodeList.Add(endNode);
422
423            float actualWidth =(float) parent.ActualWidth, actualHeight =(float) parent.ActualWidth;
424            //Consider zoom factor
425            QuadTreeLib.QuadTree<FakeNode> quadTree = new QuadTreeLib.QuadTree<FakeNode>
426                (new System.Drawing.RectangleF(-actualWidth, -actualHeight, actualWidth*5, actualHeight*5));
427
428            //foreach (var element in parent.Children)
429            //{
430            //    if (element is PluginContainerView)
431            //    {
432            //        PluginContainerView p1 = element as PluginContainerView;
433            //        foreach (var routPoint in p1.RoutingPoints)
434            //        {
435            //            nodeList.Add(new Node() { Point = routPoint });
436            //        }
437            //        quadTree.Insert(new FakeNode() { Rectangle = new System.Drawing.RectangleF((float)(p1.RenderTransform as TranslateTransform).X,
438            //                                                                                    (float)(p1.RenderTransform as TranslateTransform).Y,
439            //                                                                                    (float)p1.ActualWidth,
440            //                                                                                    (float)p1.ActualHeight)});
441            //    }
442            //}
443            for (int routPoint = 0; routPoint < 4; ++routPoint)
444            {
445                foreach (var element in parent.Children)
446                {
447                    if (element is PluginContainerView)
448                    {
449                        PluginContainerView p1 = element as PluginContainerView;
450                        nodeList.Add(new Node() { Point = p1.GetRoutingPoint(routPoint) });
451                        if (routPoint == 0)
452                        {
453                            quadTree.Insert(new FakeNode()
454                            {
455                                Rectangle = new System.Drawing.RectangleF((float)(p1.RenderTransform as TranslateTransform).X,
456                                                                           (float)(p1.RenderTransform as TranslateTransform).Y,
457                                                                           (float)p1.ActualWidth,
458                                                                           (float)p1.ActualHeight)
459                            });
460                        }
461                    }
462                }
463            }
464
465            // connect points
466            int loopCount = nodeList.Count;
467            const int performanceTradeoffAt = 10;
468
469            LinkedList<Node> path = null;
470
471            for(int i=0; i<loopCount; ++i)
472            {
473                if (performanceTradeoffAt != 0 &&
474                       i == performanceTradeoffAt)
475                {
476                    StackFrameDijkstra.Dijkstra<Node> dijkstra = new StackFrameDijkstra.Dijkstra<Node>();
477                    path = dijkstra.findPath(nodeList, startNode, endNode);
478                    if (path != null)
479                    {
480                        break;
481                    }
482                }
483
484                var p1 = nodeList[i];
485                // TODO: inner loop restriction! n²-n!
486                // is k=i instead of k=0 correct?
487                for(int k=i; k<loopCount; ++k)
488                {
489                   
490
491                    var p2 = nodeList[k];
492                    if (p1 == p2)
493                        continue;
494                    if (p1.Vertices.Contains(p2))
495                        continue;
496
497                    // no helping point required?
498                    if (p1.Point.X == p2.Point.X ||
499                        p1.Point.Y == p2.Point.Y)
500                    {
501                        performOrthogonalPointConnection(p1, p2, quadTree);
502                    }
503                    else
504                    {
505                        Point help = new Point(p1.Point.X, p2.Point.Y);
506
507                        if (!performOrthogonalPointConnection(p1, help, p2, nodeList, quadTree ))
508                        {
509                            help = new Point(p2.Point.X, p1.Point.Y);
510                            if (!performOrthogonalPointConnection(p1, help, p2, nodeList, quadTree))
511                            {
512                                // optional todo: double edge helping routes
513                            }
514                        }
515                       
516                    }
517                }
518            }
519
520            if (path == null)
521            {
522                StackFrameDijkstra.Dijkstra<Node> dijkstra = new StackFrameDijkstra.Dijkstra<Node>();
523                path = dijkstra.findPath(nodeList, startNode, endNode);
524            }
525
526            if (path != null)
527            {
528                pointList.Clear();
529                Point prevPoint = StartPoint;
530
531                foreach (var i in path)
532                {
533                    Point thisPoint = i.Point;
534                    this.pointList.Add(new FromTo(prevPoint, thisPoint));
535                    prevPoint = thisPoint;
536                }
537            }
538                //Failsafe
539            else if (StartPoint.X < EndPoint.X)
540            {
541                pointList.Clear();
542                pointList.Add(new FromTo(StartPoint, new Point((EndPoint.X + StartPoint.X) / 2, StartPoint.Y)));
543                pointList.Add(new FromTo(new Point((EndPoint.X + StartPoint.X) / 2, StartPoint.Y), new Point((EndPoint.X + StartPoint.X) / 2, EndPoint.Y)));
544                pointList.Add(new FromTo(new Point((EndPoint.X + StartPoint.X) / 2, EndPoint.Y), EndPoint));
545            }
546            else
547            {
548                if (StartPoint.X > EndPoint.X)
549                {
550                    pointList.Clear();
551                    pointList.Add(new FromTo(StartPoint, new Point((StartPoint.X + EndPoint.X) / 2, StartPoint.Y)));
552                    pointList.Add(new FromTo(new Point((StartPoint.X + EndPoint.X) / 2, StartPoint.Y), new Point((StartPoint.X + EndPoint.X) / 2, EndPoint.Y)));
553                    pointList.Add(new FromTo(new Point((StartPoint.X + EndPoint.X) / 2, EndPoint.Y), EndPoint));
554                }
555            }
556        }
557               
558                #endregion
559
560        #region IUpdateableView Members
561
562        public void update()
563        {
564            Stroke = Brushes.Green;
565        }
566
567        #endregion
568
569        internal void Reset()
570        {
571            Color color = ColorHelper.GetColor(Model.ConnectionType);
572            Stroke = new SolidColorBrush(color);
573        }
574    }
575}
Note: See TracBrowser for help on using the repository browser.