Algorithme pour créer des triangles adjacents


14

J'ai un système où vous pouvez cliquer une fois pour placer un nœud dans une scène. Lorsque vous placez 3 nœuds, il forme un triangle. Lorsque vous placez des nœuds futurs, il crée un nouveau triangle en joignant ce nœud aux 2 nœuds existants les plus proches.

Cela fonctionne très bien la plupart du temps mais est défectueux lorsqu'il est utilisé près de triangles avec des angles très aigus, car l'un des 2 nœuds les plus proches n'est souvent pas celui qui devrait être utilisé.

Par exemple, voir l'image ci-dessous. Le triangle magenta est le premier placé. Si je clique ensuite à la position marquée X, ce que j'obtiens est un nouveau triangle où se trouve la superposition bleue. Ce que je veux, c'est un nouveau triangle où se trouve la superposition verte. (c'est-à-dire symétriques au magenta, dans cet exemple. Clarification: les triangles vert et magenta ne se chevauchent pas - le vert s'étend sous le bleu jusqu'au nœud le plus à gauche)

Exemple de comportement réel et souhaité

Comment puis-je déterminer les 2 sommets existants à utiliser lors de la création de nouveaux triangles afin que les triangles ne soient pas superposés comme ceci?

EDIT : La recherche du bord le plus proche donne de meilleurs résultats, mais pas parfaits. Considérez cette situation:

entrez la description de l'image ici

Le test du «bord le plus proche» est ambigu et peut renvoyer AB ou AC (car le point le plus proche de X pour les deux est en A). Le résultat souhaité serait AC, pour former le triangle ACX sans chevauchement d'arêtes. Comment pourrais-je garantir ce résultat? (Je préfère ne pas avoir à effectuer des tests de chevauchement de bords individuels comme briseur d'égalité si possible car je crains que le test de bord le plus proche ne repère pas nécessairement les 2 sont exactement équidistants, étant donné les problèmes de précision en virgule flottante.)


N'est-il pas suffisant de regarder les 5 derniers sommets placés et de sélectionner les deux plus proches du sommet nouvellement placé? Je voudrais vous indiquer les algorithmes pour les bandes triangulaires ( codercorner.com/Strips.htm ), mais ceux-ci utilisent souvent les deux derniers ou les trois derniers en sautant un.
Roy T.

1
Le triangle vert chevauche-t-il le magenta? Quel est le but de tout ça? L'utilisateur a-t-il besoin de contrôler où et comment les triangles sont créés ou la triangulation d'un nuage de points serait-elle acceptable?
bummzack

Pour mettre cela dans un contexte graphique, vous voulez essentiellement connecter vos nœuds, sans chevauchement d'arêtes? (En supposant que les triangles magenta / vert partageraient un bord)
MichaelHouse

Roy T: non - il suffit de choisir les 2 plus proches, comme je le pensais dans l'exemple. Quelque chose n'est pas clair? Bummzack - Le vert ne chevauche pas le magenta. Le but est de faire un maillage ou un graphe de ces triangles. L'utilisateur a besoin de contrôle, oui. Byte56 - oui, aucun bord ne doit se croiser.
Kylotan

2
L'utilisateur verra-t-il réellement les triangles individuels? Ou est-ce que ça va être une surface continue?
bummzack

Réponses:


11

Plutôt que de trouver la distance minimale aux nœuds, recherchez la distance minimale au bord (c'est-à-dire le segment de ligne défini par les nœuds).

Ensuite, si le point le plus proche est un sommet (que vous devrez utiliser un test epsilon ** à virgule flottante), comparez l'angle entre la ligne du nouveau point au sommet et chacune des arêtes connectées à ce sommet. Choisissez celui avec l'angle absolu minimum:

MinAngle(newPoint, vertex, edge1, edge2)
{
   newEdgeUnit = norm(newPoint - vertex); // don't actually need to normalize this
   edge1Unit = norm(edge1 - vertex);      // you probably have these from your dist to line tests
   edge2Unit = norm(edge2 - vertex);

   edge1Dot = dot(edge1Unit, newEdgeUnit);
   edge2Dot = dot(edge2Unit, newEdgeUnit);

   // you can simply compare dot products to find the minimum absolute angle
   if (edge1Dot > edge2Dot) return edge1;     // set up this way so you can generalize to an array
   return edge2;
}

** Pour éviter d'ajouter des triangles dégénérés, ce qui pourrait perturber le test epsilon, vous souhaiterez peut-être placer une région autour de chaque sommet où l'ajout de points est interdit (quelque chose comme interdire les points dans un multiple de l'epsilon utilisé ci-dessus).


3
+1 - c'est à mon humble avis une réponse beaucoup plus simple que les autres, et plus susceptible de fournir les bons résultats. La distance par rapport au segment est également facile à calculer avec un schéma intelligent.
Steven Stadnicki

D'accord, c'est une méthode plus propre. Probablement ce à quoi j'aurais pu arriver si j'y avais réfléchi davantage: /
MichaelHouse

Ah, si près! Mais, comme avec la réponse de Byte56 et le diagramme de Jimmy, il y a parfois 2 bords équidistants, et l'un d'eux viole les contraintes. J'ai mis à jour ma question.
Kylotan

@Kylotan Peut-être que dans ce cas, vérifier simplement celui qui se chevauche et prendre l'autre option ferait l'affaire? Recherchez les triangles partageant le bord que vous avez choisi et vérifiez si votre nouveau triangle est du même côté de ce bord que celui existant.
Kevin Reid

@Kylotan Assurez-vous que vos triangles ont toujours le même enroulement? Si oui, vous pouvez exclure le bord qui a un pointage normal loin de votre nouveau sommet (en utilisant le produit scalaire).
bummzack

6

Une fois le premier triangle placé, lorsque vous placez un nouveau sommet, vous générerez toujours deux nouvelles arêtes. Le troisième bord du nouveau triangle sera toujours un bord partagé avec un triangle précédent. Si vous pouviez trouver un moyen de déterminer le bord partagé, vous sauriez à quels sommets se connecter, mais c'est la partie difficile. Je pense que vous pouvez le faire en traçant une ligne de votre nouveau sommet au centre de chacune des trois dernières arêtes générées (ou probablement les 3 arêtes les plus proches).

entrez la description de l'image ici

Si la ligne allant de votre sommet au centre du bord ne pas traverser l'une des deux autres bords, vous avez votre avantage partagé. L'arête partagée vous indiquera les deux sommets auxquels connecter votre nouveau sommet.

Jimmy a soulevé le cas d'un point ambigu quant à la destination du nouveau triangle:

triangle ambigu

Cela vous donnerait la possibilité de choisir entre deux triangles valides. Peut-être que le bris d'égalité est le point central le plus proche.

Compte tenu de votre mise à jour, bien que plus complexe, ma solution ne donnera lieu à une égalité que si vous avez deux triangles valides. En utilisant cette méthode, votre deuxième exemple d'image produirait le résultat souhaité.

entrez la description de l'image ici


Il est possible d'avoir une situation où deux des lignes ne se coupent pas avec des arêtes (lorsque X est plus proche d'un sommet que de l'arête)
Jimmy

@Jimmy pouvez-vous dessiner une image d'une telle situation?
MichaelHouse


Ah oui, alors vous avez deux choix où placer le triangle! L'un ou l'autre côté fonctionnerait. Vous pouvez peut-être faire le lien avec celui qui a la distance la plus courte au centre.
MichaelHouse

@Kylotan cette solution ne fonctionne-t-elle pas? Vous avez mentionné dans un commentaire à Jeff que l'image de Jimmy a deux cas et l'un viole les contraintes, mais ce n'est pas vrai. À l'image de Jimmy, les deux cas produiraient tous les deux des triangles valides en utilisant ma méthode.
MichaelHouse

1

Ayant votre triangle magenta ABC, vous incorporez ensuite un nouveau sommet X. Je pense qu'il est évident qu'il y aura deux lignes commençant à D qui ne se coupent entre aucun des bords du triangle ABC.

Ces deux lignes peuvent être AX & BX, BX & CX ou AX & CX. Vous pouvez alors traiter votre problème comme le problème classique de "deux lignes se croisent"? Vous pouvez ensuite vérifier laquelle de ces paires de lignes ne coupe aucune des arêtes du triangle ABC en suivant, par exemple, l' une des méthodes de cette question . Par conséquent, vous aurez les deux nouveaux bords du nouveau triangle.


Cela semble bien, mais la façon dont vous l'avez dit semble supposer qu'il n'y a qu'un seul triangle existant. Comment cela se généraliserait-il à beaucoup?
Kylotan

Hum ... si votre X et votre triangle ABC sont fixes, je suppose qu'il n'y en a qu'un, n'est-ce pas?
Dan

Le système crée un nouveau triangle pour chaque nœud après le 2e.
Kylotan

Désolé, j'ai mal compris votre question. Voyons comment je peux étendre cela à de nombreux triangles.
Dan

Eh bien, je suppose que vous pourriez rechercher les deux sommets les plus proches de X qui ne traversent aucun bord lorsqu'ils sont connectés à X?
bummzack

1

Déterminer si vous vous trouvez dans l'une des régions sans ambiguïté (1, 2, 3 ci-dessous) est assez simple: traitez chaque bord de votre triangle comme un plan 2D et testez de quel côté du plan se trouve votre nouveau point. Si vous êtes à l'intérieur de deux d'entre eux mais à l'extérieur de celui-ci, alors celui-ci correspond au bord du triangle qui contribue deux sommets à votre nouveau triangle.

Régions de Voronoi d'un triangle

Si vous êtes à l'intérieur d'un et à l'extérieur de deux, vous êtes dans le cas ambigu où la partie la plus proche du triangle de votre nouveau point est un coin. Dans ce cas, vous pouvez former un plan 2D à partir du milieu du bord opposé (celui à l'intérieur duquel vous êtes) et du sommet le plus proche (celui partagé par les deux plans dont vous êtes à l'extérieur). Vous pouvez choisir une arête en fonction du côté de cet avion sur lequel se trouve votre nouveau point.

Notez qu'un test d'avion en 2D fonctionne de la même manière qu'en 3D: parsemez un vecteur de n'importe où sur l'avion jusqu'à votre point avec la normale de l'avion (en 2D, c'est la perpendiculaire de la ligne).

(Soit dit en passant, les régions délimitées par le magenta dans cette image sont appelées régions de Voronoï; ce sont les zones d'espace contenant des points qui sont les plus proches d'une entité particulière - bord ou sommet - du triangle. Edit: Ma terminologie ici n'est pas réellement tout à fait correct, ce ne sont pas exactement les régions de Voronoi.)


Il n'est pas immédiatement clair pour moi comment cela se généralise à plusieurs triangles dans la scène - surtout si l'entité la plus proche est un sommet qui peut être partagé par plus d'un triangle.
Kylotan

@Kylotan Il suffit d'exécuter l'algorithme pour tous les triangles et de sélectionner l'entité globale la plus proche. Vous avez besoin d'une logique de bris d'égalité, quoi qu'il arrive. Si vous vous retrouvez avec l'entité la plus proche étant un sommet partagé, alors vous devriez être dans la région de bord (# 1, # 2, # 3) pour un seul triangle, alors peut-être que vous pouvez choisir cela?
John Calsbeek
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.