Ce problème concerne en fait les roll-overs, je vais juste généraliser ci-dessous en tant que tel:
J'ai une vue 2D et j'ai un certain nombre de rectangles dans une zone de l'écran. Comment étaler ces boîtes de manière à ce qu'elles ne se chevauchent pas, mais uniquement les ajuster avec un mouvement minimal?
Les positions des rectangles sont dynamiques et dépendent de l'entrée de l'utilisateur, de sorte que leurs positions peuvent être n'importe où.
Les images jointes montrent le problème et la solution souhaitée
Le problème réel concerne les renversements, en fait.
Réponses aux questions dans les commentaires
La taille des rectangles n'est pas fixe et dépend de la longueur du texte dans le survol
À propos de la taille de l'écran, pour le moment, je pense qu'il vaut mieux supposer que la taille de l'écran est suffisante pour les rectangles. S'il y a trop de rectangles et que l'algo ne produit aucune solution, alors je dois juste modifier le contenu.
L'exigence de «bouger au minimum» relève davantage de l'éthique que d'une exigence technique absolue. On pourrait espacer deux rectangles en ajoutant une grande distance entre eux, mais cela ne semblera pas bon dans le cadre de l'interface graphique. L'idée est de rapprocher le rollover / rectangle de sa source (que je connecterai ensuite à la source avec une ligne noire). Donc, «déplacer un seul pour x» ou «déplacer les deux pour la moitié de x» est très bien.
Réponses:
Je travaillais un peu là-dessus, car j'avais également besoin de quelque chose de similaire, mais j'avais retardé le développement de l'algorithme. Vous m'avez aidé à avoir une impulsion: D
J'avais également besoin du code source, alors le voici. Je l'ai travaillé dans Mathematica, mais comme je n'ai pas beaucoup utilisé les fonctionnalités fonctionnelles, je suppose que ce sera facile à traduire dans n'importe quel langage procédural.
Une perspective historique
J'ai d'abord décidé de développer l'algorithme pour les cercles, car l'intersection est plus facile à calculer. Cela dépend juste des centres et des rayons.
J'ai pu utiliser le solveur d'équations Mathematica, et il a bien fonctionné.
Il suffit de regarder:
C'était facile. Je viens de charger le solveur avec le problème suivant:
Aussi simple que cela, et Mathematica a fait tout le travail.
J'ai dit "Ha! C'est facile, maintenant c'est parti pour les rectangles!". Mais je me trompais ...
Blues rectangulaires
Le principal problème avec les rectangles est que l'interrogation de l'intersection est une fonction désagréable. Quelque chose comme:
Donc, quand j'ai essayé de nourrir Mathematica avec beaucoup de ces conditions pour l'équation, cela a si mal fonctionné que j'ai décidé de faire quelque chose de procédural.
Mon algorithme s'est terminé comme suit:
Vous remarquerez peut-être que la condition du «plus petit mouvement» n'est pas entièrement satisfaite (seulement dans une direction). Mais j'ai trouvé que déplacer les rectangles dans n'importe quelle direction pour le satisfaire aboutissait parfois à une carte déroutante changeante pour l'utilisateur.
En concevant une interface utilisateur, je choisis de déplacer le rectangle un peu plus loin, mais de manière plus prévisible. Vous pouvez modifier l'algorithme pour inspecter tous les angles et tous les rayons entourant sa position actuelle jusqu'à ce qu'une place vide soit trouvée, bien que ce soit beaucoup plus exigeant.
Quoi qu'il en soit, ce sont des exemples de résultats (avant / après):
Modifier> Plus d'exemples ici
Comme vous pouvez le voir, le "mouvement minimum" n'est pas satisfait, mais les résultats sont assez bons.
Je posterai le code ici car j'ai des problèmes avec mon référentiel SVN. Je le supprimerai lorsque les problèmes seront résolus.
Éditer:
Vous pouvez également utiliser des R-Trees pour trouver des intersections de rectangles, mais cela semble exagéré pour traiter un petit nombre de rectangles. Et je n'ai pas les algorithmes déjà implémentés. Peut-être que quelqu'un d'autre peut vous indiquer une implémentation existante sur la plate-forme de votre choix.
Avertissement! Le code est une première approche .. pas encore de grande qualité, et a sûrement quelques bugs.
C'est Mathematica.
Principale
HTH!
Edit: recherche multi-angle
J'ai mis en place un changement d'algorithme permettant de chercher dans toutes les directions, mais en privilégiant l'axe imposé par la symétrie géométrique.
Au détriment de plus de cycles, cela a abouti à des configurations finales plus compactes, comme vous pouvez le voir ci-dessous:
Plus d'échantillons ici .
Le pseudocode de la boucle principale a été changé en:
Je n'inclus pas le code source par souci de concision, mais demandez-le simplement si vous pensez pouvoir l'utiliser. Je pense que, si vous allez dans cette direction, il vaut mieux passer aux R-tree (beaucoup de tests d'intervalle sont nécessaires ici)
la source
Voici une supposition.
Trouvez le centre C de la boîte englobante de vos rectangles.
Pour chaque rectangle R qui en chevauche un autre.
Cela éloigne progressivement les rectangles les uns des autres et du centre de tous les rectangles. Cela se terminera car le composant de v de l'étape 4 finira par les répartir suffisamment tout seul.
la source
Je pense que cette solution est assez similaire à celle donnée par cape1232, mais elle est déjà implémentée, cela vaut donc la peine de vérifier :)
Suivez cette discussion sur reddit: http://www.reddit.com/r/gamedev/comments/1dlwc4/procedural_dungeon_generation_algorithm_explained/ et consultez la description et l'implémentation. Il n'y a pas de code source disponible, alors voici mon approche de ce problème dans AS3 (fonctionne exactement de la même manière, mais garde les rectangles alignés sur la résolution de la grille):
la source
velocity
c'est la somme des vecteurs entre son centre et le centre des autres pièces, si toutes les pièces sont empilées avec le même centre,velocity.length == 0
pour toutes les pièces et rien ne bougera jamais. De la même manière, si deux salles ou plus ont le même rectangle avec le même centre, elles se déplaceront ensemble mais resteront empilées.J'aime vraiment l'implémentation de b005t3r! Cela fonctionne dans mes cas de test, mais mon représentant est trop faible pour laisser un commentaire avec les 2 correctifs suggérés.
Vous ne devriez pas traduire les pièces par incréments de résolution unique, vous devez traduire par la vitesse que vous venez de calculer de manière stricte! Cela rend la séparation plus organique, car les pièces profondément entrecroisées séparent plus chaque itération que les pièces qui se croisent pas si profondément.
Vous ne devez pas supposer que les vélociites inférieures à 0,5 signifient que les pièces sont séparées car vous pouvez vous retrouver coincé dans un cas où vous n'êtes jamais séparé. Imaginez que 2 pièces se croisent, mais sont incapables de se corriger parce que chaque fois que l'une ou l'autre tente de corriger la pénétration, elles calculent la vitesse requise comme <0,5, de sorte qu'elles itèrent sans fin.
Voici une solution Java (: Cheers!
la source
Voici un algorithme écrit en Java pour gérer un cluster de
Rectangle
s non rotatifs . Il vous permet de spécifier le rapport hauteur / largeur souhaité de la mise en page et de positionner le cluster en utilisant un paramètre définiRectangle
comme point d'ancrage, sur lequel toutes les traductions effectuées sont orientées. Vous pouvez également spécifier une quantité arbitraire de remplissage par laquelle vous souhaitez répartir lesRectangle
s.}
Voici un exemple utilisant un
AspectRatio
of1.2
, unFillPercentage
of0.8
et unPadding
of10.0
.Il s'agit d'une approche déterministe qui permet un espacement autour de l'ancre tout en laissant l'emplacement de l'ancre elle-même inchangée. Cela permet à la mise en page de se produire partout où se trouve le point d'intérêt de l'utilisateur. La logique de sélection d'une position est assez simpliste, mais je pense que l'architecture environnante consistant à trier les éléments en fonction de leur position initiale puis à les itérer est une approche utile pour implémenter une distribution relativement prévisible. De plus, nous ne nous appuyons pas sur des tests d'intersection itératifs ou quoi que ce soit du genre, nous construisons simplement des cadres de délimitation pour nous donner une indication générale de l'endroit où aligner les choses; après cela, appliquer un rembourrage vient tout naturellement.
la source
Voici une version qui reprend la réponse de cape1232 et est un exemple exécutable autonome pour Java:
la source