How to draw stars using Quartz Core?

前端 未结 3 2149
北恋
北恋 2020-12-28 10:29

I\'m trying to adapt an example provided by Apple in order to programmatically draw stars in line, the code is the following:

CGContextRef context = UIGraphi         


        
相关标签:
3条回答
  • 2020-12-28 10:42

    I prefer using a CAShaperLayer to implementing drawRect, as it can then be animated. Here's a function that will create a path in the shape of a 5 point star:

    func createStarPath(size: CGSize) -> CGPath {
        let numberOfPoints: CGFloat = 5
    
        let starRatio: CGFloat = 0.5
    
        let steps: CGFloat = numberOfPoints * 2
    
        let outerRadius: CGFloat = min(size.height, size.width) / 2
        let innerRadius: CGFloat = outerRadius * starRatio
    
        let stepAngle = CGFloat(2) * CGFloat(M_PI) / CGFloat(steps)
        let center = CGPoint(x: size.width / 2, y: size.height / 2)
    
        let path = CGPathCreateMutable()
    
        for i in 0..<Int(steps) {
            let radius = i % 2 == 0 ? outerRadius : innerRadius
    
            let angle = CGFloat(i) * stepAngle - CGFloat(M_PI_2)
    
            let x = radius * cos(angle) + center.x
            let y = radius * sin(angle) + center.y
    
            if i == 0 {
                CGPathMoveToPoint(path, nil, x, y)
            }
            else {
                CGPathAddLineToPoint(path, nil, x, y)
            }
        }
    
        CGPathCloseSubpath(path)
        return path
    }
    

    It can then be used with a CAShapeLayer like so:

    let layer = CAShapeLayer()
    layer.path = createStarPath(CGSize(width: 100, height: 100))
    layer.lineWidth = 1
    layer.strokeColor = UIColor.blackColor().CGColor
    layer.fillColor = UIColor.yellowColor().CGColor
    layer.fillRule = kCAFillRuleNonZero
    
    0 讨论(0)
  • 2020-12-28 10:52

    Here is code that will draw 3 stars in a horizontal line, it's is not pretty but it may help:

    -(void)drawRect:(CGRect)rect
    {
        int aSize = 100.0;
        const CGFloat color[4] = { 0.0, 0.0, 1.0, 1.0 }; // Blue
        CGColorRef aColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), color);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetLineWidth(context, aSize);
        CGFloat xCenter = 100.0;
        CGFloat yCenter = 100.0;
    
        float  w = 100.0;
        double r = w / 2.0;
        float flip = -1.0;
    
        for (NSUInteger i=0; i<3; i++) 
        {
            CGContextSetFillColorWithColor(context, aColor);
            CGContextSetStrokeColorWithColor(context, aColor);
    
            double theta = 2.0 * M_PI * (2.0 / 5.0); // 144 degrees
    
            CGContextMoveToPoint(context, xCenter, r*flip+yCenter);
    
            for (NSUInteger k=1; k<5; k++) 
            {
                float x = r * sin(k * theta);
                float y = r * cos(k * theta);
                CGContextAddLineToPoint(context, x+xCenter, y*flip+yCenter);
            }
            xCenter += 150.0;
        }
        CGContextClosePath(context);
        CGContextFillPath(context);
    }
    

    enter image description here

    0 讨论(0)
  • 2020-12-28 10:55

    Here's an algorithm to implement what buddhabrot implied:

    - (void)drawStarInContext:(CGContextRef)context withNumberOfPoints:(NSInteger)points center:(CGPoint)center innerRadius:(CGFloat)innerRadius outerRadius:(CGFloat)outerRadius fillColor:(UIColor *)fill strokeColor:(UIColor *)stroke strokeWidth:(CGFloat)strokeWidth {
        CGFloat arcPerPoint = 2.0f * M_PI / points;
        CGFloat theta = M_PI / 2.0f;
    
        // Move to starting point (tip at 90 degrees on outside of star)
        CGPoint pt = CGPointMake(center.x - (outerRadius * cosf(theta)), center.y - (outerRadius * sinf(theta)));
        CGContextMoveToPoint(context, pt.x, pt.y);
    
        for (int i = 0; i < points; i = i + 1) {
            // Calculate next inner point (moving clockwise), accounting for crossing of 0 degrees
            theta = theta - (arcPerPoint / 2.0f);
            if (theta < 0.0f) {
                theta = theta + (2 * M_PI);
            }
            pt = CGPointMake(center.x - (innerRadius * cosf(theta)), center.y - (innerRadius * sinf(theta)));
            CGContextAddLineToPoint(context, pt.x, pt.y);
    
            // Calculate next outer point (moving clockwise), accounting for crossing of 0 degrees
            theta = theta - (arcPerPoint / 2.0f);
            if (theta < 0.0f) {
                theta = theta + (2 * M_PI);
            }
            pt = CGPointMake(center.x - (outerRadius * cosf(theta)), center.y - (outerRadius * sinf(theta)));
            CGContextAddLineToPoint(context, pt.x, pt.y);
        }
        CGContextClosePath(context);
        CGContextSetLineWidth(context, strokeWidth);
        [fill setFill];
        [stroke setStroke];
        CGContextDrawPath(context, kCGPathFillStroke);
    }
    

    Works for me for most basic stars. Tested from 2 points (makes a good diamond!) up to 9 stars.

    If you want a star with point down, change the subtraction to addition.

    To draw multiples, create a loop and call this method multiple times, passing a new center each time. That should line them up nicely!

    0 讨论(0)
提交回复
热议问题