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

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

-Mandatory Connector now indicated by the red border
-Textbox added for custom description
-Major Style changes
-Icon updated
-WorkSpace Scrolling now Possible

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