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

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

-Completed pathfinding

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