/******************************************
*
* Cedric Pradalier 2001
* mail : http://cedric.pradalier.free.fr/mail.html
*
*****************************************/
#include "output.h"
#include "lignes.h"
#include <string.h>
#include <stdlib.h>
#include "corresp.h"
/*****************************************************
Implementation des lignes.
******************************************************/
//#define DEBUG
/* Initialisation physique */
CLignes::CLignes(char * rep,char * name,int i)
{
mRep = (char *) malloc ((strlen(rep) + 1) * sizeof(char));
strcpy(mRep,rep);
mName = (char *) malloc ((strlen(name) + 1) * sizeof(char));
strcpy(mName,name);
mId = i;
tArrets[s_aller]=tArrets[s_retour]=NULL;
nArrets[s_aller]=nArrets[s_retour]=0;
DonneesInterpol[s_aller] = NULL;
DonneesInterpol[s_retour] = NULL;
}
/* On detruit tout */
CLignes::~CLignes()
{
free(mName);
free(mRep);
delete [] tArrets[s_aller];
delete [] tArrets[s_retour];
delete [] DonneesInterpol[s_aller];
delete [] DonneesInterpol[s_retour];
}
/* Lecture de toutes les donnees : Acces sequentiels a
tous les fichiers. Attention a la syntaxe */
int CLignes::Read(CBDArrets * Liste)
{
int s;
char temp[100]="horaires/\0";
char ext[] = "+-";
int n;
FILE * fp;
strcat(temp,mRep);
strcat(temp,"/arrets");
n = strlen(temp);
/* lecture de l'aller */
strcat(temp," ");
for(s=(int)s_aller;s<=(int)s_retour;s++)
{
temp[n] = ext[s];
if ((fp = fopen(temp,"r")) == NULL)
{
sprintf(outbuf,"impossible de lire %s\n",temp);FlushBuffer();
return 1;
}
else
{
fscanf(fp,"#arrets = %d \n",&nArrets[s]);
tArrets[s] = new (CArrets*)[nArrets[s]];
for (int i=0;i<nArrets[s];i++)
{
tArrets[s][i] = Liste->Find(tArrets[s][i]->ReadId(fp));
}
fclose(fp);
}
}
return 0;
}
/* Affichage standard : */
void CLignes::Print()
{
int s;
char * titres[2] = {"Aller","Retour"};
sprintf(outbuf,"nom : %s\n",mName);FlushBuffer();
sprintf(outbuf,"Id : %i\n",mId);FlushBuffer();
for(s=(int)s_aller;s<=(int)s_retour;s++)
{
sprintf(outbuf,"Arrets : %s\n",titres[s]);FlushBuffer();
for (int i=0;i<nArrets[s];i++)
tArrets[s][i]->Print();
sprintf(outbuf,"Horaires : %s\n",titres[s]);FlushBuffer();
horaires[s].Print();
}
}
/* Affichage minimum */
void CLignes::PrintMin()
{
int s;
char * titres[2] = {"Aller","Retour"};
sprintf(outbuf,"nom : %s\n",mName);FlushBuffer();
sprintf(outbuf,"Id : %i\n",mId);FlushBuffer();
for(s=(int)s_aller;s<=(int)s_retour;s++)
{
sprintf(outbuf,"Arrets : %s\n",titres[s]);FlushBuffer();
for (int i=0;i<nArrets[s];i++)
tArrets[s][i]->PrintMin();
}
}
/* Recherche du type d'horaire correspondant a une date D
Acces sequentiel au fichier calendrier. Les periodes
sont classees par priorite croissantes :
8 : Pas de bus ce jour la
6 : Date
4 : Periode
2 : Jour de la semaine ( toute l'annee )
0 : Defaut
Les date de validite du calendrier doivent etre correcte.
*/
TypeHoraire CLignes::FindTypeHoraire(CDate D)
{
char temp[127] = "horaires/\0";
strcat(temp,mRep);
strcat(temp,"/calendrier");
FILE * fp;
if ((fp = fopen(temp,"r")) == NULL)
{
sprintf(outbuf,"impossible de lire %s\n",temp);FlushBuffer();
return t_aucun;
}
Jours J = D.GetDayinWeek();
CDate D1,D2;
char ch;
TypeHoraire Lu,Trouve = t_aucun;
int Priorite_Trouve = -1;
int i,j,n;
/* Test de la periode de validite */
fscanf(fp,"debut validite = ");
D1.Read(fp);
fscanf(fp," fin validite = ");
D2.Read(fp);
if (!D.IsBetween(D1,D2))
{
sprintf(outbuf,"Les horaires pour %s ne sont plus valides\n",mName);FlushBuffer();
fclose(fp);
return t_aucun;
}
/* Test dans toutes les periodes */
for (i=0;i<5;i++)
{
/* Lecture : BLANC : n
Ou n correspond au nombre de lignes a lire ensuite pour
avoir toutes les donnees sur cette periode.
si n = 0 : periode par defaut
si n = -1 : Periode non utilisee
sinon, on lit */
fscanf(fp,"%s : %d \n",temp,&n);
Lu = TypeofS(temp);
if ((int)Lu == -1)
{
sprintf(outbuf,"Fichier calendrier pour %s invalide.\n",mName);FlushBuffer();
fclose(fp);
return t_aucun;
}
if (n<0)
continue;
else if ((n==0) && (Priorite_Trouve < 0))
{
Priorite_Trouve = 0;
Trouve = Lu;
}
else
/* Format des lignes :
D <date>
ou I <date_debut> <date_fin>
ou J <Jour de la semaine>
*/
for(j=0;j<n;j++)
{
fscanf(fp,"\t%c ",&ch);
switch (ch)
{
case 'D' : {
D1.Read(fp);
fscanf(fp," \n");
if ((Priorite_Trouve < 6) && (D1 == D))
{
Priorite_Trouve = (Lu!=t_aucun)?6:8;
Trouve = Lu;
}
break;
}
case 'J' : {
fscanf(fp,"%s \n",temp);
if ((Priorite_Trouve < 4) && (J == GetDayofS(temp)))
{
Priorite_Trouve = (Lu!=t_aucun)?4:8;
Trouve = Lu;
}
break;
}
case 'I' : {
D1.Read(fp); fscanf(fp," ");
D2.Read(fp); fscanf(fp," \n");
if ((Priorite_Trouve < 2) && (D.IsBetween(D1,D2)))
{
Priorite_Trouve = (Lu!=t_aucun)?2:8;
Trouve = Lu;
}
break;
}
}
}
}
fclose(fp);
return Trouve;
}
/* Lecture des horaires correspondant a un type d'horaire
Blanc, orange...
La lecture en elle meme est laissee a la charge de la table
d'horaire. Les donnees d'interpolation sont mises a jour
*/
void CLignes::LoadHoraires(TypeHoraire t,CBDArrets * liste)
{
char temp[127] = "horaires/\0";
int n;
if (t == t_aucun)
return;
strcat(temp,mRep);
strcat(temp,"/horaires");
n=strlen(temp);
strcat(temp,"+");
strcat(temp,GetExtension(t));
horaires[s_aller].Read(temp,liste);
temp[n]=0;
strcat(temp,"-");
strcat(temp,GetExtension(t));
horaires[s_retour].Read(temp,liste);
UpdateInterpol ();
}
// renvoie l'indice (prive) d'un arret sur la ligne
int CLignes::Indice(SensTrajet s,CArrets * arret)
{
int i=0;
if (tArrets[s] == NULL)
{
i += 1;
}
while ((i<nArrets[s]) && (arret != tArrets[s][i]))
i++;
if (i<nArrets[s])
return i;
else
return -1;
}
/* Test si un arret appartient a la ligne */
bool CLignes::IsKnown(CArrets * arret)
{
return (Indice(s_aller,arret) > -1)
|| (Indice(s_retour,arret) > -1);
}
/* Test si on peut aller de l'arret From a l'arret Dest
sans changement */
bool CLignes::IsAccessible(CArrets * From,CArrets * Dest)
{
int i;
if (!IsUnique(From))
return true; // D'un arret desservi dans les deux sens,
// on peut acceder a tout autre arret (c'est un choix)
bool FromTrouveAller = false;
bool FromTrouveRetour = false;
// On parcourt l'aller en esperant trouver From en premier
// sinon, il n'est pas accessible dans ce sens
for (i=0;i<nArrets[s_aller];i++)
{
if (tArrets[s_aller][i] == From)
FromTrouveAller = true;
if (tArrets[s_aller][i] == Dest)
if (FromTrouveAller)
return true;
else
break;
}
// Puis on repete dans l'autre sens. Ici, on peut sortir
// directement.
for (i=0;i<nArrets[s_retour];i++)
{
if (tArrets[s_retour][i] == From)
FromTrouveRetour = true;
if (tArrets[s_retour][i] == Dest)
return FromTrouveRetour;
}
return false;
}
// renvoie le sens du trajet pour aller de depart a arrivee
// renvoie nonsens si depart ou arrivee ne sont pas sur cette ligne
SensTrajet CLignes::FindDirection(CArrets * depart,CArrets * arrivee)
{
int i=0;
int s;
for (s=(int)s_aller;s<=(int)s_retour;s++)
{
for (i=0;i<nArrets[s];i++)
{
if (depart == tArrets[s][i])
return (SensTrajet)s;
if (arrivee == tArrets[s][i])
return (SensTrajet) (1-s);
}
}
return nonsens;
}
// Renvoie l'horaire de passage a l'arret 1
// Sachant qu'on veut etre a l'arret 2 avant
// l'horaire limite
// renvoie HNULL en cas de Pb
CHoraire CLignes::Passage(CArrets * depart,CArrets * arrivee,CHoraire & limite)
{
SensTrajet s;
int trajet;
int IndDepart,IndArrivee;
// sprintf(outbuf,"On entre dans le passage (%s) ...\n",mName);FlushBuffer();
if ((s=FindDirection(depart,arrivee)) == nonsens)
return HNULL; // impossible de trouver depart ou arrivee
// sprintf(outbuf,"Sens OK(%i) // cherchons le trajet...\n",s);FlushBuffer();
if (((IndDepart = Indice(s,depart)) == -1) || ((IndArrivee = Indice(s,arrivee)) == -1))
return HNULL;
// sprintf(outbuf,"les arrets sont coherents.\n");FlushBuffer();
if ((trajet = horaires[s].FindTrajet(IndArrivee,limite)) < 0)
return HNULL; // arret introuvable ou pas d'horaire possible
// sprintf(outbuf,"ce trajet (%i) est il possible ?\n",trajet);FlushBuffer();
if ((trajet = horaires[s].FindFirstTrajetValid(trajet,IndDepart,IndArrivee)) < 0)
return HNULL; // pas d'horaire possible
// sprintf(outbuf,"Ya pus k interpoler le depart (%i)...\n",trajet);FlushBuffer();
limite = horaires[s].Interpol(trajet,IndArrivee);
return horaires[s].Interpol(trajet,IndDepart);
// sprintf(outbuf,"Yaouuuuuu, ca a marche :)\n");FlushBuffer();
}
/* Mise a jour des donnees d'interpolation :
on a besoin pour chaque arret de savoir entre quelles arrets de
reference il se situe et sa position :
0 1 2 3 4 5 6
+------+-------+-------+-------+------+------+
Rf2 Arret A Rf3
Les donnees pour A sont
Reference : 2
NumeroArretInter = 3
NbArretInter = 6
On parcours tous les arrets sequentiellement
en mettant ces donnees a jour
*/
void CLignes::UpdateInterpol()
{
int last, Nb, i , j;
InterPol temp = {0,1,0};
int s;
for (s=(int)s_aller;s<=(int)s_retour;s++)
{
last = -1;Nb = 0;
DonneesInterpol[s] = new InterPol[nArrets[s]];
for (i=0;i<nArrets[s];i++)
{
temp.NumArretInter = 0xFF;
DonneesInterpol[s][i] = temp;
}
for (i=0;i<horaires[s].NbArretRef;i++)
{
temp.NumArretInter = 0;
DonneesInterpol[s][Indice((SensTrajet)s,horaires[s].tArretRef[i])] = temp;
}
// sprintf(outbuf,"initialisation aller : \n");FlushBuffer();
for (i=0;i<nArrets[s];i++,Nb++)
if (DonneesInterpol[s][i].NumArretInter == 0)
{
for (j=0;j<Nb;j++)
{
temp.NumArretInter = j;
temp.NumArretRef = last;
temp.NbArretsInter = Nb;
DonneesInterpol[s][i-Nb+j] = temp;
}
Nb = 0;
last ++;
}
/* Cas particulier pour le dernier arret */
temp.NumArretInter = 0;
temp.NumArretRef = horaires[s].NbArretRef - 1;
temp.NbArretsInter = 1;
DonneesInterpol[s][nArrets[s]-1] = temp;
/* Repercution des modif sur La table des horaires
Son pointeur pointe sur le meme objet que celui de
la ligne */
horaires[s].SetInterpol(DonneesInterpol[s]);
}
}
/* Lignes accessibles a partir d'un arret
Les correspondances possibles sont inserees dans l'ensemble
E. Les lignes accessibles a partir de l'endroit ou on est
ne sont pas prise en compte. En effet, si on veut prendre une
autre ligne par cet arret, on ne passera pas par celle-ci.
Parcours encore une fois sequentiel.
*/
void CLignes::LignesAccessibles(CEnsemble * E,CBDLignes * pBD,CCorresp * OuOnEst)
{
CLignes * temp;
CEnsemble * lignes = new CEnsemble();
lignes->ajoute((CObjet*)this);
int i,j,s;
int Indic[2];
int borneInf = 0;// L'aller
int borneSup = 1;// Le retour
// sprintf(outbuf,"Recherche des lignes accessibles\n");FlushBuffer();
if ((Indic[s_aller] = Indice(s_aller,OuOnEst->arret)) == -1)
{
// On ne cherche pas sur l'aller, mais de toute facon, l'arret doit etre sur la ligne
borneInf = 1;
}
if ((Indic[s_retour] = Indice(s_retour,OuOnEst->arret)) == -1)
{
// On ne cherche pas sur le retour, mais de toute facon, l'arret doit etre sur la ligne
borneSup = 0;
}
for (s = borneInf ; s <= borneSup ; s++ )
for (i = Indic[s] ; i < nArrets[s] ; i++)
for (j=0;j<tArrets[s][i]->mNbLignesPresentes;j++)
{
if (tArrets[s][i]->mId != OuOnEst->arret->mId)
{
int l=tArrets[s][i]->tLignesPresentes[j];
// sprintf(outbuf," %i",l);FlushBuffer();
temp = pBD->Find(l);
if ((temp != NULL) &&
(lignes->contains(temp) == -1))
{
// sprintf(outbuf,"OK");FlushBuffer();
CCorresp * nouveau = new CCorresp(tArrets[s][i],temp,(SensTrajet)s);
nouveau->precedent = OuOnEst;
E->ajoute((CObjet *)nouveau);
lignes->ajoute((CObjet *)temp);
}
}
}
delete lignes;
// sprintf(outbuf,"\n");FlushBuffer();
}
/* Determine l'ensemble des arrets en sens unique
La liste des arrets dans les deux sens doit avoir ete
lue auparavent */
void CLignes::FindSensUnique()
{
int i_go,i_back;
i_go = 0;
i_back = nArrets[s_retour]-1;
#ifdef DEBUG
sprintf(outbuf,"Ligne étudiée : %s \n",mName);FlushBuffer();
tArrets[s_aller][i_go]->Print();
tArrets[s_retour][i_back]->Print();
#endif
while ((i_back >= 0) && (i_go < nArrets[s_aller] ))
{
if (tArrets[s_aller][i_go] == tArrets[s_retour][i_back])
{
i_go += 1;
i_back -= 1;
}
else
{
#ifdef DEBUG
sprintf(outbuf,"...?????./....???.\n");FlushBuffer();
tArrets[s_aller][i_go]->Print();
tArrets[s_retour][i_back]->Print();
#endif
if (Indice(s_aller,tArrets[s_retour][i_back]) == -1)
if (Indice(s_retour,tArrets[s_aller][i_go]) == -1)
{
ArretsUniques.ajoute((CObjet *) tArrets[s_aller][i_go]);
ArretsUniques.ajoute((CObjet *) tArrets[s_retour][i_back]);
i_go += 1;
i_back -= 1;
}
else
{
ArretsUniques.ajoute((CObjet *) tArrets[s_retour][i_back]);
i_back -= 1;
}
else
if (Indice(s_retour,tArrets[s_aller][i_go]) == -1)
{
ArretsUniques.ajoute((CObjet *) tArrets[s_aller][i_go]);
i_go += 1;
}
else
{
sprintf(outbuf,"Recherche des arrets uniques : situation absurde \n");FlushBuffer();
exit(0);
}
}
}
#ifdef DEBUG
if (ArretsUniques.GetNbElem() == 0)
{
sprintf(outbuf,"Aucun arrets a sens unique\n");FlushBuffer();
}
else
{
sprintf(outbuf,"Arrets a sens uniques...\n");FlushBuffer();
ArretsUniques.Print();
sprintf(outbuf,"\n");FlushBuffer();
}
#endif
}
/* Test si un arret n'est desservi que dans un seul sens
par cette ligne -- Utilisation de l'ensemble des arrets
en sens unique */
bool CLignes::IsUnique(CArrets * arret)
{
return (ArretsUniques.contains(arret) != -1);
}