2011-12-09 22 views
9

Sto cercando di adattare un esempio fornito da Apple per attirare programmazione stelle, in linea, il codice è il seguente:Come disegnare stelle usando Quartz Core?

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSetLineWidth(context, aSize); 

    for (NSUInteger i=0; i<stars; i++) 
    { 

     CGContextSetFillColorWithColor(context, aColor); 
     CGContextSetStrokeColorWithColor(context, aColor); 

     float w = item.size.width; 
     double r = w/2; 
     double theta = 2 * M_PI * (2.0/5.0); // 144 degrees 

     CGContextMoveToPoint(context, 0, r); 

     for (NSUInteger k=1; k<5; k++) 
     { 
      float x = r * sin(k * theta); 
      float y = r * cos(k * theta); 
      CGContextAddLineToPoint(context, x, y); 
     } 

     CGContextClosePath(context); 
     CGContextFillPath(context); 
    } 

Il codice di cui sopra disegna un perfetto stella, ma è 1. visualizzato a testa in giù 2. è nero e senza bordo Quello che voglio fare è disegnare molte stelle sulla stessa linea e con lo stile dato. Capisco che in realtà sto disegnando lo stesso percorso 5 volte nella stessa posizione e che ho in qualche modo capovolto verticalmente il contesto, ma dopo diversi test ho rinunciato! (Mi mancano le competenze matematiche e geometriche necessarie: P) ... potresti aiutarmi per favore?

UPDATE:

Ok, grazie ad CocoaFu, questo è il mio refactoring e di lavoro di utilità pareggio:

- (void)drawStars:(NSUInteger)count inContext:(CGContextRef)context; 
{ 
    // constants 
    const float w = self.itemSize.width; 
    const float r = w/2; 
    const double theta = 2 * M_PI * (2.0/5.0); 
    const float flip = -1.0f; // flip vertically (default star representation) 

    // drawing center for the star 
    float xCenter = r; 

    for (NSUInteger i=0; i<count; i++) 
    { 
     // get star style based on the index 
     CGContextSetFillColorWithColor(context, [self fillColorForItemAtIndex:i]); 
     CGContextSetStrokeColorWithColor(context, [self strokeColorForItemAtIndex:i]); 

     // update position 
     CGContextMoveToPoint(context, xCenter, r * flip + r); 

     // draw the necessary star lines 
     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 + r); 
     } 

     // update horizontal center for the next star 
     xCenter += w + self.itemMargin; 

     // draw current star 
     CGContextClosePath(context); 
     CGContextFillPath(context); 
     CGContextStrokePath(context); 
    } 
} 
+0

Cosa vuoi dire a testa in giù? Una stella non ha un "fondo" in quanto tale, sbaglio? Forse potresti pubblicare un paio di schermate, di quello che stai ricevendo e di quello che ti aspetti. –

+0

Una stella ha solitamente un punto in alto e un 2 in basso. Stella normale: http://www.allstarbaseballcamp.com/star_clipart.gif, stella capovolta (verticale capovolta): http://sunandshield.files.wordpress.com/2010/03/eastern-star.jpg – daveoncode

+0

Vedere https: //calayer.com/core-animation/2016/05/22/cashapelayer-in-depth.html#path – iwasrobbed

risposta

28

Ecco il codice che trarrà 3 stelle in una linea orizzontale, è non è abbastanza, ma può essere utile:

-(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

grazie mille! Ad ogni modo le stelle sono ancora nella posizione sbagliata ... come posso girarle verticalmente? (Mi sento un idiota: P) – daveoncode

+0

Ho risolto utilizzando: CGAffineTransform verticalFlip = CGAffineTransformMake (1, 0, 0, -1, 0, w); CGContextConcatCTM (context, verticalFlip); ...C'è un modo migliore? – daveoncode

+0

Probabilmente c'è, perché facendo così tutto ciò che si disegna dopo la chiamata sarà capovolto. Quindi dovresti ripristinare la trasformazione dopo aver disegnato le stelle, nel caso in cui desideri disegnare anche qualcos'altro. –

7

Ecco un algoritmo per attuare ciò che implicava buddhabrot:

- (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); 
} 

lavora per me per la maggior parte delle stelle di base. Testato da 2 punti (fa un buon diamante!) Fino a 9 stelle.

Se si desidera una stella con il punto verso il basso, modificare la sottrazione in aggiunta.

Per disegnare multipli, creare un ciclo e chiamare questo metodo più volte, passando ogni volta un nuovo centro. Questo dovrebbe allinearli bene!

+0

Qual è il rapporto 'innerRadius/outerRadius' per un 5 stelle per essere" perfetto "(come quello disegnato nell'altra risposta)? – Colas

+0

Non so se chiamerei la stella nell'altra risposta "perfetta", ma credo che il rapporto sia 2/5 (innerRadius/outerRadius) – gavdotnet

4

Preferisco utilizzare un CAShaperLayer per implementare drawRect, in quanto può essere animato. Ecco una funzione che creerà un percorso a forma di una stella dei 5 punti:

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 
} 

Può quindi essere utilizzato con un CAShapeLayer in questo modo:

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 
Problemi correlati