核心graphics的三angular形渐变

我试图在视图中绘制一个这样的三angular形(一个UIView,一个NSView):
三角形渐变
我的第一个想法是CoreGraphics,但我找不到任何信息可以帮助我绘制任意颜色的三点之间的渐变。

任何帮助?

谢谢!

其实CoreGraphics很简单。 在下面你可以find渲染给定三angular形的代码,但是首先让我们考虑如何解决这个问题。

理论

想象一下边长为w的等边三angular形。 所有三个angular度都等于60度:

等边三角形

每个angular度将代表像素的组成部分:红色,绿色或蓝色。

让我们分析顶angular附近像素中的绿色分量的强度:

分析

与angular度越接近的像素,其将具有的成分越强烈,反之亦然。 在这里,我们可以将我们的主要目标分解为小的目标:

  1. 按像素绘制三angular形像素。
  2. 对于每个像素的每个像素计算值基于距离相应angular度的每个分量。

要解决第一个任务,我们将使用CoreGraphics位图上下文。 每个像素将有四个分量,每个长度为8位。 这意味着分量值可以在0到255之间变化。第四个分量是alpha通道,并且总是等于最大值 – 255.下面是如何对顶angular插值的示例:

插值示例

现在我们需要考虑如何计算组件的价值。

首先,我们定义每个angular度的主要颜色:

定义角色对

现在我们select一个三angular形上坐标为(x,y)的任意点A

选择点

接下来,我们从与红色分量相关的angular度画一条线,它穿过A,直到它与三angular形的相对边相交:

线

如果我们能finddc,它们的商就等于分量的标准化值,那么可以很容易地计算出这个值:

组件值http://www.sciweavers.org/tex2img.php?eq=componentValue%20=%20%5Cfrac%7Bd%7D%7Bc%7D%20*%20255&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit= 0 /

找出两点之间距离的公式很简单:

距离公式http://www.sciweavers.org/tex2img.php?eq=%5Csqrt%7B(x_%7B2​​%7D%20-%20x_%7B1%7D)%5E2%20(y_%7B2​​%7D%20 – %20y_%7B1%7D)%5E2%7D&BC =白色&FC =黑与IM = JPG&FS = 12&FF = AREV&编辑= 0 /

我们可以很容易地findd的距离,但不是c ,因为我们没有交点的坐标。 其实并不难 我们只需要为通过A的直线和直线描述三angular形的相反侧并find它们的交点,

线路交叉口

有交点我们可以应用距离公式http://www.sciweavers.org/tex2img.php?eq=%5Csqrt%7B(x_%7B2​​%7D%20-%20x_%7B1%7D)%5E2%20 (y_%7B2%7D%20-%20y_%7B1%7D)%5E2%7D&bc = White&fc = Black&im = jpg&fs = 12&ff = arev&edit = 0 /findc并最终计算当前点的分量值。 组件值http://www.sciweavers.org/tex2img.php?eq=componentValue%20=%20%5Cfrac%7Bd%7D%7Bc%7D%20*%20255&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit= 0 /

相同的stream程适用于其他组件。

这是实现上述概念的代码:

+ (UIImage *)triangleWithSideLength:(CGFloat)sideLength { return [self triangleWithSideLength:sideLength scale:[UIScreen mainScreen].scale]; } + (UIImage *)triangleWithSideLength:(CGFloat)sideLength scale:(CGFloat)scale { UIImage *image = nil; CGSize size = CGSizeApplyAffineTransform((CGSize){sideLength, sideLength * sin(M_PI / 3)}, CGAffineTransformMakeScale(scale, scale)); size_t const numberOfComponents = 4; size_t width = ceilf(size.width); size_t height = ceilf(size.height); size_t realBytesPerRow = width * numberOfComponents; size_t alignedBytesPerRow = (realBytesPerRow + 0xFF) & ~0xFF; size_t alignedPixelsPerRow = alignedBytesPerRow / numberOfComponents; CGContextRef ctx = CGBitmapContextCreate(NULL, width, height, 8, alignedBytesPerRow, CGColorSpaceCreateDeviceRGB(), (CGBitmapInfo)kCGImageAlphaPremultipliedLast); char *data = CGBitmapContextGetData(ctx); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int edge = ceilf((height - i) / sqrt(3)); if (j < edge || j > width - edge) { continue; } CGFloat redNormalized = 0; CGFloat greenNormalized = 0; CGFloat blueNormalized = 0; CGPoint currentTrianglePoint = (CGPoint){j / scale, (height - i) / scale}; [self calculateCurrentValuesAtGiventPoint:currentTrianglePoint sideLength:sideLength sideOne:&redNormalized sideTwo:&greenNormalized sideThree:&blueNormalized]; int32_t red = redNormalized * 0xFF; int32_t green = greenNormalized * 0xFF; int32_t blue = blueNormalized * 0xFF; char *pixel = data + (j + i * alignedPixelsPerRow) * numberOfComponents; *pixel = red; *(pixel + 1) = green; *(pixel + 2) = blue; *(pixel + 3) = 0xFF; } } CGImageRef cgImage = CGBitmapContextCreateImage(ctx); image = [[UIImage alloc] initWithCGImage:cgImage]; CGContextRelease(ctx); CGImageRelease(cgImage); return image; } + (void)calculateCurrentValuesAtGiventPoint:(CGPoint)point sideLength:(CGFloat)length sideOne:(out CGFloat *)sideOne sideTwo:(out CGFloat *)sideTwo sideThree:(out CGFloat *)sideThree { CGFloat height = sin(M_PI / 3) * length; if (sideOne != NULL) { // Side one is at 0, 0 CGFloat currentDistance = sqrt(point.x * point.x + point.y * point.y); if (currentDistance != 0) { CGFloat a = point.y / point.x; CGFloat b = 0; CGFloat c = -height / (length / 2); CGFloat d = 2 * height; CGPoint intersection = (CGPoint){(d - b) / (a - c), (a * d - c * b) / (a - c)}; CGFloat currentH = sqrt(intersection.x * intersection.x + intersection.y * intersection.y); *sideOne = 1 - currentDistance / currentH; } else { *sideOne = 1; } } if (sideTwo != NULL) { // Side two is at w, 0 CGFloat currentDistance = sqrt(pow((point.x - length), 2) + point.y * point.y); if (currentDistance != 0) { CGFloat a = point.y / (point.x - length); CGFloat b = height / (length / 2); CGFloat c = a * -point.x + point.y; CGFloat d = b * -length / 2 + height; CGPoint intersection = (CGPoint){(d - c) / (a - b), (a * d - b * c) / (a - b)}; CGFloat currentH = sqrt(pow(length - intersection.x, 2) + intersection.y * intersection.y); *sideTwo = 1 - currentDistance / currentH; } else { *sideTwo = 1; } } if (sideThree != NULL) { // Side three is at w / 2, w * sin60 degrees CGFloat currentDistance = sqrt(pow((point.x - length / 2), 2) + pow(point.y - height, 2)); if (currentDistance != 0) { float dy = point.y - height; float dx = (point.x - length / 2); if (fabs(dx) > FLT_EPSILON) { CGFloat a = dy / dx; CGFloat b = 0; CGFloat c = a * -point.x + point.y; CGFloat d = 0; CGPoint intersection = (CGPoint){(d - c) / (a - b), (a * d - b * c) / (a - b)}; CGFloat currentH = sqrt(pow(length / 2 - intersection.x, 2) + pow(height - intersection.y, 2)); *sideThree = 1 - currentDistance / currentH; } else { *sideThree = 1 - currentDistance / height; } } else { *sideThree = 1; } } } 

这是一个由此代码生成的三angular形图像:

渲染的三角形