阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

贝塞尔曲线在 iOS 端的绘图实践

  • 2020-09-15
  • 本文字数:9102 字

    阅读完需:约 30 分钟

贝塞尔曲线在iOS端的绘图实践

1 前言

在这个大数据的时代,很多信息只有通过图形才能更好的展示给用户。例如:房屋的历史价格、基金股票的历史增长、数据占比分析图等。如何做图形?需要用到什么知识?本文将从 建模、显示 两方面来展开介绍。


2 建模

建模是一切图形的基础,其他内容的前提,要用代码展示一个图形,首先要有它的几何模型表达。目前在客户端二维图形建模上,Bézier curve(贝塞尔曲线)可以称为 经典 和 主流 并重的数学曲线。


对于贝塞尔曲线来说,最重要的是 起始点、终止点(也称锚点)、控制点。控制点决定了一条路径的弯曲轨迹,根据控制点的个数,贝塞尔曲线被分为:一阶贝塞尔曲线(0 个控制点)、二阶贝塞尔曲线(1 个控制点)、三阶贝塞尔曲线(2 个控制点)、N 阶贝塞尔曲线(n - 1 个控制点)。

2.1 贝塞尔曲线原理

以二阶贝塞尔曲线为例 解释说明:


起始点:P0 ; 控制点:P1 ; 终止点:P2



  1. 连接 P0P1 线 和 P1P2 线。

  2. 在 P0P1 线上找到点 A,在 P1P2 线上找到点 B,使得 P0A/AP1 = P1B/BP2

  3. 连接 AB,在 AB 上找到点 X,X 点满足:AX/XB = P0A/AP1 = P1B/BP2

  4. 找出所有满足公式:AX/XB = P0A/AP1 = P1B/BP2 的 X 点。(从 P0 到 P2 的红色曲线点为所有 X 点的连线)这条由所有 X 点组成的连线 即为 贝塞尔曲线。


二阶贝塞尔曲线 起始点:P0 ; 控制点:P1 ; 终止点:P2



三阶贝塞尔曲线 起始点:P0 ; 控制点:P1、P2; 终止点:P3



四阶贝塞尔曲线 起始点:P0 ; 控制点:P1、P2、P3 ; 终止点:P4


2.2 UIBezierPath 类

系统给我们提供了一个叫做 UIBezierPath 类,用它可以画简单的圆形,椭圆,矩形,圆角矩形,也可以通过添加点去生成任意的图形,还可以简单的创建一条二阶贝塞尔曲线和三阶贝塞尔曲线。我们来了解一下它的常用方法:

2.2.1 初始化方法

// 创建UIBezierPath对象+ (instancetype)bezierPath;// 创建在rect内的矩形+ (instancetype)bezierPathWithRect:(CGRect)rect;// 设定特定的角为圆角的矩形,corners:指定的角为圆角,其他角不变,cornerRadii:圆角的大小+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;// 创建圆弧+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;// 通过已有路径创建路径+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;// 创建三次贝塞尔曲线 endPoint:终点 controlPoint1:控制点1 controlPoint2:控制点2- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;- // 创建二次贝塞尔曲线 endPoint:终点 controlPoint:控制点- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
复制代码

2.2.2 使用方法

// 移动到某一点- (void)moveToPoint:(CGPoint)point;// 绘制一条线- (void)addLineToPoint:(CGPoint)point;// 闭合路径,即在终点和起点连一根线- (void)closePath;// 清空路径- (void)removeAllPoints;// 填充- (void)fill;// 描边,路径创建需要描边才能显示出来- (void)stroke;
复制代码

2.2.3 常用属性

// 将UIBezierPath类转换成CGPath,类似于UIColor的CGColor@property(nonatomic) CGPathRef CGPath;// path线的宽度@property(nonatomic) CGFloat lineWidth;// path端点样式@property(nonatomic) CGLineCap lineCapStyle;// 拐角样式@property(nonatomic) CGLineJoin lineJoinStyle;
复制代码

2.2.4 举个栗子🌰

先看效果👇:



代码如下:


- (void)drawRect:(CGRect)rect {
[[UIColor redColor] set];
// 右边第一个图 UIBezierPath* maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(30, 30)]; maskPath.lineWidth = 20.f; maskPath.lineJoinStyle = kCGLineJoinBevel; [maskPath stroke]; // 中间第二个图 UIBezierPath* maskFillPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(200, 50, 100, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(30, 30)]; maskFillPath.lineWidth = 20.f; maskFillPath.lineJoinStyle = kCGLineJoinBevel; [maskFillPath fill]; [maskFillPath stroke]; // 右边第三个图 UIBezierPath *maskLinePath = [UIBezierPath bezierPath]; maskLinePath.lineWidth = 20.f; maskLinePath.lineCapStyle = kCGLineCapRound; [maskLinePath moveToPoint:CGPointMake(250.0, 50)]; [maskLinePath addLineToPoint:CGPointMake(300.0, 100.0)]; [maskLinePath stroke];}
复制代码


上图中:


1)图一和图二 唯一的不同是[maskFillPath fill]方法,fill 方法要在封闭的曲线调用。


2)图一和图二 为设定特定的角为圆角的矩形,corners 为 UIRectCornerTopLeft 左上角,cornerRadii 圆角大小为 30,绿色的箭头 表示的设定的这个角。


corners 为下面五种类型typedef NS_OPTIONS(NSUInteger, UIRectCorner) {    UIRectCornerTopLeft     = 1 << 0,    // 左上角    UIRectCornerTopRight    = 1 << 1,    // 右上角    UIRectCornerBottomLeft  = 1 << 2,    // 左下角    UIRectCornerBottomRight = 1 << 3,    // 右下角    UIRectCornerAllCorners  = ~0UL        // 全部};
复制代码


3)图一和图二 黄色的箭头 设置的属性 拐角样式:lineJoinStyle kCGLineJoinBevel(缺角)


lineJoinStyle 为下面三种类型typedef CF_ENUM(int32_t, CGLineJoin) {    kCGLineJoinMiter,    // 尖角    kCGLineJoinRound,    // 圆角    kCGLineJoinBevel    // 缺角};
复制代码


4)图三 白色的箭头 设置的属性 path 端点样式:lineCapStyle kCGLineCapRound(圆形端点)


lineCapStyle 为下面三种类型typedef CF_ENUM(int32_t, CGLineCap) {    kCGLineCapButt,        // 无端点    kCGLineCapRound,    // 圆形端点    kCGLineCapSquare    // 方形端点};
复制代码


有兴趣的 可以试试别的方法属性~

2.3 波浪曲线实现

如何实现 N 阶 波浪式曲线?如何找到 N-1 个对应的控制点?


有两个方法,下图为同数据,方案一 和 方案二 分别所得曲线图。


方案一 为左边(三阶贝塞尔)图 其中 第二条的红点 为数据的位置


方案二 为右边(CatmullRom)图 其中 第二条的红点 为数据的位置



方案一:根据 创建三次贝塞尔曲线 方法 实现波浪曲线


控制点的选取方案不唯一,以下为我选择控制点的方案:


控制点 P1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y)


控制点 P2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)


可以根据前一个点 PrePonit 和 现在的点 NowPoint 进行计算 控制点。


主要代码如下:


UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:[self pointAtIndex:0]];NSInteger count = self.points.count;CGPoint PrePonit;
for (NSInteger i = 0; i < count; i++) {
CGPoint NowPoint = [self pointAtIndex:i]; if(i == 0) { PrePonit = NowPoint; } else { // 利用三次曲线 形成波浪曲线 [path addCurveToPoint:point controlPoint1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y) controlPoint2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)]; PrePonit = NowPoint; }}return path;
复制代码


方案二:使用 CatmullRom 插值样条。(有兴趣的可以百度一下~这里只简单介绍)


要点分析:


1)给定一组控制点而得到一条曲线,曲线经过给定所有数据点。


2)Catmull-Rom 公式:P(t) = 0.5 * (2*p1 + (p2 - p0) *t + (2*p0 - 5*p1 + 4*p2 - p3)* t * t + (3*p1 - p0 - 3*p2 + p3) * t * t * t);


注:t 为分割的最小粒尺寸,根据 P0 P1 P2 P3 顺序的四个点 求得 P1P2 曲线公式。


主要代码如下:


void getPointsFromBezier(void *info, const CGPathElement *element) {    NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;    CGPathElementType type = element->type;    CGPoint *points = element->points;
if (type != kCGPathElementCloseSubpath) { [bezierPoints addObject:VALUE(0)]; if ((type != kCGPathElementAddLineToPoint) && (type != kCGPathElementMoveToPoint)) [bezierPoints addObject:VALUE(1)]; } if (type == kCGPathElementAddCurveToPoint) [bezierPoints addObject:VALUE(2)];}
NSArray *pointsFromBezierPath(UIBezierPath *bpath) { NSMutableArray *points = [NSMutableArray array]; // 获取贝塞尔曲线上所有的点 CGPathApply(bpath.CGPath, (__bridge void *)points, getPointsFromBezier); return points;}
- (UIBezierPath*)smoothedPathWithGranularity:(NSInteger)granularity path:(UIBezierPath *)path { NSMutableArray *points = [pointsFromBezierPath(path) mutableCopy];
if (points.count < 4) return [path copy]; [points insertObject:[points objectAtIndex:0] atIndex:0]; [points addObject:[points lastObject]];
UIBezierPath *smoothedPath = [path copy]; [smoothedPath removeAllPoints]; [smoothedPath moveToPoint:POINT(0)];
for (NSUInteger index = 1; index < points.count - 2; index++) { CGPoint p0 = POINT(index - 1); CGPoint p1 = POINT(index); CGPoint p2 = POINT(index + 1); CGPoint p3 = POINT(index + 2);
for (int i = 1; i < granularity; i++) { // granularity 这里按照 20 粒度划分的 float t = (float) i * (1.0f / (float) granularity); float tt = t * t; float ttt = tt * t;
CGPoint pi; // 根据 CatmullRom 公式 根据 P0 P1 P2 P3 获取点的坐标 pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt); pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt); if (pi.x <= self.width) { [smoothedPath addLineToPoint:pi]; } }
if (p2.x <= self.width) { [smoothedPath addLineToPoint:p2]; } }
return smoothedPath;}
复制代码


对比总结:


方案一 控制点的选取比较难,曲线的弯度 也取决于控制点,操作简单,易理解。


方案二 曲线更顺滑,但实现更复杂,不易理解。


这里推荐两个好用的网站:


a 这个网站提供了丰富的曲线类型可供选择,非常直观。


http://easings.net


b 这个网站提供了可视化的修改两个控制点,来生成一条三阶贝塞尔曲线,并切右边还可以看到这条曲线产生的动画会做怎样的速度改变。


http://www.roblaplaca.com/examples/bezierBuilder/#

3 显示

当 layer 与贝塞尔曲线相遇,会发生什么样的神奇反应?

3.1 CALayer

苹果官网注释:“An object that manages image-based content and allows you to perform animations on that content.” 管理基于图像的内容并允许您对该内容执行动画的对象。


CALayer 主要就两方面作用:


1) 管理展示内容


2)内容可执行动画


CALayer 自身有很多情况下自带隐式动画,但是 UIView 的根 Layer 是没有隐式动画的。

3.1.1 常用属性

// 图层大小 支持隐式动画@property CGRect bounds;// 图层位置 支持隐式动画@property CGPoint position;// 在z轴上的位置 支持隐式动画@property CGFloat zPosition;// 沿z轴位置的锚点 支持隐式动画@property CGFloat anchorPointZ;// 锚点 默认在layer的中心点 取值范围(0~1) 支持隐式动画@property CGPoint anchorPoint;// 图层变换 支持隐式动画@property CATransform3D transform;// 图层大小和位置 不支持隐式动画@property CGRect frame;// 是否隐藏 支持隐式动画@property(getter=isHidden) BOOL hidden;// 图层背景是否显示 支持隐式动画@property(getter=isDoubleSided) BOOL doubleSided;// 父图层 支持隐式动画@property(nullable, readonly) CALayer *superlayer;// 子图层 支持隐式动画@property(nullable, copy) NSArray<__kindof CALayer *> *sublayers;// 子图层变换 支持隐式动画@property CATransform3D sublayerTransform;// 图层蒙版 支持隐式动画@property(nullable, strong) __kindof CALayer *mask;// 子图层是否裁切超出父图层的部分,默认为NO@property BOOL masksToBounds;// 图层显示内容 设置layer的contents可以为layer添加显示内容 支持隐式动画@property(nullable, strong) id contents;// 图层显示内容的大小和位置 支持隐式动画@property CGRect contentsRect;// 用于指定层的内容如何在其范围内定位或缩放@property(copy) CALayerContentsGravity contentsGravity;// 是否包含完全不透明内容的布尔值@property(getter=isOpaque) BOOL opaque;// 背景色 支持隐式动画@property(nullable) CGColorRef backgroundColor;// 圆角半径 支持隐式动画@property CGFloat cornerRadius;// 边框宽度 支持隐式动画@property CGFloat borderWidth;// 边框颜色 支持隐式动画@property(nullable) CGColorRef borderColor;// 透明度 支持隐式动画@property float opacity;// 阴影颜色 支持隐式动画@property(nullable) CGColorRef shadowColor;// 阴影透明度 默认为0 需要显示阴影 必须设置值 支持隐式动画@property float shadowOpacity;// 阴影偏移量 支持隐式动画@property CGSize shadowOffset;// 阴影半径 支持隐式动画@property CGFloat shadowRadius;// 阴影形状 支持隐式动画@property(nullable) CGPathRef shadowPath;
复制代码

3.1.2 子类


CALayer 的子类有很多,下面说几个比较常用的。

3.2 CAShapeLayer

苹果官网注释:“A layer that draws a cubic Bezier spline in its coordinate space.” 专门用于绘制贝塞尔曲线的 layer。

3.2.1 看一下它独特的属性:

// path属性是曲线的路径,也是它和贝塞尔曲线紧密连接一个入口,决定了图层上画的是什么形状。@property(nullable) CGPathRef path;// 填充颜色@property(nullable) CGColorRef fillColor;// 曲线 指定哪块区域为内部,内部会被填充颜色@property(copy) CAShapeLayerFillRule fillRule;// 线的颜色@property(nullable) CGColorRef strokeColor;// strokeStart 和 strokeEnd 两者的取值都是0~1,决定贝塞尔曲线的划线百分比@property CGFloat strokeStart;@property CGFloat strokeEnd;// 虚线开始的位置@property CGFloat lineDashPhase;// 虚线设置,数组中奇数位实线长度,偶数位带遍空白长度@property(nullable, copy) NSArray<NSNumber *> *lineDashPattern;// 线的宽度@property CGFloat lineWidth;// 最大斜接长度 只有lineJoin属性为kCALineJoinMiter时miterLimit才有效@property CGFloat miterLimit;// 线端点样式(样式与 贝塞尔曲线的CGLineCap 属性一致)@property(copy) CAShapeLayerLineCap lineCap;// 拐角样式(样式与 贝塞尔曲线的CGLineJoin 属性一致)@property(copy) CAShapeLayerLineJoin lineJoin;
复制代码

3.2.2 举个栗子🌰

使用上面的一些属性,再结合贝塞尔曲线,我们实现了如下一些效果:



其中图五的效果,代码实现如下:


UIBezierPath *maskPath = [UIBezierPath bezierPath];for (NSInteger i = 1; i < 9; i++) {    UIBezierPath *tempPath = [UIBezierPath bezierPathWithRect:CGRectMake(190 - 20 * i, 550 - 10 * i, 40 * i, 20 * i)];    [maskPath appendPath:tempPath];}[maskPath stroke];
// CAShapeLayerCAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];maskLayer.frame = self.view.bounds;maskLayer.path = maskPath.CGPath;maskLayer.lineWidth = 5;maskLayer.strokeColor = [UIColor purpleColor].CGColor;maskLayer.fillRule = kCAFillRuleEvenOdd;maskLayer.fillColor = [UIColor cyanColor].CGColor;maskLayer.strokeStart = 0.2;maskLayer.strokeEnd = 0.5;maskLayer.lineDashPattern = @[@(10), @(10), @(30), @(30)];maskLayer.lineDashPhase = 0;[self.view.layer addSublayer:maskLayer];
复制代码

3.3 CAGradientLayer

苹果官网注释:“A layer that draws a color gradient over its background color, filling the shape of the layer (including rounded corners)” 专门用于在背景色上绘制颜色渐变的图层,填充图层的形状。

3.3.1 看一下它独特的属性:

// colors属性是CAGradientLayer的特殊属性,完美实现几种颜色的过渡。@property(nullable, copy) NSArray *colors;// 定义每个梯度停止的位置。取值范围为0~1递增@property(nullable, copy) NSArray<NSNumber *> *locations;// 决定了变色范围的起始点@property CGPoint startPoint;// 决定了变色范围的结束点@property CGPoint endPoint;// startPoint 和 endPoint两者的连线决定变色的趋势
复制代码

3.3.2 举个栗子🌰

使用上面的一些属性我们实现了如下一些效果:



其中图五的效果,代码实现如下:


CAGradientLayer *gradientLayer = [CAGradientLayer layer];gradientLayer.frame = CGRectMake(20, 450, 150, 150);gradientLayer.locations = @[@(0.2), @(0.5), @(0.6), @(0.8)];gradientLayer.startPoint = CGPointMake(0, 0);gradientLayer.endPoint = CGPointMake(1, 1);gradientLayer.colors = @[(id)[UIColor purpleColor].CGColor, (id)[UIColor greenColor].CGColor, (id)[UIColor orangeColor].CGColor, (id)[UIColor blackColor].CGColor];[self.view.layer addSublayer:gradientLayer];
复制代码

3.4 再举个栗子🌰🌰

当 CAGradientLayer + CAShapeLayer + 贝塞尔曲线 会有什么效果?上代码~


- (void)setupUI {    // 贝塞尔曲线    UIBezierPath *maskPath = [UIBezierPath bezierPath];    [maskPath moveToPoint:CGPointMake(100, 220)];    [maskPath addLineToPoint:CGPointMake(200, 150)];    [maskPath addLineToPoint:CGPointMake(300, 220)];    [maskPath stroke];
UIBezierPath *maskBottomPath = [UIBezierPath bezierPath]; [maskBottomPath moveToPoint:CGPointMake(280, 250)]; [maskBottomPath addCurveToPoint:CGPointMake(120, 250) controlPoint1:CGPointMake(250, 320) controlPoint2:CGPointMake(150, 320)]; [maskBottomPath stroke];
[maskPath appendPath:maskBottomPath];
// CAShapeLayer CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = self.view.bounds; maskLayer.path = maskPath.CGPath; maskLayer.lineWidth = 20; maskLayer.strokeColor = UIColorFromRGB(0xF0F5FF).CGColor; maskLayer.lineCap = kCALineCapRound; maskLayer.lineJoin = kCALineJoinRound; maskLayer.fillColor = [UIColor clearColor].CGColor; maskLayer.strokeStart = 0; maskLayer.strokeEnd = 0; [self.view.layer addSublayer:maskLayer];
// CAGradientLayer NSMutableArray *colorArray = [NSMutableArray new]; for (NSInteger i = 0; i < 6; i++) { [colorArray addObject:[self arc4randomColor]]; }
CAGradientLayer *gradientLayer = [CAGradientLayer layer]; gradientLayer.frame = self.view.bounds; gradientLayer.colors = colorArray; gradientLayer.startPoint = CGPointMake(0, 0.5); gradientLayer.endPoint = CGPointMake(1, 0.5); gradientLayer.mask = maskLayer; [self.view.layer addSublayer:gradientLayer];
// 创建全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 创建定时器 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 设置定时器,每N秒触发 int64_t intervalInNanoseconds = (int64_t)(0.3 * NSEC_PER_SEC); dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), (uint64_t)intervalInNanoseconds, 0); // 设置定时器处理事件 dispatch_source_set_event_handler(timer, ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (maskLayer.strokeEnd < 0.6) { maskLayer.strokeEnd += 0.4; } else if (maskLayer.strokeEnd < 0.8){ maskLayer.strokeEnd += 0.2; } else if (maskLayer.strokeEnd < 1){ maskLayer.strokeEnd += 0.1; } else { maskLayer.strokeEnd = 1; if (maskLayer.strokeStart < 0.6) { maskLayer.strokeStart += 0.4; } else if (maskLayer.strokeStart < 0.8){ maskLayer.strokeStart += 0.2; } else if (maskLayer.strokeStart < 1){ maskLayer.strokeStart += 0.1; } else { [colorArray removeObjectAtIndex:0]; [colorArray addObject:[self arc4randomColor]]; gradientLayer.colors = colorArray;
maskLayer.strokeStart = 0; maskLayer.strokeEnd = 0; } } }); });
_timer = timer;
// 开启定时器 dispatch_resume(_timer);}
- (id)arc4randomColor { return (id)[UIColor colorWithRed:arc4random()%255/255.f green:arc4random()%255/255.f blue:arc4random()%255/255.f alpha:1].CGColor;}
复制代码


运行结果👇


<https://v.qq.com/x/page/l3146iykm06.html


其他 layer 怎么使用?贝塞尔曲线 + Layer 还可以组合出更多神奇的反应!感兴趣的可以去试试哦~本文仅为抛砖引玉~~


本文转载自公众号贝壳产品技术(ID:beikeTC)。


原文链接


贝塞尔曲线在iOS端的绘图实践


2020-09-15 10:083274

评论

发布
暂无评论
发现更多内容

网格策略交易软件,量化马丁倍投交易机器人

NUCLEO-L432KC实现UART1、UART2双串口数据通信(STM32L432KC)

不脱发的程序猿

嵌入式 stm32 单片机 NUCLEO-L432KC 串口通信

聊聊微服务治理的落地问题 | Geek大咖说第二期

百度Geek说

微服务 自动化

最佳入门系列 | 何为服务网关?

架构精进之路

微服务 5月日更

电子产品PCB电路板散热的方法

不脱发的程序猿

嵌入式 PCB 电路板散热 电子电路 电路板

Logo设计软件 Tech Support

凌天一击

网络攻防学习笔记 Day27

穿过生命散发芬芳

5月日更 网络攻防

【大咖直播】Elastic 可观测性实战工作坊

腾讯云大数据

elastic

索信达控股:金融机构如何打造最适合自己的个性化推荐系统?

索信达控股

大数据 金融科技 金融 个性化推荐 营销数字化

集成学习中的随机森林

华为云开发者联盟

机器学习 决策树 随机森林 集成学习 Bagging

实测Tengine开源的Dubbo功能

捉虫大师

dubbo 网关 tengine

哈工大与华为终端有限公司签署首个HarmonyOS高校协同育人合作协议

科技汇

请警惕 ES 的三大坑

悟空聊架构

elasticsearch 架构 分布式 微服务 ES

突击 22 天面进腾讯,给到 32K*14 薪!全靠这份阿里面试参考指南了

Java 程序员 架构 面试 计算机

MySQL 数据库救火:磁盘爆满了,怎么办?

华为云开发者联盟

数据库 磁盘 MySQL 数据库 日志文件 磁盘爆满

OCR性能优化:从神经网络到橡皮泥

华为云开发者联盟

神经网络 机器学习 OCR 橡皮泥 CNN网络

为什么你的Docker容器刚启动就停了?

运维研习社

Docker Linux 5月日更

GitHub开源14.5万行阿波罗11号源代码

不脱发的程序猿

GitHub 开源 阿波罗11号

☕️【Java 技术之旅】带你看透Lambda表达式的底层

洛神灬殇

Java Lambda 底层原理 5月日更 行为参数化

可视化突破海绵城市发展困境,智慧城市从“一张图”开始

一只数据鲸鱼

数据可视化 智慧城市 智慧水务 三维可视化 海绵城市

视频门禁的优点及应用场景

anyRTC开发者

音视频 WebRTC RTC sdk

终于看到阿里大牛能把springboot讲的如此出神入化

Java 程序员 架构 计算机

Flink的批数据SQL

五分钟学大数据

flink 5月日更

阿里云联合中国信通院发布《云计算开放应用架构》标准,加速云原生应用规模化落地进程

阿里巴巴云原生

容器 开发者 运维 云原生 k8s

VSCode 无鼠标操作快捷键对比Atom

追风的少年

《复仇者联盟》AI换脸平台

不脱发的程序猿

人工智能 开源 AI 复仇者联盟

【多线程与高并发】从一则招聘信息进入多线程的世界

牧小农

Java 多线程与高并发

Flume自定义拦截器

大数据技术指南

大数据 5月日更

阿里开源:历年亿级活动高并发系统设计场景总结

Java架构师迁哥

BI系统里的数据赋能与业务决策

薄荷点点

数据产品经理 决策 BI 数据驱动 风险识别

合作伙伴眼中的HarmonyOS 专访方太智能厨电专家俞贵涛

科技汇

贝塞尔曲线在iOS端的绘图实践_大数据_孙齐_InfoQ精选文章