Olivia_v2017/Olivia/olv_reco_thr.cpp

2064 lines
55 KiB
C++

#include "stdafx.h"
#ifdef OLIVIA_COMPILA
//olivia
#include "olv_reco_thr.h"
#include "olv_thr.h"
#include "olv_limp.h"
#include "olv.h"
#include "olv_reco.h"
#include "olv_geom.h"
#include "olv_csv.h"
#include "olv_sens_ws.h"
#include "math.h"
#include <iostream>
#include <sstream>
#include <string>
//utiles
#include "b_file.h"
#include "Fdbf.h"
#include "ManagerDbfGdataTable.h"
using namespace std;
/**
* @file olv_limp_thr.h
* Archivo de implementaciones del thread de control de la utilidad de recogida de residuos del programa Olivia.
*/
Colv_reco_thr::Colv_reco_thr(Colv_reco *olv_reco) : Colv_limp_thr(olv_reco)
{
this->olv_reco = olv_reco;
}
Colv_reco_thr::~Colv_reco_thr(void)
{
//destruye los subthreads
if(subthrs)
{
for(int i=0;i<n_subthr;i++)
{
if(subthrs[i])
delete subthrs[i];
}
free(subthrs);
subthrs=NULL;
}
if(olv_limp->tramos)
delete [] olv_limp->tramos;
}
//*************************************************************************************
void Colv_reco_thr::inicia_th()
{
inicia(OLV_MILIS_COLA,&cola_proc,-1,"reco_thr");
olvlog(LOG_TODO,"olv_limp_t","Thread de recogida reco_thr arrancado");
borra_temp_files();
pirate=FALSE;
}
//*************************************************************************************
/**
* Cola de procesos en la que itera el thr cuando es recogida. Override de limpieza, así que se implementan\n
* solo los eventos que tienen sentido en recogida y son diferentes que en limpieza
*/
void Colv_reco_thr::cola_proc(int evento, OlvAsync_cola<Param_olv_limp_thr> *clase,Param_olv_limp_thr *e)
{
BOOL bien=TRUE;
BOOL hecho=FALSE;
Colv_reco_thr *this_i=static_cast<Colv_reco_thr *>(clase);
switch (evento)
{
case OLV_LIMP_EV_RELL_DAT:
{
hecho=TRUE;
bien=this_i->rellena_datos();
if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
{
if(this_i->olv_reco->info_sens.url[0]==0)
this_i->encola(OLV_LIMP_EV_UNE_AMB_NW,NULL,FALSE);
else
this_i->encola(OLV_RECO_EV_SENS,NULL,FALSE);
}
break;
}
case OLV_RECO_EV_SENS:
{
//esta tarea lanza varios subthreads para realizar las peticiones de carga a los
//sensores(les encola la tarea pide_info_sensores_sub),
//y estos cuando acaban le encolan al padre (el que los ha lanzado)
//la tarea de dist_conj_fin
hecho=TRUE;
bien=this_i->pide_info_sens();
break;
}
case OLV_RECO_EV_SENS_SUB:
{
//aquí entran los subthreads para hacer los cálculos de ángulos, cuando acaban
//encolan al padre la tarea de fin
int ithr;
hecho=TRUE;
if(e!=NULL)
ithr=e->id_e;
this_i->pide_info_sens_sub(ithr);
break;
}
case OLV_RECO_EV_SENS_FIN:
{
//aquí entra el padre cuando van acabando los subthreads
//si han terminado todos encola la siguiente tarea
int i;
int nno;
hecho=TRUE;
this_i->n_subthr_fin++;
nno=0;
if(this_i->n_subthr_fin==this_i->n_subthr)
{
this_i->n_subthr_fin=0;
for(i=0;i<this_i->n_subthr;i++)
{
if(this_i->subthrs[i]->prog_subthr<0)
break;
nno+=(int)this_i->subthrs[i]->prog_subthr;
}
if(i<this_i->n_subthr)
{
bien=FALSE;
this_i->pon_mi_msg("Errores en la conexión con la base de datos de los sensores");
break;
}
bien=this_i->pide_info_sens_fin(nno);
if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
this_i->encola(OLV_LIMP_EV_UNE_AMB_NW,NULL,FALSE);
}
break;
}
}
if(!bien)
{
this_i->pon_mi_progre(OLV_TAREA_FIN_NOK,0);
}
if(!hecho)
Colv_limp_thr::cola_proc(evento, clase,e);
}
//*************************************************************************************
/**
* Rellena la información asociada de la red navegable y los datos de limpieza
*/
BOOL Colv_reco_thr::rellena_datos()
{
int icampu,icampkg,ia,uds_,icampcap,icampid,icampoid, capa_, idd;
char nfile[MAX_PATH];
Cb_file f;
Fdbf dbf;
char *uds, *kg, *capa, *id;
double kg_,auxi;
BOOL ret=TRUE;
olvlog(LOG_TODO,"olv_limp_t","Rellenando matriz de info asociada a ámbitos");
pon_mi_progre(OLV_TAREA_IMP, (int) (OliviaDef::GeneralDef::ProgrMax*2/3));
uds=kg=capa=id=0;
//lee dbf del shp
strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
//cambiaext(nfile,".shp",".dbf");
strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");
if(!f.abre(nfile,1) || !dbf.lee(&f))
{
pon_mi_msg("Error al abrir %s",nfile);
ret=FALSE;
goto fin;
}
//busca el campo de unidades
icampu=dbf.findCol(olv_reco->camps_r.campo_uds);
if(icampu==-1)
{
sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->camps_r.campo_uds,nfile);
ret=FALSE;
goto fin;
}
icampoid=dbf.findCol(OLV_NOMB_OID);
icampkg=icampcap=icampid=-1;
//busca el campo de kgrec, si es el caso
//si es 0 los kg por defecto, se lee el campo de kg, si es negativo, se lee el campo de capacidad porque o bien están
//llenos o bien se lee la info de los sensores, pero tiene densidad
if(olv_reco->kg_reco_def==0)
{
icampkg=dbf.findCol(olv_reco->camps_r.campo_kgcont);
if(icampkg==-1)
{
sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->camps_r.campo_kgcont,nfile);
ret=FALSE;
goto fin;
}
}
else if(olv_reco->kg_reco_def<=0)//busca el campo de capacidad, si es el caso
{
icampcap=dbf.findCol(olv_reco->camps_r.campo_capa);
if(icampcap==-1)
{
sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->camps_r.campo_capa,nfile);
ret=FALSE;
goto fin;
}
if(olv_reco->info_sens.camps.id[0])//es el caso de los sensores
{
icampid=dbf.findCol(olv_reco->info_sens.camps.id);
if(icampid==-1)
{
sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->info_sens.camps.id,nfile);
ret=FALSE;
goto fin;
}
}
}
idd =dbf.leeNexRow();
ia=0;
while(idd == 1)
{
///////////////////////////////
uds_=1;
uds_=dbf.getI(icampu);
if(uds_<0 || uds_>50)
{
uds_=1;//pone por def
olvlog(LOG_TODO,"olv_limp_t","Cuidado, info asociada %ld, puesto unidades por defecto a 1",ia+1);
}
olv_limp->iaso[ia].inf_r.uds=uds_;
///////////////////////////////
if(icampkg>-1)
{
kg_=dbf.getI(icampkg);
/*//por si viene con notación científica
stringstream ss(kg);
ss >> kg_;
if (ss.fail()) {kg_=0;}
/////////////////////////////////
//kg_=atof(dd);*/
if(kg_<0 || kg_>10000)
{
kg_=50;//pone por def
olvlog(LOG_TODO,"olv_limp_t","Cuidado, info asociada %ld, puesto kg por defecto a 50",ia+1);
}
uds_=1; //pone las uds a 1 para no multiplicar: en caso de que venga el campo de carga ya está multiplicado
}
else if(icampcap>-1)
{
capa_=dbf.getI(icampcap);
if(capa_<0 || capa_>100000)
{
capa_=3000;//pone por def
olvlog(LOG_TODO,"olv_limp_t","Cuidado, info asociada %ld, puesto capacidad por defecto a 3000 l",ia+1);
}
kg_=capa_*olv_reco->dens_frac/1000; //en kg /1000 para pasar de m3 a l
}
else
kg_=olv_reco->kg_reco_def;
olv_limp->iaso[ia].inf_r.kg=kg_*uds_;//pone la carga total como la carga por el número de contenedores
///////////////////////////////
if(icampid>=0)
{
olv_limp->iaso[ia].inf_r.id = (char*)malloc(dbf.getSize(icampid)+1);
if(!olv_limp->iaso[ia].inf_r.id)
break;
olv_limp->iaso[ia].inf_r.id[0]=0;
if(dbf.getType(icampid)==DBF_TYPE_DATA_STR)
{
strcpy(olv_limp->iaso[ia].inf_r.id,dbf.getStr(icampid));
}
else
{
auxi=dbf.getD(icampid);
if(auxi==(double)(int)auxi)
{
sprintf(olv_limp->iaso[ia].inf_r.id,"%ld",(int)auxi);
}
else
{
sprintf(olv_limp->iaso[ia].inf_r.id,"%lf",auxi);
}
}
}
if(icampoid>=0)
olv_limp->iaso[ia].oid = dbf.getI(icampoid);
//olvlog(LOG_TODO,"olv_limp_t","Rellena %0d %3.1f %ld %04d",ia, kg_,uds_,olv_limp->iaso[ia].oid);
///////////////////////////////
//avisa de progreso
if((ia%100==0) || (ia==(olv_limp->n_amb-1)))
{
pon_mi_progre(OLV_TAREA_IMP, (int) (OliviaDef::GeneralDef::ProgrMax*
((1.0*(ia+1)/olv_limp->n_amb)/3)+2/3));
olvlog(LOG_TODO,"olv_limp_t","Rellenando info asociada a ámbitos, %ld de %ld",
ia+1,olv_limp->n_amb);
}
ia++;
idd =dbf.leeNexRow();
}
if(ia<olv_limp->n_amb)
{
sprintf_s(err_str,OLV_MAX_ERR,"Error al leer información asociada %ld en\n%s",ia,nfile);
ret=FALSE;
goto fin;
}
olvlog(LOG_TODO,"olv_limp_t","Finaliza Matriz de info asociada a ámbitos");
fin:
if(!ret)
olvlog(LOG_TODO,"olv_limp_t","Fallos en Matriz de info asociada a ámbitos");
olvlog(LOG_TODO,"olv_limp_t","Giro límite %lf",olv_limp->ang_lim);
return ret;
}
//*************************************************************************************
/**
* Para la conexión a la lectura de sensores
*/
BOOL Colv_reco_thr::pide_info_sens()
{
olvlog(LOG_TODO,"olv_limp_t","Leyendo info de los sensores");
pon_mi_progre(OLV_TAREA_SENS, 0);
//Inicia el array donde se guarda la info de carga
olv_reco->info_carg = (int *)malloc(olv_limp->n_amb*sizeof(int));
if(!olv_reco->info_carg)
{
sprintf_s(err_str,OLV_MAX_ERR,"Error, sin memoria para info de carga");
return FALSE;
}
//lanza los threads
lanza_subthrs(OLV_RECO_EV_SENS_SUB);
return TRUE;
}
//*************************************************************************************
/**
* Rellena los valores de los sensores de cada contenedor
* El thread entra aquí cuando los subthreads que realizan la tarea realmente han finalizado
*/
BOOL Colv_reco_thr::pide_info_sens_fin(int nno)
{
class AddColPorc : public IAddColDbf
{
public:
Colv_reco *olv_reco;
AddColPorc(Colv_reco *rr)
{
this->olv_reco=rr;
}
virtual void setData(int i, void *data)
{
if(data)
{
memcpy(data,(void*)&olv_reco->info_carg[i],sizeof(int));
}
};
};
AddColPorc dataDbf(olv_reco);
ManagerDbfGdataTable dbfmgr;
char path_dbf[MAX_PATH];
////////////////
//para los threads
para_subthrs();
//guarda la info al shp
strcpy_s(path_dbf,MAX_PATH,olv_limp->olv->paths.path_data);
//cambiaext(path_dbf,".shp",".dbf");
strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");
if(!dbfmgr.AddCol(path_dbf,"PORC_RECO",GdataTable::Tint,&dataDbf))
//if(!olv_limp->olv->olv_sh->add_col_dbf(path_dbf,olv_limp->n_amb,TIPO_IA_INT,(char*)olv_reco->info_carg,"PORC_RECO",err_str,OLV_MAX_ERR))
{
free(olv_reco->info_carg);
olv_reco->info_carg=NULL;
return FALSE;
}
olvlog(LOG_TODO,"olv_limp_t","FIN %ld peticiones de carga a sensores",
olv_limp->n_amb);
free(olv_reco->info_carg);
olv_reco->info_carg=NULL;
return TRUE;
}
//*************************************************************************************
/**
* Rellena los valores de los sensores, es la parte de cálculos que
* realizan los subthreads. 'ithr' indica qué thread es, para calcular qué ámbitos le tocan.
*/
void Colv_reco_thr::pide_info_sens_sub(int ithr)
{
int na_ini,na_fin,na_desp,na,nno;
int KK, seg;
Param_olv_limp_thr pp;
Colv_sens_ws sens;
double carg;
BOOL mal=FALSE;
const int SZ_CAMP =32;
const int SZ_SENTEN =1024;
char nfile[MAX_PATH];
strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
//cambiaext(nfile,".shp",".dbf");
strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");
////////////////
pp.id_e=OLV_TAREA_SENS;//manda de parámetro la tarea de la que es el progreso
KK=olv_limp->tipo_ambit;
na_desp = (int)ceil(1.0*(olv_limp->n_amb)/n_subthr);
na_ini=ithr*na_desp;
na_fin = min((ithr+1)*na_desp,olv_limp->n_amb);
nno=0;
////////////////
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Ambs %04d a %04d", ithr,na_ini, na_fin);
seg = GetTickCount();
/////////////////////////////////////
//Conecta con el servicio
sens.inicia(&olv_reco->info_sens);
/////////////////////////////////////
/////////////////////////////////////
//Bucle por cada ámbito de los que le tocan a este thread para pedir su carga
/////////////////////////////////////
for(na=na_ini;na<na_fin && !pirate; na++)
{
carg=0;
if(!olv_limp->iaso[na].inf_r.id || strlen(olv_limp->iaso[na].inf_r.id)==0)
{
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en la petición de carga de contenedor %ld, no hay ID",
ithr,na);
carg=100;
olv_reco->info_carg[na]=(int) carg;
continue;
}
/////////////////////////////////////
//Tiene el id en info2
carg = sens.dame_porc_cont_i(olv_limp->iaso[na].inf_r.id);
if(carg==0)
{
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en la petición de carga de contenedor %s: %s",ithr,
olv_limp->iaso[na].inf_r.id,sens.err_str);
carg=100;
}
olv_reco->info_carg[na]=(int) carg;
/////////////////////////////////////
//Pone la carga recibida
if(carg>=olv_reco->info_sens.porc_lim)//Si la carga supera el valor límite, la pone
olv_limp->iaso[na].inf_r.kg *= carg/100; //info1 contiene antes los kg del contenedor si estuviera lleno
else
{
olv_limp->iaso[na].flgs |= OLV_LIMP_FLG_AMB_NO; //lo marca para no recogerlo
nno++;
}
//avisa de progreso
if(((na-na_ini)%50==0) || ((na-na_ini)==(na_desp-1)))
{
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Pidiendo info de carga a sensores %ld de %ld", ithr,
(na-na_ini+1),na_desp);
//avisa de progreso
prog_subthr=(1.0*(na-na_ini+1)/na_desp);
thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
}
}
if(mal)
{
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error al pedir info de carga a sensores");
prog_subthr=-1;//para avisar al padre de que ha habido un error
}
else
{
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin peticiones de carga a sensores, %.3f seg", ithr, 1.0*(GetTickCount()-seg)/1000);
prog_subthr=nno;
}
thr_padre->encola(OLV_RECO_EV_SENS_FIN,NULL,FALSE);
/////////////////////////////////////
}
//*************************************************************************************
/**
* Añade a la red de conjunciones en qué conjunción está la planta y la instalación
*/
BOOL Colv_reco_thr::pon_nodos_planta(double pt[3])
{
double pt_[3];
memcpy(pt_,pt,3*sizeof(double));
if(!Colv_limp_thr::pon_nodos_planta(pt))//es la instalación olv_limp->coor_instal
return FALSE;
if(Colv_geom::pto_equals(pt_, olv_reco->coor_plant))
{
memcpy(olv_reco->coor_plant,pt,3*sizeof(double));
}
else
{
if(!Colv_limp_thr::pon_nodos_planta(olv_reco->coor_plant))
return FALSE;
}
return TRUE;
}
//*************************************************************************************
/**
* Apunta en qué nodos está la planta y la instalación
*/
BOOL Colv_reco_thr::busca_conjs_planta(double pt[3], int *nod)
{
double pt_[3];
memcpy(pt_,pt,3*sizeof(double));
if(!Colv_limp_thr::busca_conjs_planta(pt,nod))//es la instalación olv_limp->coor_instal, olv_limp->nod_instal
return FALSE;
if(Colv_geom::pto_equals(pt_, olv_reco->coor_plant))
{
olv_reco->nod_plant=*nod;
}
else
{
if(!Colv_limp_thr::busca_conjs_planta(olv_reco->coor_plant,&olv_reco->nod_plant))
return FALSE;
}
return TRUE;
}
//*************************************************************************************
double Colv_reco_thr::dame_cost_jornada()
{
return olv_limp->t_conv-olv_reco->t_sal*2-olv_limp->t_desc;
}
//*************************************************************************************
/**
* Calcula el coste de los ámbitos a la planta e instalación
*/
BOOL Colv_reco_thr::calcula_cost_plant()
{
int ic,ia,ka,nais, KK, ref_ia;
Djkt_nodo *costes_nodos;
BOOL mal=FALSE;
//Inicia el array de orden /secuencia
olv_reco->ord_sec_plan=(Secu_amb*)malloc(sizeof(Secu_amb)*2);
if(!olv_reco->ord_sec_plan)
{
pon_mi_msg("Error, sin memoria para matriz de orden y secuencia");
return FALSE;
}
memset(olv_reco->ord_sec_plan,0,sizeof(Secu_amb)*2);
olvlog(LOG_TODO,"olv_limp_t","Calculando coste a planta e instalación");
costes_nodos=NULL;
if(olv_reco->nod_plant==olv_reco->nod_instal)
KK=1;
else
KK=2;
for(int k=0;k<KK;k++)
{
if(k==OLV_PLANT)//plant
ic=olv_reco->nod_plant;
else if(k==OLV_INSTAL)//instal
ic=olv_reco->nod_instal;
if(!Colv_geom::dijkstra_ang_inv_ok(olv_limp->cost_conj, olv_limp->ang_conj, olv_limp->conjs.n,
ic, &costes_nodos, &visto_ang))
{
mal=TRUE;
break;
}
olv_reco->ord_sec_plan[k].ctnod[0]=costes_nodos;
olv_reco->ord_sec_plan[k].ctnod[1]=NULL;
costes_nodos=NULL;
//revisa si está aislado de algún ámbito
nais=0;
for(ia=0;ia<olv_limp->n_amb;ia++)
{
ref_ia=olv_limp->carto.get(ia).entity()->ref;
if(olv_limp->iaso[ref_ia].flgs & OLV_LIMP_FLG_AMB_NO)
continue;
for(ka=0;ka<olv_limp->tipo_ambit;ka++)
{
if(olv_reco->ord_sec_plan[k].ctnod[0][olv_limp->iaso[ref_ia].inod[ka]].dis>=MAYUSCULO)
{
nais++;
}
}
}
if(nais)
{
mal=TRUE;
break;
}
}
if(mal)
{
pon_mi_msg("Error al calcular costes de ámbitos a instalación");
return FALSE;
}
if(KK==1)
{
olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0]=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0];
olv_reco->ord_sec_plan[OLV_PLANT].ctnod[1]=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[1];
}
////////////////////
//inicializa array
olv_reco->ptos_vaci=(short*)malloc(olv_limp->n_amb*sizeof(short));
if(!olv_reco->ptos_vaci)
return FALSE;
memset(olv_reco->ptos_vaci,0,olv_limp->n_amb*sizeof(short));
return TRUE;
}
//*************************************************************************************
/**
* Calcula el coste de desplazamiento de ir de ir por todos los ambitos sec desde ini hasta fin
*/
double Colv_reco_thr::dame_coste( Secu_amb * sec, int ini, int fin, Info_sec *s, BOOL ind_abs)
{
double d=0;
int ind_cost, ind_cost1;
int fin_old=fin;
int id_ambf, ref_ambf;
int id_ambf1;
double capac_v=olv_reco->kg_max, cap_act=0,cap_h, cap_t;
int nv_p, i, sel;//numero de veces por ir a planta
double coste;
double cap_g, dd;
cap_t=cap_act;
while(ini<fin)
{
id_ambf=s->iamb[sec[fin].iamb];
id_ambf1=s->iamb[sec[fin-1].iamb];
ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
if (ind_abs)
ind_cost=id_ambf;
else
ind_cost=sec[fin].iamb;
cap_t+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma a la carga la basura del ambito
d+=olv_limp->cost_amb[id_ambf][id_ambf];//suma el coste del ambito
d+=olv_limp->arch_dj.dame_dis(id_ambf1, 0, id_ambf,sec[fin].entrada);
fin--;
}
if (ind_abs)
ind_cost=s->iamb[sec[ini].iamb];
else
ind_cost=sec[ini].iamb;
id_ambf=s->iamb[sec[ini].iamb];
d+=olv_reco->cost_amb[id_ambf][id_ambf];//suma el coste de hacer el primer ambito
if(ini==0)//si ini es 0 falta sumar el coste de la planta a el primer ambito
{
d+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal, 0, s->iamb[sec[ini].iamb],0);
d+=olv_reco->t_sal;
}
cap_t+=olv_limp->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inf_r.kg;//suma a la carga total la basura del primer ambito
nv_p=(int)(cap_t/capac_v +1);//numero de veces que se tendra que ir a planta
cap_h=nv_p*capac_v-cap_t;//carga con la que se puede jugar (holgura) capacidad desaprovechada
if(cap_h>=capac_v)
{
cap_h-=capac_v;
nv_p--;
}
cap_t+=olv_reco->iaso[olv_limp->carto.get(ind_cost).entity()->ref].inf_r.kg;
//suma coste de ir a planta
if (ind_abs)
ind_cost=s->iamb[sec[fin_old].iamb];
else
ind_cost=sec[fin_old].iamb;
id_ambf=s->iamb[sec[fin_old].iamb];//id del ultimo ambito
nv_p--;//se descuenta uno porque se tiene que terminar en planta
d+=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inod[0]].dis;//suma el coste de ir del ultimo ambito a la planta
d+=olv_reco->t_descarg;//suma el coste de descargar
d+=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0][olv_reco->nod_plant].dis;//suma el coste de ir de planta a instalacion
d+=olv_reco->t_sal;//suma el coste de la llegada
int iold=-1;
BOOL errores=FALSE;
double cos_tray=d;
int veces_plan=nv_p;
BOOL salir=FALSE;
double cap_ult_cont;
while (!salir)
{
salir=TRUE;
cap_h=(1+veces_plan)*capac_v-cap_t;
nv_p=veces_plan;
coste=MAYUSCULO;
cap_g=0;
sel=-1;
d=cos_tray;
cap_act=0;
int isel_old=-1;
double cap_old;
i=ini;
while(nv_p>0 && i<=fin_old)
{
if (ind_abs)
ind_cost=s->iamb[sec[i].iamb];
else
ind_cost=sec[i].iamb;
id_ambf=s->iamb[sec[i].iamb];//id del ambito iesimo de la secuen
ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
cap_old=cap_act;
cap_act+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma capacidad del ambito de la secuencia iesima
cap_ult_cont=olv_reco->iaso[ref_ambf].inf_r.kg;
i++;
if(i>fin_old)
{
if(cap_act<capac_v)
break;
}
id_ambf1=s->iamb[sec[i].iamb];//id del ambito iesimo+1 de la secuen
if (ind_abs)
ind_cost1=s->iamb[sec[i].iamb];
else
ind_cost1=sec[i].iamb;
if((capac_v-cap_act)>cap_h)
{
//calcula si el siguiente entra
if((cap_act+olv_reco->iaso[olv_limp->carto.get(id_ambf1).entity()->ref].inf_r.kg)>capac_v)
{
nv_p++;
cap_h=cap_h+capac_v;
}
else
continue;
}
if(cap_act-capac_v<=0)
{
//prueba candidato
//calcula el coste de ir a planta desde el i-1 y de planta a el i y se le resta el coste de ir del i-1 al i
dd=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[ref_ambf].inod[0]].dis;//coste del i-1 a planta
dd+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_plan,0,id_ambf1, 0);
dd-=olv_limp->arch_dj.dame_dis(id_ambf,0,id_ambf1, 0);
dd+=olv_reco->t_descarg;//suma el coste de descargar
if(dd>=MAYUSCULO)
errores=TRUE;//existen errores
if(coste>dd)
{
sel=i;
coste=dd;
cap_g=capac_v-cap_act;
}
}
else
{
//pone candidato
//suma coste de ir a la planta y el de volver de ella
if(coste>=MAYUSCULO)
{
if(errores)
olvlog(LOG_TODO,"olv_limp_t","No conseguido candidato para ir a descargar");//algo va mal
//pone una vuelta mas a planta en el i-1;
salir=FALSE;
veces_plan++;
if(cap_ult_cont>capac_v)
{
olvlog(LOG_TODO,"olv_limp_t","Capacidad de contenedor %ld mas grande que la del vehiculo ", i);//algo va mal
return MAYUSCULO;
}
break;
//calcula coste
}
cap_act=0;
cap_h-=cap_g;
iold=i;
isel_old=sel;
i=sel;
d+=coste;
cap_g=0;
coste=MAYUSCULO;
sel=-1;
nv_p--;
}
}
}
return d;
}
//*************************************************************************************
/**
* Rellena los tiempos de desplazamiento
*/
void Colv_reco_thr::pon_t_desp(Info_sec *s, Secu_amb *sec)
{
if((olv_limp->nod_instal>=0) && (s->namb>1))
{
s->t_despl[0]=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0 ,s->iamb[sec[0].iamb],sec[0].entrada);
s->t_despl[1]=olv_limp->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->nod_instal].dis;
}
}
//*************************************************************************************
/**
* Calcula el coste de desplazamiento de ir por todos los ambitos sec desde ini hasta fin, e indica en qué puntos se va a vaciar
*/
double Colv_reco_thr::dame_coste_pon_viajes( Secu_amb * sec, int ini, int fin, Info_sec *s, int *nvac)
{
double d=0;
int ind_cost, ind_cost1;
int fin_old=fin;
int id_ambf, ref_ambf;
int id_ambf1;
double capac_v=olv_reco->kg_max, cap_act=0,cap_h, cap_t;
int nv_p, i, sel;//numero de veces por ir a planta
double coste;
double cap_g, dd;
cap_t=cap_act;
BOOL ind_abs=TRUE;
while(ini<fin)
{
id_ambf=s->iamb[sec[fin].iamb];
id_ambf1=s->iamb[sec[fin-1].iamb];
if (ind_abs)
ind_cost=id_ambf;
else
ind_cost=sec[fin].iamb;
ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
cap_t+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma a la carga la basura del ambito
d+=olv_limp->cost_amb[id_ambf][id_ambf];//suma el coste del ambito
d+=olv_limp->arch_dj.dame_dis(id_ambf1, 0, id_ambf,sec[fin].entrada);
fin--;
}
if (ind_abs)
ind_cost=s->iamb[sec[ini].iamb];
else
ind_cost=sec[ini].iamb;
id_ambf=s->iamb[sec[ini].iamb];
d+=olv_reco->cost_amb[id_ambf][id_ambf];//suma el coste de hacer el primer ambito
if(ini==0)//si ini es 0 falta sumar el coste de la planta a el primer ambito
{
d+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal, 0, s->iamb[sec[ini].iamb],0);
d+=olv_reco->t_sal;//suma el coste de la llegada
}
cap_t+=olv_limp->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inf_r.kg;//suma a la carga total la basura del primer ambito
//////////////////
//lo almacena
s->dis_med=(float)cap_t;
//////////////////
nv_p=(int)(cap_t/capac_v +1);//numero de veces que se tendra que ir a planta
cap_h=nv_p*capac_v-cap_t;//carga con la que se puede jugar (holgura) capacidad desaprovechada
if(cap_h>=capac_v)
{
cap_h-=capac_v;
nv_p--;
}
cap_t+=olv_reco->iaso[olv_limp->carto.get(ind_cost).entity()->ref].inf_r.kg;
//suma coste de ir a planta
if (ind_abs)
ind_cost=s->iamb[sec[fin_old].iamb];
else
ind_cost=sec[fin_old].iamb;
id_ambf=s->iamb[sec[fin_old].iamb];//id del ultimo ambito
nv_p--;//se descuenta uno porque se tiene que terminar en planta
d+=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inod[0]].dis;//suma el coste de ir del ultimo ambito a la planta
d+=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0][olv_reco->nod_plant].dis;//suma el coste de ir de planta a instalacion
d+=olv_reco->t_descarg;//suma el coste de descargar
d+=olv_reco->t_sal;//suma el coste de la llegada
///////////////////////////
coste=MAYUSCULO;
int iold=-1;
BOOL errores=FALSE;
double cos_tray=d;
int veces_plan=nv_p;
BOOL salir=FALSE;
double cap_ult_cont;
while (!salir)
{
salir=TRUE;
cap_h=(1+veces_plan)*capac_v-cap_t;
nv_p=veces_plan;
coste=MAYUSCULO;
cap_g=0;
sel=-1;
d=cos_tray;
cap_act=0;
int isel_old=-1;
double cap_old;
i=ini;
//borra marcas------------
for(int ii=0; ii<fin_old-1; ii++)
{
id_ambf=s->iamb[sec[ii].iamb];
olv_reco->ptos_vaci[id_ambf]=0;
}
while(nv_p>0 && i<=fin_old)
{
if (ind_abs)
ind_cost=s->iamb[sec[i].iamb];
else
ind_cost=sec[i].iamb;
id_ambf=s->iamb[sec[i].iamb];//id del ambito iesimo de la secuen
ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
cap_old=cap_act;
cap_act+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma capacidad del ambito de la secuencia iesima
cap_ult_cont=olv_reco->iaso[ref_ambf].inf_r.kg;
i++;
if(i>fin_old)
{
if(cap_act<capac_v)
break;
}
id_ambf1=s->iamb[sec[i].iamb];//id del ambito iesimo+1 de la secuen
if (ind_abs)
ind_cost1=s->iamb[sec[i].iamb];
else
ind_cost1=sec[i].iamb;
if((capac_v-cap_act)>cap_h)
{
//calcula si el siguiente entra
if((cap_act+olv_reco->iaso[olv_limp->carto.get(id_ambf1).entity()->ref].inf_r.kg)>capac_v)
{
nv_p++;
cap_h=cap_h+capac_v;
}
else
continue;
}
if(cap_act-capac_v<=0)
{
//prueba candidato
//calcula el coste de ir a planta desde el i-1 y de planta a el i y se le resta el coste de ir del i-1 al i
dd=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[ref_ambf].inod[0]].dis;//coste del i-1 a planta
dd+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_plan,0,s->iamb[sec[i].iamb],0);
dd-=olv_limp->arch_dj.dame_dis(id_ambf, 0, s->iamb[sec[i].iamb],0);
dd+=olv_reco->t_descarg;//suma el coste de descargar
if(dd>=MAYUSCULO)
errores=TRUE;//existen errores
if(sel==-1
|| (coste>dd))
{
sel=i;
coste=dd;
cap_g=capac_v-cap_act;
}
}
else
{
//suma coste de ir a la planta y el de volver de ella
if(coste>=MAYUSCULO)
{
if(errores)
olvlog(LOG_TODO,"olv_limp_t","No conseguido candidato para ir a descargar");//algo va mal
//pone una vuelta mas a planta en el i-1;
salir=FALSE;
veces_plan++;
if(cap_ult_cont>capac_v)
{
olvlog(LOG_TODO,"olv_limp_t","Capacidad de contenedor %ld mas grande que la del vehiculo ", i);//algo va mal
return MAYUSCULO;
}
break;
//calcula coste
}
cap_act=0;
cap_h-=cap_g;
iold=i;
isel_old=sel;
i=sel;
///////////////
//pone candidato
olv_reco->ptos_vaci[s->iamb[sec[i-1].iamb]]=(short)OLV_IDA_PLANT;
///////////////
d+=coste;
cap_g=0;
coste=MAYUSCULO;
sel=-1;
nv_p--;
}
}
}
//Cuenta el número de veces que va a vaciar
sel=0;
for(i=0;i<s->namb;i++)
{
if(olv_reco->ptos_vaci[s->iamb[sec[i].iamb]])
sel++;
}
id_ambf=s->iamb[sec[fin_old].iamb];//id del ultimo ambito
olv_reco->ptos_vaci[id_ambf]=(short)OLV_IDA_PLANT_ULT; //indica que en el último se va a planta
*nvac=sel;
return d;
}
//*************************************************************************************
/**
* Lanza sub-threads
*/
void Colv_reco_thr::lanza_subthrs(int tar, int nthr_def/*=-1*/)
{
char nomb[32];
Param_olv_limp_thr pp;
int nn;
if((nthr_def>0) && (nthr_def<n_subthr))
nn=nthr_def;
else
nn=n_subthr;
//Arranca los subthreads
for(int i=0;i<nn;i++)
{
if(!subthrs[i])
subthrs[i]=new Colv_reco_thr(olv_reco);
sprintf_s(nomb,32,"limp_subth_%ld",i);
pp.id_e=i;
subthrs[i]->n_subthr = nn;
subthrs[i]->thr_padre=this;
subthrs[i]->pirate=FALSE;
subthrs[i]->inicia(OLV_MILIS_COLA,&cola_proc,-1,nomb);
subthrs[i]->encola(tar,&pp,FALSE);
}
//fuerza fin para que avance olivia
for(int i=nn;i<n_subthr;i++)
{
if(!subthrs[i])
subthrs[i]=new Colv_limp_thr(olv_limp);
subthrs[i]->prog_subthr = 0;
}
for(int i=0;i<n_subthr-nn;i++)
encola(tar+1,NULL,FALSE); //encola la tarea de fin
}
//*************************************************************************************
/**
* Devuelve la planificación del sector iésimo, que realiza el thread 'ithr'
*/
void Colv_reco_thr::planifica_sub_1(int ithr, Matrix2d<float> &cost_amb)
{
Info_sec *s;
Info_amb_sec *aa;
int i,iaux,is_ini,is_fin,is_desp,is,jmin,nvac;
BOOL log_debug=FALSE;
BOOL sal,sig;
Djkt_nodo *costes_nodos;
int nsecu,KK,ic_aux,ss;
int nsecu2;
Secu_amb *secu_ambi=NULL;
Param_olv_limp_thr pp;
Djkt_nodo *buf_aux=NULL;
int msecu1, msecu2;
int *secu, *secu2;
costes_nodos=NULL;
msecu2 = msecu1 = olv_limp->conjs.n;
secu=(int *)malloc(olv_limp->conjs.n*sizeof(int));
if(!secu)
{
sal=TRUE;
goto fin;
}
memset(secu,0,olv_limp->conjs.n*sizeof(int));
secu2=(int *)malloc(olv_limp->conjs.n*sizeof(int));
if(!secu2)
{
sal=TRUE;
goto fin;
}
memset(secu2,0,olv_limp->conjs.n*sizeof(int));
nsecu2=0;
//////////////////////////
pp.id_e=OLV_TAREA_PLANIF;//manda de parámetro la tarea de la que es el progreso
ic_aux=0;
KK=olv_limp->tipo_ambit;
sal=sig=FALSE;
jmin=0;
prog_subthr=0;
//cost_amb=olv_limp->cost_amb;
aa=olv_limp->amb_sec;
iaux=-1;
////////////////////////////////////////////////////
//mira a ver cuántos sectores le tocan a este thread
if(olv_limp->nsec<n_subthr)
{
//hay menos sectores que threads, o le toca uno o ninguno
if(ithr<olv_limp->nsec)
{
//solo hace un sector, el ithr-esimo
is_ini=ithr;
is_fin=ithr+1;
}
else
{
//no hace ningún sector, no hace falta
is_ini=0;
is_fin=0;
}
}
else
{
//hay más sectores que threads, le tocan más de uno
is_desp=(int)ceil(1.0*(olv_limp->nsec)/n_subthr);
is_ini=ithr*is_desp;
is_fin=min((ithr+1)*is_desp,olv_limp->nsec);
}
//////////////////////////
if(is_fin==is_ini)
olvlog(LOG_TODO,"olv_limp_t","Subthr %02d, No Planifica ningún sector", ithr);
else if(is_fin-is_ini-1==0)
olvlog(LOG_TODO,"olv_limp_t","Subthr %02d, Planifica sector %02d", ithr,is_ini);
else
olvlog(LOG_TODO,"olv_limp_t","Subthr %02d, Planifica sectores %02d a %02d", ithr,is_ini, is_fin-1);
buf_aux=olv_limp->arch_dj.dame_buf_nodos();
if(!buf_aux)
{
olvlog(LOG_TODO,"olv_limp_t","Error en planifica_sub 1 th: %ld sin memo para buffer", ithr);
sal=TRUE;
}
//////////////////////////
//bucle en todos los sectores que le tocan al thread
for(is=is_ini;is<is_fin && !pirate && !sal;is++)
{
s = &olv_limp->sec[is];
if(s->namb<=0)
continue;
s->cost_despl_aux=0;
sig=FALSE;
//busca el ámbito inicial de la planificiación
secu_ambi=planifica_sect(s,olv_limp->ang_conj,OLV_LIMP_FACT_PERM);
if(!secu_ambi)
{
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Imposible planificar sector %02d",ithr,is);
sal=TRUE;
continue;
}
if(esta_repe(secu_ambi, s->namb))
{
olvlog(LOG_TODO,"olv_limp_t","Esta repe despues de planifica sec");
sal=TRUE;
continue;
}
nvac=0;
s->cost_despl_aux=(float)dame_coste_pon_viajes(secu_ambi,0,s->namb-1,s,&nvac);
if(s->cost_despl_aux==0)
{
olvlog(LOG_TODO,"olv_limp_t","Error al calcular viajes");
sal=TRUE;
continue;
}
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Sector %02d, va a vaciar %ld veces",ithr,is,nvac);
///////////////////////////////////////////
//Añade la ruta de la instalación al primer punto
olv_limp->arch_dj.get_b(s->iamb[secu_ambi[0].iamb],secu_ambi[0].entrada, buf_aux);
Colv_geom::ruta_dj_inv_ok(
olv_reco->nod_instal,//id conjuncion inicial
&secu2[0], //puntero a secuencia
buf_aux, //nodos djktra conj final
olv_limp->conjs.n,
&nsecu2);
if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_IDA_INST))
sal=TRUE;
///////////////////////////////////////////
secu[0]=olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[0].iamb]).entity()->ref].inod[secu_ambi[0].entrada];
aa[s->iamb[secu_ambi[0].iamb]].iseq=0;
//olv_limp->t_conv
double cc=0, cc1=0;
ss=1;
int iam_ped;
int iam_ent;
for (i=1; i<s->namb; i++)
{
///////////////////////////////////////////
//Comprueba si hay que ir a vaciar
if(olv_reco->ptos_vaci[s->iamb[secu_ambi[i-1].iamb]]==(short)OLV_IDA_PLANT)
{
//de i-1 a planta
cc+=Colv_geom::ruta_dj_inv_ok(
olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[i-1].iamb]).entity()->ref].inod[(secu_ambi[i-1].entrada+1)%2],
&secu2[0], //puntero a secuencia
olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0], //nodos djktra conj final
olv_limp->conjs.n,
&nsecu2);
if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_IDA_PLANT))
{
sal=TRUE;
break;
}
//de planta a i
olv_limp->arch_dj.get_b(s->iamb[secu_ambi[i].iamb],secu_ambi[i].entrada, buf_aux);
iam_ped=s->iamb[secu_ambi[i].iamb];
iam_ent=secu_ambi[i].entrada;
cc+=Colv_geom::ruta_dj_inv_ok(
olv_reco->nod_plant,
&secu2[0], //puntero a secuencia
buf_aux, //nodos djktra conj final
olv_limp->conjs.n,
&nsecu2);
if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_VUELTA_PLANT))
{
sal=TRUE;
break;
}
}
else
iam_ped=iam_ent=-1;
if(i==s->namb)
continue;
///////////////////////////////////////////
if(iam_ped!=s->iamb[secu_ambi[i].iamb] || iam_ent!=secu_ambi[i].entrada)
olv_limp->arch_dj.get_b(s->iamb[secu_ambi[i].iamb],secu_ambi[i].entrada, buf_aux);
Colv_geom::ruta_dj_inv_ok(
olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[i-1].iamb]).entity()->ref].inod[(secu_ambi[i-1].entrada+1)%2],//id conjuncion inicial
&secu[ss], //puntero a secuencia
buf_aux, //nodos djktra conj final
olv_limp->conjs.n,
&nsecu);
ss+=nsecu;
//almacena el coste acumulado
aa[s->iamb[secu_ambi[i].iamb]].iseq=i;
//////////////////
if((i%50)==0 || (i==s->namb-1))
{
//avisa de progreso
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Planificando sector %02d, amb %ld de %ld", ithr,is,
(i+1),(s->namb));
prog_subthr=(1.0*(i+1)/(s->namb))*((is+1)/(is_fin-is_ini)); //porque son varios sectores
thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
}
/////////////////
}
if(olv_limp->tipo_ambit==OLV_AMB_LIN)//añade el coste del último ámbito si es lineal
{
secu[ss++]=olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[s->namb-1].iamb]).entity()->ref].inod[(secu_ambi[s->namb-1].entrada+1)%2];
}
///////////////////////////////////////////
//Añade la ruta del último punto a descargar
cc+=Colv_geom::ruta_dj_inv_ok(
olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[s->namb-1].iamb]).entity()->ref].inod[(secu_ambi[s->namb-1].entrada+1)%2],
&secu2[0], //puntero a secuencia
olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0], //nodos djktra conj final
olv_limp->conjs.n,
&nsecu2);
if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_IDA_PLANT))
{
sal=TRUE;
break;
}
if(olv_reco->nod_instal!=olv_reco->nod_plant)
{
//de descargar a la instalación
cc+=Colv_geom::ruta_dj_inv_ok(
olv_reco->nod_plant,
&secu2[0], //puntero a secuencia
olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0], //nodos djktra conj final
olv_limp->conjs.n,
&nsecu2);
if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_VUELTA_INST))
{
sal=TRUE;
break;
}
}
///////////////////////////////////////////
if(esta_repe(secu_ambi, s->namb, FALSE))
olvlog(LOG_TODO,"olv_limp_t","Esta repe despues de planificar");
olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Planificando sector %02d, coste total %lf",ithr,is,s->cost_despl_aux);
if(!pirate && !sal)
{
//////////////////////////////////
//genera la ruta y los puntos de control
if(!genera_planif(is,s->cost_despl_aux/*-cc*/, ss, secu,OLV_PLAN_RECO))
sal=TRUE;
olv_limp->sec[is].cost_ac=s->cost_despl_aux;
//olv_limp->sec[is].cost_ac=(float)(olv_limp->plan[is].elem[olv_limp->plan[is].nelem-1].coste+olv_limp->sec[is].t_despl[0]+olv_limp->sec[is].t_despl[1]);
}
//////////////////////////////////
if( secu_ambi)
{
free(secu_ambi);
secu_ambi=NULL;
}
}
free(secu);
free(secu2);
fin:
//Ha terminado, encola al padre
olv_limp->arch_dj.libera_buf(buf_aux);
if(sal)
{
prog_subthr=-1;//para avisar al padre de que ha habido un error
}
thr_padre->encola(OLV_LIMP_EV_PLANIFICA_FIN,NULL,FALSE);
}
//*************************************************************************************
/**
* Pone en la ruta en qué contenedores corresponden los puntos de control
*/
void Colv_reco_thr::pon_ptos_ctrl(Info_planif *pp, int npt_ctrl, double cost_ctrl)
{
double cost_acum, cost_viajes;
int i, ipc, iviaje;
///////////////////////////////////////////////////////////////
//Inicializa el array de puntos de control
pp->pts_ctrl=(Info_planif_ctrl*)malloc((olv_limp->npts_ctrl-2+1)*sizeof(Info_planif_ctrl));
if(!pp->pts_ctrl)
return;
memset(pp->pts_ctrl,0,(olv_limp->npts_ctrl-2+1)*sizeof(Info_planif_ctrl));
ipc=0;
/////////////////////////////
cost_acum=cost_viajes=0;
iviaje=1;//la primera ida será en el viaje 1 (ida desde inst,ida a planta)
for(i=0;i<pp->nelem;i++)
{
/////////////////////////////
cost_acum=pp->elem[i].coste+cost_viajes;
//mira si toca punto de control
if((cost_acum-ipc*(cost_ctrl/*+olv_limp->t_desc*/))>(cost_ctrl+1))
{
if(ipc<npt_ctrl)
{
//añade como punto de control
pp->pts_ctrl[ipc].ipt=i-1;
ipc++;
}
else
ipc=ipc;
}
if(pp->elem[i].tp==OLV_PLAN_TIP_AMB)
{
if(olv_reco->ptos_vaci[olv_limp->iaso[pp->elem[i].refe].iamb]==(short)OLV_IDA_PLANT)
{
cost_viajes+=pp->planif_insta[iviaje].elem[pp->planif_insta[iviaje].nelem-1].coste;//ida
iviaje++;
cost_viajes+=olv_reco->t_descarg;
cost_viajes+=pp->planif_insta[iviaje].elem[pp->planif_insta[iviaje].nelem-1].coste;//vuelta
iviaje++;
}
}
}
for(i=0;i<npt_ctrl;i++)
{
if(pp->pts_ctrl[i].ipt<0)
pp->pts_ctrl[i].ipt=pp->nelem-1;
}
}
//*************************************************************************************
/**
* Dada la secuencia de las conjunciones que sigue la ruta para ir a vaciar, genera el obg
*/
BOOL Colv_reco_thr::genera_planif_vaci(int is, int ini, int fin, int *secu, int tip_viaje)
{
int i,nvaciados;
Info_planif *pp,*pp_insta;
Info_sec *ss;
ss=&olv_limp->sec[is];
pp=&olv_limp->plan[is];
pp_insta = pp->planif_insta;
nvaciados=0;
if(!pp_insta)
{
nvaciados=1;//siempre está el último, que va a vaciar
for(i=0;i<ss->namb;i++)
{
if(olv_reco->ptos_vaci[ss->iamb[i]]==(short)OLV_IDA_PLANT)
nvaciados++;//por cada vez que va a descargar
}
}
if(!genera_planif_instala(is, nvaciados, ini, fin, secu, tip_viaje))
return FALSE;
return TRUE;
}
//*************************************************************************************
/**
* Añade una línea al listado csv con el viaje a vaciar y vuelta
*/
BOOL Colv_reco_thr::genera_list_fila_vaci(Colv_csv *cc, char *fila0, int ielem, int isec, int secu, double tt, double *t0,BOOL is_fin)
{
int h,m,seg,i,iplan;
Info_planif *pp;
double cost_despl,ltot,kgac;
int iamb, iamb2;
iamb=olv_limp->iaso[ielem].iamb;
if(iamb<0)
iamb=olv_limp->iaso[ielem].refe2;
if(iamb<0 || !olv_reco->ptos_vaci[iamb])
return TRUE;//no es punto en el que se va a vaciar
if(!is_fin && (olv_reco->ptos_vaci[iamb]!=(short)OLV_IDA_PLANT))
return TRUE;//no es punto en el que se va a vaciar
//busca la ruta de este punto en el que se va a vaciar
if(!olv_limp->plan[isec].planif_insta || !olv_limp->plan[isec].ninsta)
return FALSE;
for(i=0;i<olv_limp->plan[isec].ninsta;i++)
{
if(olv_limp->plan[isec].planif_insta[i].elem[0].refe==ielem)
break;
}
if(i>=olv_limp->plan[isec].ninsta)
return FALSE;
iplan=i;
//ha encontrado la planificación, coge el tiempo de desplazamiento
pp = &olv_limp->plan[isec].planif_insta[i];
if(!pp->nelem)
return FALSE;
cost_despl = pp->elem[pp->nelem-1].coste;
ltot=pp->m[OLV_DESP];
//////////////////
//pone el tiempo acumulado, aprovecha y lo guarda aquí
pp->t[OLV_TTO]=tt;
//////////////////
//////////////////
//Calcula los kg acumulados
kgac=0;
for(i=0;i<olv_limp->plan[isec].nelem;i++)
{
if(olv_limp->plan[isec].elem[i].tp!=OLV_PLAN_TIP_AMB)
continue;
iamb2=olv_limp->iaso[olv_limp->plan[isec].elem[i].refe].refe2;
kgac+=olv_limp->iaso[iamb2].inf_r.kg;
if(olv_limp->plan[isec].elem[i].refe==ielem)
break;
}
if(i>=olv_limp->plan[isec].nelem)
return FALSE;
//le resta los kg acumulados en el viaje anterior
i=iplan;
while((i-2)>0)//dos antes está la anterior planif a vaciar, si la hubiera
{
kgac-=olv_limp->plan[isec].planif_insta[i-2].m[OLV_TTO];//aprovecha y lo guarda aquí
i-=2;
}
pp->m[OLV_TTO]=kgac;
//////////////////
*t0+=cost_despl+olv_reco->t_descarg;
tt+=cost_despl+olv_reco->t_descarg;
dame_h_m_s(tt, &h, &m, &seg);
sprintf_s(fila0,256,"%02d;%04d;%s;%.1f;%s;%.1f;%02d:%02d:%02d;\r\n",isec+1,secu,"",kgac,"Descarga",ltot,h,m,seg);
if(!cc->escribe(fila0))
{
return FALSE;
}
if(olv_reco->ptos_vaci[iamb]!=(short)OLV_IDA_PLANT)
return TRUE;
//escribe la vuelta de la descarga
if((iplan+1)>=olv_limp->plan[isec].ninsta)
return TRUE;
pp = &olv_limp->plan[isec].planif_insta[iplan+1];
if(!pp->nelem)
return FALSE;
cost_despl = pp->elem[pp->nelem-1].coste;
ltot=pp->m[OLV_DESP];
//////////////////
//pone el tiempo acumulado
pp->t[OLV_TTO]=tt;
//////////////////
*t0+=cost_despl;
tt+=cost_despl;
dame_h_m_s(tt, &h, &m, &seg);
sprintf_s(fila0,256,"%02d;%04d;%s;%s;%s;%.1f;%02d:%02d:%02d;\r\n",isec+1,secu,"","","Vuelta de Descarga",ltot,h,m,seg);
if(!cc->escribe(fila0))
{
return FALSE;
}
//reinicia, para que no vuelva a entrar
olv_reco->ptos_vaci[iamb]=0;
return TRUE;
}
//*************************************************************************************
/**
* Quita al tiempo total el del último desplazamiento y la última descarga, solo para reco
*/
void Colv_reco_thr::quita_t_ult_desc(int s, double *t)
{
int tt=(int)*t;
if(olv_limp->plan[s].ninsta>2 && olv_limp->plan[s].planif_insta[olv_limp->plan[s].ninsta-2].nelem>0) //quita el tiempo de desplazamiento de la instalación a la planta
tt-=(int)olv_limp->plan[s].planif_insta[olv_limp->plan[s].ninsta-2].elem[olv_limp->plan[s].planif_insta[olv_limp->plan[s].ninsta-2].nelem-1].coste;
tt-=olv_reco->t_descarg;
*t=tt;
}
//*************************************************************************************
/**
* Añade una columna de observación al listado si es contenedores
*/
void Colv_reco_thr::dame_observ_cont(int iamb, char *observ)
{
int i=olv_limp->iaso[iamb].iamb;
if(i<0)
i=olv_limp->iaso[iamb].refe2;
sprintf_s(observ,32,"%ld",olv_limp->iaso[i].inf_r.uds);
}
//*************************************************************************************
/**
* Añade las columnas de información a la ruta, tiempos, longitudes, y demás
*/
BOOL Colv_reco_thr::guarda_cols_ruta(char *path_shp)
{
char *info;
char path_dbf[MAX_PATH];
double tt;
int h,m,s,j;
int nsec, i, isec_novac;
ManagerDbfGdataTable dbfmgr;
//cuenta el número de sectores no vacíos
nsec=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb!=0)
nsec++;
}
/////////////////////////////////////
if(!Colv_limp_thr::guarda_cols_ruta(path_shp))
return FALSE;
//añade una columna a la ruta de tiempo de ruta
strcpy_s(path_dbf,MAX_PATH,path_shp);
//cambiaext(path_dbf,".shp",".dbf");
strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");
info = (char *)malloc(nsec* OLV_SHP_SZ_CAMP_SZ);
if(!info)
{
return FALSE;
}
memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
AddColsDbf dataDbf(info);
//sustituye la info de hora final
isec_novac=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
{
continue;
}
tt=olv_limp->t_ini+ olv_limp->sec[i].cost_ac + olv_limp->t_desc;
dame_h_m_s(tt, &h, &m, &s);
sprintf_s(&info[isec_novac*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
isec_novac++;
}
if(!dbfmgr.AddCol(path_dbf,"H_FIN",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
{
free(info);
return FALSE;
}
memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
//sustituye la columna de uds de tratamiento porque hay contenedores que son varias unidades
isec_novac=0;
for(i=0;i<nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
tt=0;
for(j=0;j<olv_limp->sec[i].namb;j++)
tt+=olv_limp->iaso[olv_limp->sec[i].iamb[j]].inf_r.uds;
//para guardar en número
((int*)info)[isec_novac] = tt;
isec_novac++;
}
if(!dbfmgr.AddCol(path_dbf,"UDS_TRAT",GdataTable::Tint,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
//Kg recogidos
isec_novac=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
tt=olv_limp->sec[i].dis_med;
//para guardar en número
((double*)info)[isec_novac] = tt;
isec_novac++;
}
if(!dbfmgr.AddCol(path_dbf,"KG_TOT_REC",GdataTable::Tdouble,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
//número de descargas
isec_novac=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
tt=(olv_limp->plan[i].ninsta-1)/2;
//para guardar en número
((int*)info)[isec_novac] = tt;
isec_novac++;
}
if(!dbfmgr.AddCol(path_dbf,"N_DESCARG",GdataTable::Tint,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
//rellena la info de duración de los desplazamientos a descargar
isec_novac=0;
int p;
for(i=0;i<olv_limp->nsec;i++)
{
tt=0;
if(olv_limp->sec[i].namb==0)
continue;
for(p=1;p<olv_limp->plan[i].ninsta;p++)
{
if(olv_limp->plan[i].planif_insta[p].nelem==0)
continue;
tt+=olv_limp->plan[i].planif_insta[p].elem[olv_limp->plan[i].planif_insta[p].nelem-1].coste;
}
//tt=olv_limp->sec[i].cost_ac-olv_limp->plan[i].elem[olv_limp->plan[i].nelem-1].coste-olv_limp->sec[i].t_despl[0]-olv_limp->sec[i].t_despl[1]-olv_reco->t_sal;
dame_h_m_s(tt, &h, &m, &s);
sprintf_s(&info[isec_novac*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
isec_novac++;
}
if(!dbfmgr.AddCol(path_dbf,"T_DESCARG",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
{
free(info);
return FALSE;
}
memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
free(info);
return TRUE;
}
//*************************************************************************************
/**
* Añade las columnas de información a la ruta, tiempos, longitudes, y demás
*/
BOOL Colv_reco_thr::guarda_cols_insta(char *path_shp)
{
char *info;
char path_dbf[MAX_PATH];
double tt;
//int h;
int insta, ninsta_parc,ninsta,ninsta_novac;
ManagerDbfGdataTable dbfmgr;
/////////////////////////////////////
if(!Colv_limp_thr::guarda_cols_insta(path_shp))
return FALSE;
//cuenta el número de instalaciones
ninsta=0;
for(int i=0;i<olv_limp->nsec;i++)
{
for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
{
if(olv_limp->plan[i].planif_insta[insta].nelem!=0)
ninsta++;
}
}
//añade una columna a la ruta de tiempo de ruta
strcpy_s(path_dbf,MAX_PATH,path_shp);
//cambiaext(path_dbf,".shp",".dbf");
strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");
info = (char *)malloc(ninsta* OLV_SHP_SZ_CAMP_SZ);
if(!info)
{
return FALSE;
}
memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);
AddColsDbf dataDbf(info);
//kg descargados
ninsta_parc=0;
for(int i=0;i<olv_limp->nsec;i++)
{
ninsta_novac=0;
for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
{
if(olv_limp->plan[i].planif_insta[insta].nelem==0)
continue;
if(olv_limp->plan[i].planif_insta[insta].ninsta==OLV_IDA_PLANT)
tt=olv_limp->plan[i].planif_insta[insta].m[OLV_TTO];
else
tt=0;
((double*)info)[insta + ninsta_parc] = tt;
ninsta_novac++;
}
ninsta_parc+=ninsta_novac;
}
if(!dbfmgr.AddCol(path_dbf,"KG_DESCARG",GdataTable::Tdouble,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);
//num de trayecto a descargar
ninsta_parc=0;
tt=0;
int tt2=0;
for(int i=0;i<olv_limp->nsec;i++)
{
ninsta_novac=0;
tt2=0;
for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
{
if(olv_limp->plan[i].planif_insta[insta].nelem==0)
continue;
if(olv_limp->plan[i].planif_insta[insta].ninsta==OLV_IDA_PLANT ||
olv_limp->plan[i].planif_insta[insta].ninsta==OLV_VUELTA_INST)
{
tt2++;
tt=tt2;
}
else if(olv_limp->plan[i].planif_insta[insta].ninsta==OLV_VUELTA_PLANT)
tt=tt2;
else
tt=0;
((int*)info)[insta + ninsta_parc] = tt;
ninsta_novac++;
}
ninsta_parc+=ninsta_novac;
}
if(!dbfmgr.AddCol(path_dbf,"VIAJE",GdataTable::Tint,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);
free(info);
return TRUE;
}
//*************************************************************************************
/**
* Comprueba si en este elemento se va a descargar y en ese caso no se cuenta el desplazamiento hasta el siguiente
*/
BOOL Colv_reco_thr::comprueba_descarg(int iamb)
{
return (olv_reco->ptos_vaci[iamb]==(short)OLV_IDA_PLANT);
}
//*************************************************************************************
/**
* Añade las columnas de información a la ruta, tiempos, longitudes, y demás
*/
BOOL Colv_reco_thr::guarda_cols_ruta_tram(char *path_shp)
{
char *info;
char path_dbf[MAX_PATH];
double tt;
int i, it,ntram,nt,nt_parc;
ManagerDbfGdataTable dbfmgr;
if(!Colv_limp_thr::guarda_cols_ruta_tram(path_shp))
return FALSE;
//añade
//cuenta el número de sectores no vacíos
ntram=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
ntram+=(int)olv_limp->tramos[i].size();
}
//añade una columna a la ruta de tiempo de ruta
strcpy_s(path_dbf,MAX_PATH,path_shp);
//cambiaext(path_dbf,".shp",".dbf");
strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");
info = (char *)malloc(ntram* OLV_SHP_SZ_CAMP_SZ);
if(!info)
{
return FALSE;
}
memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
AddColsDbf dataDbf(info);
//M_DESP
nt_parc=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
nt=(int)olv_limp->tramos[i].size();
for(it=0;it<nt;it++)
{
tt=olv_limp->tramos[i][it].long_tr;
((double*)info)[nt_parc + it] = tt;
}
nt_parc+=nt;
}
if(!dbfmgr.AddCol(path_dbf,"M_DESP",GdataTable::Tdouble,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
//N_AMB
nt_parc=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
nt=(int)olv_limp->tramos[i].size();
for(it=0;it<nt;it++)
{
tt=olv_limp->tramos[i][it].namb;
((int*)info)[nt_parc + it] = tt;
}
nt_parc+=nt;
}
if(!dbfmgr.AddCol(path_dbf,"N_AMB",GdataTable::Tint,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
//UDS_TTO
nt_parc=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
nt=(int)olv_limp->tramos[i].size();
for(it=0;it<nt;it++)
{
tt=olv_limp->tramos[i][it].ncont;
((int*)info)[nt_parc + it] = tt;
}
nt_parc+=nt;
}
if(!dbfmgr.AddCol(path_dbf,"UDS_TTO",GdataTable::Tint,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
//KG_RECO
nt_parc=0;
for(i=0;i<olv_limp->nsec;i++)
{
if(olv_limp->sec[i].namb==0)
continue;
nt=(int)olv_limp->tramos[i].size();
for(it=0;it<nt;it++)
{
tt=olv_limp->plan[i].planif_insta[2*it+1].m[OLV_TTO];
((double*)info)[nt_parc + it] = tt;
}
nt_parc+=nt;
}
if(!dbfmgr.AddCol(path_dbf,"KG_RECO",GdataTable::Tdouble,&dataDbf))
{
free(info);
return FALSE;
}
memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
return TRUE;
}
//*************************************************************************************
/**
* Rellena la info de los tramos
*/
void Colv_reco_thr::rellena_tramos()
{
Info_planif *pp;
Info_tramos *tramo;
int ie,it,nt;
for(int is=0;is<olv_limp->nsec;is++)
{
pp=&olv_limp->plan[is];
nt=(int)olv_limp->tramos[is].size();
for(it=0;it<nt;it++)
{
tramo = &olv_limp->tramos[is][it];
tramo->namb=0;
tramo->ncont=0;
for(ie=tramo->ie[0]; ie<=tramo->ie[1];ie++)
{
tramo->long_tr+=(float) pp->elem[ie].ltot;
if(pp->elem[ie].tp!=OLV_PLAN_TIP_AMB)
continue;
tramo->namb++;
tramo->ncont+=olv_limp->iaso[olv_limp->iaso[pp->elem[ie].refe].refe2].inf_r.uds;
}
tramo->t_tto_tr = (float)(tramo->ncont*olv_reco->t_tto);
if(it==0)
tramo->t_ini = (float)(olv_limp->t_ini+pp->planif_insta[0].elem[pp->planif_insta[0].nelem-1].coste);
else
tramo->t_ini = (float)(pp->planif_insta[2*it].t[OLV_TTO]+pp->planif_insta[2*it].elem[pp->planif_insta[2*it].nelem-1].coste);
tramo->t_fin = (float)pp->planif_insta[2*it+1].t[OLV_TTO];
tramo->t_total_tr = (float) (tramo->t_fin-tramo->t_ini);
}
}
}
//*************************************************************************************
/**
* Como los viajes a instalaciones están ordenados, y los tramos también
* le corresponde a cada tramo it el viaje it y el it+1, excepto al último, que le pueden
* corresponder 3 viajes si la instalación y la descarga no son en el mismo sitio
* Además, actualiza el tiempo de los tramos
*/
int Colv_reco_thr::rellena_insta_tramos()
{
int it, nt, nins,ii;
Info_planif *pinsta;
Info_tramos *tramo;
ii=0; //para saber si hace algún tramo o no
for(int is=0;is<olv_limp->nsec;is++)
{
nt=(int)olv_limp->tramos[is].size();
nins = olv_limp->plan[is].ninsta;
if(!nins)
continue;
if(olv_limp->plan[is].planif_insta[nins-1].nelem==0)
nins--; //es porque la descarga y planta son la misma
pinsta = olv_limp->plan[is].planif_insta;
for(it=0;it<nt-1;it++)
{
tramo = &olv_limp->tramos[is][it];
tramo->iins[0]=2*it;
tramo->iins[1]=2*it+1;
///////////////////////////////////////
//Actualiza los tiempos del tramo sumando los tiempos del viaje a inst
tramo->t_ini -= (float)pinsta[tramo->iins[0]].elem[pinsta[tramo->iins[0]].nelem-1].coste;
tramo->t_fin += (float)pinsta[tramo->iins[1]].elem[pinsta[tramo->iins[1]].nelem-1].coste;
tramo->t_total_tr=(float) (tramo->t_fin-tramo->t_ini);
}
//para el último tramo
tramo = &olv_limp->tramos[is][it];
tramo->iins[0]=2*it;
tramo->iins[1]=nins-1;
tramo->t_ini -= (float)pinsta[tramo->iins[0]].elem[pinsta[tramo->iins[0]].nelem-1].coste;
//si la instalación no es la misma que la descarga, le suma el tiempo de ir a descargar y el de ir a la instalación
BOOL notdesc=TRUE;
for(int i=tramo->iins[0]+1;i<=tramo->iins[1];i++)
{
if(notdesc)
{
tramo->t_fin += olv_reco->t_descarg;
notdesc=FALSE;
}
tramo->t_fin += (float)pinsta[i].elem[pinsta[i].nelem-1].coste;
}
tramo->t_total_tr=(float) (tramo->t_fin-tramo->t_ini);
ii++;
}
return ii;
}
//*************************************************************************************
#endif