Bonjour,
Pour ceux que cela intéresse, voici une solution pour vérifier que des Polygones ne se coupent pas les uns les autres et ne sont pas des polygones croisés. Il y a quelques restrictions, comme le fait qu'un Polygone a au moins 3 cotés, et une particularité (lié à ce qu'il me fallait) qui est qu'il y a un Polygone extérieur englobant. Mais je ne doute pas que vous puissiez adapter cette solution à votre problème.
Objectif : 1 premier polygone (rectangulaire) est dessiné sur la zone
On peut ajouter autant de polygone que l'on veut mais toujours à l'intérieur de ce premier polygone
On peut modifier les polygone en sélectionnant puis déplaçant un angle
On ne peut déplacer que 1 angle à la fois
Aucun polygone ne doit se superposer
Aucun polygone ne doit être croisé
AVERTISSEMENT : CE CODE EST INCOMPLET
en clair il ne compilera pas tel quel
ceci afin de ne pas noyer encore plus la partie d'intérêt qui est le test
Est présenté uniquement
- le test en lui même bien sur ;-)
- quelques éléments indispensables à la compréhension du test:
* initialisation
* modifications
* ajout d'un polygone afin de bien comprendre comment ils sont gérés ici
ce qui fait déjà pas mal, il ne vous reste qu'à implémenter la plomberie autour.
Pour commencer une classe Angle. Cette classe n'a rien de compliquée. Dans mon projet elle contient quelques éléments suplémentaires pour d'autres besoins d'où son interet.
Les différents éléments de la classe pour manipuler les polygones :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class Angle{ private int abscisse,ordonnee; private Rectangle rectangle; private Color currentColor; public Angle(int x,int y){ abscisse=x; ordonnee=y; currentColor=Color.BLACK; doRect(); } public int getX(){return abscisse;} public int getY(){return ordonnee;} public void setX(int x){ abscisse=x; doRect(); } public void setY(int y){ ordonnee=y; doRect(); } public void setCouleur(Color c){ currentColor=c; doRect(); } public boolean containsPoint(int x, int y){ return rectangle.contains(x,y); } private void doRect(){ rectangle=new Rectangle(abscisse-10,ordonnee-10,20,20); } public void dessine(Graphics2D g){ g.setPaint(currentColor); g.fill(rectangle); } }//fin public class Angle
Déclaration des variables
Création du polygone initiale
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 private ArrayList<Polygon> lesPolygones;//une liste des Polygon utilisés private ArrayList<ArrayList<Angle>> lesAngles;//pour chaque polygone une liste d'Angle private ArrayList<ArrayList<Line2D.Double>> lesLignes;//pour chaque polygone une liste de Line2D.Double private int largeurTotal,hauteurTotal;// la largeur et la hauteur de la zone autorisée private int selectedPolygon;//le numéro du polygone sélectionné private int selectedAngle;//le numéro de l'angle sélectionné pour ce Polygone private int ancienX,ancienY;//lors de la sélection de l'angle mémorisation des anciennes coordonnées
Ajout d'un polygone, pour comprendre comment je traite les polygones
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 //initialisation des ArrayList lesAngles = new ArrayList<ArrayList<Angle>>(); lesLignes = new ArrayList<ArrayList<Line2D.Double>>(); lesPolygones = new ArrayList<Polygon>(); //création de la première liste d'angle ArrayList<Angle> al =new ArrayList<Angle>(); //création des angles al.add(new Angle(0,0)); al.add(new Angle(largeurTotal,0)); al.add(new Angle(largeurTotal,hauteurTotal)); al.add(new Angle(0,hauteurTotal)); lesAngles.add(al); //pas d'angle selectionné au départ selectedAngle=-1; //le premier Polygon Polygon p = new Polygon(new int[]{0,largeurTotal,largeurTotal,0},new int[]{0,0,hauteurTotal,hauteurTotal},4); lesPolygones.add(p); //la liste de liste de Line2D ArrayList<Line2D.Double> ll=new ArrayList<Line2D.Double>(); //la première liste de Line2D ll.add(new Line2D.Double(0,0,largeurTotal,0)); ll.add(new Line2D.Double(largeurTotal,0,largeurTotal,hauteurTotal)); ll.add(new Line2D.Double(largeurTotal,hauteurTotal,0,hauteurTotal)); ll.add(new Line2D.Double(0,hauteurTotal,0,0)); lesLignes.add(ll);
Déplacer un angle,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 private void addPolygone(){ //j'ai choisi la solution de facilité: // - largeur et hauteur fixe au départ (1/20 de la largeur ou de la hauteur) // - polygone régulier // ne peut être déterminé que: le nombre de coté et la position //on demande le nombre de coté(premier JSpinner) int increment = Math.min(largeurTotal/20,hauteurTotal/20); SpinnerNumberModel model1 = new SpinnerNumberModel(3, 3, 1000, 1); JSpinner sp1 = new JSpinner(model1); //position du centre du Polygone //JSpinner2 pour l'abscisse //JSpinner3 pour l'ordonné SpinnerNumberModel model2 = new SpinnerNumberModel(increment, increment, largeurTotal-increment, increment/2); JSpinner sp2 = new JSpinner(model2); SpinnerNumberModel model3 = new SpinnerNumberModel(increment, increment, hauteurTotal-increment, increment/2); JSpinner sp3 = new JSpinner(model3); //et un petit panneau de dialogue int r=JOptionPane.showOptionDialog(null, new Object[]{"combien d'angle",sp1,"entrez les coordonnées","abscisse",sp2,"ordonné",sp3}, ressources.getString("nouveau Polygone"),JOptionPane.OK_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE,null,null,null); // bien sur on ajoute que si on a cliqué sur OK if (r==JOptionPane.OK_OPTION){ int x1 =model2.getNumber().intValue(); int y1 =model3.getNumber().intValue(); //on récupere abscise et ordonné Rectangle rec= new Rectangle(x1-increment,y1-increment,2*increment,2*increment); if (!contient(rec)){ //on est en dehors du polygone de base ou dans un autre polygone intérieur //Voir la méthode contient plus bas JOptionPane.showMessageDialog(null,ressources.getString("messageNBPoly6"),null,JOptionPane.WARNING_MESSAGE); return; } //on récupere les coordonnes du centre int i=model1.getNumber().intValue(); //on calcule la valeur du pas double decal =2*Math.PI/i; double alpha=0; //on prépare les tableaux et les ArrayList int[] lesX=new int[i]; int[]lesY=new int[i]; ArrayList<Angle> al= new ArrayList<Angle>(); ArrayList<Line2D.Double> ll=new ArrayList<Line2D.Double>(); //et on remplit for (int j=0;j<i;j++){ lesX[j]=new Double((increment*Math.cos(alpha))+x1).intValue(); lesY[j]=new Double((increment*Math.sin(alpha))+y1).intValue(); al.add(new Angle(lesX[j],lesY[j])); alpha=alpha+decal; if(j>0){ //pour créer la première ligne il faut au moins 2 points ll.add(new Line2D.Double(lesX[j-1],lesY[j-1],lesX[j],lesY[j])); } } //et on crée la dernière ligne ll.add(new Line2D.Double(lesX[i-1],lesY[i-1],lesX[0],lesY[0])); //on remplit les ArrayList lesAngles.add(al); lesLignes.add(ll); lesPolygones.add(new Polygon(lesX,lesY,i)); repaint(); }//fin de if (r==JOptionPane.OK_OPTION) }//fin de private void addPolygone() /* * La méthode "contient" pour tester l'ajout d'un nouveau polygone * A noter que le retour est très imprécis car il ne se base que sur * les rectangles englobants Il y a donc une possibilité que le polygone * ne soit pas reconnu comme bon alors qu'il l'est. Mais pour l'usage qui en est fait * c'est amplement suffisant. * a ne pas mettre en méthode "public" bien sur. * et ne surcharge certainement pas contains... * */ private boolean contient(Rectangle2D r){ boolean c=lesPolygones.get(0).contains(r); if (c){ for (int i=1;i<lesPolygones.size();i++){ c=c&&(!lesPolygones.get(i).intersects(r))&&(!lesPolygones.get(i).contains(r))&&(!r.contains(lesPolygones.get(i).getBounds())); } } return c; }
partie 1 sélectionner:
on notera que pour désélectionner l'angle il suffit de cliquer partout sauf sur un angle
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public void mousePressed(MouseEvent e) { if (e.getButton()==MouseEvent.BUTTON1){ //c'est que sur un clic gauche for (int i=0;i<lesAngles.size();i++){ //on regarde par,is tous les angles si il y en a un de bons ArrayList<Angle> al =lesAngles.get(i); for (int j=0;j<al.size();j++){ if (al.get(j).contains(e.getX(),e.getY())){ lacheAngle();//on lâche l'angle précédemment sélectionné selectedPolygon=i;//numéro du polygone auquel appartient l'angle selectedAngle=j;//numéro de l'angle lesAngles.get(selectedPolygon).get(selectedAngle).setCouleur(Color.RED); //l'Angle devient rouge ancienX=lesAngles.get(selectedPolygon).get(selectedAngle).getX(); ancienY=lesAngles.get(selectedPolygon).get(selectedAngle).getY(); //on conserve les anciennes coordonnées repaint(); return;//important sinon on relâchera l'angle } }//fin de for (int j=0;j<al.size();j++) }//fin de for (int i=o;i<lesAngles.size();i++) lacheAngle();//pas trouvé d'angle qui colle? // alors on lâche l'angle précédemment sélectionné }//fin de if (e.getButton()==MouseEvent.BUTTON1) }//fin de public void mousePressed(MouseEvent e) /* *partie 1 bis : lacher d'angle */ private void lacheAngle(){ if (selectedAngle!=-1){ //si il y avait un angle sélectionné lesAngles.get(selectedPolygon).get(selectedAngle).setCouleur(Color.BLACK); //on le remet en noir selectedAngle=-1;//et on indique qu'il n'y en plus repaint(); } }//fin private void lacheAngle()
partie 2 : Déplacer l'angle
partie 3 :Arrêter de le déplacer
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 public void mouseDragged(MouseEvent e) { if (selectedAngle!=-1){ //si un angle est sélectionné mettre à jour ses coordonnées lesAngles.get(selectedPolygon).get(selectedAngle).setX(e.getX()); lesAngles.get(selectedPolygon).get(selectedAngle).setY(e.getY()); repaint(); }//fin de if (selectedAngle!=-1) }//fin de public void mouseDragged(MouseEvent e)
Une petite note avant de rentrer dans le vif du sujet:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 public void mouseReleased(MouseEvent e) { if (e.getButton()==MouseEvent.BUTTON1){ if (selectedAngle!=-1){ //toujours si un angle est selectionné testAngle();//On va enfin rentrer dans le vif du sujet ;-) repaint(); } }//fin de if (e.getButton()==MouseEvent.BUTTON1) }// fin de public void mouseReleased(MouseEvent e)
On peut remarquer que j'ai délibérément choisi de ne tester QUE lorsque on a fini le déplacement. Si le déplacment est terminé et l'angle mal placé, il revient à sa position précedente.
L'introduction d'un appel a testAngle() dans la methode mouseDragged est tout a fait possible auquel cas il faut aussi ajourner en permanence les anciennes coordonnées
Comme promis : le test :
Et pour dessiner tout ça , la méthode paint
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 private void testAngle(){ //recuperation de l'angle selectionne et de ses coordonnées // cela rendra la suite plus simple Angle selec =lesAngles.get(selectedPolygon).get(selectedAngle); int x1=selec.getX(); int y1=selec.getY(); if ((x1>=0) && (x1<=largeurTotal)&&(y1>=0)&&(y1<=hauteurTotal)){ //l'angle est à l'interieur de la zone de dessin // recuperation des deux lignes constituants les arretes // autour de notre angle ou plutot creation d'une copie // car on va les modifiers pour tenir compte des nouvelles coordonnées // On récupère aussi les deux lignes encore apres // En effet ces deux lignes ne vont pas pouvoir etre traitées comme // les autres car elles interceptent obligatoirement nos deux arretes // par l'angle qu'elles ont en commun ArrayList<Line2D.Double> lin = lesLignes.get(selectedPolygon); // ligne suivant l'angle (meme numero que l'angle) Line2D.Double ls=new Line2D.Double(lin.get(selectedAngle).getP1(),lin.get(selectedAngle).getP2()); //indice de la ligne encore apres int suiLs = selectedAngle+1; if (selectedAngle==lin.size()-1){ //si l'angle selectionne est le dernier angle //une petit correction s'impose suiLs=0; } int suiLsPlus=suiLs+1; // suiLsPlus est l'indice de l'angle pour la fin de la ligne suiLs // donc l'Angle encore encore aprés if (suiLs==lin.size()-1){ suiLsPlus=0;//idem correction } //indice de la ligne precedent l'angle int indiceLp=selectedAngle-1;//indice de la ligne precedent l'angle if (selectedAngle==0){ //correction dans l'autre sens: //si l'angle selectionné est le premier, la ligne est la dernière indiceLp=lin.size()-1; } Line2D.Double lp= new Line2D.Double(lin.get(indiceLp).getP1(),lin.get(indiceLp).getP2()); int preLp = indiceLp-1;//la ligne encore avant if (indiceLp==0){preLp=lin.size()-1;}//idem correction // modification des lignes constituant les deux arrtes // pour tenir compte de la nouvelle position de l'angle // pour cela on teste si le premier point est notre angle (anciennes coordonnées) // ou pas et on change // pour la ligne precedent if (lp.x1==ancienX && lp.y1==ancienY){ lp.x1=x1; lp.y1=y1; } else{ lp.x2=x1; lp.y2=y1; } //pour la ligne suivante if (ls.x1==ancienX && ls.y1==ancienY){ ls.x1=x1; ls.y1=y1; } else{ ls.x2=x1; ls.y2=y1; } //Debut du test proprement dit for (int i=0;i<lesPolygones.size();i++){ //on va passer tous les polygones en revues //(ils ne doivent pas se superposer) if(i!=selectedPolygon){ // c'est un autre polygone que le notre // un premier tri pour regarder si l'angle // n'est pas inclu dans un autre polygone // pas forcement necessaire d'ailleurs if ( !(selectedPolygon!=0 && i==0) && lesPolygones.get(i).contains(x1,y1)){ // note sur !(selectedPolygon!=0 && i==0) // si on est sur le premier polygone il ne doit pas intercepter // les autres mais si on est sur les autres, ils doivent // etre contenu dans le polygone numero 0 // noter que on pourrait alors tester si l'angle est dehors // c'est inutile car on part d'un polygone DEJA inclus, // ayant un minimum de 3 angles et // on ne modifie qu'un seul angle donc on coupera // necessairement une arrete du polygone exterieur si on sort l'angle // ce qui sera testé après //l'angle est a l'interieur d'un polygone interieur autre //donc on remet l'angle en place (le reste n'a pas été modifié) selec.setX(ancienX); selec.setY(ancienY); repaint(); return;//important pour ne pas faire les autres tests } else { //on teste si des lignes ne se croisent pas ArrayList<Line2D.Double> l=lesLignes.get(i); for (int j=0;j<l.size();j++){ //là on teste pour tous les polygones car un polygone interieur //ne doit pas sortir //a chaque fois on teste les 2 arretes, lp et ls if (lp.intersectsLine(l.get(j))||ls.intersectsLine(l.get(j))){ //une des lignes croise une autre ligne selec.setX(ancienX); selec.setY(ancienY); repaint(); return; } }//fin du for (int j=0;j<l.size();j++) }//fin du else }//fin du if(i!=selectedPolygon) //ici on a fini le test sur le Polygon i else{ //il sagit du meme polygone, on teste qu'il ne se croise pas ArrayList<Line2D.Double> l=lesLignes.get(i); for (int j=0;j<l.size();j++){ //on va parcourir toutes les arretes if ((j!=selectedAngle) && (j!=indiceLp)){ //ou presque... //on ne teste pas les deux lignes contre elle meme //on sait deja qu'elles ont un point commun :) //si on fait un "plat" il sera detecté grace à l'autre arrete if(j==preLp){ //c'est la ligne precedente (pas celle juste avant l'angle // celle avant l'arrete precedente //on ne peut pas la tester commeles autres car elle possède //déjà un point commun avec lp if ((0==l.get(j).ptLineDist(x1,y1))|| (0==lp.ptLineDist(lesAngles.get(selectedPolygon).get(j).getX(),lesAngles.get(selectedPolygon).get(j).getY()))){ //on teste si les deux elles ne sont pas superposées //en regardant si notre angle qui vient de bouger n'est pas // sur l'arrete precedente ou inversement //note : le contains ne fonctionne pas dans ce cas //trop imprecis il laisse passer les angles plats ou nuls //l'un des 2 angles est sur l'autre lignes; elles sont superposées selec.setX(ancienX); selec.setY(ancienY); repaint(); return;//toujours important pour quitter les test } else if((l.size()>3) && ls.intersectsLine(l.get(j)) ){ //pour un polygone de trois coté il ne faut pas tester cette condition //car la ligne preLp est aussi la ligne suiLs donc meme probleme d'anlge commun //mais comme on vient de la tester... selec.setX(ancienX); selec.setY(ancienY); repaint(); return; } }//fin du if (j==preLp) else if(j==suiLs){ //c'est la ligne suivante (pas celle juste apres l'angle mais celle d'apres) //meme raisonnement if ((l.get(j).contains(x1,y1))|| ls.contains(lesAngles.get(selectedPolygon).get(suiLsPlus).getX(),lesAngles.get(selectedPolygon).get(suiLsPlus).getY())){ //l'un des 2 angles est sur l'autre lignes; elles sont superposées selec.setX(ancienX); selec.setY(ancienY); repaint(); return; } else if((l.size()>3) && lp.intersectsLine(l.get(j))) { //pour un polygone de trois coté il ne faut pas tester cette condition //car la ligne preLp est aussi la ligne suiLs donc meme probleme selec.setX(ancienX); selec.setY(ancienY); repaint(); return; }//fin du else if l.size()>3... }//fin du if (j==suiLp) else if (ls.intersectsLine(l.get(j)) || lp.intersectsLine(l.get(j))){ // Et enfin c'est une autre ligne donc on teste normalement // et une des lignes croise une autre ligne selec.setX(ancienX); selec.setY(ancienY); repaint(); return; }//fin du else i //si pas de condition rempli c'est OK donc on continue le test }//fin du if ((j!=selectedAngle) && (j!=indiceLp)) }//fin du for (int j=0;j<l.size();j++) }//fin du else indiquant le meme polygone }//fin du for pour parcourir tous les polygones //A ce point tout est OK. //On valide en mettant a jour les ArrayList //les deux lignes sont remplacées pas les copies modifiées lin.remove(selectedAngle); lin.add(selectedAngle,ls); lin.remove(indiceLp); lin.add(indiceLp,lp); //reconstruction du Polygon int[] lesX=lesPolygones.get(selectedPolygon).xpoints.clone(); int[] lesY=lesPolygones.get(selectedPolygon).ypoints.clone(); lesX[selectedAngle]=x1; lesY[selectedAngle]=y1; Polygon temp = new Polygon(lesX,lesY,lin.size()); lesPolygones.remove(selectedPolygon); lesPolygones.add(selectedPolygon,temp); //et voilà ! } else { //Ah non! il reste: l'angle est a l'exterieur de la zone selec.setX(ancienX); selec.setY(ancienY); repaint();//on remet tout comme avant et on arrete return; }//fin du else }//fin de private void testAngle()
Et voilà.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public void paint(Graphics g){ Graphics2D g2=(Graphics2D)g; //on remplit le fond g2.setPaint(couleurZone); g2.fillRect(0,0,largeurTotal,hauteurTotal); //on passe tous les polygones for (int j=0;j<lesAngles.size();j++){ //on commence par dessiner les angles int[] lesx=new int[lesAngles.get(j).size()]; int[] lesy=new int[lesAngles.get(j).size()]; for (int i=0;i<lesAngles.get(j).size();i++){ ArrayList<Angle> al=(ArrayList<Angle>)lesAngles.get(j); al.get(i).dessine(g2); lesx[i]=al.get(i).getX(); lesy[i]=al.get(i).getY(); } //si c'est le premier Fond blanc if (j==0) {g2.setPaint(Color.WHITE);} //sinon une autre couleur else {g2.setPaint(couleurInterne);}; g2.fillPolygon(lesx,lesy,lesx.length); //et le tour g2.setPaint(Color.BLACK); g2.drawPolygon(lesx,lesy,lesx.length); //on peut aussi dessiner les angles apres mais je trouvais //plus jolis sans rentrer dans le polygone }//fin de (int j=0;j<lesAngles.size();j++) }//fin de paint
Si il y a quelques questions n'hésitez pas.
bon code
kerinel
Partager