60 votes

algorithme de dessin de croquis lisse iPhone

Je suis en train de travailler sur un croquis de l'app sur l'iPhone. Je l'ai eu à travailler, mais pas assez comme on le voit ici enter image description here

Et je suis à la recherche de toute suggestion pour lisser le dessin Fondamentalement, ce que j'ai fait, c'est quand l'utilisateur place un doigt sur l'écran, j'ai appelé

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 

puis-je percevoir une touche unique dans un tableau avec

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

et lorsque l'utilisateur lefts un doigt de l'écran, j'ai appelé

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

je dessine ensuite tous les points dans le tableau à l'aide de

NSMutableArray *points = [collectedArray points];   

CGPoint firstPoint;
[[points objectAtIndex:0] getValue:&firstPoint];

CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);

for (int i=1; i < [points count]; i++) {
    NSValue *value = [points objectAtIndex:i];
    CGPoint point;
    [value getValue:&point];    
    CGContextAddLineToPoint(context, point.x, point.y);

} 

CGContextStrokePath(context);
UIGraphicsPushContext(context);

Et maintenant, je veux améliorer le dessin de tobe plus comme "Carnet de Croquis" App enter image description here

Je pense qu'il y a quelque chose à voir avec l'algorithme de traitement du signal pour réorganiser tous les points dans le tableau, mais je ne suis pas sûr. Toute Aide serait grandement appréciée.

Thankz à l'avance :)

56voto

kyoji Points 431
CGPoint midPoint(CGPoint p1, CGPoint p2)
{

    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *touch = [touches anyObject];

    previousPoint1 = [touch previousLocationInView:self];
    previousPoint2 = [touch previousLocationInView:self];
    currentPoint = [touch locationInView:self];

}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *touch = [touches anyObject];

    previousPoint2 = previousPoint1;
    previousPoint1 = [touch previousLocationInView:self];
    currentPoint = [touch locationInView:self];


    // calculate mid point
    CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2 = midPoint(currentPoint, previousPoint1);

    UIGraphicsBeginImageContext(self.imageView.frame.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [self.imageView.image drawInRect:CGRectMake(0, 0, self.imageView.frame.size.width, self.imageView.frame.size.height)];

    CGContextMoveToPoint(context, mid1.x, mid1.y);
    // Use QuadCurve is the key
    CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 

    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
    CGContextStrokePath(context);

    self.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

}

22voto

Brad Larson Points 122629

La façon la plus simple pour lisser une courbe comme cela est d'utiliser une courbe de Bézier au lieu de segments de ligne droite. Pour les maths derrière tout cela, voir cet article (souligné dans cette réponse), qui décrit la façon de calculer les courbes nécessaire pour lisser une courbe qui passe par plusieurs points.

Je crois que le Cœur de l'Intrigue cadre a désormais la possibilité de lisser les courbes de parcelles, de sorte que vous pourriez regarder le code utilisé ici pour mettre en oeuvre ce type de lissage.

Il n'y a rien de magique dans tout cela, que ces lissage routines sont rapides et relativement facile à mettre en œuvre.

18voto

entrez la description de l'image ici

J'ai écrit un exemple de projet et un article de blog expliquant les concepts de base relatifs à la création d'une telle application de dessin avec opengl / cocos2d: http://www.merowing.info/2012/04/drawing-smooth-lines-with-cocos2d-ios-inspired-by -papier/

15voto

alex Points 150

J'aime vraiment le sujet. Merci pour toutes les implémentations, espesially Krzysztof Zabłocki et Yu-Sen Han. J'ai modifié la version de Yu-Sen Han pour changer l'épaisseur de la ligne en fonction de la vitesse de panoramique (en fait, la distance entre la dernière touche). Aussi j'ai mis en place dot dessin (pour touchBegan et touchEnded des emplacements proches les uns des autres) Voici le résultat: enter image description here

Pour définir l'épaisseur de ligne, j'ai choisi une fonction de la distance:

(Ne me demandez pas pourquoi... je viens si elle convient bien, mais je suis sûr que vous pouvez trouver mieux)

enter image description here

CGFloat dist = distance(previousPoint1, currentPoint);
CGFloat newWidth = 4*(atan(-dist/15+1) + M_PI/2)+2;

Une allusion plus. Pour être sûr que l'épaisseur est en train de changer en douceur, j'ai délimité en fonction de l'épaisseur du segment précédent et une coutume coef:

self.lineWidth = MAX(MIN(newWidth,lastWidth*WIDTH_RANGE_COEF),lastWidth/WIDTH_RANGE_COEF);

12voto

Raj Points 1740

Tracer une ligne lisse

Ceci est un exemple de projet de dessin

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X