una tangente resueltos recta punto parametricas normal integrales hallar ejercicios ecuaciones ecuacion derivada dela curva con calculadora ios swift bezier

ios - resueltos - Encuentra la tangente de un punto en una curva cúbica bezier



recta tangente a una curva en un punto (5)

Para una curva de Bézier cúbica con los cuatro puntos habituales a, b, c y d,

para un valor dado t,

¿Cómo encontrar con más elegancia la tangente en ese punto?


Aquí está el código completamente probado para copiar y pegar:

Dibuja puntos aproximados a lo largo de la curva, y dibuja las tangentes.

bezierInterpolation encuentra los puntos

bezierTangent encuentra las tangentes

Hay DOS VERSIONES de bezierInterpolation suministradas a continuación:

bezierInterpolation funciona perfectamente

altBezierInterpolation es exactamente lo mismo, PERO está escrito de manera expandida, muy clara y explicativa. Hace que la aritmética sea mucho más fácil de entender.

Utilice cualquiera de estas dos rutinas: los resultados son idénticos.

En ambos casos, use bezierTangent para encontrar las tangentes. (Nota: la fabulosa base de códigos de Michal here ).

También se incluye un ejemplo completo de cómo usar con drawRect:

// MBBezierView.m original BY MICHAL #4058979 #import "MBBezierView.h" CGFloat bezierInterpolation( CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) { // see also below for another way to do this, that follows the ''coefficients'' // idea, and is a little clearer CGFloat t2 = t * t; CGFloat t3 = t2 * t; return a + (-a * 3 + t * (3 * a - a * t)) * t + (3 * b + t * (-6 * b + b * 3 * t)) * t + (c * 3 - c * 3 * t) * t2 + d * t3; } CGFloat altBezierInterpolation( CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) { // here''s an alternative to Michal''s bezierInterpolation above. // the result is absolutely identical. // of course, you could calculate the four ''coefficients'' only once for // both this and the slope calculation, if desired. CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a ); CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) ); CGFloat C3 = ( (3.0 * b) - (3.0 * a) ); CGFloat C4 = ( a ); // it''s now easy to calculate the point, using those coefficients: return ( C1*t*t*t + C2*t*t + C3*t + C4 ); } CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) { // note that abcd are aka x0 x1 x2 x3 /* the four coefficients .. A = x3 - 3 * x2 + 3 * x1 - x0 B = 3 * x2 - 6 * x1 + 3 * x0 C = 3 * x1 - 3 * x0 D = x0 and then... Vx = 3At2 + 2Bt + C */ // first calcuate what are usually know as the coeffients, // they are trivial based on the four control points: CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a ); CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) ); CGFloat C3 = ( (3.0 * b) - (3.0 * a) ); CGFloat C4 = ( a ); // (not needed for this calculation) // finally it is easy to calculate the slope element, // using those coefficients: return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 ); // note that this routine works for both the x and y side; // simply run this routine twice, once for x once for y // note that there are sometimes said to be 8 (not 4) coefficients, // these are simply the four for x and four for y, // calculated as above in each case. } @implementation MBBezierView - (void)drawRect:(CGRect)rect { CGPoint p1, p2, p3, p4; p1 = CGPointMake(30, rect.size.height * 0.33); p2 = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); p3 = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); p4 = CGPointMake(-30 + CGRectGetMaxX(rect), rect.size.height * 0.66); [[UIColor blackColor] set]; [[UIBezierPath bezierPathWithRect:rect] fill]; [[UIColor redColor] setStroke]; UIBezierPath *bezierPath = [[[UIBezierPath alloc] init] autorelease]; [bezierPath moveToPoint:p1]; [bezierPath addCurveToPoint:p4 controlPoint1:p2 controlPoint2:p3]; [bezierPath stroke]; [[UIColor brownColor] setStroke]; // now mark in points along the bezier! for (CGFloat t = 0.0; t <= 1.00001; t += 0.05) { [[UIColor brownColor] setStroke]; CGPoint point = CGPointMake( bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x), bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y)); // there, use either bezierInterpolation or altBezierInterpolation, // identical results for the position // just draw that point to indicate it... UIBezierPath *pointPath = [UIBezierPath bezierPathWithArcCenter:point radius:5 startAngle:0 endAngle:2*M_PI clockwise:YES]; [pointPath stroke]; // now find the tangent if someone on knows how CGPoint vel = CGPointMake( bezierTangent(t, p1.x, p2.x, p3.x, p4.x), bezierTangent(t, p1.y, p2.y, p3.y, p4.y)); // the following code simply draws an indication of the tangent CGPoint demo = CGPointMake( point.x + (vel.x*0.3), point.y + (vel.y*0.33) ); // (the only reason for the .3 is to make the pointers shorter) [[UIColor whiteColor] setStroke]; UIBezierPath *vp = [UIBezierPath bezierPath]; [vp moveToPoint:point]; [vp addLineToPoint:demo]; [vp stroke]; } } @end to draw that class... MBBezierView *mm = [[MBBezierView alloc] initWithFrame:CGRectMake(400,20, 600,700)]; [mm setNeedsDisplay]; [self addSubview:mm];

Aquí están las dos rutinas para calcular puntos aproximadamente equidistantes, y las tangentes de esos , a lo largo de una cúbica bezier.

Para mayor claridad y confiabilidad, estas rutinas están escritas de la manera más simple y explicativa posible.

CGFloat bezierPoint(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) { CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a ); CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) ); CGFloat C3 = ( (3.0 * b) - (3.0 * a) ); CGFloat C4 = ( a ); return ( C1*t*t*t + C2*t*t + C3*t + C4 ); } CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) { CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a ); CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) ); CGFloat C3 = ( (3.0 * b) - (3.0 * a) ); CGFloat C4 = ( a ); return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 ); }

Los cuatro valores precalculados, C1 C2 C3 C4, a veces se llaman los coeficientes del bezier. (Recuerde que abcd se suele llamar los cuatro puntos de control ).

Por supuesto, t va de 0 a 1, por ejemplo, cada 0.05.

Simplemente llame a estas rutinas una vez para X, y luego una vez por separado para Y.

Espero que ayude a alguien!

Hechos importantes:

(1) Es un hecho absoluto que: desafortunadamente, no existe ningún método, proporcionado por Apple, para extraer puntos de un UIBezierPath.

(2) No olvides que es tan fácil como un pastel animar algo a lo largo de un UIBezierPath. Google muchos ejemplos .

(3) Muchos preguntan: "¿No se puede utilizar CGPathApply para extraer los puntos de un UIBezierPath?" No, CGPathApply no tiene ninguna relación : simplemente le proporciona una lista de sus instrucciones para hacer cualquier ruta (así que, "comience aquí", "dibuje una línea recta hasta este punto", etc., etc.)


Aquí va mi implementación Swift.

Lo que hice lo mejor que pude para optimizar la velocidad, eliminando todas las operaciones matemáticas redundantes. Es decir, hacer el número mínimo de llamadas a las operaciones matemáticas. Y use el menor número posible de multiplicaciones (que son mucho más caras que las sumas).

Hay 0 multiplicaciones para crear el bezier. Luego 3 multiplicaciones para obtener un punto de bezier. Y 2 multiplicaciones para obtener una tangente al bezier.

struct CubicBezier { private typealias Me = CubicBezier typealias Vector = CGVector typealias Point = CGPoint typealias Num = CGFloat typealias Coeficients = (C: Num, S: Num, M: Num, L: Num) let xCoeficients: Coeficients let yCoeficients: Coeficients static func coeficientsOfCurve(from c0: Num, through c1: Num, andThrough c2: Num, to c3: Num) -> Coeficients { let _3c0 = c0 + c0 + c0 let _3c1 = c1 + c1 + c1 let _3c2 = c2 + c2 + c2 let _6c1 = _3c1 + _3c1 let C = c3 - _3c2 + _3c1 - c0 let S = _3c2 - _6c1 + _3c0 let M = _3c1 - _3c0 let L = c0 return (C, S, M, L) } static func xOrYofCurveWith(coeficients coefs: Coeficients, at t: Num) -> Num { let (C, S, M, L) = coefs return ((C * t + S) * t + M) * t + L } static func xOrYofTangentToCurveWith(coeficients coefs: Coeficients, at t: Num) -> Num { let (C, S, M, _) = coefs return ((C + C + C) * t + S + S) * t + M } init(from start: Point, through c1: Point, andThrough c2: Point, to end: Point) { xCoeficients = Me.coeficientsOfCurve(from: start.x, through: c1.x, andThrough: c2.x, to: end.x) yCoeficients = Me.coeficientsOfCurve(from: start.y, through: c1.y, andThrough: c2.y, to: end.y) } func x(at t: Num) -> Num { return Me.xOrYofCurveWith(coeficients: xCoeficients, at: t) } func y(at t: Num) -> Num { return Me.xOrYofCurveWith(coeficients: yCoeficients, at: t) } func dx(at t: Num) -> Num { return Me.xOrYofTangentToCurveWith(coeficients: xCoeficients, at: t) } func dy(at t: Num) -> Num { return Me.xOrYofTangentToCurveWith(coeficients: yCoeficients, at: t) } func point(at t: Num) -> Point { return .init(x: x(at: t), y: y(at: t)) } func tangent(at t: Num) -> Vector { return .init(dx: dx(at: t), dy: dy(at: t)) } }

Utilizar como

let bezier = CubicBezier.init(from: .zero, through: .zero, andThrough: .zero, to: .zero) let point02 = bezier.point(at: 0.2) let point07 = bezier.point(at: 0.7) let tangent01 = bezier.tangent(at: 0.1) let tangent05 = bezier.tangent(at: 0.5)


La tangente de una curva es simplemente su derivada. La ecuación paramétrica que usa Michal:

P(t) = (1 - t)^3 * P0 + 3t(1-t)^2 * P1 + 3t^2 (1-t) * P2 + t^3 * P3

debe tener un derivado de

dP(t) / dt = -3(1-t)^2 * P0 + 3(1-t)^2 * P1 - 6t(1-t) * P1 - 3t^2 * P2 + 6t(1-t) * P2 + 3t^2 * P3

Lo que, por cierto, parece estar equivocado en su pregunta anterior. Creo que estás usando la pendiente para una curva Bezier cuadrática allí, no cúbica.

A partir de ahí, debería ser trivial implementar una función C que realice este cálculo, como Michal ya ha proporcionado para la curva en sí.


Me pareció demasiado propenso a errores al usar las ecuaciones proporcionadas. Demasiado fácil perder un soporte sutil o mal colocado.

En contraste, Wikipedia proporciona un IMHO mucho más claro, claro y derivado:

... que se implementa fácilmente en el código como:

3f * oneMinusT * oneMinusT * (p1 - p0) + 6f * t * oneMinusT * (p2 - p1) + 3f * t * t * (p3 - p2)

(asumiendo que tiene vector-minus configurado en el idioma de su elección; la pregunta no está marcada específicamente como ObjC e iOS ahora tiene varios idiomas disponibles)


No pude hacer que nada de esto funcionara hasta que me di cuenta de que para las ecuaciones paramétricas, (dy / dt) / (dx / dt) = dy / dx