最近一段时间调研书写带有笔锋的问题,一时间没有思路,然后在网上找啊找啊全是收费的。在网上找思路和源代码发现这块的资料少的可怜,没有办法只好自己研究了。
突然Duang的有种灵感爆发,想到最后两个点链接起来就是一个线段,可以把它均匀的分段然后设置笔宽。按照这种思路走发现可行。然后就拿起笔来画画写写了。。。。。。。
最后的实验效果是这样的(个人感觉看起来还挺不错的):
思路讲解:
1.先假设把两个点距离放大然后设置好固定的长度,设置好后平均分成多条均匀的线段并把每条线段点记录,注,我这块默认长度设置是2.5,设置的长度最好尽可能偏小。
void Splitline(PointF point1, PointF point2, Graphics g)
{
double fz = 2.5;
double lineline = Math.Sqrt(Math.Pow((point2.X - point1.X), 2) + Math.Pow((point2.Y - point1.Y), 2));//获取到线段的长度
if (lineline > fz)
{
//平均分成多少份,然后把每份的点数保存
int num = Convert.ToInt32(lineline / fz);
List<PointF> points = new List<PointF>();
double doublex = (point2.X - point1.X) / num;
double doubley = (point2.Y - point1.Y) / num;
for (int i = 0; i < num; i++)
{
PointF pointF = new PointF(point1.X + (float)(i * doublex), point1.Y + (float)(i * doubley));
points.Add(pointF);
}
Console.WriteLine("总数:"+points.Count);
//依次递减笔宽
float widtline = 7.0f;
float widthlinedj = widtline / points.Count;
for (int i = 0; i < points.Count - 1; i++)
{
widtline = widtline - widthlinedj;
Pen pen = new Pen(Color.Red, widtline);
g.DrawLine(pen, points[i], points[i + 1]);
}
}
}
2.完成以上步骤后运行代码后会发现缓慢书写绘画笔锋出不来,突然拖动一笔会有笔锋,这个是因为move绘画笔记两个点相隔太近了导致笔锋没有出现。所以我们这块的在move方法里设置一个阈值来减少点这样绘画就能出现笔锋。注:鼠标这块我设置是10,触摸点这块设置5,如果设置太大了会导致书写轨迹略微有点偏移,所以阈值尽可能小。
private void BezierPenForm_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Console.WriteLine(e.X+","+e.Y);
double lineline = Math.Sqrt(Math.Pow((e.X - startpoint.X), 2) + Math.Pow((e.Y - startpoint.Y), 2));
if (lineline >= 10)
{
bezierPen.AddPoint(e.X, e.Y);
startpoint = new PointF(e.X, e.Y);
bezierPen.Draw3(this.CreateGraphics());
}
}
}
3.完成以上操作后书写操作就会有笔锋。注:一边绘画和一边出现笔锋这块需要在move的draw3里实现。
public void Draw3(Graphics graphics)
{
if (points.Count < 1) {
return;
}
Pen pen = new Pen(Color.Red,7.0f);
graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; //高像素偏移质量
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
pen.LineJoin = LineJoin.Round;
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
//graphics.DrawLine(pen, points[points.Count-2].x, points[points.Count-2].y, points[points.Count-1].x, points[points.Count - 1].y);
if (points.Count >= 3)
{
graphics.DrawLine(pen, points[points.Count - 3].x, points[points.Count - 3].y, points[points.Count - 2].x, points[points.Count - 2].y);
Splitline(new PointF(points[points.Count - 2].x, points[points.Count - 2].y), new PointF(points[points.Count - 1].x, points[points.Count - 1].y), graphics);
}
else if (points.Count == 2)
{
graphics.DrawLine(pen, points[points.Count - 2].x, points[points.Count - 2].y, points[points.Count - 1].x, points[points.Count - 1].y);
}
else
{
graphics.DrawLine(pen, points[points.Count - 1].x, points[points.Count - 1].y, points[points.Count - 1].x+1, points[points.Count - 1].y+1);
}
}
其实以上思路最主要的还是增加坐标点和减坐标点。以下就是全部代码,复制粘贴即可使用。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RedrawUITest
{
public partial class Form6 : Form
{
private BezierPen bezierPen = new BezierPen();
List<PointF> listpoint = new List<PointF>();
public Form6()
{
InitializeComponent();
this.DoubleBuffered = true;
this.MouseDown += BezierPenForm_MouseDown;
this.MouseMove += BezierPenForm_MouseMove;
this.MouseUp += BezierPenForm_MouseUp;
}
PointF startpoint;
Bitmap bitmap;
private void BezierPenForm_MouseDown(object sender, MouseEventArgs e)
{
bezierPen.AddPoint(e.X, e.Y);
startpoint = new PointF(e.X,e.Y);
}
private void BezierPenForm_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Console.WriteLine(e.X+","+e.Y);
double lineline = Math.Sqrt(Math.Pow((e.X - startpoint.X), 2) + Math.Pow((e.Y - startpoint.Y), 2));
if (lineline >= 10)
{
bezierPen.AddPoint(e.X, e.Y);
startpoint = new PointF(e.X, e.Y);
//bezierPen.Draw2(this.CreateGraphics());
bezierPen.Draw3(this.CreateGraphics());
}
}
}
private void BezierPenForm_MouseUp(object sender, MouseEventArgs e)
{
Graphics g = Graphics.FromImage(bitmap);
bezierPen.Draw2(g);
bezierPen.ClearPoint();
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (bitmap != null)
{
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; //高像素偏移质量
e.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawImage(bitmap, 0, 0);
}
}
private void Form6_Load(object sender, EventArgs e)
{
bitmap = new Bitmap(this.Width, this.Height);
}
}
public class BezierPen
{
private List<pendraw> points = new List<pendraw>();
public void AddPoint(float x, float y)
{
pendraw pdraw = new pendraw();
pdraw.x = x;
pdraw.y = y;
points.Add(pdraw);
}
public void ClearPoint()
{
points.Clear();
}
public void Draw2(Graphics graphics)
{
if (points.Count < 1)
{
return;
}
Pen pen = new Pen(Color.Red, 7.0f);
pen.LineJoin = LineJoin.Round;
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; //高像素偏移质量
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (points.Count >= 3)
{
if (points.Count > 4)
{
for (int i = 0; i < points.Count - 4; i++)
{
graphics.DrawBezier(pen, new PointF(points[i].x, points[i].y), new PointF(points[i + 1].x, points[i + 1].y), new PointF(points[i + 2].x, points[i + 2].y), new PointF(points[i + 3].x, points[i + 3].y));
}
}
else if (points.Count > 2 && points.Count < 5)
{
for (int i = 0; i < points.Count - 2; i++)
{
graphics.DrawLine(pen, points[i].x, points[i].y, points[i + 1].x, points[i + 1].y);
}
}
Splitline(new PointF(points[points.Count - 2].x, points[points.Count - 2].y), new PointF(points[points.Count - 1].x, points[points.Count - 1].y), graphics);
}
else if (points.Count == 2)
{
graphics.DrawLine(pen, points[points.Count - 2].x, points[points.Count - 2].y, points[points.Count - 1].x , points[points.Count - 1].y );
}
else
{
graphics.DrawLine(pen, points[points.Count - 1].x, points[points.Count - 1].y, points[points.Count - 1].x+1 , points[points.Count - 1].y+1);
}
}
public void Draw3(Graphics graphics)
{
if (points.Count < 1) {
return;
}
Pen pen = new Pen(Color.Red,7.0f);
graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; //高像素偏移质量
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
pen.LineJoin = LineJoin.Round;
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
//graphics.DrawLine(pen, points[points.Count-2].x, points[points.Count-2].y, points[points.Count-1].x, points[points.Count - 1].y);
if (points.Count >= 3)
{
if (points.Count > 4)
{
graphics.DrawBezier(pen, new PointF(points[points.Count - 5].x, points[points.Count - 5].y), new PointF(points[points.Count - 4].x, points[points.Count - 4].y), new PointF(points[points.Count - 3].x, points[points.Count - 3].y), new PointF(points[points.Count - 2].x, points[points.Count - 2].y));
}
else
{
graphics.DrawLine(pen, points[points.Count - 3].x, points[points.Count - 3].y, points[points.Count - 2].x, points[points.Count - 2].y);
}
Splitline(new PointF(points[points.Count - 2].x, points[points.Count - 2].y), new PointF(points[points.Count - 1].x, points[points.Count - 1].y), graphics);
}
else if (points.Count == 2)
{
graphics.DrawLine(pen, points[points.Count - 2].x, points[points.Count - 2].y, points[points.Count - 1].x, points[points.Count - 1].y);
}
else
{
graphics.DrawLine(pen, points[points.Count - 1].x, points[points.Count - 1].y, points[points.Count - 1].x+1, points[points.Count - 1].y+1);
}
}
void Splitline(PointF point1, PointF point2, Graphics g)
{
double fz = 2.5;
double lineline = Math.Sqrt(Math.Pow((point2.X - point1.X), 2) + Math.Pow((point2.Y - point1.Y), 2));
if (lineline > fz)
{
int num = Convert.ToInt32(lineline / fz);
List<PointF> points = new List<PointF>();
double doublex = (point2.X - point1.X) / num;
double doubley = (point2.Y - point1.Y) / num;
for (int i = 0; i < num; i++)
{
PointF pointF = new PointF(point1.X + (float)(i * doublex), point1.Y + (float)(i * doubley));
points.Add(pointF);
}
Console.WriteLine("总数:"+points.Count);
float widtline = 7.0f;
float widthlinedj = widtline / points.Count;
for (int i = 0; i < points.Count - 1; i++)
{
widtline = widtline - widthlinedj;
Pen pen = new Pen(Color.Red, widtline);
g.DrawLine(pen, points[i], points[i + 1]);
}
}
}
}
public class pendraw
{
public float x { get; set; }
public float y { get; set; }
}
}