OpenGL ES案例学习-画板

#import "PaintView.h"
#import <QuartzCore/QuartzCore.h>
#import <GLKit/GLKit.h>
#import <OpenGLES/EAGLDrawable.h>
#import "debug.h"
#import "shaderUtil.h"
#import "fileUtil.h"
//画笔透明度
#define kBrushOpacity        (1.0 / 2.0)
//画笔每一笔,有几个点!
#define kBrushPixelStep        2
//画笔的比例
#define kBrushScale            2enum {PROGRAM_POINT, //0,NUM_PROGRAMS   //1,有几个程序
};enum {UNIFORM_MVP,         //0UNIFORM_POINT_SIZE,  //1UNIFORM_VERTEX_COLOR,//2UNIFORM_TEXTURE,     //3NUM_UNIFORMS         //4
};enum {ATTRIB_VERTEX, //0NUM_ATTRIBS//1
};//定义一个结构体
typedef struct {//vert,frag 指向顶点、片元着色器程序文件char *vert, *frag;//创建uniform数组,4个元素,数量由你的着色器程序文件中uniform对象个数GLint uniform[NUM_UNIFORMS];GLuint infoId;
} programInfo_t;//注意数据结构
/*programInfo_t 结构体,相当于数据类型program 数组名,相当于变量名NUM_PROGRAMS 1,数组元素个数"point.vsh"和"point.fsh";2个着色器程序文件名是作为program[0]变量中vert,frag2个字符指针的值。uniform 和 id 是置空的。*/programInfo_t program[NUM_PROGRAMS] = {{ "pointv.vsh",   "pointf.fsh" },
};//纹理
typedef struct {GLuint textureId;GLsizei width, height;
} textureInfo_t;@implementation DrawPoint
- (instancetype)initWithCgpoint:(CGPoint)point {if (self = [super init]) {self.mX = [NSNumber numberWithFloat:point.x];self.mY = [NSNumber numberWithFloat:point.y];}return self;
}
@end@interface PaintView()
{//后备缓冲区的像素尺寸GLint backingWidth;GLint backingHeight;EAGLContext *context;//缓存区frameBuffer\renderBufferGLuint viewRenderBuffer,viewFrameBuffer;//画笔纹理,画笔颜色textureInfo_t brushTexture;GLfloat brushColor[4];//是否第一次点击Boolean firstTouch;//是否需要清屏Boolean needsErase;//shader object 顶点Shader、片元Shader、ProgramGLuint vertexShader;GLuint fragmentShader;GLuint shaderProgram;//VBO 顶点BufferGLuint vboId;//是否初始化BOOL initialized;//点NSMutableArray <DrawPoint *>* pointArr;}@end@implementation PaintView
- (instancetype) initWithFrame:(CGRect)frame{if (self = [super initWithFrame: frame]) {CAEAGLLayer *eagLayer = (CAEAGLLayer *)self.layer;eagLayer.opaque = YES;eagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];if (context == nil || ![EAGLContext setCurrentContext:context]) {return nil;}self.contentScaleFactor =  [[UIScreen mainScreen] scale];needsErase = YES;}return  self;
}
- (void)layoutSubviews {[EAGLContext setCurrentContext:context];if (!initialized) {initialized = [self initGL];} else {[self resizeFromLayer:(CAEAGLLayer *)self.layer];}if (needsErase) {[self clearScren];needsErase = NO;}
}-(BOOL)initGL {//1.glGenRenderbuffers(1, &viewRenderBuffer);glGenFramebuffers(1, &viewFrameBuffer);//绑定glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer);glBindFramebuffer(GL_FRAMEBUFFER, viewFrameBuffer);//[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>) self.layer];//attachglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderBuffer);// 获取绘制缓存区的宽和高glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);//检查framebuffer 状态if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {NSLog(@"make complete framebuffer failed");return NO;}glViewport(0, 0, backingWidth, backingHeight);/// 顶点缓冲区glGenBuffers(1, &vboId);// 加载画笔brushTexture = [self textureFromName:@"Particle.png"];// 加载shader[self setUpShader];//点模糊glEnable(GL_BLEND);/*GL_ONE_MINUS_CONSTANT_ALPHA在 OpenGL中,GL_ONE_MINUS_CONSTANT_ALPHA是一个混合因子,它的值为1-const ant的alpha分量。在混合方程中,GL_ONE_MINUS_CONSTANT_ALPHA等因子允许在混合过程中引入一个常量混合颜色。这些因子可以用于设置不同通道的颜色混合选项,从而实现丰富的颜色效果。*/glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);///回放路径NSString *path = [[NSBundle mainBundle] pathForResource:@"abc" ofType:@"string"];NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];pointArr = [[NSMutableArray alloc] init];NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];//便利jsonfor (NSDictionary *dict in jsonArray) {DrawPoint *point = [[DrawPoint alloc] initWithCgpoint:CGPointMake([[dict objectForKey:@"mX"] floatValue], [[dict objectForKey:@"mY"] floatValue])];[pointArr addObject:point];}[self performSelector:@selector(paint) withObject:nil afterDelay:0.5];return  YES;
}
-(void)paint {//for (int i = 0; i < pointArr.count - 1; i+=2) {DrawPoint *p1 = pointArr[i];DrawPoint *p2 = pointArr[i+1];CGPoint p3,p4;p3.x = p1.mX.floatValue;p3.y = p1.mY.floatValue;p4.x = p2.mX.floatValue;p4.y = p2.mY.floatValue;//将亮点链接成线[self renderLineFromPoint:p3 end:p4];}
}
-(void)renderLineFromPoint:(CGPoint)start  end:(CGPoint)end {// 顶点缓冲区static GLfloat *vertexBuffer = NULL;// 暂时顶点数static NSUInteger vertexMax = 64;//顶点个数NSUInteger vertexCount = 0, count;// 普通点-<像素点CGFloat scale = self.contentScaleFactor;start.x *= scale;start.y *= scale;end.x *= scale;end.y *= scale;if (vertexBuffer == NULL) {// 开辟顶点缓冲区vertexBuffer = malloc(vertexMax * 2  * sizeof(GLfloat));}/// 亮点之间的距离 statt endfloat seq = sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y));//kBrushPixelStep 值越大笔触越细腻NSInteger pointCount = ceilf(seq/kBrushPixelStep);/// 取最大点数count = MAX(pointCount, 1);// 遍历顶点for (int i = 0; i < count; i++) {/// 当前订单个数大于开辟的空间就需要扩容if (vertexCount >= vertexMax) {vertexMax = 2 * vertexMax;vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));}// start end 距离之间 计算出count个数 并存储在vertexBuffer 中vertexBuffer[2*vertexCount+0] = start.x + (end.x - start.x) * ((GLfloat)i/ (GLfloat)count);vertexBuffer[2*vertexCount+1] = start.y + (end.y - start.y) * ((GLfloat)i/ (GLfloat)count);vertexCount++;}glBindBuffer(GL_ARRAY_BUFFER, vboId);glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);//glglEnableVertexAttribArray(ATTRIB_VERTEX);glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);glUseProgram(program[PROGRAM_POINT].infoId);glDrawArrays(GL_POINTS, 0, (int)vertexCount);///显示glBindBuffer(GL_RENDERBUFFER, viewRenderBuffer);[context presentRenderbuffer:GL_RENDERBUFFER];
}-(textureInfo_t)textureFromName:(NSString *)name {textureInfo_t texture;CGContextRef brushContext;GLubyte    *brushData;size_t width,height;CGImageRef brushImage;GLuint textId;brushImage = [UIImage imageNamed:name].CGImage;width = CGImageGetWidth(brushImage);height = CGImageGetHeight(brushImage);brushData = (GLubyte *)calloc(width * height * 4, sizeof(GLubyte));brushContext = CGBitmapContextCreate(brushData, width, height, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0f, (CGFloat)width, (CGFloat)height), brushImage);CGContextRelease(brushContext);glGenTextures(1, &textId);glBindTexture(GL_TEXTURE_2D, textId);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);/// 获取纹理glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)width,(int)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);free(brushData);texture.textureId = textId;texture.width = (int)width;texture.height =  (int)height;return texture;
}
-(BOOL)resizeFromLayer:(CAEAGLLayer *)layer {//根据当前图层大小分配颜色缓冲区//绑定一个Drawable对象存储到一个OpenGL ES渲染缓存对象。glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer);/*创建一个渲染,可以呈现到屏幕上,你将渲染然后分配共享存储通过调用此方法。这个方法的调用替换通常给glrenderbufferstorage。缓存的存储分配了这个方法以后可以显示一个回调presentrenderbuffer:- (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id<EAGLDrawable>)drawable;为绘制缓冲区分配存储区,此处将CAEAGLLayer的绘制存储区作为绘制缓冲区的存储区参数1:OpenGL ES的结合点为当前绑定的渲染。这个参数的值必须gl_renderbuffer(或gl_renderbuffer_oes在OpenGL ES 1.1语境)参数2:对象管理数据存储区中的渲染。在iOS中,这个参数的值必须是一个CAEAGLLayer对象*/[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];获取绘制缓存区的像素宽度 --将绘制缓存区像素宽度存储在backingWidthglGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);获取绘制缓存区的像素高度--将绘制缓存区像素高度存储在backingHeightglGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);//检查GL_FRAMEBUFFER缓存区状态if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {NSLog(@"Make compelete framebuffer object failed!%x",glCheckFramebufferStatus(GL_FRAMEBUFFER));return NO;}//更新投影矩阵、模型视图矩阵// 投影矩阵/*投影分为正射投影和透视投影,我们可以通过它来设置投影矩阵来设置视域,在OpenGL中,默认的投影矩阵是一个立方体,即x y z 分别是-1.0~1.0的距离,如果超出该区域,将不会被显示正射投影(orthographic projection):GLKMatrix4MakeOrtho(float left, float righ, float bottom, float top, float nearZ, float farZ),该函数返回一个正射投影的矩阵,它定义了一个由 left、right、bottom、top、near、far 所界定的一个矩形视域。此时,视点与每个位置之间的距离对于投影将毫无影响。透视投影(perspective projection):GLKMatrix4MakeFrustum(float left, float right,float bottom, float top, float nearZ, float farZ),该函数返回一个透视投影的矩阵,它定义了一个由 left、right、bottom、top、near、far 所界定的一个平截头体(椎体切去顶端之后的形状)视域。此时,视点与每个位置之间的距离越远,对象越小。在平面上绘制,只需要使正投影就可以了!!*/GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, backingWidth, 0, backingHeight, -1, 1);// //模型矩阵,比如你要平移、旋转、缩放,就可以设置在模型矩阵上//这里不需要这些变换,则使用单元矩阵即可,相当于1 * ? = ?GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;//矩阵相乘,就2个矩阵的结果交给MVPMatrixGLKMatrix4 MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);/*void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);功能:为当前程序对象指定uniform变量值参数1:location 指明要更改的uniform变量的位置 MVP参数2:count 指定将要被修改的矩阵的数量参数3:transpose 矩阵的值被载入变量时,是否要对矩阵进行变换,比如转置!参数4:value ,指向将要用于更新uniform变量MVP的数组指针*//// 传递到vshglUniformMatrix4fv(program[PROGRAM_POINT].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);//更新视口glViewport(0, 0, backingWidth, backingHeight);return YES;
}
-(void)setUpShader{for (int i = 0; i < NUM_PROGRAMS; i++) {char *vsrc = readFile(pathForResource(program[i].vert));char *fsrc = readFile(pathForResource(program[i].frag));//        NSString *vsrcString = [[NSString alloc] initWithBytes:vsrc length:strlen(vsrc) - 1 encoding:NSUTF8StringEncoding];
//        NSString *fsrcString = [[NSString alloc] initWithBytes:fsrc length:strlen(fsrc) - 1 encoding:NSUTF8StringEncoding];GLsizei attribCt = 0;GLchar *attribUsed[NUM_ATTRIBS];GLint attrib[NUM_ATTRIBS];GLchar *attribName[NUM_ATTRIBS] = {"inVertex"};GLchar *uniformName[NUM_UNIFORMS] = {"MVP","pointSize","vertexColor","texture"};for (int j = 0; j < NUM_ATTRIBS; j++) {if (strstr(vsrc, attribName[j])) {attrib[attribCt] = j;attribUsed[attribCt++] = attribName[j];}}glueCreateProgram(vsrc, fsrc, attribCt, (const GLchar **) &attribUsed[0], attrib, NUM_UNIFORMS, (const GLchar **)&uniformName[0], program[i].uniform, &program[i].infoId);free(vsrc);free(fsrc);if (PROGRAM_POINT == i) {glUseProgram(program[PROGRAM_POINT].infoId);glUniform1i(program[PROGRAM_POINT].uniform[UNIFORM_TEXTURE], 0);/// 更新投影/模型视图矩阵 --正投影GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, backingWidth, 0, backingHeight, -1, 1);GLKMatrix4 modelviewMatrix = GLKMatrix4Identity;//GLKMatrix4 MVPMatrix = GLKMatrix4Multiply(projectionMatrix,modelviewMatrix);glUniformMatrix4fv(program[PROGRAM_POINT].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);///点大小glUniform1f(program[PROGRAM_POINT].uniform[UNIFORM_POINT_SIZE], brushTexture.width/kBrushScale);/// 笔刷颜色glUniform4fv(program[PROGRAM_POINT].uniform[UNIFORM_VERTEX_COLOR], 1, brushColor);}}
}- (void)setBrushColorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue {// 获取需要更新的颜色brushColor[0] = red * kBrushOpacity;brushColor[1] = green * kBrushOpacity;brushColor[2] = blue * kBrushOpacity;brushColor[3] = kBrushOpacity;// 判断是否初始化图层if (initialized) {glUseProgram(program[PROGRAM_POINT].infoId);// 将颜色通过uniform传递到顶点着色器glUniform4fv(program[PROGRAM_POINT].uniform[UNIFORM_VERTEX_COLOR], 1, brushColor);}}
- (void)clearScren {//1.清空viewFrameBufferglBindFramebuffer(GL_FRAMEBUFFER, viewFrameBuffer);glClearColor(0, 0, 0, 1.0);glClear(GL_COLOR_BUFFER_BIT);//2. viewRenderBuffer 重新渲染glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer);[context presentRenderbuffer:GL_RENDERBUFFER];}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {CGRect bounds = [self bounds];UITouch *touch = [[event touchesForView:self] anyObject];firstTouch = YES;_location = [touch locationInView:self];_location.y = bounds.size.height - _location.y;
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {CGRect bounds = [self bounds];UITouch *touch = [[event touchesForView:self] anyObject];if (firstTouch) {firstTouch = NO;/// 获取上一次点击的位置_previousLocation = [touch previousLocationInView:self];_previousLocation.y = bounds.size.height - _previousLocation.y;} else {_location = [touch locationInView:self];_location.y = bounds.size.height - _location.y;_previousLocation = [touch previousLocationInView:self];_previousLocation.y = bounds.size.height - _previousLocation.y;}//p1 p2[self renderLineFromPoint:_previousLocation end:_location];}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {CGRect bounds = [self bounds];UITouch *touch = [[event touchesForView:self] anyObject];if (firstTouch) {firstTouch = NO;/// 获取上一次点击的位置_previousLocation = [touch previousLocationInView:self];_previousLocation.y = bounds.size.height - _previousLocation.y;[self renderLineFromPoint:_previousLocation end:_location];}
}+(Class)layerClass
{return [CAEAGLLayer class];
}
-(void)dealloc
{//安全释放viewFrameBuffer、viewRenderBuffer、brushTexture、vboId、contextif (viewFrameBuffer) {glDeleteFramebuffers(1, &viewFrameBuffer);viewFrameBuffer = 0;}if (viewRenderBuffer) {glDeleteRenderbuffers(1, &viewRenderBuffer);viewRenderBuffer = 0;}if (brushTexture.textureId) {glDeleteTextures(1, &brushTexture.textureId);brushTexture.textureId = 0;}if (vboId) {glDeleteBuffers(1, &vboId);vboId = 0;}if ([EAGLContext currentContext] == context) {[EAGLContext setCurrentContext:nil];}
}/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {// Drawing code
}
*/@end

初始化上下文

- (instancetype) initWithFrame:(CGRect)frame{if (self = [super initWithFrame: frame]) {CAEAGLLayer *eagLayer = (CAEAGLLayer *)self.layer;eagLayer.opaque = YES;eagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];if (context == nil || ![EAGLContext setCurrentContext:context]) {return nil;}self.contentScaleFactor =  [[UIScreen mainScreen] scale];needsErase = YES;}return  self;
}

顶点着色器

//顶点
attribute vec4 inVertex;
//矩阵
uniform mat4 MVP;
//点的大小
uniform float pointSize;
//点的颜色
uniform lowp vec4 vertexColor;
//输出颜色
varying lowp vec4 color;
void main() {//顶点计算 = 矩阵 * 顶点gl_Position = MVP * inVertex;//修改顶点大小gl_PointSize = pointSize;//    1 * 3.0;//将通过uniform 传递进来的颜色,从顶点着色器程序传递到片元着色器color = vertexColor;
}

片元着色器

//获取纹理
uniform sampler2D texture;
/*sampler2D,中的2D,表示这是一个2D纹理。我们也可以使用1D\3D或者其他类型的采样器。我们总是把这个值设置为0。来指示纹理单元0.*/
//获取从顶点程序传递过来的颜色
//lowp,精度
varying lowp vec4 color;
void main() {//将颜色和纹理组合 是相乘!!!!gl_FragColor = color * texture2D(texture,gl_PointCoord);
}

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

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

相关文章

mobilevit v3 学习笔记

目录 原理讲解:不是特别全,可供参考: torch实现代码: 有预训练:

深信服AF防火墙配置SSL VPN

防火墙版本&#xff1a;8.0.85 需提前确认防火墙是是否有SSL VPN的授权&#xff0c;确认授权用户数量 1、确认内外网接口划分 2、网络→SSL VPN&#xff0c;选择内外网接口地址 3、SSL VPN→用户管理→新增一个SSL VPN的用户 4、新增L3VPN资源&#xff0c;类型选择Other&…

【基础】【Python网络爬虫】【1.认识爬虫】什么是爬虫,爬虫分类,爬虫可以做什么

Python网络爬虫基础 认识爬虫1.什么是爬虫2.爬虫可以做什么3.为什么用 Ptyhon 爬虫4.爬虫的分类通用爬虫聚焦爬虫功能爬虫增量式爬虫分布式爬虫 5.爬虫的矛与盾&#xff08;重点&#xff09;6.盗亦有道的君子协议robots7.爬虫合法性探究 认识爬虫 1.什么是爬虫 网络爬虫&…

第5课 使用openCV捕获摄像头并实现预览功能

这节课我们开始利用ffmpeg和opencv来实现一个rtmp推流端。推流端的最基本功能其实就两个:预览画面并将画面和声音合并后推送到rtmp服务器。 一、FFmpeg API 推流的一般过程 1.引入ffmpeg库&#xff1a;在代码中引入ffmpeg库&#xff0c;以便使用其提供的功能。 2.捕获摄像头…

MongoDB的基本使用

MongoDB的引出 使用Redis技术可以有效的提高数据访问速度&#xff0c;但是由于Redis的数据格式单一性&#xff0c;无法操作结构化数据&#xff0c;当操作对象型的数据时&#xff0c;Redis就显得捉襟见肘。在保障访问速度的情况下&#xff0c;如果想操作结构化数据&#xff0c;…

Spark中的数据加载与保存

Apache Spark是一个强大的分布式计算框架&#xff0c;用于处理大规模数据。在Spark中&#xff0c;数据加载与保存是数据处理流程的关键步骤之一。本文将深入探讨Spark中数据加载与保存的基本概念和常见操作&#xff0c;包括加载不同数据源、保存数据到不同格式以及性能优化等方…

20231231_小米音箱接入GPT

参考资料&#xff1a; GitHub - yihong0618/xiaogpt: Play ChatGPT and other LLM with Xiaomi AI Speaker *.设置运行脚本权限 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned *.配置小米音箱 ()pip install miservice_fork -i https://pypi.tuna.tsinghua.edu.cn/sim…

算法逆袭之路(1)

11.29 开始跟进算法题进度! 每天刷4题左右 ,一周之内一定要是统一类型 而且一定稍作总结, 了解他们的内在思路究竟是怎样的!! 12.24 一定要每天早中晚都要复习一下 早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义 12.26/27&#xff1a; 斐波那契数 爬…

B3610 [图论与代数结构 801] 无向图的块 题解

B3610 [图论与代数结构 801] 无向图的块 题解 2023 2023 2023&#xff0c;再见。 2024 2024 2024&#xff0c;你好&#xff01; 解法 其实就是统计点双连通分量的个数。需要注意的是&#xff0c;孤立点在这里不被看作块。本文使用 tarjan 算法来解决这道题。 概念明晰 时间…

机器学习:贝叶斯估计在新闻分类任务中的应用

文章摘要 随着互联网的普及和发展&#xff0c;大量的新闻信息涌入我们的生活。然而&#xff0c;这些新闻信息的质量参差不齐&#xff0c;有些甚至包含虚假或误导性的内容。因此&#xff0c;对新闻进行有效的分类和筛选&#xff0c;以便用户能够快速获取真实、有价值的信息&…

【完整思路】2023 年中国高校大数据挑战赛 赛题 B DNA 存储中的序列聚类与比对

2023 年中国高校大数据挑战赛 赛题 B DNA 存储中的序列聚类与比对 任务 1.错误率和拷贝数分析&#xff1a;分析“train_reads.txt”和“train_reference.txt”数据集中的错误率&#xff08;插入、删除、替换、链断裂&#xff09;和序列拷贝数。 2.聚类模型开发&#xff1a;开发…

Unity坦克大战开发全流程——结束场景——失败界面

结束场景——失败界面 在玩家类中重写死亡函数 在beginPanel中锁定鼠标

Redis 分布式锁总结

在一个分布式系统中,由于涉及到多个实例同时对同一个资源加锁的问题,像传统的synchronized、ReentrantLock等单进程情况加锁的api就不再适用,需要使用分布式锁来保证多服务实例之间加锁的安全性。常见的分布式锁的实现方式有zookeeper和redis等。而由于redis分布式锁相对于比…

搭建普罗米修斯Prometheus,并监控MySQL

1.简介 prometheus是一种时间序列的数据库&#xff0c;适合应用于监控以及告警&#xff0c;但是不适合100%的准确计费&#xff0c;因为采集的数据不一定很准确&#xff0c;主要是作为监控以及收集内存、CPU、硬盘的数据。 Prometheus生态系统由多个组件组成&#xff0c;其中许…

积水监测识别摄像机

积水监测识别摄像机是一种利用摄像技术来监测和识别道路、桥梁、隧道等区域积水情况的设备&#xff0c;它可以有效地提供实时的积水监测信息&#xff0c;帮助交通部门和相关单位及时采取应对措施&#xff0c;确保道路交通的畅通和人员安全。 积水监测识别摄像机通过安装在适当位…

STM32F407ZGT6定时器(学习笔记二)

STM32F407ZGT6定时器&#xff08;学习笔记一&#xff09;-CSDN博客这篇文章中已经对前三种定时器的使用进行了介绍&#xff0c;本篇文章将介绍&#xff08;1&#xff09;输入捕获之计算方波时长&#xff0c;&#xff08;2&#xff09;输入捕获之编码器模式。 高级定时器和通用定…

【深入之Java进阶篇】fastjson的反序列化漏洞(详解总结)

✔️ fastjson的反序列化漏 1️⃣典型解析2️⃣拓展知识仓1️⃣AutoType2️⃣AutoType 有何错?3️⃣ 绕过checkAutotype&#xff0c;黑客与fastjson的博弈4️⃣autoType不开启也能被攻击?5️⃣利用异常进行攻击6️⃣AutoType 安全模式? 1️⃣典型解析 当我们使用fastjson进行…

mllib可扩展学习库java api使用

mllib可扩展学习库java api是使用Apache Spark构建的机器学习库&#xff0c;包括分类&#xff0c;聚类&#xff0c;特征提取和预处理等功能。本文将从以下几个方面详细介绍如何使用mllib可扩展学习库java api。 一、数据预处理 数据预处理是机器学习的重要步骤之一&#xff0…

2023.12.28 Python高级-正则表达式

目录 re正则表达式,一种专门用来匹配目标字符串的规则 re.match(),从头匹配一个,无则none re.search(), 不从头匹配返回一个,无则none re.findall(), 不从头匹配,用list返回所有 re分组 re匹配修饰符 re贪婪非贪婪 re切割和替换 re正则表达式,一种专门用来匹配目标字符串…

linux的页缓存page cache

目录 如何查看系统的 Page Cache&#xff1f; 为什么 Linux 不把 Page Cache 称为 block cache&#xff1f; Page Cache 的优劣势 Page Cache 的优势 加快数据访问 减少 IO 次数&#xff0c;提高系统磁盘 I/O 吞吐量 Page Cache 的劣势 由于我们开发的程序要运行的话一般…