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

基于:https://blog.csdn.net/weixin_51599044/article/details/111741111

实现的功能:

绘制图元的方法:
前5种图元的菜单项均在“绘制”菜单里。
1.直线:按下左键作为起点,按住左键拖动鼠标到你想设定的终点,然后放开鼠标即可。
2.矩形:按下左键确定左上角,按住左键拖动鼠标到你想设定的右下角,然后放开鼠标。
3.折线:同直线画法,第一条线要设置起点和终点,后续的线条只需设置终点,结束需要按下右键,并且要再次点击折线按钮或菜单才能绘制新的折线。
4.贝塞尔曲线:先画一条直线,然后依次拖动选择第一个、第二个控制点。
5.圆:按下左键作为圆心,按住左键拖动鼠标设定半径,然后放开鼠标
6.b样条:点击“新增功能”里的“绘制b样条曲线”菜单项,每次鼠标点下即可设置一个控制点(注意每次按下后不需要按住),控制点会被直线连接起来。至少要设置四个控制点才会画出曲线,设置完毕后点击右键完成一条曲线的绘制。
再次绘制样条曲线需要重新点击“绘制b样条”菜单项。

设计思路

说明:GDI函数的调用(参看https://blog.csdn.net/qq_61814350/article/details/133284380)、界面设计、设置消息处理函数(鼠标按下、移动、松开以及点击菜单栏的某项)、解决动态绘制出现的重影(反色笔)、图形的重绘(保存图形,在ondraw函数里调用绘图函数)不再赘述,请参看文章最前面的参考文章和同专栏的【mfc/VS2022】计图实验:绘图工具设计知识笔记系列文章。

画直线

画直线的例子参考文章的基础上进行了修改,主要是加入了自己实现的中点画线法函数(算法思路可以查看专栏里的有关文章),newdraw是调用中点画线法函数的,以及相应的处理斜率的变量。相应的h和cpp文件如下:

#pragma once
class CLine
{
public:CLine();void Set_start_point(CPoint p);void Set_end_point(CPoint p);CPoint Get_start_point();CPoint Get_end_point();double slope;double b;//y=kx+bint slope_is_exist;// 斜率是否存在的标志CPoint Line_start_point;CPoint Line_end_point;public:void Draw(CDC* pDC);void MidLine(int x0, int y0, int x1, int y1, CDC* pDC);void NewDraw(CDC* pDC);};
#include "pch.h"
#include "CLine.h"
CLine::CLine()
{slope = 0; b = 0;slope_is_exist = 1;
}void CLine::Set_start_point(CPoint p)
{Line_start_point = p;
}void CLine::Set_end_point(CPoint p)
{Line_end_point = p;}CPoint CLine::Get_start_point()
{return Line_start_point;
}CPoint CLine::Get_end_point()
{return Line_end_point;
}void CLine::Draw(CDC* pDC)
{if (Line_end_point.x - Line_start_point.x == 0) slope_is_exist = 0;else{slope_is_exist = 1;slope = (1.0 * Line_end_point.y- Line_start_point.y) / (Line_end_point.x - Line_start_point.x);b = Line_end_point.y - slope * Line_end_point.x;}pDC->MoveTo(Line_start_point);pDC->LineTo(Line_end_point);
}void CLine::MidLine(int x1, int y1, int x2, int y2, CDC* pDC)
{int dx, dy, d, Deta1, Deta2, x, y;double k{ 0 };if (x1 != x2) k = (1.0 * y2 - y1) / (x2 - x1);if (x1 > x2 && abs(k) <= 1){x = x2; x2 = x1; x1 = x;y = y2; y2 = y1; y1 = y;}else if (y1 > y2 && abs(k) > 1){x = x2; x2 = x1; x1 = x;y = y2; y2 = y1; y1 = y;}x = x1; y = y1;if (x2 == x1){while (y < y2){pDC->SetPixel(x, y, RGB(0, 0, 0));y++;}return;}dx = x2 - x1; dy = y2 - y1;if (k >= 0 && k <= 1){Deta1 = 2 * dx - 2 * dy; Deta2 = -2 * dy; d = dx - 2 * dy;while (x <= x2){pDC->SetPixel(x, y, RGB(0, 0, 0));x++;if (d < 0){y++;d += Deta1;}elsed += Deta2;}}else if (k <= 0 && k >= -1){/**/Deta1 = -2 * dy; Deta2 = -2 * dx - 2 * dy; d = -dx - 2 * dy;while (x <= x2){pDC->SetPixel(x, y, RGB(0, 0, 0));x++;if (d >= 0){y--;d += Deta2;}elsed += Deta1;}}else if (k > 1){Deta1 = 2 * dx - 2 * dy; Deta2 = 2 * dx; d = 2 * dx - dy;while (y <= y2){pDC->SetPixel(x, y, RGB(0, 0, 0));y++;if (d >= 0){x++;d += Deta1;}elsed += Deta2;}}else if (k < -1){/**/Deta1 = 2 * dx; Deta2 = 2 * dx + 2 * dy; d = 2 * dx + dy;while (y <= y2){pDC->SetPixel(x, y, RGB(0, 0, 0));y++;if (d < 0){x--;d += Deta2;}elsed += Deta1;}//pDC->MoveTo(Line_start_point);//pDC->LineTo(Line_end_point);}}void CLine::NewDraw(CDC* pDC)
{if (Line_end_point.x - Line_start_point.x == 0) slope_is_exist = 0;else{slope_is_exist = 1;slope = (1.0 * Line_end_point.y- Line_start_point.y) / (Line_end_point.x - Line_start_point.x);//这里要加上计算slope的部分,计算交点的时候要判断b = Line_end_point.y - slope * Line_end_point.x;}MidLine(Line_start_point.x, Line_start_point.y, Line_end_point.x, Line_end_point.y, pDC);
}

画矩形:

矩形的数据结构实现起来与直线很类似,因为考虑到其他功能(比如不调用Rectangle()而是用

Polyline()来绘制),所以用了一个数组pts保存了矩形的顶点。并保存了矩形的几何中点,方便计算一个点和矩形的位置关系(比较中点到该点的垂直、水平距离来判断点位于矩形内、外还是上)。消息处理函数与直线差不多,不再赘述。

#pragma once
class CQuare
{
public:CQuare();void Set_first_point(CPoint p);void Get_other_point();void Set_end_point(CPoint p);CPoint Get_first_point();CPoint Get_end_point();CPoint Get_central_point();void Draw(CDC* pDC);CPoint pts[5];//保存矩形顶点,可以用于多义线方式绘制//private:CPoint square_first_point;CPoint square_end_point;CPoint square_central_point;CPoint square_east_point;CPoint square_south_point;
};
#include "pch.h"
#include "CQuare.h"
CQuare::CQuare()
{}
void CQuare::Set_first_point(CPoint p)
{square_first_point = p;
}
void CQuare::Set_end_point(CPoint p)
{square_end_point = p;
}
CPoint CQuare::Get_first_point()
{return square_first_point;
}
CPoint CQuare::Get_end_point()
{return square_end_point;
}
CPoint CQuare::Get_central_point()
{return square_central_point;
}
void CQuare::Get_other_point()
{square_east_point.x = square_end_point.x;square_east_point.y = square_first_point.y;square_south_point.x = square_first_point.x;square_south_point.y = square_end_point.y;
}
void CQuare::Draw(CDC* pDC)
{square_central_point.x = (square_first_point.x+square_end_point.x)/ 2;square_central_point.y = (square_first_point.y + square_end_point.y )/ 2;Get_other_point();pts[0] = square_first_point;pts[1] = square_east_point;pts[2] = square_end_point;pts[3] = square_south_point;pts[4] = square_first_point;pDC->Rectangle(square_first_point.x, square_first_point.y, square_end_point.x, square_end_point.y);
}

画折线(多义线)

类似直线的画法。因为要动态地一条一条的绘制,所以不能直接调用绘制多义线的GDI函数,要一条一条的调用绘制直线的函数。给出相应的类定义:

#pragma once
class CPolyline
{
public:CPolyline();void Set_start_point(CPoint p);void Set_end_point(CPoint p);BOOL Sure_is_first();//private:CPoint Line_start_point;CPoint Line_end_point;BOOL is_first;public:void Draw(CDC* pDC);void ReDraw(CDC* pDC);void chgstartpoint();void selfincre_point_num();int Get_point_num();void Set_point_num(int num);int point_num;int is_closed;//判断多义线是不是画成了三角形之类的封闭图形CPoint polyline_pts[256];
};

说明:在构造函数里初始化状态isfirst为1,表示是第一条线,需要设置起点和终点,在画完第一条线后置为0,只需要设置终点。

is_closed判断是否画成了封闭图形,为1,表示封闭,可以结束一次多义线绘制。

注意:不能在void CPolyline::Set_end_point(CPoint p)自增点的数量,因为不断地在设置终点。用void CPolyline::selfincre_point_num()专门做这个操作,在void CSimpleDrawView::OnLButtonUp(UINT nFlags, CPoint point),即左键松开的时候调用。

void CPolyline::ReDraw(CDC* pDC)为在ondraw()里重绘多义线的函数,因为此时该图形的点已经全部确定,可以直接调用GDI的多义线绘制函数。
void CPolyline::chgstartpoint()将上段线的终点设置为下段要画的线的起点。

相应的类定义如下:

#include "pch.h"
#include "CPolyline.h"
CPolyline::CPolyline()
{is_first = 1;point_num = 0;is_closed = 0;}
void CPolyline::Set_start_point(CPoint p)
{Line_start_point = p;polyline_pts[point_num] = Line_start_point;point_num++;is_first = 0;
}void CPolyline::Set_end_point(CPoint p)//不断地在设置终点,所以不能在这里自增
{Line_end_point = p;polyline_pts[point_num] = Line_end_point;//point_num++;}
BOOL CPolyline::Sure_is_first()
{return is_first;
}
void CPolyline::Draw(CDC* pDC)
{pDC->MoveTo(Line_start_point);pDC->LineTo(Line_end_point);
}
void CPolyline::ReDraw(CDC* pDC)
{pDC->Polyline(polyline_pts, point_num);
}
void CPolyline::chgstartpoint()
{Line_start_point = Line_end_point;
}void CPolyline::selfincre_point_num()
{point_num++;
}int CPolyline::Get_point_num()
{return point_num;
}void CPolyline::Set_point_num(int num)
{point_num = num;
}

消息函数具体的处理 

剩余图形的绘制有空再在下篇文章里说明。再说明一下相关的消息函数的处理:

在view的消息处理函数进行单独说明较复杂,故直接给出相关的部分 :

type变量==1(type变量表示不同的使用状态,详见参考的文章)表示用GDI函数绘制的直线,10表示用中点画线法绘制的直线(两者点击的菜单栏不同),2为矩形,3和11为GDI和bresenham绘制的圆,4,5,6,8为多义线,贝塞尔曲线,垂线,b样条曲线。

注意:每条case语句块后记得加break;代码只复制了相关的部分,所以可能存在括号不对应的问题。 

void CSimpleDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{CDC* pDC = GetDC();switch (type){case 1:{m_pline = new CLine;m_pline->Set_start_point(point);}break;case 10:{m_pline = new CLine;m_pline->Set_start_point(point);}break;case 2:{m_psquare = new CQuare;m_psquare->Set_first_point(point);}break;case 3:{m_pcircle = new CCircle;m_pcircle->Set_CenPoint(point);}break;case 11:{m_pcircle = new CCircle;m_pcircle->Set_CenPoint(point);}break;case 4:{if (!on_polyline){on_polyline = 1;m_polyline = new CPolyline;}if (m_polyline->Sure_is_first()){m_polyline->Set_start_point(point);}else m_polyline->chgstartpoint();//上次的终点设为起点}break;case 5:{if (!on_polybezier){m_polybezier = new CPolyBezier;on_polybezier = 1;m_polybezier->Set_start_point(point);}}break;case 6:{if (on_verticalline && choose_line == 0 && is_choose){m_verpline = new CVerticalLine;choose_line = 1;m_verpline->Set_start_point(point);}if (on_verticalline && choose_line == 2 && is_choose){CPoint verfoot = m_verpline->Get_foot_point();m_verpline->Set_end_point(verfoot);Add_insect_point(verfoot);m_verpline->Draw(pDC);choose_line = 0;}}break;}if (type != 0)  start = true;ReleaseDC(pDC);CView::OnLButtonDown(nFlags, point);
}

鼠标左键按下函数里需要注意的是需要标识多义线是否在画第一条线,要设置起点和终点。由于多义线的点的数量未知,结束一次绘制不能像其他图形一样通过松开左键来结束。这里采用了按下右键时on_polyline = 0;来标识结束。如下面的函数:

void CSimpleDrawView::OnRButtonDown(UINT nFlags, CPoint point)
{CDC* pDC = GetDC();if (type == 4 && on_polyline){Node* repaint = new Node;repaint->now_type = 4;repaint->data = m_polyline;m_line_list.InputFront(repaint);on_polyline = 0;}type = 0;on_polybezier = 0;is_choose = 0;on_verticalline = 0;is_get_cenpoint = 0;on_find_intersection = 0;choose_line = 0;on_fill = 0;CView::OnRButtonDown(nFlags, point);
}

void CSimpleDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{CDC* pDC = GetDC();if (start == true){Node* repaint = new Node;switch (type){case 1:{repaint->now_type = 1;repaint->data = m_pline;m_line_list.InputFront(repaint);}break;case 10:{repaint->now_type = 1;repaint->data = m_pline;m_line_list.InputFront(repaint);}break;case 2:{repaint->now_type = 2;repaint->data = m_psquare;m_line_list.InputFront(repaint);}break;case 3:{repaint->now_type = 3;repaint->data = m_pcircle;m_line_list.InputFront(repaint);}break;case 11:{repaint->now_type = 3;repaint->data = m_pcircle;m_line_list.InputFront(repaint);}break;case 4:{if (m_polyline->Sure_is_first() == 0){m_polyline->selfincre_point_num();if (on_polyline&&m_polyline->is_closed==1){Node* repaint = new Node;repaint->now_type = 4;repaint->data = m_polyline;m_line_list.InputFront(repaint);on_polyline = 0;}}}break;}}go = false;start = false;ReleaseDC(pDC);CView::OnLButtonUp(nFlags, point);
}

 OnLButtonUp鼠标左键松开函数里,m_line_list是保存图形的链表,具体说明见参考的文章。需要注意的就是多义线的点的数目的增加是在这里进行的(如前文所述),以及画出的是封闭图形的话就结束这次绘制。

void CSimpleDrawView::OnMouseMove(UINT nFlags, CPoint point)
{if (start == true){if (type == 1){if (go){pDC->SetROP2(R2_NOTXORPEN);m_pline->Draw(pDC);}elsego = true;m_pline->Set_end_point(point);m_pline->Draw(pDC);}if (type == 10){if (go){pDC->SetROP2(R2_NOTXORPEN);m_pline->NewDraw(pDC);}elsego = true;m_pline->Set_end_point(point);m_pline->NewDraw(pDC);}if (type == 2){if (go){pDC->SetROP2(R2_NOTXORPEN);m_psquare->Draw(pDC);}elsego = true;m_psquare->Set_end_point(point);m_psquare->Draw(pDC);}if (type == 3){if (go){pDC->SetROP2(R2_NOTXORPEN);m_pcircle->Draw(pDC);}elsego = true;m_pcircle->Get_Radius(point);m_pcircle->Draw(pDC);}if (type == 11){if (go){pDC->SetROP2(R2_NOTXORPEN);m_pcircle->NewDraw(pDC);}elsego = true;m_pcircle->Get_Radius(point);m_pcircle->NewDraw(pDC);}if (type == 4)//折线段{if (go){pDC->SetROP2(R2_NOTXORPEN);m_polyline->Draw(pDC);}elsego = true;//绘制封闭图形,当鼠标点接近第一个点时,鼠标显示问号,可以绘制封闭的图形if (dis_to_another(point, m_polyline->polyline_pts[0]) <= 8&& m_polyline->point_num>2){SetCursor(LoadCursor(NULL, IDC_HELP));m_polyline->Set_end_point(m_polyline->polyline_pts[0]);m_polyline->is_closed = 1;}else{SetCursor(LoadCursor(NULL, IDC_ARROW));m_polyline->Set_end_point(point);m_polyline->is_closed = 0;}m_polyline->Draw(pDC);}}ReleaseDC(pDC);CView::OnMouseMove(nFlags, point);
}

在鼠标移动函数onmousemove里,采用了参考文章里的反色笔(其实就是用颜色进行异或,相同颜色异或两次就恢复成背景色)处理方法避免动态绘制里出现的重影,也可以采用双缓冲方式(此处不赘述)。 

保存图形的链表

在参考文章的基础上实现了node类的串行化,可以将数据存入文件。 

类的串行化方法见:https://blog.csdn.net/qq_61814350/article/details/133870684

 Node.h和cpp

#pragma once
class Node :public CObject
{DECLARE_SERIAL(Node)
public:void* data;int now_type;Node* next;Node();void Serialize(CArchive& archive);
};
#include "pch.h"
#include "Node.h"
#include "CLine.h"
#include "CCircle.h"
#include  "CPolyline.h"
#include"CPolyBezier.h"
#include"CVerticalLine.h"
#include"CIntersectPoint.h"
#include"CQuare.h"
#include"CBSpline.h"
IMPLEMENT_SERIAL(Node, CObject, 1)
Node::Node()
{data = NULL;now_type = 1;next = NULL;
}void Node::Serialize(CArchive& ar)
{if (ar.IsStoring()){ar << now_type;if (now_type == 1){ar << ((CLine*)data)->Get_start_point() << ((CLine*)data)->Get_end_point();}if (now_type == 2){ar << ((CQuare*)data)->Get_first_point() << ((CQuare*)data)->Get_end_point();}if (now_type == 3){ar << ((CCircle*)data)->Get_m_CenPoint() << ((CCircle*)data)->Get_m_Radius();}if (now_type == 4){int pnum = ((CPolyline*)data)->Get_point_num();ar << pnum;for (int i = 0; i < pnum; i++){ar << ((CPolyline*)data)->polyline_pts[i];}}if (now_type == 5){for (int i = 0; i < 4; i++){ar << ((CPolyBezier*)data)->pts[i];}}if (now_type == 6){ar << ((CVerticalLine*)data)->Get_start_point() << ((CVerticalLine*)data)->Get_end_point();}if (now_type == 8){CBSpline* bstemp = ((CBSpline*)data);int tnum = bstemp->nPoints;ar <<tnum <<bstemp->linewidth<<bstemp->is_on_changed;for (int i = 0; i < tnum; i++){ar << bstemp->xcoordinate[i] << bstemp->ycoordinate[i];}}}else{CPoint tempp; int tempr;ar >> now_type;if (now_type == 1){data = new CLine;//注意这里要创建一个类对象让data指向ar >> tempp;((CLine*)data)->Set_start_point(tempp);ar >> tempp;((CLine*)data)->Set_end_point(tempp);}if (now_type == 2){data = new CQuare;ar >> tempp;((CQuare*)data)->Set_first_point(tempp);ar >> tempp;((CQuare*)data)->Set_end_point(tempp);}if (now_type == 3){data = new CCircle;ar >> tempp;((CCircle*)data)->Set_CenPoint(tempp);ar >> tempr;((CCircle*)data)->Set_m_Radius(tempr);}if (now_type == 4){data = new CPolyline;ar >> tempr;((CPolyline*)data)->Set_point_num(tempr);for (int i = 0; i < tempr; i++){ar >> ((CPolyline*)data)->polyline_pts[i];}}if (now_type == 5){data = new CPolyBezier;for (int i = 0; i < 4; i++){ar >> ((CPolyBezier*)data)->pts[i];}}if (now_type == 6){data = new CVerticalLine;ar >> tempp;((CVerticalLine*)data)->Set_start_point(tempp);ar >> tempp;((CVerticalLine*)data)->Set_end_point(tempp);}if (now_type == 8){data = new CBSpline;ar >> ((CBSpline*)data)->nPoints >> ((CBSpline*)data)->linewidth >> ((CBSpline*)data)->is_on_changed;int tnum = ((CBSpline*)data)->nPoints;for (int i = 0; i < tnum; i++){ar >> ((CBSpline*)data)->xcoordinate[i] >> ((CBSpline*)data)->ycoordinate[i];}}}
}

列表的定义:

#pragma once
#include"Node.h"class CSlist
{public:CSlist();~CSlist();Node* first;void InputFront(Node* Pelem);//在前面插入最新的一个节点int Length()const;//判断链表长度bool IsEmpty()const;//判断链表是否为空void MakeEmpty();//将链表清空Node* Locate(int i);//将第i个数据取出int Input_behind_pos(Node* Pelem, int pos);//在第几个数值之后插入新节点int Input_before_pos(Node* Pelem, int pos);void Delete(int pos);};
#include "pch.h"
#include "CSlist.h"#include"Node.h"CSlist::CSlist()
{first = NULL;
}
CSlist::~CSlist()
{MakeEmpty();
}void CSlist::InputFront(Node* Pelem)//头插法
{if (Pelem == NULL)  return;Pelem->next = first;first = Pelem;
}
int CSlist::Length()const
{if (first == NULL)   return 0;Node* n = first;int length = 1;while (n->next){length++;n = n->next;}return length;
}
bool CSlist::IsEmpty()const
{if (first == NULL){return true;}else{return false;}
}
void CSlist::MakeEmpty()
{Node* d;while (first){d = first;first = first->next;delete d;}return;
}
Node* CSlist::Locate(int i)
{int j = 1;Node* L = first;while (L){if (j == i){return L;}else  L = L->next;j++;}}
int CSlist::Input_behind_pos(Node* Pelem, int pos)
{Node* d = Locate(pos + 1);Pelem->next = d;//新节点的next指向原来的下一个节点Node* c = Locate(pos);c->next = Pelem;//上一个节点的next指向新节点return 1;
}
int CSlist::Input_before_pos(Node* Pelem, int pos)
{Node* c = Locate(pos - 1);c->next = Pelem;//上一个节点的next指向新节点Node* d = Locate(pos);Pelem->next = d;//新节点的next指向原来的下一个节点return 1;
}
void CSlist::Delete(int pos)
{Node* a = Locate(pos - 1);Node* b = Locate(pos);Node* c = Locate(pos + 1);a->next = c;delete b;
}

Doc类重写序列化函数:

void CSimpleDrawDoc::Serialize(CArchive& ar)
{POSITION pos = GetFirstViewPosition();CSimpleDrawView* pView = (CSimpleDrawView*)GetNextView(pos);if (ar.IsStoring()){int nCount = pView->m_line_list.Length();ar << nCount;for (int i = 1; i <= nCount; i++){ar << pView->m_line_list.Locate(i);}ar << pView->insect_num;int j = pView->insect_num;for (int i = 0; i < j; i++){ar << pView->m_intersectp[i].Get_point();}}else{int nCount;ar >> nCount;Node* pGraph;for (int i = 1; i <= nCount; i++){ar >> pGraph;pView->m_line_list.InputFront(pGraph);}ar >> pView->insect_num;int j = pView->insect_num;for (int i = 0; i < j; i++){CPoint tempp;ar >> tempp;pView->m_intersectp[i].Set_point(tempp);}}
}

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

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

相关文章

使用Map.clear()、List.clear()方法,清空时注意!

对 Map、List 对象进行清空操作时&#xff0c;常常会使用 clear() 方法。 例如&#xff0c;清空 Map Map map new HashMap();map.put("key1","value1");map.put("key2","value2");System.out.println(map.size()); //2map.clear();Sy…

.gitignore文件设置了忽略但不生效,git提交过程解析

这里写目录标题 第一章、gitignore文件设置了忽略路径&#xff0c;但是不生效1.1&#xff09;原因1.2&#xff09;解决 第一章、gitignore文件设置了忽略路径&#xff0c;但是不生效 1.1&#xff09;原因 在初次提交代码的时候&#xff0c;没有进行文件忽略&#xff0c;某些文…

【Python_PySide6学习笔记(三十一)】基于PySide6实现自定义串口设备连接界面类:可实现串口连接断开、定时发送等功能

基于PySide6实现自定义串口设备连接界面类:可实现串口连接关闭、定时发送等功能 基于PySide6实现自定义串口设备连接界面类:可实现串口连接关闭、定时发送等功能前言一、界面布局二、串口相关功能实现三、完整代码四、调用方法五、实现效果基于PySide6实现自定义串口设备连接…

快慢指针-Floyd判圈算法

对于环形链表是否存在环的做法&#xff0c;普通算法可以通过额外Hash数组来存储链表元素&#xff0c;直到Hash数组中出现重复元素。时间复杂度O(n)&#xff0c;空间复杂度O(n) Floyd判圈算法通过利用快慢指针的移动来实现&#xff0c;时间复杂度O&#xff08;n&#xff09;&am…

hash 路由和 history 路由的区别

Hash 路由&#xff08;Hash Routing&#xff09;&#xff1a; URL 结构&#xff1a; 使用URL中的哈希部分&#xff08;#&#xff09;来表示不同的路由。例如&#xff0c;http://example.com/#/page1。实现方式&#xff1a; 前端路由器通过监听 window.onhashchange 来判断路由的…

Java进阶之旅第三天

Java进阶之旅第三天 文章目录 Java进阶之旅第三天TreeMap特点:题目 使用TreeMap进行数据统计题目: TreeMap 特点: 1.TreeMap根TreeSet底层原理一样,都是红黑树结构2.由键决定特性: 不重复,无索引,可排序3.可排序: 对键进行牌序注意: 默认按照键的从小到大进行排序,也可以自己…

【备战蓝桥杯】今天给大家整点解压的~

【备战蓝桥杯】今天给大家整点解压的~ 蓝桥杯备赛 | 洛谷做题打卡day8 文章目录 【备战蓝桥杯】今天给大家整点解压的~ 蓝桥杯备赛 | 洛谷做题打卡day8[NOIP2017 普及组] 成绩题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提…

【C语言编程之旅 1】刷题篇-初识c语言

文章目录 第一题答案及解析 第二题答案及解析 第三题答案及解析 第四题答案及解析 第五题答案及解析 第六题答案及解析 第一题 答案及解析 C语言中内置类型包括&#xff1a; char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更长的整形 float //单精…

ArcGIS Pro 拓扑编辑和常见一些拓扑错误处理

7.4 拓扑编辑 拓扑编辑也叫共享编辑&#xff0c;多个数据修改时&#xff0c;一块修改&#xff0c;如使用数据&#xff1a;chp7\拓扑检查.gdb,数据集DS下JZX、JZD和DK&#xff0c;加载地图框中&#xff0c;在“地图”选项卡下选择“地图拓扑”或“ds_Topology(地理数据库)”&…

Oracle-java下载、开源/商业许可证(收费、免费说明)、版本发布日志

Oracle-java下载、开源/商业许可证&#xff08;收费、免费说明&#xff09;、版本发布日志 下载开源/商业许可证&#xff08;收费、免费说明&#xff09;java8版本发布日志以上是一般情况&#xff0c;具体的以官网发布信息为准 下载 下载地址&#xff1a;https://www.oracle.c…

google cloud storage批量文件下载

背景&#xff1a; 一些google cloud storage文件的下载是需要付费的&#xff0c;一些是不需要的&#xff0c;不需要的直接点击下方的下载按钮即可&#xff0c;但是常常存在大量的文件下载&#xff0c;挨个下载有点费时间而且占内存&#xff0c;所以我尝试了批量下载到HPC&…

前端面试题-webpack

1.webpack是什么&#xff1f; 模块打包工具&#xff0c;用于将前端资源&#xff0c;如JavaScript、css、图片等打包成可以在浏览器运行的静态资源。可以将多个模块打包成一个或多个bundle。 主要功能&#xff1a; 模块化&#xff1a;可以将多个模块打包成一个或多个bundle&…

day17 二叉树part04

110. 平衡二叉树 简单 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 class Solution {public boolean isBalanced(TreeNode root) {re…

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (3) | 正则化与最优化

前言 &#x1f4da; 笔记专栏&#xff1a;斯坦福CS231N&#xff1a;面向视觉识别的卷积神经网络&#xff08;23&#xff09;&#x1f517; 课程链接&#xff1a;https://www.bilibili.com/video/BV1xV411R7i5&#x1f4bb; CS231n: 深度学习计算机视觉&#xff08;2017&#xf…

智能代码:生成式 AI 在软件开发中的革命性角色

想象一下&#xff0c;在智能手机革命性地改变了我们的生活之后&#xff0c;现在轮到了生成式 AI 在软件开发领域掀起风暴。你知道吗&#xff0c;如果代码能自己编写自己&#xff0c;这将是多么惊人的一步&#xff1f;这就好比我们现在能轻松地用手机应用管理日常生活一样&#…

【嘉立创EDA-PCB设计指南】1.PCB基本概念及原理图绘制

前言&#xff1a;本文详解PCB基本概念以及实现MCU最小系统原理图的绘制&#xff08;原理图包括MCU芯片GD32F103C8T6、外部晶振、输出端口、USB输入口、5v转3v3稳压输出、复位按键、唤醒按键、LED&#xff09;。为本专栏后面章节实现PCB绘制做准备。 最终绘制的原理图如下所示&…

代码随想录算法训练营第二十八天| 93.复原IP地址、78.子集 、90.子集II

代码随想录算法训练营第二十八天| 93.复原IP地址、78.子集 、90.子集II 题目 93.复原IP地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1…

2019年认证杯SPSSPRO杯数学建模B题(第二阶段)外星语词典全过程文档及程序

2019年认证杯SPSSPRO杯数学建模 基于统计和迭代匹配的未知语言文本片段提取模型 B题 外星语词典 原题再现&#xff1a; 我们发现了一种未知的语言&#xff0c;现只知道其文字是以 20 个字母构成的。我们已经获取了许多段由该语言写成的文本&#xff0c;但每段文本只是由字母…

注意!不清楚这些,2024上半年软考别轻易尝试!

看着周围的朋友们纷纷去考软考&#xff0c;很多人也跃跃欲试了吧。那我劝你&#xff0c;如果不清楚这些&#xff0c;不要轻易考2024年软考&#xff01; 01 软考介绍 软考是计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试的简称&#xff0c;由工信部、人社部领导…