您的位置:首页 > 其它

绘制直线和直线剪切

2013-01-04 13:49 281 查看
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace XnaGeometric
{
public class CLine : IGeometric
{
enum PtDirection
{
//None = 0,
N = 1,//North
E = 2,//East
S = 4,//South
W = 8,//West
NE = N | E,//NorthEast
SE = S | E,//SouthEast
SW = S | W,//SouthWest
NW = N | W,//NorthWest
C = 0,//Center
}

private Color m_color = Color.Green;
private CPoint m_P0;//起始点
private CPoint m_P1;//结束点

public Color Color
{
get { return this.m_color; }
set { this.m_color = value; }
}

public CPoint P0
{
get { return this.m_P0; }
set { this.m_P0 = value; }
}

public CPoint P1
{
get { return this.m_P1; }
set { this.m_P1 = value; }
}

public CLine(CPoint P0, CPoint P1)
{

this.m_P0 = P0;
this.m_P1 = P1;
}

/// <summary>
/// 通过此直线方程计算x坐标
/// //x = (y - y0)*(x1 - x0)/(y1 - y0) + x0
/// </summary>
private void ComputeX(ref float x, float y,
float dx, float dy,
float x0, float y0)
{
x = (y - y0) * dx / dy + x0;
//x = (int)(x + ((float)Math.Sign(x)) * 0.5f);
}
/// <summary>
/// y = (x - x0)*(y1 - y0)/(x1 - x0) + y0
/// </summary>
private void ComputeY(float x, ref float y,
float dx, float dy,
float x0, float y0)
{
y = (x - x0) * dy / dx + y0;
//y = (int)(y + ((float)Math.Sign(y)) * 0.5f);
}

private int Round(float value)
{
return (int)(value + ((float)Math.Sign(value)) * 0.5f);
}

private bool IsAtLR(Rectangle rect, float x) { return x >= rect.Left && x <= rect.Right; }
private bool IsAtTB(Rectangle rect, float y) { return y >= rect.Top && y <= rect.Bottom; }

private bool IsSameDir(PtDirection src, PtDirection dest)
{
return ((PtDirection)(src & dest) == dest);
}

private bool Clip(ref CPoint ptCliped,
PtDirection ptDir,
Rectangle rect,
float x0, float y0,
float x1, float y1,
float dx, float dy)
{
float clipX = ptCliped.X, clipY = ptCliped.Y;
if (IsSameDir(ptDir, PtDirection.N))
{
clipY = rect.Top;
this.ComputeX(ref clipX, clipY, dx, dy, x0, y0);
//NE
if (clipX > rect.Right)
{
clipX = rect.Right;
this.ComputeY(clipX, ref clipY, dx, dy, x0, y0);
if (!IsAtTB(rect, clipY)) return false;
}//NW
else if (clipX < rect.Left)
{
clipX = rect.Left;
this.ComputeY(clipX, ref clipY, dx, dy, x0, y0);
if (!IsAtTB(rect, clipY)) return false;
}
//else { //true}
}
else if (IsSameDir(ptDir, PtDirection.E))
{
clipX = rect.Right;
ComputeY(clipX, ref clipY, dx, dy, x0, y0);
if (clipY < rect.Top)
{
clipY = rect.Y;
this.ComputeX(ref  clipX, clipY, dx, dy, x0, y0);
if (!IsAtLR(rect, clipX)) return false;
}
else if (clipY > rect.Bottom)
{
clipY = rect.Bottom;
this.ComputeX(ref  clipX, clipY, dx, dy, x0, y0);
if (!IsAtLR(rect, clipX)) return false;
}
}
else if (IsSameDir(ptDir, PtDirection.S))
{
clipY = rect.Bottom;
this.ComputeX(ref clipX, clipY, dx, dy, x0, y0);
//NE
if (clipX > rect.Right)
{
clipX = rect.Right;
this.ComputeY(clipX, ref clipY, dx, dy, x0, y0);
if (!IsAtTB(rect, clipY)) return false;
}//NW
else if (clipX < rect.Left)
{
clipX = rect.Left;
this.ComputeY(clipX, ref clipY, dx, dy, x0, y0);
if (!IsAtTB(rect, clipY)) return false;
}
}
else if (IsSameDir(ptDir, PtDirection.W))
{
clipX = rect.Left;
ComputeY(clipX, ref clipY, dx, dy, x0, y0);
if (clipY < rect.Top)
{
clipY = rect.Y;
this.ComputeX(ref  clipX, clipY, dx, dy, x0, y0);
if (!IsAtLR(rect, clipX)) return false;
}
else if (clipY > rect.Bottom)
{
clipY = rect.Bottom;
this.ComputeX(ref  clipX, clipY, dx, dy, x0, y0);
if (!IsAtLR(rect, clipX)) return false;
}
}
ptCliped.X = this.Round(clipX);
ptCliped.Y = this.Round(clipY);
return true;
}

private bool ClipLine(ref CPoint newP0, ref CPoint newP1, Rectangle rect)
{
Point tmpP0 = new Point(newP0.X, newP0.Y);
Point tmpP1 = new Point(newP1.X, newP1.Y);
//两个点在绘制区域里面
bool bContainP0 = rect.Contains(tmpP0);
bool bContainP1 = rect.Contains(tmpP1);
if (bContainP0 && bContainP1)
{
return true;
}
#region Relate
//       *                       *
//  NW   *          N            *  NE
//       *                       *
//***************************************
//       *                       *
//       *                       *
//       *                       *
//   W   *         C             *   E
//       *                       *
//       *                       *
//       *                       *
//***************************************
//       *                       *
//  SW   *          S            *   SE
//       *                       *
#endregion
//获取P0, P1的所在的方位
PtDirection dir0 = PtDirection.C;
PtDirection dir1 = PtDirection.C;
this.GetPtDir(rect, ref dir0, tmpP0);
this.GetPtDir(rect, ref dir1, tmpP1);
float x0 = tmpP0.X, y0 = tmpP0.Y;
float x1 = tmpP1.X, y1 = tmpP1.Y;
float dx = x1 - x0;
float dy = y1 - y0;
bool bP0Clip = Clip(ref newP0, dir0, rect, x0, y0, x1, y1, dx, dy);
bool bP1Clip = Clip(ref newP1, dir1, rect, x0, y0, x1, y1, dx, dy);
return (bP0Clip && bP1Clip);
}
/// <summary>
/// 获取线的形状
/// </summary>
/// <param name="buffer">绘线的缓冲区</param>
/// <param name="rectSrc">源区域(一般是剪切区域)</param>
/// <param name="rectDest">目标区域(一般是屏幕缓冲区域)</param>
public void Get(ref Color[] buffer, Rectangle rectSrc, Rectangle rectDest)
{
CPoint newP0 = P0.Copy();
CPoint newP1 = P1.Copy();
Rectangle rectCliped = AdjustClipRect(rectSrc, rectDest);
if (!ClipLine(ref newP0, ref newP1, rectCliped)) return;
this.GetLine(newP0, newP1, ref buffer, rectDest.Width);
}

/// <summary>
/// 调整剪切区域
/// </summary>
/// <param name="rectSrc">源区域(即剪切区域)</param>
/// <param name="rectDest">目标区域(例如屏幕)</param>
/// <returns>返回调整后的剪切区域</returns>
private Rectangle AdjustClipRect(Rectangle rectSrc, Rectangle rectDest)
{
Rectangle rectCliped = rectSrc;
if (rectCliped.Left < rectDest.Left)
{
rectCliped.X = rectDest.Left;
}
if (rectCliped.Right > rectDest.Right)
{
rectCliped.Width = rectCliped.Right - rectDest.Right + 1;
}
if (rectCliped.Top < rectDest.Top)
{
rectCliped.Y = rectDest.Top;
}
if (rectCliped.Bottom > rectDest.Bottom)
{
rectCliped.Height = rectCliped.Bottom - rectDest.Bottom;
}
return rectCliped;
}

private void GetPtDir(Rectangle rect, ref PtDirection ptDir, Point pt)
{
if (rect.Contains(pt))
{
ptDir = PtDirection.C;
return;
}
else
{
if (pt.Y < rect.Top) { ptDir |= PtDirection.N; }
else if (pt.Y > rect.Bottom) { ptDir |= PtDirection.S;}

if (pt.X < rect.Left) { ptDir |= PtDirection.W; }
else if (pt.X > rect.Right) { ptDir |= PtDirection.E; }
}
}

/// <summary>
/// 没有剪切的版本
/// </summary>
private void GetLine(CPoint P0, CPoint P1,
ref Color[] buffer, int scrWidth)
{
CPoint ptExtra = P1 - P0;
int dx = ptExtra.X, dy = ptExtra.Y;
int yStep = 1, xStep = 1;
if (dx < 0) { dx = -dx; xStep = -1; }
if (dy < 0) { dy = -dy; yStep = -1; }
int dx2 = dx << 1;
int dy2 = dy << 1;

//int yStart = P0.Y, yEnd = P1.Y,
//    xStart = P0.X, xEnd = P1.X;
int xi = 0, yi = 0;
int x = P0.X, y = P0.Y;
//int ix = xStart, iy = yStart;

int index = 0;

if (dx >= dy)
{//0 <= 斜率的绝对值 < 1,以x为增量
int error = -dx;
//if (dy > 0) { yStep = 1; }
//else { yStep = -1; }
//yStep = dy > 0 ? 1 : -1;
for (xi = 0; xi <= dx; xi++)
{
index = x + y * scrWidth;
buffer[index] = this.Color;
error += dy2;
if (error >= 0)
{
y += yStep;
error -= dx2;
}
x += xStep;
}
}
else
{//斜率的绝对值 >= 1,以y为增量
int error = -dy;
for (yi = 0; yi <= dy; yi++)
{
index = x + y * scrWidth;
buffer[index] = this.Color;
error += dx2;
if (error >= 0)
{
x += xStep;
error -= dy2;
}
y += yStep;
}
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: