La question traitée ici concerne le mapping de données dans un espace cyclique. Le traitement d'angle est le premier qui me vient en tête.
manipulation:
code:
First important method is cyclic_bound. Its role is to remap any value in the given range [from_in,from_out]. It's a modulo in both directions.
function cyclic_bound( value, from_in, from_out ) { if ( value >= from_in && value <= from_out ) { return value; } var d = from_out - from_in; while( value < from_in ) { value += d; } while( value > from_out ) { value -= d; } return value; }
cyclic_bound is applied on all entries of the mapping function.
Mapping the value, steps:
Once done, we have everything we need to render the value mapped form the world range to the new range. Note that the returned value will also be bounded to world range.
The process to do so:
function cyclic_map( value, from_in, from_out, to_in, to_out ) { var half = ( from_out - from_in ) * 0.5; var bvalue = cyclic_bound( value, from_in, from_out ); var bin = cyclic_bound( to_in, from_in, from_out ); var bout = cyclic_bound( to_out, from_in, from_out ); var bmid = cyclic_bound( to_in + ( to_out - to_in ) * 0.5, from_in, from_out ); var pc = cyclic_bound( ( bvalue - bmid ) / half, -1, 1 ); var brange = cyclic_bound( half - ( bmid - bin ), -half, half ); if ( pc >= 0 ) { return cyclic_bound( bout + (brange * pc), from_in, from_out ); } return cyclic_bound( bin + (brange * pc), from_in, from_out ); }
The tests below test all cases where lower limit bin is the closest form given value.
// possible configurations of the In, Mid and Out: // I M O > "normal" // M O I > "rejected in" // O I M > "rejected out" // booleans normal therm speciaL term restriction boolean cnormal = (bin <= bmid) && (bmid < bout); boolean crejected_in = (bmid <= bout) && (bin > bmid); boolean crejected_out = (bin <= bmid) && (bout < bmid) && !cnormal; if ( cnormal && ( ( bvalue <= bmid && bvalue >= bmid - half ) || bvalue >= bmid + half ) ) { return bin; } else if ( crejected_in && ( bvalue <= bmid || bvalue > bmid + half ) ) { return bin; } else if ( crejected_out && ( bvalue < bmid && bvalue >= bmid - half ) ) { return bin; } return bout;
|--------*-----------------*-----------*--------------*--------| 0 a b c d 2PI
l´idée est d´écarter 2 valeurs consécutives, b et c par ex, et de rediffuser les 2 autres, a et d, de manière proportionnelle
pour ce faire > calcul du point médian x
|--------*-----------------*-----!-----*--------------*--------| 0 a b x c d 2PI
distance bx = (c-b) x = b + bx/2
le remap spécifie les nouvelles valeurs de b et de c
|--------*--------<--------*-----!-----*-------->------*--------| 0 a b´ b x c c´ d 2PI
distance b´x = (c´-b´) x = b + bx/2
on a donc perdu (b´x - bx) radians
|----*---------|----*---------|----*---------| -2PI a´ 0 a 2PI a´´ 4PI
ce qu´il ne faut pas oublier: l´espace est cyclique > a´ ~ a ~ a´´
on peut descendre en négatif et passer 2PI sans que ça pose de réel problème
|---!--------*-----------*-----*----------*-----|---!--------* 0 x´ a b c d 2PI x a´ 3 11 22 27 37 42 45 53
l´angle entre d et a est à plusieurs positions simultanément pour son calcul: ( d + a ) / 2 - ( 37 + 11 ) -> 48!!!!, divisé par 2, on arrive à 24, donc pas du tout où il faut! il faut ajouter 42 à a => 53, et là: (37+57)/2, 90/2 => 45 paf! si a < d,
a += 2PI
center = (d+a)/2
dans le remap, je demande un recalcul de b dans les bornes d > a vers d-5, a + 5
a, in, out, in_to, out_to b, 11, 37, 16, 32
|-----------*--->--*---*---*----------*---<--*-----| 0 | | | | | | 2PI a | c b | d 11 | 19 22 | 37 0 |´ | | | | \ | | a´ c´ b´ d´ 16 20.9 22.8 32
? b´
distance_b distance_init distance_new percent_b out_b si b < d:
distance_b = b - a => 11 distance_init = d - a => 26 distance_new = d´ - a´ => 16 percent_b = distance_b / distance_init = > 0.423076923 out_b = a´ + percent_b * distance_new (6.769230769) => 22.769230769
return out_b
pour c´ si c < d:
distance_c = b - a => 8 distance_init = d - a => 26 distance_new = d´ - a´ => 16 percent_b = distance_c / distance_init = > 0.307692308 out_b = a´ + percent_b * distance_new (4.923076923) => 20.923076923
return out_b
le process semble ok pour les angles compris entre a et d
online identity ∋ [ social ∋ [mastodon♥, twitter®, facebook®, diaspora, linkedin®]
∥ repos ∋ [github®, gitlab♥, bitbucket®, sourceforge] ∥ media ∋ [itch.io®, vimeo®, peertube♥, twitch.tv®, tumblr®] ∥ communities ∋ [godotengine♥, openprocessing, stackoverflow, threejs]]