Je fais un contrôle personnalisé dans Delphi (hérité de tcustomcontrol code>) qui consiste en un certain nombre d'éléments de liste de polygones (formes irrégulières). J'ai besoin de mettre en œuvre des événements de souris par article, mais je dois d'abord pouvoir détecter si la position de la souris se trouve dans un polygone donné (gamme
de tappoint code>). Je attrape le message de test Hit (
wm_nchittest code>) et c'est là que je vais devoir faire cette validation. J'ai un certain nombre de polygones, je ferai une boucle à travers chaque élément de polygone et effectuera ce chèque pour voir si la position X / Y de la souris est dans ce polygone.
procedure TMyControl.WMNCHitTest(var Message: TWMNCHitTest);
var
P: TPoint; //X/Y of Mouse
Poly: TPoints; //array of TPoint
X: Integer; //iterator
I: TMyListItem; //my custom list item
begin
P.X:= Message.XPos;
P.Y:= Message.YPos;
for X := 0 to Items.Count - 1 do begin
I:= Items[X]; //acquire my custom list item by index
Poly:= I.Points; //acquire polygon points
//Check if Point (P) is within Polygon (Poly)...?
end;
end;
4 Réponses :
Vous pouvez utiliser pTinregion code>
:
C'était aussi ma première idée. Je suppose que les frais généraux de créer une région GDI ne sont pas trop mauvais (?).
@Andreas je n'imagine pas que les frais généraux sont mauvais. La région GDI devrait être très légère. Si c'était un problème, vous pouvez mettre en cache les régions aux côtés des polygones.
Excellent! Je n'aurai pas beaucoup de problème avec les frais généraux car je ne m'attends pas à ce que ce contrôle ait beaucoup plus de 20 éléments de liste (qui est déjà un grand nombre pour ce contrôle).
Notez que cette approche fonctionne rapidement pour les polygones rectilignes (région contenant peu de rectangles internes) et décélère pour de grandes régions avec des frontières incurvées ou inclinées (lorsque la région contient de nombreux rectangles internes)
Vous pouvez utiliser l'algorithme de coulée de rayons trouvée ici: http://fr.wikipedia.org/wiki/point_in_polygon#ray_casting_algorithm p>
La plupart des classes graphiques d'ordinateur l'utilisent comme exemple. P>
Vérification si le point est à l'intérieur d'un polygone peut être fait en imaginant une ligne horizontale à travers ce point, puis de gauche à droite comptant combien de fois cette ligne imaginée traverse un polygone. Si le nombre de croix de polygone avant de frapper un point est impair, le point est à l'intérieur, si même le point est à l'extérieur d'un polygone. P>
Il existe une autre technique que nous utilisons de manière approfondie, ce qui n'implique aucun calcul du tout et peut gérer des commandes incorporées extrêmement complexes de toutes les formes. Avoir simplement une image hors écran du contrôle avec toutes les pièces codées par couleur (comme indiqué dans l'image ci-dessous) que l'utilisateur pouvait cliquer sur.
Alors qu'ils déplacent leur souris, regardez simplement la couleur du pixel sous le Souris dans notre image hors écran et qui nous dit exactement quel bouton / contrôle ils sont sur blanc pour pas sur elle et toute série de couleurs pour les différentes parties. P>
// pseudo-code p> Remarque: l'image de masque de couleur attachée représente cinq commandes circulaires identiques cassées en quadrants avec un bouton central (et comme ils utilisent tous les mêmes couleurs que nous avons des constantes pour chaque couleur et que nous déterminons lequel des cinq souris est terminé par une simple xposition) avec une commande irrégulière supplémentaire à leur droite et à un ensemble ou de boutons rectangulaires en dessous. P> P>
Juste pour signaler, il me manque une ligne de code
p: = screyoclient (p); code> juste après l'attribution de
p.x code> et
p.y code>. Cela convertit ces points d'être relatifs à l'écran pour être relatif au contrôle.
Bien sûr, il pourrait être aussi simple que
p: = screentoclient (point (message.xpos, message.ypos)); code> (Tour 3 lignes de code en une)