CGPath : appliquer une CGAffineTransform

AliGatorAliGator Membre, Modérateur
février 2009 modifié dans API UIKit #1
Bon juste pour info, j'ai fait la fonction CGPathApplyTransform, que j'ai en fait appelée CGPathCreateTransformedMutableCopy pour que le nom soit plus clair (et fasse penser à  faire le CGPathRelease dessus) :
<br />typedef struct {<br />	CGMutablePathRef newPath;<br />	CGAffineTransform* transform;<br />} CGPathInfoData;<br /><br />void PathElementTransform(void* info, const CGPathElement* element)<br />{<br />	CGPathInfoData* infoData = (CGPathInfoData*)info;<br />	switch(element-&gt;type)<br />	{<br />		case kCGPathElementMoveToPoint:<br />			CGPathMoveToPoint(infoData-&gt;newPath, infoData-&gt;transform, element-&gt;points[0].x, element-&gt;points[0].y);<br />			break;<br />		case kCGPathElementAddLineToPoint:<br />			CGPathAddLineToPoint(infoData-&gt;newPath, infoData-&gt;transform, element-&gt;points[0].x, element-&gt;points[0].y);<br />			break;<br />		case kCGPathElementAddQuadCurveToPoint:<br />			CGPathAddQuadCurveToPoint(infoData-&gt;newPath, infoData-&gt;transform, element-&gt;points[0].x, element-&gt;points[0].y, element-&gt;points[1].x, element-&gt;points[1].y);<br />			break;<br />		case kCGPathElementAddCurveToPoint:<br />			CGPathAddCurveToPoint(infoData-&gt;newPath, infoData-&gt;transform, element-&gt;points[0].x, element-&gt;points[0].y, element-&gt;points[1].x, element-&gt;points[1].y, element-&gt;points[2].x, element-&gt;points[2].y);<br />			break;<br />		case kCGPathElementCloseSubpath:<br />			CGPathCloseSubpath(infoData-&gt;newPath);<br />			break;<br />	}<br />}<br /><br />/** @brief Create a MutableCopy of path, after applying the transform matrix.<br /> *<br /> * path is untouched, to you still have the responsability to call CGPathRelease on it<br /> * the returned path has a retainCount of 1 so you also have the responsability to call CGPathRelease on it when done.<br /> *<br /> * Call example :<br /> * &nbsp; CGPathRef p = ...<br /> * &nbsp; CGMutablePathRef mp = CGPathCreateTransformedMutableCopy(p, CGAffineTransformMakeRotation(M_PI_4));<br /> * &nbsp; CGPathRelease(p);<br /> * &nbsp; ...<br /> * &nbsp; // p is not valid anymore, and typically you do sthg with mp here<br /> * &nbsp; ...<br /> * &nbsp; CGPathRelease(mp);<br /> */<br />CGMutablePathRef CGPathCreateTransformedMutableCopy(const CGPathRef path, CGAffineTransform m)<br />{<br />	CGPathInfoData infoData;<br />	infoData.newPath = CGPathCreateMutable();<br />	infoData.transform = &amp;m;<br />	<br />	CGPathApply(path, &amp;infoData, PathElementTransform);<br />	<br />	return infoData.newPath;<br />}<br />
A priori de ce que j'ai testé, elle fonctionne comme il faut, donc bon après à  creuser plus profondément avant de dire qu'elle est bug-free mais bon. Ca peut toujours servir.

Cependant, cela reste lourd car recrée un CGPath (attention le CGPath créé a un retainCount de 1 et de plus ne touche pas au CGPath passé en argument... donc il faudra penser à  faire un CGPathRelease non seulement sur le CGPath qu'on a passé en argument, mais aussi sur le CGMutablePathRef retourné par la fonction CGPathCreateTransformedMutableCopy, comme indiqué dans les commentaires).
Il est donc souvent bien plus préférable d'appliquer la transformation lors du dessin, et d'appliquer la transformation inverse (surtout si ce n'est qu'une translation) sur le CGPoint quand c'est un test type containsPoint qu'on veut faire.

Réponses

  • schlumschlum Membre
    04:50 modifié #2
    Un handle CoreGraphics qui aurait un retainCount... On m'aurait menti ?  :P
  • AliGatorAliGator Membre, Modérateur
    février 2009 modifié #3
    Hé oui, les types CoreGraphics aussi on un retainCount !
    Enfin il est p'tet pas géré pile pareil qu'en Cocoa, mais il n'empêche qu'il existe les méthodes CGPathRetain et CGPathRelease... et que quand on crée un CGPath via CGPathCreateMutable ou CGPathCopy ou CGPathMutableCopy, il faut faire un CGPathRelease pour balancer... comme avec retain/release en Cocoa ;)

    En fait tout est basé sur CFRetain/CFRelease sous le capot.
    CGPathRetain
    Increments the retain count of a graphics path.

    [tt]CGPathRef CGPathRetain (
       CGPathRef path
    );[/tt]
    Parameters
    path
    The graphics path to retain.

    Return Value
    The same path you passed in as the path parameter.

    Discussion
    This function is equivalent to CFRetain, except that it does not cause an error if the path parameter is NULL.
    CGPathRelease
    Decrements the retain count of a graphics path.

    [tt]void CGPathRelease (
       CGPathRef path
    );[/tt]
    Parameters
    path
    The graphics path to release.

    Discussion
    This function is equivalent to CFRelease, except that it does not cause an error if the path parameter is NULL.
    Donc oui, CoreFoundation utilise la mécanique des retainCount aussi :o et les CGPath aussi par voie de fait  ;)
  • schlumschlum Membre
    04:50 modifié #4
    Ah oui, exact, c'est l'autoRelease (qui serait adéquat dans ce cas...) qui manque  o:)
  • Philippe49Philippe49 Membre
    04:50 modifié #5
    Sans compter avec CFGetRetainCount()

    Pour l'autorelease j'avais trouvé
    #define CGAutorelease(x) (__typeof(x))[NSMakeCollectable(x) autorelease]
    mais il y a peut-être mieux ...

  • AliGatorAliGator Membre, Modérateur
    04:50 modifié #6
    Heu j'ai pas regardé NSMakeCollectable mais ça ressemble à  s'y méprendre, vu le nom, à  du Garbage-Collector plus q'à  de l'autorelease... donc si le GC n'est pas activé, qu'est ce que ça fait ?!

    PS : Je ne suis pas sûr que cette discussion ait sa place ici... on commence à  dériver là ... on pourrait pas splitter les sujets ?
  • Philippe49Philippe49 Membre
    04:50 modifié #7
    NSMakeCollectable
    Makes a newly allocated Core Foundation object eligible for collection.

    NS_INLINE id NSMakeCollectable(CFTypeRef cf) {
      return cf ? (id)CFMakeCollectable(cf) : nil;
    }
    Discussion
    This function is a wrapper for CFMakeCollectable, but its return type is id"avoiding the need for casting when using Cocoa objects.

    This function may be useful when returning Core Foundation objects in code that must support both garbage-collected and non-garbage-collected environments, as illustrated in the following example.

    - (CFDateRef)foo {
        CFDateRef aCFDate;
        // ...
        return [NSMakeCollectable(aCFDate) autorelease];
    }


  • AliGatorAliGator Membre, Modérateur
    04:50 modifié #8
    Ouch... ouais ça (appeler autorelease sur l'objet, casté en "id") ça marche parce que CFDateRef et NSDate sont toll-free bridged, non ? Si ce n'était pas le cas et donc qu'on pouvais pas considérer un CFDateRef comme un objet Cocoa (id), on ne pourrait pas faire ça, me trompe-je ?

    Et puis c'est pas aussi simple/propre que ça j'ai l'impression, en tout cas moi ça m'embrouille un peu j'aurais peur de faire des leaks selon si on est dans un environnement avec ou sans GC...
    Because CFMakeCollectable is a no-op in a reference counted environment, if you use it with mixed mode code you do need to use CFRelease when running without garbage collection.
    CFStringRef myCFString = CFMakeCollectable(CFStringCreate...(...));<br />// do interesting things with myCFString...<br />if ([NSGarbageCollector defaultCollector] == NULL) CFRelease(myCFString);
    

    It is important to appreciate the asymmetry between Core Foundation and Cocoa"where retain, release, and autorelease are no-ops. If, for example, you have balanced a CFCreate... with release or autorelease, you will leak the object in a garbage collected environment:
    NSString *myString = (NSString *)CFStringCreate...(...);<br />// do interesting things with myString...<br />[myString release]; // leaked in a garbage collected environment
    
  • Philippe49Philippe49 Membre
    mars 2009 modifié #9
    Bon un essai sans Garbage Collector qui ne produit aucun leak selon Instruments :

    CGPathRef gPath=CGAutorelease(CGPathCreateMutable());<br />	CGColorRef color=CGAutorelease(CGColorCreateGenericRGB(1.,1.,1.,1.));<br />	int n=12;<br />	CFNumberRef number=CGAutorelease(CFNumberCreate (kCFAllocatorDefault,	kCFNumberSInt32Type,&amp;n));<br />	CFStringRef cfString=CGAutorelease(CFSTR(&quot;Coucou&quot;));<br />	CGImageRef imageRef=CGImageAtPath(@&quot;/Users/Bureau/Desktop/Lune.JPG&quot;);<br />	CFDateFormatterRef df=CGAutorelease(CFDateFormatterCreate(kCFAllocatorDefault,NULL,kCFDateFormatterNoStyle,kCFDateFormatterNoStyle));<br />
    


    Le dernier est surement non toll-free bridged si on en croit la doc

    Maintenant, j'ai pris ce procédé sur les exemples Core-Animation de Theo-Cacao, et je n'ai pas d'autres références. (les autres sites qui l'utilisent sont celui que j'ai fait sur Core Animation, et quelques autres qui semblent s'en inspirer, alors ... )
Connectez-vous ou Inscrivez-vous pour répondre.