¿Cómo puedo escalar un rectángulo al tamaño máximo posible dentro de otro rectángulo?


Tengo un rectángulo de origen y un rectángulo de destino. Necesito encontrar la escala máxima a la que se puede escalar la fuente mientras se ajusta dentro del rectángulo de destino y manteniendo su relación de aspecto original.

Google encontró una manera de hacerlo, pero no estoy seguro de si funciona en todos los casos. Aquí está mi solución casera:

  • Calcular Altura/Anchura para cada rectángulo. Esto da las pendientes de las diagonales msrc y mdest.
  • Si msrc < mdst, escalar la fuente width para ajustarse al destino width (y escalar la altura en la misma proporción)
  • De lo contrario, escala la fuente altura para ajustarse al destino altura (y escala el ancho en la misma proporción)

Buscando otras posibles soluciones a este problema. Ni siquiera estoy seguro de si mi algoritmo funciona en todos los casos!

Author: Agnel Kurian , 2009-09-03

5 answers

scale = min( dst.width/src.width, dst.height/src.height)

Este es su enfoque, pero escrito de manera más limpia.

 99
Author: tom10,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-03 14:50:34

Otra opción podría ser escalar al ancho máximo y luego verificar si la altura escalada es mayor que la altura máxima permitida y, si es así, escalar por altura (o viceversa):

scale = (dst.width / src.width);
if (src.height * scale > dst.height)
 scale = dst.height / src.height;

Creo que esta solución es más corta, más rápida y más fácil de entender.

 10
Author: Guss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-03 17:24:03
  1. Calcular el menor de destWidth / srcWidth y destHeight / srcHeight
  2. Escala por eso

edit es, por supuesto, el mismo que tu método, con las piezas de la fórmula movidas. Mi opinión es que esto es semánticamente más claro, pero es solo eso - una opinión.

 1
Author: AakashM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-03 12:14:46

Si todas las dimensiones son distintas de cero, usaría el siguiente código (que esencialmente coincide con su código).

scaleFactor = (outerWidth / outerHeight > innerWidth / innerHeight) 
    ? outerHeight / innerHeight
    : outerWidth / innerWidth

Esto también se puede modificar para permitir que cualquier dimensión sea cero si es necesario.

 1
Author: Daniel Brückner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-03 12:41:59

Las otras respuestas sufren el riesgo de generar una excepción de división por cero cuando el sourceWidth o sourceHeight se convierte en cero. Para evitar esto, debemos reescribir la comparación en una expresión múltiple matemáticamente equivalente. Además, condición de borde adicional para capturar el escenario de escala infinita.

Aparte de tener la escala, realmente quería las dimensiones del rectángulo objetivo, así que aquí proporcionaré el cálculo de la escala y el rectángulo objetivo calculo.

Debido a la condición de borde infinito, creo que el rectángulo de destino será más robusto / útil:

    if (sourceWidth == 0 && sourceHeight == 0) {
        // scale = Infinity;
        outputWidth = 0;
        outputHeight = 0;
        outputX = destWidth / 2;
        outputY = destHeight / 2;
    } else if (destWidth * sourceHeight > destHeight * sourceWidth) {
        scale = destHeight / sourceHeight;
        outputWidth = sourceWidth * destHeight / sourceHeight;
        outputHeight = destHeight;
        outputX = (destWidth - outputWidth) / 2;
        outputY = 0;
    } else {
        scale = destWidth / sourceWidth;
        outputWidth = destWidth;
        outputHeight = sourceHeight * destWidth / sourceWidth;
        outputX = 0;
        outputY = (destHeight - outputHeight) / 2;
    }
 0
Author: Stephen Quan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-15 04:16:14