Accueil > > > POINTS LES PLUS PROCHES
POINTS LES PLUS PROCHES
Information sur la source
Description
l'algorithme de complexité inférieur à n^2 pour trouver les 2 points les plus rapprochés dans un nuage de points. La petite application graphique est en swing et awt.
Source
- package com.xsimo;
-
- import java.awt.BorderLayout;
- import java.awt.Color;
- import java.awt.Point;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.Dimension;
- import java.awt.event.ActionListener;
- import java.awt.event.ActionEvent;
- import javax.swing.JFrame;
- import javax.swing.JButton;
- import javax.swing.JPanel;
- import javax.swing.JLabel;
- import javax.swing.SwingUtilities;
-
- /**
- * @author Simon Arame
- *
- */
- public class MyJWS extends JFrame{
- private static final long serialVersionUID = -3246226270054064224L;
- private JPanel mainPane;
- private JPanel bPanel;
- private JButton buttonGenerate;
- private JLabel distanceLabel;
- private Point[] points;
- private Point[] PY;
- int indice1;
- int indice2;
- private double distMin;
- private static int NOMBRE_DE_POINTS = 12;
-
- public void paint(Graphics g){
- super.paint(g);
- Graphics2D g2D = (Graphics2D)g;
- g2D.setColor(Color.BLUE);
- for(int i = 0 ; i< NOMBRE_DE_POINTS;i++){
- g.fillOval((int)points[i].getX()-2,(int)points[i].getY()-2,5,5);
- }
- g2D.setColor(Color.RED);
- java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double(points[indice1],points[indice2]);
- java.awt.BasicStroke bs = new java.awt.BasicStroke(2);
- g2D.setStroke(bs);
- g2D.draw(line);
- String distMinRounded = ""+(double)((int)(distMin*100))/100.0;
- distanceLabel.setText("min distance = "+distMinRounded+" pixels");
- }
- public MyJWS(){
-
- //THIS
- super("l'algorithme des 2 points les plus proches");
-
- //TWEAK to get screensize
- JFrame frame = new JFrame();
- frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
- frame.setVisible(true);
- Dimension screen = frame.getSize();
- frame.setVisible(false);
-
- //THIS
- this.setSize(screen);
- this.setExtendedState(JFrame.MAXIMIZED_BOTH);
- this.setLayout(new BorderLayout());
- this.getContentPane().setBackground(Color.WHITE);
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-
- //MAIN
- mainPane = new JPanel();
- mainPane.setSize(new Dimension(screen.width,screen.height-80));
- mainPane.setBackground(new Color(235, 235, 235));
- this.getContentPane().add(mainPane,BorderLayout.CENTER);
-
- //bPANEL
- bPanel = new JPanel();
- bPanel.setPreferredSize(new Dimension(screen.width,70));
- bPanel.setBackground(Color.BLUE);
- bPanel.setLayout(new BorderLayout());
- this.getContentPane().add(bPanel,BorderLayout.SOUTH);
-
- //BOUTON
- buttonGenerate = new JButton("new");
- buttonGenerate.addActionListener(new PointsFieldGen());
- //buttonGenerate.setSize(new Dimension(50,50));
- bPanel.add(buttonGenerate,BorderLayout.WEST);
-
- //LABEL
- distanceLabel = new JLabel();
- distanceLabel.setForeground(Color.WHITE);
- bPanel.add(distanceLabel,BorderLayout.CENTER);
-
- //POINTS
- points = new Point[NOMBRE_DE_POINTS];
- generer();
- distMin = PtProche();
- }
-
- /**
- * Important : l'utilisation de SwingUtilities.invokeLater
- * @param args
- */
- public static void main(String [] args){
- SwingUtilities.invokeLater(new Runnable(){
- public void run() {
- MyJWS m = new MyJWS();
- m.setVisible(true);
- }
- });
- }
- class PointsFieldGen implements ActionListener{
- public void actionPerformed(ActionEvent e){
- generer();
- distMin = PtProche();
- repaint();
- }
- }
- public void generer(){
- java.util.Random r = new java.util.Random();
- for(int i = NOMBRE_DE_POINTS-1;i>=0;i--){
- points[i] = new Point();
- points[i].setLocation(r.nextInt(this.mainPane.getWidth()),r.nextInt(this.mainPane.getHeight()));
- }
- indice2 = indice1;
- }
- public double PtProche(){
- PY = new Point[NOMBRE_DE_POINTS];
- PY = points.clone();
- sort(0,NOMBRE_DE_POINTS-1);
- sortX(0,NOMBRE_DE_POINTS-1);
- Couple c = PtProcheRec(points,PY);
-
- for(int i = 0 ; i<NOMBRE_DE_POINTS;i++){
- if(c.p1.getX()==points[i].getX() && c.p1.getY()==points[i].getY()){
- indice1 = i;
- }
- if(c.p2.getX()==points[i].getX() && c.p2.getY()==points[i].getY()){
- indice2 = i;
- }
- }
- return c.d;
- }
- public Couple PtProcheRec(Point [] PX, Point [] PY){
- if(PX.length>4){
- Division div = diviserPoint(PX,PY);
- Couple c1 = PtProcheRec(div.PGX,div.PGY);
- Couple c2 = PtProcheRec(div.PDX,div.PDY);
- Couple cr = null;
- if(c1.d<c2.d){
- cr = c1.clone();
- }else{
- cr = c2.clone();
- }
- Point[] PYY = bandeVert(PY,div.l,cr.d);
- Couple cm = rechVert(PYY,cr.d);
- if(cm.d<cr.d){
- return cm;
- }else{
- return cr;
- }
- }else{
- return naif(PX);
- }
- }
- public Point[] bandeVert(Point [] PY,Point l, double delta){
- java.util.ArrayList<Integer> a = new java.util.ArrayList<Integer>();
- for(int j = 0; j<PY.length;j++){
- if(PY[j].getX()>=l.getX()-delta && PY[j].getX()<= l.getX()+delta){
- a.add(j);
- }
- }
- Point[] PYY = new Point[a.size()];
- for(int k = 0; k<a.size();k++){
- PYY[k] = PY[a.get(k)];
- }
- return PYY;
- }
- public Couple rechVert(Point[] PYY, double delta){
- double min = delta;
- Couple c = new Couple();
- c.d = delta;
- for(int i = 0; i<PYY.length;i++){
- for(int j=i+1;j<i+8 && j< PYY.length;j++){
- double d = distance(PYY[i],PYY[j]);
- if(d<min){
- min=d;
- c.d = d;
- c.p1 = PYY[i];
- c.p2 = PYY[j];
- }
- }
- }
- return c;
- }
- public double distance(Point p1, Point p2){
- double dx = p2.getX()-p1.getX();
- double dy = p2.getY()-p1.getY();
- double dist = java.lang.Math.sqrt(dx*dx+dy*dy);
- return dist;
- }
- public Couple naif(Point[] PX){
- Couple c = new Couple();
- double min = (double)Integer.MAX_VALUE;
- for(int i = 0; i< PX.length-1;i++){
- for(int j = i+1;j<PX.length;j++){
- double dist = distance(PX[i],PX[j]);
- if(dist<min){
- min = dist;
- c.d = dist;
- c.p1 = PX[i];
- c.p2 = PX[j];
- }
- }
- }
- return c;
- }
- public Division diviserPoint(Point[] PX, Point[] PY){
- Division div = new Division();
- Point split = PX[PX.length/2];
- div.l = split;
- div.PGX = new Point[PX.length/2];
- for(int i = 0 ; i< PX.length/2; i++){
- div.PGX[i] = (Point)PX[i].clone();
- }
- div.PGY = new Point[PX.length/2];
- if(PX.length %2 == 0){
- div.PDX = new Point[PX.length/2];
- for(int i = PX.length/2 ; i< PX.length; i++){
- div.PDX[i-PX.length/2] = (Point)PX[i].clone();
- }
- div.PDY = new Point[PX.length/2];
- }else{
- div.PDX = new Point[(PX.length/2)+1];
- for(int i = PX.length/2 ; i < PX.length;i++){
- div.PDX[i-PX.length/2] = (Point)PX[i].clone();
- }
- div.PDY = new Point[(PX.length/2)+1];
- }
- int i = 0;
- int j = 0;
- for(int k = 0 ; k< PX.length; k++){
- if(PY[k].getX()<split.getX() || (PY[k].getX() == split.getX() && PY[k].getY() < split.getY())){
- div.PGY[i]=(Point)PY[k].clone();
- i++;
- }else{
- try{
- div.PDY[j]=(Point)PY[k].clone();
- }catch(Exception e){
- System.out.println("oups");
- }
- j++;
- }
- }
- return div;
- }
- class Couple{
- public Point p1;
- public Point p2;
- public double d;
- public Couple clone(){
- Couple c = new Couple();
- c.p1 = (Point)this.p1.clone();
- c.p2 = (Point)this.p2.clone();
- c.d = new java.lang.Double(this.d);
- return c;
- }
- }
- class Division{
- Point[] PGX;
- Point[] PDX;
- Point[] PGY;
- Point[] PDY;
- Point l;
- }
- public void sort(int p, int q){
- if(p<q){
- int r = part(p,q);
- sort(p,r-1);
- sort(r+1,q);
- }
- }
- public int part(int p, int q){
- Point pivot = PY[p];
- int i = p;
- for(int j = p+1; j<=q ; j++){
- if(PY[j].getY()<=pivot.getY()){
- i=i+1;
- Point temp = PY[i];
- PY[i] = PY[j];
- PY[j] = temp;
- }
- }
- Point temp = PY[i];
- PY[i] = PY[p];
- PY[p] = temp;
- return i;
- }
- public void sortX(int p, int q){
- if(p<q){
- int r = partX(p,q);
- sortX(p,r-1);
- sortX(r+1,q);
- }
- }
- public int partX(int p, int q){
- Point pivot = points[p];
- int i = p;
- for(int j = p+1; j<=q ; j++){
- if(points[j].getX()<pivot.getX()||(points[j].getX()==pivot.getX()&&points[j].getY()<pivot.getY())){
- i=i+1;
- Point temp = points[i];
- points[i] = points[j];
- points[j] = temp;
- }
- }
- Point temp = points[i];
- points[i] = points[p];
- points[p] = temp;
- return i;
- }
- }
package com.xsimo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
/**
* @author Simon Arame
*
*/
public class MyJWS extends JFrame{
private static final long serialVersionUID = -3246226270054064224L;
private JPanel mainPane;
private JPanel bPanel;
private JButton buttonGenerate;
private JLabel distanceLabel;
private Point[] points;
private Point[] PY;
int indice1;
int indice2;
private double distMin;
private static int NOMBRE_DE_POINTS = 12;
public void paint(Graphics g){
super.paint(g);
Graphics2D g2D = (Graphics2D)g;
g2D.setColor(Color.BLUE);
for(int i = 0 ; i< NOMBRE_DE_POINTS;i++){
g.fillOval((int)points[i].getX()-2,(int)points[i].getY()-2,5,5);
}
g2D.setColor(Color.RED);
java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double(points[indice1],points[indice2]);
java.awt.BasicStroke bs = new java.awt.BasicStroke(2);
g2D.setStroke(bs);
g2D.draw(line);
String distMinRounded = ""+(double)((int)(distMin*100))/100.0;
distanceLabel.setText("min distance = "+distMinRounded+" pixels");
}
public MyJWS(){
//THIS
super("l'algorithme des 2 points les plus proches");
//TWEAK to get screensize
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
Dimension screen = frame.getSize();
frame.setVisible(false);
//THIS
this.setSize(screen);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLayout(new BorderLayout());
this.getContentPane().setBackground(Color.WHITE);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//MAIN
mainPane = new JPanel();
mainPane.setSize(new Dimension(screen.width,screen.height-80));
mainPane.setBackground(new Color(235, 235, 235));
this.getContentPane().add(mainPane,BorderLayout.CENTER);
//bPANEL
bPanel = new JPanel();
bPanel.setPreferredSize(new Dimension(screen.width,70));
bPanel.setBackground(Color.BLUE);
bPanel.setLayout(new BorderLayout());
this.getContentPane().add(bPanel,BorderLayout.SOUTH);
//BOUTON
buttonGenerate = new JButton("new");
buttonGenerate.addActionListener(new PointsFieldGen());
//buttonGenerate.setSize(new Dimension(50,50));
bPanel.add(buttonGenerate,BorderLayout.WEST);
//LABEL
distanceLabel = new JLabel();
distanceLabel.setForeground(Color.WHITE);
bPanel.add(distanceLabel,BorderLayout.CENTER);
//POINTS
points = new Point[NOMBRE_DE_POINTS];
generer();
distMin = PtProche();
}
/**
* Important : l'utilisation de SwingUtilities.invokeLater
* @param args
*/
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
MyJWS m = new MyJWS();
m.setVisible(true);
}
});
}
class PointsFieldGen implements ActionListener{
public void actionPerformed(ActionEvent e){
generer();
distMin = PtProche();
repaint();
}
}
public void generer(){
java.util.Random r = new java.util.Random();
for(int i = NOMBRE_DE_POINTS-1;i>=0;i--){
points[i] = new Point();
points[i].setLocation(r.nextInt(this.mainPane.getWidth()),r.nextInt(this.mainPane.getHeight()));
}
indice2 = indice1;
}
public double PtProche(){
PY = new Point[NOMBRE_DE_POINTS];
PY = points.clone();
sort(0,NOMBRE_DE_POINTS-1);
sortX(0,NOMBRE_DE_POINTS-1);
Couple c = PtProcheRec(points,PY);
for(int i = 0 ; i<NOMBRE_DE_POINTS;i++){
if(c.p1.getX()==points[i].getX() && c.p1.getY()==points[i].getY()){
indice1 = i;
}
if(c.p2.getX()==points[i].getX() && c.p2.getY()==points[i].getY()){
indice2 = i;
}
}
return c.d;
}
public Couple PtProcheRec(Point [] PX, Point [] PY){
if(PX.length>4){
Division div = diviserPoint(PX,PY);
Couple c1 = PtProcheRec(div.PGX,div.PGY);
Couple c2 = PtProcheRec(div.PDX,div.PDY);
Couple cr = null;
if(c1.d<c2.d){
cr = c1.clone();
}else{
cr = c2.clone();
}
Point[] PYY = bandeVert(PY,div.l,cr.d);
Couple cm = rechVert(PYY,cr.d);
if(cm.d<cr.d){
return cm;
}else{
return cr;
}
}else{
return naif(PX);
}
}
public Point[] bandeVert(Point [] PY,Point l, double delta){
java.util.ArrayList<Integer> a = new java.util.ArrayList<Integer>();
for(int j = 0; j<PY.length;j++){
if(PY[j].getX()>=l.getX()-delta && PY[j].getX()<= l.getX()+delta){
a.add(j);
}
}
Point[] PYY = new Point[a.size()];
for(int k = 0; k<a.size();k++){
PYY[k] = PY[a.get(k)];
}
return PYY;
}
public Couple rechVert(Point[] PYY, double delta){
double min = delta;
Couple c = new Couple();
c.d = delta;
for(int i = 0; i<PYY.length;i++){
for(int j=i+1;j<i+8 && j< PYY.length;j++){
double d = distance(PYY[i],PYY[j]);
if(d<min){
min=d;
c.d = d;
c.p1 = PYY[i];
c.p2 = PYY[j];
}
}
}
return c;
}
public double distance(Point p1, Point p2){
double dx = p2.getX()-p1.getX();
double dy = p2.getY()-p1.getY();
double dist = java.lang.Math.sqrt(dx*dx+dy*dy);
return dist;
}
public Couple naif(Point[] PX){
Couple c = new Couple();
double min = (double)Integer.MAX_VALUE;
for(int i = 0; i< PX.length-1;i++){
for(int j = i+1;j<PX.length;j++){
double dist = distance(PX[i],PX[j]);
if(dist<min){
min = dist;
c.d = dist;
c.p1 = PX[i];
c.p2 = PX[j];
}
}
}
return c;
}
public Division diviserPoint(Point[] PX, Point[] PY){
Division div = new Division();
Point split = PX[PX.length/2];
div.l = split;
div.PGX = new Point[PX.length/2];
for(int i = 0 ; i< PX.length/2; i++){
div.PGX[i] = (Point)PX[i].clone();
}
div.PGY = new Point[PX.length/2];
if(PX.length %2 == 0){
div.PDX = new Point[PX.length/2];
for(int i = PX.length/2 ; i< PX.length; i++){
div.PDX[i-PX.length/2] = (Point)PX[i].clone();
}
div.PDY = new Point[PX.length/2];
}else{
div.PDX = new Point[(PX.length/2)+1];
for(int i = PX.length/2 ; i < PX.length;i++){
div.PDX[i-PX.length/2] = (Point)PX[i].clone();
}
div.PDY = new Point[(PX.length/2)+1];
}
int i = 0;
int j = 0;
for(int k = 0 ; k< PX.length; k++){
if(PY[k].getX()<split.getX() || (PY[k].getX() == split.getX() && PY[k].getY() < split.getY())){
div.PGY[i]=(Point)PY[k].clone();
i++;
}else{
try{
div.PDY[j]=(Point)PY[k].clone();
}catch(Exception e){
System.out.println("oups");
}
j++;
}
}
return div;
}
class Couple{
public Point p1;
public Point p2;
public double d;
public Couple clone(){
Couple c = new Couple();
c.p1 = (Point)this.p1.clone();
c.p2 = (Point)this.p2.clone();
c.d = new java.lang.Double(this.d);
return c;
}
}
class Division{
Point[] PGX;
Point[] PDX;
Point[] PGY;
Point[] PDY;
Point l;
}
public void sort(int p, int q){
if(p<q){
int r = part(p,q);
sort(p,r-1);
sort(r+1,q);
}
}
public int part(int p, int q){
Point pivot = PY[p];
int i = p;
for(int j = p+1; j<=q ; j++){
if(PY[j].getY()<=pivot.getY()){
i=i+1;
Point temp = PY[i];
PY[i] = PY[j];
PY[j] = temp;
}
}
Point temp = PY[i];
PY[i] = PY[p];
PY[p] = temp;
return i;
}
public void sortX(int p, int q){
if(p<q){
int r = partX(p,q);
sortX(p,r-1);
sortX(r+1,q);
}
}
public int partX(int p, int q){
Point pivot = points[p];
int i = p;
for(int j = p+1; j<=q ; j++){
if(points[j].getX()<pivot.getX()||(points[j].getX()==pivot.getX()&&points[j].getY()<pivot.getY())){
i=i+1;
Point temp = points[i];
points[i] = points[j];
points[j] = temp;
}
}
Point temp = points[i];
points[i] = points[p];
points[p] = temp;
return i;
}
}
Conclusion
l'algorithme naif est utilisé pour les nuages des points de moins de 4 pts.
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
JAVA2D et ECRAN TACTILE [ par MICHELGERARD ]
Je developpe une application graphique destinée à servir de "croquis" dans les relevés topographiques et donc à fonctionner sur des tablettes graphiqu
menu non graphique en java [ par emubusta ]
slt à tous j'aimerai savoir comment on fait un menu non graphique en java ;-)
menu non graphique [ par emubusta ]
slt à tous j'aimerai faire un menu en sortie texte en mode console et je ne sais pas comme m'y prendre!!:-(
icones dans jlabel [ par HFanny ]
Bonjour à tous,je souhaiterais remplacer les caractères d'une String par des icones (images de chaque lettre) correspondantes.Simplement pour rendre m
interface graphique [ par emubusta ]
slt à tous je suis en stage e et j'aimerai savoir si qqn aurait les codes sources d'une interface graphique pour une agenda
interface graphique en java [ par maximus84 ]
bonjour, je travail sur un prog en java qui doit simuler un ascenseur désservant 10 étages....etc J'aimerai savoir si c t possible une interface gaphi
Interface graphique, JLabel [ par tlehoucq ]
Bonjour, Voilà mon pb: j'ai une fenêtre sur laquelle se trouve un JPanel principal. Sur ce panel principal j' ai créé plusieurs autres petits JP
insérer une image dans une interface graphique Swing [ par asx9 ]
asx9salut,je ne sais pas comment on insert une images dans une interface graphique Swing. j'aimerai en positionner soit directement sur mon cadre soit
panel graphique visible [ par moffer ]
bonjour,je voudrais utiliser un composant avec une bordure exterieur dans lequel je peu inserer des composants, mais je ne sais pas quel composant uti
JScrollPane et Layout à null [ par Kael_Kael ]
Bonjour,je développe actuellement une interface graphique affichant une hiérarchie. Cette hiérarchie est entièrement faite à la mains.Ainsi, dans mon
|
Derniers Blogs
GESTION D'EXCEPTION AVEC LES TASKSGESTION D'EXCEPTION AVEC LES TASKS par richardc
Nous avons vu dans un précédent article comment utiliser Task pour effectuer des opérations dans un autre thread.
Malheureusement, comme tout le monde n'est pas parfait, il se peut que cette exécution se passe mal et qu'une exception se produise.
La...
Cliquez pour lire la suite de l'article par richardc DéMARRONS AVEC LES TASKSDéMARRONS AVEC LES TASKS par richardc
Que vous le vouliez ou non, le développement multi-tâche est maintenant une obligation pour toute nouvelle application. Il est donc vital d'en comprendre les mécanismes et de s'y mettre le plus tôt possible.
En attendant le .NET Framework 4.5 avec le...
Cliquez pour lire la suite de l'article par richardc SLIDE & DéMO TECHDAYS 2012 - FAST & FURIOUS XAML APPSSLIDE & DéMO TECHDAYS 2012 - FAST & FURIOUS XAML APPS par Vko
Retrouvez les slides et les démo de ma session Fast & Furious XAML Apps. A ceux qui se posent la question : "est-ce que le code de la DataGrid est disponible?", je vous répondrais "pas encore". Je vais mettre en place un projet codeplex pour part...
Cliquez pour lire la suite de l'article par Vko XNA IS DEAD!XNA IS DEAD! par richardc
Depuis la semaine dernière (et grâce aux TechDays 2012), je me penche activement sur la nouvelle version de Windows, aka Windows 8. Vous me direz, il était temps puisque la première preview date de Septembre dernier.
OK. Remarquez, on n'en est qu'aux...
Cliquez pour lire la suite de l'article par richardc TECHDAYS PARIS 2012 : WINDOWS SERVER "8" QUOI DE 9 !TECHDAYS PARIS 2012 : WINDOWS SERVER "8" QUOI DE 9 ! par ROMELARD Fabrice
Speakers: Fabrice Meillon et Stanislas Quastana Cette session est basée entièrement sur celle donnée lors de la BUILD cet hiver. Il n'y a pas d'ajout d'information en rapport avec cet évènement passé. Windows 8 Server sera intégralem...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice
Forum
J2EEJ2EE par barhoum1111
Cliquez pour lire la suite par barhoum1111
Logiciels
DocTranslate (V3.1.0.0)DOCTRANSLATE (V3.1.0.0)DocTranslate est un traducteur de document Microsoft Word, PowerPoint et Excel. Il permet d'autom... Cliquez pour télécharger DocTranslate Tribler (2012)TRIBLER (2012)Tribler est un client pair à pair (P2P/Peer-to-Peer) open source avec la capacité de regarder des... Cliquez pour télécharger Tribler OneSwarm (2012)ONESWARM (2012)Le peer-to-peer qui protège votre vie privée, c'est OneSwarm.
Ce logiciel de peer-to-peer crypté... Cliquez pour télécharger OneSwarm PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V8.4)PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V8.4)PONAMEDIA TV DEVIENS HELLLOOO FLASH
LA TV SUR VOTRE ORDINATEUR.
Toute une plateforme Multi... Cliquez pour télécharger PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO Academy System (17.2.1.0)ACADEMY SYSTEM (17.2.1.0)Logiciel de gestion des établissements.
- élèves/étudiants (inscription, dossier, absence...)
-... Cliquez pour télécharger Academy System
|