javascript - ordenamiento - metodo dela burbuja java script
¿Cuál es el algoritmo para calcular la relación de aspecto? Necesito una salida como: 4: 3, 16: 9 (15)
Aquí hay una versión del mejor algoritmo de aproximación racional de James Farey con nivel de borrosidad ajustable, portado a javascript desde el código de cálculo de relación de aspecto escrito originalmente en python.
El método toma un flotante ( width/height
) y un límite superior para el numerador / denominador de la fracción.
En el siguiente ejemplo, estoy estableciendo un límite superior de 50
porque necesito 1035x582
(1.77835051546) para ser tratado como 16:9
(1.77777777778) en lugar de 345:194
que obtiene con el algoritmo simple de gcd
enumerado en otras respuestas.
<html>
<body>
<script type="text/javascript">
function aspect_ratio(val, lim) {
var lower = [0, 1];
var upper = [1, 0];
while (true) {
var mediant = [lower[0] + upper[0], lower[1] + upper[1]];
if (val * mediant[1] > mediant[0]) {
if (lim < mediant[1]) {
return upper;
}
lower = mediant;
} else if (val * mediant[1] == mediant[0]) {
if (lim >= mediant[1]) {
return mediant;
}
if (lower[1] < upper[1]) {
return lower;
}
return upper;
} else {
if (lim < mediant[1]) {
return lower;
}
upper = mediant;
}
}
}
document.write (aspect_ratio(800 / 600, 50) +"<br/>");
document.write (aspect_ratio(1035 / 582, 50) + "<br/>");
document.write (aspect_ratio(2560 / 1440, 50) + "<br/>");
</script>
</body></html>
El resultado:
4,3 // (1.33333333333) (800 x 600)
16,9 // (1.77777777778) (2560.0 x 1440)
16,9 // (1.77835051546) (1035.0 x 582)
Planeo usarlo con javascript para recortar una imagen para que se ajuste a toda la ventana.
Editar: Usaré un componente de la 3ª parte que solo acepta la relación de aspecto en el formato como: 4: 3, 16: 9
Como una solución alternativa a la búsqueda de GCD, le sugiero que consulte un conjunto de valores estándar. Puedes encontrar una lista en Wikipedia .
Creo que esto hace lo que estás pidiendo:
webdeveloper.com - decimal a fracción
El ancho / alto le da un decimal, convertido a una fracción con ":" en lugar de "/" le da una "proporción".
Creo que la relación de aspecto es ancho dividido por altura.
r = w/h
En caso de que seas un fanático del rendimiento ...
La forma más rápida (en JavaScript) para calcular una relación rectangular es usar un algoritmo binario Great Common Divisor.
(Todas las pruebas de velocidad y tiempo han sido realizadas por otros, puede consultar un punto de referencia aquí: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor/ )
Aquí es:
/* the binary Great Common Divisor calculator */
function gcd (u, v) {
if (u === v) return u;
if (u === 0) return v;
if (v === 0) return u;
if (~u & 1)
if (v & 1)
return gcd(u >> 1, v);
else
return gcd(u >> 1, v >> 1) << 1;
if (~v & 1) return gcd(u, v >> 1);
if (u > v) return gcd((u - v) >> 1, v);
return gcd((v - u) >> 1, u);
}
/* returns an array with the ratio */
function ratio (w, h) {
var d = gcd(w,h);
return [w/d, h/d];
}
/* example */
var r1 = ratio(1600, 900);
var r2 = ratio(1440, 900);
var r3 = ratio(1366, 768);
var r4 = ratio(1280, 1024);
var r5 = ratio(1280, 720);
var r6 = ratio(1024, 768);
/* will output this:
r1: [16, 9]
r2: [8, 5]
r3: [683, 384]
r4: [5, 4]
r5: [16, 9]
r6: [4, 3]
*/
Esta es mi solución, es bastante sencillo ya que lo único que me importa no es necesariamente GCD o incluso razones precisas: porque entonces obtienes cosas raras como 345/113 que no son comprensibles para el ser humano.
Básicamente establezco un paisaje aceptable, o proporciones de retratos y su "valor" como un flotador ... Luego comparo mi versión flotante de la relación con cada uno y la diferencia mínima de valores absolutos es la relación más cercana al ítem. De esta forma, cuando el usuario lo convierte en 16: 9 pero luego elimina 10 píxeles de la parte inferior, todavía cuenta como 16: 9 ...
accepted_ratios = {
''landscape'': (
(u''5:4'', 1.25),
(u''4:3'', 1.33333333333),
(u''3:2'', 1.5),
(u''16:10'', 1.6),
(u''5:3'', 1.66666666667),
(u''16:9'', 1.77777777778),
(u''17:9'', 1.88888888889),
(u''21:9'', 2.33333333333),
(u''1:1'', 1.0)
),
''portrait'': (
(u''4:5'', 0.8),
(u''3:4'', 0.75),
(u''2:3'', 0.66666666667),
(u''10:16'', 0.625),
(u''3:5'', 0.6),
(u''9:16'', 0.5625),
(u''9:17'', 0.5294117647),
(u''9:21'', 0.4285714286),
(u''1:1'', 1.0)
),
}
def find_closest_ratio(ratio):
lowest_diff, best_std = 9999999999, ''1:1''
layout = ''portrait'' if ratio < 1.0 else ''landscape''
for pretty_str, std_ratio in accepted_ratios[layout]:
diff = abs(std_ratio - ratio)
if diff < lowest_diff:
lowest_diff = diff
best_std = pretty_str
return best_std
def extract_ratio(width, height):
try:
divided = float(width)/float(height)
if divided == 1.0:
return ''1:1''
else:
return find_closest_ratio(divided)
except TypeError:
return None
La respuesta de paxdiablo es genial, pero hay muchas resoluciones comunes que tienen solo unos pocos píxeles más o menos en una dirección determinada, y el mayor enfoque de divisor común les da resultados horribles.
Tomemos, por ejemplo, la resolución de 1360x765, que se comporta bien, que da una buena proporción de 16: 9 usando el enfoque de gcd. Según Steam, esta resolución solo la usa el 0.01% de sus usuarios, mientras que 1366x768 es utilizada por un 18.9%. Veamos qué obtenemos usando el enfoque de gcd:
1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)
Quisiéramos redondear esa proporción de 683: 384 a la proporción más cercana, 16: 9.
Escribí un script de Python que analiza un archivo de texto con números pegados de la página de encuestas de Steam Hardware e imprime todas las resoluciones y ratios conocidos más cercanos, así como la prevalencia de cada relación (que era mi objetivo cuando comencé esto):
# Contents pasted from store.steampowered.com/hwsurvey, section ''Primary Display Resolution''
steam_file = ''./steam.txt''
# Taken from http://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Vector_Video_Standards4.svg/750px-Vector_Video_Standards4.svg.png
accepted_ratios = [''5:4'', ''4:3'', ''3:2'', ''8:5'', ''5:3'', ''16:9'', ''17:9'']
#-------------------------------------------------------
def gcd(a, b):
if b == 0: return a
return gcd (b, a % b)
#-------------------------------------------------------
class ResData:
#-------------------------------------------------------
# Expected format: 1024 x 768 4.37% -0.21% (w x h prevalence% change%)
def __init__(self, steam_line):
tokens = steam_line.split('' '')
self.width = int(tokens[0])
self.height = int(tokens[2])
self.prevalence = float(tokens[3].replace(''%'', ''''))
# This part based on pixdiablo''s gcd answer - http://.com/a/1186465/828681
common = gcd(self.width, self.height)
self.ratio = str(self.width / common) + '':'' + str(self.height / common)
self.ratio_error = 0
# Special case: ratio is not well behaved
if not self.ratio in accepted_ratios:
lesser_error = 999
lesser_index = -1
my_ratio_normalized = float(self.width) / float(self.height)
# Check how far from each known aspect this resolution is, and take one with the smaller error
for i in range(len(accepted_ratios)):
ratio = accepted_ratios[i].split('':'')
w = float(ratio[0])
h = float(ratio[1])
known_ratio_normalized = w / h
distance = abs(my_ratio_normalized - known_ratio_normalized)
if (distance < lesser_error):
lesser_index = i
lesser_error = distance
self.ratio_error = distance
self.ratio = accepted_ratios[lesser_index]
#-------------------------------------------------------
def __str__(self):
descr = str(self.width) + ''x'' + str(self.height) + '' - '' + self.ratio + '' - '' + str(self.prevalence) + ''%''
if self.ratio_error > 0:
descr += '' error: %.2f'' % (self.ratio_error * 100) + ''%''
return descr
#-------------------------------------------------------
# Returns a list of ResData
def parse_steam_file(steam_file):
result = []
for line in file(steam_file):
result.append(ResData(line))
return result
#-------------------------------------------------------
ratios_prevalence = {}
data = parse_steam_file(steam_file)
print(''Known Steam resolutions:'')
for res in data:
print(res)
acc_prevalence = ratios_prevalence[res.ratio] if (res.ratio in ratios_prevalence) else 0
ratios_prevalence[res.ratio] = acc_prevalence + res.prevalence
# Hack to fix 8:5, more known as 16:10
ratios_prevalence[''16:10''] = ratios_prevalence[''8:5'']
del ratios_prevalence[''8:5'']
print(''/nSteam screen ratio prevalences:'')
sorted_ratios = sorted(ratios_prevalence.items(), key=lambda x: x[1], reverse=True)
for value in sorted_ratios:
print(value[0] + '' -> '' + str(value[1]) + ''%'')
Para los curiosos, esta es la prevalencia de las relaciones de pantalla entre los usuarios de Steam (a partir de octubre de 2012):
16:9 -> 58.9%
16:10 -> 24.0%
5:4 -> 9.57%
4:3 -> 6.38%
5:3 -> 0.84%
17:9 -> 0.11%
Según las otras respuestas, así es como obtuve los números que necesitaba en Python;
from decimal import Decimal
def gcd(a,b):
if b == 0:
return a
return gcd(b, a%b)
def closest_aspect_ratio(width, height):
g = gcd(width, height)
x = Decimal(str(float(width)/float(g)))
y = Decimal(str(float(height)/float(g)))
dec = Decimal(str(x/y))
return dict(x=x, y=y, dec=dec)
>>> closest_aspect_ratio(1024, 768)
{''y'': Decimal(''3.0''),
''x'': Decimal(''4.0''),
''dec'': Decimal(''1.333333333333333333333333333'')}
Supongo que estás hablando de video aquí, en cuyo caso también es posible que debas preocuparte por la proporción de píxeles del video original. Por ejemplo.
PAL DV viene en una resolución de 720x576. Que se vería como 4: 3. Ahora, dependiendo de la relación de aspecto de píxeles (PAR), la relación de pantalla puede ser 4: 3 o 16: 9.
Para obtener más información, echa un vistazo aquí http://en.wikipedia.org/wiki/Pixel_aspect_ratio
Puede obtener una relación de aspecto de píxeles cuadrados, y una gran cantidad de video web es eso, pero es posible que desee tener cuidado con los otros casos.
Espero que esto ayude
marca
Supongo que quieres decidir cuál de 4: 3 y 16: 9 es el que mejor se ajusta.
function getAspectRatio(width, height) {
var ratio = width / height;
return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? ''4:3'' : ''16:9'';
}
una forma extraña de hacer esto pero usa la resolución como el aspecto. P.EJ
1024: 768
o puedes probar
var w = screen.width;
var h = screen.height;
for(var i=1,asp=w/h;i<5000;i++){
if(asp*i % 1==0){
i=9999;
document.write(asp*i,":",1*i);
}
}
Este algoritmo en Python te lleva a una parte del camino allí.
Dime qué sucede si las ventanas tienen un tamaño divertido.
Tal vez lo que debería tener es una lista de todas las relaciones aceptables (para el componente de terceros). Luego, busca la coincidencia más cercana a tu ventana y regresa esa relación de la lista.
Supongo que está buscando un integer:integer
relación de aspecto utilizable integer:integer
solución integer:integer
como 16:9
lugar de una solución float:1
como 1.77778:1
.
Si es así, lo que necesita hacer es encontrar el divisor común más grande (GCD) y dividir ambos valores por eso. El GCD es el número más alto que divide equitativamente ambos números. Entonces el GCD para 6 y 10 es 2, el GCD para 44 y 99 es 11.
Por ejemplo, un monitor de 1024x768 tiene un GCD de 256. Cuando divides ambos valores, obtienes 4x3 o 4: 3.
Un algoritmo GCD (recursivo):
function gcd (a,b):
if b == 0:
return a
return gcd (b, a mod b)
Cª:
static int gcd (int a, int b) {
return (b == 0) ? a : gcd (b, a%b);
}
int main(void) {
printf ("gcd(1024,768) = %d/n",gcd(1024,768));
}
Y aquí hay un HTML / Javascript completo que muestra una forma de detectar el tamaño de la pantalla y calcular la relación de aspecto a partir de eso. Esto funciona en FF3, no estoy seguro de qué soporte tienen otros navegadores para screen.width
y screen.height
.
<html><body>
<script type="text/javascript">
function gcd (a, b) {
return (b == 0) ? a : gcd (b, a%b);
}
var w = screen.width;
var h = screen.height;
var r = gcd (w, h);
document.write ("<pre>");
document.write ("Dimensions = ", w, " x ", h, "<br>");
document.write ("Gcd = ", r, "<br>");
document.write ("Aspect = ", w/r, ":", h/r);
document.write ("</pre>");
</script>
</body></html>
Emite (en mi raro monitor de pantalla ancha):
Dimensions = 1680 x 1050
Gcd = 210
Aspect = 8:5
Otros en los que probé esto:
Dimensions = 1280 x 1024
Gcd = 256
Aspect = 5:4
Dimensions = 1152 x 960
Gcd = 192
Aspect = 6:5
Dimensions = 1280 x 960
Gcd = 320
Aspect = 4:3
Dimensions = 1920 x 1080
Gcd = 120
Aspect = 16:9
Desearía haber tenido el último en casa pero, desafortunadamente, es una máquina de trabajo.
Lo que haces si descubres que la relación de aspecto no es compatible con tu herramienta de cambio de tamaño de gráficos es otra cuestión. Sospecho que la mejor opción sería agregar líneas de letter boxing (como las que obtienes en la parte superior e inferior de tu viejo televisor cuando estás viendo una película de pantalla ancha). Los agregaría en la parte superior / inferior o en los laterales (lo que resulte en el menor número de líneas de letter-boxing) hasta que la imagen cumpla con los requisitos.
Una cosa que quizás desee considerar es la calidad de una imagen que ha cambiado de 16: 9 a 5: 4. Todavía recuerdo los vaqueros increíblemente altos y delgados que solía ver en mi juventud en la televisión antes de que se introdujera el boxeo. Puede que sea mejor tener una imagen diferente por relación de aspecto y simplemente cambiar el tamaño de la correcta para las dimensiones reales de la pantalla antes de enviarla por el cable.
Width / Height
?
aspectRatio = width / height
si eso es lo que buscas. Luego puede multiplicarlo por una de las dimensiones del espacio objetivo para descubrir el otro (que mantiene la proporción), por ej.
widthT = heightT * aspectRatio
heightT = widthT / aspectRatio