ios math core-graphics cgpath

Dibujar iOS 7 estilo squircle programatically



math core-graphics (3)

Estoy tratando de encontrar una forma de dibujar una forma de icono de ''estilo de iOS 7 programáticamente, usando gráficos centrales. No estoy preguntando cómo dibujar un rectángulo redondeado . Un squircle es un superelipso:

que es ligeramente diferente de un rectángulo redondeado regular:

Su fórmula exacta está disponible . Sin embargo, no puedo entender cómo dibujar esto usando, por ejemplo, un CGPath, y mucho menos llenarlo, y poder cambiar el tamaño de forma bastante fácil. Todo esto siendo totalmente exacto con la fórmula. ¿Alguna idea?


Esta no es una gran respuesta, ya que no llega al corazón de lo que está preguntando, que es cómo dibujar un superelleno ** programáticamente, pero puede:

  1. Descargue el SVG para la forma del icono de iOS7 aquí: http://dribbble.com/shots/1127699-iOS-7-icon-shape-PSD
  2. Importe a su proyecto Xcode
  3. Agregue PocketSVG a su proyecto: https://github.com/arielelkin/PocketSVG
  4. Cargue el SVG y conviértalo en UIBezierPath, desde allí puede escalar y transformar como quiera:

    PocketSVG *myVectorDrawing = [[PocketSVG alloc] initFromSVGFileNamed:@"iOS_7_icon_shape"]; UIBezierPath *myBezierPath = myVectorDrawing.bezier; // Apply your transforms here: [myBezierPath applyTransform:CGAffineTransformMakeScale(2.5, 2.5)]; [myBezierPath applyTransform:CGAffineTransformMakeTranslation(10, 50)]; CAShapeLayer *myShapeLayer = [CAShapeLayer layer]; myShapeLayer.path = myBezierPath.CGPath; myShapeLayer.strokeColor = [[UIColor redColor] CGColor]; myShapeLayer.lineWidth = 2; myShapeLayer.fillColor = [[UIColor clearColor] CGColor]; [self.view.layer addSublayer:myShapeLayer];

** Tal vez valga la pena señalar que la forma puede no ser una superellipse exacta de todos modos: http://i.imgur.com/l0ljVRo.png


Esto sería bastante fácil de hacer en OpenGL ES con un sombreador. Simplemente dibuje un cuadrángulo y pase los atributos x y y como vértices. En el sombreador de fragmentos, inserte xey en la ecuación. Si el resultado es <= 1, entonces el fragmento está dentro de la forma. Si puedo tener algo de tiempo libre, podría intentarlo y publicarlo aquí.

Si desea usar CGPath, creo que la clave es parametrizar xey en términos de t, que va de 0 a 2π. Luego evalúa xey a intervalos regulares. Trataré de resolver esto en mi tiempo libre, también, pero mi matemática está algo oxidada.

Por cierto, estoy seguro de que Apple no está usando esta fórmula. Vea el enlace que @millimoose publicó: http://blog.mikeswanson.com/post/62341902567/unleashing-genetic-algorithms-on-the-ios-7-icon


Cita de Wikipedia: Superellipse

Para n = 1/2, en particular, cada uno de los cuatro arcos es una curva de Bézier cuadrática definida por los dos ejes; como resultado, cada arco es un segmento de una parábola.

Entonces, ¿por qué no intentar acercarse a Squircle usando curvas de Bezier? Ambas curvas (Bezier y Squircle) están definidas por las ecuaciones paramétricas.

UIBezierPath Class tiene el método: addCurveToPoint:controlPoint1:controlPoint2:

Añade una curva de Bézier cúbica a la trayectoria del receptor.

NOTA: El uso del método addQuadCurveToPoint:controlPoint: da resultados peores: probado.

Usé este método y eso es lo que sucedió como resultado:

red line - rectángulo redondeado, blue line - rectángulo de cuatro curvas de Bezier

Si este resultado está interesado, dibuje el código a continuación.

NOTA: Para lograr una coincidencia más exacta, se puede requerir que la curva de Bezier cambie las coordenadas de los cuatro corner points (ahora corresponden a los ángulos del rectángulo en el que está inscrita la figura).

CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); //set rect size for draw float rectSize = 275.; CGRect rectangle = CGRectMake(CGRectGetMidX(rect) - rectSize/2, CGRectGetMidY(rect) - rectSize/2, rectSize, rectSize); //Rounded rectangle CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor); UIBezierPath* roundedPath = [UIBezierPath bezierPathWithRoundedRect:rectangle cornerRadius:rectSize/4.7]; [roundedPath stroke]; //Rectangle from Fours Bezier Curves CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor); UIBezierPath *bezierCurvePath = [UIBezierPath bezierPath]; //set coner points CGPoint topLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMinY(rectangle)); CGPoint topRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMinY(rectangle)); CGPoint botLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMaxY(rectangle)); CGPoint botRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMaxY(rectangle)); //set start-end points CGPoint midRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMidY(rectangle)); CGPoint botMPoint = CGPointMake(CGRectGetMidX(rectangle), CGRectGetMaxY(rectangle)); CGPoint topMPoint = CGPointMake(CGRectGetMidX(rectangle), CGRectGetMinY(rectangle)); CGPoint midLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMidY(rectangle)); //Four Bezier Curve [bezierCurvePath moveToPoint:midLPoint]; [bezierCurvePath addCurveToPoint:topMPoint controlPoint1:topLPoint controlPoint2:topLPoint]; [bezierCurvePath moveToPoint:midLPoint]; [bezierCurvePath addCurveToPoint:botMPoint controlPoint1:botLPoint controlPoint2:botLPoint]; [bezierCurvePath moveToPoint:midRPoint]; [bezierCurvePath addCurveToPoint:topMPoint controlPoint1:topRPoint controlPoint2:topRPoint]; [bezierCurvePath moveToPoint:midRPoint]; [bezierCurvePath addCurveToPoint:botMPoint controlPoint1:botRPoint controlPoint2:botRPoint]; [bezierCurvePath stroke]; CGContextRestoreGState(context);