Синус CAShapeLayer как маска CALayer

Я пытаюсь реализовать следующую любопытную вещь: у меня есть несколько точек, и я хотел бы связать их с синусоидами.

Следующий метод возвращает массив точек для построения графика:

- (NSArray *)plotPointsBetweenPoint:(CGPoint)pointA andPoint:(CGPoint)pointB {
  double H = fabs(pointB.y - pointA.y);
  double L = fabs(pointB.x - pointA.x);

  NSInteger granularity = 40;
  NSMutableArray *array = [NSMutableArray arrayWithCapacity:granularity + 1];
  for (int i = 0; i <= granularity; ++i) {
    CGFloat x = M_PI*(float)i/(granularity);
    CGFloat y = -cosf(x);
    CGFloat multiplier = pointA.y > pointB.y ? 1 : -1;
    CGPoint newPoint = CGPointMake(pointA.x + L*(float)i/granularity, pointA.y - multiplier*H*(1.0 + y)/2.0);
    [array addObject:[NSValue valueWithCGPoint:newPoint]];
  }
  return array;
}

После этого я создаю специальный UIBezierPath:

- (UIBezierPath *)sineWaveWithPoints:(NSArray *)points {
  UIBezierPath *path = [[UIBezierPath alloc] init];
  NSMutableArray *array = [NSMutableArray array];

  for (int i = 0; i < points.count - 1; ++i) {
    [array addObjectsFromArray:[self plotPointsBetweenPoint:[points[i] CGPointValue] andPoint:[points[i+1] CGPointValue]]];
  }
  [path moveToPoint:[array[0] CGPointValue]];
  for (NSValue *value in array) {
    CGPoint point = [value CGPointValue];
    [path addLineToPoint:point];
  }
  [path closePath];
  path.lineWidth = 2.0;
  [path stroke];
  return path;
}

Затем я добавляю этот путь с помощью CAShapeLayer:

CAGradientLayer *gradientLayer = [self gradientLayer];
CAShapeLayer *maskLine = [CAShapeLayer layer];
maskLine.path = [self sineWaveWithPoints:pointsArray].CGPath;
maskLine.lineWidth = self.plotWidth;
gradientLayer.mask = maskLine;
[self.view.layer addSublayer:gradientLayer];

вот что у меня получилось

Поэтому я хотел бы иметь градиентную синусоиду между этими точками. Что именно не так в моих действиях?

Идеально: введите здесь описание изображения


person agoncharov    schedule 10.04.2014    source источник
comment
Извините, но я не понимаю, что вы имеете в виду, говоря, что я хотел бы иметь градиентную синусоиду между этими точками. Можете ли вы пояснить, что вы имеете в виду, или, может быть, даже показать макет (пример, сделанный в графическом редакторе) того, что вы пытаетесь сделать?   -  person David Rönnqvist    schedule 10.04.2014
comment
Конечно. Задача состоит в том, чтобы построить график, цвет точки значения y зависит от высоты значения (например, от фиолетового до желтого). Я решил, что лучший способ заполнить линию таким градиентом — это создать градиентный слой с соответствующими цветами и выполнить метод setMask, используя созданный синус CAShapeLayer. P.S. Я закрепил рендер с основной целью.   -  person agoncharov    schedule 10.04.2014
comment
Замаскировать градиент обведенным контуром?   -  person David Rönnqvist    schedule 10.04.2014


Ответы (1)


Программа ведет себя правильно, то есть делает именно то, что вы ей говорите. Проблема в том, что то, что вы говорите ему делать (в своем коде), не является тем, что вы говорите, что хотите (вашими словами и изображением в вашем вопросе).

Первое, что вы делаете неправильно: вы сказали closePath. Так он закрывает путь! Это означает, что, нарисовав волну, она соединяет последнюю точку с первой точкой прямой линией, придавая фигуру, которую вы показываете.

Второе, что вы делаете неправильно: вы не можете манипулировать слоем формы. Вы создаете ванильный CAShapeLayer и оставляете его по умолчанию. Ну, по умолчанию fillColor черный (а не strokeColor). Вы не меняете это. Таким образом, вы получаете свою (неправильную) форму, заполненную черным цветом, а не обводку, и, следовательно, результирующая маска является формой внутренней части вашей (неправильной) формы, придавая форму градиентной маски, которую вы показываете.

person matt    schedule 10.04.2014