Frankiezafe (Talk | contribs) |
Frankiezafe (Talk | contribs) (→Resources) |
||
(21 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
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. | 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. | ||
− | = | + | == javascript (p5.js) == |
− | == base == | + | <html><iframe src="files/cyclic_mapping/index.html" width="800" height="200" scrolling="no" frameBorder="0"></iframe></html> |
+ | |||
+ | manipulation: | ||
+ | |||
+ | * right-click & drag to modify mapping angle | ||
+ | * left-click & drag to modify mapping range | ||
+ | |||
+ | code: | ||
+ | |||
+ | * javascript : https://www.openprocessing.org/sketch/445816 | ||
+ | * java : [https://bitbucket.org/frankiezafe/remappingradians RemappingRadians] (made with processing 3.3.5) | ||
+ | |||
+ | === functions (js) === | ||
+ | |||
+ | 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: | ||
+ | |||
+ | * calculation of the middle of the world range (''from_in'',''from_out''), divided by 2, ''half'' | ||
+ | * bounding of value to map in the world range | ||
+ | * bounding of lower limit of the new range (''to_in'' > ''bin'') in the world range | ||
+ | * bounding of lower limit of the new range (''to_out'' > ''bout'') in the world range | ||
+ | * calculation and bounding of middle of the new range (''bmid'') in the world range | ||
+ | |||
+ | 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: | ||
+ | |||
+ | * Calculation of the distance between the bounded value and the middle of the new range. This returns a value between -''half'' and ''half''. Because we will have to map this distance to the new range, we have to divide it by ''half''. This returns a percentage. Its value is in the range [-2, 2]. Indeed, the value to map might be at the opposite of the the middle of the new range. Because world space is cyclic, if the absolute value of the percentage is greater than 1, 1.5 for instance, the value can be bounded in the range [-1, 1]. The 1.5 becomes -0.5, and it's still the same value. | ||
+ | * Calculation of the new range. The distance between one of the limits ( ''to_in'' or ''to_out'' ) and their center (''bmid'') has to be removed form the half of the world range. Once done, the new range might exceed the half of the world range, when ''to_out'' is smaller than the lower limit (''to_in'') of the world, for instance. Therefore, we have to bound the new range between -''half'' and ''half''. From now on, the percentage and the new range can be multiply by one another . | ||
+ | * Last step is to check the sign of the percentage. If it is positive, the limit to use is the highest one, '''bout'''. We add the percentage of the new range and returns the value. If it is negative, the process is similar but uses the lower limit '''bin'''. | ||
+ | |||
+ | 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 ); | ||
+ | |||
+ | } | ||
+ | |||
+ | === identification of the nearest limit === | ||
+ | |||
+ | 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; | ||
+ | |||
+ | == research == | ||
+ | |||
+ | === base === | ||
Line 47: | Line 147: | ||
center = (d+a)/2 | center = (d+a)/2 | ||
− | == remap method() == | + | === remap method() === |
dans le remap, je demande un recalcul de b dans les bornes d > a vers d-5, a + 5 | dans le remap, je demande un recalcul de b dans les bornes d > a vers d-5, a + 5 | ||
Line 87: | Line 187: | ||
le process semble ok pour les angles compris entre a et d | le process semble ok pour les angles compris entre a et d | ||
− | + | ||
+ | == Resources == | ||
+ | |||
+ | <html><iframe width="560" height="315" src="https://www.youtube.com/embed/65wYmy8Pf-Y" frameborder="0" allowfullscreen></iframe></html> | ||
+ | |||
+ | * [[wikipedia:Color_wheel_graphs_of_complex_functions|Color wheel graphs of complex functions]] | ||
+ | |||
+ | [[Category:analysis]] | ||
+ | [[Category:logic]] | ||
+ | [[Category:mapping]] | ||
+ | [[Category:programmation]] | ||
+ | [[Category:notes]] | ||
+ | [[Category:math]] | ||
+ | [[Category:processing.org]] | ||
+ | [[Category:javascript]] |
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]]