Calcul d'un "endPoint" en fonction d'un angle
Bonjour,
Je crée ce topic car je suis un peu perdu dans mes formules mathématiques..
Dans le but de créer un wrapper Objective-C pour CGGradient (pour iOS, NSGradient n'étant pas dispo pour cette plateforme).
Je me base donc entièrement sur NSGradient pour essayer de re-créer à l'identique mon wrapper CGGradient.
La méthode -drawInRect:angle: me pose problème, puisque CGGradient requiert un startPoint et un endPoint.
Ci dessous, un tableau (issu de NSGradient) qui liste les 4 startPoint possibles selon l'angle:
Si on prend donc un angle à 90°, mon gradient aura un startPoint de maxX(rect), maxY(rect), et un endPoint de maxX(rect), minY(rect).
Pour un angle à 0 ou 360°, mon gradient aura un startPoint de minX(rect), maxY(rect), et un endPoint de maxX(rect), maxY(rect).
Voilà pour les deux exemples. Le startPoint est donc facile à déterminer puisqu'il suffit de suivre le tableau.
J'ai donc procédé comme suit:
Je ne suis pas trop fan de ces conditions, mais je ne vois pas d'autre solution pour l'instant.
Le gros problème pour moi c'est le calcul du endPoint. Ma première erreur aura été de me baser sur un carrée pour essayer de trouver une formule adéquate... Il vaut mieux partir sur un rectangle.. 6x4 par exemple..
Quelques exemples simples pour le endPoint à des valeurs précises pour une forme carrée:
0° : Starts from lower-left, Ends to lower-right
45° : Starts from lower-left, Ends to upper-right
90° : Starts from lower-right, Ends to upper-right
Je ne sais pas quoi indiquer de plus.. J'espère simplement que vous avez cerné mon problème, et surtout le but..
Je crée ce topic car je suis un peu perdu dans mes formules mathématiques..
Dans le but de créer un wrapper Objective-C pour CGGradient (pour iOS, NSGradient n'étant pas dispo pour cette plateforme).
Je me base donc entièrement sur NSGradient pour essayer de re-créer à l'identique mon wrapper CGGradient.
La méthode -drawInRect:angle: me pose problème, puisque CGGradient requiert un startPoint et un endPoint.
Ci dessous, un tableau (issu de NSGradient) qui liste les 4 startPoint possibles selon l'angle:
0-89° : Lower-left (minX,maxY)
90-179° : Lower-right (maxX,maxY)
180-269° : Upper-right (maxX, minY)
270-359° : Upper-left (minX,minY)
Si on prend donc un angle à 90°, mon gradient aura un startPoint de maxX(rect), maxY(rect), et un endPoint de maxX(rect), minY(rect).
Pour un angle à 0 ou 360°, mon gradient aura un startPoint de minX(rect), maxY(rect), et un endPoint de maxX(rect), maxY(rect).
Voilà pour les deux exemples. Le startPoint est donc facile à déterminer puisqu'il suffit de suivre le tableau.
J'ai donc procédé comme suit:
<br />
<br />
- (CGFloat)__positiveAngleFromAngle:(CGFloat)angle<br />
{<br />
return (CGFloat)((360+((int)(round(angle)) % 360))%360);<br />
}<br />
<br />
- (CGPoint)__startLocationForAngle:(CGFloat)angle inRect:(CGRect)rect<br />
{<br />
CGPoint startLocation = CGPointZero;<br />
CGFloat positiveAngle = [self __positiveAngleFromAngle:angle];<br />
<br />
if (positiveAngle < 90.0f)<br />
startLocation = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect));<br />
else if (positiveAngle < 180.0f)<br />
startLocation = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));<br />
else if (positiveAngle < 270.0f)<br />
startLocation = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));<br />
else<br />
startLocation = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));<br />
<br />
return startLocation;<br />
}<br />
Je ne suis pas trop fan de ces conditions, mais je ne vois pas d'autre solution pour l'instant.
Le gros problème pour moi c'est le calcul du endPoint. Ma première erreur aura été de me baser sur un carrée pour essayer de trouver une formule adéquate... Il vaut mieux partir sur un rectangle.. 6x4 par exemple..
Quelques exemples simples pour le endPoint à des valeurs précises pour une forme carrée:
0° : Starts from lower-left, Ends to lower-right
45° : Starts from lower-left, Ends to upper-right
90° : Starts from lower-right, Ends to upper-right
Je ne sais pas quoi indiquer de plus.. J'espère simplement que vous avez cerné mon problème, et surtout le but..
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Quand tu fais un gradient par exemple horizontal, qui va de gauche à droite, tu peux mettre le startPoint tout à gauche de ton rect, et le endPoint soit tout à droite... soit à droite du startPoint, mais sur le chemin qui va jusqu'au bord droit, et pas forcément tout au bout. Le vecteur [startPoint ... endPoint] définit à la fois la direction du gradient (selon la direction du segment) mais aussi son étalement (selon la longueur du vecteur, donc la distance entre startPoint et endPoint). Plus tes 2 points seront éloignés, plus le gradient sera étiré.
C'est ce qui se passe sous Photoshop par exemple quand tu prend l'outil gradient, tu cliques pour positionner le startPoint, et ensuite quand tu drag ta souris dans une direction données, tu étires le gradient plus tu t'éloignes de ton point de départ.
Après peut-être que tu veux que ton endPoint soit le point à l'intérieur de ton rect qui soit le plus loin possible de ton startPoint -- pour étirer au maximum ton gradient tout en étant sûr de voir toutes les couleurs du panel du gradient (y compris la endColor quoi) -- mais dans la direction définie par ton angle demandé ? Ou pas ?
Il faut que tu nous précise exactement ce que tu veux pour ce endPoint
Pour un rect {0,0,6,4} et un angle de 45°.. le startPoint se trouve donc à {minX, maxY} mais le endPoint se trouve à {4,0}
Si ça avait été un carré {0,0,6,6}, par exemple, toujours avec un angle de 45°, le endPoint se serait trouvé à {6,0}
De plus, je n'ai pas la main sur la valeur de l'angle.. On pourrait très bien passer 75°..
L'idée est de trouver l'intersection entre la demi-droite D qui part de startPoint et va dans la direction spécifiée par ton angle, et ton rectangle. Cette intersection va se placer soit sur le bord vertical opposé à ton startPoint, soit sur le bord horizontal.
Donc du coup l'idée est de calculer l'intersection de ta demi-droite D avec chacun des 2 bords opposés, pour trouver les intersections E1 et E2 sur ma capture. Et de retenir le point entre E1 et E2 qui est le plus proche. Dans mon exemple ci-dessous, si ton angle est petit, c'est E1 (intersection avec le bord vertical opposé) qui sera le plus proche et donc retenu, si ton angle est plus grand c'est E2 qui sera plus proche de S.
Dans l'idée ça donnerait un truc du genre :
Non il est bon.. L'angle est bien de 45°
surtout que l'on était jeudi /biggrin.png' class='bbc_emoticon' alt=':D' />
Merci !
Le premier exemple est ce à quoi je m'attendais, mais vraiment, le second exemple est plus proche du résultat du NSGradient. Son implémentation est également plus simple, et comme je pense qu'Apple est allé au plus simple, je ne dois pas être très loin ;-)
Cool, allez encore1599 classes a faire et hop on a OSX en open source /smile.png' class='bbc_emoticon' alt=':)' />
Peut-être sur le site cocotron.org, il ont fait la classe?
Je n'y avais même pas songé. Oui, elle y est!
Et le schéma qui donne des explications.