【mfc/VS2022】绘图工具设计-绘制基本图元2

接着:https://blog.csdn.net/qq_61814350/article/details/135609009?spm=1001.2014.3001.5501

画圆

添加了bresenham法绘制圆的函数(该算法详细步骤见专栏相关文章):

void Bresenham_Circle(int xc, int yc, int r, CDC* pDC);
void NewDraw(CDC* pDC);

is_CenPoint用来标志是否已经设置好了圆心(按下了鼠标左键),可以计算半径。

详细定义如下:

#pragma once
class CCircle
{
public:CCircle();void Set_CenPoint(CPoint p);void Get_Radius(CPoint p);int Get_m_Radius();CPoint Get_m_CenPoint();void Draw(CDC* pDC);void Set_m_Radius(int r);void Bresenham_Circle(int xc, int yc, int r, CDC* pDC);void NewDraw(CDC* pDC);CPoint m_CenPoint;int m_Radius;bool is_CenPoint;
};

#include "pch.h"
#include "CCircle.h"
CCircle::CCircle()
{is_CenPoint = false;
}
void CCircle::Set_CenPoint(CPoint p)//圆心
{is_CenPoint = true;m_CenPoint = p;
}
void CCircle::Get_Radius(CPoint p)
{if (is_CenPoint){double x = (p.x - m_CenPoint.x) * (p.x - m_CenPoint.x);double y = (p.y - m_CenPoint.y) * (p.y - m_CenPoint.y);m_Radius = (int)sqrt(x + y);}
}
int CCircle::Get_m_Radius()
{return m_Radius;
}
CPoint CCircle::Get_m_CenPoint()
{return m_CenPoint;
}
void CCircle::Draw(CDC* pDC)
{pDC->Ellipse(m_CenPoint.x - m_Radius, m_CenPoint.y - m_Radius, m_CenPoint.x + m_Radius, m_CenPoint.y + m_Radius);
}void CCircle::Set_m_Radius(int r)
{m_Radius = r;
}void CCircle::Bresenham_Circle(int xc, int yc, int r, CDC* pDC)
{int x, y, d, d1, d2, direction;x = 0, y = r, d = 2 * (1 - r);//初始化while (y >= 0){pDC->SetPixel(x + xc, y + yc, RGB(0, 0, 0));pDC->SetPixel(x + xc, -y + yc, RGB(0, 0, 0));pDC->SetPixel(-x + xc, y + yc, RGB(0, 0, 0));pDC->SetPixel(-x + xc, -y + yc, RGB(0, 0, 0));if (d < 0){d1 = 2 * (d + y) - 1;if (d1 < 0) direction = 1;else direction = 2;}else if (d > 0){d2 = 2 * (d - x) - 1;if (d2 <= 0) direction = 2;else direction = 3;}else direction = 2;switch (direction){case 1:d += 2 * x + 3; x++;  break;case 2: d += 2 * (x + 1) - 2 * (y - 1) + 2; x++, y--; break;case 3:d += -2 * (y - 1) + 1; y--; break;}}
}void CCircle::NewDraw(CDC* pDC)
{Bresenham_Circle(m_CenPoint.x, m_CenPoint.y, m_Radius, pDC);
}

在鼠标的消息处理函数里的写法和直线、矩形类似,不再说明。

画贝塞尔曲线

贝塞尔曲线设计的绘制方法是“贝塞尔曲线:先画一条直线,然后依次拖动选择第一个、第二个控制点。”。

由于绘制是用户一个一个地设置四个控制点,调用的又是GDI绘制四个控制点的贝塞尔曲线的函数,所以在设置第三个控制点时(前两个控制点是贝塞尔曲线的起点和终点,设置时调用绘制直线的函数,贝塞尔曲线的性质之一是起点和终点也在贝塞尔曲线的起点和终点),第四个控制点还没有设置,这里设置为自动变成跟第三个控制点一样,等到第三个点设置好,可以再设置第四个控制点。need_control,count1就是用来标识这几个情况的。因为涉及到设置第四个点时,要把设置第三个点时的曲线擦除,所以用pts1数组存了设置第三个点时的四个控制点,同样用反色笔方法来擦除,count1用来控制只擦除一次。

Redraw函数是重绘时调用的,因为控制点已经确定,直接调用GDI函数即可。

详细定义如下:

#pragma once
class CPolyBezier
{
private:int need_control;int count1;
public:CPoint pts[4];CPoint pts1[4];//存三个点时的状态,用来擦除上一次的曲线的CPolyBezier();void Set_start_point(CPoint p);void Set_end_point(CPoint p);void Set_start_control(CPoint p);void Set_end_control(CPoint p);CPoint Get_start_point();CPoint Get_end_point();void Draw(CDC* pDC);void ReDraw(CDC* pDC);int Get_control_state();void Set_control_state(int s);
};
#include "pch.h"
#include "CPolyBezier.h"
CPolyBezier::CPolyBezier()
{need_control = 1;count1  = 0;
}void CPolyBezier::Set_start_point(CPoint p)
{pts[0].x = p.x;pts[0].y = p.y;
}void CPolyBezier::Set_end_point(CPoint p)
{pts[3].x = p.x;pts[3].y = p.y;//need_control = 2;
}void CPolyBezier::Set_start_control(CPoint p)
{pts[1].x = p.x;pts[1].y = p.y;pts[2].x = pts[1].x;pts[2].y = pts[1].y;for (int i = 0; i < 4; i++)pts1[i] = pts[i];//need_control = 3;
}void CPolyBezier::Set_end_control(CPoint p)
{pts[2].x = p.x;pts[2].y = p.y;//need_control = 0;
}CPoint CPolyBezier::Get_start_point()
{return pts[0];
}CPoint CPolyBezier::Get_end_point()
{return pts[3];
}void CPolyBezier::Draw(CDC* pDC)
{if (3 == need_control){if (count1 == 1){pDC->SetROP2(R2_NOTXORPEN);pDC->PolyBezier(pts1, 4);count1++;}pDC->PolyBezier(pts, 4);}else if (2 == need_control){if (count1 == 0){pDC->SetROP2(R2_NOTXORPEN);pDC->MoveTo(pts[0]);pDC->LineTo(pts[3]);count1++;}pDC->PolyBezier(pts, 4);}else if (0 == need_control){pDC->PolyBezier(pts, 4);}else{pDC->MoveTo(pts[0]);pDC->LineTo(pts[3]);}
}void CPolyBezier::ReDraw(CDC* pDC)
{pDC->PolyBezier(pts, 4);
}int CPolyBezier::Get_control_state()
{return need_control;
}void CPolyBezier::Set_control_state(int s)
{need_control = s;
}

消息处理函数部分需要注意的是 不是每次按下左键都要重新新建曲线对象,所以用on_polybezier变量的变化来判断一条曲线是否绘制完毕。

相应的消息处理函数部分如下(注意只是部分,省去了前后文): 

void CSimpleDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
//............//case 5:{if (!on_polybezier){m_polybezier = new CPolyBezier;on_polybezier = 1;m_polybezier->Set_start_point(point);}}break;//..........//
}void CSimpleDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{//............//case 5:{if (m_polybezier->Get_control_state() == 1){m_polybezier->Set_control_state(2);}else if (m_polybezier->Get_control_state() == 2){m_polybezier->Set_control_state(3);}else if (m_polybezier->Get_control_state() == 3){m_polybezier->Set_control_state(0);repaint->now_type = 5;repaint->data = m_polybezier;m_line_list.InputFront(repaint);on_polybezier = 0;}}break;//............//}void CSimpleDrawView::OnMouseMove(UINT nFlags, CPoint point)
{if (type == 5)//贝塞尔曲线{if (go){if (m_polybezier->Get_control_state() == 1){pDC->SetROP2(R2_NOTXORPEN);m_polybezier->Draw(pDC);}if (m_polybezier->Get_control_state() == 2 && on_polybezier){pDC->SetROP2(R2_NOTXORPEN);m_polybezier->Draw(pDC);}if (m_polybezier->Get_control_state() == 3 && on_polybezier){pDC->SetROP2(R2_NOTXORPEN);m_polybezier->Draw(pDC);}}elsego = true;if (m_polybezier->Get_control_state() == 1){m_polybezier->Set_end_point(point);m_polybezier->Draw(pDC);}if (m_polybezier->Get_control_state() == 2 && on_polybezier){m_polybezier->Set_start_control(point);m_polybezier->Draw(pDC);}else if (m_polybezier->Get_control_state() == 3 && on_polybezier){m_polybezier->Set_end_control(point);m_polybezier->Draw(pDC);}}}

画b样条曲线

b样条曲线采用三次b样条曲线拼接而成,计算控制点对应的系数如下:

void CBSpline::calculate_base_func(double& f1, double& f2, double& f3, double& f4,double t)
{f1 = (1.0 / 6) * ((-1) * t * t * t + 3 * t * t - 3 * t + 1);f2 = (1.0 / 6) * (3 * t * t * t - 6 * t * t + 4);f3 = (1.0 / 6) * ((-3) * t * t * t + 3 * t * t + 3 * t + 1);f4 = (1.0 / 6) * (t * t * t);
}

 名字里有changed的函数,变量是用来在修改b样条时来做操作的。

注意:细分精度时,用浮点数要注意精度丢失问题,不然b样条拼接时会有缝隙,有些点就没计算出来。

b样条曲线与贝塞尔曲线不同,控制点的起点和终点不在曲线上,但这里实现了让控制点的起点和终点在曲线上,方法是额外添加了一个新的起点P-1和终点Pn+1,即xleft,yleft,xright,yright,多绘制出了两段线。然后让原本的起点P0和终点Pn变成P-1P1,Pn-1Pn+1的中点,就能让曲线通过原本的起点和中点(因为三次b样条曲线的性质就是P(0)——曲线的起点,在前三个点组成的三角形的中线上,且位于距三角形底边对着的顶点的1/3处,详见《计算机图形学实用教程》(第四版),苏小红等著,p94和p96有详细的推导和说明)。

同样地,因为b样条的控制点数目也不确定,结束一条曲线的绘制也采用跟多义线绘制(见上一篇文章)一样的方法,在按下右键的函数里面处理。

详细定义如下:

#pragma once
class CBSpline
{
public:int xcoordinate[100], ycoordinate[100];//控制点坐标CPoint cpts[100];int nPoints;//已选择控制点的数量int linewidth;//曲线线宽int bechangednum;int is_on_changed;void is_near_control();
public:CBSpline();CBSpline(CPoint p[],int n);void BSpline(CDC* pDC);void display(CDC* pDC);//绘图函数void setcontrol(CPoint p);void changecontrol(CPoint p);void finishchangecontrol();void drawtoend(CDC* pDC);//画出到最后一个控制点的曲线段//void after_change_display(CDC* pDC);void calculate_base_func(double& f1, double& f2, double& f3, double& f4,double t);};
#include "pch.h"
#include "CBSpline.h"CBSpline::CBSpline()
{nPoints = 0;linewidth = 2;is_on_changed = 0;bechangednum = 0;
}CBSpline::CBSpline(CPoint p[], int n)
{nPoints = n;linewidth = 2;for (int i = 0; i < n; i++){xcoordinate[i] = p[i].x;ycoordinate[i] = p[i].y;cpts[i] = p[i];}
}void CBSpline::BSpline(CDC* pDC)//三次b样条画曲线
{CPen newpen, * pOldpen;;newpen.CreatePen(PS_SOLID, linewidth, RGB(0, 0, 0));pOldpen = pDC->SelectObject(&newpen);//注意保存成原来的画笔CPoint pre;int j, n = 50;//j表示已经绘制的曲线条数,n为曲线的细分程度double t, dt, f1, f2, f3, f4;dt = 1.0 / n;//dt表示每次画点后坐标的增量int xleft, yleft, xright, yright;//使用三顶点共线技巧使得曲线经过控制点起点终点xleft = 2 * xcoordinate[0] - xcoordinate[1], yleft = 2 * ycoordinate[0] - ycoordinate[1];t = 0;calculate_base_func(f1, f2, f3, f4, t);pre.x = f1 * xleft + f2 * xcoordinate[0] + f3 * xcoordinate[1] + f4 * xcoordinate[2],pre.y = f1 * yleft + f2 * ycoordinate[0] + f3 * ycoordinate[1] + f4 * ycoordinate[2];pDC->MoveTo(pre.x, pre.y);for (t = dt; t - 1 <= 1e-6; t += dt){//根据B样条曲线的公式绘制每条曲线calculate_base_func(f1, f2, f3, f4, t);pDC->LineTo(f1 * xleft + f2 * xcoordinate[0] + f3 * xcoordinate[1] + f4 * xcoordinate[2],f1 * yleft + f2 * ycoordinate[0] + f3 * ycoordinate[1] + f4 * ycoordinate[2]);pre.x = f1 * xleft + f2 * xcoordinate[0] + f3 * xcoordinate[1] + f4 * xcoordinate[2],pre.y = f1 * yleft + f2 * ycoordinate[0] + f3 * ycoordinate[1] + f4 * ycoordinate[2];//指定需要连线的点}for (j = 0; j < (nPoints - 3); j++)//曲线条数为n-3条{t = 0;calculate_base_func(f1, f2, f3, f4, t);pre.x = f1 * xcoordinate[j] + f2 * xcoordinate[j + 1] + f3 * xcoordinate[j + 2] + f4 * xcoordinate[j + 3],pre.y = f1 * ycoordinate[j] + f2 * ycoordinate[j + 1] + f3 * ycoordinate[j + 2] + f4 * ycoordinate[j + 3];pDC->MoveTo(pre.x, pre.y);for (t = dt; t - 1 <= 1e-6; t += dt)//浮点数有精度损失,所以要用 t-1 <= 1e-6{//根据B样条曲线的公式绘制每条曲线calculate_base_func(f1, f2, f3, f4, t);pDC->LineTo(f1 * xcoordinate[j] + f2 * xcoordinate[j + 1] + f3 * xcoordinate[j + 2] + f4 * xcoordinate[j + 3],f1 * ycoordinate[j] + f2 * ycoordinate[j + 1] + f3 * ycoordinate[j + 2] + f4 * ycoordinate[j + 3]);pre.x = f1 * xcoordinate[j] + f2 * xcoordinate[j + 1] + f3 * xcoordinate[j + 2] + f4 * xcoordinate[j + 3],pre.y = f1 * ycoordinate[j] + f2 * ycoordinate[j + 1] + f3 * ycoordinate[j + 2] + f4 * ycoordinate[j + 3];//指定需要连线的点}}pDC->SelectObject(pOldpen);//注意还原成原来的画笔newpen.DeleteObject();}void CBSpline::display(CDC* pDC)
{for (int i = 0; i < nPoints - 1; i++){pDC->MoveTo(xcoordinate[i], ycoordinate[i]);pDC->LineTo(xcoordinate[i + 1], ycoordinate[i + 1]);}if (nPoints >= 4){//如果已经选择的控制点数大于4个,则调用BSpline绘制曲线BSpline(pDC);}}void CBSpline::setcontrol(CPoint p)
{xcoordinate[nPoints] = p.x;ycoordinate[nPoints] = p.y;cpts[nPoints] = p;nPoints++;
}void CBSpline::drawtoend(CDC* pDC)
{//将曲线终点落到最后一个点上CPen newpen, * pOldpen;newpen.CreatePen(PS_SOLID, linewidth, RGB(0, 0, 0));pOldpen =pDC->SelectObject(&newpen);int xright = 2 * xcoordinate[nPoints - 1] - xcoordinate[nPoints - 2], yright = 2 * ycoordinate[nPoints - 1] - ycoordinate[nPoints - 2];double dt, t = 0; CPoint pre; int n = 50;double f1 ;double f2;double f3;double f4;calculate_base_func(f1, f2, f3, f4, t);pre.x = f4 * xright + f1 * xcoordinate[nPoints - 3] + f2 * xcoordinate[nPoints - 2] + f3 * xcoordinate[nPoints - 1],pre.y = f4 * yright + f1 * ycoordinate[nPoints - 3] + f2 * ycoordinate[nPoints - 2] + f3 * ycoordinate[nPoints - 1];pDC->MoveTo(pre.x, pre.y);dt = 1.0 / n;for (t = dt; t - 1 <= 1e-6; t += dt){//根据B样条曲线的公式绘制每条曲线calculate_base_func(f1, f2, f3, f4, t);pre.x = f4 * xright + f1 * xcoordinate[nPoints - 3] + f2 * xcoordinate[nPoints - 2] + f3 * xcoordinate[nPoints - 1],pre.y = f4 * yright + f1 * ycoordinate[nPoints - 3] + f2 * ycoordinate[nPoints - 2] + f3 * ycoordinate[nPoints - 1];pDC->LineTo(pre.x, pre.y);//指定需要连线的点}pDC->SelectObject(pOldpen);newpen.DeleteObject();
}void CBSpline::changecontrol(CPoint p)
{if (is_on_changed){xcoordinate[bechangednum] = p.x;ycoordinate[bechangednum] = p.y;cpts[bechangednum] = p;}
}void CBSpline::is_near_control()
{if (!is_on_changed){is_on_changed = 1;}
}void CBSpline::finishchangecontrol()
{is_on_changed = 0;
}void CBSpline::calculate_base_func(double& f1, double& f2, double& f3, double& f4,double t)
{f1 = (1.0 / 6) * ((-1) * t * t * t + 3 * t * t - 3 * t + 1);f2 = (1.0 / 6) * (3 * t * t * t - 6 * t * t + 4);f3 = (1.0 / 6) * ((-3) * t * t * t + 3 * t * t + 3 * t + 1);f4 = (1.0 / 6) * (t * t * t);
}

消息处理函数如下(修改b样条部分还没给全,还涉及到鼠标移动到控制点附近,鼠标变形然后选中该曲线进行修改操作的部分)

void CSimpleDrawView::OnLButtonDown(UINT nFlags, CPoint point)对应的部分

case 8://b样条绘制{if (!is_on_drawspline){m_bspline = new CBSpline;is_on_drawspline = 1;}if(is_on_drawspline)m_bspline->setcontrol(point);}break;case 9://b样条修改{}break;

void CSimpleDrawView::OnLButtonUp(UINT nFlags, CPoint point)对应的部分

		case 8:{if(is_on_drawspline)m_bspline->display(pDC);}break;case 9:{if (m_CurEditbspline->is_on_changed && m_CurEditbspline != NULL){m_CurEditbspline->finishchangecontrol();}}break;

 void CSimpleDrawView::OnMouseMove(UINT nFlags, CPoint point):

		if (type == 9)//b样条曲线修改{if (m_CurEditbspline->is_on_changed&&m_CurEditbspline!=NULL){m_CurEditbspline->changecontrol(point);changedrawspline();}}

绘制曲线时只需要点击设置控制点,所以鼠标移动函数里没有操作。

CBSpline* m_bspline;//当前绘制的样条
CBSpline* m_CurEditbspline;//当前修改的样条,好在遍历保存图形的链表时比较是不是当前要修改的对象

int is_on_drawspline;表示当前是否在画b样条

修改b样条曲线,也就是修改控制点后重绘曲线的函数用了双缓冲来实现动态效果,比起反色笔,双缓冲可以降低闪烁。双缓冲就是先在另一个逻辑缓冲设备上画好了再放到你现在用的设备上,注释已经很详细,不再赘述。注意,主要要记得删除对象和解除笔的绑定。

void CSimpleDrawView::changedrawspline()
{//双缓冲CDC* pDC = GetDC();CRect rect;GetClientRect(rect);int x0 = rect.Width();//获得中点int y0 = rect.Height();// 创建一个内存设备上下文CDC memDC;memDC.CreateCompatibleDC(pDC);// 创建一个位图对象CBitmap NewBitbmp, * pOldBitmap;NewBitbmp.CreateCompatibleBitmap(pDC, x0, y0);pOldBitmap = memDC.SelectObject(&NewBitbmp);//兼容位图选入memdc//	memDC.FillSolidRect(0, 0, x0, y0, RGB(255, 255, 255));memDC.FillSolidRect(rect, pDC->GetBkColor());//按原来背景填充客户区否则是黑色//这里可以不设,因为设的PDCCPen NewPen, * pOldpen;NewPen.CreatePen(PS_SOLID, 4, RGB(0, 0, 0));  //实线,宽度为4像素pOldpen = pDC->SelectObject(&NewPen);   //选择创建的画笔ReDraw(&memDC);m_CurEditbspline->display(&memDC);m_CurEditbspline->drawtoend(&memDC);pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);//内存位图复制到屏幕memDC.SelectObject(pOldBitmap);NewBitbmp.DeleteObject();memDC.SelectObject(pOldpen);NewPen.DeleteObject();memDC.DeleteDC();
}

void CSimpleDrawView::ReDraw(CDC* pDC)
{int i, j;j = m_line_list.Length();if (m_line_list.IsEmpty() == false){for (i = 1; i <= j; i++){pDC->SelectStockObject(NULL_BRUSH);//空心笔刷,封闭图形不填充Node* paint;paint = m_line_list.Locate(i);if (paint->now_type == 1){((CLine*)paint->data)->Draw(pDC);}if (paint->now_type == 2){((CQuare*)paint->data)->Draw(pDC);}if (paint->now_type == 3){((CCircle*)paint->data)->Draw(pDC);}if (paint->now_type == 4){((CPolyline*)paint->data)->ReDraw(pDC);}if (paint->now_type == 5){((CPolyBezier*)paint->data)->ReDraw(pDC);}if (paint->now_type == 6){((CVerticalLine*)paint->data)->Draw(pDC);}if (paint->now_type == 8){if ((CBSpline*)paint->data != m_CurEditbspline){((CBSpline*)paint->data)->display(pDC);((CBSpline*)paint->data)->drawtoend(pDC);}}}}}

ReDraw函数除了用在修改b样条函数时的重绘,也可以用在Ondraw的重绘里 

void CSimpleDrawView::OnDraw(CDC* /*pDC*/)
{CSimpleDrawDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;CDC* pDC = GetDC();ReDraw(pDC);ReleaseDC(pDC);/**/// TODO: 在此处为本机数据添加绘制代码
}

修改b样条的部分说明起来实在比较麻烦,有空再说吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/636096.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十一章 请求响应

第十一章 请求响应 1.概述2.请求-postman工具3.请求-简单参数&实体参数4.请求-数组集合参数5.请求-日期参数&JSON参数6.请求-路径参数7.响应-ResponseBody&统一响应结果8.响应-案例 1.概述 将前端发送的请求封装为HttpServletRequest对象 在通过HttpServletRespo…

OpenCV-Python(51):基于Haar特征分类器的面部检测

目标 学习了解Haar 特征分类器为基础的面部检测技术将面部检测扩展到眼部检测等。 基础 以Haar 特征分类器为基础的对象检测技术是一种非常有效的对象检测技术(2001 年Paul_Viola 和Michael_Jones 提出)。它是基于机器学习的,通过使用大量的正负样本图像训练得到一个cascade_…

【Linux取经路】初探进程地址空间

文章目录 一、历史问题回顾二、语言层面的地址空间2.1 验证 三、虚拟地址的引入3.1 初步解释这种现象——引入地址空间的概念3.2 再来粗粒度理解上面的现象 四、细节解释4.1 地址空间究竟是什么&#xff1f;4.2为什么要有地址空间4.3 页表4.3.1 CR3寄存器4.3.2 页表是由页表项组…

【Linux的基本指令】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 1、ls 指令 2、 pwd命令 3、cd 指令 4、touch指令 5、mkdir指令&#xff08;重要&#xff09; 6、rmdir指令 && rm 指令&#xff08;重要&#xff09;…

前后端分离,仓储模式的医院安全(不良)事件报告系统

医院安全&#xff08;不良&#xff09;事件报告系统源码&#xff0c;PHP语言开发 医院不良事件上报系统&#xff0c;按照不良事件的管理部门不同&#xff0c;分为护理不良事件、药品不良反应事件、医技不良事件、院内感染事件、输血不良反应事件、器械不良事件、信息不良事件、…

strlen的使用和模拟实现

strlen的使用和模拟实现 首先&#xff0c;我们来看一下strlen的格式 size_t strlen(const char * str); 在这个strlen中&#xff0c;我们有几个需要注意的点&#xff1a; 1.strlen函数是用来测量字符串长度的&#xff08;在字符串当中在‘\0’之前的字符个数&#xff0c;\0不…

国产AI新篇章:书生·浦语2.0带来200K超长上下文解决方案

总览&#xff1a;大模型技术的快速演进 自2023年7月6日“书生浦语”&#xff08;InternLM&#xff09;在世界人工智能大会上正式开源以来&#xff0c;其在社区和业界的影响力日益扩大。在过去半年中&#xff0c;大模型技术体系经历了快速的演进&#xff0c;特别是100K级别的长…

力扣:474. 一和零(动态规划)(01背包)

题目&#xff1a; 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0c;集合 x 是集合 y 的 子集 。 示例 1&#xff1a; 输入&#…

JOSEF约瑟 零序过流继电器LGL-110/AC AC220V 0.01~9.99A 柜内安装

LGY 、LGL零序过电压继电器 系列型号 LGY-110零序过电压继电器&#xff1b; LGL-110零序过电压继电器&#xff1b; LGL-110/AC零序过电压继电器&#xff1b; LGL-110静态零序过电流继电器 &#xff11; 应用 LGL-110 型零序过电流继电器用作线路和电力设备的零序过电流保护。…

一文详解Bitcoin Wallet(btc钱包),推荐bitget钱包

​ 比特币&#xff08;BTC&#xff09;是什么&#xff1f; 比特币&#xff08;BTC&#xff09;于 2008 年由中本聪创建&#xff0c;是一个去中心化的点对点网络。这个开创性的系统运用了密码学技术和分布式账本技术&#xff0c;无需中央权威机构的验证。比特币的诞生标志着去中…

【工具】使用ssh进行socket5代理

文章目录 shellssh命令详解正向代理&#xff1a;反向代理&#xff1a;本地 socks5 代理 shell ssh -D 3333 root192.168.0.11 #输入密码 #3333端口已经使用远程机进行转发设置Windows全局代理转发 socks127.0.0.1 3333如果远程机为公网ip&#xff0c;可通过搜索引擎查询出网…

【LeetCode每日一题】2788. 按分隔符拆分字符串

2024-1-20 文章目录 [2788. 按分隔符拆分字符串](https://leetcode.cn/problems/split-strings-by-separator/)思路&#xff1a; 2788. 按分隔符拆分字符串 思路&#xff1a; 对于每个单词&#xff0c;使用一个可变字符串 StringBuilder 来构建拆分后的单词。初始时&#xff0…

IPv6--ACL6(IPv6访问控制列表--基本ACL6配置)

ACL基本原理 ACL由一系列规则组成,通过将报文与ACL规则进行匹配,设备可以过滤出特定的报文。 ACL的组成 ACL编号: 在网络设备上配置ACL时,每个ACL都需要分配一个编号,称为ACL编号,用来标识ACL。不同分类的ACL编号范围不同,这个后面具体讲。 规则: 前面提到了,一个AC…

网络编程01 常见名词的一些解释

本文将讲解网络编程的一些常见名词以及含义 在这之前让我们先唠一唠网络的产生吧,其实网络的产生也拯救了全世界 网络发展史 网络的产生是在美苏争霸的期间,实际上双方都持有核武器,希望把对方搞垮的同时不希望自己和对方两败俱伤. 希望破坏对方的核武器发射,这就涉及到三个方面…

【力扣每日一题】力扣2788用分隔符拆分字符串

力扣2788用分隔符拆分字符串 题目来源 力扣2788用分隔符拆分字符串 题目概述 给你一个字符串数组 words 和一个字符 separator &#xff0c;请你按 separator 拆分 words 中的每个字符串。 返回一个由拆分后的新字符串组成的字符串数组&#xff0c;不包括空字符串 。 注意…

【router-link详细介绍】

router-link详细介绍 1. router-link1.1. to1.2. replace1.3. append1.4. tag1.5. active-class1.6. exact1.7. event1.8. exact-active-class1.9. aria-current-value 1. router-link router-link 是一个用于在 Vue 应用中创建导航链接的组件&#xff0c;由 Vue Router 提供&…

【Github搭建网站】零基础零成本搭建个人Web网站~

Github网站&#xff1a;https://github.com/ 这是我个人搭建的网站&#xff1a;https://xf2001.github.io/xf/ 大家可以搭建完后发评论区看看&#xff01;&#xff01;&#xff01; 搭建教程&#xff1a;https://www.bilibili.com/video/BV1xc41147Vb/?spm_id_from333.999.0.0…

机器学习:简要介绍及应用案例

机器学习是一种人工智能&#xff08;AI&#xff09;的分支&#xff0c;它致力于研究和开发系统&#xff0c;使它们能够从经验中学习并自动改善。这种学习过程使机器能够适应新的数据&#xff0c;识别模式&#xff0c;做出决策和预测&#xff0c;而无需明确的编程。 机器学习的…

CentOS安装Flume

CentOS安装Flume 一、简介二、安装1、下载2、解压3、创建配置文件4、启动flume agent5、验证 一、简介 Flume is a distributed, reliable, and available service for efficiently collecting, aggregating, and moving large amounts of log data. It has a simple and flexi…

ES进阶使用

配置 pom依赖 <dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>7.17.5</version></dependency>yml配置 elasticsearch:address: http://192.168.133.100:9200数据库…