Непрерывная анимация по пути swift [duplicate]

Нет, не разбит, но большинство десятичных дробей должно быть аппроксимировано

Резюме

Арифметика с плавающей точкой точный, к сожалению, он не очень хорошо сочетается с нашим обычным представлением числа base-10, так что получается, что мы часто даем ему ввод, который немного от того, что мы написали.

Даже простые числа, такие как 0.01, 0.02, 0.03, 0.04 ... 0.24, не представляются точно как двоичные дроби, даже если в мантиссе были тысячи бит точности, даже если у вас были миллионы. Если вы отсчитываете с шагом 0,01, пока вы не достигнете 0,25, вы получите первую фракцию (в этой последовательности), представленную в base10 и base2. Но если вы попытались использовать FP, ваш 0,01 был бы слегка отключен, поэтому единственный способ добавить 25 из них до хорошего точного 0.25 потребовал бы длинной цепи причинности, включающей защитные биты и округление.

Мы постоянно даем аппарату FP что-то вроде простого в базе 10, но это повторяющаяся фракция в базе 2.

Как это произошло?

Когда мы пишем в десятичной форме, каждая дробь является рациональным числом форма

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; x / (2n + 5n).

В двоичном выражении мы получаем только член 2n , то есть:

& nbsp ; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; x / 2n

Итак, в десятичной форме мы не можем представлять 1/3. Поскольку база 10 включает в себя 2 как простой коэффициент, каждое число, которое мы можем записать как двоичную дробь , также может быть записано в виде базовой дроби. Однако вряд ли что-либо, что мы пишем как base10, представляется в двоичном виде. В диапазоне от 0,01, 0,02, 0,03 ... 0,99 только цифры три могут быть представлены в нашем формате FP: 0,25, 0,50 и 0,75, поскольку они равны 1/4, 1/2, и 3/4 - все числа с простым множителем, использующим только 2n-член.

В базе 10 мы не можем представлять 1/3. Но в двоичном коде мы не можем делать 1/10 или 1/3.

Так что, хотя каждая двоичная дробь может быть записана в десятичной системе, обратное неверно. И фактически большинство десятичных дробей повторяются в двоичном формате.

Работа с ним

Разработчикам обычно дают указание & Lt; epsilon , лучшим советом может быть округление до целочисленных значений (в библиотеке C: round () и roundf (), т. е. оставаться в формате FP), а затем сравнивать. Округление до определенной длины десятичной дроби решает большинство проблем с выходом.

Кроме того, при реальных проблемах с хрустом (проблемы, которые FP был изобретен на ранних, ужасно дорогих компьютерах) физические константы Вселенной и все другие измерения известны только относительно небольшому числу значимых цифр, поэтому все пространство проблем было «неточным» в любом случае. FP «точность» не является проблемой в этом виде приложений.

Вся проблема действительно возникает, когда люди пытаются использовать FP для подсчета бобов. Это работает для этого, но только если вы придерживаетесь интегральных значений, какой вид поражает смысл его использования. Вот почему у нас есть все эти библиотеки программного обеспечения с десятичной дроби.

Мне нравится ответ на пиццу от Chris , потому что он описывает фактическую проблему, а не только обычная ручная работа о «неточности». Если бы FP были просто «неточными», мы могли бы исправить , что и сделали бы это несколько десятилетий назад. Причина, по которой у нас нет, - это то, что формат FP компактен и быстр, и это лучший способ хрустить множество чисел. Кроме того, это наследие космической эры и гонки вооружений и ранние попытки решить большие проблемы с очень медленными компьютерами с использованием небольших систем памяти. (Иногда отдельные магнитные сердечники для 1-битного хранилища, но это другая история. )

Заключение

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

7
задан rmaddy 12 February 2016 в 15:10
поделиться

3 ответа

Как рисовать путь безье в UIKit?

Создайте объект UIBezierPath, а затем используйте различные методы для его создания .

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

  • moveToPoint: (Справедливо самоочевидно, перемещает текущая точка к заданной точке)
  • addLineToPoint: (добавляет прямую линию, начиная с текущей точки и заканчивая в данной точке)
  • addCurveToPoint:controlPoint1:controlPoint2: (добавляет кривую безье, начиная текущую точку, с установленной конечной точкой и контрольными точками)
  • addQuadCurveToPoint:controlPoint: Добавляет квадратичную кривую , начиная с текущей точки, с установленной конечной точкой и контрольной точкой.

Например, что-то вроде этого создаст простой путь безье с квадратичной кривой:

UIBezierPath* yourPath = [UIBezierPath bezierPath]; // create the bezier path
[yourPath moveToPoint:CGPointMake(100, 100)]; // move to your starting point
[yourPath addQuadCurveToPoint:CGPointMake(300, 500) controlPoint:CGPointMake(500, 350)]; // add a new quad curve to the point

Однако, если вы привыкли использовать что-то вроде Photoshop для создания своих путей, вам может понравиться PaintCode , который позволяет создавать пути безье, используя «то, что вы видите» вы получите «подход».

Вы можете добавить это UIBezierPath к свойству path для CAShapeLayer, чтобы отобразить его на экране.

CAShapeLayer* yourShapeLayer = [CAShapeLayer layer]; // create your shape layer
yourShapeLayer.frame = CGRectMake(0, 0, 300, 500); // assign it's frame
yourShapeLayer.path = yourPath.CGPath; // add your path to the shape layer
yourShapeLayer.fillColor = [UIColor clearColor].CGColor; // prevent the shape layer from filling

[self.view.layer addSublayer:yourShapeLayer]; // add the shape layer to the view

Вы можете то легко установить t его свойства strokeColor и lineWidth на слое формы, чтобы настроить, как ваш путь поглаживается.

yourShapeLayer.strokeColor = [UIColor redColor].CGColor; // red stroke color
yourShapeLayer.lineWidth = 5.0; // 5 point stroke width

Вы должны получить что-то вроде этого:


Как я мог его оживить, как если бы невидимый карандаш рисовал это на экране?

Вы можете легко создать CABasicAnimation, который может анимировать свойство strokeStart или strokeEnd для CAShapeLayer для достижения желаемой анимации.

Это может привести к эффекту анимации линии, получаемой на экране.

Например, этот код приведет к анимации свойства strokeEnd с 0.0 до 1.0, создав желаемый эффект:

yourShapeLayer.strokeStart = 0.0; // reset stroke start before animating

CABasicAnimation* strokeAnim = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; // create animation that changes the strokeEnd property
strokeAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; // give it a nice timing function
strokeAnim.duration = 2.0; // duration of the animation
strokeAnim.fromValue = @(0.0); // provide the start value for the animation, wrapped in an NSNumber literal.
strokeAnim.toValue = @(1.0); // provide the end value for the animation, wrapped in an NSNumber literal.

[yourShapeLayer addAnimation:strokeAnim forKey:@"strokeAnim"]; // add animation to layer


Как я могу масштабировать этот путь для работы с экранами разного размера?

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

Итак, все, что нам нужно сделать, это генерировать наш масштабный коэффициент.

CGFloat sf = self.view.frame.size.width/500.0; // The factor to scale the path by

Тогда нам просто нужно несколько всех наших точек в UIBezierPath этот масштабный коэффициент. Например, взяв наш предыдущий путь:

UIBezierPath* yourPath = [UIBezierPath bezierPath]; // create the bezier path
[yourPath moveToPoint:CGPointMake(100.0*sf, 100.0*sf)]; // move to your starting point
[yourPath addQuadCurveToPoint:CGPointMake(300.0*sf, 500.0*sf) controlPoint:CGPointMake(500.0*sf, 350.0*sf)];

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

Вы также захотите изменить размер вашего CAShapeLayer так, чтобы он был квадратным и занимал всю ширину экрана.

yourShapeLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width);

Наконец, вы хотите поместить CAShapeLayer в центр экрана. Вы можете сделать это легко, установив свойство position слоя в center представления.

yourShapeLayer.position = self.view.center;

Теперь ваш путь должен всегда масштабироваться, чтобы занять ширину экрана.

(Я добавил серый фон к слою, чтобы проиллюстрировать масштабирование)


Полный проект (для вашего удобства): https://github.com/hamishknight/Drawing-Scaling-Animating-UIBezierPaths

20
ответ дан Hamish 23 August 2018 в 16:17
поделиться

Я написал об этом в 2010 году: Анимация рисунка CGPath с CAShapeLayer .

Суть в этом:

  • Создайте UIBezierPath или CGPath с фигурой, которую вы хотите нарисовать. Используйте методы moveToPoint:, addLineToPoint:, addCurveToPoint:controlPoint1:controlPoint2: и т. Д. Для создания фигуры.
  • Создайте CGShapeLayer и назначьте путь к свойству path уровня.
  • Добавьте слой в иерархию вида / уровня (например, в контроллере вида: [self.view.layer addSublayer:shapeLayer];).
  • Анимировать свойство слоя strokeEnd слоя от 0 до 1.
2
ответ дан Ole Begemann 23 August 2018 в 16:17
поделиться

Ответ, отправленный originaluser2, решает все. Вы также можете попробовать этот способ, если хотите изменить размер пути безье для разных экранов:

Вы можете просто подклассифицировать UIView и настроить его метод drawRect:

  - (void)drawRect: (CGRect)frame
{

    //// Bezier Drawing
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.23370 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame))];
[bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.49457 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.33088 * CGRectGetHeight(frame)) controlPoint1: CGPointMake(CGRectGetMinX(frame) + 0.23370 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame)) controlPoint2: CGPointMake(CGRectGetMinX(frame) + 0.35870 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.33088 * CGRectGetHeight(frame))];
[bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77717 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame)) controlPoint1: CGPointMake(CGRectGetMinX(frame) + 0.63043 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.33088 * CGRectGetHeight(frame)) controlPoint2: CGPointMake(CGRectGetMinX(frame) + 0.77717 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.65441 * CGRectGetHeight(frame))];
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];

}

frame 50x50:

кадр 100x100:

кадр 100x50

Это рисует кривую Безье в кадре размером 50x50, если вы отправляете кадр размером 50x50. Также этот код автоматически изменяется в зависимости от размера кадра, который он получает.

1
ответ дан Teja Nandamuri 23 August 2018 в 16:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: