Pregunta

No es que esto no tenga sentido, pero simplemente funciona incómodo el 99% del tiempo.

A menudo, en los gráficos 2D, los rectángulos se inicializan, almacenan y manipulan como un par de puntos. En ningún idioma en particular,

class Rect:
   p1, p2: point

Tiene más sentido definir un rectángulo como dos valores x y dos valores Y, como este:

class Rect
   xleft, xright: int
   ytop, ybottom: int

Con dos puntos, si en algún lugar en el código fuente desea utilizar el valor y de la parte superior, tendría que decir rect.p1.y (hmmm, detente y piensa, ¿es p1 o p2) pero? Con los cuatro valores como miembros de datos simples, es claro y directo: rect.ytop (¡no se requiere pensar!) El uso de dos puntos significa que al tratar con la vertical, debe enredar la horizontal; Hay una relación extraña entre elementos independientes.

¿Cómo surgió esta idea de dos puntos y por qué persiste? ¿Tiene algún beneficio sobre las coordenadas de X e Y desnudas?

Nota adicional: Esta pregunta está en el contexto de rectángulos alineados XY, como en los administradores de Windows y los kits de herramientas GUI, no en el contexto de formas arbitrarias en la aplicación de dibujo y pintura.

¿Fue útil?

Solución

¿Ha considerado que es menos propenso a errores?

Si usa (Point1, Point2) es entonces muy Borre lo que está especificando. Si proporciona 2 puntos, entonces el único error posible es que el usuario ha mezclado sus X e Y al construir los puntos ya que el orden de los puntos no importa.

Si suministra 4 enteros, entonces si alguien no está prestando atención, puede suministrar (x1, x2, y1, y2) cuando desea (x1, y1, x2, y2) o viceversa. Además, algunas API como WCF Recto La estructura define un rectángulo como (x, y, ancho, altura) que luego podría causar confusión sobre lo que significa (1, 2, 3, 4). ¿Es eso (x, y, w, h) o (x1, y1, x2, y2) o (x1, x2, y1, y2)?

En general, (Point1, Point2) me parece un poco más seguro.

Otros consejos

Siempre me gustó definir un rectángulo como punto + ancho y altura, donde el punto es la esquina superior izquierda del rectángulo.

class Rect {
  float x, y;
  float width, height;
}

Y luego agregue los métodos que necesite para obtener las otras métricas. Como el Java versión

En realidad, un rectagle no está definido por 2 puntos. Un rectángulo solo se puede definir por dos puntos si es paralelo a los ejes.

Hay varias formas de representar rectángulos que son paralelos a los ejes:

  1. Dos puntos diagonalmente opuestos
  2. Un punto de esquina, altura y ancho
  3. Punto central, media altura y ancho (poco común, pero a veces útil).
  4. Como dos coordenadas x y dos coordenadas Y

Para (1), muchas bibliotecas usan una convención para determinar qué dos puntos se usan: topleft y fondo, por ejemplo.

La elección de la representación puede ser impulsada por el propósito original de la definición del rectángulo, pero me imagino que a menudo arbitrario. Las representaciones son equivalentes en la información que llevan. Sin embargo, difieren en la facilidad con la que se pueden calcular las propiedades del rectángulo y la conveniencia con la que las operaciones se pueden realizar en el reacectángulo.

Los beneficios de la definición (1) sobre otros incluyen:

  • Consistencia de API con otros polígonos, líneas, etc.
  • Topleft, Bottomight se puede pasar a cualquier método que acepte puntos
  • Se pueden llamar a los métodos de clase de punto en Topleft,
  • La mayoría de las propiedades se pueden derivar fácilmente, por ejemplo. Bottomleft, de primera categoría, ancho, altura, centro, longitud diagonal, etc.

Bien p1: Point y p2: Point cada uno va a tener dos int coordenadas En ellos de todos modos, ¿no su clase no equivale a lo mismo?

Y si almacena esos dos puntos como de primera clase Point Objetos, ¿no obtienes un poco más de utilidad de ellos? En la mayoría de los sistemas de coordenadas gráficas que conozco, los puntos se subclasifican de esta manera para crear una jerarquía de objetos: point -> circle -> ellipse y así.

Entonces, si haces un objeto que no usa el Point clase, te has divorciado de ese objeto del resto de la jerarquía de clases.

Por eso me gusta Delphi's TRect. Se define como un registro de variante (SUNM Struct en C-speak) que puede interpretarse como un topleft y un punto de derecha, o enteros superior, izquierdo, inferior y derecho, lo que sea más conveniente en este momento.

Seguramente si define su rectángulo como:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

Entonces sabes de inmediato qué punto es cuál.

Aún mejor sería agregar propiedades adicionales que le permitieran manipular el rectángulo en cuyo formas que necesitaba para su aplicación. Estos simplemente actualizarían la estructura de datos subyacente.

Al agregar una transformación a la forma, puede orientar su rectángulo de cualquier manera que desee. Todavía necesitaría un cuadro delimitador alineado con eje para verificaciones rápidas de aceptación/rechazo :)

Sin embargo, si su modelo permite rectángulos en cualquier orientación sin aplicar una transformación, entonces "abajo a la izquierda" y "arriba a la derecha" no tienen significado, lo que lleva a "P1" y "P2" (o algo equivalente).

Creo que tiene más sentido que un rectángulo esté representado por una extensión X e Y y un punto; Incluso podría hacer que el punto de ubicación sea el centro del rectángulo para que sea independiente de la rotación

¡Pero probablemente fue más fácil codificarlo como dos puntos!

No me gusta porque hemos arrojado un posible grado de libertad, que esencialmente permite una rotación arbitraria. Un rectángulo general 2D tiene cinco incógnitas (grados de libertad). Podríamos especificarlos como las coordenadas de un punto, las longitudes de los dos lados que forman un vértice con este punto, y el ángulo desde la horizontal de la primera línea (se supone que el otro tiene un ángulo 90 grados más grande). También se podría usar un número infinito de otras posibilidades, pero hay cinco cantidades independientes que deben especificarse. Algunas opciones conducirán a un álgebra más fácil que otras, dependiendo de lo que se haga con ellas.

¿No es exactamente lo mismo que 2 puntos? ¿Cómo es esta incómoda? La mayoría de las rutinas de dibujo requieren puntos, no componentes X/Y separados.

Definir rectángulos como pares de puntos le permite reutilizar el punto como vértice para otra forma. Solo un pensamiento...

Creo que es principalmente establecer uniformidad entre todas las primitivas de forma.

Seguro que puede definir el rectángulo de muchas maneras diferentes, pero ¿cómo define un triángulo, una estrella o un círculo de una manera que pueda usar estructuras de datos similares?

Todos los polígonos pueden definirse por sus puntos, con una breve cantidad de lógica para determinar qué hacer con los puntos.

Las bibliotecas gráficas operan principalmente en estos polígonos en términos de vértices y bordes, por lo que los puntos y las líneas entre ellos, todos los cálculos funcionan en estas dos características, bueno, eso y facetas, pero eso es solo una función de los bordes.

En dos dimensiones, almacenar un rectángulo como dos puntos es más claro que definir una esquina particular y un ancho y altura; considere el ancho o la altura negativa, o los cálculos requeridos para determinar cada opción desde la otra.

Realizar rotaciones en un rectángulo definido por puntos también es mucho más simple que uno definido con un punto más ancho y altura.

Esperaría que la encapsulación haga que esta diferenciación no sea importante como usuario de la clase.

Un rectángulo debe definirse como tres puntos para estar bien definidos en 3 dimensiones. No estoy completamente seguro del requisito de definir un rectángulo en 4 o más dimensiones.

Es completamente arbitrario. Necesita cuatro piezas de información para dibujar un rectángulo. El diseñador (s) de la biblioteca decidió representarlo con dos puntos (cada uno con una coordenada XY), pero podría haberlo hecho fácilmente con X/Y/W/H o superior/inferior/izquierda/derecha.

Supongo que la verdadera pregunta del OP es: por qué ¿Se realizó esta elección particular?

La elección de los parámetros solo es importante para los diseñadores / codificadores de bajo nivel.

Los usuarios de alto nivel solo necesitan pensar:

  • IspointInrect
  • Área
  • Intersección (o recorte)
  • HASOVERLAP (igual que la intersección. AREA> 0)
  • Unión (se convierte en una lista de rectángulos)
  • Resta (una lista de rectángulos que representan el mismo conjunto de puntos que está en rect a pero no en rect b)
  • Transformar
    • Cambios en x e y
    • Rotación (0, 90, 180, 270)
    • Escala en x e y (ver nota)
  • Sintaxis simple para propiedades xmin, xmax, ymin, ymax, ancho, altura para que el usuario no necesite saber la elección exacta de los parámetros.

Nota: Para minimizar la pérdida de precisión durante la transformación de escala, a veces es apropiado implementar una segunda clase RECT que utiliza coordenadas de punto flotante, de modo que los resultados intermedios se pueden almacenar con precisión en una secuencia de transformaciones y solo redondeados a enteros en el último paso.

Como dice @steven, creo que debería ser en términos de un punto (x, y) y un vector de tamaño (W, H). Eso es porque es fácil caer en una ambigüedad. Supongamos que tiene el siguiente rectángulo rellenado a partir del punto (0,0).

  012
0 XXX
1 XXX
2 XXX

Claramente, es ancho, la altura es (3,3), pero ¿cuál es el segundo punto? ¿Es (2,2) o (3,3)?

Esta ambigüedad puede causar todo tipo de problemas.

Aprendí de la manera difícil hace años que es mejor pensar en las coordenadas gráficas como líneas Entre los píxeles, no como las líneas son los píxeles en. De esa manera no hay ambigüedad.

Pa(x,y)*-----------------------------------*Pb(x,y)
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
Pc(x,y)*-----------------------------------*Pd(x,y)

Podemos definir tanto PB como PC:

PB (PD (X), PA (y))

y

PC (PA (X), PD (y))

Por lo tanto, no hay necesidad de definir los cuatro puntos debido a la simetría

Licenciado bajo: CC-BY-SA con atribución
scroll top