BeizerView.m 11.1 KB
//
//  BeizerView.m
//  DreamSleep
//
//  Created by peter on 2022/7/2.
//

#import "BeizerView.h"

@interface BeizerView ()
@property (nonatomic,assign) float step;
@property (nonatomic,assign) float total;
@end

@implementation BeizerView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = DSClearColor;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    CGFloat x = 0, y = 0, width = self.width, height = self.height;
    CGPoint center = CGPointMake(x + width / 2.0, y + height / 2.0);
    
    CGFloat startAngle = 95*M_PI_2/90;
    CGFloat endAngle = 30*M_PI_2/90;
    CGFloat diff = startAngle - endAngle;
    CGFloat endAngle2 = startAngle-self.progressRate*diff;
    
    // 总曲线
    UIBezierPath *totalClip = [UIBezierPath bezierPathWithArcCenter:center
                                                             radius:MAX(width, height)
                                                         startAngle:M_PI_2
                                                           endAngle:0
                                                          clockwise:NO];
    [totalClip addLineToPoint:center];
    [totalClip closePath];
    [totalClip addClip];
    
    UIBezierPath *totalArc = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, width, height)];
    [[UIColor redColor] setStroke];
    [totalArc stroke];
    
    // 当前曲线
    UIBezierPath* curClip = [UIBezierPath bezierPathWithArcCenter:center
                                                           radius:MAX(width, height)
                                                       startAngle:startAngle
                                                         endAngle:endAngle2
                                                        clockwise:NO];
    [curClip addLineToPoint:center];
    [curClip closePath];
    [curClip addClip];
    
    UIBezierPath *curArc = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, width, height)];
    [[UIColor greenColor] setStroke];
    [curArc stroke];
    
    //    CGPoint center = CGPointMake(67, -508);
    //    if (self.tag == 1) {
    //        UIBezierPath *path = [UIBezierPath bezierPath];
    //        [path addArcWithCenter:center radius:600 startAngle:startAngle endAngle:-M_PI_2 clockwise:NO];
    //        CAShapeLayer *layer = [CAShapeLayer layer];
    //        layer.path = path.CGPath;
    //        layer.fillColor = [UIColor clearColor].CGColor;
    //        layer.strokeColor = [UIColor blueColor].CGColor;
    //        [self.layer addSublayer:layer];
    //    } else {
    //        UIBezierPath *path2 = [UIBezierPath bezierPath];
    //        [path2 addArcWithCenter:center radius:600 startAngle:startAngle endAngle:-M_PI_2 clockwise:NO];
    //        CAShapeLayer *layer2 = [CAShapeLayer layer];
    //        layer2.path = path2.CGPath;
    //        layer2.fillColor = [UIColor clearColor].CGColor;
    //        layer2.strokeColor = [UIColor greenColor].CGColor;
    //        [self.layer addSublayer:layer2];
    //    }
    
    // 绘制总弧线
    //    UIBezierPath *aPath1 = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.width, -self.height -2, 2*self.width + 2, 2*self.height + 2)];
    //    aPath1.lineWidth = 2;
    //    aPath1.lineJoinStyle = kCGLineJoinRound;
    //    [UIColor.blueColor set];
    //    [aPath1 stroke];
    
    //    [self debugViewShowBorder];
    
    // 渐变色
    //    CAGradientLayer *gradLayer = [CAGradientLayer layer];
    //    gradLayer.frame = aPath1.bounds;
    //        gradLayer.colors = @[(__bridge id)ColorFromHex(0x9CE5EF).CGColor,(__bridge id)ColorFromHex(0x217B8B).CGColor];
    //        gradLayer.startPoint = CGPointMake(0, .5);
    //        gradLayer.endPoint = CGPointMake(1, .5);
    //        gradLayer.locations = @[@0,@1.0];
    //        gradLayer.type = kCAGradientLayerRadial;
    //        [self.layer addSublayer:gradLayer];
    
    // 绘制当前弧线
    //    UIBezierPath *aPath2=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.width, -self.height -2, 2*self.width + 2, 2*self.height + 2)];
    //    aPath2.lineWidth = 2.0;
    //    [aPath2 stroke];
    //    self.clipsToBounds = YES;
    
    //        UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 0)
    //                                                             radius:self.width
    //                                                         startAngle:-75*M_PI_2/90
    //                                                           endAngle:-55*M_PI_2/90
    //                                                          clockwise:NO];
    //    aPath.lineWidth = 2.0;
    //    aPath.lineCapStyle = kCGLineCapRound; //线条拐角
    //    aPath.lineJoinStyle = kCGLineJoinRound; //终点处理
    //    [aPath stroke];
    //    self.clipsToBounds = YES;
    
    //    [self debugViewShowBorder];
    
    // 创建CAShapeLayer
    //        CAShapeLayer *layer = [CAShapeLayer layer];
    //        layer.fillColor = [UIColor clearColor].CGColor;
    //        layer.lineWidth =  2.0f;
    //        layer.lineCap = kCALineCapRound;
    //        layer.lineJoin = kCALineJoinRound;
    //        layer.strokeColor = [UIColor blueColor].CGColor;
    //        [self.layer addSublayer:layer];
    //        layer.path = curClip.CGPath;
    //
    //    // 创建Animation
    //        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    //        animation.fromValue = @(0.0);
    //        animation.toValue = @(1.0);
    //        layer.autoreverses = NO;
    //        animation.duration = 4.0;
    //
    //    // 设置layer的animation
    //        [layer addAnimation:animation forKey:nil];
}

-(void)animateProgress:(float)progress animate:(BOOL)animate
{
    if (animate) {
        self.total = progress;
        /*
         利用定时器做进度动画
         */
        [NSTimer scheduledTimerWithTimeInterval:0.01
                                         target:self
                                       selector:@selector(numberAnimation:)
                                       userInfo:nil
                                        repeats:YES];
    } else {
        [self setNeedsDisplay];
    }
}

-(void)numberAnimation:(NSTimer*)timer {
    _step += 0.01;
    if (self.step > self.total) {
        [timer invalidate];
        timer = nil;
        self.step = 0;
        return;
    }
    self.progressRate = self.step;
    
    DSLog(@"self.step:%f", self.step);
    
    [self setNeedsDisplay];
}

#pragma mark - others
- (void)addArc:(CGPoint)start end:(CGPoint)end angle:(double)angle clockwise:(BOOL)clockwise path:(UIBezierPath *)path {
    if (!((start.x != end.x || start.y != end.y) && (angle >= 0 && angle <= 2 * M_PI))) {
        return;
    }
    if (angle == 0) {
        return;
    }
    
    CGPoint tmpStart = start, tmpEnd = end;
    double tmpAngle = angle;
    // Note: 保证计算圆心时是从 start 到 end 顺时针 小于 π 的角
    if (tmpAngle > M_PI) {
        tmpAngle = 2 * M_PI - tmpAngle;
        CGPoint tmpP = tmpStart;
        tmpStart = tmpEnd;
        tmpEnd = tmpP;
    }
    if (!clockwise) {
        CGPoint tmpP = tmpStart;
        tmpStart = tmpEnd;
        tmpEnd = tmpP;
    }
    
    CGPoint center = [self calculateCenterFor:tmpStart end:tmpEnd radian:tmpAngle];
    CGFloat radius = [self calculateLineLength:start p2:center];
    
    double startAngle = [self calculateAngle:start origin:center];
    double endAngle = [self calculateAngle:end origin:center];
    
    // Note: 逆时针绘制则交换 startAngle 和 endAngle,并且将开始点移动的 end 位置
    if (!clockwise) {
        double tmpAngle = startAngle;
        startAngle = endAngle;
        endAngle = tmpAngle;
        //            [path moveToPoint:end];
    }
    [path addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:clockwise];
    //    [path moveToPoint:end];
}

// 计算2点间的距离
- (CGFloat)calculateLineLength:(CGPoint)p1 p2:(CGPoint)p2 {
    CGFloat w = p1.x - p2.x;
    CGFloat h = p1.y - p2.y;
    return sqrt(w * w + h * h);
}

// 计算point和origin连接线在iOS坐标系的角度
- (double)calculateAngle:(CGPoint)point origin:(CGPoint)origin {
    if (point.y == origin.y) {
        return point.x > origin.x ? 0.0 : -M_PI;
    }
    
    if (point.x == origin.x) {
        return point.y > origin.y ? M_PI * 0.5 : M_PI * -0.5;
    }
    // Note: 修正标准坐标系角度到 iOS 坐标系
    double rotationAdjustment = M_PI * 0.5;
    
    double offsetX = point.x - origin.x;
    double offsetY = point.y - origin.y;
    // Note: 使用 -offsetY 是因为 iOS 坐标系与标准坐标系的区别
    if (offsetY > 0) {
        return floor(atan(offsetX / -offsetY)) + rotationAdjustment;
    } else {
        return floor(atan(offsetX / -offsetY)) - rotationAdjustment;
    }
}

// 计算圆心坐标
- (CGPoint)calculateCenterFor:(CGPoint)start end:(CGPoint)end radian:(double)radian {
    if (radian > M_PI) {
        return CGPointZero;
    }
    if (start.x == end.x && start.y == end.y) {
        return CGPointZero;
    }
    if (radian == M_PI) {
        double centerX = (end.x - start.x) * 0.5 + start.x;
        double centerY = (end.y - start.y) * 0.5 + start.y;
        return CGPointMake(centerX, centerY);
    }
    
    double lineAB = [self calculateLineLength:start p2:end];
    
    // 平行 Y 轴
    if (start.x == end.x) {
        double centerY = (end.y - start.y) * 0.5 + start.y;
        double tanResult = floor(tan(radian * 0.5));
        double offsetX = lineAB * 0.5 / tanResult;
        double centerX = start.x + offsetX * (start.y > end.y ? 1.0 : -1.0);
        return CGPointMake(centerX, centerY);
    }
    
    // 平行 X 轴
    if (start.y == end.y) {
        double centerX = (end.x - start.x) * 0.5 + start.x;
        double tanResult = floor(tan(radian * 0.5));
        double offsetY = lineAB * 0.5 / tanResult;
        double centerY = start.y + offsetY * (start.x < end.x ? 1.0 : -1.0);
        return CGPointMake(centerX, centerY);
    }
    
    // 普通情况
    
    // 计算半径
    double radius = lineAB * 0.5 / floor(sin(radian * 0.5));
    // 计算与 Y 轴的夹角
    double angleToYAxis = atan(fabs(start.x - end.x) / fabs(start.y - end.y));
    double cacluteAngle = floor(M_PI - radian) * 0.5 - angleToYAxis;
    // 偏移量
    double offsetX = radius * sin(cacluteAngle);
    double offsetY = radius * cos(cacluteAngle);
    
    double centetX = end.x;
    double centerY = end.y;
    // 以 start 为原点判断象限区间(iOS坐标系)
    if (end.x > start.x && end.y < start.y) {
        // 第一象限
        centetX = end.x + offsetX;
        centerY = end.y + offsetY;
    } else if (end.x > start.x && end.y > start.y) {
        // 第二象限
        centetX = start.x - offsetX;
        centerY = start.y + offsetY;
    } else if (end.x < start.x && end.y > start.y) {
        // 第三象限
        centetX = end.x - offsetX;
        centerY = end.y - offsetY;
    } else if (end.x < start.x && end.y < start.y) {
        // 第四象限
        centetX = start.x + offsetX;
        centerY = start.y - offsetY;
    }
    return CGPointMake(centetX, centerY);
}

@end