/**======================================================================== === Fichier : DisplayTsp.java === Fonction : Affichage du résultat du problème du voyageur de commerce === Version : 0.37 === Ecrit le : 28/12/2002 (derniere mise a jour) === Auteurs : Alexandre AUPETIT et Xavier CLARIST === Licence : GPL (logiciel libre) =========================================================================*/ import java.applet.Applet; import java.awt.Graphics; import java.awt.event.*; import java.net.URL; // pour la recuperation des parametres import java.awt.*; import java.util.StringTokenizer; import java.util.NoSuchElementException; /*======================================================================== Classe : Affichage d'un problème du voyageur de commerce ==========================================================================*/ public class DisplayTsp extends java.applet.Applet { int iMaxX; int iMaxY; double fPasX; double fPasY; double fXMinFen,fXMaxFen,fYMinFen,fYMaxFen; int iXClick; int iYClick; double fXCentreEcran, fYCentreEcran; double dernierXCentreEcran, dernierYCentreEcran; double lfFacteurZoom; double diff; double diffX; double diffY; double dernierZoom; boolean bZoom; double CitiesPosX[]; double CitiesPosY[]; int Parcours[]; int Parcours2[]; int Parcours3[]; boolean bParcours2AAfficher; boolean bParcours3AAfficher; boolean bShowCityNumber; double distance; double distance2; double distance3; int iNbCities; double d; int mode, nbmode; int iType; double fMinParcours, fMaxParcours; /*======================================================================== Fonction : Initialisation de l'applet et récupération des paramètres ==========================================================================*/ public void init() { int i; String sParam; String sCityPosX; String sCityPosY; System.out.println(getAppletInfo()); iMaxX = size().width; iMaxY = size().height; // type de problème : tsplib (int) ou alex (double) sParam = getParameter("ProblemType"); iType=0; try { if ( sParam.equals("tsplib") || sParam.equals("int") || sParam.equals("TSPlib") ) { iType=1; } } catch (Exception e) { iType=0; } // sParam = getParameter("ShowCityNumber"); bShowCityNumber=false; try { if ( sParam.equals("true") || sParam.equals("TRUE") ) { bShowCityNumber=true; } } catch (Exception e) { bShowCityNumber=false; } // Problème personnalisé (Nb de villes et postitions paramétrables) sParam = getParameter("Problem"); if (sParam.equals("custom")) { sParam = getParameter("NbCities"); iNbCities = (Integer.valueOf(sParam)).intValue(); System.out.println("NbCities=" + iNbCities); sCityPosX = getParameter("CitiesPosX"); sCityPosY = getParameter("CitiesPosY"); } // Problème par défaut de 250 villes else { iNbCities = 250; sCityPosX = "0.22312;0.44756;0.56937;0.47492;0.95404;0.15392;0.18974;0.62258;0.08402;0.96130;0.77813;0.79242;0.43972;0.82812;0.73679;0.84150;0.46119;0.45252;0.76285;0.06421;0.88594;0.97797;0.57890;0.24255;0.19040;0.87224;0.70068;0.91345;0.16925;0.03785;0.98596;0.86594;0.16841;0.47770;0.24590;0.64814;0.76005;0.20752;0.22667;0.00188;0.65393;0.38558;0.53878;0.49500;0.04061;0.61406;0.41220;0.47372;0.79846;0.51186;0.49334;0.17619;0.78612;0.59234;0.83379;0.42984;0.46834;0.84232;0.11446;0.71516;0.87016;0.18163;0.80922;0.86296;0.60678;0.65203;0.53483;0.35351;0.21194;0.33372;0.54007;0.53345;0.57899;0.01553;0.71309;0.84852;0.05991;0.86561;0.68550;0.47681;0.10340;0.39240;0.95707;0.95916;0.69176;0.21475;0.05645;0.24024;0.12397;0.32890;0.98646;0.42031;0.20756;0.91550;0.01449;0.18534;0.52115;0.75611;0.32366;0.64723;0.00816;0.24724;0.61018;0.70006;0.74325;0.57121;0.20636;0.77607;0.27743;0.30699;0.08388;0.40981;0.07008;0.08325;0.88119;0.40915;0.59247;0.95396;0.14387;0.93680;0.68297;0.61682;0.49952;0.30326;0.08447;0.06887;0.10258;0.77338;0.64459;0.56639;0.58712;0.41512;0.63192;0.38224;0.02310;0.66290;0.82705;0.59540;0.67261;0.10352;0.50891;0.92542;0.65106;0.78415;0.55544;0.82142;0.32606;0.32214;0.60563;0.73377;0.02341;0.33479;0.67638;0.17703;0.82886;0.10607;0.45293;0.94926;0.73029;0.39964;0.08394;0.42828;0.45761;0.36799;0.45480;0.69195;0.49842;0.32867;0.95694;0.52380;0.78624;0.12358;0.66135;0.34316;0.80625;0.67737;0.96386;0.30019;0.85607;0.48470;0.76993;0.78908;0.20340;0.44316;0.62345;0.94615;0.59683;0.64887;0.14256;0.64982;0.73483;0.83900;0.43285;0.12016;0.80736;0.59979;0.78151;0.84565;0.50662;0.14525;0.25578;0.53977;0.16112;0.11079;0.18067;0.25249;0.08780;0.61420;0.23068;0.80957;0.33922;0.61534;0.79823;0.10564;0.74981;0.43492;0.34229;0.85820;0.16333;0.80710;0.72960;0.25950;0.15108;0.33805;0.60806;0.41980;0.55698;0.06802;0.49613;0.66005;0.42456;0.25154;0.06966;0.27027;0.07873;0.57699;0.13695;0.62573;0.71019;0.66978;0.11141;0.26554;0.12472;0.02360;0.50723;0.86680;0.77863;0.69864;0.22808;0.08128;"; sCityPosY = "0.21680;0.49262;0.47379;0.03366;0.95850;0.26108;0.36078;0.16687;0.58984;0.20932;0.49682;0.94493;0.50458;0.89746;0.24439;0.95990;0.28906;0.03055;0.92744;0.71689;0.21813;0.07568;0.60055;0.66293;0.20385;0.96852;0.66466;0.14039;0.74157;0.90603;0.87935;0.44715;0.31846;0.93126;0.54192;0.13184;0.62611;0.33895;0.45007;0.41706;0.87412;0.35460;0.29903;0.70803;0.53285;0.02657;0.48000;0.58060;0.95142;0.04436;0.16000;0.25339;0.38372;0.01278;0.59422;0.48772;0.81543;0.00713;0.33732;0.15506;0.32922;0.28236;0.65535;0.60768;0.37482;0.10012;0.82823;0.32094;0.94585;0.04573;0.76357;0.00841;0.37577;0.69345;0.73069;0.58325;0.03015;0.86913;0.72857;0.29228;0.12884;0.63822;0.74591;0.16901;0.29289;0.23183;0.74820;0.63544;0.25577;0.83706;0.17741;0.04637;0.28592;0.89306;0.39231;0.11789;0.57774;0.47822;0.71527;0.01542;0.86198;0.06461;0.48748;0.73415;0.02895;0.72971;0.99151;0.41392;0.69157;0.29192;0.49233;0.60503;0.16591;0.39373;0.73049;0.88935;0.65639;0.20265;0.65402;0.88711;0.50801;0.88934;0.39289;0.77695;0.61025;0.16835;0.47867;0.17265;0.85663;0.52578;0.97553;0.17959;0.36908;0.77579;0.31904;0.70607;0.27972;0.32657;0.89866;0.75707;0.17239;0.61149;0.69880;0.29565;0.35053;0.14255;0.23654;0.95798;0.70438;0.62872;0.39667;0.85046;0.93020;0.34899;0.28054;0.33777;0.03149;0.10399;0.73341;0.28573;0.22106;0.41000;0.75042;0.06323;0.10176;0.47821;0.02675;0.17481;0.50570;0.78580;0.62986;0.23917;0.07284;0.39164;0.74280;0.89019;0.10565;0.42147;0.66818;0.31087;0.17665;0.26836;0.11775;0.16034;0.96696;0.40970;0.06972;0.25818;0.99203;0.94881;0.32719;0.69869;0.13919;0.28892;0.60486;0.57730;0.38887;0.98491;0.28882;0.13007;0.09140;0.85261;0.18864;0.30368;0.76061;0.91551;0.09149;0.52065;0.73436;0.03804;0.40936;0.12073;0.46099;0.30485;0.25090;0.00559;0.97469;0.50341;0.96899;0.34400;0.05959;0.81740;0.87370;0.38176;0.14762;0.94729;0.03514;0.35521;0.17366;0.24595;0.09497;0.76685;0.10974;0.23299;0.07736;0.80833;0.83649;0.28803;0.96379;0.31826;0.08958;0.66839;0.33356;0.62085;0.68365;0.93179;0.11834;0.84829;0.96891;0.30682;"; } // Position des villes CitiesPosX = new double[iNbCities]; CitiesPosY = new double[iNbCities]; StringTokenizer stPosX = new StringTokenizer(sCityPosX, ";"); for (i=0; i<iNbCities; i++) { CitiesPosX[i] = (Double.valueOf(stPosX.nextToken())).doubleValue(); } StringTokenizer stPosY = new StringTokenizer(sCityPosY, ";"); for (i=0; i<iNbCities; i++) { CitiesPosY[i] = (Double.valueOf(stPosY.nextToken())).doubleValue(); } // Parcours (trajet) entre les villes sParam = getParameter("Parcours"); Parcours = new int[iNbCities]; StringTokenizer stParcours = new StringTokenizer(sParam, "-"); try { for (i=0; i<iNbCities; i++) { Parcours[i] = (Integer.valueOf(stParcours.nextToken())).intValue(); } // si le parcours n'est pas complet } catch (NoSuchElementException e0) { for (; i<iNbCities; i++) { Parcours[i] = Parcours[i-1]; } } nbmode=1; sParam = getParameter("Parcours2"); try { bParcours2AAfficher = !(sParam.equals("")); if (bParcours2AAfficher) { nbmode=2; Parcours2 = new int[iNbCities]; StringTokenizer stParcours2 = new StringTokenizer(sParam, "-"); for (i=0; i<iNbCities; i++) { Parcours2[i] = (Integer.valueOf(stParcours2.nextToken())).intValue(); } } } catch (Exception e) { bParcours2AAfficher = false; } sParam = getParameter("Parcours3"); try { bParcours3AAfficher = !(sParam.equals("")); if (bParcours3AAfficher) { nbmode=3; Parcours3 = new int[iNbCities]; StringTokenizer stParcours3 = new StringTokenizer(sParam, "-"); for (i=0; i<iNbCities; i++) { Parcours3[i] = (Integer.valueOf(stParcours3.nextToken())).intValue(); } } } catch (Exception e) { bParcours3AAfficher = false; } CalculeDistance(); CalculeFenetre(); System.out.println("Fenetre : " + fMinParcours + " " + fMaxParcours + " " + fMinParcours + " " + fMaxParcours); DefFenetre(fMinParcours, fMinParcours, fMaxParcours, fMaxParcours); fXCentreEcran = (fMinParcours + fMaxParcours)/2; fYCentreEcran = fXCentreEcran; dernierXCentreEcran = fXCentreEcran; dernierYCentreEcran = fYCentreEcran; lfFacteurZoom = (fMaxParcours - fMinParcours)/2; dernierZoom = lfFacteurZoom; bZoom = false; } /*======================================================================== Fonction : Définition de la résolution la fenêtre d'affichage ==========================================================================*/ public void DefFenetre(double x0, double y0, double x1, double y1) { fXMinFen = x0; fXMaxFen = x1; fYMinFen = y0; fYMaxFen = y1; fPasX = (double)Math.abs(fXMinFen-fXMaxFen)/(double)iMaxX; fPasY = (double)Math.abs(fYMinFen-fYMaxFen)/(double)iMaxY; } /*======================================================================== Fonction : Dessine un "point" de 2x2 pixels ==========================================================================*/ public void TracePoint(Graphics g, double x, double y, int i) { int x0, y0, x1, y1; x0 = (int)((x-fXMinFen)/(fXMaxFen-fXMinFen)*iMaxX); y0 = (int)(iMaxY-(y-fYMinFen)/(fYMaxFen-fYMinFen)*iMaxY); g.fillRect(x0-1, y0-1, 2, 2); if (bShowCityNumber) { // TSPLIB if (iType == 1) { g.drawString(""+i+1, x0+2, y0-2); } else { // Alex g.drawString(""+i, x0+2, y0-2); } } } /*======================================================================== Fonction : Dessine une ligne entre deux points ==========================================================================*/ public void TraceLigne(Graphics g, double x0, double y0, double x, double y) { if ( (x0 != x) || (y0 != y) ) { g.drawLine( (int)((x0-fXMinFen)/(fXMaxFen-fXMinFen)*iMaxX),(int)(iMaxY-(y0-fYMinFen)/(fYMaxFen-fYMinFen)*iMaxY), (int)((x-fXMinFen)/(fXMaxFen-fXMinFen)*iMaxX),(int)(iMaxY-(y-fYMinFen)/(fYMaxFen-fYMinFen)*iMaxY)); } } /*======================================================================== Fonction : Affichage de l'applet ==========================================================================*/ public void paint(Graphics g) { int i; //g.setBackground(Color.white); // Tracé du contour de l'applet g.setColor(Color.black); g.drawRect(0, 0, iMaxX-1, iMaxY-1); // Tracé du parcours (trajet) entre les villes if ( (bParcours3AAfficher) && ((mode==0) || (mode==3)) ) { if (mode == 0) { g.setColor(Color.magenta); } else { g.setColor(Color.blue); } for (i=0; i<iNbCities - 1; i++) { TraceLigne(g, CitiesPosX[Parcours3[i]], CitiesPosY[Parcours3[i]], CitiesPosX[Parcours3[i+1]], CitiesPosY[Parcours3[i+1]] ); } TraceLigne(g, CitiesPosX[Parcours3[iNbCities-1]], CitiesPosY[Parcours3[iNbCities-1]], CitiesPosX[Parcours3[0]], CitiesPosY[Parcours3[0]] ); } if ( (bParcours2AAfficher) && ((mode==0) || (mode==2)) ) { if (mode == 0) { g.setColor(Color.green); } else { g.setColor(Color.blue); } for (i=0; i<iNbCities - 1; i++) { TraceLigne(g, CitiesPosX[Parcours2[i]], CitiesPosY[Parcours2[i]], CitiesPosX[Parcours2[i+1]], CitiesPosY[Parcours2[i+1]] ); } TraceLigne(g, CitiesPosX[Parcours2[iNbCities-1]], CitiesPosY[Parcours2[iNbCities-1]], CitiesPosX[Parcours2[0]], CitiesPosY[Parcours2[0]] ); } if ( (mode==0) || (mode==1) ) { g.setColor(Color.blue); for (i=0; i<iNbCities - 1; i++) { TraceLigne(g, CitiesPosX[Parcours[i]], CitiesPosY[Parcours[i]], CitiesPosX[Parcours[i+1]], CitiesPosY[Parcours[i+1]] ); } TraceLigne(g, CitiesPosX[Parcours[iNbCities-1]], CitiesPosY[Parcours[iNbCities-1]], CitiesPosX[Parcours[0]], CitiesPosY[Parcours[0]] ); } if (!bZoom) { // Tracé des villes g.setColor(Color.red); for (i=0; i<iNbCities; i++) { TracePoint(g, CitiesPosX[i], CitiesPosY[i], i); } // Distance totale g.setColor(Color.black); if ( (bParcours3AAfficher) && (mode==3) ) { g.drawString("d = " + distance3, 5, iMaxY - 10); } if ( (bParcours2AAfficher) && (mode==2) ) { g.drawString("d = " + distance2, 5, iMaxY - 10); } if ( (mode==0) || (mode==1) ) { g.drawString("d = " + distance, 5, iMaxY - 10); } } // tracé du "X" de zoom if (bZoom) { if (diff < 0) { g.setColor(Color.red); } TraceLigne(g, fXCentreEcran-diff/5, fYCentreEcran-diff/5, fXCentreEcran+diff/5, fYCentreEcran+diff/5); TraceLigne(g, fXCentreEcran+diff/5, fYCentreEcran-diff/5, fXCentreEcran-diff/5, fYCentreEcran+diff/5); // Debug //g.setColor(Color.black); //g.drawString("diff=" + diff + " diffX=" + diffX + " Z=" + lfFacteurZoom, 5, iMaxY - 10); } } /*======================================================================== Fonction : Calcul de la distance totale ==========================================================================*/ public void CalculeDistance() { distance = CalcDist(Parcours); if (bParcours2AAfficher) { distance2 = CalcDist(Parcours2); } if (bParcours3AAfficher) { distance3 = CalcDist(Parcours3); } } /*======================================================================== Fonction : Calcul de la distance totale ==========================================================================*/ public double CalcDist(int MonParcours[]) { int i; long l; d = 0; for (i=0; i<iNbCities-1; i++) { if (iType == 0) { d += Math.sqrt( (CitiesPosX[MonParcours[i]]-CitiesPosX[MonParcours[i+1]])*(CitiesPosX[MonParcours[i]]-CitiesPosX[MonParcours[i+1]]) + (CitiesPosY[MonParcours[i]]-CitiesPosY[MonParcours[i+1]])*(CitiesPosY[MonParcours[i]]-CitiesPosY[MonParcours[i+1]]) ); } else { d += (double) (int) (Math.sqrt( (CitiesPosX[MonParcours[i]]-CitiesPosX[MonParcours[i+1]])*(CitiesPosX[MonParcours[i]]-CitiesPosX[MonParcours[i+1]]) + (CitiesPosY[MonParcours[i]]-CitiesPosY[MonParcours[i+1]])*(CitiesPosY[MonParcours[i]]-CitiesPosY[MonParcours[i+1]]) ) +0.5); } } if (iType == 0) { d += Math.sqrt( (CitiesPosX[MonParcours[iNbCities-1]]-CitiesPosX[MonParcours[0]])*(CitiesPosX[MonParcours[iNbCities-1]]-CitiesPosX[MonParcours[0]]) + (CitiesPosY[MonParcours[iNbCities-1]]-CitiesPosY[MonParcours[0]])*(CitiesPosY[MonParcours[iNbCities-1]]-CitiesPosY[MonParcours[0]]) ); } else { d += (double) (int) (Math.sqrt( (CitiesPosX[MonParcours[iNbCities-1]]-CitiesPosX[MonParcours[0]])*(CitiesPosX[MonParcours[iNbCities-1]]-CitiesPosX[MonParcours[0]]) + (CitiesPosY[MonParcours[iNbCities-1]]-CitiesPosY[MonParcours[0]])*(CitiesPosY[MonParcours[iNbCities-1]]-CitiesPosY[MonParcours[0]]) ) +0.5); } //arrondi l = (long) (d * 10000); return (double)( (double)(l) / (double)10000 ); } /*======================================================================== Fonction : Calcul les bords de la fenêtre initiale par rapport à la position des points ==========================================================================*/ public void CalculeFenetre() { int i; fMinParcours = CitiesPosX[0]; fMaxParcours = CitiesPosX[0]; for (i=0; i<iNbCities-1; i++) { if (CitiesPosX[i] > fMaxParcours) { fMaxParcours = CitiesPosX[i]; } if (CitiesPosY[i] > fMaxParcours) { fMaxParcours = CitiesPosY[i]; } if (CitiesPosX[i] < fMinParcours) { fMinParcours = CitiesPosX[i]; } if (CitiesPosY[i] < fMinParcours) { fMinParcours = CitiesPosY[i]; } } fMinParcours -= (fMaxParcours - fMinParcours)/25; fMaxParcours += (fMaxParcours - fMinParcours)/25; } /*======================================================================== Fonction : ==========================================================================*/ public boolean mouseDown(Event event, int x, int y) { if (!bZoom) { iXClick = x; iYClick = y; } return false; } /*======================================================================== Fonction : ==========================================================================*/ public boolean mouseDrag(Event event, int x, int y) { // si clic droit bZoom = (event.modifiers == event.META_MASK); boolean bOk = true; diffX = ((double)(x-iXClick)/(double)(iMaxX)); diffY = ((double)(y-iYClick)/(double)(iMaxY)); if ( (Math.abs(x-iXClick) < iMaxX) ) { if (bZoom) { diff = diffX*dernierZoom*2; if ((dernierZoom - diff > 0.1*lfFacteurZoom) && (dernierZoom - diff <10*lfFacteurZoom)) { lfFacteurZoom = dernierZoom - diff; } else { bOk = false; } } else { fXCentreEcran = dernierXCentreEcran - diffX*(double)Math.abs(fXMinFen-fXMaxFen); fYCentreEcran = dernierYCentreEcran + diffY*(double)Math.abs(fYMinFen-fYMaxFen); } if (bOk) { DefFenetre(fXCentreEcran-lfFacteurZoom, fYCentreEcran-lfFacteurZoom, fXCentreEcran+lfFacteurZoom, fYCentreEcran+lfFacteurZoom ); repaint(); } } return false; } /*======================================================================== Fonction : ==========================================================================*/ public boolean mouseUp(Event evt, int x, int y) { mode++; if (mode > nbmode) { mode=0; } dernierZoom = lfFacteurZoom; bZoom = false; dernierXCentreEcran = fXCentreEcran; dernierYCentreEcran = fYCentreEcran; DefFenetre(fXCentreEcran-lfFacteurZoom, fYCentreEcran-lfFacteurZoom, fXCentreEcran+lfFacteurZoom, fYCentreEcran+lfFacteurZoom ); repaint(); return false; } /*======================================================================== Fonction : Info sur l'applet ==========================================================================*/ public String getAppletInfo() { return "DisplayTsp v 0.37 - Affichage d'un parcours pour le problème du voyageur du commerce - Alexandre Aupetit et Xavier Clarist, décembre 2003 - Logiciel libre sous licence GPL"; } /*======================================================================== === Fonction : Info sur les parametres de l'applet =========================================================================*/ public String[][] getParameterInfo() { String[][] aasArgs = { {"Problem", "String", "default = problème par défaut de 250 villes, custom = autres problèmes"}, {"CitiesPosX", "String", "Position en X des villes. Exemple : 0.21679;0.49261;... "}, {"CitiesPosX", "String", "Position en Y des villes. Exemple : 0.21679;0.49261;... "}, {"Parcours", "String", "liste des villes visitées"}, }; return aasArgs; } }