using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace AutoDiagramer
{
#region AssociationDrawer CLASS
/// <summary>
/// This class simply draws a single association line between
/// a source <see cref="ucDrawableClass">class</see> and a
/// destination <see cref="ucDrawableClass">class</see>. The line
/// is drawn using the Graphics object of the
/// <see cref="ClassDrawerContainerPanel"> ClassDrawerContainerPanel
/// </see>, where all the classes are contained
/// </summary>
public class AssociationDrawer
{
#region Instance fields
//instance fields
private ucDrawableClass _ucdSrc = null;
private ucDrawableClass _ucdDest = null;
private int _GenericSpace=0;
private Graphics _g = null;
public enum AssociationDirections { North,South,East,West,NorthNonDirect,
SouthNonDirect, EastNonDirect, WestNonDirect,
NorthEast,SouthEast,NorthWest,SouthWest,NOTRECOGNIZED };
private AssociationDirections _CurrAssDirection = AssociationDirections.NOTRECOGNIZED;
private int _RandomLineOffSet = 10;
#endregion
#region Constructor
/// <summary>
/// Creates a new AssociationDrawer object using the parameters provided and
/// then calls the internal Draw() method
/// </summary>
/// <param name="g">The graphics object of the <see cref="ClassDrawerContainerPanel">
/// ClassDrawerContainerPanel</see>, so that this class can draw an association
/// line on the panel where the classes are held</param>
/// <param name="ucdSrc">The source <see cref="ucDrawableClass">class</see></param>
/// <param name="ucdDest">The destination <see cref="ucDrawableClass">class</see></param>
/// <param name="genericSpace">The generic space between classes used by the
/// <see cref="ClassDrawerContainerPanel">ClassDrawerContainerPanel</see>
/// when laying out the controls</param>
public AssociationDrawer(Graphics g,ucDrawableClass ucdSrc,
ucDrawableClass ucdDest,int genericSpace)
{
this._ucdSrc = ucdSrc;
this._ucdDest = ucdDest;
this._GenericSpace = genericSpace;
this._g = g;
//do the draw
GetDirectionAndDraw();
}
#endregion
#region Private Methods
/// <summary>
/// Works out which direction the association line should be based
/// on the source <see cref="ucDrawableClass">class</see> ContainerRow/
/// ContainerColumn and the destination <see cref="ucDrawableClass">class</see>
/// ContainerRow/ ContainerColumn. When the direction is found, one of the Draw
/// direction methods is called, for example DrawNorth(), DrawSouth()
/// </summary>
private void GetDirectionAndDraw()
{
//NORTH = Row is 1 below the current row, but same column
if (_ucdDest.ContainerRow == _ucdSrc.ContainerRow - 1 &&
_ucdDest.ContainerColumn == _ucdSrc.ContainerColumn)
{
DrawNorth();
}
//SOUTH = Row is 1 above the current row, but same column
if (_ucdDest.ContainerRow == _ucdSrc.ContainerRow + 1 &&
_ucdDest.ContainerColumn == _ucdSrc.ContainerColumn)
{
DrawSouth();
}
//EAST = Column is 1 above the current column, but same row
if (_ucdDest.ContainerColumn == _ucdSrc.ContainerColumn + 1 &&
_ucdDest.ContainerRow == _ucdSrc.ContainerRow)
{
DrawEast();
}
//WEST = Column is 1 below the current column, but same row
if (_ucdDest.ContainerColumn == _ucdSrc.ContainerColumn - 1 &&
_ucdDest.ContainerRow == _ucdSrc.ContainerRow)
{
DrawWest();
}
//NORTH-EAST = Row is 1 or more below and the column is 1 or more above
if (_ucdDest.ContainerRow <= _ucdSrc.ContainerRow - 1 &&
_ucdDest.ContainerColumn >= _ucdSrc.ContainerColumn + 1)
{
DrawNorthEast_DrawSouthEast();
}
//SOUTH-EAST = Row is 1 or more above and the column is 1 or more above
if (_ucdDest.ContainerRow >= _ucdSrc.ContainerRow + 1 &&
_ucdDest.ContainerColumn >= _ucdSrc.ContainerColumn + 1)
{
DrawNorthEast_DrawSouthEast();
}
//NORTH-WEST = Row is 1 or more below and the column is 1 or more below
if (_ucdDest.ContainerRow <= _ucdSrc.ContainerRow - 1 &&
_ucdDest.ContainerColumn <= _ucdSrc.ContainerColumn - 1)
{
DrawNorthWest_DrawSouthWest();
}
//SOUTH-WEST = Row is 1 or more above and the column is 1 or more below
if (_ucdDest.ContainerRow >= _ucdSrc.ContainerRow + 1 &&
_ucdDest.ContainerColumn <= _ucdSrc.ContainerColumn - 1)
{
DrawNorthWest_DrawSouthWest();
}
//NORTH-NON-DIRECT = Row is 2 or more below the current row, but same column
if (_ucdDest.ContainerRow <= _ucdSrc.ContainerRow - 2 &&
_ucdDest.ContainerColumn == _ucdSrc.ContainerColumn)
{
DrawNorthNonDirect_DrawSouthNonDirect();
}
//SOUTH-NON-DIRECT = Row is 2 or more above the current row, but same column
if (_ucdDest.ContainerRow >= _ucdSrc.ContainerRow + 2 &&
_ucdDest.ContainerColumn == _ucdSrc.ContainerColumn)
{
DrawNorthNonDirect_DrawSouthNonDirect();
}
//EAST-NON-DIRECT = Column is 2 or more above the current column, but same row
if (_ucdDest.ContainerRow == _ucdSrc.ContainerRow &&
_ucdDest.ContainerColumn >= _ucdSrc.ContainerColumn+2)
{
DrawEastNonDirect_DrawWestNonDirect();
}
//WEST-NON-DIRECT = Column is 2 or more below the current column, but same row
if (_ucdDest.ContainerRow == _ucdSrc.ContainerRow &&
_ucdDest.ContainerColumn <= _ucdSrc.ContainerColumn - 2)
{
DrawEastNonDirect_DrawWestNonDirect();
}
}
/// <summary>
/// Draws a North association line and arrow
/// </summary>
private void DrawNorth()
{
// /\
// |
// |
int xStart = 0;
int xEnd = 0;
if (_ucdDest.Right <= _ucdSrc.Right)
{
xStart = _ucdDest.Right - 20;
xEnd = _ucdDest.Right - 20;
}
else
{
xStart = _ucdSrc.Right - 20;
xEnd = _ucdSrc.Right - 20;
}
int yStart = _ucdSrc.Top;
int yEnd = _ucdDest.Bottom;
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//and drawn the association
_g.DrawLine(p,new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 5, yEnd + 10));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 5, yEnd + 10));
}
/// <summary>
/// Draws a South association line and arrow
/// </summary>
private void DrawSouth()
{
// |
// |
// \/
int xStart = 0;
int xEnd = 0;
if (_ucdDest.Right <= _ucdSrc.Right)
{
xStart = _ucdDest.Right - 20;
xEnd = _ucdDest.Right - 20;
}
else
{
xStart = _ucdSrc.Right - 20;
xEnd = _ucdSrc.Right - 20;
}
int yStart = _ucdSrc.Bottom;
int yEnd = _ucdDest.Top;
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//and drawn the association
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 5, yEnd - 10));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 5, yEnd - 10));
}
/// <summary>
/// Draws a East association line and arrow
/// </summary>
private void DrawEast()
{
// <----
int xStart = _ucdSrc.Right;
int yStart = (int)(_ucdSrc.Top + 20);
int xEnd = _ucdDest.Left;
int yEnd = (int)(_ucdDest.Top + 20);
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//and drawn the association
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd + 5));
}
/// <summary>
/// Draws a West association line and arrow
/// </summary>
private void DrawWest()
{
// ---->
int xStart = _ucdSrc.Left;
int yStart = (int)(_ucdSrc.Top + 20);
int xEnd = _ucdDest.Right;
int yEnd = (int)(_ucdDest.Top + 20);
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//and drawn the association
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 10, yEnd + 5));
}
/// <summary>
/// Draws a NorthEast OR SouthEast association line and arrow
/// </summary>
private void DrawNorthEast_DrawSouthEast()
{
int xStart = _ucdSrc.Right;
int yStart = (int)(_ucdSrc.Top + 40);
int xEnd = _ucdSrc.Right + (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet)));
int yEnd = (int)(_ucdSrc.Top + 40);
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//line across
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//see if we need to draw up and along then up again for NorthEast
// ---->
// |
// |
// ______|
// |
//
// OR see if we need to draw down and along then down again for SouthEast
//
// |______
// |
// |
// ---->
if (_ucdDest.ContainerColumn - _ucdSrc.ContainerColumn > 1)
{
//line up
xStart = xEnd;
yStart = yEnd;
//if its the very first row, make sure line is actually visible
if (_ucdSrc.ContainerRow != 0)
{
yEnd = _ucdSrc.Top - (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet)));
}
else
{
yEnd = _ucdSrc.Top - (_GenericSpace - 10);
}
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
xEnd = _ucdDest.Left - (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet)));
yStart = yEnd;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line up
xStart = xEnd;
yStart = yEnd;
yEnd = _ucdDest.Top + 40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
xEnd = _ucdDest.Left;
yStart = yEnd;
yEnd = _ucdDest.Top + 40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd + 5));
}
//its only 1 column across, so only need to draw up for NorthEast
// ---->
// |
// |
//
// OR down and across for SouthEast
//
// |
// |
// ---->
else
{
//line up
xStart = xEnd;
yStart = yEnd;
yEnd = _ucdDest.Top +40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
xEnd = _ucdDest.Left;
yStart = yEnd;
yEnd = _ucdDest.Top + 40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd + 5));
}
}
/// <summary>
/// Draws a NorthWest OR SouthWest association line and arrow
/// </summary>
private void DrawNorthWest_DrawSouthWest()
{
int xStart = _ucdSrc.Left;
int yStart = _ucdSrc.Top + 40;
int xEnd = _ucdSrc.Left - (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet)));
int yEnd = _ucdSrc.Top + 40;
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//line across
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//see if we need to draw up and along then up again for NorthWest
// <----
// |
// |
// |_____
// |
//
// OR see if we need to draw down and along then down again for SouthWest
//
// _____|
// |
// |
// <----
if (_ucdSrc.ContainerColumn - _ucdDest.ContainerColumn > 1)
{
//line up
xStart = xEnd;
yStart = yEnd;
//if its the very first row, make sure line is actually visible
if (_ucdSrc.ContainerRow != 0)
{
yEnd = _ucdSrc.Top - (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet)));
}
else
{
yEnd = _ucdSrc.Top - (_GenericSpace - 10);
}
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
yStart = yEnd;
xEnd = _ucdDest.Right + (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet))) ;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line up
xStart = xEnd;
yStart = yEnd;
yEnd = _ucdDest.Top + 40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
xEnd = _ucdDest.Right;
yStart = yEnd;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 10, yEnd + 5));
}
//its only 1 column across, so only need to draw up for NorthWest
// <-----
// |
// |
//
// OR down and across for SouthWest
//
// |
// |
// <-----
else
{
//line up
xStart = xEnd;
yStart = yEnd;
yEnd = _ucdDest.Top + 40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
xEnd = _ucdDest.Right;
yStart = yEnd;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 10, yEnd + 5));
}
}
/// <summary>
/// Draws a NorthNonDirect OR SouthNonDirect association line and arrow
/// </summary>
private void DrawNorthNonDirect_DrawSouthNonDirect()
{
int xStart = _ucdSrc.Left;
int yStart = _ucdSrc.Top + 40;
int xEnd = _ucdSrc.Left - (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet)));
int yEnd = _ucdSrc.Top + 40;
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//line across
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line up
xStart = xEnd;
yStart = yEnd;
yEnd = _ucdDest.Top + 40;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
xEnd = _ucdDest.Left;
yStart = yEnd;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd - 5));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 10, yEnd + 5));
}
/// <summary>
/// Draws a EastNonDirect OR WestNonDirect association line and arrow
/// </summary>
private void DrawEastNonDirect_DrawWestNonDirect()
{
int xStart = _ucdSrc.Right - 20;
int yStart = _ucdSrc.Top;
int xEnd = _ucdSrc.Right - 20;
int yEnd = _ucdSrc.Top - (_GenericSpace - (_RandomLineOffSet + Program.GetRandom(_RandomLineOffSet))); ;
//create a dasked line
Pen p = new Pen(new SolidBrush(Color.Black));
p.DashStyle = DashStyle.Dash;
//line up
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line across
xStart = xEnd;
yStart = yEnd;
xEnd = _ucdDest.Right - 20;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//line down
xStart = xEnd;
yStart = yEnd;
yEnd = _ucdDest.Top;
_g.DrawLine(p, new Point(xStart, yStart), new Point(xEnd, yEnd));
//draw the end arrow
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd - 5, yEnd - 10));
_g.DrawLine(p, new Point(xEnd, yEnd), new Point(xEnd + 5, yEnd - 10));
}
#endregion
}
#endregion
}