An algorithm to find bounding box of closed bezier curves?

后端 未结 7 855
半阙折子戏
半阙折子戏 2020-12-05 13:54

I\'m looking for an algorithm to find bounding box (max/min points) of a closed quadratic bezier curve in Cartesian axis:

input: C (a closed bezier curve)
out         


        
相关标签:
7条回答
  • 2020-12-05 14:42

    Timo-s first variant adapted to Objective-C

    CGPoint CubicBezierPointAt(CGPoint p1, CGPoint p2, CGPoint p3, CGPoint p4, CGFloat t) {
    
       CGFloat x = CubicBezier(p1.x, p2.x, p3.x, p4.x, t);
       CGFloat y = CubicBezier(p1.y, p2.y, p3.y, p4.y, t);
    
       return CGPointMake(x, y);
    }
    
    // array containing TopLeft and BottomRight points for curve`s enclosing bounds
    NSArray* CubicBezierExtremums(CGPoint p1, CGPoint p2, CGPoint p3, CGPoint p4) {
    
       CGFloat a, b, c, t, t1, t2, b2ac, sqrtb2ac;
       NSMutableArray *tValues = [NSMutableArray new];
    
       for (int i = 0; i < 2; i++) {
          if (i == 0) {
             a = 3 * (-p1.x + 3 * p2.x - 3 * p3.x + p4.x);
             b = 6 * (p1.x - 2 * p2.x +  p3.x);
             c = 3 * (p2.x - p1.x);
          }
          else {
             a = 3 * (-p1.y + 3 * p2.y - 3 * p3.y + p4.y);
             b = 6 * (p1.y - 2 * p2.y +  p3.y);
             c = 3 * (p2.y - p1.y);
          }
    
          if(ABS(a) < CGFLOAT_MIN) {// Numerical robustness
             if (ABS(b) < CGFLOAT_MIN) {// Numerical robustness
                continue;
             }
    
             t = -c / b;
    
             if (t > 0 && t < 1) {
                [tValues addObject:[NSNumber numberWithDouble:t]];
             }
             continue;
          }
    
          b2ac = pow(b, 2) - 4 * c * a;
    
          if (b2ac < 0) {
             continue;
          }
    
          sqrtb2ac = sqrt(b2ac);
    
          t1 = (-b + sqrtb2ac) / (2 * a);
    
          if (t1 > 0.0 && t1 < 1.0) {
             [tValues addObject:[NSNumber numberWithDouble:t1]];
          }
    
          t2 = (-b - sqrtb2ac) / (2 * a);
    
          if (t2 > 0.0 && t2 < 1.0) {
             [tValues addObject:[NSNumber numberWithDouble:t2]];
          }
       }
    
       int j = (int)tValues.count;
    
       CGFloat x = 0;
       CGFloat y = 0;
       NSMutableArray *xValues = [NSMutableArray new];
       NSMutableArray *yValues = [NSMutableArray new];
    
       while (j--) {
          t = [[tValues objectAtIndex:j] doubleValue];
          x = CubicBezier(p1.x, p2.x, p3.x, p4.x, t);
          y = CubicBezier(p1.y, p2.y, p3.y, p4.y, t);
          [xValues addObject:[NSNumber numberWithDouble:x]];
          [yValues addObject:[NSNumber numberWithDouble:y]];
       }
    
       [xValues addObject:[NSNumber numberWithDouble:p1.x]];
       [xValues addObject:[NSNumber numberWithDouble:p4.x]];
       [yValues addObject:[NSNumber numberWithDouble:p1.y]];
       [yValues addObject:[NSNumber numberWithDouble:p4.y]];
    
       //find minX, minY, maxX, maxY
       CGFloat minX = [[xValues valueForKeyPath:@"@min.self"] doubleValue];
       CGFloat minY = [[yValues valueForKeyPath:@"@min.self"] doubleValue];
       CGFloat maxX = [[xValues valueForKeyPath:@"@max.self"] doubleValue];
       CGFloat maxY = [[yValues valueForKeyPath:@"@max.self"] doubleValue];
    
       CGPoint origin = CGPointMake(minX, minY);
       CGPoint bottomRight = CGPointMake(maxX, maxY);
    
       NSArray *toReturn = [NSArray arrayWithObjects:
                            [NSValue valueWithCGPoint:origin],
                            [NSValue valueWithCGPoint:bottomRight],
                            nil];
    
       return toReturn;
    }
    
    0 讨论(0)
提交回复
热议问题