Free cookie consent management tool by TermsFeed Policy Generator

source: tags/3.3.12/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Diagram elements/Connections/Connection.cs @ 13398

Last change on this file since 13398 was 5485, checked in by mkommend, 13 years ago

Removed warnings from Netron.Diagramming.Core (ticket #1419).

File size: 10.1 KB
Line 
1using System;
2using System.Drawing;
3using System.Drawing.Drawing2D;
4namespace Netron.Diagramming.Core {
5  /// <summary>
6  /// Represents the connection between two connectors
7  /// </summary>
8  public sealed partial class Connection : ConnectionBase {
9
10
11    // ------------------------------------------------------------------
12    /// <summary>
13    /// Implementation of IVersion - the current version of
14    /// Connection.
15    /// </summary>
16    // ------------------------------------------------------------------
17    private const double connectionVersion = 1.0;
18
19    #region Hack for the caps
20    private const float capslength = 0.01F;
21    private const float standardsshift = 7F;
22    private const float arrowshift = 0.1F;
23    /// <summary>
24    /// the ration between the arrow width to the line width
25    /// </summary>
26    private const float capsratio = 5.5F;
27    private const float generalizationration = 2.2F;
28    private float capsshift;
29    private Pen leftPen;
30    private Pen rightPen;
31    private PointF unitvector;
32
33    #endregion
34
35    #region Properties
36
37    // ------------------------------------------------------------------
38    /// <summary>
39    /// Gets the current version.
40    /// </summary>
41    // ------------------------------------------------------------------
42    public override double Version {
43      get {
44        return connectionVersion;
45      }
46    }
47
48    /// <summary>
49    /// Gets the friendly name of the entity to be displayed in the UI
50    /// </summary>
51    /// <value></value>
52    public override string EntityName {
53      get { return "Default Connection"; }
54    }
55    /// <summary>
56    /// The bounds of the paintable entity
57    /// </summary>
58    /// <value></value>
59    public override Rectangle Rectangle {
60      get {
61        if ((From == null) || (To == null)) {
62          return Rectangle.Empty;
63        }
64        return Rectangle.FromLTRB(
65            Math.Min(From.Point.X, To.Point.X),
66            Math.Min(From.Point.Y, To.Point.Y),
67            Math.Max(From.Point.X, To.Point.X),
68            Math.Max(From.Point.Y, To.Point.Y));
69      }
70    }
71
72    #endregion
73
74    #region Constructor
75
76    /// <summary>
77    /// Constructs a connection between the two given points
78    /// </summary>
79    /// <param name="mFrom">the starting point of the connection</param>
80    /// <param name="mTo">the end-point of the connection</param>
81    /// <param name="model">The model.</param>
82    public Connection(Point mFrom, Point mTo, IModel model)
83      : base(model) {
84      this.From = new Connector(mFrom, model);
85      this.From.Name = "From";
86      this.From.Parent = this;
87      this.To = new Connector(mTo, model);
88      this.To.Name = "To";
89      this.To.Parent = this;
90      PenStyle = ArtPalette.GetDefaultPenStyle();
91    }
92
93    /// <summary>
94    /// Initializes a new instance of the <see cref="T:Connection"/> class.
95    /// </summary>
96    /// <param name="from">From.</param>
97    /// <param name="to">To.</param>
98    public Connection(Point from, Point to)
99      : base(from, to) {
100    }
101
102    public Connection()
103      : base(new Point(10, 10), new Point(20, 20)) {
104
105    }
106    #endregion
107
108    #region Methods
109
110    /// <summary>
111    /// Paints the connection on the canvas.
112    /// </summary>
113    /// <param name="g"></param>
114    public override void Paint(Graphics g) {
115      g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
116      base.Paint(g);
117
118      if (Hovered) {
119        g.DrawLine(ArtPalette.HighlightPen, From.Point, To.Point);
120      } else {
121        g.DrawLine(mPenStyle.DrawingPen(), From.Point, To.Point);
122      }
123
124      if (ArtPalette.EnableShadows)
125        g.DrawLine(ArtPalette.ConnectionShadow, From.Point.X + 5, From.Point.Y + 5, To.Point.X + 5, To.Point.Y + 5);
126
127      if (leftPen != null) {
128        g.DrawLine(leftPen, From.Point.X + capsshift * unitvector.X, From.Point.Y + capsshift * unitvector.Y, From.Point.X + (capsshift + capslength) * unitvector.X, From.Point.Y + (capsshift + capslength) * unitvector.Y);
129      }
130      if (rightPen != null) {
131        g.DrawLine(rightPen, To.Point.X - (capsshift + capslength) * unitvector.X, To.Point.Y - (capsshift + capslength) * unitvector.Y, To.Point.X - capsshift * unitvector.X, To.Point.Y - capsshift * unitvector.Y);
132      }
133    }
134    /// <summary>
135    /// Invalidates the connection
136    /// </summary>
137    public override void Invalidate() {
138
139      float x = 0, y = 0;
140      try {
141        if (To == null || From == null) return;
142        double length = Math.Sqrt((To.Point.X - From.Point.X) * (To.Point.X - From.Point.X) + (To.Point.Y - From.Point.Y) * (To.Point.Y - From.Point.Y));
143        x = Convert.ToSingle(Convert.ToDouble(To.Point.X - From.Point.X) / length);
144        y = Convert.ToSingle(Convert.ToDouble(To.Point.Y - From.Point.Y) / length);
145      }
146      catch (OverflowException exc) {
147        throw new InconsistencyException("So, you tried to shrink the connection too much...", exc);
148      }
149      unitvector = new PointF(x, y);
150      /* the old way
151Rectangle f = new Rectangle(From.Point,new Size(10,10));
152Rectangle t = new Rectangle(To.Point,new Size(10,10));
153this.Invalidate(Rectangle.Union(f,t));
154       */
155      base.Invalidate();
156
157    }
158
159    /// <summary>
160    /// Tests if the mouse hits this connection
161    /// </summary>
162    /// <param name="p"></param>
163    /// <returns></returns>
164    public override bool Hit(Point p) {
165      Point p1, p2, s;
166      RectangleF r1, r2;
167      p1 = From.Point; p2 = To.Point;
168
169      // p1 must be the leftmost point.
170      if (p1.X > p2.X) { s = p2; p2 = p1; p1 = s; }
171
172      r1 = new RectangleF(p1.X, p1.Y, 0, 0);
173      r2 = new RectangleF(p2.X, p2.Y, 0, 0);
174      r1.Inflate(3, 3);
175      r2.Inflate(3, 3);
176      if (RectangleF.Union(r1, r2).Contains(p)) {
177        PointF connectionVector = new PointF(p2.X - p1.X, p2.Y - p1.Y);
178        PointF normalVector = new PointF(connectionVector.Y, connectionVector.X * -1);
179        PointF pointVector = new PointF(p.X - p1.X, p.Y - p1.Y);
180
181        double normalVectorLength = Math.Sqrt(normalVector.X * normalVector.X + normalVector.Y * normalVector.Y);
182        double distance = Math.Abs(pointVector.X * normalVector.X + pointVector.Y * normalVector.Y) / normalVectorLength;
183
184        return distance < 5;
185      }
186      return false;
187    }
188
189    /// <summary>
190    /// Moves the connection with the given shift
191    /// </summary>
192    /// <param name="p"></param>
193    public override void MoveBy(Point p) {
194      if (From.AttachedTo != null || To.AttachedTo != null) return;
195
196      Rectangle rec = this.Rectangle;
197      rec.Inflate(20, 20);
198      this.From.MoveBy(p);
199      this.To.MoveBy(p);
200      this.Invalidate();
201      this.Invalidate(rec);
202    }
203    /// <summary>
204    /// Updates pens and brushes.
205    /// <remarks>The .Net API allows you to simply set caps but the visual results are less than satisfactory, to say the least. So, there is
206    /// a hack here (unfortunately) which amounts to use two pen for one connection; one pen for the line and one for the (custom) cap. This is
207    /// the easiest way to have visible arrow which otherwise is miniaturistic. There is also a custom shift of the caps since the location is sometime
208    /// inappropriate; the arrow is drawn with the tip at the end of the connection while the diamond or circle caps are drawn with their center at the connection
209    /// end. So, altogether a lot of tweaking and I really find it regrettable that the out-of-the-box caps are not what they should be (besides some obvious bugs like
210    /// the 'not implemented' one if you try to fill a custom cap...).
211    /// </remarks>
212    /// </summary>
213    protected override void UpdatePaintingMaterial() {
214      base.UpdatePaintingMaterial();
215      #region Hack
216      //see the code comments of the LinePenStyle to understand the problem and this hack
217      if (this.PenStyle is LinePenStyle) {
218
219        LinePenStyle lp = PenStyle as LinePenStyle;
220        if (lp.StartCap == System.Drawing.Drawing2D.LineCap.NoAnchor) {
221          leftPen = null;
222        } else {
223
224
225          if (lp.StartCap == System.Drawing.Drawing2D.LineCap.Custom) {
226            //leftPen.StartCap = System.Drawing.Drawing2D.LineCap.Custom;
227            //AdjustableArrowCap ccap = new AdjustableArrowCap(lp.Width+2, lp.Width+2, true);
228            //leftPen.CustomStartCap = ccap;
229            leftPen = new Pen(lp.Color, lp.Width * generalizationration);
230            leftPen.CustomStartCap = LinePenStyle.GenerallizationCap; //change to something like lp.CustomStartCap if you have more than one custom cap
231            capsshift = standardsshift;
232          } else if (lp.StartCap == LineCap.ArrowAnchor) {
233            leftPen = new Pen(lp.Color, lp.Width * capsratio);
234            leftPen.StartCap = lp.StartCap;
235            capsshift = arrowshift;
236          } else {
237            leftPen = new Pen(lp.Color, lp.Width * capsratio);
238            leftPen.StartCap = lp.StartCap;
239            capsshift = standardsshift;
240          }
241        }
242
243        if (lp.EndCap == System.Drawing.Drawing2D.LineCap.NoAnchor) {
244          rightPen = null;
245        } else {
246
247          if (lp.EndCap == System.Drawing.Drawing2D.LineCap.Custom) {
248            //leftPen.StartCap = System.Drawing.Drawing2D.LineCap.Custom;
249            //AdjustableArrowCap ccap = new AdjustableArrowCap(lp.Width+2, lp.Width+2, true);
250            //leftPen.CustomStartCap = ccap;
251            //rightPen = new Pen(lp.Color, lp.Width * generalizationration);                       
252            //rightPen.CustomEndCap = lp.CustomEndCap;
253            //capsshift = standardsshift;
254            Pen.CustomEndCap = LinePenStyle.GenerallizationCap;
255          } else if (lp.EndCap == LineCap.ArrowAnchor) {
256            rightPen = new Pen(lp.Color, lp.Width * capsratio);
257            rightPen.EndCap = lp.EndCap;
258            capsshift = arrowshift;
259          } else {
260            rightPen = new Pen(lp.Color, lp.Width * capsratio);
261            rightPen.EndCap = lp.EndCap;
262            capsshift = standardsshift;
263          }
264        }
265
266      }
267      #endregion
268    }
269
270
271
272    #endregion
273
274  }
275}
Note: See TracBrowser for help on using the repository browser.