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

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

-Added Pathfinding (experimental)
-Dijkstra algorithm added

File size: 19.5 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
279        private bool isConnectionPossible(Point p1, Point p2)
280        {
281            if (p1.X != p2.X && p1.Y != p2.Y)
282                throw new ArgumentException("only 90° allowed");
283
284            if (p1.Y != p2.Y)
285            {
286                Point up = p2.Y < p1.Y ? p1 : p2;
287                Point down = p2.Y < p1.Y?p2 : p1;
288
289                Panel parent = (Parent as Panel);
290                foreach (var element in parent.Children)
291                {
292                    PluginContainerView plug1 = element as PluginContainerView;
293                    if (plug1 == null)
294                        continue;
295                    Point pos = new Point((plug1.RenderTransform as TranslateTransform).X, (plug1.RenderTransform as TranslateTransform).Y);
296
297                    if (!isBetween(pos.X, pos.X + plug1.ActualWidth, up.X))
298                        continue;
299
300                    // case 1: one point is inside the plugion
301                    if (isBetween(pos.Y, pos.Y + plug1.ActualHeight, up.Y) ||
302                        isBetween(pos.Y, pos.Y + plug1.ActualHeight, down.Y))
303                    {
304                        return false;
305                    }
306
307                    // case 2: goes through
308                    if (pos.Y > up.Y && pos.Y + plug1.ActualHeight < down.Y)
309                    {
310                        return false;
311                    }
312                }
313            }
314            else
315            {
316                Point left = p2.X < p1.X ? p2 : p1;
317                Point right = p2.X < p1.X ? p1 : p2; 
318
319                Panel parent = (Parent as Panel);
320                foreach (var element in parent.Children)
321                {
322                    PluginContainerView plug1 = element as PluginContainerView;
323                    if (plug1 == null)
324                        continue;
325                    Point pos = new Point((plug1.RenderTransform as TranslateTransform).X, (plug1.RenderTransform as TranslateTransform).Y);
326
327                    if (!isBetween(pos.Y, pos.Y + plug1.ActualHeight, left.Y))
328                        continue;
329
330                    // case 1: one point is inside the plugion
331                    if(isBetween(pos.X, pos.X + plug1.ActualWidth, left.X) ||
332                        isBetween(pos.X, pos.X + plug1.ActualWidth, right.X))
333                    {
334                        return false;
335                    }
336
337                    // case 2: goes through
338                    if(pos.X > left.X && pos.X + plug1.ActualWidth < right.X)
339                    {
340                        return false;
341                    }
342                }
343            }
344
345            return true;
346        }
347
348        internal class Node : StackFrameDijkstra.Node<Node>
349        {
350            public Point Point { get; set; }
351            public HashSet<Node> Vertices { get; private set; }
352            public Node()
353            {
354                Vertices = new HashSet<Node>();
355            }
356
357            public double pathCostEstimate(Node goal)
358            {
359                return 0;
360            }
361
362            public double traverseCost(Node dest)
363            {
364                if (!Vertices.Contains(dest))
365                    return Double.PositiveInfinity;
366
367                if (dest.Point.X == Point.X)
368                    return Math.Abs(dest.Point.Y - Point.Y);
369                return Math.Abs(dest.Point.X - Point.X);
370            }
371
372            public IEnumerable<Node> neighbors()
373            {
374                return Vertices;
375            }
376        }
377
378        private bool performOrthogonalPointConnection(Node n1, Point p2, Node n3, List<Node> nodeList)
379        {
380            if (isConnectionPossible(n1.Point, p2) && isConnectionPossible(p2, n3.Point))
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)
397        {
398            if (isConnectionPossible(p1.Point, p2.Point))
399            {
400                p1.Vertices.Add(p2);
401                p2.Vertices.Add(p1);
402            }
403        }
404
405        private void makeOrthogonalPoints()
406        {
407            List<Node> nodeList = new List<Node>();
408            Panel parent = (Parent as Panel);
409
410            // add start and end. Index will be 0 and 1
411            Node startNode = new Node() { Point = StartPoint },
412                endNode = new Node() { Point = EndPoint };
413            nodeList.Add(startNode);
414            nodeList.Add(endNode);
415
416            foreach (var element in parent.Children)
417            {
418                if (element is PluginContainerView)
419                {
420                    PluginContainerView p1 = element as PluginContainerView;
421                    foreach (var routPoint in p1.RoutingPoints)
422                    {
423                        nodeList.Add(new Node() { Point = routPoint });
424                    }
425                }
426            }
427           
428            // connect points
429            int loopCount = nodeList.Count;
430            for(int i=0; i<loopCount; ++i)
431            {
432                var p1 = nodeList[i];
433                // TODO: inner loop restriction! n²-n!
434                // is k=i instead of k=0 correct?
435                for(int k=0; k<loopCount; ++k)
436                {
437                    var p2 = nodeList[k];
438                    if (p1 == p2)
439                        continue;
440                    if (p1.Vertices.Contains(p2))
441                        continue;
442
443                    // no helping point required?
444                    if (p1.Point.X == p2.Point.X ||
445                        p1.Point.Y == p2.Point.Y)
446                    {
447                        performOrthogonalPointConnection(p1, p2);
448                    }
449                    else
450                    {
451                        Point help1 = new Point(p1.Point.X, p2.Point.Y);
452
453                        if (!performOrthogonalPointConnection(p1, help1, p2, nodeList))
454                        {
455                            Point help2 = new Point(p2.Point.X, p1.Point.Y);
456                            performOrthogonalPointConnection(p1, help2, p2, nodeList);
457                            // optinal TODO: other possible helping points
458                        }
459                       
460                    }
461                }
462            }
463
464            StackFrameDijkstra.Dijkstra<Node> dijkstra = new StackFrameDijkstra.Dijkstra<Node>();
465            var path = dijkstra.findPath(nodeList, startNode, endNode);
466
467            if (path != null)
468            {
469                pointList.Clear();
470                Point prevPoint = StartPoint;
471
472                foreach (var i in path)
473                {
474                    Point thisPoint = i.Point;
475                    this.pointList.Add(new FromTo(prevPoint, thisPoint));
476                    prevPoint = thisPoint;
477                }
478            }
479                //Failsafe
480            else if (StartPoint.X < EndPoint.X)
481            {
482                pointList.Clear();
483                pointList.Add(new FromTo(StartPoint, new Point((EndPoint.X + StartPoint.X) / 2, StartPoint.Y)));
484                pointList.Add(new FromTo(new Point((EndPoint.X + StartPoint.X) / 2, StartPoint.Y), new Point((EndPoint.X + StartPoint.X) / 2, EndPoint.Y)));
485                pointList.Add(new FromTo(new Point((EndPoint.X + StartPoint.X) / 2, EndPoint.Y), EndPoint));
486            }
487            else
488            {
489                if (StartPoint.X > EndPoint.X)
490                {
491                    pointList.Clear();
492                    pointList.Add(new FromTo(StartPoint, new Point((StartPoint.X + EndPoint.X) / 2, StartPoint.Y)));
493                    pointList.Add(new FromTo(new Point((StartPoint.X + EndPoint.X) / 2, StartPoint.Y), new Point((StartPoint.X + EndPoint.X) / 2, EndPoint.Y)));
494                    pointList.Add(new FromTo(new Point((StartPoint.X + EndPoint.X) / 2, EndPoint.Y), EndPoint));
495                }
496            }
497        }
498               
499                #endregion
500
501        #region IUpdateableView Members
502
503        public void update()
504        {
505            Stroke = Brushes.Green;
506        }
507
508        #endregion
509
510        internal void Reset()
511        {
512            Color color = ColorHelper.GetColor(Model.ConnectionType);
513            Stroke = new SolidColorBrush(color);
514        }
515    }
516}
Note: See TracBrowser for help on using the repository browser.