Pregunta

I desarrollar un programa de dibujo basado en Python, Whyteboard ( https://launchpad.net/whyteboard )

Estoy desarrollando funciones para permitir al usuario rotar y escalar un polígono que dibujan. Aquí está mi problema:

Tengo una clase Polygon que contiene una lista de todos los puntos, que está "cerrado off" al final. Los usuarios pueden seleccionar las formas dibujadas en mi programa, que "destacados" ellos, dibujo controladores de selección en cada punto. Estos puntos pueden ser "agarraron" para cambiar su posición, y alterando la forma del polígono.

Tengo un problema: Tengo que encontrar la manera de calcular el cambio de tamaño de una "escala" para aplicar al polígono. Por ejemplo, (con el ratón pulsado), el usuario mueve su ratón fuera de la forma debe ser una acción de "crecer", y con lo que el ratón hacia la forma debe reducir su tamaño.

Tengo el código en el lugar para realizar la escala (que creo que es correcto), pero simplemente no puedo crear una "buena" factor de escala. El código siguiente es lo que he llegado con, basado en las respuestas

/ editar -. Aquí está el código resuelto

def rescale(self, x, y):
    """ 
    x and y are the current mouse positions. the center and "original" mouse 
    coords are calculated below
    """
    if not self.center:
        a = sum([x for x, y in self.points]) / len(self.points)
        b = sum([y for x, y in self.points]) / len(self.points)
        self.center = (a, b)
    if not self.orig_click:  # where the user first clicked on
        self.orig_click = (x, y)
    if not self.original_points:  # the points before applying any scaling
        self.original_points = list(self.points)


    orig_click = self.orig_click
    original_distance = math.sqrt((orig_click[0] - self.center[0]) ** 2 + (orig_click[1] - self.center[1]) ** 2)

    current_distance = (math.sqrt((x - self.center[0]) ** 2 + 
                       (y - self.center[1]) ** 2))
    self.scale_factor = current_distance / original_distance        

    for count, point in enumerate(self.original_points): 
        dist = (point[0] - self.center[0], point[1] - self.center[1]) 
        self.points[count] = (self.scale_factor * dist[0] + self.center[0], self.scale_factor * dist[1] + self.center[1]) 

En la actualidad este código parece escalar mi polígono a nada rápidamente, y ninguna cantidad de movimiento del ratón va a crecer de nuevo. A veces se hará lo contrario, y crecer rápidamente; pero no se vuelven atrás.

¿Fue útil?

Solución

En primer lugar, vamos a corregir su código de escala:

for count, point in enumerate(self.points): 
    dist = (point[0] - self.center[0], point[1] - self.center[1]) 
    self.points[count] = (self.scale_factor * dist[0] + self.center[0], self.scale_factor * dist[1] + self.center[1]) 

Espero que sus puntos se mantienen en coma flotante, ya que los errores de truncamiento de enteros van a acumularse muy rápidamente. Puede ser que sea mejor tener dos copias de los puntos, uno reducido y un sin escala.

Para determinar el factor de escala, tomar la relación de la distancia desde el clic original a la central, y la posición actual del ratón al centro.

original_distance = sqrt((click[0] - self.center[0])**2 + (click[1] - self.center[1])**2)
current_distance = sqrt((current_position[0] - self.center[0])**2 + (current_position[1] - self.center[1])**2)
self.scale_factor = current_distance / original_distance

Editar Su último problema hace hincapié en la importancia de tener dos conjuntos de puntos, el original y la escalada. Dado que el factor de escala es relativa al tamaño original de la forma, es necesario comenzar con los puntos originales de la forma cada vez que se cambia la escala. Puede consolidar esa vuelta a un juego cuando el usuario ha terminado de jugar con el ratón.

Y a tu comentario, no, no tiene que volver a calcular el centro. El centro no debe estar en movimiento.

Editar 2: Cuando se cambia la escala, que está escalando de un tamaño a otro tamaño. Si está reescalado constantemente, tiene dos opciones: guardar una copia de la forma con su tamaño original, o hacer su factor de escala en relación con el último tamaño de la forma, en lugar de su tamaño original. Yo prefiero el enfoque de dos copias, porque de lo contrario es muy fácil que se acumulen errores, incluso si usted está usando en coma flotante; también es más fácil de obtener el derecho de la lógica.

Otros consejos

El factor de escala más intuitiva sería la relación de (distancia desde la posición actual del ratón al centro de polígono) a (distancia desde la posición del ratón en el inicio de arrastre para el centro polígono) - de modo que al hacer clic en un punto en el polígono y arrastrándolo dos veces más lejos del centro, ya que era duplica el tamaño del polígono.

No estoy versado en Python, así que trataremos de responder en pseudocódigo.

En primer lugar, tendrá que calcular el centro del polígono. Esto se hace muy fácilmente (y tiene sentido cuando se piensa en ello.): Sólo tiene que añadir todos los puntos juntos y dividirlos por la cantidad de puntos

center = (point1 + point2 + point3) / 3

Se desea modificar la escala basado en el ratón, ¿correcto? Eso siempre va a ser incómoda, pero debería ser algo como esto:

scale = lengthof(mouse - center) / MAGIC_NUMBER

A continuación, se calculan los puntos con respecto al centro. Se está configurando de manera efectiva el origen de un gráfico en el punto central.

relative_point1 = point1 - center
relative_point2 = point2 - center
relative_point3 = point3 - center

A continuación, se cambia la escala de los puntos relativos por la escala:

relative_point1 *= scale
relative_point2 *= scale
relative_point3 *= scale

Y colocarlos de nuevo en la posición correcta:

point1 = center + relative_point1
point2 = center + relative_point2
point3 = center + relative_point3

Para evitar errores de redondeo, es probable que desee para mantener los puntos originales hasta que el usuario se lleva a cabo la ampliación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top