绘制直线和直线剪切
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; } } } } }
相关文章推荐
- 在vc2010内使用GDI绘制直线
- Android编程之canvas绘制各种图形(点,直线,弧,圆,椭圆,文字,矩形,多边形,曲线,圆角矩形)
- Canvas 绘制直线
- 使用html5 Canvas绘制线条(直线、折线等)
- 直线绘制算法源代码
- 再学 GDI+[2]: DrawLine - 绘制直线
- 在MFC下绘制直线,使用橡皮筋技术,可以使直线效果跟随鼠标移
- IOS绘制圆,直线,弧线,矩形,扇形,三角形,贝塞尔等图形
- 绘制带箭头的直线
- iOS 图形绘制<一> 利用Quartz2D绘制直线
- Andriod在摄像头预览的场景下,动态绘制直线
- TWaver3D直线、曲线、曲面的绘制
- 使用CPen类绘制指定直线
- html5 canvsast元素绘制直线
- 【Unity Shader学习笔记】(三)绘制点、直线、网格等基本图形
- 绘制带箭头的直线
- 怎么用qt4绘制橡皮筋直线
- 【OpenCV3】几何图形(直线、矩形、圆、椭圆、多边形等)绘制
- <canvas>学习笔记——绘制直线的API
- iOS图像处理之绘制直线