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

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

-added configuration into PluginContainerView (experimental)
-several style changes

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