Question

Je développe un programme de dessin basé sur Python, Whyteboard ( https://launchpad.net/whyteboard )

Je développe des fonctionnalités pour permettre à l'utilisateur de faire pivoter et de l'échelle d'un polygone qu'ils dessinent. Voici mon problème:

J'ai une classe Polygon contenant une liste de tous les points, ce qui est « terminée » à la fin. Les utilisateurs peuvent choisir les formes dessinées dans mon programme, qui « highlights » eux, la sélection de dessin des poignées à chaque point. Ces points peuvent être « saisis » pour changer sa position, et de modifier la forme du polygone.

J'ai un problème: je dois comprendre comment calculer un redimensionnement « échelle » pour appliquer au polygone. Par exemple, (avec la souris enfoncé), l'utilisateur se déplaçant leur souris de la forme doit être une action « grandir » et amener la souris vers la forme devrait rétrécir.

J'ai le code en place pour effectuer l'échelle (qui je crois est correct) mais je ne peux pas créer un facteur d'échelle « bonne ». Le code ci-dessous est ce que je suis venu avec, sur la base des réponses

/ edit -. Est le code résolu ici

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]) 

À l'heure actuelle ce code semble à l'échelle de mon polygone à rien rapidement, et aucune quantité de mouvement de la souris va croître en arrière. Parfois, il fera le contraire, et se développer rapidement; mais pas reculer.

Était-ce utile?

La solution

D'abord, corriger votre code de mise à l'échelle:

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]) 

J'espère que vos points sont conservés en virgule flottante, car les erreurs de troncature entier vont accumuler très rapidement. Il pourrait être préférable d'avoir deux copies des points, une échelle et un non calibré.

Pour déterminer le facteur d'échelle, prendre le rapport de la distance du clic d'origine au centre, et la position actuelle de la souris au centre.

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

Modifier Votre dernier problème souligne l'importance d'avoir deux ensembles de points, l'original et la mise à l'échelle. Étant donné que le facteur d'échelle est par rapport à la taille originale de la forme, vous devez commencer avec les points d'origine de la forme à chaque fois que vous changez l'échelle. Vous pouvez consolider que vers le bas à un ensemble lorsque l'utilisateur se fait de jouer avec la souris.

Et à votre commentaire, pas vous n'avez pas recalcule le centre. Le centre ne doit pas être en mouvement.

Edit 2: Lorsque vous redimensionnez, vous augmentez l'échelle de taille une autre taille. Si vous êtes constamment remise à l'échelle, vous avez deux choix: garder une copie de la forme à sa taille d'origine, ou que votre facteur d'échelle par rapport à la dernière taille de la forme, plutôt que la taille d'origine. Je préfère l'approche de deux copies, car sinon il est trop facile pour les erreurs d'accumuler, même si vous utilisez à virgule flottante; il est également plus facile d'obtenir le droit logique.

Autres conseils

Le facteur d'échelle la plus intuitive serait le rapport de (distance entre la position courante de la souris au centre du polygone) à (distance entre la position de la souris au début de glisser vers le centre du polygone) - de telle sorte que la pression d'un point du polygone et le faisant glisser deux fois plus loin du centre comme il était double la taille du polygone.

Je ne suis pas versé en Python, donc je vais essayer de répondre à pseudocode.

Tout d'abord, vous voulez calculer le centre du polygone. Cela se fait très facilement (et est logique quand on y pense). Il suffit d'ajouter tous les points ensemble et les diviser par le nombre de points

center = (point1 + point2 + point3) / 3

Vous voulez mettre à l'échelle en fonction de la souris, non? Cela a toujours va être fiddly, mais il devrait être quelque chose comme ceci:

scale = lengthof(mouse - center) / MAGIC_NUMBER

Ensuite, vous calculez les points par rapport au centre. Vous l'origine mise en place effective d'un graphique au point central.

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

Ensuite, vous l'échelle des points relatifs à l'échelle:

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

Et les remettre à la position correcte:

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

Pour éviter les erreurs d'arrondi, vous voudrez probablement conserver les points d'origine jusqu'à ce que l'utilisateur se fait à l'échelle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top