#include "stdafx.h"

#ifdef OLIVIA_COMPILA
//olivia
#include "olv_limp_thr.h"
#include "olv_thr.h"
#include "olv_limp.h"
#include "olv.h"
#include "olv_geom.h"
#include "olv_csv.h"
//igt_base 
#include "lock.h"
#include <stack>
#include "olv_tasks.h"
#include "olv_tasks_def.h"
#include "olv_sock.h"
//utiles
#include "dir_manager.h"
#include "GeometryFunction.h"
#include "Fdbf.h"
#include "b_file.h"
#include "ManagerDbfGdataTable.h"
#include "sock_sv.h"
#include <map>

UINT th_planificacion(LPVOID pp);
/**
*	@file olv_limp_thr.cpp
*	Archivo de implementaciones del thread de control de la utilidad de limpieza viaria del programa Olivia.
*/

Colv_limp_thr::Colv_limp_thr(Colv_limp *olv_limp) : Colv_thr(olv_limp->olv)
{
	this->olv_limp = olv_limp;
	thr_padre=NULL;
	n_subthr_fin=0;		
	pirate=FALSE;
	fin_permu=FALSE;
	//los subthreads
	n_subthr=Colv_geom::dame_n_nucleos(); //lanza un thread por procesador
	subthrs = (Colv_limp_thr **)malloc(n_subthr*sizeof(Colv_limp_thr *));
	for(int i=0;i<n_subthr;i++)
	{
		subthrs[i] = NULL;
	}
	prog_subthr=0;	
	n_subthr_mal=0;
	visto_ang=NULL;
	olv_limp->tramos=NULL;
}

Colv_limp_thr::~Colv_limp_thr(void)
{
	int i;

	//destruye los subthreads
	if(subthrs)
	{
		for(i=0;i<n_subthr;i++)
		{
			if(subthrs[i])
				delete subthrs[i];
		}
		free(subthrs);
	}			
	if(visto_ang)
		free(visto_ang);
	borra_temp_files();
	if(olv_limp->tramos)
		delete [] olv_limp->tramos;
}

//*************************************************************************************
void Colv_limp_thr::inicia_th()
{
	inicia(OLV_MILIS_COLA,&cola_proc,-1,"limp_thr");
	olvlog(LOG_TODO,"olv_limp_t","Thread de limpieza limp_thr arrancado");	
	borra_temp_files();
	pirate=FALSE;
	fin_permu=FALSE;
}

//*************************************************************************************
/**
 * Cola de procesos en la que el thread está iterando y va ejecutando la tarea que le toque en cada momento
 * También se usa en los subprocesos, cuando el proceso principal lanza los subprocesos, cada uno itera en una cola como esta
 */
void Colv_limp_thr::cola_proc(int evento, OlvAsync_cola<Param_olv_limp_thr> *clase,Param_olv_limp_thr *e)
{
	BOOL bien=TRUE;

	Colv_limp_thr *this_i=static_cast<Colv_limp_thr *>(clase);
	switch (evento)
	{
	case OLV_LIMP_EV_ABRE_DAT:
		{
			bien=this_i->abre_datos();
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
				this_i->encola(OLV_LIMP_EV_RELL_DAT,NULL,FALSE);
			break;
		}
	case OLV_LIMP_EV_RELL_DAT:
		{
			bien=this_i->rellena_datos();
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
			{
				if(!this_i->olv->olv_limp->barr_mix)
					this_i->encola(OLV_LIMP_EV_UNE_AMB_NW,NULL,FALSE);
				else
					this_i->encola(OLV_LIMP_EV_BARRMIX,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_BARRMIX:
		{
			//esta tarea lanza varios subthreads para realizar las comprobaciones del barrido mixto
			//y estos cuando acaban le encolan al padre (el que los ha lanzado)
			//la tarea de comprueba_barr_mixto_fin
			this_i->mejora_barr_mix();
			break;
		}
	case OLV_LIMP_EV_BARRMIX_SUB:
		{
			//aquí entran los subthreads para hacer las comprobaciones del barrido mixto
			//encolan al padre la tarea de fin
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->mejora_barr_mix_sub(ithr);
			break;
		}
	case OLV_LIMP_EV_BARRMIX_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			this_i->n_subthr_fin++;
			if(this_i->n_subthr_fin==this_i->n_subthr)
			{		
				this_i->n_subthr_fin=0;
				bien=this_i->mejora_barr_mix_fin();
				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;
		}
	case OLV_LIMP_EV_UNE_AMB_NW:
		{
			int soloi=-1;
			bien=this_i->une_amb_nw(soloi);
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
			{
				if(this_i->olv_limp->tipo_ambit==OLV_AMB_LIN)
					this_i->encola(OLV_LIMP_EV_COMPCORT,NULL,FALSE);
				else //si son lineales, se mira si hay cortes para reapuntar antes de hacer topo
					this_i->encola(OLV_LIMP_EV_TOPO_NW,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_COMPCORT:
		{			
			this_i->compr_cortes_amb();
			break;
		}
	case OLV_LIMP_EV_COMPCORT_SUB:
		{
			//aquí entran los subthreads para hacer los cálculos de distancia, cuando acaban
			//encolan al padre la tarea de fin
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->compr_cortes_amb_sub(ithr);
			break;
		}
	case OLV_LIMP_EV_COMPCORT_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			this_i->n_subthr_fin++;
			if(this_i->n_subthr_fin==this_i->n_subthr)
			{		
				this_i->n_subthr_fin=0;
				bien=this_i->compr_cortes_amb_sub_fin();
				if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
				{
					this_i->encola(OLV_LIMP_EV_TOPO_NW,NULL,FALSE);
				}
			}
			break;
		}
	case OLV_LIMP_EV_TOPO_NW:
		{			
			bien=this_i->topo_nw();
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
				this_i->encola(OLV_LIMP_EV_COST_CONJ,NULL,FALSE);
			break;
		}
	case OLV_LIMP_EV_COST_CONJ:
		{
			//esta tarea lanza varios subthreads para realizar los cálculos
			//de costes entre conjunciones (les encola la tarea dist_conj_sub), 
			//y estos cuando acaban le encolan al padre (el que los ha lanzado)
			//la tarea de dist_conj_fin
			bien=this_i->calcula_cost_conj();
			break;
		}
	case OLV_LIMP_EV_COST_CONJ_SUB:
		{
			//aquí entran los subthreads para hacer los cálculos de distancia, cuando acaban
			//encolan al padre la tarea de fin
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->calcula_cost_conj_sub(ithr);
			break;
		}
	case OLV_LIMP_EV_COST_CONJ_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			
			this_i->n_subthr_fin++;
			if(this_i->n_subthr_fin==this_i->n_subthr)
			{		
				this_i->n_subthr_fin=0;
				bien=this_i->calcula_cost_conj_fin();
				if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
				{
					this_i->encola(OLV_LIMP_EV_ANG_CONJ,NULL,FALSE);
				}
			}
			break;
		}
	case OLV_LIMP_EV_ANG_CONJ:
		{
			//esta tarea lanza varios subthreads para realizar los cálculos
			//de ángulos entre conjunciones (les encola la tarea ang_conj_sub), 
			//y estos cuando acaban le encolan al padre (el que los ha lanzado)
			//la tarea de ang_conj_fin
			bien=this_i->calcula_ang_conj();
			break;
		}
	case OLV_LIMP_EV_ANG_CONJ_SUB:
		{
			//aquí entran los subthreads para hacer los cálculos de ángulos, cuando acaban
			//encolan al padre la tarea de fin
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->calcula_ang_conj_sub(ithr);
			break;
		}
	case OLV_LIMP_EV_ANG_CONJ_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			this_i->n_subthr_fin++;
			if(this_i->n_subthr_fin==this_i->n_subthr)
			{		
				this_i->n_subthr_fin=0;
				bien=this_i->calcula_ang_conj_fin();
				if(bien && this_i->olv_limp->olv->modo_multitask && !this_i->pirate)
					this_i->encola(OLV_LIMP_EV_GUARD_MATS,NULL,FALSE);
				else if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
					this_i->encola(OLV_LIMP_EV_COST_AMB,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_GUARD_MATS:
		{
			bien=this_i->guarda_mats();
			break;
		}
	case OLV_LIMP_EV_GUARD_MATS_SUB:
		{
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->guarda_mats_sub(ithr);
			break;
		}
	case OLV_LIMP_EV_GUARD_MATS_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			this_i->n_subthr_fin++;
			int i;
			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;
				if(i<this_i->n_subthr)
				{
					bien=FALSE;
					this_i->pon_mi_msg("Errores al guardar matrices de costes");
					break;
				}		
				bien=this_i->guarda_mats_fin();
				if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
					this_i->encola(OLV_LIMP_EV_TASK_ESCUCHA,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_TASK_ESCUCHA:
		{
			bien=this_i->task_dj_escucha();
			break;
		}
	case OLV_LIMP_EV_TASK_FIN:
		{		
			this_i->n_subthr_fin++;
			if((e!=NULL) && e->id_e<0)//ha ido mal
			{
				if(e->id_e==-1)
					this_i->subthrs[this_i->n_subthr_fin-1]->prog_subthr=-1;
				else if(e->id_e==-2)
				{
					bien=FALSE;
					this_i->pon_mi_msg("Errores en cálculo multitask, no ha habido conexión");
					break;
				}	
			}
			int i;
			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;
				if(i<this_i->n_subthr)
				{
					bien=FALSE;
					this_i->pon_mi_msg("Errores en cálculo multitask");
					break;
				}		
				this_i->task_dj_fin();
				if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
					this_i->encola(OLV_LIMP_EV_COST_AMB,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_COST_AMB:
		{
			//esta tarea lanza varios subthreads para realizar los cálculos
			//de costes(les encola la tarea dist_amb_sub), 
			//y estos cuando acaban le encolan al padre (el que los ha lanzado)
			//la tarea de dist_amb_fin			
			bien=this_i->calcula_cost_amb();
			break;
		}
	case OLV_LIMP_EV_COST_AMB_SUB:
		{
			//aquí entran los subthreads para hacer los cálculos de costes entre ámbitos, cuando acaban
			//encolan al padre la tarea de fin
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;			
			this_i->calcula_cost_amb_sub(ithr);
			break;
		}	
	case OLV_LIMP_EV_COST_AMB_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			int i;
			this_i->n_subthr_fin++;
			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;
				if(i<this_i->n_subthr)
				{
					bien=FALSE;
					this_i->pon_mi_msg("Errores al calcular coste entre ámbitos");
					break;
				}					
				bien=this_i->calcula_cost_amb_fin();
				if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
				{
					if(this_i->olv->modo_ejec==OLV_EJEC_PLAN) //lee info de sectorización y va a planif
						this_i->encola(OLV_LIMP_EV_LEE_SECTO,NULL,FALSE);
					else //sectoriza
					{
						if(this_i->olv_limp->nsec==0)//hay que calcular el número de sectores
							this_i->encola(OLV_LIMP_EV_CALC_NSEC,NULL,FALSE);
						else
						{
							if(this_i->olv_limp->nsec<0)
							{
								this_i->olv_limp->calc_nsec=this_i->dame_cost_jornada();//indica que se tiene que ajustar a la jornada
								this_i->olv_limp->nsec=this_i->olv_limp->nsec_act=this_i->olv_limp->nsec*(-1);
							}
							this_i->encola(OLV_LIMP_EV_SECTORIZA,NULL,FALSE);
						}
					}
				}
				
			}
			break;
		}
	case OLV_LIMP_EV_CALC_NSEC:
		{
			bien=this_i->calcula_n_sec();	
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_SIGUE_NOPLAN) && !this_i->pirate)//sigue
			{					
				this_i->encola(OLV_LIMP_EV_SECTORIZA,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_SECTORIZA:
		{
			bien=this_i->sectoriza();	
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_SIGUE_NOPLAN) && !this_i->pirate)//sigue
			{
				this_i->pon_info_resul();
				if(this_i->olv->modo_ejec>=OLV_EJEC_DEBUG_SIGUE)
					this_i->encola(OLV_LIMP_EV_PLANIFICA,NULL,FALSE);
				else
				{
					this_i->borra_temp_files();
					this_i->pon_mi_progre(OLV_TAREA_FIN_SEC,0);					
				}
			}
			break;
		}
	case OLV_LIMP_EV_LEE_SECTO:
		{
			bien=this_i->lee_secto();
			if(bien && !this_i->pirate)//sigue
			{
				this_i->encola(OLV_LIMP_EV_PLANIFICA,NULL,FALSE);
			}
			break;
		}
	case OLV_LIMP_EV_PLANIFICA:
		{
			bien=this_i->planifica();	
			break;
		}
	case OLV_LIMP_EV_PLANIFICA_SUB:
		{
			//aquí entran los subthreads para hacer los cálculos de planificación, cuando acaban
			//encolan al padre la tarea de fin
			int ithr;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->planifica_sub_1(ithr, this_i->olv_limp->cost_amb);
			break;
		}
	case OLV_LIMP_EV_PLANIFICA_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea	
			int i;
			this_i->n_subthr_fin++;
			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;
					}
				}
				if(i<this_i->n_subthr)
				{
					bien=FALSE;
					this_i->pon_mi_msg("Errores al planificar th %ld",i);
					break;
				}
				bien = this_i->planifica_fin();
				//pone progreso como que ha terminado
				if(bien)
				{
					this_i->pon_info_resul();
					this_i->borra_temp_files();
					this_i->pon_mi_progre(OLV_TAREA_FIN_PLANIF,0); 
				}
			}
			break;
		}
	case OLV_LIMP_EV_SUBTHR_PROG:
		{
			//aquí entra el padre porque le encolan los subthreads para avisarle del progreso
			double pro=0;
			for(int i=0;i<this_i->n_subthr;i++)
				pro+=this_i->subthrs[i]->prog_subthr;
			pro=OliviaDef::GeneralDef::ProgrMax*pro/this_i->n_subthr;
			if(e!=NULL)
			{
				this_i->pon_mi_progre(e->id_e,(int)pro);
			}				
			break;
		}	
	}
	if(!bien)
	{
		this_i->pon_mi_progre(OLV_TAREA_FIN_NOK,0);
#ifndef _DEBUG
		this_i->borra_temp_files();
#endif
	}
}
//*************************************************************************************
void Colv_limp_thr::termina_th()
{
	if(tarea==OLV_TAREA_PERMU && !fin_permu)
	{
		fin_permu=TRUE;
		return;
	}
	if(fin_permu)
		fin_permu=FALSE;
	pirate=TRUE;
	para_subthrs();
	termina();
	olvlog(LOG_TODO,"olv_limp_t","Thread de limpieza limp_thr finalizado");
}
//*************************************************************************************
/**
 * Abre los datos de cartografía
 */
BOOL Colv_limp_thr::abre_datos() 
{
	////////////////////////////////////////////////////////
	int i;
	Info_aso2 info_aux;
	CartoBaseInfoEntity ient;

	olvlog(LOG_TODO,"olv_limp_t","Abriendo datos");
	pon_mi_progre(OLV_TAREA_IMP, 0);
	pon_mi_msg("");
	err_str[0]=0;

	//abre la cartografía con los datos	
	if(!olv_limp->carto.importShp(olv_limp->olv->paths.path_data))
	{
		pon_mi_msg("Error en la importación del archivo\n%s",olv_limp->olv->paths.path_data);
		return FALSE;
	}
	olv_limp->n_amb=olv_limp->carto.getNumberEntities();
	if(olv_limp->n_amb>=USHRT_MAX)
	{
		pon_mi_msg("Número de ámbitos (%ld) mayor que el permitido (%ld)\n",olv_limp->n_amb,USHRT_MAX);
		return FALSE;
	}
	//Inicializa la información asociada
	info_aux.reset();
	//si es tipo eje de calle lo pone en el flag
	if((olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMh_eje) || 
		(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoM2h_eje))
	{
		info_aux.flgs = OLV_LIMP_FLG_EJE;
	}
	info_aux.flgs |= OLV_LIMP_FLG_AMB;
	for(i=0;i<olv_limp->n_amb;i++)
	{
		ient = olv_limp->carto.get(i);
		info_aux.refe = ient.entity()->ref;
		info_aux.iamb=i;
		olv_limp->iaso[info_aux.refe]=info_aux;
	}

	//abre la cartografía de la red navegable
	if(!olv_limp->carto.importShp(olv_limp->olv->paths.path_nw))
	{
		pon_mi_msg("Error en la importación del archivo\n%s",olv_limp->olv->paths.path_nw);
		return FALSE;
	}
	olv_limp->n_nw=olv_limp->carto.getNumberEntities()-olv_limp->n_amb;
	//Inicializa la información asociada
	info_aux.reset();
	info_aux.flgs = OLV_LIMP_FLG_NW;
	for(i=olv_limp->n_amb;i<olv_limp->n_nw+olv_limp->n_amb;i++)
	{
		ient=olv_limp->carto.get(i);
		info_aux.refe = ient.entity()->ref;
		olv_limp->iaso[info_aux.refe]=info_aux;
	}

	//////////////////////////////////////////////////////////////////////////
	//rellena la información asociada de la red: 
	//sentidos de circulación, velocidad de la vía...
	if(!rellena_info_nw())
	{
		pon_mi_msg("Error al leer info asociada a red navegable: %s", err_str);
		return FALSE;
	}

	////////////////////

	olvlog(LOG_TODO,"olv_limp_t","Finaliza Abrir datos con éxito");

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la información asociada de la red navegable y los datos de limpieza
 */
BOOL Colv_limp_thr::rellena_datos()
{	
	if(!rellena_info_amb())
	{
		pon_mi_msg("Error al leer info asociada a ámbitos: %s", err_str);
		return FALSE;
	}

	olvlog(LOG_TODO,"olv_limp_t","Finaliza Rellena datos con éxito");

	return TRUE;
}
//*************************************************************************************
/**
 * Comrpueba las entidades para adecuarlas al barrido mixto
 */
void Colv_limp_thr::mejora_barr_mix()
{
	int nthr=n_subthr;
	olvlog(LOG_TODO,"olv_limp_t","Comienza las comprobaciones para el barrido mixto");
	lanza_subthrs(OLV_LIMP_EV_BARRMIX_SUB,nthr);		
}
//*************************************************************************************
/**
 * Comrpueba las entidades para adecuarlas al barrido mixto
 */
BOOL Colv_limp_thr::mejora_barr_mix_fin()
{
	////////////////	
	//para los threads
	para_subthrs();

	return TRUE;
}
//*************************************************************************************
/**
 * Comrpueba las entidades para adecuarlas al barrido mixto
 */
void Colv_limp_thr::mejora_barr_mix_sub(int ithr)
{	
	//recorre los ámbitos 
	int i,j;
	int refe_ace, refe_otro, refe_ant;
	int na_desp,na_ini, na_fin, seg;	
	double lon_ace, lon_otro, pond, lon_ant,da;
	BOOL mal=FALSE;
	BOOL paralelas;
	CartoBaseInfoEntity ient_ace, ient_otro;

	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);
	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Comprueba Barr Mix Ambs %04d a %04d", ithr, na_ini, na_fin);
	seg = GetTickCount();

	//Bucle en los ámbitos
	for(i=na_ini;i<na_fin && !pirate; i++)
	{		
		ient_ace = olv_limp->carto.get(i);
		refe_ace = ient_ace.entity()->ref;

		if(!(olv_limp->iaso[refe_ace].flgs & OLV_LIMP_FLG_AMB_ACE))
			continue;		

		//Se recorre las aceras
		//Por cada acera, se recorre el resto de entidades, y las que sean 
		//bordillo o banda de aparcamiento, comprueba si es paralela
		for(j=0;j<olv_limp->n_amb && !pirate; j++)
		{		
			ient_otro = olv_limp->carto.get(j);
			refe_otro = ient_otro.entity()->ref;
			if((j==i) || !(olv_limp->iaso[refe_otro].flgs & (OLV_LIMP_FLG_AMB_APA|OLV_LIMP_FLG_AMB_BORD)))
				continue;

			//recorre ambas rectas a la par
			//para ello, primero mira cuál es la más larga
			lon_ace = ient_ace.getLong();
			lon_otro = ient_otro.getLong();

			//parte de la más corta, y avanza en pasos del PORC_AVANCE% de su longitud
			if(lon_ace<lon_otro)
			{
				paralelas=barr_mix_paralelas(ient_ace,ient_otro);
			}
			else
			{
				paralelas=barr_mix_paralelas(ient_otro,ient_ace);				
			}
			if(!paralelas)
				continue;

			//marca la acera como nula
			//No pasa nada multithread porque toca cada thread unas aceras
			//indica que no se use ese ámbito para sectorizar, y lo apunta al bordillo con el que se hace 
			if(olv_limp->iaso[refe_ace].refe2==-1)
			{
				//es la primera vez que ecuentra un bordillo paralelo
				olv_limp->iaso[refe_ace].flgs=olv_limp->iaso[refe_ace].flgs | OLV_LIMP_FLG_AMB_NO;
				while(olv_limp->iaso[refe_otro].refe2!=-1)
				{
					refe_otro=olv_limp->iaso[refe_otro].refe2;
				}
				olv_limp->iaso[refe_ace].refe2=refe_otro;				
			}
			else
			{
				//esa acera ya tiene un bordillo paralelo, a este nuevo bordillo se le
				//marca para que no se haga, y se acumula al anterior
				refe_ant=olv_limp->iaso[refe_ace].refe2;
				//marca el nuevo como no 
				olv_limp->iaso[refe_otro].flgs=olv_limp->iaso[refe_otro].flgs | OLV_LIMP_FLG_AMB_NO;
				//coge el anterior
				olv_limp->iaso[refe_otro].refe2=refe_ant;
				//le añade un delta de ancho al anterior para que compense la longitud del nuevo
				lon_ant=olv_limp->carto.getRef(refe_ant).getLong();
				da=lon_otro*olv_limp->iaso[refe_otro].inf_l.ancho/lon_ant;
				olv_limp->iaso[refe_ant].inf_l.ancho+=da;
				//renombra el otro como el anterior, para añadirle la acera
				refe_otro=refe_ant;
			}
			//olv_limp->iaso[refe_ace].refe2=refe_otro;

			//suma los anchos de forma ponderada
			pond=lon_ace/lon_otro;
			if(pond>1)
				pond=1; //cuando la acera es más grande, se suma el ancho de la acera, no se amplia

			//cuando la acera es más pequeña, puede que en ese bordillo o banda de aparcamiento
			//haya otra acera en paralelo, así que se le sumará después su ancho también, 
			//de forma que la suma total sea la ponderación de los anchos
			olv_limp->iaso[refe_otro].inf_l.ancho += olv_limp->iaso[refe_ace].inf_l.ancho*pond;
		}

		//avisa de progreso
		if(((i-na_ini)%100==0) || ((i-na_ini)==(na_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Comprobando Barrido Mixto ambs %ld de %ld", ithr,
				(i-na_ini+1),na_desp);
		}
	}

	if(mal)
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en mejoras Barrido mixto", ithr);
		prog_subthr=-1;//para avisar al padre de que ha habido un error
	}
	else
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin mejoras Barrido mixto, %.3f seg", ithr, 1.0*(GetTickCount()-seg)/1000);
	}
	thr_padre->encola(OLV_LIMP_EV_BARRMIX_FIN,NULL,FALSE);

}
//*************************************************************************************
/**
 * Avanza desde el primer punto de ient1 y el más próximo en ient2, 
 * midiendo la distancia entre las dos rectas
 * devuelve si son paralelas o no en función de la dmedia y la desv
 */
BOOL Colv_limp_thr::barr_mix_paralelas(CartoBaseInfoEntity ient1, CartoBaseInfoEntity ient2)
{
	const double PORC_AVANCE = 0.2; //avanza en pasos del porc % de la longitud de la línea pequeña
	////////////////////////////////////
	double l_avan, dmed, desv, l_parc, long1, dis;	
	int n;
	double pt[3];

	//comprueba si las puede descartar porque estén muy lejos
	//mira si la distancia mínima del primer punto de ient1 a ient2 
	//es muy grande para descartar
	if((ient2.DisPtoLine(ient1.getPto(0))>OLV_BARRMIX_DMAX_DESC) && (ient2.DisPtoLine(ient1.getPto(ient1.getNumberPtos()-1))>OLV_BARRMIX_DMAX_DESC))
		return FALSE;	

	l_parc=0;
	long1=ient1.getLong();
	l_avan=PORC_AVANCE*long1;
	n=(int)(1/PORC_AVANCE+0.5);
	dmed=desv=0;
	while(l_parc<long1)
	{
		dis=ient2.DisPtoLine(ient1.GetPtoDis(l_parc, pt, &long1));
		dmed+=dis/n;
		desv+=GeometryFunction::Poten(dis)/n;
		l_parc+=l_avan;
	}

	desv=sqrt(desv-GeometryFunction::Poten(dmed));

	if(dmed>OLV_BARRMIX_DMED_MAX || desv>OLV_BARRMIX_DESV_MAX)
		return FALSE;

	return TRUE;
}
//*************************************************************************************
/**
 * Copia en las aceras que no se han usado para sectorizar porque se han asignado a bordillos o
 * bandas de aparcamiento, el mismo sector que el bordillo que tienen asignado
 * modo 0 secto, modo 1 planif
 */
void Colv_limp_thr::copia_info_barr_mix()
{
	for(int i=0;i<olv_limp->n_amb;i++)
	{
		if(!(olv_limp->iaso[i].flgs & OLV_LIMP_FLG_AMB_NO) || olv_limp->iaso[i].refe2<0)
			continue;

		olv_limp->amb_sec[i].sec=olv_limp->amb_sec[olv_limp->iaso[olv_limp->iaso[i].refe2].iamb].sec;
		olv_limp->amb_sec[i].iseq=olv_limp->amb_sec[olv_limp->iaso[olv_limp->iaso[i].refe2].iamb].iseq;
	}
}
//*************************************************************************************
/**
 * Rellena la información de sentidos de circulación y velocidad de las vías
 * en la tabla de información asociada
 */
BOOL Colv_limp_thr::rellena_info_nw()
{
	Cb_file file;
	Fdbf dbf;
	int n,ntf, nft, nboth, nno,s,ia;
	int icamps,icampv,icampn,icampf,f,idd, icampoid;
	char nfile[MAX_PATH];
	char *sent;
	BOOL ret=TRUE,ispedestrian;

	olvlog(LOG_TODO,"olv_limp_t","Rellenando matriz de info asociada a carreteras");
	pon_mi_progre(OLV_TAREA_IMP, (int) (OliviaDef::GeneralDef::ProgrMax*1/3)); //1/32 porque ya ha hecho 1/3, que es la importación
	
	ntf=nft=nboth=nno=0;
	sent=NULL;

	//si no aplican los sentidos de circulación no se calculan, se ponen todos a todos sentidos
	if(olv_limp->res_circ==OLV_RES_NO)
	{
		olvlog(LOG_TODO,"olv_limp_t","No aplican sentidos de circulación, puestos todos a 'ambos'");
		nboth=olv_limp->n_nw;
	}

	//lee dbf del shp
	strcpy_s(nfile,MAX_PATH,olv->paths.path_nw);
	char bufAux[256];
	strcpy(nfile, Cdir_manager::cambia_extension_archivo(nfile,bufAux,".dbf"));
	//cambiaext(nfile,".shp",".dbf");
	if(!file.abre(nfile,1) || !dbf.lee(&file))
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al abrir %s",nfile);
		olvlog(LOG_TODO,"olv_limp_t","Error al abrir %s",nfile);
		return FALSE;
	}

	//busca el campo del sentido "ONEWAY" y el de "KPH"
	icamps=icampv=icampn=icampf=-1;
	icamps=dbf.findCol(olv_limp->camps.campo_circ);
	icampv=dbf.findCol(olv_limp->camps.campo_velo);
	icampn=dbf.findCol(olv_limp->camps.campo_name);
	icampf=dbf.findCol(olv_limp->camps.campo_fow);
	if(icamps==-1 || icampv==-1 || icampn==-1 || icampf==-1)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s y/o %s y/o %s en\n%s",olv_limp->camps.campo_circ,
			olv_limp->camps.campo_velo,olv_limp->camps.campo_name,nfile);
		olvlog(LOG_TODO,"No encontrado campo %s y/o %s y/o %s en\n%s",olv_limp->camps.campo_circ,
			olv_limp->camps.campo_velo,olv_limp->camps.campo_name,nfile);
		return FALSE;
	}
	icampoid=dbf.findCol(OLV_NOMB_OID);
	
	////////////////////////////////////////
	sent = (char*)malloc(dbf.getSize(icamps)+1);
	if(!sent)
		return FALSE;
	sent[0]=0;
	idd =dbf.leeNexRow();
	n=0;
	ia=olv_limp->n_amb;//la info aso de la nw empieza donde acaba la de los ámbitos
	while(idd == 1)
	{		
		///////////////////////////////
		ispedestrian=FALSE;
		if(olv_limp->res_circ!=OLV_RES_NO)
		{		
			//("FOW" =3 OR "FOW">=7) AND ("ONEWAY" = 'N' OR "ONEWAY" = ' ' )
			//si se cumple lo anterior, son como doble sentido pero no se replican
			//////////////////////////
			//sentido de circulación
			strcpy(sent,dbf.getStr(icamps));
			s=0;
			if(strcmp(sent,olv_limp->camps.atr_circ[OLV_ATR_CIRC_TF])==0)
			{
				s=OLV_LIMP_FLG_CIRC_TF;
				ntf++;
			}
			else if(strcmp(sent,olv_limp->camps.atr_circ[OLV_ATR_CIRC_FT])==0)
			{
				s=OLV_LIMP_FLG_CIRC_FT;
				nft++;
			}
			else if(strcmp(sent,olv_limp->camps.atr_circ[OLV_ATR_CIRC_NONE])==0)
			{
				//no aplica la restricción por ser servicio público, cómo se sabe si es de un único sentido?
				s=OLV_LIMP_FLG_CIRC_NONE;
				nno++;
			}
			else
			{
				nboth++;
			}

			///////////////////////////////
			//fow
			f=dbf.getI(icampf);			
			//solo mira si es pedestrian, f==14
			if(f==atoi(olv_limp->camps.atr_circ[OLV_ATR_CIRC_PEDES]) || f==-1)
			{
				s=OLV_LIMP_FLG_CIRC_NONE;
				ispedestrian=TRUE;
			}
			///////////////////////////////

			olv_limp->iaso[ia].flgs|=s;	
		}
		
		///////////////////////////////
		//velocidad
		if((olv_limp->iaso[ia].flgs & OLV_LIMP_FLG_CIRC_NONE) || ispedestrian)
		{
			s= OLV_LIMP_VELO_CIRC_PEAT;	//se le pone velo muy bajita para que intente no ir por ahí, porque son calles prohibidas
					//a no ser que haya un contenedor
					//o si es peatonal igual, que no haga las rutas por ahí, pero sí pase a hacer tratamientos
		}
		else
		{	
			s=dbf.getI(icampv);
		}
		if(s<=0)
		{
			s=OLV_LIMP_VELO_DEF;//pone por def	
		}		

		olv_limp->iaso[ia].inf_n.velo=1.0*s*OLV_KMH2MS;

		///////////////////////////////
		//nombre	
		olv_limp->iaso[ia].inf_n.nomb = (char*)malloc(dbf.getSize(icampn)+1);
		if(!olv_limp->iaso[ia].inf_n.nomb)
			break;
		strcpy(olv_limp->iaso[ia].inf_n.nomb,dbf.getStr(icampn));

		if(icampoid>=0)
			olv_limp->iaso[ia].oid = dbf.getI(icampoid);

		///////////////////////////////
		//avisa de progreso
		if((n%200==0) || (n==(olv_limp->n_nw+olv_limp->n_amb-1)))
		{
			pon_mi_progre(OLV_TAREA_IMP, (int) (OliviaDef::GeneralDef::ProgrMax*
				(1.0*(n+1)/olv_limp->n_nw/3)+1/3));//por 2/3 porque esta tarea es la 2/3
			olvlog(LOG_TODO,"olv_limp_t","Rellenando info asociada a nw, %ld de %ld",
				n+1,olv_limp->n_nw);
		}

		ia++;
		n++;
		idd =dbf.leeNexRow();

	}
	if(n<olv_limp->n_nw)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al leer record %ld en\n%s",ia,nfile);
		ret=FALSE;
		goto fin;
	}

	olvlog(LOG_TODO,"olv_limp_t","Finaliza matriz de info asociada a carreteras: %ld doble sentido, %ld TF, %ld FT, %ld ninguno, %ld de %ld",
		nboth,ntf,nft, nno, nboth+ntf+nft+nno, olv_limp->n_nw);	
	
fin:
	if(sent)
		free(sent);

	return ret;
}
//*************************************************************************************
/**
 * Rellena la información de ancho de los ámbitos
 * en la tabla de información asociada
 */
BOOL Colv_limp_thr::rellena_info_amb()
{
	Cb_file f;
	Fdbf dbf;
	int icampa,icampo,icampta,icampte,idd,ia, icampoid;
	char *tipent, *tipap, *obs,*anc;
	double ancho;
	BOOL ret=TRUE,modo_ejes=FALSE;
	int barr_mix=0; 
	char nfile[MAX_PATH];

	//en principio, tipos puntuales no tienen info asociada
	if(olv_limp->tipo_ambit==OLV_AMB_PUN)
		return TRUE;

	//cuando se ha enviado eje de calle, no se lee info asociada porque la tabla es de tomotom, no tiene info
	//tipo entidad ni nada..
	if((olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMh_eje) || 
		(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoM2h_eje))
		modo_ejes= 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));

	tipent=tipap=obs=anc=NULL;

	//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 observaciones, de ancho_tipo, de tipo_entidad y tipología_aparc
	icampo=dbf.findCol(olv_limp->camps.campo_obs);
	icampa=dbf.findCol(olv_limp->camps.campo_anch);
	icampta=dbf.findCol(olv_limp->camps.campo_tipo_ap);
	icampte=dbf.findCol(olv_limp->camps.campo_tipo_ent);
	if(!modo_ejes && (icampa==-1 || icampo==-1 || icampta==-1 || icampte==-1))
	{
		sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s y/o %s y/o %s\ny/o %s en\n%s",olv_limp->camps.campo_obs,olv_limp->camps.campo_anch,
			olv_limp->camps.campo_tipo_ap,olv_limp->camps.campo_tipo_ent,nfile);
		ret=FALSE;
		goto fin;
	}	
	icampoid=dbf.findCol(OLV_NOMB_OID);

	if(!modo_ejes)
	{
		tipent = (char*)malloc(dbf.getSize(icampte)+1);
		tipap = (char*)malloc(dbf.getSize(icampta)+1);
		obs = (char*)malloc(dbf.getSize(icampo)+1);
		anc = (char*)malloc(dbf.getSize(icampa)+1);
		if(!tipent || !tipap || !obs || !anc)
			return FALSE;
	}

	idd =dbf.leeNexRow();
	ia=0;
	while(idd == 1)
	{
		if(!modo_ejes)
		{		
			//si el campo tipo de entidad es banda_aparcamiento, el ancho es fijo, 
			//en función de la tipología del aparcamiento
			//si no, hay que leer el ancho
			ancho=OLV_LIMP_ANCH_DEF;

			///////////////////////////////
			strcpy(tipent,dbf.getStr(icampte));
			if(strlen(tipent)>0 && strcmp(tipent,olv_limp->camps.atr_tip_ent[OLV_ATR_NOM_TIP_ENT_AP])==0)
			{
				//es banda de aparcamiento
				strcpy(tipap,dbf.getStr(icampta));
				if(strlen(tipap)>0 && strcmp(tipap,olv_limp->camps.atr_tip_apa[OLV_ATR_TIP_AP_LIN])==0)
				{
					//es aparcamiento lineal, ancho fijo 2
					ancho=olv_limp->anchos_def[OLV_ANCH_DEF_APLIN];
				}
				else if(strlen(tipap)>0 && strcmp(tipap,olv_limp->camps.atr_tip_apa[OLV_ATR_TIP_AP_BAT])==0)
				{
					//es aparcamiento en batería, ancho fijo 4
					ancho=olv_limp->anchos_def[OLV_ANCH_DEF_APBAT];
				}
				
				//lo marca para saber si es barrido mixto
				olv_limp->iaso[ia].flgs |= OLV_LIMP_FLG_AMB_APA;
				if(!olv_limp->barr_mix && !(barr_mix & OLV_LIMP_FLG_AMB_APA))
					barr_mix |= OLV_LIMP_FLG_AMB_APA;
			}
			else if(strlen(tipent)>0 && strcmp(tipent,olv_limp->camps.atr_tip_ent[OLV_ATR_NOM_TIP_ENT_BORD])==0)
			{
				//es bordillo libre
				ancho=olv_limp->anchos_def[OLV_ANCH_DEF_BORD];

				//lo marca para saber si es barrido mixto
				olv_limp->iaso[ia].flgs |= OLV_LIMP_FLG_AMB_BORD;
				if(!olv_limp->barr_mix && !(barr_mix & OLV_LIMP_FLG_AMB_BORD))
					barr_mix |= OLV_LIMP_FLG_AMB_BORD;
			}
			else if(strlen(tipent)>0)
			{
				//es acera o peatonal
				//hay que leer el ancho	
				strcpy(obs,dbf.getStr(icampo));
				strcpy(anc,dbf.getStr(icampa));

				ancho = olv_limp->dame_ancho(obs,anc);			
						
				if(strcmp(tipent,olv_limp->camps.atr_tip_ent[OLV_ATR_NOM_TIP_ENT_ACERA])==0)
				{
					if(ancho==0)
						ancho=olv_limp->anchos_def[OLV_ANCH_DEF_ACE];//acera

					//lo marca para saber si es barrido mixto
					olv_limp->iaso[ia].flgs |= OLV_LIMP_FLG_AMB_ACE;
					if(!olv_limp->barr_mix && !(barr_mix & OLV_LIMP_FLG_AMB_ACE))
						barr_mix |= OLV_LIMP_FLG_AMB_ACE;
				}
				else if(strcmp(tipent,olv_limp->camps.atr_tip_ent[OLV_ATR_NOM_TIP_ENT_PEAT])==0)
				{
					if(ancho==0)
						ancho=olv_limp->anchos_def[OLV_ANCH_DEF_PEAT];//peatonal
					
					olv_limp->iaso[ia].flgs |=OLV_LIMP_FLG_AMB_PEAT;
				}
				else
					if(ancho==0)
						ancho = OLV_LIMP_ANCH_DEF;
				
			}		
			olv_limp->iaso[ia].inf_l.ancho=ancho;	

			///////////////////////////////
			//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);
			}

			if(!olv_limp->barr_mix)
				olv_limp->barr_mix=(barr_mix & (OLV_LIMP_FLG_AMB_APA | OLV_LIMP_FLG_AMB_BORD)) && (barr_mix & OLV_LIMP_FLG_AMB_ACE);
		}
		if(icampoid>=0)
			olv_limp->iaso[ia].oid = dbf.getI(icampoid);

		ia++;
		idd =dbf.leeNexRow();
	}

	//olv_limp->barr_mix=FALSE;

	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(tipent)
		free(tipent);
	if(tipap)
		free(tipap);
	if(obs)
		free(obs);
	if(anc)
		free(anc);

	return ret;
}
//*************************************************************************************
/**
 * Replica los ámbitos cuando son tipo peatonal, añadiendo otro lineal igual que tendrá solo coste
 * de desplazamiento, no de tratamiento, más los segmentos que los unen, de coste 0
 */
BOOL Colv_limp_thr::replica_peat()
{
	int i,j,k;
	CartoBaseInfoEntity ient, ientcp;
	CartoLine peatcp;
	Info_aso2 info_aux;
	double ptos[2][3];
	CartoLine ptos_aux;
	ptos_aux.pts.n = 2;
	ptos_aux.pts.ptr = ptos;

	olvlog(LOG_TODO,"olv_limp_t","Replicando calles peatonales");

	peatcp.idPropsP =0;
	for(i=0;i<olv_limp->n_amb; i++)
	{
		ient=olv_limp->carto.get(i);
		if(!(olv_limp->iaso[ient.entity()->ref].flgs & OLV_LIMP_FLG_AMB_PEAT))
			continue;

		//Replica la peatonal
		if(!ient.getCopy(&peatcp) || !olv_limp->carto.add(peatcp))
			break;
		ientcp=olv_limp->carto.get(olv_limp->carto.getNumberEntities()-1);

		//Añade la info aso
		info_aux.reset();
		info_aux.flgs=OLV_LIMP_FLG_PEAT_REP;
		info_aux.refe=ientcp.entity()->ref;
		info_aux.refe2=ient.entity()->ref;	
		olv_limp->iaso[info_aux.refe]=info_aux;

		//añade los dos extremos
		for(j=0;j<2;j++)
		{			
			for(k=0;k<2;k++)
			{
				memcpy(ptos[k],ient.getPto(j),3*sizeof(double));
			}
			//lo añade al carto
			olv_limp->carto.add(ptos_aux);
			ientcp=olv_limp->carto.get(olv_limp->carto.getNumberEntities()-1);
			//Añade la info aso
			info_aux.reset();
			info_aux.flgs=OLV_LIMP_FLG_PEAT_SEG | (j*OLV_LIMP_FLG_FIN);
			info_aux.refe=ientcp.entity()->ref;
			info_aux.refe2=ient.entity()->ref;	
			olv_limp->iaso[info_aux.refe]=info_aux;
		}
	}
	ptos_aux.pts.ptr = NULL;
	if(i<olv_limp->n_amb)
		return FALSE;

	return TRUE;
}
//*************************************************************************************
/**
 * Replica las calles cuando son de doble sentido y se tienen en cuenta las restricciones 
 * de circulación, para que se asignen los ámbitos sólo a la calle del sentido en el que estén
 */
BOOL Colv_limp_thr::replica_doble_sent(Info_inw_dmin *inww_ord)
{
	int i,KK,iaux;
	unsigned short refnw;
	CartoBaseInfoEntity ientamb, ientcp, ientnw;
	CartoLine nwcp;
	Info_aso2 info_aux;

	if(olv_limp->res_circ<OLV_RES_RECOGER_SOLO_LADO_Y_GIROS)
		return TRUE;

	KK=olv_limp->tipo_ambit;
	nwcp.idPropsP=0;

	//recorre los ámbitos viendo a qué calle están asignados, y si es a una
	//de doble sentido, se replica la calle y se pone cada una de un sentido, y se asigna
	//el ámbito a la calle de la que esté a la derecha
	//recorre el array de info nw
	for(i=0;i<olv_limp->n_amb*KK;i++)
	{   
		refnw=inww_ord[i].refnw;	
		if(!(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_NW) || 
			(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_CIRC_NO_DOB))
			continue;

		ientamb = olv_limp->carto.getRef(inww_ord[i].refamb);
		ientnw = olv_limp->carto.getRef(refnw);

		//Replica la calle
		if(!ientnw.getCopy(&nwcp) || !olv_limp->carto.add(nwcp))
			break;
		ientcp=olv_limp->carto.get(olv_limp->carto.getNumberEntities()-1);

		//le pone a la calle original que es solo FT
		olv_limp->iaso[refnw].flgs |= OLV_LIMP_FLG_CIRC_FT;
		//Añade la info aso de la copia
		info_aux.reset();
		info_aux.flgs=OLV_LIMP_FLG_NW | OLV_LIMP_FLG_NW_REP | OLV_LIMP_FLG_CIRC_TF;
		info_aux.refe=ientcp.entity()->ref;
		//copia la velo y el nombre
		info_aux.inf_n.velo=olv_limp->iaso[refnw].inf_n.velo;	
		info_aux.inf_n.nomb = (char*)malloc(strlen(olv_limp->iaso[refnw].inf_n.nomb)+1);
		if(!info_aux.inf_n.nomb)
			break;
		strcpy(info_aux.inf_n.nomb,olv_limp->iaso[refnw].inf_n.nomb);
		info_aux.refe2=refnw;
		//añade la info
		olv_limp->iaso[info_aux.refe]=info_aux;

		//////////////////////////////////////////////
		//busca los ámbitos apuntados a ese nw, los que están a la izquiera les reapunta
		iaux=i;
		while((iaux<olv_limp->n_amb*KK) && (inww_ord[iaux].refnw==refnw))
		{
			if(!(olv_limp->iaso[inww_ord[iaux].refamb].flgs & OLV_LIMP_FLG_DER))
			{				
				inww_ord[iaux].refnw=info_aux.refe;//el lineal que acaba de añadir
				//reapunta también el original
				olv_limp->inww_amb[(int)inww_ord[iaux].alpha].refnw=info_aux.refe;
				/////////////////////////////
				olv_limp->iaso[inww_ord[iaux].refamb].flgs |= OLV_LIMP_FLG_DER;
			}
			iaux++;

		}
		i=iaux-1;

	}
	if(i<olv_limp->n_amb*KK)
		return FALSE;

	return TRUE;
}
//*************************************************************************************
/**
 * Une la red navegable y los ámbitos
 * 'soloi' es para debug, indica si se quiere realizar la unión de un único ámbito pasado en soloi
 */
BOOL Colv_limp_thr::une_amb_nw(int soloi)
{
	int KK,i,refamb,k;
	CartoBaseInfoEntity iamb;
	BOOL comp_lejos,modo_ejes=FALSE;

	comp_lejos=(olv_limp->res_circ<OLV_RES_RECOGER_SOLO_LADO_Y_GIROS) && ((olv_limp->uds_tto!=OliviaDef::GeneralDef::OlvTipTtoMh_eje) && 
		(olv_limp->uds_tto!=OliviaDef::GeneralDef::OlvTipTtoM2h_eje));


	//si es tipo ejes, lo hace de otra forma
	if((olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMh_eje) || 
		(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoM2h_eje))
	{
		modo_ejes=TRUE;
	}
	//////////////////
	//coge el factor del tipo de ámbito, 1 si es puntual, 2 si es lineal
	KK=olv_limp->tipo_ambit;

	//////////////////
	//replica las peatonales que sea necesario
	if(KK==OLV_AMB_LIN)
	{
		if(!replica_peat())
		{
			pon_mi_msg("Error al replicar peatonales");
			return FALSE;
		}
	}

	//////////////////		
	//inicia cuando ya sabe si es tipo lineal o puntual	
	if(!olv_limp->inww_amb)
	{
		olv_limp->inww_amb = (Info_inw_dmin *)malloc(olv_limp->n_amb*KK*sizeof(Info_inw_dmin));
	}
	if(!olv_limp->inww_amb)
	{
		pon_mi_msg("Error, sin memoria para matriz de índices\nde ámbitos a carreteras");
		return FALSE;
	}
	//rellena todos a no def
	for(i=0;i<olv_limp->n_amb*KK;i++)
	{
		olv_limp->inww_amb[i].reset(i%olv_limp->n_amb);
	}
	///////////////////
	olvlog(LOG_TODO,"olv_limp_t","Uniendo ámbitos a NW");
	pon_mi_progre(OLV_TAREA_UNE_NW_AMB, 0);
	pon_mi_msg("");
	err_str[0]=0;

	//Bucle por ámbito
	for(i=0;i<olv_limp->n_amb && !pirate; i++)
	{
		if((soloi>-1) && (soloi<olv_limp->n_amb) && (i!=soloi))
			continue;//para debug, si soloi apunta al ámbito que queremos calcular solo

		iamb = olv_limp->carto.getEntity(i);
		refamb=iamb.entity()->ref;
		if(olv_limp->iaso[refamb].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;

		//rellena en inww_amb el inw y su info de la carretera del nw élegida como
		//más cercana al ámbito
		if(modo_ejes)
			busca_inw_dmin_ejes(i);
		else
			busca_inw_dmin(i);	

		////////////////////////////////////////////
		//comprueba en todos los ámbitos si va andando, si están asignados a una carretera muy lejos
		//y tienen un ámbito más cerca, les asigna ese (excepto en el caso ejes)
		if(comp_lejos)
			comprueba_amb_lejos(i);

		if((i%100==0) ||(i==(olv_limp->n_amb-1)))
		{		
			olvlog(LOG_TODO,"olv_limp_t","Uniendo ámbitos a NW, %ld de %ld",i+1,olv_limp->n_amb);
			//avisa de progreso
			pon_mi_progre(OLV_TAREA_UNE_NW_AMB, (int) ((OliviaDef::GeneralDef::ProgrMax*
				(i+1)/olv_limp->n_amb)*((olv_limp->tipo_ambit==OLV_AMB_LIN ? 0.5 : 1))));	
		}
	}
	//cuida si ha salido antes por falta de memo
	if(i<olv_limp->n_amb)
	{
		pon_mi_msg("Error en la unión de ámbitos a red navegable");
		return FALSE;
	}	
	//Bucle por ámbito
	for(i=0;i<olv_limp->n_amb && !pirate; i++)
	{
		if((soloi>-1) && (soloi<olv_limp->n_amb) && (i!=soloi))
			continue;//para debug, si soloi apunta al ámbito que queremos calcular solo

		iamb = olv_limp->carto.getEntity(i);
		refamb=iamb.entity()->ref;
		if(olv_limp->iaso[refamb].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;

		//Añade los segmentos a clase NW_union
		add_uniones_obj(i);
	}

	//cuida si ha salido antes por falta de memo
	if(i<olv_limp->n_amb)
	{
		pon_mi_msg("Error en la unión de ámbitos a red navegable");
		return FALSE;
	}	

	if(comp_lejos) //ojo
		comprueba_aislados(olv_limp->inww_amb);

	/////////////////////////////////////////////////////
	//si hay algún ámbito asignado a una carretera de prohibido circular
	//se le quita el flag a la carretera
	if(olv_limp->res_circ!=OLV_RES_NO)
	{
		for(i=0;i<olv_limp->n_amb && !pirate; i++)
		{
			refamb=olv_limp->carto.getEntity(i).entity()->ref;
			if(olv_limp->iaso[refamb].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			for(k=0; k<KK;k++)
			{			
				if(olv_limp->iaso[olv_limp->inww_amb[i + k*olv_limp->n_amb].refnw].flgs & 
					OLV_LIMP_FLG_CIRC_NONE)
				{
					//le quita el flag
					olv_limp->iaso[olv_limp->inww_amb[i + k*olv_limp->n_amb].refnw].flgs = 
						olv_limp->iaso[olv_limp->inww_amb[i + k*olv_limp->n_amb].refnw].flgs & ~OLV_LIMP_FLG_CIRC_NONE;
				}
			}
		}
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Como se ha podido unir unos ámbitos a otros, revisa que no se hayan unido sólo entre sí
 * y no a ninguna carretera, en ese caso estarían aislados. Lo revisa para, en esos casos,
 * forzar a que apunte alguno a una carretera
 */
void Colv_limp_thr::comprueba_aislados(Info_inw_dmin *inww)
{
	int i,KK,iamb,k,j, refamb;
	BYTE *ambs_flgs;
	int *ambs_cola;
	int ncola;
	BOOL aislado;
	double dmin;
	int iambmin;

#define FLG_VISTO	1
#define FLG_TEMP	2

	KK=olv_limp->tipo_ambit;
	//inicia el array de flags
	ambs_flgs = (BYTE*)malloc(olv_limp->n_amb);
	if(!ambs_flgs)
		return;
	memset(ambs_flgs,0,olv_limp->n_amb);
	//inicia la cola
	ambs_cola = (int*)malloc(olv_limp->n_amb*sizeof(int));
	if(!ambs_cola)
		return;
	memset(ambs_cola,0,olv_limp->n_amb*sizeof(int));
	ncola=0;	

	//bucle para cada ámbito
	for(i=0;i<olv_limp->n_amb && !pirate; i++)
	{
		if(ambs_flgs[i] & FLG_VISTO)
			continue;

		refamb=olv_limp->carto.getEntity(i).entity()->ref;
		if(olv_limp->iaso[refamb].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;
		aislado=TRUE;
		//lo mete a la cola
		ambs_cola[ncola]=i;
		ncola=1;

		while (ncola)
		{
			//saca ámbito de la cola
			ncola--;
			iamb=ambs_cola[ncola];

			//le pone el flag temporal
			ambs_flgs[iamb] |= FLG_TEMP;

			//bucle en los dos extremos
			for(k=0;k<KK;k++)
			{
				if(!(olv_limp->iaso[inww[iamb+k*olv_limp->n_amb].refnw].flgs & OLV_LIMP_FLG_NW))
				{
					//lo mete en la cola si su extremo es un ámbito
					//no visto ni temporal
					if(ambs_flgs[inww[iamb+k*olv_limp->n_amb].refnw] & (FLG_TEMP | FLG_VISTO))
						continue;
					ambs_cola[ncola]=inww[iamb+k*olv_limp->n_amb].refnw;
					ncola++;
				}
				else
					aislado=FALSE;
			}
		}

		if(aislado)
		{				
			//es una aislada o grupo de aisladas, 
			//deja apuntada a una nw la de distancia menor
			dmin=MAYUSCULO;
			iambmin=-1;
			for(j=0;j<olv_limp->n_amb; j++)
			{
				if(!(ambs_flgs[j] & FLG_TEMP))
					continue;

				for(k=0;k<KK;k++)
				{
					if(!inww[j+k*olv_limp->n_amb].inw_old)
						continue;//no debería
					if(inww[j+k*olv_limp->n_amb].inw_old->dmin<dmin)
					{
						iambmin=j+k*olv_limp->n_amb;
						dmin=inww[j+k*olv_limp->n_amb].inw_old->dmin;
					}
				}
			}
			if(dmin<MAYUSCULO && iambmin>=0)
			{
				//reapunta a la inw old
				memcpy(&inww[iambmin],inww[iambmin].inw_old,sizeof(Info_inw_dmin));				
				free(inww[iambmin].inw_old);
				inww[iambmin].inw_old=NULL;

				//añade el segmento de unión
				add_uniones_obj(iambmin%olv_limp->n_amb);
			}
		}

		//todos los estudiados, que son los del flag temporal, los pone como vistos
		for(j=0;j<olv_limp->n_amb; j++)
		{
			if(ambs_flgs[j] & FLG_TEMP)
			{
				ambs_flgs[j] = ambs_flgs[j] & ~FLG_TEMP;
				ambs_flgs[j] = ambs_flgs[j] | FLG_VISTO; //le quita el flag temporal y le pone el de visto
			}
		}		
	}

	free(ambs_flgs);
	free(ambs_cola);
}
//*************************************************************************************
/**
 * Comprueba en 'inww' si 'daux' es menor que las almacenadas.
 * Devuelve la posición del array inww donde tiene que ir o -1 si no es menor
 * y vacía dicha posición, moviendo las demás, para que el siguiente guarde ahí lo que toca
 */
int Colv_limp_thr::is_dmin(double daux, Info_inw_dmin *inww)
{
	int i=-1,k;

	if(!inww)
		return i;
	
	for(i=0; i<OLV_LIMP_N_DMIN_NW;i++)
	{
		if(daux<inww[i].dmin)
		{
			for(k=OLV_LIMP_N_DMIN_NW-2;k>=i; k--)
			{
				memcpy(&inww[k+1], &inww[k],sizeof(Info_inw_dmin));
			}
			break;
		}
	}
	if(i>=OLV_LIMP_N_DMIN_NW)
		i=-1;
	
	return i;
}
//*************************************************************************************
/**
 * Devuelve la ent de la nw que esté más cerca del ámbito iamb, a la que se le asigna
 */
BOOL Colv_limp_thr::busca_inw_dmin_ejes(int i_amb)
{
	CartoBaseInfoEntity ientnw, ientamb;
	int refamb, refenw,inw,z,npts,k;
	//se recorre las nw buscando el mismo oid
	ientamb=olv_limp->carto.getEntity(i_amb);
	refamb=ientamb.entity()->ref;
	npts=ientamb.getNumberPtos();
	////////////////////////////////////////////////////////////////////////
	//Bucle por cada carretera de la nw
	//empiezan donde acaban los ámbitos, y terminan en namb+nnw
	for(inw=olv_limp->n_amb; inw<olv_limp->n_amb+olv_limp->n_nw && !pirate; inw++)
	{
		ientnw=olv_limp->carto.getEntity(inw);
		refenw=ientnw.entity()->ref;
		if(!(olv_limp->iaso[refenw].flgs & OLV_LIMP_FLG_NW))
			continue; //no debería, pero por si acaso

		if(olv_limp->iaso[refenw].oid==olv_limp->iaso[refamb].oid)
			break;
	}
	if(inw>=olv_limp->n_amb+olv_limp->n_nw || pirate)
		return FALSE;

	//ha encontrado la nw, la pone en inww
	//para el punto inicial y final, o solo una vez si es puntual
	for(k=0; k<2; k++)
	{
		z=i_amb+k*olv_limp->n_amb;
		olv_limp->inww_amb[z].reset();	
		olv_limp->inww_amb[z].refnw=refenw;
		olv_limp->inww_amb[z].dmin=0;
		olv_limp->inww_amb[z].ip=k*(npts-2);
		olv_limp->inww_amb[z].lamb=(float)k;
		memcpy(olv_limp->inww_amb[z].pt,ientamb.getPto(k*(npts-1)),3*sizeof(double));
		//copia info de qué amb y qué punto ini o fin es, para poder recuperar cuando está ordenador por inw
		olv_limp->inww_amb[z].refamb=refamb;
		olv_limp->inww_amb[z].alpha=(float)(z);
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Devuelve la distancia de un ámbito 'i_amb' a la carretera más cercana, 
 * y rellena la info de dicha carretera en inww_amb.
 * KK indica el tipo de ámbito, si es 1 es puntual, sólo se calcula una distancia a la carretera,
 * si es 2, es lineal, se calculan la distancia al extremo inicial y al final 
 */
BOOL Colv_limp_thr::busca_inw_dmin(int i_amb)
{
	Info_inw_dmin	inwaux, inww[OLV_LIMP_N_DMIN_NW*2];	//Almacena las N mejores carreteras del punto inicial y las N del punto final
	CartoLine prime_ptos_i, prime_ptos_f, prime_ptos, ptos_aux;
	double lon, disptos, daux, alphamin[2], desv,lamb;
	int i, inw, refenw,k,i_inww,j,jmin[2],i_nw,KK,refamb,ip;
	CartoBaseInfoEntity ientnw, ientamb;
	double pt_ang[2][3], *p0, *p1, prod, mod1, mod2;	//almacena dos puntos para calcular el vector con el que forma el ángulo el ámbito

	////////////////////////////
	//esto se hace porque se sabe que son siempre 2 puntos, y así no se pide memoria
	//dinámica en el garray
	ptos_aux.pts.n = 2;
	ptos_aux.pts.ptr =pt_ang;
	////////////////////////////
	ientamb=olv_limp->carto.getEntity(i_amb);
	refamb=ientamb.entity()->ref;
	KK=olv_limp->tipo_ambit;



	//inicializa array local para almacenamiento de las tres carreteras más cercanas
	memset(inww,0,sizeof(Info_inw_dmin)*OLV_LIMP_N_DMIN_NW*2);
	for(i=0; i<OLV_LIMP_N_DMIN_NW*2;i++)
		inww[i].reset();

	////////////////////////////////////////////////////////////////////////	
	//inicia variables para cálculo de distancias, con respecto al ámbito actual
	if(KK==OLV_AMB_LIN)//para tipo lineal, obtiene los primeros puntos de los dos extremos
	{
		lon=ientamb.getLong();
		disptos=min(OLV_LIMP_N_PTOS_DIST,lon);
		ientamb.GetNPrimePtos(&prime_ptos_i,OLV_LIMP_N_PTOS_MED,disptos,TRUE);
		ientamb.GetNPrimePtos(&prime_ptos_f,OLV_LIMP_N_PTOS_MED,disptos,FALSE);
	}

	////////////////////////////////////////////////////////////////////////
	//Bucle por cada carretera de la nw
	//empiezan donde acaban los ámbitos, y terminan en namb+nnw
	for(inw=olv_limp->n_amb; inw<olv_limp->n_amb+olv_limp->n_nw && !pirate; inw++)
	{
		ientnw=olv_limp->carto.getEntity(inw);
		refenw=ientnw.entity()->ref;
		if(!(olv_limp->iaso[refenw].flgs & OLV_LIMP_FLG_NW))
			continue; //no debería, pero por si acaso

		//lo hace para punto inicial y final si es lineal, o solo una vez si es puntual
		for(k=0; k<KK;k++) 
		{
			inwaux.reset();	
			inwaux.refnw=refenw;

			if(KK==OLV_AMB_LIN)
			{		
				//calcula la daux media de 3 puntos desde los extremos del ámbito
				if(k==0)
					prime_ptos = prime_ptos_i;
				else
					prime_ptos = prime_ptos_f;

				//necesita una función que dé la distancia media de prime_ptos a ientnw
				daux=prime_ptos.disMedLines(&ientnw,&desv);		//coge la dis media para quedarse con la min
				ientnw.DisPtoLine(prime_ptos.getPto(0),&ip, &lamb);	//coge el punto donde se da la min
			}
			else if(KK==OLV_AMB_PUN)
			{
				//calcula la daux media
				daux=ientnw.DisPtoLine(ientamb.pto()->pts,&ip, &lamb);				
			}

			inwaux.ip=(short)ip;
			inwaux.lamb=(float)lamb;

			i_inww=is_dmin(daux,&inww[k*OLV_LIMP_N_DMIN_NW]);
			if(i_inww>=0)
			{
				//Dist ptos-recta. Si dist mayor que la mínima guardada, descarta. 
				// Si todas dist similares y menores que una dada, se guarda
				//inw->linea de la nw
				inww[i_inww+k*OLV_LIMP_N_DMIN_NW].dmin=(float)daux;
				inww[i_inww+k*OLV_LIMP_N_DMIN_NW].refnw=inwaux.refnw;
				inww[i_inww+k*OLV_LIMP_N_DMIN_NW].ip = inwaux.ip;
				inww[i_inww+k*OLV_LIMP_N_DMIN_NW].lamb=inwaux.lamb;
				inww[i_inww+k*OLV_LIMP_N_DMIN_NW].pt[0]=inww[i_inww+k*OLV_LIMP_N_DMIN_NW].pt[1]=
					inww[i_inww+k*OLV_LIMP_N_DMIN_NW].pt[2]=0;
			}	
		}
	}	
	////////////////////////////////////////////////////////////////////////
	//coger de los tres de inww el que del punto ip de nw al extremo de amb forme el ángulo 
	//cuya diferencia con pi/2 sea menor (en el caso lineal)
	//y ponerlo en inww_amb[i-olv_limp->n_ini_amb]
	jmin[0]=jmin[1]=0;			
	alphamin[0]=alphamin[1]=MAYUSCULO;
	for(j=0;j<OLV_LIMP_N_DMIN_NW;j++)
	{
		for(k=0; k<KK; k++)
		{		
			//k=0, para el punto inicial
			//k=1, para el punto final
			i_nw=inww[j+k*OLV_LIMP_N_DMIN_NW].refnw;
			if(i_nw<0 || (i_nw>=OLV_LIMP_AMB_NW_NODEF)) //por si acaso
				continue;	

			ientnw=olv_limp->carto.getRef(i_nw);

			//calcula el punto del inw donde se da el mínimo
			p0=ientnw.getPto(inww[j+k*OLV_LIMP_N_DMIN_NW].ip);
			p1=ientnw.getPto(inww[j+k*OLV_LIMP_N_DMIN_NW].ip+1);
			inww[j+k*OLV_LIMP_N_DMIN_NW].pt[2]=0;
			inww[j+k*OLV_LIMP_N_DMIN_NW].pt[0]=p0[0]+(p1[0]-p0[0])*inww[j+k*OLV_LIMP_N_DMIN_NW].lamb;
			inww[j+k*OLV_LIMP_N_DMIN_NW].pt[1]=p0[1]+(p1[1]-p0[1])*inww[j+k*OLV_LIMP_N_DMIN_NW].lamb;

			//solo para tipo lineal, elige el de distancia menor y que el ángulo que forma el ámbito con
			//el punto más cercano de la nw sea el más ortogonal
			if(KK==OLV_AMB_LIN)
			{				
				if(k==0)
					prime_ptos = prime_ptos_i;
				else
					prime_ptos = prime_ptos_f;
				//el ángulo se calcula entre el extremo del ámbito con el vector que forman dicho extremo del 
				//ámbito con el punto del inw donde se da el mínimo
				pt_ang[0][0] = prime_ptos.getPto(0)[0];
				pt_ang[0][1] = prime_ptos.getPto(0)[1];
				pt_ang[0][2] = prime_ptos.getPto(0)[2];
				pt_ang[1][0] = inww[j+k*OLV_LIMP_N_DMIN_NW].pt[0];
				pt_ang[1][1] = inww[j+k*OLV_LIMP_N_DMIN_NW].pt[1];
				pt_ang[1][2] = inww[j+k*OLV_LIMP_N_DMIN_NW].pt[2];

				prod=GeometryFunction::ProdEscalar(&prime_ptos,&ptos_aux);
				mod1=GeometryFunction::Dist2d(prime_ptos.getPto(0), prime_ptos.getPto(1));
				mod2=GeometryFunction::Dist2d(pt_ang[0],pt_ang[1]);
				inww[j+k*OLV_LIMP_N_DMIN_NW].alpha=(float)fabs(prod/(mod1*mod2));					
			}
		}			
	}
	if(pirate)
		goto fin;

	if(KK==OLV_AMB_LIN)
	{
		//únicamente si el segundo más cercano (el de la pos '1') tiene alpha menor, y una distancia no mucho mayor
		//lo coge,
		//si no, se queda el más cercano
		for(k=0; k<KK; k++)
		{	
			if((inww[1+k*OLV_LIMP_N_DMIN_NW].alpha<inww[k*OLV_LIMP_N_DMIN_NW].alpha) && 
				(inww[1+k*OLV_LIMP_N_DMIN_NW].dmin<(inww[k*OLV_LIMP_N_DMIN_NW].dmin + OLV_DIST_MAX_AMB_NW)))
				jmin[k]=1;

			/*if((inww[1+k*OLV_LIMP_N_DMIN_NW].alpha<=inww[k*OLV_LIMP_N_DMIN_NW].alpha) && 
				(inww[1+k*OLV_LIMP_N_DMIN_NW].dmin<(inww[k*OLV_LIMP_N_DMIN_NW].dmin *1000)))
				jmin[k]=1;*/
		}	
	}

	if(olv_limp->res_circ!=OLV_RES_NO)
	{
		//si hay restricciones de circulación, y se va a coger como dmin una carretera peatonal, coge la siguiente de dmin
		for(k=0; k<KK; k++)
		{	
			if((olv_limp->iaso[inww[k*OLV_LIMP_N_DMIN_NW].refnw].flgs & OLV_LIMP_FLG_CIRC_NONE) && 
				!(olv_limp->iaso[inww[1+k*OLV_LIMP_N_DMIN_NW].refnw].flgs & OLV_LIMP_FLG_CIRC_NONE))
				jmin[k]=1;
		}	
	}

	//copia el mínimo que ha encontrado
	//para el punto inicial y final, o solo una vez si es puntual
	for(k=0; k<KK; k++)
	{
		memcpy(&olv_limp->inww_amb[i_amb+k*olv_limp->n_amb],&inww[jmin[k]+k*OLV_LIMP_N_DMIN_NW],sizeof(Info_inw_dmin));
		//copia info de qué amb y qué punto ini o fin es, para poder recuperar cuando está ordenador por inw
		olv_limp->inww_amb[i_amb+k*olv_limp->n_amb].refamb=refamb;
		olv_limp->inww_amb[i_amb+k*olv_limp->n_amb].alpha=(float)(i_amb+k*olv_limp->n_amb);
	}
fin:
	prime_ptos.pts.ptr = NULL;
	ptos_aux.pts.ptr = NULL;
	return TRUE;
}
//*************************************************************************************
/**
 * Dado un ámbito 'i_amb' (ya relativo al n_ini_amb) de un total de n_amb, 
 * de 'npt_amb' puntos almacenados en 'pt_amb',
 * añade al 'ob' las uniones del mismo con la carretera 'pt_nw'
 * de los dos extremos si es lineal o uno si es puntual, indicado por 'KK'
 */
void Colv_limp_thr::add_uniones_obj(int i_amb)
{
	double ptos[2][3];
	int refamb,nptos,KK, refnw,npt_amb;
	CartoBaseInfoEntity ientamb,ientnw,ientseg;
	CartoLine ptos_aux;
	INT64 ff;
	Info_aso2 info_aux;
	BOOL ya=TRUE;
	Info_inw_dmin *inww;

	////////////////////////////
	//esto se hace porque se sabe que son siempre 2 puntos, y así no se pide memoria
	//dinámica en el garray
	ptos_aux.pts.n = 2;
	ptos_aux.pts.ptr = ptos;
	////////////////////////////
	ientamb=olv_limp->carto.getEntity(i_amb);
	refamb=ientamb.entity()->ref;
	KK=olv_limp->tipo_ambit;
	nptos=2; //siempre añade segmentos

	//poner el flag de segmento, si es eje, refe2... si es lin o pun, si es fin...
	if(KK==OLV_AMB_LIN)
		ff=OLV_LIMP_FLG_SEG_LIN;
	else
		ff=OLV_LIMP_FLG_SEG_PUN;
	if(olv_limp->iaso[refamb].flgs & OLV_LIMP_FLG_EJE)
		ff|=OLV_LIMP_FLG_EJE_SEG;

	//////////////////////////
	for(int k=0; k<KK; k++)
	{
		inww=&olv_limp->inww_amb[i_amb+k*olv_limp->n_amb];
		ya=TRUE;
		do 
		{
			//apunta al nw más cercano del ámbito actual que se acaba de encontrar
			refnw=inww->refnw;		
			if(refnw<0 || refnw>=(olv_limp->n_nw+olv_limp->n_amb) || (refnw==i_amb)) //por si acaso
				continue;
			ientnw = olv_limp->carto.getRef(refnw);

			//apunta el array de puntos al ámbito
			if(KK==OLV_AMB_LIN)//para tipo lineal, obtiene los primeros puntos de los dos extremos
			{	
				npt_amb = ientamb.getNumberPtos();
			}
			else if(KK==OLV_AMB_PUN) //para tipo puntual, es un único punto
			{	
				npt_amb = 1;
			}	

			if(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_AMB)
				ff |= OLV_LIMP_FLG_DER | OLV_LIMP_FLG_SEG_AMB;
			else if(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_NW)
			{
				if((GeometryFunction::IsDer(&ientnw, ientamb.getPto((npt_amb-1)*k),inww->ip, inww->ip+1)))
				{
					if(!(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_CIRC_TF))
					{
						ff |= OLV_LIMP_FLG_DER; //FT o both
						olv_limp->iaso[refamb].flgs |= OLV_LIMP_FLG_DER;
					}
				}
				else if(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_CIRC_TF)
				{
					ff |= OLV_LIMP_FLG_DER; //TF	
					olv_limp->iaso[refamb].flgs |= OLV_LIMP_FLG_DER;
				}
			}
			if(k==OLV_AMB_LIN-1)
				ff|=OLV_LIMP_FLG_FIN;

			//rellena el segmento
			//el primer punto es el de la carretera más cercano al ámbito
			memcpy(ptos[0],inww->pt,3*sizeof(double));
			//el segundo punto es el propio del ámbito (inicio y final si es lineal)
			memcpy(ptos[1],ientamb.getPto((npt_amb-1)*k),3*sizeof(double));
			//lo añade al carto
			olv_limp->carto.add(ptos_aux);

			ientseg=olv_limp->carto.getEntity(olv_limp->carto.getNumberEntities()-1);
			//Añade la info aso
			info_aux.reset();
			info_aux.flgs=ff;
			info_aux.refe=ientseg.entity()->ref;
			info_aux.refe2=ientamb.entity()->ref;	
			olv_limp->iaso[info_aux.refe]=info_aux;

			if(inww->inw_old)//ojo
			{
				if(inww->inw_old->dmin<OLV_DIST_MAX_AMB_NW)
				{
					inww=inww->inw_old;//añade las uniones a la nw y a los cercanos siempre!
					ya=FALSE;
				}
				else
					ya=TRUE;
			}
			else
				ya=TRUE;
		} while (!ya);
	}
	ptos_aux.pts.ptr = NULL;
}
//*************************************************************************************
/**
 * Comprueba si el segmento corta a otro ámbito (en tratamientos lineales)
 * si lo corta, apunta el primer punto del segmento al punto extremo más cercano 
 * de dicho ámbito al ámbito ppal
 */
void Colv_limp_thr::compr_cortes_amb()
{
	olvlog(LOG_TODO,"olv_limp_t","Comprobando cortes entre uniones y ámbitos");
	pon_mi_progre(OLV_TAREA_COST_AMB, 0);
	pon_mi_msg("Comprobando cortes entre uniones y ámbitos");
	err_str[0]=0;
	//lanza los threads
	lanza_subthrs(OLV_LIMP_EV_COMPCORT_SUB,1);	
}
//*************************************************************************************
/**
 * Función de los subthreads
 */
void Colv_limp_thr::compr_cortes_amb_sub(int ithr)
{
	int na_ini,na_fin,na_desp,na;
	int KK, seg;
	Param_olv_limp_thr pp;

	CartoBaseInfoEntity ient_na, ient_i, ient_ia;
	int ref_na, ref_i, ref_ia, isg,nent;
	int iamb2,npt_amb2,ip,h;
	double dist,lamb,*pt_amb2,lambs,distseg;

	////////////////
	pp.id_e=OLV_TAREA_COST_AMB;//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);
	////////////////

	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Ambs %04d a %04d", ithr,na_ini, na_fin);

	seg = GetTickCount();
	/////////////////////////////////////
	//Bucle por cada ámbito de los que le tocan a este thread
	/////////////////////////////////////
	na=na_ini;	
	nent=olv_limp->carto.getNumberEntities();

	/////////////////////////////////////
	for(na=na_ini;na<na_fin && !pirate; na++)
	{			
		ient_na=olv_limp->carto.get(na);
		ref_na=ient_na.entity()->ref;
		//revisa si la unión de este ámbito con la carretera interseca con otro ámbito
		for(isg=olv_limp->n_amb+olv_limp->n_nw;isg<nent;isg++) //los segmentos siempre están a partir de las carreteras
		{
			ient_i=olv_limp->carto.get(isg);
			if(ient_i.entity()->type!=CartoBaseTypes::Line)
				continue;

			ref_i=ient_i.entity()->ref;

			if(!(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_SEG_LIN) || olv_limp->iaso[ref_i].refe2!=ref_na || 
				(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_SEG_AMB))
				continue;

			//ha encontrado el segmento inicial del ámbito, comprueba si corta con algún otro ámbito
			//recorre de nuevo los ámbitos, esta vez todos
			for(iamb2=0;iamb2<olv_limp->n_amb;iamb2++)
			{
				if(iamb2==na)
					continue;
				
				ient_ia=olv_limp->carto.get(iamb2);
				ref_ia=ient_ia.entity()->ref;
				if(olv_limp->iaso[ref_ia].refe2==ref_na || olv_limp->iaso[ref_na].refe2==ref_ia)
					continue;
				dist=ient_ia.DplineSeg(ient_i.getPto(0), ient_i.getPto(1),&ip, &lamb,&lambs);
				if(dist>=OLV_DIF_MAX_MISMA_COOR || (lambs<=0.1) || (lambs>=0.9))
					continue;//no intersecan

				//intersecan
				//apunta el primer ámbito al extremo más cercano del otro ámbito
				//mira cuál es el extremo más cercano
				npt_amb2 = ient_ia.getNumberPtos();				
				//pt_amb2=ient_ia.PtInLine(ip, lamb,pt_aux);				
				//renombra pt_amb2 al extremo al que esta mas cerca
				if((ip+lamb)>=((npt_amb2-1)/2))
				{
					//extremo final					
					h=1;
				}
				else
				{
					//extremo inicial
					h=0;
				}
				pt_amb2=ient_ia.getPto((npt_amb2-1)*h);
				//calcula distancia del ámbito a ientamb2
				dist=GeometryFunction::Dist2d(ient_i.getPto(1),pt_amb2);//el segundo punto de la unión es el punto del ámbito
				distseg=ient_i.getLong();//la longitud del segmento que lo unía con la carretera
				if(dist<1.5*distseg && dist<OLV_DIST_MAX_AMB_NW)
				{
					//Cambia el punto inicial de la unión,que era la carretera, por este punto del otro ámbito
					ient_i.getPto(0)[0]=pt_amb2[0];
					ient_i.getPto(0)[1]=pt_amb2[1];				
				}
			}
			
		}

		//avisa de progreso
		if(((na-na_ini)%100==0) || ((na-na_ini)==(na_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Comprobando cortes entre uniones y ambs %ld de %ld", ithr,
				(na-na_ini+1),na_desp);
			//avisa de progreso	
			prog_subthr=((1.0*(na-na_ini+1)/na_desp)+2)/(n_subthr*2);//
			thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
		}
	}
	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin comprobación cortes entre uniones y ambs, %.3f seg", ithr, 1.0*(GetTickCount()-seg)/1000);
	thr_padre->encola(OLV_LIMP_EV_COMPCORT_FIN,NULL,FALSE);
}
//*************************************************************************************
/**
 * Función final
 */
BOOL Colv_limp_thr::compr_cortes_amb_sub_fin()
{
	//para los threads
	para_subthrs();

	return TRUE;
}
//*************************************************************************************
/**
 * Comprueba, si es ámbito, si la carretera está muy lejos. 
 * Si es que sí, o bien busca otro ámbito más cercano, o lo deja vacío
 */
void Colv_limp_thr::comprueba_amb_lejos(int i_amb )
{
	int i,k,h, iaux,is_fin,npt_amb_min, lejos;
	double dist_aux,dist_aux2,dmin,dmax,longmax;
	double *pt_amb_min;
	BOOL ya_ini;
	BOOL modo_solouno;
	BOOL modo_unolibre;
	Info_inw_dmin *inwaux=NULL;
	int KK,refamb,refamb2,npt_amb,npt_amb2;
	CartoBaseInfoEntity ientamb,ientamb2;
	double *pt_amb, *pt_amb2;
	BOOL guarda_nw_old;

	/*double lamb, pt_aux[3];
	int ip;*/

	////////////////////////
	KK=olv_limp->tipo_ambit;
	dmax=OLV_DIST_MAX_AMB_NW;// m de separación max entre peatonal y calle
	///////////////////////
	ientamb=olv_limp->carto.getEntity(i_amb);
	refamb=ientamb.entity()->ref;
	npt_amb=ientamb.getNumberPtos();
	///////////////////////

	ya_ini=FALSE;
	modo_unolibre=(olv_limp->iaso[refamb].flgs & OLV_LIMP_FLG_AMB_PEAT); //Solo para las peatonales permite dejar un lado sin apuntar
	modo_solouno=FALSE;
	lejos=0;
	longmax=dmax;
	if(modo_unolibre)
		longmax=ientamb.getLong();
	//Calcula la distancia del principio y del final a la nw
	for(k=0;k<KK;k++)
	{
		pt_amb=ientamb.getPto((npt_amb-1)*k);
		dist_aux2 =  GeometryFunction::Dist2d(pt_amb, 
			olv_limp->inww_amb[i_amb+k*olv_limp->n_amb].pt);
		guarda_nw_old=TRUE;

		
		//if(dist_aux2<dmax)
		//	continue;

		//Distancia muy grande
		//Recorre el resto de ámbitos buscando uno más cercana
		//Bucle por ámbito
		dmin=MAYUSCULO;
		for(i=0;i<olv_limp->n_amb; i++)
		{
			if(i==i_amb)
				continue;

			ientamb2=olv_limp->carto.getEntity(i);
			refamb2=ientamb2.entity()->ref;

			if(olv_limp->iaso[refamb2].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;

			if(KK==OLV_AMB_LIN)//para tipo lineal, obtiene los primeros puntos de los dos extremos
			{	
				npt_amb2 = ientamb2.getNumberPtos();				
				
			}
			else if(KK==OLV_AMB_PUN) //para tipo puntual, es un único punto
			{	
				npt_amb2 = 1;
			}
			for(h=0;h<KK;h++)
			{
				pt_amb2 = ientamb2.getPto((npt_amb2-1)*h);
				dist_aux=GeometryFunction::Dist2d(pt_amb, pt_amb2);
				if(dist_aux<dmin)
				{
					dmin=dist_aux;
					iaux=refamb2;
					is_fin = h;
					npt_amb_min= npt_amb2;
					pt_amb_min = pt_amb2;						
				}	
			}	
			/*if(KK==OLV_AMB_LIN)//para tipo lineal, obtiene los primeros puntos de los dos extremos
			{	
				npt_amb2 = ientamb2.getNumberPtos();
				//busca el punto mas cercano a pt_amb dentro de ientamb2
				ientamb2.DisPtoLine(pt_amb, &ip, &lamb);
				pt_amb2=ientamb2.PtInLine(ip, lamb,pt_aux);
				//calcula la distancia
				dist_aux=GeometryFunction::Dist2d(pt_amb, pt_amb2);
				//renombra pt_amb2 al extremo al que esta mas cerca
				if((ip+lamb)>=((npt_amb2-1)/2))
				{
					//extremo final					
					h=1;
				}
				else
				{
					//extremo inicial
					h=0;
				}
				pt_amb2=ientamb2.getPto((npt_amb2-1)*h);

			}
			else if(KK==OLV_AMB_PUN) //para tipo puntual, es un unico punto
			{	
				npt_amb2 = 1;
				pt_amb2 = ientamb2.getPto(0);
				dist_aux=GeometryFunction::Dist2d(pt_amb, pt_amb2);
				h=0;
			}

			if(dist_aux<dmin)
			{
				dmin=dist_aux;
				iaux=refamb2;
				is_fin = h;
				npt_amb_min= npt_amb2;
				pt_amb_min = pt_amb2;						
			}*/	
						
		}

		///////////////////
		if((dmin<dist_aux2) && (!modo_solouno || (modo_solouno && !ya_ini)))
		{	
			//ha encontrado uno cercano, mira si lo tiene que apuntar	
			//comprueba si el que ha encontrado ya le tiene a él
			if((olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].refnw==i_amb) &&
				olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old)
			{
				//si sí, comprueba cuál de los dos tiene la nw a menos distancia
				//ese lo apunta a la nw y el otro al ámbito cercano
				if(olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old->dmin<
					olv_limp->inww_amb[i_amb+k*olv_limp->n_amb].dmin)
				{

					if(olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old->dmin<dmax)
					{
						//es el anterior el que está más cerca 
						//se pone como principal la nw
						//y este como principal al ámbito y no se guarda la nw
						//copia el old del otro al ppal
						inwaux=olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old;
						memcpy(&olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb],inwaux,sizeof(Info_inw_dmin));					
						//libera el old
						free(olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old);
						olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old=NULL;
					}
					//si es mayor que dmax, el anterior se queda como está, y este pone de ppal al ámbito y no guarda old
					//indica que no guarde de este el old porque solo va a coger de ppal al ámbito
					guarda_nw_old=FALSE;
				}
				else
				{
					//es éste el que está más cerca
					//al otro le borra el old
					free(olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old);
					olv_limp->inww_amb[iaux+is_fin*olv_limp->n_amb].inw_old=NULL;
					if(olv_limp->inww_amb[i_amb+k*olv_limp->n_amb].dmin<dmax)
					{
						//este se queda como ppal la nw, y el otro ppal a este, y nw old nada
						continue;
					}
					else
					{
						//este esta mas cerca pero lo guarda en old, y el otro solo apunta a este, sin su old
						guarda_nw_old=TRUE;
					}
				}
			}
			if(guarda_nw_old)
			{			
				//copia a inw_old lo de la nw a la que estaba apuntado
				inwaux = new Info_inw_dmin;
				if(!inwaux)
					break;
				memcpy(inwaux,&olv_limp->inww_amb[i_amb+k*olv_limp->n_amb],sizeof(Info_inw_dmin));
				olv_limp->inww_amb[i_amb+k*olv_limp->n_amb].inw_old = inwaux;
			}

			//copia en la principal la nueva info
			inwaux=&olv_limp->inww_amb[i_amb+k*olv_limp->n_amb];			
			////////////////////////////////////////////
			inwaux->dmin = (float)dmin;	
			inwaux->refnw = iaux;
			inwaux->ip = (npt_amb_min-1)*is_fin;
			inwaux->lamb = 0;			
			memcpy(inwaux->pt,pt_amb_min,3*sizeof(double));			
			ya_ini=TRUE;
		}
		else if((dmin>longmax) && !modo_solouno)
		{
			//si está todavía más lejos, lo apunta a su principio
			lejos|=1<<k;
		}
	}
	if(!modo_unolibre)
		return;
	//comprueba si ha dejado alguna sin apuntar
	if(lejos & (1<<1))
	{
		//si ha dejado los dos o sólo el primero
		olv_limp->inww_amb[i_amb].refnw = refamb;
		olv_limp->inww_amb[i_amb].ip =0;
		memcpy(olv_limp->inww_amb[i_amb].pt,ientamb.getPto(olv_limp->inww_amb[i_amb].ip),3*sizeof(double));
	}
	else if(lejos & (1<<0))
	{
		//si ha dejado sólo el segundo
		olv_limp->inww_amb[i_amb+olv_limp->n_amb].refnw = refamb; 
		olv_limp->inww_amb[i_amb+olv_limp->n_amb].ip = npt_amb-1;
		memcpy(olv_limp->inww_amb[i_amb+olv_limp->n_amb].pt,ientamb.getPto(olv_limp->inww_amb[i_amb+olv_limp->n_amb].ip),3*sizeof(double));
	}
}
//*************************************************************************************
/**
 * Comprueba si hay ámbitos a un lado que se supone deberían estar al otro
 */
BOOL Colv_limp_thr::comprueba_latelaridad()
{
	int sent,id;
	BOOL sigue_msg=TRUE;

	if(olv_limp->res_circ<OLV_RES_RECOGER_SOLO_LADO_Y_GIROS)
		return TRUE;
	if(olv_limp->lateral<=0)
		return TRUE;

	char msg_[OLV_MAX_MSG_PROCE];
	char nfile[MAX_PATH];

	strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
	//cambiaext(nfile,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");

	msg_[0]=0;

	///////////////////LATERALIDAD
	//recorres inww_amb_aux, que está ordenado por inw
	//solo en puntuales
	//si res_cir<solo_lados_y_giros, pirate
	//si calle un único sentido: ias[(*ob->objt)[inww_amb_aux[i].inw].ia].flgs & OLV_LIMP_FLG_CIRC_FT //fronto mismo sentido que lineal
	//si lateral==derecha y amb a la izquierda, descarta
	//amb -> ias[inww_amb_aux[ì].iamb].flgs & OLV_LIMP_FLG_DER
	//o si lateral==izda y amb a la derecga, descarta

	for(int ia=0; ia<olv_limp->n_amb; ia++)
	{
		sent=0;
		if(olv_limp->iaso[olv_limp->inww_amb[ia].refnw].flgs & OLV_LIMP_FLG_CIRC_FT )
			sent++;
		if(olv_limp->iaso[olv_limp->inww_amb[ia].refnw].flgs & OLV_LIMP_FLG_CIRC_TF )
			sent++;
		if(sent!=1)
			continue;
		//comprueba lateralidad
		if(olv_limp->iaso[olv_limp->inww_amb[ia].refamb].flgs & OLV_LIMP_FLG_DER)//ambito a la derecha
		{
			if(olv_limp->lateral==1) //lateralidad derecha
				continue;	
		}
		else//ambito a la izquierda
		{
			if(olv_limp->lateral==2) //lateralidad izquierda
				continue;	
		}		

		//lee el objectid del ámbito
		id=olv_limp->iaso[olv_limp->inww_amb[ia].refamb].oid;
		olvlog(LOG_TODO,"olv_limp_t","Ámbito %ld lateralidad errónea",olv_limp->iaso[olv_limp->inww_amb[ia].refamb].oid);
		
		//imprime
		if(msg_[0]==0)
			sprintf_s(msg_,OLV_MAX_MSG_PROCE,"Encontrados contenedores con lateralidad errónea: ");
		if(sigue_msg)
			sprintf_s(msg_,OLV_MAX_MSG_PROCE,"%s %ld,",msg_,id);
		if(sigue_msg && strlen(msg_)+10>=OLV_MAX_MSG_PROCE)
			sigue_msg=FALSE;//para que no se pase del largo

	}
	if(!sigue_msg && ((strlen(msg_)+5)<OLV_MAX_MSG_PROCE))
		sprintf_s(msg_,"%s %s",msg_,"y mas");
	if(msg_[0]!=0)
	{
		pon_mi_msg(msg_);
		Sleep (OLV_T_SLEEP_MSG);
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Realiza el ánalisis topológico a la red navegable junto con los ámbitos y los segmentos
 * que les unen, para incluir los mismos en la red navegable
 */
BOOL Colv_limp_thr::topo_nw()
{
	int KK, ia,ia_aux, iat, nt,npt_nw_aux,pp,npt_nw;
	Info_inw_dmin *inww_amb_aux;
	unsigned short refnw;
	CartoBaseInfoEntity ientamb, ientcp, ientnw;
	CartoLine nwcp;
	Info_aso2 info_aux;
	CartoLine ptos_aux;
	BOOL mal;

	/////////////////
	inww_amb_aux=NULL;
	KK=olv_limp->tipo_ambit;
	mal=FALSE;
	nwcp.idPropsP=0;
	/////////////////

	/////////////////
	olvlog(LOG_TODO,"olv_limp_t","Generando topología con los segmentos de unión");
	pon_mi_progre(OLV_TAREA_TOPO_NW, 0);
	pon_mi_msg("");
	err_str[0]=0;

	int ent1=olv_limp->carto.getNumberEntities();

	//inicializa la matriz auxiliar para ordenación
	inww_amb_aux = (Info_inw_dmin *)malloc(olv_limp->n_amb*KK*sizeof(Info_inw_dmin));
	if(!inww_amb_aux)
	{
		pon_mi_msg("Error, sin memoria para matriz de índices\nde ámbitos a carreteras");
		return FALSE;
	}
	memcpy(inww_amb_aux,olv_limp->inww_amb,olv_limp->n_amb*KK*sizeof(Info_inw_dmin));
	//////////////////////////////////////////////////
	//ordena la matriz de info de inw, va de punto más cercano 
	//al inicio del inw inicial al más lejano, y aumentando en inw
	//dentro del mismo inw, ordena por ip y a igual ip, por lamb
	qsort(inww_amb_aux,olv_limp->n_amb*KK,sizeof(Info_inw_dmin),Colv_limp_thr::compara_inww_amb);

	olvlog(LOG_TODO,"olv_limp_t","Generando topología: Matriz de info de inw dmin ordenada");

	//////////////////////
	//mira a ver si tiene que replicar calles de doble sentido	
	if(!replica_doble_sent(inww_amb_aux))
	{
		pon_mi_msg("Errores al replicar doble sentido");
		return FALSE;
	}
	//hay que volver a ordenar por si se ha modificado algo al replicar
	qsort(inww_amb_aux,olv_limp->n_amb*KK,sizeof(Info_inw_dmin),Colv_limp_thr::compara_inww_amb);

	////////////////////
	if(KK<2)//en recogida, se mira si hay que comprobar la lateralidad
		comprueba_latelaridad();

	///////////////////////////////////////////////////////////////////////
	//Bucle por cada item del array inww_amb, para ir troceando las carreteras que cortan
	ia=0;
	while(ia<olv_limp->n_amb*KK && !pirate)
	{

		///////////////////////////////
		ia_aux=ia;
		refnw=inww_amb_aux[ia_aux].refnw;

		if(olv_limp->iaso[inww_amb_aux[ia_aux].refamb].flgs & OLV_LIMP_FLG_AMB_NO)
		{
			ia++;
			continue;
		}
		if(!(olv_limp->iaso[refnw].flgs & OLV_LIMP_FLG_NW)) //es que se ha reapuntado a otro ámbito por ser peatonal lejana
		{
			ia++;
			continue;
		}
		ientnw=olv_limp->carto.getRef(refnw);
		npt_nw=ientnw.getNumberPtos();
		memcpy(&info_aux,&olv_limp->iaso[refnw],sizeof(Info_aso2));
		
		iat=ia;
		nt=1;
		//primero cuenta los tramos de esa inwi, nt
		while((ia<olv_limp->n_amb*KK) && (inww_amb_aux[ia].refnw==refnw))
		{
			ia++;
			nt++;
		}

		if(nt<2) //tiene que haber siempre mínimo 2 tramos, ya que en todos los inw de este array hay algún ámbito asignado
		{
			olvlog(LOG_TODO,"olv_limp_t","Gen. Topo. Inw %03d mal, se obtienen %ld tramos, no suficientes",refnw,nt);
			mal=TRUE;
			ia++;
			continue;
		}

		//ya se saben los tramos, se va troceando la carretera
		ia=iat;
		iat=0;
		inww_amb_aux[ia].flgs=0;
		while(iat<nt)
		{
			ptos_aux.pts.n=0;

			//guarda en alpha la nueva refn
			if(ia>0 && inww_amb_aux[ia-1].flgs>1)
				olv_limp->inww_amb[(int)inww_amb_aux[ia-1].alpha].refnw=info_aux.refe;

			//recorre la carretera inwi y la parte en trozos acorde a los ámbitos 
			if(iat==0)//hace el primer tramo, del extremo inicial al primer ámbito
			{
				npt_nw_aux=inww_amb_aux[ia].ip+2;				
				if(Colv_geom::pto_equals(ientnw.getPto(0), inww_amb_aux[ia].pt))
				{
					//no se hace tramo porque está unido por el extremo
					iat++;
					ia++;
					if(nt==2)
					{
						iat++;//si solo eran dos tramos, pasa
						ia++;
					}
					continue;
				}
				//los primeros puntos son los de la carretera hasta el ámbito
				for(pp=0;pp<npt_nw_aux-1;pp++) //pp<ip+1
					ptos_aux.addPto(ientnw.getPto(pp));
				//el punto final es el del ámbito
				ptos_aux.addPto(inww_amb_aux[ia].pt);
				inww_amb_aux[ia].flgs++;
			}
			else if(iat==(nt-1))//hace el último tramo, del último ámbito al extremo final
			{				
				npt_nw_aux=npt_nw-inww_amb_aux[ia-1].ip;	
				if(Colv_geom::pto_equals(ientnw.getPto(npt_nw-1), inww_amb_aux[ia-1].pt))
				{
					//no se hace tramo porque está unido por el extremo
					iat++;
					ia++;
					continue;
				}
				//el primer punto es el del ámbito anterior
				ptos_aux.addPto(inww_amb_aux[ia-1].pt);
				//los siguientes puntos son los de la carretera hasta el final
				for(pp=inww_amb_aux[ia-1].ip+1;pp<npt_nw;pp++)
					ptos_aux.addPto(ientnw.getPto(pp));	
				inww_amb_aux[ia-1].flgs++;
			}
			else //hace los tramos de enmedio
			{
				npt_nw_aux=inww_amb_aux[ia].ip-inww_amb_aux[ia-1].ip+2;				
				//el primer punto es el del primer ámbito
				ptos_aux.addPto(inww_amb_aux[ia-1].pt);
				//los siguientes puntos son los de la carretera
				for(pp=inww_amb_aux[ia-1].ip+1;pp<inww_amb_aux[ia].ip+1;pp++)
					ptos_aux.addPto(ientnw.getPto(pp));		
				//el último punto es el del ámbito siguiente
				ptos_aux.addPto(inww_amb_aux[ia].pt);	
				inww_amb_aux[ia-1].flgs++;
			}			
	
			//añade el tramo, le pone el índice a la misma info asociada que la carretera original
			olv_limp->carto.add(ptos_aux);
			info_aux.refe=olv_limp->carto.get(olv_limp->carto.getNumberEntities()-1).entity()->ref;
			if(olv_limp->iaso[refnw].inf_n.nomb)
			{
				info_aux.inf_n.nomb = (char*)malloc(strlen(olv_limp->iaso[refnw].inf_n.nomb)+1);
				strcpy(info_aux.inf_n.nomb,olv_limp->iaso[refnw].inf_n.nomb);
			}
			olv_limp->iaso[info_aux.refe]=info_aux;

			iat++;
			ia++;
		}
		


		if((ia%100==0) || (ia==(olv_limp->n_amb*KK)))
		{		
			olvlog(LOG_TODO,"olv_limp_t","Generando topología, %ld de %ld",ia,olv_limp->n_amb*KK);
			//avisa de progreso
			pon_mi_progre(OLV_TAREA_TOPO_NW, (int) ((OliviaDef::GeneralDef::ProgrMax*
				1.0*(ia)/(olv_limp->n_amb*KK))));	
		}
		ia--; //decrementa para cuando se ha pasado	
	}
	info_aux.inf_n.nomb = NULL;
	if(mal)
	{
		pon_mi_msg("Errores en el análisis topológico");
	}
	if(mal || pirate)
	{
		if(inww_amb_aux)
			free(inww_amb_aux);
		return FALSE;
	}	

	int ia_old;
	ia=ia_old=0;
	while(ia<olv_limp->n_amb*KK)
	{
		refnw=inww_amb_aux[ia].refnw;
		if(olv_limp->iaso[inww_amb_aux[ia].refamb].flgs & OLV_LIMP_FLG_AMB_NO)
		{
			ia++;
			continue;
		}
		if((refnw<0) || (refnw<olv_limp->n_amb) || (inww_amb_aux[ia].flgs<2)) //si al final no ha hecho tramos
		{
			ia++;
			continue;
		}

		//marca para borrar calle
		olv_limp->carto.removeRef(refnw);

		//avanza hasta el siguiente inwi
		while((ia<olv_limp->n_amb*KK) && (inww_amb_aux[ia].refnw==refnw))
		{
			ia++;
		}

	}

	//hace limpieza de la carto
	olv_limp->carto.FastClear();

	if(inww_amb_aux)
		free(inww_amb_aux);

	if(!pon_nodos_planta(olv_limp->coor_instal))
	{
		pon_mi_msg("Error, No se ha podido incluir planta en red");
		return FALSE;
	}

	//hace limpieza de la carto, ya que ha terminado de hacer topología o añadir cosas
	olv_limp->carto.FastClear();

	//olv_limp->carto.linesExportShp("C:\\Proyectos\\Olivia\\Instal\\topo.shp");
	
	return TRUE;
}
//*************************************************************************************
/**
 * Compara las estructuras inww_amb. Las ordena por inw, a mismo inw por ip, y a mismo ip por lamb
 */
int Colv_limp_thr::compara_inww_amb (const void * a, const void * b)
{
	//si a<b devuelve negativo, si son iguales 0, y si es mayor positivo
	int r;
	double dd;
	//es menor el de menor inw
	r=((Info_inw_dmin*) a)->refnw - ((Info_inw_dmin*) b)->refnw;
	if(r==0)
	{
		//a mismo inw, es menor el de menor ip
		r=((Info_inw_dmin*) a)->ip - ((Info_inw_dmin*) b)->ip;
		if(r==0)
		{
			//a mismo ip, es menor el de menor lamb
			dd=((Info_inw_dmin*) a)->lamb - ((Info_inw_dmin*) b)->lamb;
			if(dd<0)
				r=-1;
			else if(dd>0)
				r=1;
			else
				r=0;
		}	
	}
		
	return r; 
}
//*************************************************************************************
/**
 * Añade a la red de conjunciones en qué conjunción está la planta y la instalación
 */
BOOL Colv_limp_thr::pon_nodos_planta(double pt[3])
{
	int i, nent, refent,ip;
	double dmin,d,lamb,pt_proy_nw[3],*pt_ip,*pt_ip1;
	CartoBaseInfoEntity ientnw;
	CartoLine lines[2];
	Info_inw_dmin inww;
	Info_aso2 info_aux;

	if((pt[0]==0) && (pt[1]==0))
		return TRUE;//no hay instalación, no se pone

	////////////////////////////////////////////////////////////////////////
	//Bucle por cada carretera de la nw
	dmin=DBL_MAX;
	nent=olv_limp->carto.getNumberEntities();
	inww.reset();
	for(i=0; i<nent && !pirate; i++)
	{
		if(olv_limp->carto.get(i).entity()->type!=CartoBaseTypes::Line)
			continue;

		refent=olv_limp->carto.get(i).entity()->ref;
		if(!(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_NW))
			continue;

		ientnw=olv_limp->carto.get(i);

		//calcula la distancia al punto de la instalación
		d = ientnw.DisPtoLine(pt,&ip,&lamb);
		if(d<dmin)
		{
			dmin=d;
			inww.dmin=(float)d;
			inww.refnw=refent;
			inww.ip=(short)ip;
			inww.lamb=(float)lamb;
		}
	}
	if(dmin>=DBL_MAX)
		return FALSE;

	/////////////////////////////////////////////////
	//ya tiene el inw de la distancia mínima	

	//apunta al que ha encontrado mínimo
	ientnw = olv_limp->carto.getRef(inww.refnw);

	//calcula el punto del inw donde se da el mínimo
	pt_ip=ientnw.getPto(inww.ip);
	pt_ip1=ientnw.getPto(inww.ip+1);

	pt_proy_nw[2]=0;
	for(i=0;i<2;i++)
		pt_proy_nw[i]=pt_ip[i]+(pt_ip1[i]-pt_ip[i])*inww.lamb;	

	/////////////////////////////////////////////////
	//sustituye las coords por el punto proyectado en la nw
	memcpy(pt,pt_proy_nw,3*sizeof(double));
	/////////////////////////////////////////////////

	//hace dos tramos
	if(!ientnw.DivLine(&lines[0],&lines[1],inww.ip,inww.lamb))
		return FALSE;

	//añade los tramos, les pone la misma info asociada que la carretera original
	info_aux.reset();
	memcpy(&info_aux,&olv_limp->iaso[inww.refnw],sizeof(Info_aso2));
	
	for(i=0;i<2;i++)
	{
		if(lines[i].getNumberPtos()<2)
			continue;
		olv_limp->carto.add(lines[i]);
		info_aux.refe=olv_limp->carto.get(olv_limp->carto.getNumberEntities()-1).entity()->ref;

		if(olv_limp->iaso[inww.refnw].inf_n.nomb)
		{
			info_aux.inf_n.nomb = (char*)malloc(strlen(olv_limp->iaso[inww.refnw].inf_n.nomb)+1);
			strcpy(info_aux.inf_n.nomb,olv_limp->iaso[inww.refnw].inf_n.nomb);
		}

		olv_limp->iaso[info_aux.refe]=info_aux;
	}

	olv_limp->carto.removeRef(inww.refnw);
	//olv_limp->carto.clear(); //se hace después

	return TRUE;
}
//*************************************************************************************
/**
 * Apunta en qué nodos está la planta y la instalación
 */
BOOL Colv_limp_thr::busca_conjs_planta(double pt[3], int *nod)
{
	int ic;
	BOOL mal=FALSE;

	if((pt[0]==0) && (pt[1]==0))
		return TRUE;//no hay instalación, no se pone

	//busca ese punto en la lista de conjunciones
	//busca la conjunción en la lista
	//lo hace para los dos extremos de la línea
	for(ic=0; ic<olv_limp->conjs.n;ic++)
	{
		if((Colv_geom::pto_equals(pt,olv_limp->conjs.coor[ic])))
			break;
	}			
	if(ic==olv_limp->conjs.n)
	{
		return FALSE;
	}
	*nod=ic;	

	return TRUE;
}
//*************************************************************************************
/**
 * Lanza sub-threads 
 */
void Colv_limp_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_limp_thr(olv_limp);
		sprintf_s(nomb,32,"limp_subth_%ld",i);
		pp.id_e=i;
		subthrs[i]->thr_padre=this;
		subthrs[i]->n_subthr = nn;
		subthrs[i]->prog_subthr = 0;
		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
}
//*************************************************************************************
/**
 * Para sub-threads 
 */
void Colv_limp_thr::para_subthrs()
{
	//Para los subthreads
	for(int i=0;i<n_subthr;i++)
	{		
		if(subthrs[i])
		{			
			subthrs[i]->pirate=pirate;
			subthrs[i]->termina();
		}
	}
}
//*************************************************************************************
/**
 * Rellena la matriz de costes entre todas las conjunciones
 */
BOOL Colv_limp_thr::calcula_cost_conj()
{	
	int i;
	////////////////

	olvlog(LOG_TODO,"olv_limp_t","Rellenando matriz de costes entre conjunciones");
	pon_mi_progre(OLV_TAREA_COST_AMB, 0);
	pon_mi_msg("Rellenando matriz de costes entre nodos");
	err_str[0]=0;

	//calcula el número de nodos de la red
	//que es el número de intersecciones de la red navegable, incluyendo el número de ámbitos x2 porque 
	//aparecen el punto del ámbito y el proyectado en la carretera más próxima (y x2 si son lineales)
	olvlog(LOG_TODO,"olv_limp_t","Comienza a buscar conjunciones"); 
	if(!busca_conjs())
	{
		pon_mi_msg("Error, sin memoria para matriz de conjunciones en busca_conjs");
		return FALSE;
	}	

	//*****************************************************************
	//log_debug
	/*CartoBaseInfoEntity ient;
	int refent;
	for(int i=0;i<olv_limp->n_amb;i++)
	{
		refent=i;
		ient=olv_limp->carto.getRef(refent);
	
		olvlog(LOG_TODO,"olv_limp_t","refent %04d flgs 0x%x -----------------------", refent, olv_limp->iaso[refent].flgs);
		olvlog(LOG_TODO,"olv_limp_t","inod 0 %03d 1 %03d",olv_limp->iaso[refent].inod[0],olv_limp->iaso[refent].inod[1]);
		olvlog(LOG_TODO,"olv_limp_t","refe2 %04d",olv_limp->iaso[refent].refe2);
		olvlog(LOG_TODO,"olv_limp_t","refe_nw 0 %04d 1 %04d",olv_limp->iaso[olv_limp->inww_amb[refent].refnw].oid,
			olv_limp->iaso[olv_limp->inww_amb[refent+olv_limp->n_amb].refnw].oid);
		olvlog(LOG_TODO,"olv_limp_t","refe_nw inod 0 %03d 1 %03d",olv_limp->iaso[olv_limp->inww_amb[refent].refnw].inod[0],
			olv_limp->iaso[olv_limp->inww_amb[refent+olv_limp->n_amb].refnw].inod[1]);
	}*/
	//*****************************************************************

	pon_mi_msg("Rellenando matriz de costes entre nodos. %ld nodos por calcular", olv_limp->conjs.n);
	//pide memoria para el array de distancias entre conjunciones
	///mira a ver con cuántos nvect puede calcular la matriz
	CoptiMemo oo;
	int nvect = oo.calc_nvect_master(olv_limp->conjs.n);
	if(nvect<0)
	{
		pon_mi_msg("Error, sin memoria para matriz de conjunciones en cálculo de nvect");
		return FALSE;
	}	
	olvlog(LOG_TODO,"olv_limp_t","Se va a ejecutar con nvect=%ld de %ld",nvect,olv_limp->conjs.n); 
	olv_limp->cost_conj.clear();
	olv_limp->tip_conj.clear();
	olv_limp->cost_conj.inicializa(olv_limp->conjs.n,n_subthr,nvect);
	olv_limp->tip_conj.inicializa(olv_limp->conjs.n,n_subthr,nvect);
	
	//si solo le llega una calle a una conjunción, y es de sentido único, le pone doble sentido
	for(i=0;i<olv_limp->conjs.n;i++)
	{
		if(olv_limp->conjs.inc[i].n==1)
		{
			if(olv_limp->iaso[olv_limp->conjs.inc[i].refnw0].flgs & (OLV_LIMP_FLG_CIRC_FT | OLV_LIMP_FLG_CIRC_TF))
				olv_limp->iaso[olv_limp->conjs.inc[i].refnw0].flgs &= ~OLV_LIMP_FLG_CIRC_FT & ~OLV_LIMP_FLG_CIRC_TF;
		}			
	}
	
	//lanza los threads
	lanza_subthrs(OLV_LIMP_EV_COST_CONJ_SUB);

	return TRUE;
}
//*************************************************************************************
/**
 * Comprueba la memoria para las conjunciones
 */
BOOL Colv_limp_thr::add_conj(Info_conjs *conjs, double coor[3])
{	
	if(!cuida_memo_conj(conjs))
		return FALSE;

	memcpy(conjs->coor[conjs->n],coor,3*sizeof(double));
	conjs->n++;

	return TRUE;
}
//*************************************************************************************
/**
 * Comprueba la memoria para las conjunciones
 */
BOOL Colv_limp_thr::cuida_memo_conj(Info_conjs *conjs)
{		
	double (*coor2)[3];
	Info_conjs_inw *inc2;

	if((conjs->n+1)>conjs->m)
	{	
		conjs->m+=OLV_LIMP_M_CONJ;

		//primero las coordenadas
		coor2 = (double (*)[3])realloc(conjs->coor,conjs->m*3*sizeof(double));
		if(!coor2)
		{
			free(conjs->coor);
			return FALSE;
		}
		conjs->coor=coor2;
		memset(&conjs->coor[conjs->m-OLV_LIMP_M_CONJ],0,OLV_LIMP_M_CONJ*3*sizeof(double));	
		
		//primero las incidencias
		inc2 = (Info_conjs_inw *)realloc(conjs->inc,conjs->m*sizeof(Info_conjs_inw));
		if(!inc2)
		{
			free(conjs->inc);
			return FALSE;
		}
		conjs->inc=inc2;
		//inicializa
		for(int i=conjs->m-OLV_LIMP_M_CONJ;i<conjs->m;i++)
		{
			conjs->inc[i].n=conjs->inc[i].refnw0=-1;		
		}
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la matriz de conjunciones entre toda la red, navegable y ámbitos
 * y la info de las conjunciones se rellena en 'conjs'
 */
BOOL Colv_limp_thr::busca_conjs()
{	
	int io, refent, nent,i,k,npts,ic, ics[2], refe2,sum;
	CartoBaseInfoEntity ient;
	double *pto;
	BOOL modo_ejes, mal;

	mal=modo_ejes=FALSE;

	if((olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMh_eje) || 
		(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoM2h_eje))
		modo_ejes=TRUE;

	//bucle por cada entidad de la carto
	//si es modos de ámbitos normales, lineales o puntuales, se va de inicio a final del carto, en orden
	//y se van buscando las conjs de los ámbitos, los nw, y los segmentos
	//si es un modo en el que los ámbitos son ejes, se va al revés, añadiendo primero las conjunciones de 
	//los segmentos y la nw, y por último las de los ejes. Se hace para que en el siguiente paso, al buscar,
	//aparezca primero la conjunción de la carretera, porque es de la que no se tiene constancia ic_ini/ic_fin

	io=0;
	nent=olv_limp->carto.getNumberEntities();
	if(modo_ejes)
	{
		i=nent;
		sum=-1;
	}
	else
	{
		i=-1;
		sum=1;
	}
	for(io=0;io<nent && !mal && !pirate; io++)
	{
		i+=sum;
		if(olv_limp->carto.get(i).entity()->type!=CartoBaseTypes::Line)
			continue;
		
		ient=olv_limp->carto.get(i);
		refent=ient.entity()->ref;
		npts=ient.getNumberPtos();

		if((olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_PEAT_SEG) || 
			(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_EJE_SEG))
			continue;

		for(k=0; k<2; k++)
		{
			pto = ient.getPto(k*(npts-1));
			if((olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_PEAT_REP) || 
				(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_EJE))
			{
				//en estos casos replica las conjunciones
				//llega la segunda vez
				ic=olv_limp->conjs.n;
				if(!add_conj(&olv_limp->conjs, pto))
				{
					mal=TRUE;
					break;
				}
			}
			else
			{
				//busca la conjunción en la lista
				//lo hace para los dos extremos de la línea
				for(ic=0; ic<olv_limp->conjs.n;ic++)
				{
					if((Colv_geom::pto_equals(pto,olv_limp->conjs.coor[ic])))
						break;
				}			
				if(ic==olv_limp->conjs.n)
				{
					//no lo ha encontrado, lo añade
					if(!add_conj(&olv_limp->conjs,pto))
					{
						mal=TRUE;
						break;
					}
				}
			}
			ics[k]=ic;	

			//si es carretera, le pone a la conjunción que llega una al menos
			//if(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_NW)
			{
				if(olv_limp->conjs.inc[ic].n<0)
				{
					olv_limp->conjs.inc[ic].n=1;
					olv_limp->conjs.inc[ic].refnw0=refent;
				}
				else
					olv_limp->conjs.inc[ic].n++;
			}
		}
		
		//guarda las conjunciones en la iaso
		for(k=0; k<2; k++)
		{
			olv_limp->iaso[refent].inod[k]=ics[k];	
		}

		//si es segmento de ámbito puntual, le pone al ámbito la conjunción
		if(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_SEG_PUN)
		{
			refe2=olv_limp->iaso[refent].refe2;
			olv_limp->iaso[refe2].inod[0]=olv_limp->iaso[refe2].inod[1]=ics[1];
		}		
		
	}

	if(io<nent || mal)
	{
		olvlog(LOG_TODO,"olv_limp_t","Error, sin memoria para matriz de conjunciones en busca_conjs");
		return FALSE;
	}

	if(pirate)
		return FALSE;	

	//lo vuelve a hacer para los segmentos de ejes y de peatonales	
	nent=olv_limp->carto.getNumberEntities();	
	int ref1, ref2;
	for(i=0;i<nent;i++)
	{
		if(olv_limp->carto.get(i).entity()->type!=CartoBaseTypes::Line)
			continue;
		
		ient=olv_limp->carto.get(i);
		refent=ient.entity()->ref;
		npts=ient.getNumberPtos();

		if(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_PEAT_SEG)
		{
			//ref1 es la réplica de la peatonal
			ref1=olv_limp->iaso[refent].refe;
			//ref2 es la peatonal original
			ref2=olv_limp->iaso[refent].refe2;
		}
		else if(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_EJE_SEG)
		{
			//ref1 es el eje original, como ámbito
			ref1=olv_limp->iaso[refent].refe2;
			//ref2 es la calle a la que está asignado
			ref2=olv_limp->inww_amb[ref1].refnw;
		}
		else
			continue;
		if(olv_limp->iaso[refent].flgs & OLV_LIMP_FLG_FIN)
			k=1;
		else
			k=0;
		//el primer nodo el del ámbito
		olv_limp->iaso[refent].inod[0]=olv_limp->iaso[ref1].inod[k];
		//el primer nodo el de la réplica
		olv_limp->iaso[refent].inod[1]=olv_limp->iaso[ref2].inod[k];
	}

	olvlog(LOG_TODO,"olv_limp_t","Encontradas %ld conjunciones en la red navegable",olv_limp->conjs.n);

	olvlog(LOG_TODO,"olv_limp_t","Comienza a buscar las conjunciones de la planta"); 

	if(!busca_conjs_planta(olv_limp->coor_instal, &olv_limp->nod_instal))
	{
		olvlog(LOG_TODO,"olv_limp_t","No se ha podido encontrar los nodos de la planta");
		return FALSE;
	}
	olvlog(LOG_TODO,"olv_limp_t","Encontradas las conjunciones de la planta"); 

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la matriz de distancias entre todas las conjunciones.
 * El thread entra aquí cuando los subthreads que realizan la tarea realmente han finalizado
 */
BOOL Colv_limp_thr::calcula_cost_conj_fin()
{	
	////////////////	
	//para los threads
	para_subthrs();
	//olv_limp->cost_conj.memAjust();
	olvlog(LOG_TODO,"olv_limp_t","FIN Matriz de dist entre conjs %ldx%ld",
		olv_limp->conjs.n,olv_limp->conjs.n);
	
	///////////////////////////////
	/*if(olv_limp->res_circ==OLV_RES_NO)
	{
		//va directo a cost_amb, calcula ahora si va a ser multitask o no
		//calcula si puede ser multitask o no
		CoptiMemo oo;
		olv->modo_multitask=oo.is_multi(olv_limp->conjs.n,n_subthr,sizeof(Djkt_elem_cola));
	}*/
	////////////////////////////////

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la matriz de distancias entre todas las conjunciones, es la parte de cálculos que 
 * realizan los subthreads. 'ithr' indica qué thread es, para calcular qué conjunciones le tocan.
 */
void Colv_limp_thr::calcula_cost_conj_sub(int ithr)
{
	int nd,i,k,ics[2];
	int n_ini, n_desp, n_fin, seg;
	float cost,cost2;
	BOOL mal=FALSE;
	Param_olv_limp_thr pp;

	int nent, refent;
	CartoBaseInfoEntity ient;

	////////////////
	nent=olv_limp->carto.getNumberEntities();
	mal=FALSE;
	pp.id_e=OLV_TAREA_COST_AMB;//manda de parámetro la tarea de la que es el progreso
	n_desp = (int)ceil(1.0*(nent)/n_subthr);	
	n_ini=ithr*n_desp;
	n_fin = min((ithr+1)*n_desp,nent);
	cost=cost2=0;
	nd=0;
	////////////////
	
	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Entidades %04d a %04d", ithr,n_ini, n_fin);
	
	seg = GetTickCount();
	/////////////////////////////////////
	//bucle por cada entidad de la carto
	for(i=n_ini; i<n_fin && !mal && !pirate; i++)
	{		
		ient = olv_limp->carto.get(i);
		refent = ient.entity()->ref;
		for(k=0;k<2;k++)
			ics[k]=olv_limp->iaso[refent].inod[k];

		if(ics[0]<0 || ics[1]<0)
			continue;
		
		///////////////////
		//pone en el array de tipos qué es
		olv_limp->tip_conj.set(ics[0],ics[1],refent);
		olv_limp->tip_conj.set(ics[1],ics[0],refent);
		///////////////////////////////////
		nd+=2;

		//ya tiene una línea y sus dos extremos localizados, calcula el coste
		calcula_cost(refent,&cost,&cost2);

		//añade los costes a la matriz
		if(cost>olv_limp->cost_conj[ics[0]][ics[1]])
			cost=olv_limp->cost_conj[ics[0]][ics[1]];
		olv_limp->cost_conj.set(ics[0],ics[1], min(cost,olv_limp->cost_conj[ics[0]][ics[1]]));

		if(cost2>olv_limp->cost_conj[ics[1]][ics[0]])
			cost2=olv_limp->cost_conj[ics[1]][ics[0]];
		olv_limp->cost_conj.set(ics[1],ics[0],min(cost2,olv_limp->cost_conj[ics[1]][ics[0]]));

		/////////////////////////////////////

		//avisa de progreso
		if(((i-n_ini)%800==0) || ((i-n_ini)==(n_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Rellenando matriz de dist entre conjs %ld de %ld", ithr,
				(i-n_ini+1),n_desp);
			//avisa de progreso	
			prog_subthr=((1.0*(i-n_ini+1)/n_desp)+0)/3;///3 porque es la tercera parte del progreso los costes de conjunciones y la otra mitad los costes de ámbitos
			thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
		}
	}	

	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin Matriz de dist entre conjs, %ld distancias, %.3f seg", ithr, nd,1.0*(GetTickCount()-seg)/1000);

	thr_padre->encola(OLV_LIMP_EV_COST_CONJ_FIN,NULL,FALSE);
}
//*************************************************************************************
/**
 * Calcula el coste de la línea io, cost en sentido ida y cost2 en sentido vuelta
 */
void Colv_limp_thr::calcula_cost(int refent, float *cost, float *cost2)
{
	double ltot;

	*cost=*cost2=0;
	////////////////////	
	ltot=0;
	if(olv_limp->carto.getRef(refent).entity()->type == CartoBaseTypes::Line)
	{	
		ltot=olv_limp->carto.getRef(refent).getLong();	
		if(ltot==0)
		{
			//es un segmento de unión de peat con rep o de eje de calle con nw
			cost=cost2=0;
			return;
		}
	}
	///////////////////
	olv_limp->dame_cost(ltot,refent,cost,cost2);	
}
//*************************************************************************************
/**
 * Rellena la matriz de ángulos entre las conjunciones adyacentes a una dada
 */
BOOL Colv_limp_thr::calcula_ang_conj()
{	
	////////////////

	olvlog(LOG_TODO,"olv_limp_t","Rellenando matriz de ángulos entre conjunciones");
	pon_mi_progre(OLV_TAREA_COST_AMB, (int) (OliviaDef::GeneralDef::ProgrMax*1/3));
	pon_mi_msg("Rellenando matriz de ángulos entre nodos");
	err_str[0]=0;

	//pide memoria para el array de distancias entre conjunciones
	olv_limp->ang_conj = new Djkt_ang_ady[olv_limp->conjs.n]; 

	//lanza los threads
	lanza_subthrs(OLV_LIMP_EV_ANG_CONJ_SUB);	

	return TRUE;
}

//*************************************************************************************
/**
 * Rellena la matriz de ángulos entre todas las conjunciones.
 * El thread entra aquí cuando los subthreads que realizan la tarea realmente han finalizado
 */
BOOL Colv_limp_thr::calcula_ang_conj_fin()
{	
	////////////////	
	//para los threads
	para_subthrs();

	revisa_calles_cortadas();

	//////////////////////////////////
	//calcula si va a ser multitask o no
	CoptiMemo oo; //se deja a false siempre de momento
	olv->modo_multitask=FALSE;//oo.is_multi(olv_limp->conjs.n,n_subthr,sizeof(Djkt_elem_cola));
	//////////////////////////////////

	olvlog(LOG_TODO,"olv_limp_t","FIN Matriz de ang entre conjs %ldx%ld",
		olv_limp->conjs.n,olv_limp->conjs.n);
	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la matriz de ángulos entre todas las conjunciones adyacentes a una dada, es la parte de cálculos que 
 * realizan los subthreads. 'ithr' indica qué thread es, para calcular qué conjunciones le tocan.
 */
void Colv_limp_thr::calcula_ang_conj_sub(int ithr)
{
	Param_olv_limp_thr pp;

	int i,j,nconj,KK,na,ic,nady;
	int n_ini, n_desp, n_fin, seg;
	BOOL mal=FALSE;
	BYTE aa;
	BYTE *conjs;	
	double ang;

	////////////////
	pp.id_e=OLV_TAREA_COST_AMB;//manda de parámetro la tarea de la que es el progreso
	KK=olv_limp->tipo_ambit;	
	nconj=olv_limp->conjs.n;
	n_desp = (int)ceil(1.0*nconj/n_subthr);	
	n_ini=ithr*n_desp;
	n_fin = min((ithr+1)*n_desp,nconj);
	na=0;
	conjs=NULL;
	conjs=(BYTE*)malloc(olv_limp->conjs.n*sizeof(BYTE));
	if(!conjs)
		mal=TRUE;
	else
		memset(conjs,0,olv_limp->conjs.n*sizeof(BYTE));
	////////////////
	
	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Ángulos de conjunciones %04d a %04d", ithr,n_ini, n_fin);	
	
	seg = GetTickCount();
	/////////////////////////////////////
	//bucle por cada conjunción de la carto
	for(ic=n_ini; ic<n_fin && !mal && !pirate; ic++)
	{		
		nady=0;
		memset(conjs,0,olv_limp->conjs.n*sizeof(BYTE));
		//Busca conjunciones adyacentes
		for(i=0;i<nconj;i++)
		{
			if(i==ic)
				continue;

			if((olv_limp->cost_conj[i][ic]>=MAYUSCULO) && (olv_limp->cost_conj[ic][i]>=MAYUSCULO))
				continue;

			//marca las conjunciones que son adyacentes
			conjs[i]=1;

			for(j=i+1;j<nconj;j++)
			{
				if(j==ic)
					continue;

				if(olv_limp->cost_conj[ic][j]>=MAYUSCULO)
				{
					continue;
				}				

				//marca las conjunciones que son adyacentes
				conjs[j]=1;
			}
		
		}
		for(i=0;i<nconj;i++)
		{
			if(conjs[i])
				nady++;
		}
		if(nady==0)
			continue;
		if(nady>16)
		{
			nady=nady;
		}
		//ya tiene las adyacentes de la conjunción ic, inicializa array de angulos
		if(!olv_limp->ang_conj[ic].inicia(nady))
		{
			mal=TRUE;
			break;
		}		
		//Busca conjunciones adyacentes
		for(i=0;i<nconj;i++)
		{
			if(!conjs[i])
				continue;			

			for(j=0;j<nconj;j++)
			{
				if(!conjs[j])
					continue;	
				

				if((olv_limp->cost_conj[i][ic]>=MAYUSCULO) || (olv_limp->cost_conj[ic][j]>=MAYUSCULO))
				{
					aa=0;					
				}
				else
				{					
					//si no hay restricciones de circulación, se pone que se el ángulo es ok siempre
					//si no, se calcula, y el ángulo es ok si es menor que el ángulo límite
					//if(olv_limp->res_circ!=OLV_RES_NO)
					{	
						ang=dame_ang_conj(ic,i,j);
						aa=(ang<=olv_limp->ang_lim);
					}
				}
				olv_limp->ang_conj[ic].pon_ang_i_j(i,j,aa);		
				
				na++;
				
			}
		}

		//avisa de progreso
		if(((ic-n_ini)%500==0) || ((ic-n_ini)==(n_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Rellenando matriz de ang entre conjs %ld de %ld", ithr,
				(ic-n_ini+1),n_desp);
			//avisa de progreso	
			prog_subthr=((1.0*(ic-n_ini+1)/n_desp)+1)/3;///3 porque es la tercera parte del progreso los costes de conjunciones
			thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
		}
	}	

	if(conjs)
		free(conjs);

	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin Matriz de ang entre conjs, %ld ángulos, %.3f seg", ithr, na,1.0*(GetTickCount()-seg)/1000);

	thr_padre->encola(OLV_LIMP_EV_ANG_CONJ_FIN,NULL,FALSE);
}
//*************************************************************************************
/**
 * Devuelve el ángulo entre dos conjunciones
 */
double Colv_limp_thr::dame_ang_conj(int ic, int i, int j)
{	
	double ang, *p, v[2][2];
	int npts,k,t;
	CartoBaseInfoEntity ient;
	int refconj_i = olv_limp->tip_conj[i][ic];
	int refconj_j = olv_limp->tip_conj[j][ic];
	
	ang=0;
	
	//cambio de sentido en carretera o ámbito
	if(i==j)
	{
		if((olv_limp->iaso[refconj_i].flgs & OLV_LIMP_FLG_NW) || (olv_limp->iaso[refconj_j].flgs & OLV_LIMP_FLG_NW))
		{
			if(olv_limp->res_circ==OLV_RES_NO)
				return 0;
			else
				return OLV_PI;//ángulo de 180º en carretera y sigue sentidos, no se puede (excepto si es calle cortada, que se revisa luego)
		}
		else 
			return 0;
	}

	if(!(olv_limp->iaso[refconj_i].flgs & OLV_LIMP_FLG_NW) || !(olv_limp->iaso[refconj_j].flgs & OLV_LIMP_FLG_NW))			
	{
		return 0;//uno de los dos no son carretera, se puede siempre
	}
				
	if(((olv_limp->iaso[refconj_i].flgs & OLV_LIMP_FLG_NW_REP) && (olv_limp->iaso[refconj_i].refe2 == refconj_j)) || 
		((olv_limp->iaso[refconj_j].flgs & OLV_LIMP_FLG_NW_REP) && (olv_limp->iaso[refconj_j].refe2 == refconj_i)))
	{
		//si intenta ir de nw a réplica, pero de la misma calle
		return OLV_PI;
	}
	//return 0;		
	//las dos son carretera, mira si por coste no se puede ir	
	//calcula los puntos próximos a la conjunción	
	for(t=0;t<2;t++)
	{
		if(t==0)
			ient = olv_limp->carto.getRef(refconj_i);
		else
			ient = olv_limp->carto.getRef(refconj_j);	
	
		p=ient.getPto(0);
		npts=ient.getNumberPtos();
		if(Colv_geom::pto_equals(olv_limp->conjs.coor[ic], p))
		{
			p=ient.getPto(1);
			//la conjunción es el primer punto
			for(k=0;k<2;k++)
			{				
				v[t][k]=p[k]-olv_limp->conjs.coor[ic][k];
			}
		}
		else
		{
			p=ient.getPto(npts-2);
			//la conjunción es el último punto
			for(k=0;k<2;k++)
			{				
				v[t][k]=p[k]-olv_limp->conjs.coor[ic][k];
			}
		}	
	}	
	
	ang=Colv_geom::ang_vect(v[0],v[1]);
	ang=OLV_PI-ang;		
	
	return ang;
}
//*************************************************************************************
/**
 * Resvisa los ángulos, de forma que si hay algún giro "prohibido" de 180º, en caso
 * de que sean calles cortadas o sin salida, los pone a ok
 */
void Colv_limp_thr::revisa_calles_cortadas()
{ 
	int ic,i,j,k,nady;
	//if(olv_limp->res_circ==OLV_RES_NO)
	//	return;
	for(ic=0;ic<olv_limp->conjs.n;ic++)
	{
		nady=olv_limp->ang_conj[ic].nady;
		for(i=0;i<nady;i++)	
		{
			for(j=0;j<nady;j++)	
			{
				if(!olv_limp->ang_conj[ic].angs[i][j])
				{
					//si el ángulo es prohibido, mira a ver si hay más conjunciones
					for(k=0;k<nady;k++)
					{
						if(olv_limp->ang_conj[ic].i_conjs[k]<0 || olv_limp->ang_conj[ic].i_conjs[k]>=olv_limp->conjs.n)
						{
							olvlog(LOG_TODO,"olv_limp_t","Ojo ang_conj fuera de límites ic %ld, k %ld",ic,k);
							continue;
						}
						/*if(((k!=i) || (k!=j)) && (olv_limp->conjs.inc[olv_limp->ang_conj[ic].i_conjs[k]].n>1))
							break;*/
						if((olv_limp->ang_conj[ic].i_conjs[k]!=olv_limp->ang_conj[ic].i_conjs[i]) && 
							(olv_limp->ang_conj[ic].i_conjs[k]!=olv_limp->ang_conj[ic].i_conjs[j]) && 
							(olv_limp->cost_conj[ic][olv_limp->ang_conj[ic].i_conjs[k]]<MAYUSCULO) &&
							(olv_limp->conjs.inc[olv_limp->ang_conj[ic].i_conjs[k]].n>1))
							break;
					}
					if(k>=nady)//estos nodos son los únicos que tiene para entrar y salir
					{
						olv_limp->ang_conj[ic].angs[i][j]=1;
					}
				}
			}
		}
	}
}
//*************************************************************************************
/**
 * Rellena la matriz de costes entre todos los ámbitos
 */
BOOL Colv_limp_thr::calcula_cost_amb()
{	
	////////////////

	olvlog(LOG_TODO,"olv_limp_t","Rellenando matriz de costes entre ámbitos");
	pon_mi_progre(OLV_TAREA_COST_AMB, (int) (OliviaDef::GeneralDef::ProgrMax*2/3));
	pon_mi_msg("Rellenando matriz de costes entre ámbitos. %ld ámbitos por calcular",olv_limp->n_amb);	
	err_str[0]=0;
	char st[MAX_PATH];
	char st1[MAX_PATH];
	
	strcpy_s(st1,MAX_PATH,olv_limp->olv->paths.path_temp);
	if(st1[strlen(st1)-1]=='\\')
	{
		st1[strlen(st1)-1]=0;
	}
	sprintf(st,"%s\\%s",st1,NOMB_ARCH_DIJ_DEF);
	//inicia archivo para los djistra--------------
	if(!olv_limp->arch_dj.inicia(st,!olv->modo_multitask,olv_limp->conjs.n))
	{
		olvlog(LOG_TODO,"olv_limp_t","Error al iniciar archivo dj en directorio %s",st);
		return FALSE;
	}
	if(!olv_limp->arch_dj.inicia_inf_amb(&olv_limp->iaso,olv_limp->n_amb,olv_limp->tipo_ambit,olv_limp->nod_instal, olv_limp->nod_plant))
	{
		olvlog(LOG_TODO,"olv_limp_t","Error al iniciar info de ambitos en archivo de dj");
		return FALSE;
	}
	
	////////////////////////////////////////////////
	if(!inicia_cost_amb())
	{
		return FALSE;
	}

	if(!olv_limp->olv->modo_multitask)
	{	
		//lanza los threads, tiene memo suficiente para todos los threads		
		lanza_subthrs(OLV_LIMP_EV_COST_AMB_SUB);		
	}
	else
	{		
		//en modo multitask entra aquí cuando ya han terminado las tasks
		//se lee la matriz de ámbitos que han guardado las tasks
		if(!olv_limp->arch_dj.lee_dis())
			return FALSE;
		if(!olv_limp->olv_tasks->lee_cost_amb(olv_limp->cost_amb))
			return FALSE;	

		//borra los archivos temporales
		borra_temp_files(FALSE);

		//después de leerla, encola el cost_amb_fin
		for(int i=0;i<n_subthr;i++)
		{
			subthrs[i]->prog_subthr=0;//para que no dé error
			encola(OLV_LIMP_EV_COST_AMB_FIN,NULL,FALSE);
		}
	}

	return TRUE;
}
//*************************************************************************************
BOOL Colv_limp_thr::inicia_cost_amb()
{
	int i,j;

	//pide memoria para el array de distancias entre ámbitos		
	if(!olv_limp->cost_amb.inicia(olv_limp->n_amb,olv_limp->n_amb))
	{
		pon_mi_msg("Error, sin memoria para matriz de dist entre ámbitos");
		return FALSE;
	}

	//inicializa todo a 0
	for(i=0;i<olv_limp->n_amb;i++)
	{
		for(j=0;j<olv_limp->n_amb;j++)
			olv_limp->cost_amb[i][j]=(float)MAYUSCULO;//porque se va a almacenar la minima
	}

	//Inicia el array de orden /secuencia
	olv_limp->ord_sec=(Secu_amb*)malloc(sizeof(Secu_amb)*olv_limp->n_amb);
	if(!olv_limp->ord_sec)
	{
		pon_mi_msg("Error, sin memoria para matriz de orden y secuencia");
		return FALSE;
	}
	memset(olv_limp->ord_sec,0,sizeof(Secu_amb)*olv_limp->n_amb);

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la matriz de distancias entre todos los ámbitos.
 * El thread entra aquí cuando los subthreads que realizan la tarea realmente han finalizado
 */
BOOL Colv_limp_thr::calcula_cost_amb_fin()
{	
	////////////////
	int ai=1;
	
	if(!olv_limp->olv->modo_multitask)
	{	
		//para los threads
		para_subthrs();
	}

	if(pirate)
		return FALSE;

	////////////////
	//mira si hay aislados
	if(!avisa_aislados())
		return FALSE;

	//avisa aislados ha ido bien, no hay aislados

	if(pirate)
		return FALSE;

	//calcula el coste a las plantas
	if(!calcula_cost_plant())
	{
		pon_mi_msg("Error, planta o instalación aisladas");
		return FALSE;
	}

	olv_limp->nsec_act=olv_limp->nsec;

	olvlog(LOG_TODO,"olv_limp_t","FIN Matriz de dist entre ámbitos %ldx%ld",
		olv_limp->n_amb,olv_limp->n_amb);

	return TRUE;
}
//*************************************************************************************
/**
 * Dado el array relleno con los aislados, saca cartel avisando
 */
BOOL Colv_limp_thr::avisa_aislados()
{
	int i,j,k,ii, ref_i, ref_j;
	BYTE *ambs_ais;
	char ais_msg[OLV_MAX_MSG_PROCE];
	char nfile[MAX_PATH];

	strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
	//cambiaext(nfile,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");
	ambs_ais = (BYTE*)malloc(olv_limp->n_amb);
	if(!ambs_ais)
	{		
		pon_mi_msg("Error, sin memoria en fin de calcula coste ámbitos");
		return FALSE;
	}
	memset(ambs_ais,0,olv_limp->n_amb);

	//revisa costes de ámbitos
	int nais;
	for(i=0;i<olv_limp->n_amb; i++)
	{
		if(ambs_ais[i])
			continue;
		ref_i=olv_limp->carto.get(i).entity()->ref;

		if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;
		for(j=0;j<olv_limp->n_amb; j++)
		{
			if(i==j)
				continue;
			ref_j=olv_limp->carto.get(j).entity()->ref;

			if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			if(ambs_ais[j])
				continue;
			if(olv_limp->cost_amb[i][j]>=MAYUSCULO)
			{
				//puede estar aislado i o j
				nais=0;				
				for(k=0;k<olv_limp->n_amb;k++)
				{
					if(k==i)
						continue;
					if(olv_limp->cost_amb[k][j]>=MAYUSCULO)//comprueba si j está aislado para los demás ámbitos también
					{
						nais=j;	
						break;
					}
					if(k==j)
						continue;
					if(olv_limp->cost_amb[i][k]>=MAYUSCULO)//comprueba si i está aislado para los demás ámbitos también
					{
						nais=i;	
						break;
					}				
				}
				if(k<olv_limp->n_amb)
					ambs_ais[nais]=1;
			}
		}
	}

	nais=0;
	int inw,inw2;
	INT64 flgs2;
	for(i=0;i<olv_limp->n_amb;i++)
	{
		if(ambs_ais[i])
		{
			nais++;			
			inw=olv_limp->inww_amb[i].refnw;
			if(olv_limp->tipo_ambit==OLV_AMB_LIN)
			{
				inw2=olv_limp->inww_amb[i+olv_limp->n_amb].refnw;
				flgs2=olv_limp->iaso[inw2].flgs;
			}
			else
			{
				inw2=0;
				flgs2=0;
			}
			olvlog(LOG_TODO,"olv_limp_t","Ámbito %05d aislado, inw1 %05d inw2 %05d, flags amb %02X inw1 %02X inw2 %02X ",i,inw,inw2,
				olv_limp->iaso[i].flgs,olv_limp->iaso[inw].flgs,flgs2);
		}
	}

	if(!nais)
	{
		free(ambs_ais);
		return TRUE;
	}

	if(nais==1)	
		sprintf_s(ais_msg,"Encontrado %ld ámbito aislado %s: ", nais,olv_limp->igno_ais?"(Se ignora)":"");	
	else	
		sprintf_s(ais_msg,"Encontrados %ld ámbitos aislados %s: ",nais,olv_limp->igno_ais?"(Se ignoran)":"");
	int inais=0;
	for(i=0;i<olv_limp->n_amb;i++)
	{
		if(ambs_ais[i])
		{
			ref_i=olv_limp->carto.get(i).entity()->ref;
			if(olv_limp->igno_ais)//si toca ignorar aislados, lo marca para ignorarlo en la sectorización
			{
				olv_limp->iaso[ref_i].flgs|=OLV_LIMP_FLG_AMB_NO;
			}

			ii=olv_limp->iaso[ref_i].oid;
			if(nais==1)	
			{
				sprintf_s(ais_msg,"%s %ld",ais_msg,ii);
				break;
			}
			else if(inais==nais-1)
				sprintf_s(ais_msg,"%s y %ld",ais_msg,ii);
			else if(inais>0 && inais%4==0)
				sprintf_s(ais_msg,"%s %ld,\n",ais_msg,ii);
			else
				sprintf_s(ais_msg,"%s %ld,",ais_msg,ii);
			if(strlen(ais_msg)+10>=OLV_MAX_MSG_PROCE)
				break;
			inais++;

		}
	}
	if(i<olv_limp->n_amb && nais>1 && ((strlen(ais_msg)+5)<OLV_MAX_MSG_PROCE))
		sprintf_s(ais_msg,"%s %s",ais_msg,"y mas");
	
	pon_mi_msg(ais_msg);
	if(olv_limp->igno_ais)
		Sleep (OLV_T_SLEEP_MSG);
	////////////////////////////
	
	free(ambs_ais);
	if(olv_limp->igno_ais)
		return TRUE;
	else
		return FALSE;
}
//*************************************************************************************
/**
 * Apunta en qué nodos está la planta y la instalación
 */
BOOL Colv_limp_thr::calcula_cost_plant()
{
	int ic,ia,ka,nais,k, ref_ia;
	Djkt_nodo *costes_nodos;
	BOOL mal=FALSE;

	if(olv_limp->nod_instal<0)
		return TRUE;

	//Inicia el array de orden /secuencia
	olv_limp->ord_sec_plan=(Secu_amb*)malloc(sizeof(Secu_amb));
	if(!olv_limp->ord_sec_plan)
	{
		pon_mi_msg("Error, sin memoria para matriz de orden y secuencia");
		return FALSE;
	}
	memset(olv_limp->ord_sec_plan,0,sizeof(Secu_amb));
	olvlog(LOG_TODO,"olv_limp_t","Calculando coste a planta e instalación");

	costes_nodos=NULL;
	k=0;
	
	ic=olv_limp->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))
	{
		pon_mi_msg("Error al calcular costes de ámbitos a instalación");
		return FALSE;
	}

	olv_limp->ord_sec_plan[k].ctnod[0]=costes_nodos;
	olv_limp->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_limp->ord_sec_plan[k].ctnod[0][olv_limp->iaso[ref_ia].inod[ka]].dis>=MAYUSCULO)
			{
				nais++;
				break;
			}
		}
		if(nais)
			break;
	}
	if(ia<olv_limp->n_amb)
	{
		pon_mi_msg("Error al calcular costes de ámbitos a instalación");
		return FALSE;
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la matriz de distancias entre todos los ámbitos, es la parte de cálculos que 
 * realizan los subthreads. 'ithr' indica qué thread es, para calcular qué ámbitos le tocan.
 */
void Colv_limp_thr::calcula_cost_amb_sub(int ithr)
{
	int na_ini,na_fin,na_desp,na,i,k;
	int KK, seg;
	BOOL log_debug=FALSE;
	Djkt_nodo *costes_nodos;
	double caux;
	Param_olv_limp_thr pp;
	BOOL mal=FALSE;
	CartoBaseInfoEntity ient_na, ient_i;
	int ref_na, ref_i, amb_i, amb_na;

	////////////////
	pp.id_e=OLV_TAREA_COST_AMB;//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);
	costes_nodos=NULL;
	////////////////
	
	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Ambs %04d a %04d", ithr,na_ini, na_fin);
	
	seg = GetTickCount();
	/////////////////////////////////////
	//Bucle por cada ámbito de los que le tocan a este thread
	/////////////////////////////////////
	//el coste de un ámbito a sí mismo es el de trabajar ese ámbito, 
	//que es el coste de ir de su conj inicial a la final
	na=na_ini;	
	
	/////////////////////////////////////
	for(na=na_ini;na<na_fin && !pirate; na++)
	{		
		//En olv_limp->ias[i].ic_ini está almacenado el índice de la conjunción del nodo inicial del ámbito
		//y en olv_limp->ias[i].ic_fin el del final. 	
		/////////////////////////////////////////////
		//calcula el coste máximo del ámbito na a todos los demás
		//los añade a la fila na de la matriz de costes
		//es coste máximo porque hace el máximo de:
		//inicio(na)->inicio(ni), inicio(na)->final(ni), final(na)->inicio(ni), final(na)->final(ni)
		/////////////////////////////////////////////
		//k==0, calcula las distancias del nodo inicial de ese ámbito a todas las demás conjunciones
		//k==1, calucla las distancias del nodo final		
		ient_na = olv_limp->carto.get(na);
		ref_na = ient_na.entity()->ref;
		amb_na=olv_limp->iaso[ref_na].iamb;

		for(k=0;k<KK;k++)
		{	
			costes_nodos=NULL;
			if(!Colv_geom::dijkstra_ang_inv_ok(olv_limp->cost_conj, olv_limp->ang_conj, olv_limp->conjs.n, 
				(1-k)*olv_limp->iaso[ref_na].inod[0]+k*olv_limp->iaso[ref_na].inod[1], 
				&costes_nodos, &visto_ang))
			{
				mal=TRUE;
				break;
			}		
		
			//recorre todos los demás ámbitos buscando el coste a ellos en el array de costes devuelto, y los almacena
			//almacena el coste a su nodo inicial y a su nodo final
			if(olv_limp->iaso[ref_na].flgs & OLV_LIMP_FLG_AMB_NO)
			{
				for (i=0; i<olv_limp->conjs.n; i++)
				{
					costes_nodos[i].dis=(float)MAYUSCULO;
					costes_nodos[i].id_padre=-1;
					costes_nodos[i].ids_ady.nady=0;
				}
			}
			else
			{
				for(i=0;i<olv_limp->n_amb;i++)
				{
					ient_i = olv_limp->carto.get(i);
					ref_i = ient_i.entity()->ref;
					amb_i=olv_limp->iaso[ref_i].iamb;

					if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
						continue;
					if(na==i)
					{
						//el coste de un ámbito a sí mismo es el de trabajar ese ámbito
						olv_limp->cost_amb[amb_na][amb_na]=olv_limp->cost_conj[olv_limp->iaso[ref_na].inod[0]][olv_limp->iaso[ref_na].inod[1]];
						continue;
					}
					
					if(olv_limp->cost_amb[amb_i][amb_na]>costes_nodos[olv_limp->iaso[ref_i].inod[0]].dis)
						olv_limp->cost_amb[amb_i][amb_na]=costes_nodos[olv_limp->iaso[ref_i].inod[1]].dis;
					if(KK==OLV_AMB_LIN)
					{				
						if(olv_limp->cost_amb[amb_i][amb_na]>costes_nodos[olv_limp->iaso[ref_i].inod[0]].dis)
							olv_limp->cost_amb[amb_i][amb_na]=costes_nodos[olv_limp->iaso[ref_i].inod[1]].dis;							
					}
				}
			}			
			
			if(!olv_limp->arch_dj.add_b(costes_nodos, na, k, TRUE))
			{
				olvlog(LOG_TODO,"olv_limp_t","Subthr %ld,Error %ld no se ha podido guardar dj iref: %ld k: %ld", ithr,
					GetLastError(),na,k);
			}
			
			for(i=0;i<olv_limp->conjs.n;i++)
			{
				costes_nodos[i].libera();
			}
			free(costes_nodos);
			
			olv_limp->ord_sec[na].ctnod[k]=NULL;
			if(KK==1)
				olv_limp->ord_sec[na].ctnod[1]=NULL;
			
		}
		if(mal)
			break;

		//si es ámbito lineal calcula la distancia media de los cuatro nodos
		if(na==1)
		if(log_debug)
		{
			for(i=0;i<olv_limp->n_amb;i++)
			{
				if(olv_limp->cost_amb[amb_na][i]>=MAYUSCULO)
					caux=-1;
				else
					caux=olv_limp->cost_amb[amb_na][amb_i];
				olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Coste ámb %ld a ámb %ld es %lf", ithr,
					na,i,caux);
			}
		}		

		//avisa de progreso
		if(((na-na_ini)%100==0) || ((na-na_ini)==(na_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Rellenando matriz de dist entre ambs %ld de %ld", ithr,
				(na-na_ini+1),na_desp);
			//avisa de progreso	
			prog_subthr=((1.0*(na-na_ini+1)/na_desp)+2)/3;///3 porque es la tercera parte del progreso los costes de conjunciones
			thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
		}
	}

	if(visto_ang)
	{
		free(visto_ang);
		visto_ang=NULL;
	}
	
	if(mal)
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en cálculo de matriz de distancias entre ámbitos", ithr);
		prog_subthr=-1;//para avisar al padre de que ha habido un error
	}
	else
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin Matriz de dist entre ambs, %.3f seg", ithr, 1.0*(GetTickCount()-seg)/1000);
	}
	thr_padre->encola(OLV_LIMP_EV_COST_AMB_FIN,NULL,FALSE);

	/////////////////////////////////////
}
//*************************************************************************************
/**
 * Genera los sectores 
 */
BOOL Colv_limp_thr::sectoriza()
{
	int i;
	BOOL res=TRUE;

	if(olv_limp->n_amb<2)
	{
		pon_mi_msg("Error, número de ámbitos es %ld",olv_limp->n_amb);
		return FALSE;
	}	

	pon_mi_progre(OLV_TAREA_SECTORIZ, 0);
	pon_mi_msg("");	
	err_str[0]=0;

	if(!pide_memo_secto())
	{
		pon_mi_msg("Error, Sin memoria para sectorización");
		return FALSE;
	}		

	//////////////////////////////////////////////////////////////
	olvlog(LOG_TODO,"olv_limp_t","Comienza sectorización %ld ámbitos en %ld sectores",
		olv_limp->n_amb, olv_limp->nsec_act);	

	///////////////////////////////////////
	//Algoritmo 1
	if(!sectoriza_1())
	{
		pon_mi_msg("Errores producidos en sectorización: %s",err_str);
		res=FALSE;
		goto pinta;
	}	

	///////////////////////////////////////
	//Si es barrido mixto hay que copiar la info en las que no se ha sectorizado
	if(olv_limp->barr_mix)
		copia_info_barr_mix();
	
	//////////////////////////////////////////////////////////////////////////////
	//Guarda el shape añadiendo la columna de sector
	if(!guarda_dbf_sector(0))
	{
		pon_mi_msg("Errores producidos en sectorización: %s",err_str);
		return FALSE;
	}	
	//Guarda el shape añadiendo la columna de secuencia vacía
	if(!guarda_dbf_sector(1))
	{
		pon_mi_msg("Errores producidos en sectorización: %s",err_str);
		return FALSE;
	}	
	//////////////////////////////////////////////////////////////////////////////
	for(i=0;i<olv_limp->nsec;i++)
	{
		olvlog(LOG_TODO,"olv_limp_t","Sector %ld, %03d ámbitos, coste total %lf",i,olv_limp->sec[i].namb, olv_limp->sec[i].cost_ac);
	}
	olvlog(LOG_TODO,"olv_limp_t","Finalizada generacion de sectores--------------------------");

pinta:	
	
	return res;
}
//*************************************************************************************
/**
 * Pide memoria e inicializa los arrays para la sectorización
 */
BOOL Colv_limp_thr::pide_memo_secto()
{
	int i,j;
	//////////////////////////////////////////////////////////////
	//pide memoria para el array de distancias del sector
	olv_limp->sec = (Info_sec *)malloc(olv_limp->nsec*sizeof(Info_sec));
	if(!olv_limp->sec)
	{
		pon_mi_msg("Error, sin memoria para matriz de sectores");
		return FALSE;
	}
	memset(olv_limp->sec,0,olv_limp->nsec*sizeof(Info_sec));
	for(i=0;i<olv_limp->nsec;i++)
	{		
		olv_limp->sec[i].iamb = (short *)malloc(olv_limp->n_amb*sizeof(short));
		if(!olv_limp->sec[i].iamb)
		{
			pon_mi_msg("Error, sin memoria para matriz de sectores");
			return FALSE;
		}
	}
	//inicializa todo a mayúsculo
	for(i=0;i<olv_limp->nsec;i++)
	{
		olv_limp->sec[i].namb=0;
		olv_limp->sec[i].iamb_ini_def=-1;
		olv_limp->sec[i].sec_def = i+1;
		olv_limp->sec[i].t_despl[0]=olv_limp->sec[i].t_despl[1]=(float)olv_limp->t_despl;
		for(j=0;j<olv_limp->n_amb;j++)
		{
			olv_limp->sec[i].iamb[j]=-1;			
		}
	}
	//////////////////////////////////////////////////////////////
	//pide memoria para el array de ámbitos asignados al sector
	olv_limp->amb_sec = (Info_amb_sec *)malloc(olv_limp->n_amb*sizeof(Info_amb_sec));
	if(!olv_limp->amb_sec)
	{
		pon_mi_msg("Error, sin memoria para matriz de ámbitos en los sectores");
		return FALSE;
	}
	memset(olv_limp->amb_sec,0,olv_limp->n_amb*sizeof(Info_amb_sec));
	//inicializa todo
	for(j=0;j<olv_limp->n_amb;j++)
	{
		olv_limp->amb_sec[j].sec=-1;
		olv_limp->amb_sec[j].iseq=-1;
		olv_limp->amb_sec[j].t=0;
	}

	olv_limp->nsec_orig=olv_limp->nsec;

	return TRUE;
}
//*************************************************************************************
/**
 * Añade el ámbito 'i_amb' al sector 'i_sec', actualizando la info en todos los lugares necesarios
 */
BOOL Colv_limp_thr::add_amb_sec(int i_amb, int namb, int i_sec, Info_sec *ss, Info_amb_sec *aa,  Matrix2d<float> &cost_amb, double cost_tot, int i_amb_p)
{	
	if(olv_limp->iaso[olv_limp->carto.get(i_amb).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
		return FALSE;
	ss[i_sec].iamb[ss[i_sec].namb]=i_amb;
	ss[i_sec].namb++;
	//apunta el ámbito al sector
	aa[i_amb].sec=i_sec;

	return TRUE;
}
//*************************************************************************************
/**
 * Le quita el ámbito 'i_amb' al sector 'i_sec', actualizando la info en todos los lugares necesarios
 * Actualiza el coste que es el que lleva, mas el desplazamiento del que ya tiene al nuevo, más el coste del nuevo
 * Al salir, hay que actualizar las distancias!
 */
void Colv_limp_thr::quita_amb_sec(int i_amb, int namb, int i_sec, Info_sec *ss, Info_amb_sec *aa,  Matrix2d<float> &cost_amb, int i_amb_p)
{		
	int i,j;
	for(i=0;i<ss[i_sec].namb;i++)
	{
		if(ss[i_sec].iamb[i]==i_amb)
			break;
	}
	if(i>=ss[i_sec].namb)
		return ; //no lo tenía este sector

	//le quita de su array de índices si tiene al menos uno posterior
	for(j=i;j<ss[i_sec].namb-1;j++)
	{
		ss[i_sec].iamb[j]=ss[i_sec].iamb[j+1];
	}
	ss[i_sec].namb--;
	
	//desapunta el ámbito
	aa[i_amb].sec=-1;	
}
//*************************************************************************************
/**
 * Genera sectores en función del árbol. Asigna un ámbito a cada sector hasta nsec-1, y al último el resto de ámbitos
 */
BOOL Colv_limp_thr::genera_sectores3(int iamb_extr, int n_amb, int n_sec, Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa)
{
	int s, i,ii, j, k;
	double d, dmax;	
	BOOL sec_cerc;

	//busca elementos-------------------------------
	add_amb_sec(iamb_extr,n_amb,0,ss,aa,cost_amb,MAYUSCULO,-1);
	//busca ambitos extremos--------------------
	for(s=1; s<n_sec; s++)
	{
		dmax=0;
		k=-1;
		sec_cerc=TRUE;
		for (j=0; j<n_amb; j++)
		{
			if(aa[j].sec>=0)
				continue;
			if(olv_limp->iaso[olv_limp->carto.get(j).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)//se ha marcado para no usarse, por aislado o por carga insuficiente
			{
				aa[j].sec=-1;
				continue;
			}

			for (ii=0; ii<aa[j].namb_cerca; ii++)
			{
				if(aa[aa[j].iamb_cerca[ii]].sec>=0)
					break;
			}		
			if(!sec_cerc && ii<aa[j].namb_cerca)
				continue;
			d=DBL_MAX;
			for(i=0; i<s; i++)
			{
				if(cost_amb[ss[i].iamb[0]][j]<d)
					d=cost_amb[ss[i].iamb[0]][j];
			}
			if(dmax<d)
			{
				dmax=d;
				k=j;
				sec_cerc=ii<aa[j].namb_cerca;
			}
		}
		if(k<0)
		{
			return FALSE;//no debería
		}
		add_amb_sec(k,n_amb,s,ss,aa,cost_amb,MAYUSCULO,-1);
	}	

	//asigna el resto de ámbitos al último sector s=n-1
	for (j=0; j<n_amb; j++)
	{
		if(aa[j].sec>=0)
			continue;
		if(olv_limp->iaso[olv_limp->carto.get(j).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)//se ha marcado para no usarse, por aislado o por carga insuficiente
			continue;

		add_amb_sec(j,n_amb,n_sec-1,ss,aa,cost_amb,MAYUSCULO,-1);
		k=j;
	}			
	
	return TRUE;	
}
//*************************************************************************************
/**
 * Añade el ámbito 'i_amb' al sector 'i_sec', actualizando la info en todos los lugares necesarios
 * Actualiza el coste que es el que lleva, mas el desplazamiento del que ya tiene al nuevo, más el coste del nuevo
 */
BOOL Colv_limp_thr::add_amb_sec_cost(int i_amb, int namb, int i_sec, Info_sec *ss, Info_amb_sec *aa,  Matrix2d<float> &cost_amb)
{	
	if(olv_limp->iaso[olv_limp->carto.get(i_amb).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
		return FALSE;
	ss[i_sec].iamb[ss[i_sec].namb]=i_amb;
	ss[i_sec].namb++;
	//apunta el ámbito al sector
	aa[i_amb].sec=i_sec;

	//actualiza el coste del sector
	//si no es el primer ámbito, suma el coste de ir del anterior a este
	double dmed;
	int k;
	dmed=0;
	if(ss[i_sec].namb>1)
	{
		//calcula la distancia media entre los extremos
		for(k=0; k<3*olv_limp->tipo_ambit-2; k++)
		{			
			dmed+=olv_limp->arch_dj.dame_dis(ss[i_sec].iamb[ss[i_sec].namb-1], k/2, i_amb,k%2);			
		}
		dmed=dmed/(3*olv_limp->tipo_ambit-2);
		ss[i_sec].cost_ac+=(float)dmed;
	}
	//suma el coste de hacer el ámbito
	ss[i_sec].cost_ac+=cost_amb[i_amb][i_amb];

	return TRUE;
}
//*************************************************************************************
/**
 * Prueba sectorizacion algoritmo 1, expansion desde los mas dispares
 */
BOOL Colv_limp_thr::genera_sectores(int iamb_extr, int n_amb, int n_sec,  Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa)
{
	int s, i,ii, j, jj, k, kk;//,jmin;
	double d, dmax,dmed;
	double cos_acum_sec;
	int *isec=NULL;
	int nord, isec_min;
	BOOL hay_cambio=TRUE;
	isec=(int*)malloc(n_sec*sizeof(int));
	memset(isec,0,n_sec*sizeof(int));
	if(!isec)
		return FALSE;
	//busca elementos-------------------------------
	add_amb_sec_cost(iamb_extr,n_amb,0,ss,aa,cost_amb);
	//busca ambitos extremos--------------------
	for(s=1; s<n_sec; s++)
	{
		dmax=0;
		k=-1;
		for (j=0; j<n_amb; j++)
		{
			if(aa[j].sec>=0)
				continue;
			if(olv_limp->iaso[olv_limp->carto.get(j).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)//se ha marcado para no usarse, por aislado o por carga insuficiente
			{
				aa[j].sec=-1;
				continue;
			}
			d=DBL_MAX;
			for(i=0; i<s; i++)
			{			
				if(cost_amb[ss[i].iamb[0]][j]<d)
					d=cost_amb[ss[i].iamb[0]][j];
			}
			if(dmax<d)
			{
				dmax=d;
				k=j;
			}
		}
		if(k<0)
		{
			free(isec);
			return FALSE;//no deberia
		}
		add_amb_sec_cost(k,n_amb,s,ss,aa,cost_amb);
	}

	do 
	{
		if(hay_cambio)
		{
			//se ordenan sectores de mayor a menor coste----------
			nord=0;
			dmax=0;
			for(j=0; j<n_sec; j++)
			{
				dmax+=ss[j].cost_ac/n_sec;
				//busca posicion de sector j
				for(i=0; i<nord; i++)
				{
					if(ss[isec[i]].cost_ac<ss[j].cost_ac)
						break;
				}
				//despeja el lugar
				for(k=nord-1; k>=i; k--)
					isec[k+1]=isec[k];
				isec[i]=j;
				nord++;
			}
			isec_min=nord-1;
			hay_cambio=FALSE;

		}
		else
		{
			isec_min--;
			if(isec_min<0)
			{
				k=0;
				kk=0;
				for(j=0; j<n_sec; j++)
				{
					k+=ss[j].namb;
					for (i=0; i<ss[j].namb; i++)
					{
						for(ii=aa[ss[j].iamb[i]].namb_cerca-1; ii>=0; ii--)
						{							
							if(aa[aa[ss[j].iamb[i]].iamb_cerca[ii]].sec<0)
								kk++;
						}
					}
				}
				if(kk>0 || k!=n_amb)
					olvlog(LOG_TODO,"olv_limp_t","Error en la generacion de sectores, asignados %ld ambitos de %ld, existen %ld ambitos cercanos sin asignar",k, n_amb, kk);
				break;//todos asignados
			}
		}
		//intenta poner a sector de menor coste mas ambitos
		cos_acum_sec=-1;
		while(TRUE)
		{
			if(cos_acum_sec>=0)
			{
				if(cos_acum_sec==ss[isec[isec_min]].cost_ac)
					break;
				if(dmax<ss[isec[isec_min]].cost_ac)
					break;
			}
			cos_acum_sec=ss[isec[isec_min]].cost_ac;
			k=-1;
			d=MAYUSCULO;
			//se recorre todos los ámbitos del sector
				for (i=0; i<ss[isec[isec_min]].namb; i++)
			{
				jj=ss[isec[isec_min]].iamb[i];
				//recorre los cercanos a ese ámbito
				for(ii=aa[ss[isec[isec_min]].iamb[i]].namb_cerca-1; ii>=0; ii--)
				{
					j=aa[jj].iamb_cerca[ii];
					if(aa[j].sec>=0)
						continue;

					//calcula la distancia media de ese ámbito cercano al sector al que lo intenta añadir
					dmed=dame_dmed_amb_sec(j,isec[isec_min]);
					if(dmed<d)
					{
						d=dmed;
						kk=jj;
						k=j;

					}	
					/*
					dacum=dmed;
					while(aa[j].sec<0)
					{
						if(dacum==dmed)//solo la primera vez, solo añade el coste del ámbito
							dacum+=cost_amb[j][j];
						else
							dacum+=cost_amb[jj][j]+cost_amb[j][j];
						if(dacum>=d)
							break;
						if(aa[j].namb_cerca>2)
						{
							nord=0;
							//busca si resto de ramas estan pilladas
							l=-1;
							for (s=0; s<aa[j].namb_cerca; s++)
							{
								if(aa[aa[j].iamb_cerca[s]].sec<0 && !aa[j].iamb_cerca[s]!=jj)
								{
									nord++;
									if(nord>1)
										break;
									if( l<0)
										l=aa[j].iamb_cerca[s];
								}
							}
							if(nord>1 ||l<0)
								break;

						}
						else if(aa[j].namb_cerca>1)
						{
							if(aa[j].iamb_cerca[0]==jj)
								l=aa[j].iamb_cerca[1];
							else
								l=aa[j].iamb_cerca[0];
						}
						else
							break;
						jj=j;
						j=l;
						
						
					}
					if(dacum<d)
					{
						d=dacum;
						kk=ss[isec[isec_min]].iamb[i];
						k=aa[kk].iamb_cerca[ii];
						
					}	*/				
				}
			}

			if (k<0)
				break;//no hay cambio
			hay_cambio=TRUE;
			//añade el ámbito
			add_amb_sec_cost(k,n_amb,isec[isec_min],ss,aa,cost_amb);
			/*
			//se pone el ambito k en sector (y toda la rama)----------------------------------------------
			j=k;
			jj=kk;
			while(aa[j].sec<0)
			{
				//se añade a sector---------------------
				add_amb_sec_cost(j,n_amb,isec[isec_min],ss,aa,cost_amb);
				if(aa[j].namb_cerca>2)
				{
					nord=0;
					//busca si resto de ramas estan pilladas
					l=-1;
					for (s=0; s<aa[j].namb_cerca; s++)
					{
						if(aa[aa[j].iamb_cerca[s]].sec<0)
						{
							nord++;
							if(nord>1)
								break;
							if(aa[j].iamb_cerca[s]!=jj && l<0)
								l=aa[j].iamb_cerca[s];
						}
					}
					if(nord>1 || l<0)
						break;

				}
				else if(aa[j].namb_cerca>1)
				{
					if(aa[j].iamb_cerca[0]==jj)
						l=aa[j].iamb_cerca[1];
					else
						l=aa[j].iamb_cerca[0];
				}
				else
					break;
				jj=j;
				j=l;
			}*/

		}
	} while (TRUE);
	free(isec);

	return TRUE;	
}
//*************************************************************************************
/**
 * Devuelve la distancia media del sector isec al ámbito iamb
 */
double Colv_limp_thr::dame_dmed_amb_sec(int iamb, int isec)
{
	int i;//,j;
	double dmed, dmedtot;
	dmed=dmedtot=0;
	//se recorre todos los ámbitos del sector
	for (i=0; i<olv_limp->sec[isec].namb; i++)
	{		
		dmed=dame_dmed_amb(i, iamb);
		dmedtot+=dmed/olv_limp->sec[isec].namb;
	}
	return dmedtot;
}
//*************************************************************************************
/**
 * Devuelve la distancia media entre ámbitos (sobre todo para cuando son lineales)
 */
double Colv_limp_thr::dame_dmed_amb(int iamb1, int iamb2)
{
	int k;
	double dmed;
	
	dmed=0;
	//calcula la distancia media entre los extremos de i e iamb
	for(k=0; k<3*olv_limp->tipo_ambit-2; k++)
	{			
		dmed+=olv_limp->arch_dj.dame_dis(iamb1, k/2, iamb2,k%2);			
	}
	dmed=dmed/(3*olv_limp->tipo_ambit-2);	
		
	return dmed;
}
//*************************************************************************************
/**
 * Prueba sectorizacion algoritmo pro, sectoriza basado en ámbitos, no en sectores
 */
BOOL Colv_limp_thr::genera_sectores_pro(int n_sec, Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa)
{
	std::map<int,std::vector<int>> sec;
	int i,j,jj,k,kk,s,s2,n,t;
	double dmin,d,d1;
	int nsec;
	int namb;
	BOOL mal=FALSE;
	int nmax, bloq;
	int oo[2];

	//asigna cada ámbito a un sector
	namb=olv_limp->n_amb;	
	bloq=1;
	n=0;
	for(i=0;i<namb;i++)
	{
		if(olv_limp->iaso[olv_limp->carto.get(i).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)//se ha marcado para no usarse, por aislado o por carga insuficiente
		{
			aa[i].sec=-1;
			n++;
			continue;
		}
		aa[i].sec=i-n;
		sec[i-n].push_back(i);
	}
	nsec=namb-n;
	nmax=(int)(nsec/n_sec*1.3);
	
	//lo hace hasta que ya quedan solo el número de sectores que tienen que quedar
	while(nsec>n_sec)
	{
		dmin=DBL_MAX;
		k=kk=-1;
		//recorre los ámbitos, y coge el que tenga un ámbito que pertenezca a 
		//otro sector que esté a la distancia mínima
		for(i=0;i<namb;i++)
		{
			if(olv_limp->iaso[olv_limp->carto.get(i).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)//se ha marcado para no usarse, por aislado o por carga insuficiente
				continue;
			//comprueba que el sector no esté creciendo demasiado
			if(sec[aa[i].sec].size()>nmax)
				continue;
			for(j=0;j<aa[i].namb_cerca;j++)
			{
				jj=aa[i].iamb_cerca[j];
				//si son del mismo sector no lo mira
				if(aa[jj].sec==aa[i].sec)
					continue;
				if((bloq*sec[aa[jj].sec].size())>nmax)
					continue;
				////////////////////////////////
				//calcula la dist media entre el jj y todos los ámbitos del sector de i
				d=0;
				n=(int)sec[aa[i].sec].size();
				for (t=0; t<n; t++)
				{		
					d1=dis_min_amb(oo,sec[aa[i].sec][t],NULL, false,jj);
						//dame_dmed_amb(sec[aa[i].sec][t], jj);
					d+=d1/n;
				}
				///////////////////////////////
				//d=dis_min_amb(oo,i,NULL, false,jj);//dame_dmed_amb(i,jj);
				if(d<dmin)
				{
					dmin=d;
					k=i;
					kk=jj;
					break;//se pira porque los cercanos están ordenados, 
					//cuando encuentra uno que le vale ya los siguientes van a estar más lejos
				}
			}
		}
		if(k<0)
		{
			bloq=0;
			continue;
		}
		bloq=1;
		//ya tiene qué dos ámbitos están a distancia mínima
		//añade al sector de menor índice todos los ámbitos del sector de mayor índice de esos dos ámbitos
		//mira cuál es el sector de menor índice
		s=aa[k].sec;
		s2=aa[kk].sec;
		//a ese le añade todos los ámbitos del otro sector
		sec[s].insert(sec[s].end(),sec[s2].begin(),sec[s2].end());
		for(i=0;i<sec[s2].size();i++)
		{
			aa[sec[s2][i]].sec=s;
		}
		sec[s2].clear();
		//decrementa el número de sectores
		nsec--;
	}
	if(mal)
		return FALSE;
	//aquí ya tiene nsec sectores, inicializa el array de sectores oficial	
	s2=0;
	for(s=0;s<nsec;s++)
	{
		while(sec[s2].size()==0)
		{
			s2++;
		}
		for(i=0;i<sec[s2].size();i++)
		{
			ss[s].iamb[ss[s].namb]=sec[s2][i];
			ss[s].namb++;
			aa[sec[s2][i]].sec=s;
		}		
		s2++;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Prueba sectorización algoritmo 1, expansión según cercanía de árbol de coste mínimo
 */
BOOL Colv_limp_thr::sectoriza_1()
{
	double maxx,dd;
	int iamb,i;

	dd=0;

	/////////////////////////////////////
	//calcula el árbol de coste mínimo para rellenar cercanos
	if(!rellena_amb_cercanos_por_carretera(olv_limp->n_amb, olv_limp->amb_sec, olv_limp->ord_sec))
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al rellenar ambitos cercanos por carretera");
		return FALSE;
	}
	
	//comprueba islas
	if(!quita_islas(olv_limp->n_amb, olv_limp->amb_sec, olv_limp->ord_sec))
	{
		olvlog(LOG_TODO,"quita_islas","No consigue eliminar islas");
		
	}
	//////////////////////
	//Como primer ámbito coge el más extremo
	//el de menor 'y+x'
	maxx=MAYUSCULO;
	int ref_amb;
	for(i=0;i<olv_limp->n_amb;i++)
	{
		ref_amb = olv_limp->carto.get(i).entity()->ref;
		if(olv_limp->iaso[ref_amb].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;
		if((olv_limp->conjs.coor[olv_limp->iaso[ref_amb].inod[0]][1]+olv_limp->conjs.coor[olv_limp->iaso[ref_amb].inod[0]][0])<maxx)
		{
			maxx=olv_limp->conjs.coor[olv_limp->iaso[ref_amb].inod[0]][1]+olv_limp->conjs.coor[olv_limp->iaso[ref_amb].inod[0]][0];
			iamb=i;
		}
	}	

	if((iamb<0) || (iamb>=olv_limp->n_amb))
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error no se ha encontrado ambito extremo");
		return FALSE;
	}

	if(pirate)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Sale por peticion de usuario");
		return FALSE;
	}

	//si se ha calculado el número de sectores ya se ha sectorizado inicialmente, no hay que llamar a genera_sectores
	int nsec;
	if(olv_limp->calc_nsec==0)
	{			
		nsec=olv_limp->nsec;		
	}
	else
	{	
		nsec=olv_limp->nsec_act;
		//entra aquí si ha calculado el número de sectores, y ya va a sectorizar
		//en este modo, primero usa solo los dos primeros sectores, al primero le da un ámbito y al segundo el resto de ámbitos
		
	}
	if(!genera_sectores_pro(nsec,olv_limp->cost_amb,olv_limp->sec, olv_limp->amb_sec))
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al generar sectores");
		return FALSE;
	}
	
	guarda_dbf_sector(0);
	
	pon_mi_progre(OLV_TAREA_PERMU,0);
	if(olv_limp->nsec>1)
	{	
		if(olv_limp->calc_nsec==0)
		{
			dd=iguala_sectores4(olv_limp->n_amb, olv_limp->nsec, olv_limp->cost_amb, olv_limp->sec, olv_limp->amb_sec);
		}
		else
		{	
			//entra aquí si ha calculado el número de sectores, y ya va a sectorizar
			dd=iguala_sectores5(iamb,olv_limp->n_amb, olv_limp->nsec, olv_limp->cost_amb, olv_limp->sec, olv_limp->amb_sec);
		}
		olvlog(LOG_TODO,"olv_limp_t","Conseguida una desviación de: %lf",dd);
	}
	else
	{
		olv_limp->sec[0].cost_ac=(float)calcula_cost_1sec_total(olv_limp->n_amb,olv_limp->sec,olv_limp->ang_conj);
		if(olv_limp->sec[0].cost_ac>=MAYUSCULO)
			dd=-1;
	}	

	if(dd<0)//si es -2, aislados, ya lo ha puesto el iguala_sectores4
	{		
		if(dd==-2)
			sprintf_s(err_str,OLV_MAX_ERR,"Existen ámbitos aislados que\nno ha sido posible unir a la red");
		return FALSE;
	}
	
	return TRUE;
}
//*************************************************************************************
/**
*   parte del ambito central del sector y crea el arbol de camino minimo de dicho sector  
	marca en cada ambito quien es su padre y cuantos hijos tiene
	devuelve el numero de ambitos frontera
**/
int Colv_limp_thr::asigna_padres(int amb_central, int namb,  Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa, int *buf, int nhijos_fron)
{
	int i,j;
	int psel,sel;
	double d, dsel=MAYUSCULO;
	int nn=1;
	int oo[2];

	for (i=0; i<ss->namb; i++)
	{
		if(aa[ss->iamb[i]].iseq!=-1)
		{
			olvlog(LOG_TODO,"olv_limp_t","Error en iasigna_padres, Ambito %d ya tiene padre asignados, sec %d",ss->iamb[i], aa[ss->iamb[i]].sec);


		}
	}
	buf[0]=amb_central;
	aa[amb_central].iseq=-2;
	aa[amb_central].t=0;
	while(nn<ss->namb)
	{
		dsel=MAYUSCULO;
		sel=-1;
		for (i=0; i<nn; i++)//recorre ambitos del arbol
		{
			
			for(j=0; j<ss->namb; j++)//recorre ambitos del sector
			{
				if(aa[ss->iamb[j]].iseq!=-1)
					continue;
				d=dis_min_amb(oo,buf[i],NULL, false,ss->iamb[j]);//cost_amb[buf[i]][ss->iamb[j]];
				if(d<dsel)
				{
					dsel=d;
					sel=ss->iamb[j];
					psel=buf[i];
				}
			}
		}
		if(sel<0)
		{
			olvlog(LOG_TODO,"olv_limp_t","Error en iasigna_padres, no encontrado ambitos libres sin padres");
			break;//terminado (esto no deberia pasar)
		}
		if(aa[psel].iseq<0)
			aa[psel].iseq=sel;
		buf[nn]=sel;
		aa[sel].iseq=psel;
		aa[sel].t+=1;
		aa[psel].t+=1;
		nn++;
	}
	//recorre ambitos para pillar los ambitos frontera----------------
	d=0;
	j=recorre_hijos(amb_central, namb, aa, NULL, 0, cost_amb, &d);
	if((j+1)!=nn)
		olvlog(LOG_TODO,"olv_limp_t","Error en iasigna_padres,Existen hijos aislados");

	nn=0;
	for(j=0; j<ss->namb; j++)//recorre ambitos del sector
	{
		if(aa[ss->iamb[j]].t<=nhijos_fron)
			buf[nn++]=ss->iamb[j];
	}
	

	return nn;
}
//*************************************************************************************
double Colv_limp_thr::dis_min_amb(int ids[2], int id_nod_ini, Secu_amb * ord_sec, BOOL res_nod, int iamb)
{
	double dd=MAYUSCULO;
	double dis;
	double dd2=MAYUSCULO;
	ids[0]=ids[1]=0;
	CartoLine line1, line2;

	double p1[3], p2[3];
	p1[2]=p2[2]=0;
	int i;
	
	//si puntuales, entra una vez, si lineales, entra cuatro
	for(int k=0; k<3*olv_limp->tipo_ambit-2; k++)
	{			
		dis=olv_limp->arch_dj.dame_dis(id_nod_ini, k/2, iamb,k%2);
		if(dis<dd)
		{
			ids[0]=k%2;
			ids[1]=k/2;
			dd=dis;
		}
	}
	if(res_nod)
	{
		ids[1]=olv_limp->iaso[olv_limp->carto.get(id_nod_ini).entity()->ref].inod[ids[1]];
	}

	////////////////////////////////////////////////////////////
	if(OLV_PORC_LINRECT==0)
		dd2=0;
	else
	{	
		if(olv_limp->tipo_ambit==OLV_AMB_LIN)
		{				
			line1.pts.n=0;
			line2.pts.n=0;
			for(i=0;i<2;i++)
			{
				line1.addPto(olv_limp->conjs.coor[olv_limp->iaso[id_nod_ini].inod[i]]);
				line2.addPto(olv_limp->conjs.coor[olv_limp->iaso[iamb].inod[i]]);
			}
			dd2=line1.disMedLines(&line2);
		}
		else
		{			
			dd2=GeometryFunction::Dist2d(olv_limp->conjs.coor[olv_limp->iaso[id_nod_ini].inod[0]],olv_limp->conjs.coor[olv_limp->iaso[iamb].inod[0]]); 
		}
	
		//pasa de dist a segundos
		double velo;
		if(olv_limp->v_despl==0)
			velo=OLV_LIMP_VELO_CIRC_NW*OLV_KMH2MS;
		else
			velo=olv_limp->v_despl;
		dd2=dd2/velo;
	}	
	
	////////////////////////////////////////////////////////////
	//return dd;
	return dd*(1-OLV_PORC_LINRECT)+dd2*OLV_PORC_LINRECT;
}
//*************************************************************************************
typedef struct Dists
{
	double	dist;
	int		iamb;
}Dists;
//*************************************************************************************
BOOL Colv_limp_thr::quita_islas(int namb,  Info_amb_sec *aa, Secu_amb * ord_sec)
{
	int nis =-1, i;
	if(namb<2)
		return true;
	short* islas = (short*) malloc(namb * sizeof(short));

	if(!islas)
		return false;
	//marca todos los ambitos sin islas
	for (i=0;i<namb;i++)
		islas[i]=-1;

	//detecta islas--------------------------------------------
	std::stack<int> amb_pend;
	for (i=0;i<namb;i++)
	{
		if(olv_limp->iaso[olv_limp->carto.get(i).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;
		if(islas[i]>-1)
			continue;
		nis++;
		amb_pend.push(i);
		while(!amb_pend.empty()) 
		{
			int amb_act=amb_pend.top();
			amb_pend.pop();
			islas[amb_act]=nis;
			//añade cercanos a la pila
			for (int k =0 ; k<aa[amb_act].namb_cerca; k++)
			{
				if(islas[aa[amb_act].iamb_cerca[k]]>-1)
					continue;
				amb_pend.push(aa[amb_act].iamb_cerca[k]);
			}
			
		}
	}
	olvlog(LOG_TODO,"quita_islas","Numero de islas %ld",nis);

	if(nis<1)
		goto va_bien;
	
	//quita islas
	int iamb=-1;
	int iamb_cerca=-1;
	int oo[2];
	double dis, dd;
	for (int kis = nis; kis>0; kis--)
	{
		iamb=-1;
		iamb_cerca=-1;
		dis=MAYUSCULO;
		for (i=0; i<namb; i++)
		{
			if(olv_limp->iaso[olv_limp->carto.get(i).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			if(islas[i]!= kis)
				continue;
			for (int ii = 0; ii<namb; ii++)
			{
				if(olv_limp->iaso[olv_limp->carto.get(ii).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
					continue;
				if(islas[ii]== kis)
					continue;
				dd = dis_min_amb(oo,i,NULL, false,ii);
				if(dd<dis && aa[i].namb_cerca<MAX_LEN_BUF_CERCANAS)
				{
					iamb=i;
					iamb_cerca= ii;
					dis=dd;
				}
			}
		}
		if(iamb<0)
			goto va_mal;
		aa[iamb].iamb_cerca[aa[iamb].namb_cerca++]=iamb_cerca;
		//le pone cercano también recíproco//ojo
		if(aa[iamb_cerca].namb_cerca<MAX_LEN_BUF_CERCANAS)
			aa[iamb_cerca].iamb_cerca[aa[iamb_cerca].namb_cerca++]=iamb;
		for (i=0; i<namb; i++)
		{
			if(islas[i]!= kis)
				continue;
			islas[i] = islas[iamb_cerca];
		}
	}

	
va_bien:
	free(islas);
	return TRUE;
va_mal:
	free(islas);
	return FALSE;
}
//*************************************************************************************
/**
 * Rellena la info de ámbitos cercanos teniendo en cuenta la distancia por carretera entre ellos
 */
BOOL Colv_limp_thr::rellena_amb_cercanos_por_carretera(int namb,  Info_amb_sec *aa, Secu_amb * ord_sec)
{
	int i,j, n, r1, r2, cerca_p1=MAX_LEN_BUF_CERCANAS,rr,rmax;
	int oo[2], ref_i, ref_j;
	double dd;
	int *secu1, *secu2;
	int *conex=NULL;//matriz de conexión con ámbitos
	const int RMAX_INI=2;
	BOOL logdebug=FALSE;
	
	secu1=(int*)malloc(sizeof(int)*2*olv_limp->conjs.n);
	if(!secu1)
	{
		olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","Sin memoria para ambitos");
		return FALSE;
	}
	
	Dists dis_[MAX_LEN_BUF_CERCANAS];

	rmax=RMAX_INI;

	//matriz de conexion con ambitos (te dice si una conjuncion esta conectada con un ambito y en ese caso con cual. -1 en caso contrario)
	conex = (int*) malloc(olv_limp->conjs.n * sizeof(int));
	if (!conex)
	{
		olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","Sin memoria para conjunciones");
		return FALSE;
	}
	for (n=0;n<olv_limp->conjs.n;n++)
		conex[n]=-1;
	// matriz de distancias (olv_limp->cost_conj[][])
	//olv_limp->tipo_ambit//indica que tipo de ambitos estamos tratando1 si es puntual 2 si es lineal
	//olv_limp->ias[0].ic[0]id de la conjunion 1 del ambito 0
	//olv_limp->ias[0].ic[1]id de la conjunion 2 del ambito 0
	//bucle por todos los ambitos
	//bucle por todos los nodos del ambito
	//bucle por todos los nodos
	//marcas en el array si el nodo es el del ambito o si tiene conexion directa con dicho ámbito
	for (n=0;n<olv_limp->conjs.n;n++)
	{
		for (i=0;i<namb;i++)
		{
			ref_i=olv_limp->carto.get(i).entity()->ref;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			for (j=0;j<olv_limp->tipo_ambit;j++)
			{
				if (olv_limp->iaso[ref_i].inod[j]==n )
				{
					//Ha encontrado que esta conjunción conecta con el ámbito iésimo
					conex[n]=i;
					//Sale de los dos bucles
					i=namb;
					break;
				}
				else if(olv_limp->cost_conj[n][olv_limp->iaso[ref_i].inod[j]]!=(float)MAYUSCULO && conex[n]==-1)
				{
					conex[n]=i;
				}
			}
		}
	}

	if(logdebug)
	{
		for(j=0;j<olv_limp->conjs.n;j++)
		{
			olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","n %ld conex[n] %ld",j, conex[j]);
		}
	}

	secu2=&secu1[olv_limp->conjs.n];
	for(j=0; j<namb; j++)
	{
		aa[j].namb_cerca=0;
	}
	Djkt_nodo *buf_aux[2];
	BOOL cargado[2];

	buf_aux[0]=olv_limp->arch_dj.dame_buf_nodos(FALSE);
	buf_aux[1]=olv_limp->arch_dj.dame_buf_nodos(FALSE);

	if(!buf_aux[0] || !buf_aux[1])
	{
		olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","Sin memoria para buffer de nodos");
		goto va_mal;
	}

	for (j=0; j<namb; j++)
	{
		ref_j=olv_limp->carto.get(j).entity()->ref;
		if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
		cargado[0]=FALSE;
		cargado[1]=FALSE;
		for (i=0; i<namb; i++)
		{		
			ref_i=olv_limp->carto.get(i).entity()->ref;
			if(j==i)
				continue;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			//selecciona distancia minima de un ambito a otro
			dd=dis_min_amb(oo,i,&ord_sec[j], TRUE, j);
			if(dd>=MAYUSCULO)//sin conexion entre ambitos
				continue;
			
			//cargar ambito antes de archivo-------------------
			if(!cargado[oo[0]])
			{
				olv_limp->arch_dj.get_b(j,oo[0],buf_aux[oo[0]]);
				cargado[oo[0]]=TRUE;
			}
			//se verifica que en los cercanos no se pase por los mismos nodos
			Colv_geom::ruta_dj_inv_ok(oo[1], secu1, buf_aux[oo[0]],olv_limp->conjs.n, &r1);

					
			//Recorre los nodos de la ruta entre esos ámbitos para ver si alguno de los nodos no conecta directamente
			//con algún ámbito, en cuyo caso lo descarta
			//o lo descarta también si lleva varios nodos de carretera seguidos 
			rr=0;
			for (n=0;n<r1;n++)
			{
				if (conex[secu1[n]]!=-1
					&& conex[secu1[n]]!=i
					&& conex[secu1[n]]!=j)
					break;	//Esta conjunción conecta con un ámbito diferente. No vale
				if(n>0 && conex[secu1[n]]==-1 && conex[secu1[n-1]]==-1)
					rr++;
				else if( n<(r1-2))
					rr=0;
			}
			if (n<r1)
				continue;
			/////////
			if(aa[i].namb_cerca>=MAX_LEN_BUF_CERCANAS)
				continue;		

			aa[i].iamb_cerca[aa[i].namb_cerca]=j | (rr<<24);
			aa[i].namb_cerca++;
		}
	}

	//ordena-------------
	for (i=0;i<namb;i++)
	{
		ref_i=olv_limp->carto.get(i).entity()->ref;
		if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;

		memset(dis_,0,sizeof(Dists)*MAX_LEN_BUF_CERCANAS);
		if(aa[i].namb_cerca<=0)
		{
			aa[i].namb_cerca=aa[i].namb_cerca;
			olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","iamb %ld 0 cercanos",i);
			continue;				
		}

		for(j=0;j<aa[i].namb_cerca;j++)
		{
			//selecciona distancia minima de un ambito a otro
			//dis_[j].dist=(aa[i].iamb_cerca[j] & 0xff000000)>>24;
			dis_[j].dist=dis_min_amb(oo,i,&ord_sec[aa[i].iamb_cerca[j] & 0x00ffffff], TRUE, aa[i].iamb_cerca[j] & 0x00ffffff);
			dis_[j].iamb=aa[i].iamb_cerca[j];
		}
	
		qsort(dis_,aa[i].namb_cerca,sizeof(Dists),Colv_limp_thr::compara_dist_cerc);

		if(logdebug)
		{
			for(j=0;j<aa[i].namb_cerca;j++)
			{
				olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","iamb %ld, iamb_cerca %ld, rr %ld, dismin %lf",
					i,dis_[j].iamb & 0x00ffffff,(dis_[j].iamb & 0xff000000)>>24, dis_[j].dist);
			}
		}

		for(j=0;j<aa[i].namb_cerca;j++)
			aa[i].iamb_cerca[j]=dis_[j].iamb;

		for(j=aa[i].namb_cerca-1; j>0 ;j--)
		{
			r1=(aa[i].iamb_cerca[j-1] & 0xff000000)>>24;
			r2=(aa[i].iamb_cerca[j] & 0xff000000)>>24;
			if(r1>0 || r2>0)
				r1=r1;
			if((r2-r1)>RMAX_INI)
				aa[i].namb_cerca=j;

		}
		
		for(j=0;j<aa[i].namb_cerca;j++)
		{
			if(logdebug)
			{
				olvlog(LOG_TODO,"rellena_amb_cercanos_por_carretera","iamb %ld, iamb_cerca_final %ld, rr %ld",
					i,aa[i].iamb_cerca[j] & 0x00ffffff,(aa[i].iamb_cerca[j] & 0xff000000)>>24);
			}
			aa[i].iamb_cerca[j]=	aa[i].iamb_cerca[j] & 0x00ffffff;
		}
	}
	olv_limp->arch_dj.libera_buf(buf_aux[0]);
	olv_limp->arch_dj.libera_buf(buf_aux[1]);
	if(secu1)
		free(secu1);
	if(conex)
		free(conex);	

	return TRUE;
va_mal:
	olv_limp->arch_dj.libera_buf(buf_aux[0]);
	olv_limp->arch_dj.libera_buf(buf_aux[1]);
	
	if(conex)
		free(conex);
	if(secu1)
		free(secu1);
	return FALSE;

}
//*************************************************************************************
/**
 * Compara las estructuras Dist. Las ordena por distancia
 */
int Colv_limp_thr::compara_dist_cerc (const void * a, const void * b)
{
	//si a<b devuelve negativo, si son iguales 0, y si es mayor positivo

	return (int)(((Dists*) a)->dist - ((Dists*) b)->dist);	 
}
//*************************************************************************************
/**
 * Busca el sector más cercano a un ámbito
 * busca el ambito frontera de iamb mas cercano al sector id_sec
 * si modo==1 busca se busca a cualquier sector menos id_sec
 */
int Colv_limp_thr::busca_sec_cerca_amb(Info_amb_sec *aa,int iamb, int id_sec, int modo)
{
	int i,s,ia;
	if(id_sec<0)
		return -1;
	for(i=0; i<aa[iamb].namb_cerca; i++)
	{
		s=aa[aa[iamb].iamb_cerca[i]].sec;
		if(s<0)
			continue;
		if((modo==0 && s==id_sec)|| (modo==1 && s!=id_sec))
		{
			ia=aa[iamb].iamb_cerca[i];
			return ia;
		}
	}
	return -1;
}
//*************************************************************************************
/**
 * Ordena los sectores según coste de mayor a menor
 */
int* Colv_limp_thr::ordena_sec( int n_sec, Info_sec *ss, int *buf )
{
	int *isec, nord, j, i, k;
	if(buf)
		isec=buf;
	else
	{
		isec=(int*)malloc(sizeof(int)*n_sec);
		memset(isec,0,sizeof(int)*n_sec);
	}
	if(!isec)
		return NULL;	

	nord=0;
	/////////////////////////
	for(j=0; j<n_sec; j++)
	{		
		//busca posicion de sector j
		for(i=0; i<nord; i++)
		{			
			if(ss[isec[i]].cost_ac<ss[j].cost_ac)
				break;			
		}
		//despeja el lugar
		for(k=nord-1; k>=i; k--)
			isec[k+1]=isec[k];
		isec[i]=j;
		nord++;
	}
	return isec;
}
//*************************************************************************************
/**
 * Algoritmo 5 de igualación de sectores, pasando ámbitos de un sector a otro que tenga cerca
 */
double Colv_limp_thr::iguala_sectores5(int iamb, int n_amb, int n_sec, Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa)
{
	double desv;
	int res;
	enum Res{
		RES_SALE_BIEN,
		RES_SALE_MAL,
		RES_NO_SALE,
		RES_GENERA,
	};
	int i,j;

	desv=0;

	//llama al iguala_sect4 con, al principio sólo 2 sectores activos
	//luego comprueba si el último de los nsec su coste es mayor que la jornada
	//y si es así, nsec_act++, cuidando que no pase de nsec
	//se le añade un ámbito, el más lejano de nsec_act
	//si su coste es cero, nsec_act-- 
	//si es el coste es >0 y <= que el coste jornada, todo ok
	do 
	{
		olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 5 con %ld sectores", olv_limp->nsec_act);
		desv=iguala_sectores4( n_amb, olv_limp->nsec_act, cost_amb, ss, aa);
		if(desv<0)
		{
			//sale mal
			res=RES_SALE_MAL;
			continue;
		}
		if(ss[olv_limp->nsec_act-1].cost_ac==0)
		{
			if((olv_limp->nsec_act-1)<=0)
			{
				//sale bien, pero forzado, no debería salir por aquí..
				res=RES_SALE_BIEN;
				continue;
			}
			olv_limp->nsec_act--;
			res=RES_GENERA;
		}
		else if(ss[olv_limp->nsec_act-1].cost_ac>olv_limp->calc_nsec)
		{
			//añade un sec activo, siempre que haya disponibles			
			if((olv_limp->nsec_act+1)>olv_limp->nsec)
			{
				//sale bien, pero forzado, no debería salir por aquí..
				res=RES_SALE_BIEN;
				continue;
			}
			olv_limp->nsec_act++;
			//llama de nuevo al genera_sectores
			res=RES_GENERA;		
		}
		else
		{
			//sale bien
			res=RES_SALE_BIEN;
		}
		if(res==RES_GENERA)
		{		
			//////////////////////////////////////////////////////////////
			//reinicializa	
			for(i=0;i<olv_limp->nsec;i++)
			{
				olv_limp->sec[i].namb=0;
				olv_limp->sec[i].iamb_ini_def=-1;
				olv_limp->sec[i].t_despl[0]=olv_limp->sec[i].t_despl[1]=(float)olv_limp->t_despl;
				for(j=0;j<olv_limp->n_amb;j++)
				{
					olv_limp->sec[i].iamb[j]=-1;			
				}
			}
			//reinicializa
			for(j=0;j<olv_limp->n_amb;j++)
			{
				olv_limp->amb_sec[j].sec=-1;
				olv_limp->amb_sec[j].iseq=-1;
				olv_limp->amb_sec[j].t=0;
			}
			//////////////////////////////////////////////////////////////			
			if(!genera_sectores3(iamb,olv_limp->n_amb,olv_limp->nsec_act,olv_limp->cost_amb,olv_limp->sec, olv_limp->amb_sec))
			{
				//sale mal
				res=RES_SALE_MAL;
			}
		}

	} while (res>=RES_NO_SALE);	

	if(res==RES_SALE_MAL)
		return -1;

	//si sale bien, libera el espacio libre
	if(olv_limp->nsec_act<olv_limp->nsec)
	{
		for(int i=olv_limp->nsec_act;i<olv_limp->nsec;i++)
		{
			if(olv_limp->sec[i].cost_amb_sec)
			{
				free(olv_limp->sec[i].cost_amb_sec);
				olv_limp->sec[i].cost_amb_sec = NULL;
			}
			if(olv_limp->sec[i].cost_amb_sec_aux)
			{
				free(olv_limp->sec[i].cost_amb_sec_aux);
				olv_limp->sec[i].cost_amb_sec_aux = NULL;
			}
			if(olv_limp->sec[i].iamb)
			{
				free(olv_limp->sec[i].iamb);
				olv_limp->sec[i].iamb = NULL;
			}
		}	
		Info_sec* sec_aux;
		sec_aux=(Info_sec*)realloc(olv_limp->sec,olv_limp->nsec_act*sizeof(Info_sec));
		if(!sec_aux)
			return -1;
		olv_limp->sec=sec_aux;
		olv_limp->nsec=olv_limp->nsec_act;
	}

	return desv;
}
//*************************************************************************************
/**
 * Algoritmo 4 de igualación de sectores, pasando ámbitos de un sector a otro que tenga cerca
 */
double Colv_limp_thr::iguala_sectores4(int n_amb, int n_sec, Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa)
{
	double desv;
	double desv_last,cos_min, cos_min_last, cos_max, cos_max_last;
	double desv_abs_old, desv_abs;
	double d, d1;
	BYTE* st=NULL;
	int *isec=NULL, *iamb_r=NULL,  j, i, ii, jj,k;
	int sec_m=0;
	int sselc=-1;
	int iamb,ip, sec;
	int nth=Colv_geom::dame_n_nucleos();
	Secu_amb * ord_sec=olv_limp->ord_sec;
	th_param_planif thp; 
	memset(&thp, 0, sizeof(thp));
	thp.milis_sleep=1;
	thp.namb_t=n_amb;
	thp.abs=TRUE;
	desv_last=dame_desv_sec(n_sec,ss, TRUE,&desv_abs_old);
	BOOL log_debug=FALSE;
	BOOL todo_ok=FALSE;
	BOOL aisladas=FALSE;
	char nfile[MAX_PATH];
	BOOL nocalc=FALSE;
	ii=jj=0;
	iamb=-1;

	strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
	//cambiaext(nfile,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");
	
	////////////////////////////////////////////	
	//avisa de progreso
	olvlog(LOG_TODO,"olv_limp_t","Calculando permutaciones para mejorar al igualar sectores");
	pon_mi_progre(OLV_TAREA_PERMU,0);
	////////

	thp.dth=(th_data_planif*)malloc(sizeof(th_data_planif)*nth);
	memset(thp.dth, 0, sizeof(th_data_planif)*nth);
	
	for (i=0; i<nth; i++)
	{
		thp.id_th=i;
		thp.dth[i].activo=TRUE;
		lck_sum_atm(&thp.nth,1);
		AfxBeginThread(th_planificacion, (LPVOID)&thp, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
		while(thp.id_th>=0)
			Sleep(1);

	}	
	/////////////////////////////////////
	sec=-1;
	desv=iguala_sectores3(n_amb, n_sec, cost_amb, ss, aa, ord_sec, &thp);
	if(desv>=MAYUSCULO)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error en iguala_sect3");
		goto salir;
	}
	desv_last=dame_desv_sec(n_sec,ss, TRUE, &desv_abs_old);

	olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 4. Desv: %lf",desv_last);

	if(olv_limp->calc_nsec<=0)
		cos_max_last=dame_mima(n_sec, ss,&cos_min_last);
	else
		cos_max_last=cos_min_last=0;
	iamb_r=(int*)malloc(sizeof(int)*n_amb*2);
	if(!iamb_r)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al pedir memoria");
		goto salir;
	}
	
	st=guarda_estado(n_amb,n_sec,aa,ss,st);

	if(!st)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al guardar estado");
		goto salir;
	}
	do 
	{

		if(((desv_last<olv_limp->DESV_MAX) && (desv_abs_old<=olv_limp->DESV_MAX_ABS)) || (desv_abs_old<=olv_limp->DESV_MAX_ABS) || fin_permu)
		{
			todo_ok=TRUE;
			break;
		}
		//ordena sectores por coste--------------------------
		isec=ordena_sec(n_sec,ss,isec);
		//selecciona sector a bloquear
		do
		{
			//elije un sector con mas de un ambito (para poder quitarle uno)
			sselc=isec[sec_m];
			if(ss[sselc].namb>1)
				break;
			sec_m++;
		}
		while(sec_m>=n_sec-1);

		if(sec_m>=n_sec-1)
		{
			todo_ok=TRUE;
			break;
		}
		//busca ambito mas pequeño posible que tenga otro de otro sector más cerca
		d=MAYUSCULO;
		iamb=-1;
		for (i=0; i<ss[sselc].namb; i++)
		{
			if(olv_limp->iaso[olv_limp->carto.get(ss[sselc].iamb[i]).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			for (j=0; j<aa[ss[sselc].iamb[i]].namb_cerca; j++)
			{
				k=aa[ss[sselc].iamb[i]].iamb_cerca[j];
				if(aa[k].sec==sselc)
					continue;
				d1=cost_amb[ss[sselc].iamb[i]][ss[sselc].iamb[i]]+cost_amb[ss[sselc].iamb[i]][k];
				recorre_hijos(ss[sselc].iamb[i],n_amb,aa,iamb_r,0,cost_amb, &d1);
				if(d1<d && aa[k].sec>=0)
				{
					d=d1;
					iamb=ss[sselc].iamb[i];
					ip=k;
					sec=aa[k].sec;
				}
			}
		}
		if(d>=MAYUSCULO || sec<0)
		{
			sprintf_s(err_str,OLV_MAX_ERR,"Error, no encuentra más ámbitos cercanos");
			if(desv<MAYUSCULO)
				todo_ok=TRUE;//al menos ha conseguido hacer una igualación
			break;
		}
		k=recorre_hijos(iamb,n_amb,aa,iamb_r,0,cost_amb, &d1);
		quita_amb_sec(iamb,n_amb,sselc,ss,aa,cost_amb,aa[iamb].iseq);
		add_amb_sec(iamb,n_amb,sec,ss,aa,cost_amb,MAYUSCULO,ip);
		for (i=0; i<k; i++)
		{
			quita_amb_sec(iamb_r[i*2],n_amb,sselc,ss,aa,cost_amb,iamb_r[i*2+1]);
			add_amb_sec(iamb_r[i*2],n_amb,sec,ss,aa,cost_amb,MAYUSCULO,iamb_r[i*2+1]);
		}
		calcula_coste_1sec(ord_sec, &ss[sselc], &thp,FALSE);
		calcula_coste_1sec(ord_sec, &ss[sec], &thp,FALSE);		
		//se pasa ambito mas peque del mayor sector al sector mas cercano
		//se fija sector mas alto como bloqueado
		ss[sselc].flags_tem|=OLV_LIMP_FLG_SEC_INFO_BLOCK;
		
		iguala_sectores3(n_amb, n_sec, cost_amb, ss, aa, ord_sec, &thp);
		
		//se desbloquea
		ss[sselc].flags_tem&=~OLV_LIMP_FLG_SEC_INFO_BLOCK;
		iguala_sectores3(n_amb, n_sec, cost_amb, ss, aa, ord_sec, &thp);

		desv=dame_desv_sec(n_sec,ss, TRUE, &desv_abs);

		if(desv>=desv_last)
		{
			if(olv_limp->calc_nsec<=0 &&  desv==desv_last)
				cos_max=dame_mima(n_sec, ss, &cos_min);
			else
				cos_max=cos_min=0;
			
			if( desv>desv_last || (((cos_max-cos_min)>= (cos_max_last-cos_min_last))))
			
			{
				//se vuelve a estado anterior
				pon_estado(n_amb,n_sec,aa,ss,cost_amb,st);
				
				desv=dame_desv_sec(n_sec,ss, TRUE);
				if(desv!=desv_last)
					olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 4. Error no coincide desv anterior Desv: %lf Desv_old",desv, desv_last);
				sec_m++;
				if(sec_m>=n_sec-1)
				{
					todo_ok=TRUE;
					break;
				}
				continue;

			}
			sec_m=0;
		}
		sec_m=0;
		olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 4. Cambio mejora desv old: %lf, new %lf",desv_last, desv);
		desv_last=desv;
		desv_abs_old=desv_abs;
		cos_max_last=cos_max;
		cos_min_last=cos_min;

		st=guarda_estado(n_amb,n_sec,aa,ss,st);
		if(!st)
		{
			sprintf_s(err_str,OLV_MAX_ERR,"Error al guardar estado anterior");
			goto salir;
		}
	} while (!pirate);
	if(!todo_ok)
		goto salir;

	st=guarda_estado(n_amb,n_sec,aa,ss,st);
	if(!st)
		goto salir;

	/*
	if(olv_limp->calc_nsec>0)
		todo_ok=FALSE;//se reinicia para ver si la siguiente parte todo_ok
	while(olv_limp->calc_nsec>0 && !pirate)
	{		
		if((desv_last<OLV_DESV_MAX))
		{
			todo_ok=TRUE;
			break;
		}
		//selecciona sector a bloquear (el basura)
		sselc=n_sec-1;
		//busca ambito mas pequeño posible 
		d=MAYUSCULO;
		for (i=0; i<ss[sselc].namb; i++)
		{
			for (j=0; j<aa[ss[sselc].iamb[i]].namb_cerca; j++)
			{
				k=aa[ss[sselc].iamb[i]].iamb_cerca[j];
				if(aa[k].sec==sselc)
					continue;
				d1=cost_amb[ss[sselc].iamb[i]][ss[sselc].iamb[i]];
				iamb=ss[sselc].iamb[i];
				ip=k;
				sec=aa[k].sec;
				k=recorre_hijos(iamb,n_amb,aa,iamb_r,0,cost_amb, &d1);
				if(d1>MAYUSCULO)
					continue;
				quita_amb_sec(iamb,n_amb,sselc,ss,aa,cost_amb,aa[iamb].iseq);
				add_amb_sec(iamb,n_amb,sec,ss,aa,cost_amb,MAYUSCULO,ip);
				
				for (ii=0; ii<k; ii++)
				{
					quita_amb_sec(iamb_r[ii*2],n_amb,sselc,ss,aa,cost_amb,iamb_r[ii*2+1]);
					add_amb_sec(iamb_r[ii*2],n_amb,sec,ss,aa,cost_amb,MAYUSCULO,iamb_r[ii*2+1]);
				}
				//se fija sector mas alto como bloqueado
				ss[sselc].flags_tem|=OLV_LIMP_FLG_SEC_INFO_BLOCK;
				
				iguala_sectores3(n_amb, n_sec, cost_amb, ss, aa, ord_sec, &thp);

				//se desbloquea
				ss[sselc].flags_tem&=~OLV_LIMP_FLG_SEC_INFO_BLOCK;
				
				iguala_sectores3(n_amb, n_sec, cost_amb, ss, aa, ord_sec, &thp);

				desv=dame_desv_sec(n_sec,ss, TRUE);

				if(desv>=desv_last)
				{
					//se vuelve a estado anterior
					pon_estado(n_amb,n_sec,aa,ss,cost_amb,st);

					desv=dame_desv_sec(n_sec,ss, TRUE);
					if(desv!=desv_last)
						desv_last=desv;		
					continue;
				}
				olvlog(LOG_TODO,"olv_limp_t","Iguala sectores4. Cambio mejora desv old: %lf, new %lf",desv_last, desv);
				desv_last=desv;
				st=guarda_estado(n_amb,n_sec,aa,ss,st);
				if(!st)
				{
					sprintf_s(err_str,OLV_MAX_ERR,"Error al guardar estado");
					goto salir;
				}
				break;

			}
		}
		if(i>=ss[sselc].namb)
		{
			todo_ok=TRUE;
			break;
		}
	}
	*/

salir:
	if(log_debug)
	{	
		olvlog(LOG_TODO,"olv_limp_t","------------------------------------------------");
		for(i=0;i<n_sec;i++)
		{
			olvlog(LOG_TODO,"olv_limp_t","Sector %ld, namb %03d, coste_ac %lf",i,ss[i].namb, ss[i].cost_ac);
		}
		olvlog(LOG_TODO,"olv_limp_t","Finalizada igualación de sectores4----------------");
	}

	//se bloquea y 
	thp.pirate=TRUE;
	while(thp.nth>0)
		Sleep(1);
	if(iamb_r)
		free(iamb_r);
	if(st)
		free(st);
	free(isec);
	
	if(thp.dth)
	{
		if(thp.dth[0].sec)
			free(thp.dth[0].sec);
		free(thp.dth);

	}

	if(!todo_ok)
	{
		olvlog(LOG_TODO,"olv_limp_t","Errores varios en iguala_sectores4");
		if(aisladas)
			return -2;
		return -1;
	}
	return desv_last;
}
//*************************************************************************************
/**
 * Recorre los 'nesc' sectores igualando su coste
 * La idea es poner ambitos a los sectores de menor coste manteniendo la condicion de no aisladas 
 */
#define MAX_AMBI_IGUALA_SEC 500
double Colv_limp_thr::iguala_sectores3(int n_amb, int n_sec,  Matrix2d<float> &cost_amb, Info_sec *ss, Info_amb_sec *aa, Secu_amb * ord_sec, th_param_planif *thp)
{
	double desv,desv_last, desv_fut,desv_abs;//máxima desviación permitida respecto a la media	
	BOOL hay_cambio,log_debug, prime;
	int *amb_fron;//indice a ambitos frontera de sectores
	int *isec=NULL;//indice a sectores (ordenados de mayor a menor)
	int *icerca;//indice a ambitos cercanos a los frontera de un sector
	int *icamb;//indices a ambitos cambiados de sector en un pasp
	int cambio[2][2];//[0]ambito y sector que se pasa al[1] ambito (padre) y sector 
	int siz_sec=(n_amb+1);
	int  j, i, k,kk, kkk;
	int isec_min;
	int ncerca;
	int nhijos_frontera=10;
	int namb_camb;
	int ind_camb;
	int nais=0;
	//-------------------------------

	log_debug=TRUE;
	if(log_debug)
		olvlog(LOG_TODO,"olv_limp_t","Empieza igualacion de sectores 3");
	isec=(int*)malloc(sizeof(int)*(1+n_sec*(n_amb+1)+n_sec+n_amb*5));
	memset(isec,0,sizeof(int)*(1+n_sec*(n_amb+1)+n_sec+n_amb*5));
	
	desv_last=desv_abs=MAYUSCULO;
	prime=TRUE;
	
	if(!isec)
	{
		olvlog(LOG_TODO,"olv_limp_t","Error en igualacion de sectores 3, sin memoria para bufferes");
		return desv_last;//no debería pasar
	}
	icerca=&isec[n_sec+1];
	icamb=&icerca[n_amb*2];
	amb_fron=&icamb[n_amb*3];

	//calcula media y desviacion de costes en sectores
	//bucle
	hay_cambio=TRUE;
	ind_camb=-1;
	for(j=0; j<n_sec; j++)
	{	
		ss[j].flags_tem|= OLV_LIMP_FLG_SEC_CAMB;
	}
	do 
	{
		//ordena sectores por coste-------------------------------------------------
		if(hay_cambio)//se ha redistibuido ambitos entre sectores, se vuelve a intentar mejorar
		{
			nais=0;
			//recorre sectores----------------------
			//inicia todos los ambitos a -1 y numero de hijos a 0
			for (i=0; i<n_amb; i++)
			{
				if(aa[i].sec<0)
				{
					nais++;
					continue;	
				}
				if(!(ss[aa[i].sec].flags_tem & OLV_LIMP_FLG_SEC_CAMB))
					continue;
				//solo resetea los que se han cambiado
				aa[i].iseq=-1;//usada para almacenar indice al padre
				aa[i].t=0;//usada para almacenar numero de hijos
			}	
			i=0;
			for(j=0; j<n_sec; j++)
			{
				if(ss[j].namb<=0)
					continue;
				
				if(!(ss[j].flags_tem & OLV_LIMP_FLG_SEC_CAMB))
				{
					i+=ss[j].namb;
					continue;
				}

				//le quita el flag de cambio
				ss[j].flags_tem &= ~OLV_LIMP_FLG_SEC_CAMB;
				//asigna padres------------------------
				nhijos_frontera=max(5,ss[j].namb);
				amb_fron[j*siz_sec]=asigna_padres(ss[j].iamb[0], n_amb, cost_amb,&ss[j],aa,&amb_fron[j*siz_sec+1], nhijos_frontera);
				//comprobacion de fronteras-------------------------------
				for(k=0; k<amb_fron[j*siz_sec]; k++)
				{
					if(amb_fron[j*siz_sec+1+k]<0)
						olvlog(LOG_TODO,"olv_limp_t","Error en igualacion de sectores 3, calculo de fronteras erroneo en sector: %ld",j);

				}
				i+=ss[j].namb;
			}
			if(i!=n_amb-nais)
				olvlog(LOG_TODO,"olv_limp_t","Error en igualacion de sectores 3, ambitos mal asignados a sectores, la suma de los ambitos de los sectores no cuadra con los ambitos totales");
			
			if(ord_sec && ind_camb<0)
			{
				calcula_coste_sectores(ord_sec, ss,n_sec, thp);
				if(prime)
				{
					desv_last=dame_desv_sec(n_sec,ss,TRUE,&desv_abs);
					prime=FALSE;
				}
			}			
			if(((desv_last<olv_limp->DESV_MAX) && (desv_abs<=olv_limp->DESV_MAX_ABS)) || (desv_abs<=olv_limp->DESV_MAX_ABS) || fin_permu)//if(desv_last<OLV_DESV_MAX || fin_permu)
				break;
			//ordena sectores por coste--------------------------
			if(olv_limp->calc_nsec)
			{
				isec[0]=n_sec-1;
				ordena_sec(n_sec-1, ss, &isec[1]);
				isec_min=n_sec-1;
			}
			else
			{
				ordena_sec(n_sec, ss, isec);
				isec_min=n_sec-1;
			}
			hay_cambio=FALSE;
			if(log_debug && ind_camb>=0)
				olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 3, mejorada desviacion tipica a %lf", desv_last);
		}
		else
		{
			isec_min--;
			if(isec_min<=0)
				break;//no se puede mejorar mas
		}	
		//busca fronteras de otros sectores cercanas al sector isec_min
		if(ss[isec[isec_min]].flags_tem& OLV_LIMP_FLG_SEC_INFO_BLOCK)
			continue;
		ncerca=0;
		for(j=0; j<n_sec; j++)
		{
			if(ss[isec[j]].flags_tem& OLV_LIMP_FLG_SEC_INFO_BLOCK)
				continue;
			if(isec[j]==isec[isec_min])
			{
				//recorre frontera de j
				kk=isec[j]*siz_sec+1;
				for(i=amb_fron[isec[j]*siz_sec]-1; i>=0; i--)
				{
					//verifica que tenga ambitos cercanos de otros sectores
					//si es asi añade al array
					k=busca_sec_cerca_amb(aa,amb_fron[kk+i], isec[isec_min],1);
					if(k>=0)
					{
						icerca[ncerca*2]=k;
						icerca[ncerca*2+1]=amb_fron[kk+i];
						ncerca++;
					}
				}
				continue;
			}
			//recore ambitos frontera de sector j
			kk=isec[j]*siz_sec+1;
			for(i=amb_fron[isec[j]*siz_sec]-1; i>=0; i--)
			{
				k=busca_sec_cerca_amb(aa,amb_fron[kk+i], isec[isec_min]);
				if(k>=0)
				{
					icerca[ncerca*2]=amb_fron[kk+i];
					icerca[ncerca*2+1]=k;
					ncerca++;
				}
			}
		}
		if(ncerca<=0)
			continue;//no se puede mejorar
		if(ncerca>n_amb)
			ncerca=ncerca;
		desv_fut=MAYUSCULO;
		ind_camb=-1;
		for(i=0; i<ncerca; i++)
		{
			cambio[0][0]=icerca[i*2];//se pone este 
			cambio[0][1]=aa[cambio[0][0]].sec;
			cambio[1][0]=icerca[i*2+1];//con padre este
			cambio[1][1]=aa[cambio[1][0]].sec;
			namb_camb=1;
			icamb[0]=cambio[0][0];
			icamb[1]=cambio[1][0];
			icamb[2]=cambio[0][0];
			if(cambio[0][1]<0)
				continue;
			//apuntar hijos em ambitos que se van a cambiar
			for (j=0; j<namb_camb; j++)
			{
				k=icamb[j*3];
				if(aa[icamb[j*3]].t<=1)
					continue;
				for(kk=0; kk<ss[cambio[0][1]].namb; kk++)
				{
					if(aa[ss[cambio[0][1]].iamb[kk]].iseq==k && aa[k].iseq!=ss[cambio[0][1]].iamb[kk])
					{
						icamb[namb_camb*3]=ss[cambio[0][1]].iamb[kk];
						icamb[namb_camb*3+1]=k;
						icamb[namb_camb++*3+2]=aa[icamb[namb_camb*3]].iseq;
					}
				}

			}
			for (j=0; j<n_sec; j++)
				ss[j].cost_despl_aux=ss[j].cost_ac;
			
			//modifica sectores--------------------------
			for (j=0; j<namb_camb; j++)
			{
				k=icamb[j*3];
				kk=icamb[j*3+1];
				kkk=icamb[j*3+2];
				quita_amb_sec(k, n_amb, cambio[0][1], ss, aa, cost_amb,kkk);
				add_amb_sec(k,n_amb,cambio[1][1],ss,aa,cost_amb,MAYUSCULO,kk);
	
			}
			if(ord_sec)
			{
				thp->milis_sleep=0;
				calcula_coste_1sec(ord_sec, &ss[cambio[0][1]], thp,FALSE);
				calcula_coste_1sec(ord_sec, &ss[cambio[1][1]], thp,FALSE);
				thp->milis_sleep=1;				
			}
			//comprueba mejora o no-----------------------
			desv=dame_desv_sec(n_sec,ss,TRUE,&desv_abs);
				
			if(desv<desv_last)
			{
				if(desv_fut>desv)
				{
					desv_fut=desv;
					ind_camb=i;
				}				
			}
			//se deshace el cambio--------------------------
			for (j=0; j<namb_camb; j++)
			{
				k=icamb[j*3];
				kk=icamb[j*3+1];
				kkk=icamb[j*3+2];
				quita_amb_sec(k, n_amb, cambio[1][1], ss, aa, cost_amb,kk);
				add_amb_sec(k,n_amb,cambio[0][1],ss,aa,cost_amb,MAYUSCULO,kkk);

			}

			for (j=0; j<n_sec; j++)
				ss[j].cost_ac=ss[j].cost_despl_aux;
			if(olv_limp->n_amb>=MAX_AMBI_IGUALA_SEC && ind_camb>=0)
				break;
		}
		if(ind_camb>=0)
		{
			cambio[0][0]=icerca[ind_camb*2];//se pone este 
			cambio[0][1]=aa[cambio[0][0]].sec;
			cambio[1][0]=icerca[ind_camb*2+1];//con padre este
			cambio[1][1]=aa[cambio[1][0]].sec;
			namb_camb=1;
			icamb[0]=cambio[0][0];
			icamb[1]=cambio[1][0];
			icamb[2]=cambio[0][0];
			for (j=0; j<n_sec; j++)
				ss[j].cost_despl_aux=ss[j].cost_ac;
			//apuntar hijos em ambitos que se van a cambiar
			for (j=0; j<namb_camb; j++)
			{
				k=icamb[j*3];
				if(aa[icamb[j*3]].t<=1)
					continue;
				for(kk=0; kk<ss[cambio[0][1]].namb; kk++)
				{
					if(aa[ss[cambio[0][1]].iamb[kk]].iseq==k && aa[k].iseq!=ss[cambio[0][1]].iamb[kk])
					{
						icamb[namb_camb*3]=ss[cambio[0][1]].iamb[kk];
						icamb[namb_camb*3+1]=k;
						icamb[namb_camb++*3+2]=aa[icamb[namb_camb*3]].iseq;
					}
				}
			}
			//modifica sectores--------------------------
			for (j=0; j<namb_camb; j++)
			{
				k=icamb[j*3];
				kk=icamb[j*3+1];
				kkk=icamb[j*3+2];
				quita_amb_sec(k, n_amb, cambio[0][1], ss, aa, cost_amb,kkk);
				add_amb_sec(k,n_amb,cambio[1][1],ss,aa,cost_amb,MAYUSCULO,kk);
				ss[cambio[0][1]].flags_tem|=OLV_LIMP_FLG_SEC_CAMB;
				ss[cambio[1][1]].flags_tem|=OLV_LIMP_FLG_SEC_CAMB;

			}
			if(ord_sec)
			{
				thp->milis_sleep=0;
				calcula_coste_1sec(ord_sec, &ss[cambio[0][1]], thp,FALSE);
				calcula_coste_1sec(ord_sec, &ss[cambio[1][1]], thp,FALSE);
				thp->milis_sleep=1;
			}
			//comprueba mejora o no-----------------------			
			double desv_lastold=desv_last;
			desv_last=dame_desv_sec(n_sec,ss,TRUE,&desv_abs);
			
			if(desv_lastold<desv_last)
			{
				olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 3, --->OJO -->El cambio selec empeora des_act:%lf desv_obt: %lf",desv_lastold, desv_last);
				//se deshace el cambio--------------------------
				for (j=0; j<namb_camb; j++)
				{
					k=icamb[j*3];
					kk=icamb[j*3+1];
					kkk=icamb[j*3+2];
					quita_amb_sec(k, n_amb, cambio[1][1], ss, aa, cost_amb,kk);
					add_amb_sec(k,n_amb,cambio[0][1],ss,aa,cost_amb,MAYUSCULO,kkk);

				}

				for (j=0; j<n_sec; j++)
					ss[j].cost_ac=ss[j].cost_despl_aux;
				desv_last=dame_desv_sec(n_sec,ss,TRUE,&desv_abs);
				olvlog(LOG_TODO,"olv_limp_t","Iguala sectores 3, --->OJO -->Se quita cambio y queda desv: %lf",desv_last);
				hay_cambio=FALSE;	
			}
			else
				hay_cambio=TRUE;
		}
		else
		{
			hay_cambio=FALSE;			
		}
	} while (TRUE);
	//fin ----------------------------------------------------------

	if(isec)
		free(isec);
	if(FALSE)
	{
		olvlog(LOG_TODO,"olv_limp_t","------------------------------------------------");
	
		for(i=0;i<n_sec;i++)
		{
			olvlog(LOG_TODO,"olv_limp_t","Sector %ld, namb %03d, coste_ac %lf",i,ss[i].namb, ss[i].cost_ac);
		}
	
	}
	if(log_debug)
		olvlog(LOG_TODO,"olv_limp_t","Finalizada igualación de sectores 3----------------");

	return desv_last;
}
//*************************************************************************************
/**
 * Calcula la desviación típica entre los costes acumulados de los nsec sectores
 * Si porc=true, la desviación la devuelve en porcentaje respecto a la media, si no, absoluta
 * en absol se mete la maxima desviacion encontrada
 */
double Colv_limp_thr::dame_desv_sec(int nsec, Info_sec *ss, BOOL porc /*=FALSE*/, double *absol)
{
	int i=-1;
	int j;
	double costmax=MINUSCULO;
	double cost_med,dd, cost_med2;
	double cost_max, aux;
	cost_med=cost_med2=0;
	cost_max=-1;
	//calcula la media
	if(olv_limp->calc_nsec>0)
	{
		cost_med=olv_limp->calc_nsec; //impone el coste medio de los sectores, que es justo la jornada laboral
		nsec--; //se quita un sector, el último, para el cálculo de la media
	}
	else
	{	
		for(j=0;j<nsec;j++)
		{
			cost_med+=ss[j].cost_ac/nsec;
		}
	}
	//calcula la desviación típica
	for(j=0;j<nsec;j++)
	{
		dd=(ss[j].cost_ac-cost_med);
		//si hay que fijar a la jornada, no se puede pasar de ese tiempo, así que si la resta es positiva, 
		//aumenta la desviación para falsear que esa solución sea mala y no la coja
		if((olv_limp->calc_nsec>0) && (dd>0))
		{
			dd+=cost_med*nsec*2;
		}
		aux=abs(dd);
		if(aux>cost_max)
			cost_max=aux;
		cost_med2+=dd*dd/nsec;
	}
	if(olv_limp->calc_nsec>0)
	{
		if(((ss[nsec].cost_ac-cost_med)>0))//si está en modo fijar jornada, tampoco queremos que se desmadre el último
		{
			aux=cost_med;
			if(aux>cost_max)
				cost_max=aux;
			cost_med2+=cost_med*cost_med/nsec;
		}
	}
	if(cost_med2>MINUSCULO)
		cost_med2=sqrt(cost_med2);
	else
		cost_med2=0;
	if(absol)
		*absol=cost_max;
	if(porc)
		return cost_med2/cost_med;
	else
		return cost_med2;
}
//*************************************************************************************
/**
 * Calcula diferencia minima y maxima de costes entre sectores
 */
double Colv_limp_thr::dame_mima(int nsec, Info_sec *ss, double *mini)
{
	int i;
	int j;
	double costmax=-MAYUSCULO;
	double costmin=MAYUSCULO;
	double dd;


	//calcula la desviación típica
	for(j=0;j<nsec;j++)
	{
		for(i=j+1;i<nsec;i++)
			
		dd=(ss[j].cost_ac-ss[i].cost_ac);
		dd=max(dd,-dd);
		//si hay que fijar a la jornada, no se puede pasar de ese tiempo, así que si la resta es positiva, 
		//aumenta la desviación para falsear que esa solución sea mala y no la coja
		if(dd>costmax)
			costmax=dd;
		if (dd<costmin)
			costmax=dd;
		
	
	}
	if(mini)
		*mini=costmin;
	return costmax;
}
//*************************************************************************************
/** 
 * Guarda los datos necesarios para reconstuir el estado de la sectorizacion actual
 */
BYTE* Colv_limp_thr::guarda_estado( int namb,int n_sec, Info_amb_sec *aa, Info_sec *ss,BYTE *buf )
{
	int  a;
	int k;
	Info_est_amb *inf;
	BYTE *res=buf;
	if(!res)
		res=(BYTE*)malloc(sizeof(Info_est_amb)*namb+sizeof(float)*n_sec);
	if(!res)
		return NULL;//sin memoria para guardar estado
	memset(res,0,sizeof(Info_est_amb)*namb);
	k=0;

	for (a=0; a<namb ; a++)
	{
		inf=(Info_est_amb*)&res[k];
		k+=sizeof(Info_est_amb);
		inf->iseq=aa[a].iseq;
		inf->sec=aa[a].sec;
		inf->t=aa[a].t;

	}
	for (a=0; a<n_sec; a++)
	{
		*((float*)&res[k])=ss[a].cost_ac;
		k+=sizeof(float);
	}
	return res;
}
//*************************************************************************************
/**
 * Restaura el estado de la sectorización anterior
 */
BOOL Colv_limp_thr::pon_estado( int namb,int n_sec, Info_amb_sec *aa, Info_sec *ss,  Matrix2d<float> &cost_amb, BYTE* st )
{
	int i, k=0, s;
	Info_est_amb *inf;
	//prepara todo a 0---------------------
	for (i=0; i<n_sec; i++)
	{
		ss[i].namb=0;
		//ss[i].sec_def=-1; //no lo borra porque ahí tiene guardada la info de qué sector es fuera, siempre será la misma
		ss[i].flags_tem=0;
		ss[i].cost_ac=0;
		ss[i].cost_despl_aux=0;
		ss[i].dis_med=0;
	}
	for (i=0; i<namb; i++)
	{
		inf=(Info_est_amb*)&st[k];
		k+=sizeof(Info_est_amb);
		aa[i].iseq=inf->iseq;
		aa[i].t=inf->t;
		aa[i].sec=inf->sec;
		s=inf->sec;
		if(s>=0)
			ss[s].iamb[ss[s].namb++]=i;
	}
	for (i=0; i<n_sec; i++)
	{
		ss[i].cost_ac=*(float*)&st[k];
		k+=sizeof(float);
	}
	
	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la lista de hijos de un nodo del árbol
 */
int Colv_limp_thr::recorre_hijos( int iamb, int namb, Info_amb_sec *aa, int *iamb_r, int namb_r,  Matrix2d<float> &cost_amb, double *cost, BOOL inicia)
{
	int  i, h;
	int oo[2];
	if(inicia)
	{
		for (i=0; i<namb; i++)
			aa[i].res=0;
	}
	aa[iamb].res=1;
	if(aa[iamb].t<=0)//es frontera
		return 0;
	h=(int)(aa[iamb].t-1);
	for (i=0; i<namb; i++)
	{
		if(olv_limp->iaso[olv_limp->carto.get(i).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
			continue;
		if(aa[i].iseq!=iamb)
			continue;
		if(aa[i].res)
			continue;
		if(i==iamb)
			continue;
		aa[i].res=1;
		*cost+=dis_min_amb(oo,iamb,NULL, false,i)+cost_amb[i][i];//cost_amb[iamb][i]+cost_amb[i][i];
		if(iamb_r)
		{
			iamb_r[namb_r*2]=i;
			iamb_r[namb_r*2+1]=iamb;
		}
		namb_r++;
		if(namb_r>namb)
			namb_r=namb_r;
		if(aa[i].t>1)
			namb_r=recorre_hijos(i,namb, aa, iamb_r, namb_r, cost_amb, cost, FALSE);
		h--;
		if(h<=-2)
			break;
	}
	return namb_r;
}
//*************************************************************************************
/**
 * Actualiza la matriz de costes de los ámbitos a otros ámbitos
 */
BOOL Colv_limp_thr::actualiza_costes( int namb,int  n_sec, Info_amb_sec *aa, Info_sec *ss,  Matrix2d<float> &cost_amb )
{

	int s, a, i, na, k, kk, p;
	double d;
	BOOL res=TRUE;
	for (a=0; a<namb; a++)
	{
		aa[a].res=0;
	}
	for(s=0; s<n_sec; s++)
	{
		for (a=0; a<namb; a++)
		{
			if(aa[a].sec==s)
				break;
		}
		if(a>=namb)
			continue;
		na=ss[s].namb;
		ss[s].namb=1;
		ss[s].iamb[0]=a;
		ss[s].cost_ac=cost_amb[a][a];
		aa[a].res=1;
		while(TRUE)
		{
			k=-1;
			d=MAYUSCULO;
			for(i=0; i<ss[s].namb; i++)
			{
				kk=ss[s].iamb[i];
				for (a=0; a<namb; a++)
				{
					if(aa[a].res || aa[a].sec!=s)
						continue;
					if (d>cost_amb[kk][a])
					{
						d=cost_amb[kk][a];
						p=kk;
						k=a;
					}
				}
			}
			if (k<0)
			{
				break;
			}
			ss[s].cost_ac+=cost_amb[p][k]+cost_amb[k][k];
			aa[k].res=1;
			ss[s].iamb[ss[s].namb++]=k;
		}
		if(na!=ss[s].namb)
			res=FALSE;
		
		
	}

	return res;
}
//*************************************************************************************
/**
 *	Calcula el coste de desplazamiento de ir de ir por todos los ambitos sec desde ini hasta fin
 */
double Colv_limp_thr::dame_coste( Secu_amb * sec, int ini, int fin,  Info_sec	*s, BOOL ind_abs)
{
	double d=0;
	int ind_cost,fin_old;

	fin_old=fin;
	
	while(ini<fin)
	{
		if (ind_abs)
			ind_cost=s->iamb[sec[fin].iamb];
		else
			ind_cost=sec[fin].iamb;

		d+=olv_limp->cost_amb[s->iamb[sec[fin].iamb]][s->iamb[sec[fin].iamb]];	
		d+=olv_limp->arch_dj.dame_dis(s->iamb[sec[fin-1].iamb],(sec[fin-1].entrada+1)%2,s->iamb[sec[fin].iamb],sec[fin].entrada);
		fin--;		
	}
	d+=olv_limp->cost_amb[s->iamb[sec[ini].iamb]][s->iamb[sec[ini].iamb]];

	if(ini==0)//si ini es 0 falta sumar el coste de la planta al primer ambito
	{
		if (ind_abs)
			ind_cost=s->iamb[sec[ini].iamb];
		else
			ind_cost=sec[ini].iamb;
		if(olv_limp->nod_instal>=0)
		{
			int ee=0;
			if(sec[ini].entrada>=0)
				ee=sec[ini].entrada;
			d+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0,s->iamb[sec[ini].iamb],ee);
			//d+=sec[ind_cost].ctnod[ee][olv_limp->nod_instal].dis;
		}
		else
			d+=olv_limp->t_despl;
	}

	//suma el coste de ir del ultimo ambito a la instalación
	if(olv_limp->nod_instal>=0)
		d+=olv_limp->ord_sec_plan[0].ctnod[0][olv_limp->iaso[olv_limp->carto.get(s->iamb[sec[fin_old].iamb]).entity()->ref].inod[(sec[fin_old].entrada+1)%2]].dis;
	else
		d+=olv_limp->t_despl;
	
	return d;
}
//*************************************************************************************
/**
 * Calcula el coste de desplazamiento de ir por todos los ambitos sec desde ini hasta fin
 * cambiando el ámbito de pos_old como si estuviera en pos_new
 */
double Colv_limp_thr::dame_coste_ex( Secu_amb * sec, int ini, int fin,  Info_sec	*s, int pos_old, int pos_new, int entrada )
{
	double d=0;
	int sig, act;
	int a_ent, s_ent;
	
	while(ini<fin)
	{
		act=Colv_geom::dame_ind_per(ini,pos_old,pos_new);
		sig=Colv_geom::dame_ind_per(ini+1,pos_old,pos_new);
		if(act==pos_new)
			a_ent=entrada;

		else
			a_ent=sec[act].entrada;

		if(sig==pos_new)
			s_ent=entrada;

		else
			s_ent=sec[sig].entrada;
		d+=olv_limp->arch_dj.dame_dis(sec[act].iamb,a_ent,s->iamb[sec[sig].iamb],(s_ent+1)%2);
		d+=olv_limp->cost_amb[s->iamb[sec[act].iamb]][s->iamb[sec[act].iamb]];

		ini++;
	}
	
	act=Colv_geom::dame_ind_per(ini,pos_old,pos_new);
	d+=olv_limp->cost_amb[s->iamb[sec[ini].iamb]][s->iamb[sec[ini].iamb]];
	return d;
}
//*************************************************************************************
/**
 * Lee la sectorización que viene como info asociada en el shp de entrada
 */
BOOL Colv_limp_thr::lee_secto()
{
	BOOL ret;
	int i,s,idd, ics, icsq;
	char nfile[MAX_PATH];
	int *info;
	Cb_file f;
	Fdbf dbf;

	ret = TRUE;
	std::map<int,std::vector<int>> l_sec;  

	olvlog(LOG_TODO,"olv_limp_t","Comienza lectura de sectorización");
	pon_mi_progre(OLV_TAREA_LEE_SECTO, 0);
	pon_mi_msg("");	
	err_str[0]=0;

	/////////////////////////////////////	
	info = (int *)malloc(olv_limp->n_amb*sizeof(int));
	if(!info)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error, sin memoria para info asociada");
		return FALSE;
	}		
	memset(info,0,olv_limp->n_amb*sizeof(int));

	//lee dbf del shp la columna SECTOR
	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))
	{
		ret=FALSE;
		goto fin;
	}
	ics=dbf.findCol(olv_limp->camps.campo_secto);
	icsq=dbf.findCol("SECUENCIA");
	if(ics<0 || icsq<0)
	{
		ret=FALSE;
		goto fin;
	}
	idd =dbf.leeNexRow();
	//rellena para cada sector info[i] qué ámbitos tiene
	for(i=0;i<olv_limp->n_amb && idd==1; i++)
	{
		if(olv_limp->iaso[olv_limp->carto.get(i).entity()->ref].flgs & OLV_LIMP_FLG_AMB_NO)
		{
			idd=dbf.leeNexRow();
			continue;
		}
		
		s=dbf.getI(ics);
		
		//el primero lo añade vacío, por si se marca la secuencia con cuál empezar
		if(l_sec[dbf.getI(ics)].size()==0)
			l_sec[s].push_back(-1);

		if(dbf.getI(icsq)==1)//se ha marcado ese elemento como primero, lo pone en el primer elemento
			l_sec[s][0]=i;

		l_sec[s].push_back(i);
		idd=dbf.leeNexRow();
	}	
	if(i<olv_limp->n_amb)
	{
		ret=FALSE;
		goto fin;
	}

	olv_limp->nsec=(int)l_sec.size();
	
	////////////////////////////////////////
	//inicia los arrays para la sectorización
	if(!pide_memo_secto())
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error, Sin memoria para lectura de sectorización");
		ret=FALSE;
		goto fin;
	}	
	
	i=-1;
	int ia=0;
	//mira cuántos sectores diferentes hay
	for (std::map<int,std::vector<int>>::iterator it=l_sec.begin(); it!=l_sec.end(); ++it)
	{
		i++;
		olv_limp->sec[i].sec_def = it->first;
		olv_limp->sec[i].namb = (int)it->second.size()-1;
		olv_limp->sec[i].iamb_ini_def = it->second[0];
		for(int ia=1;ia<olv_limp->sec[i].namb+1;ia++)
		{			
			olv_limp->sec[i].iamb[ia-1]=it->second[ia];
			olv_limp->amb_sec[it->second[ia]].sec = i;
		}
	}
		
fin:

	free(info);

	if(!ret)
	{
		pon_mi_msg("Error en lectura de info de sectorización: %s",err_str);
	}

	return ret;
}
//*************************************************************************************
/**
 * Calcula el número de sectores óptimo para los ámbitos dados
 */
BOOL Colv_limp_thr::calcula_n_sec()
{
	BOOL ret;
	int nsec;
	double cost_tot,cost_sec;

	////////////////
	ret=TRUE;	
	nsec=-1;
	////////////////
	
	olvlog(LOG_TODO,"olv_limp_t","Comienza cálculo del número de sectores");
	pon_mi_progre(OLV_TAREA_CALC_SEC, 0);
	pon_mi_msg("");	
	err_str[0]=0;

	////////////////
	olv_limp->nsec =olv_limp->nsec_act =  1; //se fija a un sector para planificar todo junto

	if(!pide_memo_secto())
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error, Sin memoria");
		ret=FALSE;
		goto fin;
	}		

	//hace la sectorización con un sector para que lo asigne por árbol
	if(!sectoriza_1())//rellena Info_sec
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error en la primera sectorización");
		ret=FALSE;
		goto fin;
	}	
	////////////////////////////////

	//calcula el coste de un sector con todos los ámbitos
	cost_tot=olv_limp->sec[0].cost_ac;//calcula_cost_1sec_total(olv_limp->n_amb,olv_limp->sec,olv_limp->ias,olv_limp->conjs.n,olv_limp->cost_conj,olv_limp->ang_conj);
	if(cost_tot>=MAYUSCULO)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error en el cálculo del coste total de los ámbitos");
		ret=FALSE;
		goto fin;
	}

	//calcula el número de sectores, diviendo por el coste máximo de un sector
	cost_sec = dame_cost_jornada();
	if(cost_sec<=0)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Tiempos de jornada, descanso y desplazamiento erróneos");
		ret=FALSE;
		goto fin;
	}
	nsec = (int)(cost_tot/cost_sec) + 1;
	////////////////
	olv_limp->calc_nsec=cost_sec; //se indica que el número de sectores es calculado, no impuesto
	////////////////////////////////

	//libera memoria
	olv_limp->libera_memo_secto();
	//pone el número de sectores calculado
	if(nsec==1)
	{
		olv_limp->nsec =olv_limp->nsec_act = nsec;
	}
	else
	{	
		olv_limp->nsec = nsec + 2;//elena abr 2018 coge un margen de 2, excepto si le ha salido que es 1
		olv_limp->nsec_act = max(nsec,2);
	}
	/////////////////////////////////

fin:
	if(!ret)
	{
		pon_mi_msg("Error en el cálculo del número de sectores: %s",err_str);
	}

	return ret;
}
//*************************************************************************************
/**
 * Calcula el tiempo efectivo de una jornada
 */
double Colv_limp_thr::dame_cost_jornada()
{
	return olv_limp->t_conv-olv_limp->t_desc;
}
//*************************************************************************************
/**
 * Lanza la planificación de todos los ámbitos en un sector para calcular el coste total, y lo devuelve
 * Devuelve también la secuencia de ámbitos planificada
 */
double Colv_limp_thr::calcula_cost_1sec_total(int n_amb, Info_sec *ss, Djkt_ang_ady *ang_conj)
{
	double coste;
	int nth,n_sec,i;
	Secu_amb *ord_sec;
	th_param_planif thp; 	
	BOOL log_debug;
	BOOL nocalc;

	////////////////
	log_debug=TRUE;
	n_sec=1;
	nth=Colv_geom::dame_n_nucleos();
	//inicia th
	memset(&thp, 0, sizeof(thp));
	thp.milis_sleep=1;
	thp.namb_t=n_amb;
	nocalc=FALSE;
	coste=0;
	////////////////

	ord_sec=olv_limp->ord_sec;
	
	//avisa de progreso
	olvlog(LOG_TODO,"olv_limp_t","Calculando permutaciones para mejorar al calcular coste de un sector total");
	pon_mi_progre(OLV_TAREA_PERMU,0);
	////////

	thp.dth=(th_data_planif*)malloc(sizeof(th_data_planif)*nth);
	memset(thp.dth, 0, sizeof(th_data_planif)*nth);
	thp.abs=TRUE;

	//lanza threads
	for (i=0; i<nth; i++)
	{
		thp.id_th=i;
		thp.dth[i].activo=TRUE;
		lck_sum_atm(&thp.nth,1);
		AfxBeginThread(th_planificacion, (LPVOID)&thp, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
		while(thp.id_th>=0)
			Sleep(1);
	}

	if(!calcula_coste_sectores(ord_sec, ss, n_sec, &thp, FALSE))
	{
		coste=MAYUSCULO;
		goto salir;
	}
	coste=ss[0].cost_ac;
	
salir:	

	//se bloquea y 
	thp.pirate=TRUE;
	while(thp.nth>0)
		Sleep(1);
	
	if(thp.dth)
	{
		if(thp.dth[0].sec)
			free(thp.dth[0].sec);
		free(thp.dth);

	}
	return coste;
}
//*************************************************************************************
/**
 * Devuelve la planificación de todos los sectores, en los que calcula la ruta óptima o cercana a la óptima
 * que recorre los ámbitos de dicho sector
 */
BOOL Colv_limp_thr::planifica()
{
	olvlog(LOG_TODO,"olv_limp_t","Comienza planificación");
	pon_mi_progre(OLV_TAREA_PLANIF, 0);
	pon_mi_msg("");	
	err_str[0]=0;

	//revisa si algún sector no tiene ámbitos
	int ns=0;
	for(int i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb>0)
			ns++;
	}
	olv_limp->nsec=ns;

	//inicializa el array de planificaciones
	olv_limp->plan=(Info_planif*)malloc(olv_limp->nsec*sizeof(Info_planif));
	if(!olv_limp->plan)
	{
		pon_mi_msg("Error, sin memoria en array de planificación");
		return FALSE;
	}
	memset(olv_limp->plan,0,olv_limp->nsec*sizeof(Info_planif));

	//lanza los threads
	lanza_subthrs(OLV_LIMP_EV_PLANIFICA_SUB);

	return TRUE;
}
//*************************************************************************************
/**
 * Devuelve la planificación del sector iésimo, que realiza el thread 'ithr'
 */
void Colv_limp_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;
	BOOL log_debug=FALSE;
	BOOL sal,sig;
	Djkt_nodo *costes_nodos;
	int nsecu,KK,ic_aux,ss,nsecu2;
	Secu_amb *secu_ambi=NULL;
	Param_olv_limp_thr  pp;
	Djkt_nodo*  buf_nod=NULL;
	costes_nodos=NULL;
	int msecu1, msecu2;
	msecu1 = msecu2 = olv_limp->conjs.n*2;
	int *secu,*secu2;
	secu=(int *)malloc(olv_limp->conjs.n*2*sizeof(int));
	
	if(!secu)
	{
		sal=TRUE;
		goto fin;
	}
	
	buf_nod=olv_limp->arch_dj.dame_buf_nodos();
	if(!buf_nod)
	{
		sal=TRUE;
		goto fin;
	}
	
	memset(secu,0,olv_limp->conjs.n*2*sizeof(int));
	secu2=(int *)malloc(olv_limp->conjs.n*2*sizeof(int));
	if(!secu2)
	{
		sal=TRUE;
		goto fin;
	}
	memset(secu2,0,olv_limp->conjs.n*2*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;	
	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);
	
	//////////////////////////
	//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;
		}
		
		///////////////////////////////////////////
		//Añade la ruta de la instalación al primer punto
		if(olv_limp->nod_instal>=0 && olv_limp->ord_sec_plan)
		{				
			olv_limp->arch_dj.get_b(s->iamb[secu_ambi[0].iamb],secu_ambi[0].entrada,buf_nod);
			Colv_geom::ruta_dj_inv_ok(
				olv_limp->nod_instal,//id conjuncion inicial
				&secu2[0], //puntero a secuencia
				buf_nod, //nodos djktra conj final 
				olv_limp->conjs.n,
				&nsecu2);
				
			if(!genera_planif_instala(is, 0, 0, nsecu2, secu2, OLV_IDA_INST))
				sal=TRUE;
		}
		///////////////////////////////////////////
		
		ss=1;
		s->cost_despl_aux=olv_limp->cost_amb[s->iamb[secu_ambi[0].iamb]][s->iamb[secu_ambi[0].iamb]];
		s->cost_despl_aux+=s->t_despl[0];//el desplazamiento de la instalación al primer ámbito
		secu[0]=olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[0].iamb]).entity()->ref].inod[secu_ambi[0].entrada];

		//almacena el coste acumulado
		aa[s->iamb[secu_ambi[0].iamb]].iseq=0;
		double cc, cc1=0;
		for (i=1; i<s->namb; i++)
		{				
			olv_limp->arch_dj.get_b(s->iamb[secu_ambi[i].iamb],secu_ambi[i].entrada, buf_nod);
			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],//id conjuncion final
				&secu[ss], //puntero a secuencia
				buf_nod, //nodos djktra conj inicial 
				olv_limp->conjs.n,
				&nsecu);
			ss+=nsecu;
			s->cost_despl_aux+=(float)cc;
			s->cost_despl_aux+=olv_limp->cost_amb[s->iamb[secu_ambi[i].iamb]][s->iamb[secu_ambi[i].iamb]];

			//almacena el coste acumulado
			aa[s->iamb[secu_ambi[i].iamb]].iseq=i;
			cc1+=olv_limp->arch_dj.dame_dis(s->iamb[secu_ambi[i-1].iamb],(secu_ambi[i-1].entrada+1)%2,s->iamb[secu_ambi[i].iamb],  secu_ambi[i].entrada);
			
			//////////////////
			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];
		}
		s->cost_despl_aux+=s->t_despl[1];//el desplazamiento del último ámbito a la instalación
		
		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);

		///////////////////////////////////////////
		//Ruta del último punto a la instalación
		if(olv_limp->nod_instal>=0 && olv_limp->ord_sec_plan)
		{		
			
			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_limp->ord_sec_plan[0].ctnod[0], //nodos djktra conj final 
				olv_limp->conjs.n,
				&nsecu2);
			if(!genera_planif_instala(is, 0, 0, nsecu2, secu2, OLV_VUELTA_INST))
			{
				sal=TRUE;
				break;
			}
		}
		///////////////////////////////////////////
		
		if(!pirate && !sal)
		{		
			//////////////////////////////////
			//genera la ruta y los puntos de control
			if(!genera_planif(is,s->cost_despl_aux, ss, secu,OLV_PLAN_NORMAL))
				sal=TRUE;
			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_nod);
	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);
}
//*************************************************************************************
/**
 * Finaliza y centraliza tareas de planificar, cuando han acabado todos los threads
 */
BOOL Colv_limp_thr::planifica_fin()
{
	//para los threads
	para_subthrs();	
	err_str[0]=0;

	///////////////////////////////////////
	//Si es barrido mixto hay que copiar la info en las que no se ha sectorizado
	if(olv_limp->barr_mix)
		copia_info_barr_mix();	

	///////////////////////////////////
	//prepara los datos para guardarlos
	if(!genera_rut_ctrl(olv_limp->nsec, olv_limp->plan, FALSE))
	{
		pon_mi_msg("Errores en la generación de cartografía con ruta");
		return FALSE;
	}
	//genera el listado del itinerario
	if(!genera_list_rut_ctrl())
	{
		pon_mi_msg("Errores en la generación del listado de la ruta: %s",err_str);
		return FALSE;
	}
	//graba a archivo el obg
	if(!guarda_shp_rut_ctrl())
	{
		pon_mi_msg("Errores en el guardado a shp de la ruta: %s",err_str);
		return FALSE;
	}	

	if(!guarda_dbf_sector(2))
	{
		pon_mi_msg("Errores en la generación de información asociada de sector: %s",err_str);
		return FALSE;
	}
	///////////////////////////////////

	/////////////////////////////////////////////
	//A continuación genera y graba los archivos de los subtramos de cada ruta
	if(!gen_guard_subtramos())
		return FALSE;
	///////////////////////////////////

	olvlog(LOG_TODO,"olv_limp_t","Planificación finalizada");

	return TRUE;
}
//*************************************************************************************
/**
 * Dada la secuencia de las conjunciones que sigue la ruta, genera la ruta diciendo por qué 
 * elementos de la red pasa y coloca los puntos de control
 */
BOOL Colv_limp_thr::genera_planif(int is, double cost_sec, int nsecu, int *secu, int tip_plan)
{
	int npt_ctrl,ipc;
	double cost_ctrl;
	Info_planif *pp;

	olvlog(LOG_TODO,"olv_limp_t","Almacenando planificación sector %02d",is);

	/////////////////
	ipc=0;
	npt_ctrl=(olv_limp->npts_ctrl-2);
	pp=&olv_limp->plan[is];
	
	if(!genera_planif_aux(is,&olv_limp->sec[is], pp, nsecu, secu,tip_plan))
		return FALSE;

	cost_ctrl=pp->elem[pp->nelem-1].coste/(olv_limp->npts_ctrl-2+1);
	pon_ptos_ctrl(pp, npt_ctrl, cost_ctrl);
	
	//////////////////////////////////////////////////////////

	/*if (!_CrtCheckMemory())
		int i=0;*/

	return TRUE;
}
//*************************************************************************************
/**
 */
void Colv_limp_thr::pon_ptos_ctrl(Info_planif *pp, int npt_ctrl, double cost_ctrl)
{
	double cost_acum;
	int i, ipc;
	///////////////////////////////////////////////////////////////
	//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=0;
	for(i=0;i<pp->nelem;i++)
	{	
		/////////////////////////////
		cost_acum=pp->elem[i].coste;
		//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;
		}
	}

	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, genera la ruta diciendo por qué 
 * elementos de la red pasa y coloca los puntos de control - Función auxiliar
 */
BOOL Colv_limp_thr::genera_planif_aux(int is, Info_sec *ss, Info_planif *pp, int nsecu, int *secu, int tip_plan)
{
	int nent, ref_j, i, j, dt,npt, amb_j,nelesec,tp,ref_nw,itr,last_pt,k;
	double cost,cost_perd,ltot,cost_parc_aux;
	CartoBaseInfoEntity ient;
	BYTE *ambs_sec;
	BOOL is_uno,sal,is_descarg,sdire;
	
	//////////////////////////////////////////////////////////////////
	nent=olv_limp->carto.getNumberEntities();
	nelesec=itr=0;
	cost_parc_aux=0;
	sal=is_descarg=sdire=FALSE;
	last_pt=-1;
	is_uno=FALSE;
	ref_nw=0;
	//////////////////////////////////////////////////////////////////

	if(nsecu==1)
	{
		is_uno=TRUE;
		nsecu=2;
	}
	//Inicializa los arrays de elementos
	pp->nelem = nsecu-1;
	//ielem
	pp->elem=(Info_elem_planif*)malloc(pp->nelem*sizeof(Info_elem_planif));
	if(!pp->elem)
		return FALSE;
	memset(pp->elem,0,pp->nelem*sizeof(Info_elem_planif));	
	//////////////////////////////////////////////////////////////////

	//si es un único elemento
	if(is_uno)
	{
		//recorre los ámbitos buscándolo
		for(j=0;j<nent;j++)
		{
			ient=olv_limp->carto.getEntity(j);

			if(ient.entity()->type!=CartoBaseTypes::Line)
				continue;

			ref_j=ient.entity()->ref;
			amb_j=olv_limp->iaso[ref_j].iamb;			

			if(secu[0]==olv_limp->iaso[ref_j].inod[0] || 
				secu[0]==olv_limp->iaso[ref_j].inod[1])
				break;
		}
		if(j>=nent)
		{
			return FALSE;
		}
		cost=0;
		if(amb_j>0)
		{		
			cost=olv_limp->cost_amb[amb_j][amb_j];			
		}
		else
		{
			amb_j=olv_limp->iaso[olv_limp->iaso[ref_j].refe2].iamb;
			if(amb_j>0)
				cost=olv_limp->cost_amb[amb_j][amb_j];

		}
		dt=OLV_TTO;

		//añade la info del elemento
		pp->elem[0].refe=ref_j;
		pp->elem[0].k=0;
		pp->elem[0].tp = OLV_PLAN_TIP_AMB;
		pp->elem[0].ref_nw = -1;	
		pp->elem[0].coste = cost;
		pp->elem[0].ltot = 0;
		pp->t[dt]=cost;
		pp->m[dt]=0;
		pp->m[OLV_TTO_2] = 0;
		return TRUE;
	}
	//////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////
	ambs_sec=(BYTE*)malloc(ss->namb);
	if(!ambs_sec)
		return FALSE;
	memset(ambs_sec,0,ss->namb);		

	//bucle para cada conjunción de la secuencia
	for(i=0;i<nsecu-1 && !sal;i++)
	{
		if(secu[i]==secu[i+1])
			continue;//para los tipos puntuales		

		//bucle para cada elemento de la red, buscando esa conjunción
		for(j=0;j<nent;j++)
		{
			ient=olv_limp->carto.getEntity(j);
			if(ient.entity()->type!=CartoBaseTypes::Line)
				continue;

			ref_j=ient.entity()->ref;
			amb_j=olv_limp->iaso[ref_j].iamb;

			//busca por las conjunciones almacenadas
			sdire=((secu[i]==olv_limp->iaso[ref_j].inod[0])&&
				(secu[i+1]==olv_limp->iaso[ref_j].inod[1]));
			if(sdire || 
				(((secu[i+1]==olv_limp->iaso[ref_j].inod[0])&&
				(secu[i]==olv_limp->iaso[ref_j].inod[1]))))
			{
				break;
			}
		}
		if(j>=nent)
		{
			sal=TRUE;
			continue;
		}
		if(amb_j<0 && olv_limp->iaso[ref_j].refe2>=0)
		{
			//no es un ámbito
			amb_j=olv_limp->iaso[olv_limp->iaso[ref_j].refe2].iamb;
		}
		if(amb_j<0 && !(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_NW))
		{
			sal=TRUE;
			continue;
		}

		//calcula la longitud
		npt=ient.getNumberPtos();
		ltot = ient.getLong();
		cost=olv_limp->cost_conj[secu[i]][secu[i+1]];
		dt=OLV_DT_N;
		/////////////////////////////		
		//mira a ver si es carretera o amb para poner inw
		if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_AMB) //es ámbito
		{
			ref_nw=olv_limp->inww_amb[amb_j+!sdire*olv_limp->n_amb].refnw;	

			///////////////////////////////////
			//si no pertenece a los ámbitos de este sector o ya ha pasado por él, 
			//es que está desplazándose por él, le pone tipo nw
			for(k=0;k<ss->namb;k++)
			{
				if(ss->iamb[k]==amb_j)
					break;
			}
			if(k>=ss->namb || ambs_sec[k] || (tip_plan==OLV_PLAN_INST))
			{
				tp=OLV_PLAN_TIP_NW; //es la segunda vez que pasa por ahí
				dt=OLV_DESP;
				cost=ltot/olv_limp->v_despl;
			}
			else
			{			
				///////////////////////////////////				
				if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_AMB_PEAT)
					tp=OLV_PLAN_TIP_AMB_PEAT;
				else
					tp=OLV_PLAN_TIP_AMB;

				dt=OLV_TTO;
				ambs_sec[k]=1;
			}

		}
		else if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_SEG_LIN) //es segmento de ámbito
		{
			if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_FIN)
				ref_nw=olv_limp->inww_amb[amb_j+olv_limp->n_amb].refnw;
			else
				ref_nw = olv_limp->inww_amb[amb_j].refnw;
			tp=OLV_PLAN_TIP_SEG_LIN;
			ltot=0;
		}
		else if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_SEG_PUN)
		{
			ref_nw = olv_limp->inww_amb[amb_j].refnw;
			tp=OLV_PLAN_TIP_AMB;
			ltot=0;
			if((last_pt==ref_j) || (tip_plan==OLV_PLAN_INST))
			{
				cost=0;
				tp=OLV_PLAN_TIP_NW;
			}
			else
			{
				cost=olv_limp->cost_amb[amb_j][amb_j];
				last_pt=ref_j;
				dt=OLV_TTO;
			}	
		}
		else if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_PEAT_REP)
		{
			tp=OLV_PLAN_TIP_AMB_PEAT_DESP;
			//en info0 se ha guardado la peatonal original
			ref_nw=olv_limp->inww_amb[amb_j+!sdire*olv_limp->n_amb].refnw;
			dt=OLV_DESP;
			cost=ltot/olv_limp->v_despl;
		}
		else//es carretera
		{
			ref_nw=ref_j;	
			tp=OLV_PLAN_TIP_NW;
			dt=OLV_DESP;
		}

		////////////////////
		if(is_descarg && (tp!=OLV_PLAN_TIP_AMB))
		{
			cost_perd+=cost;
			cost=ltot=0;
		}
		////////////////////
		if((ltot==0) && (dt!=OLV_TTO))
			cost=0;
		//////
		//calcula coste acumulado
		if(nelesec>0)
			cost_parc_aux=pp->elem[nelesec-1].coste;
		else
			cost_parc_aux=0;
		//añade la info del elemento
		pp->elem[nelesec].refe=ref_j;
		pp->elem[nelesec].k=!sdire;
		pp->elem[nelesec].tp = tp;
		pp->elem[nelesec].ref_nw = ref_nw;	
		pp->elem[nelesec].coste = cost_parc_aux + cost;
		pp->elem[nelesec].ltot = ltot;
		pp->elem[nelesec].aux=0;

		//////////////
		if(dt<OLV_DT_N)
		{		
			if ((olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h) && (dt == OLV_TTO))
			{
				pp->m[OLV_TTO_2] += (ltot * olv_limp->iaso[ref_j].inf_l.ancho);
				pp->m[dt] += ltot;
			}
			else
				pp->m[dt]+=ltot;
			pp->t[dt]+=cost;
		}

		//////////////
		if((tip_plan==OLV_PLAN_RECO) && (tp==OLV_PLAN_TIP_AMB))
		{			
			pp->elem[nelesec].aux=itr;//marca los tramos
			if(comprueba_descarg(amb_j))
				itr++;
			if((!is_descarg && comprueba_descarg(amb_j)) 
				|| (is_descarg && !comprueba_descarg(amb_j)))
			{			
				cost_perd=0;
				is_descarg=!is_descarg; 
			}

		}
		//////////////
		nelesec++;	
	}
	if(sal)
	{
		free(ambs_sec);
		return FALSE;
	}

	pp->nelem = nelesec;

	free(ambs_sec);
	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_limp_thr::comprueba_descarg(int iamb)
{
	return FALSE;
}
//*************************************************************************************
/**
 * Dada la secuencia de las conjunciones que sigue la ruta para ir y volver de la instalación, genera la planificación
 */
BOOL Colv_limp_thr::genera_planif_instala(int is, int nvaciados, int ini, int fin, int *secu, int tip_viaje)
{
	int i;
	Info_planif *pp,*pp_insta;
	Info_sec *ss;

	ss=&olv_limp->sec[is];
	pp=&olv_limp->plan[is];
	pp_insta = pp->planif_insta;
	if(!pp_insta)
	{
		//inicializa, sólo la primera vez
		//cuenta el número de veces que va a vaciar
		pp->ninsta=2;//inicialmente tiene la ida y la vuelta a la instalación
		if(nvaciados)
			pp->ninsta+=nvaciados*2-1;	//todos los vaciados son ida y vuelta
		pp_insta = (Info_planif *)malloc(pp->ninsta*sizeof(Info_planif));
		if(!pp_insta)
			return FALSE;
		memset(pp_insta,0,pp->ninsta*sizeof(Info_planif));

		pp_insta[0].ninsta=OLV_IDA_INST;
		pp_insta[pp->ninsta-1].ninsta=OLV_VUELTA_INST;
		pp->planif_insta = pp_insta;
	}

	//busca cuál le toca rellenar
	for(i=0;i<pp->ninsta;i++)
	{
		if(pp_insta[i].nelem==0)
			break;
	}
	if(i>=pp->ninsta)
		return FALSE;
	pp_insta[i].ninsta=tip_viaje;

	if(!genera_planif_aux(is,ss, &pp_insta[i],fin-ini,&secu[ini],OLV_PLAN_INST))
		return FALSE;

	if(tip_viaje==OLV_IDA_INST)
		olv_limp->sec[is].t_despl[0]=(float)pp_insta[i].elem[pp_insta[i].nelem-1].coste + olv_limp->t_sal;
	else if(tip_viaje==OLV_VUELTA_INST)
		olv_limp->sec[is].t_despl[1]=(float)pp_insta[i].elem[pp_insta[i].nelem-1].coste + olv_limp->t_sal;

	return TRUE;
}
//*************************************************************************************
/**
 * Dadas las rutas de los sectores, genera la ruta en una única línea en el obg 
 * y en otro coloca los puntos de control
 */
BOOL Colv_limp_thr::genera_rut_ctrl(int ns, Info_planif *planif, BOOL tramos)
{
	int is, it, nt, ie_ini, ie_fin, i, k, ins, npt,nmax_pts;
	double long_fl, long_max_fl;
	BOOL mal;
	CartoLine lin, lin_fl;
	CartoPto pt;
	CartoBaseInfoEntity ient, ient2;
	Info_planif *pp;

	////////////////
	long_max_fl=15;
	long_fl=1;
	nmax_pts=0;
	mal=FALSE;
	memset(pt.pt,0,3*sizeof(double));
	/////////////////

	olvlog(LOG_TODO,"olv_limp_t","Generando lineales de las rutas en obg");

	///////////////////////////////////////////////
	//Genera el obg de la ruta, un lineal por sector (o varios por sector si hay idas a recogida)
	for(is=0;is<ns && !mal;is++)
	{
		pp=&planif[is];	

		if(tramos)
		{
			nt=(int)olv_limp->tramos[is].size();
			for(it=0;it<nt;it++)
			{		
				ie_ini=olv_limp->tramos[is][it].ie[0];
				ie_fin=olv_limp->tramos[is][it].ie[1];

				if(!genera_rut_aux(pp, is, FALSE,ie_ini,ie_fin))
				{					
					mal=TRUE;
					break;

				}
			}
		}
		else
		{
			if(!genera_rut_aux(pp, is, FALSE,0,pp->nelem-1))
			{					
				mal=TRUE;
				break;

			}

			for(ins=0;ins<pp->ninsta;ins++)
			{
				//solo entra aquí si hay ruta a las instalaciones
				if(!genera_rut_aux(&pp->planif_insta[ins], is, TRUE,0,pp->planif_insta[ins].nelem-1))
				{
					mal=TRUE;
					break;
				}
			}
		}
	}
	///////////////////////////////////////////////
	//Genera el obg de los puntos
	if(!tramos && !mal)		
	{	
		int ie;
		int isfin;
		for(is=0;is<ns && !mal;is++)
		{
			pp=&planif[is];

			for(i=0;i<olv_limp->npts_ctrl;i++)
			{
				pt.ia= olv_limp->sec[is].sec_def;
				memset(pt.pt,0,3*sizeof(double));
				if(pp->nelem>0)
				{
					isfin=0;
					if(i==0)
						ie=0; //el punto de control primero está en el primer elemento
					else if(i==olv_limp->npts_ctrl-1)
					{
						ie=pp->nelem-1;//el punto de control último está en el último elemento
						isfin=1;
					}
					else
						ie=pp->pts_ctrl[i-1].ipt;//los puntos de control intermedios, los que se han calculado

					ient=olv_limp->carto.getRef(pp->elem[ie].refe);
					npt=ient.getNumberPtos();
					k=(pp->elem[ie].k+isfin)%2; //porque si es el punto de control final, lo tiene que poner al final 
					//del tramo, no al principio  

					memcpy(pt.pt,ient.getPto(k*(npt-1)),3*sizeof(double));
				}
				mal=(!carto_ctrl.add(pt));
			}
		}
	}

	if(mal)
		return FALSE;

	return TRUE;
}
//*************************************************************************************
/**
 * Dadas las rutas de los sectores, genera la ruta en una única línea en el obg 
 * y en otro coloca los puntos de control - Función auxiliar
 */
BOOL Colv_limp_thr::genera_rut_aux(Info_planif *pp, int is, BOOL is_insta, int ie_ini, int ie_fin)
{
	int npt,npt_tot,i,k;
	double (*pts_lin)[3],(*ptos_par)[3],(*ptos)[3],(*pts_lin_fl)[3];
	BOOL mal;
	CartoLine lin, lin_parc, lin_fl;
	CartoBaseInfoEntity ient;
	double d;
	double ltot, long_max_fl;
	int nfl;
	CartoBase *flech, *rut;

	//para debug
	CartoBase carto_aux;

	if(is_insta)
	{
		flech = NULL;
		rut = &carto_inst;
	}
	else
	{
		flech=&carto_flech;
		rut =&carto_rut;
	}

	////////////////
	long_max_fl=5;
	mal=FALSE;
	/////////////////

	if(pp->nelem==0 && is_insta)
		return TRUE;
	if(pp->nelem==0 && !is_insta)
		npt_tot=2;
	else
	{
		npt_tot=0;		
		//Contar puntos
		for(i=ie_ini;i<=ie_fin;i++)
		{			
			/////////////////////////////
			npt_tot += olv_limp->carto.getRef(pp->elem[i].refe).getNumberPtos()-1;
		}
		npt_tot++;
	}
	if(!(lin.pts+=npt_tot))//pide memoria
	{
		return FALSE;
	}
	pts_lin = lin.pts.ptr;

	//Añadir puntos
	for(i=ie_ini;i<=ie_fin;i++)
	{
		ient=olv_limp->carto.getRef(pp->elem[i].refe);
		npt=ient.getNumberPtos();
		lin_parc.pts.n=0;
		ptos=(double (*)[3])ient.getPto(0);
		ptos_par=NULL;

		//si es carretera y es de doble sentido, 
		//hace la paralela a una distancia dada para que no se superpongan la ida y la vuelta
		if((pp->elem[i].tp==OLV_PLAN_TIP_NW) && (olv_limp->iaso[pp->elem[i].refe].flgs & OLV_LIMP_FLG_NW) && 
			!((olv_limp->iaso[pp->elem[i].refe].flgs & OLV_LIMP_FLG_CIRC_NO_DOB)))
		{
			d=OLV_DIST_PARALELAS;
			if(pp->elem[i].k==0)
				d=d*(-1);//distancia negativa si es sentido contrario
			
			Colv_geom::haz_paralela(ptos,npt,d,&ptos_par);
			ptos=(double (*)[3])ptos_par;
		}
		lin_parc.pts.add(ptos,npt);
		/////////////////////////
		//por si hay que darle la vuelta a los puntos
		if(pp->elem[i].k==1)
		{
			lin_parc.invert();
		}

		carto_aux.add(lin_parc);

		if(!(lin.pts+lin_parc.pts))
		{
			return FALSE;
		}
		if(i<ie_fin) //en el último caso no se hace
			lin.pts.n--;

		/////////////////////////		

		if(ptos_par)
			free(ptos_par);
	}
	if(pp->nelem==0 && !is_insta)
	{
		lin.addPto(olv_limp->carto.getPto(0));
		lin.addPto(olv_limp->carto.getPto(0));
	}
	lin.ia=olv_limp->sec[is].sec_def;
	if(!rut->add(lin))
	{
		return FALSE;
	}

	if(is_insta)
		return TRUE;
	
	/////////////////////
	//carto_aux.exportShp("C:\\Proyectos\\Olivia\\Instal\\rut.shp");
	/////////////////////

	//ahora las flechas
	lin_fl.pts+=2;
	lin_fl.pts.n=2;
	pts_lin_fl = lin_fl.pts.ptr;
	lin_fl.ia= olv_limp->sec[is].sec_def;
	if(pp->nelem==0 && !is_insta)
	{
		lin_fl.addPto(olv_limp->carto.getPto(0));
		lin_fl.addPto(olv_limp->carto.getPto(0));
		if(!flech->add(lin_fl))
		{
			return FALSE;
		}
		return TRUE;
	}

	/////////////////////////////////
	//Pone las flechas a lo largo de la línea
	nfl=0;
	ltot= lin.getLong();		
	nfl=(int)(ltot/long_max_fl);
	for(i=0;i<nfl;i++)
	{
		for(k=0;k<2;k++)
			lin.GetPtoDis(min(long_max_fl*i+k*long_max_fl,ltot),pts_lin_fl[k],&ltot);

		if(!flech->add(lin_fl))
		{
			break;
		}
	}
	if(i<nfl)
		return FALSE;

	return TRUE;
}
//*************************************************************************************
/**
 * Guarda a un archivo shape con path en la configuración la ruta y los puntos de control
 */
BOOL Colv_limp_thr::guarda_shp_rut_ctrl()
{
	char path_shp[MAX_PATH];

	//antes ha tenido que generar un único lineal con la ruta
	olvlog(LOG_TODO,"olv_limp_t","Guardandoa shp los archivos de rutas");

	//primero graba los archivos de la ruta de los sectores
	//graba todos los sectores en un único path
	strcpy_s(path_shp,MAX_PATH,olv_limp->olv->paths.path_res_rut);
	//cambiaext(path_shp,".shp","");
	*(Cdir_manager::extension_archivo(path_shp)-1)=0;

	strcat_s(path_shp,"_R.shp");
	carto_rut.setNameIa(olv_limp->camps.campo_secto);
	if(!carto_rut.linesExportShp(path_shp))
		return FALSE;
	if(!guarda_cols_ruta(path_shp))
		return FALSE;		

	///////////////////////////////////////////////////////
	//luego graba los archivos de los puntos de control
	//graba todos los sectores en un único path
	strcpy_s(path_shp,MAX_PATH,olv_limp->olv->paths.path_res_pt);
	//cambiaext(path_shp,".shp","");
	*(Cdir_manager::extension_archivo(path_shp)-1)=0;
	strcat_s(path_shp,"_C.shp");
	carto_ctrl.setNameIa(olv_limp->camps.campo_secto);
	if(!carto_ctrl.ptosExportShp(path_shp))
		return FALSE;
	if(!guarda_cols_ctrl(path_shp))
		return FALSE;		

	/////////////////////////////////////////////
	//A continuación graba los archivos de las flechas
	strcpy_s(path_shp,MAX_PATH,olv_limp->olv->paths.path_res_rut);
	//cambiaext(path_shp,".shp","");
	*(Cdir_manager::extension_archivo(path_shp)-1)=0;

	strcat_s(path_shp,"_Raux.shp");
	carto_flech.setNameIa(olv_limp->camps.campo_secto);
	if(!carto_flech.linesExportShp(path_shp))
		return FALSE;

	/////////////////////////////////////////////
	//A continuación graba los archivos de los viajes a las instalaciones
	if(olv_limp->nod_instal>=0)
	{	
		strcpy_s(path_shp,MAX_PATH,olv_limp->olv->paths.path_res_rut);
		//cambiaext(path_shp,".shp","");
		*(Cdir_manager::extension_archivo(path_shp)-1)=0;

		strcat_s(path_shp,"_I.shp");
		carto_inst.setNameIa(olv_limp->camps.campo_secto);
		if(!carto_inst.linesExportShp(path_shp))
			return FALSE;
		if(!guarda_cols_insta(path_shp))
			return FALSE;	
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Genera y guarda el shp con las rutas en subtramos, para recogida porque se va a descargar
 */
BOOL Colv_limp_thr::gen_guard_subtramos()
{
	int ntramos=0;
	char path_shp[MAX_PATH];

	//reutiliza los mismos cartos
	carto_rut.del();
	carto_flech.del();

	//cuenta tramos
	cuenta_tramos();

	if(!genera_rut_ctrl(olv_limp->nsec, olv_limp->plan, TRUE))
	{
		pon_mi_msg("Errores en la generación de cartografía con ruta de los subtramos");
		return FALSE;
	}

	rellena_tramos();

	if(olv_limp->tipo_shp_viaj==OLV_SHPRUTINST)
	{
		int ii=rellena_insta_tramos();
		//combina los lineales de cada subtramo con la ida a descargar y la vuelta de descargar anterior
		if(ii>0 && !combina_rut_insta())
		{
			pon_mi_msg("Errores en la combinación de viajes con viajes a instalación");
			return FALSE;
		}
	}	

	//graba los archivos de la ruta de los sectores
	//graba todos los sectores en un único path
	strcpy_s(path_shp,MAX_PATH,olv_limp->olv->paths.path_res_rut);
	//cambiaext(path_shp,".shp","");
	*(Cdir_manager::extension_archivo(path_shp)-1)=0;

	strcat_s(path_shp,"_R2.shp");
	carto_rut.setNameIa(olv_limp->camps.campo_secto);
	if(!carto_rut.linesExportShp(path_shp))
	{
		pon_mi_msg("Errores en el guardado del shp de la capa de viajes");
		return FALSE;
	}

	if(!guarda_cols_ruta_tram(path_shp))
	{
		pon_mi_msg("Errores al guardar las columnas de la capa de viajes");
		return FALSE;
	}	

	//guarda en los ámbitos una columna de "tramo al que pertenecen"
	if(!guarda_dbf_sector(3))
	{
		pon_mi_msg("Errores al guardar la columna de viaje de cada cont");
		return FALSE;
	}

	delete [] olv_limp->tramos;
	olv_limp->tramos=NULL;

	return TRUE;
}//*************************************************************************************
/**
 * 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_limp_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;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);

			tramo->long_tr += pinsta[tramo->iins[0]].m[OLV_DESP] + pinsta[tramo->iins[1]].m[OLV_DESP];
		}
		if (nins % 2) //instala y descarga distintos si es impar
		{
			//para el último tramo
			tramo = &olv_limp->tramos[is][nt-1];
			//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;
			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);
			tramo->long_tr += pinsta[tramo->iins[1]].m[OLV_DESP];			
		}
		ii++;
	}
	return ii;
}
//*************************************************************************************
/**
 * Añade las columnas de información a la ruta, tiempos, longitudes, y demás
 */
BOOL Colv_limp_thr::guarda_cols_ruta_tram(char *path_shp)
{
	char *info;
	char path_dbf[MAX_PATH];
	double tt;
	int h,m,s;
	int i, it,ntram,nt,nt_parc;
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	//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); 
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//SECTOR ya viene

	//TRATAMIENTO
	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++)
		{	
			sprintf_s(&info[(nt_parc+it)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%s",olv_limp->nomb_tto);
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"TTO",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//VIAJE
	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=it+1;
			((int*)info)[nt_parc + it] = tt;
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"VIAJE",GdataTable::Tint,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//H_INI
	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].t_ini;
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[(nt_parc+it)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"H_INI",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//H_FIN
	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].t_fin;
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[(nt_parc+it)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"H_FIN",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//T_TOTAL
	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].t_total_tr;//tramos[i][it].t_fin-tramos[i][it].t_ini;
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[(nt_parc+it)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"T_TOTAL",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//M_TOTAL
	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;			
			//para guardar en número
			((double*)info)[nt_parc + it] = tt;
		}
		nt_parc += nt;
	}
	if (!dbfmgr.AddCol(NULL, "M_TOTAL", GdataTable::Tdouble, &dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info, 0, ntram* OLV_SHP_SZ_CAMP_SZ);

	//T_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].t_tto_tr;
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[(nt_parc+it)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"T_TRAT",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	free(info);

	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Cuenta los tramos que hay en la ruta del sector is, si va varias veces a descargar
 */
void Colv_limp_thr::cuenta_tramos()
{
	olv_limp->tramos = new std::vector<Info_tramos>[olv_limp->nsec];  
	Info_planif *pp;
	Info_tramos tramo;
	int ie,ii,ilast,iamb;

	memset(&tramo,0,sizeof(Info_tramos));
	tramo.iins[0]=tramo.iins[1]=-1;

	for(int is=0;is<olv_limp->nsec;is++)
	{
		pp=&olv_limp->plan[is];
		ii=0;
		tramo.ie[0]=0;
		for(ie=0;ie<pp->nelem;ie++)
		{
			if(pp->elem[ie].tp!=OLV_PLAN_TIP_AMB)
				continue;
			if(pp->elem[ie].aux!=ii)
			{				
				tramo.ie[1]=ilast;
				olv_limp->tramos[is].push_back(tramo);
				ii++;
				tramo.ie[0]=ie;
			}
			if(olv_limp->iaso[pp->elem[ie].refe].flgs & OLV_LIMP_FLG_SEG_PUN)
				iamb=olv_limp->iaso[pp->elem[ie].refe].refe2;
			else
				iamb=olv_limp->iaso[pp->elem[ie].refe].iamb;
			olv_limp->amb_sec[iamb].res=ii; //marca el tramo en el array de ambitos
			ilast=ie;
		}
		tramo.ie[1]=pp->nelem-1;
		olv_limp->tramos[is].push_back(tramo);
	}
}
//*************************************************************************************
/**
 * Rellena la info de los tramos
 */
void Colv_limp_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->t_tto_tr = (float)(pp->t[OLV_TTO]);
						
			//actualiza tiempos de tramos
			if (pp->planif_insta)
			{
				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];
			}
			else
			{
				tramo->t_ini = (float)olv_limp->t_ini;
				tramo->t_fin = (float)(tramo->t_ini + olv_limp->sec[is].cost_ac + olv_limp->t_desc);
			}			
			
			tramo->t_total_tr = (float) (tramo->t_fin-tramo->t_ini);
		}
	}
}
//*************************************************************************************
/**
 * Dadas las rutas de los sectores, genera la ruta en una única línea en el obg 
 * y en otro coloca los puntos de control
 */
BOOL Colv_limp_thr::combina_rut_insta()
{
	//en ob_rut ahora están todos los subtramos en orden: 
	//1 viaje del sector 1, 2 viaje del sector 1, 1 viaje del sector 2, etc
	//hay que añadir al primer viaje de cada sector la ida desde instalación y la ida a descargar (y la ida a instalación
	//si es un único viaje)
	//al resto de viajes intermedios hay que añadirles la vuelta de descargar anterior y la ida a descargar
	//al último viaje hay que añadirle la ida a descargar y la ida a instalación
	int is=0, it=0, nt=0, i=0, npt_tot, npt, ntparc,ii;
	int niparc, res, nmax_pts;
	BOOL mal = false;
	Info_planif *planif, *pp;
	double (*ptos_aux)[3],(*ptos)[3];
	CartoLine lin;
	
	planif= olv_limp->plan;
		
	ntparc=0;
	niparc=0;
	nmax_pts=0;
	for(is=0;is<olv_limp->nsec && !mal;is++)
	{
		pp=&planif[is];	
		nt=(int)olv_limp->tramos[is].size();
		lin.ia= olv_limp->sec[is].sec_def;
		lin.pts.n=0;
		for(it=0;it<nt && !mal;it++)
		{	
			npt_tot=0;
			lin.pts.n=0;
			res=0;					
			npt=carto_rut.getEntity(it+ntparc).getNumberPtos();
			npt_tot+=npt;
			for(ii=olv_limp->tramos[is][it].iins[0]; ii<=olv_limp->tramos[is][it].iins[1];ii++)
			{
				npt=carto_inst.getEntity(ii+niparc).getNumberPtos();
				npt_tot+=npt;
				res++;
			}
			//dado que junta tramos, resta para no replicar los puntos de unión
			npt_tot=npt_tot-res;

			////////////////////////////////////////////////////////////////////
			//marca para borrar ese tramo
			carto_rut.remove(it+ntparc);
			//ya que tiene el total de puntos, actualiza el lineal de ese tramo		
			lin.pts+=npt_tot;
			ptos_aux=lin.pts.ptr;			
			if(!ptos_aux)
			{
				mal=TRUE;
				continue;
			}

			//////////////////////////////////////////////////////////////////////
			//ahora copia en ptos_aux los lineales de los tramos que le corresponden
			for(ii=olv_limp->tramos[is][it].iins[0]; ii<=olv_limp->tramos[is][it].iins[1];ii++)
			{
				npt=carto_inst.getEntity(ii+niparc).getNumberPtos();
				ptos = (double (*)[3])carto_inst.getEntity(ii+niparc).getPto(0);

				//copia el viaje al lineal total
				lin.pts.add(ptos,npt);
				lin.pts.n--;
				//memcpy(ptos_aux[npt_parc],ptos,npt*3*sizeof(double));
				//npt_parc+=npt-1;
				if(ii==olv_limp->tramos[is][it].iins[1])
					lin.pts.n++;

				if(ii==olv_limp->tramos[is][it].iins[0])
				{
					//después del primer viaje se copia el tramo de recogida
					npt=carto_rut.getEntity(it+ntparc).getNumberPtos();
					ptos = (double (*)[3])carto_rut.getEntity(it+ntparc).getPto(0);

					//copia el viaje al lineal total
					lin.pts.add(ptos,npt);
					lin.pts.n--;
					//memcpy(ptos_aux[npt_parc],ptos,npt*3*sizeof(double));
					//npt_parc+=npt-1;
				}
			}
			//////////////////////////////////////////////////////////////////////
			if(!carto_rut.add(lin))
			{
				mal=TRUE; //entra por aquí??
				continue;
			}
		}
		niparc+=ii; //ii apunta a la última instalación del primer sector
		ntparc+=nt;
	}
	if(mal)
	{
		return FALSE;
	}
	carto_rut.FastClear();
	return TRUE;
}
//*************************************************************************************
/**
 * Añade las columnas de información a la ruta, tiempos, longitudes, y demás
 */
BOOL Colv_limp_thr::guarda_cols_ruta(char *path_shp)
{
	char *info;
	char path_dbf[MAX_PATH];
	double tt;
	int h,m,s;
	char nombia[16];
	int nsec, i, isec_novac;
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	//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++;
	}

	////////////////////////////////////
	//El coste_ac es lo mismo que el cost del último elemento de la planif 
	//más el de desplazamientos inicial y final y de descargas
	//Para el total, hay que añadir los descansos
	/////////////////////////////////////

	//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);	
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//SECTOR ya viene
	//TRATAMIENTO
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
		{
			continue;
		}
		sprintf_s(&info[isec_novac*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%s",olv_limp->nomb_tto);
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"TTO",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de hora inicial
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
		{
			continue;
		}
		tt=olv_limp->t_ini;
		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(NULL,"H_INI",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena 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(NULL,"H_FIN",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de duración total
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=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(NULL,"T_TOTAL",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena col m total
	isec_novac = 0;
	for (i = 0; i < olv_limp->nsec; i++)
	{
		if (olv_limp->sec[i].namb == 0)
			continue;

		tt = 0;
		if ((olv_limp->nod_instal != -1) && (olv_limp->plan[i].ninsta > 0))
		{
			tt = olv_limp->plan[i].planif_insta[0].m[OLV_DESP];
			tt += olv_limp->plan[i].planif_insta[olv_limp->plan[i].ninsta - 1].m[OLV_DESP];
		}

		tt += olv_limp->plan[i].m[OLV_DESP] + olv_limp->plan[i].m[OLV_TTO];
		//para guardar en número
		((double*)info)[isec_novac] = tt;

		isec_novac++;
	}
	if (!dbfmgr.AddCol(NULL, "M_TOTAL", GdataTable::Tdouble, &dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info, 0, nsec * OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de duración de los desplazamientos
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt= olv_limp->sec[i].t_despl[0]+olv_limp->sec[i].t_despl[1];
		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(NULL,"T_INSTA",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena col m insta	
	isec_novac = 0;
	for (i = 0; i < olv_limp->nsec; i++)
	{
		if (olv_limp->sec[i].namb == 0)
			continue;
		if ((olv_limp->nod_instal != -1) && (olv_limp->plan[i].ninsta > 0))
		{
			tt = olv_limp->plan[i].planif_insta[0].m[OLV_DESP];
			tt += olv_limp->plan[i].planif_insta[olv_limp->plan[i].ninsta - 1].m[OLV_DESP];
		}
		else
			tt = 0;
		//para guardar en número
		((double*)info)[isec_novac] = tt;

		isec_novac++;
	}
	if (!dbfmgr.AddCol(NULL, "M_INSTA", GdataTable::Tdouble, &dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info, 0, nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de duración de los descansos
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=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(NULL,"T_DESCAN",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
	
	//rellena la info de longitud de la ruta
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=olv_limp->plan[i].m[OLV_DESP]+olv_limp->plan[i].m[OLV_TTO];		
		//para guardar en número
		((double*)info)[isec_novac] = tt;		
		
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"M_RUTA",GdataTable::Tdouble,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena primero T DESP, M DESP, VELO DESP, T TRAT, M TRAT, VELO/T TRAT
	int p;
	int tipodato, sz;
	tipodato = GdataTable::Tstring;
	sz = OLV_SHP_SZ_CAMP_CHAR;
	for(int k=0;k<= OLV_TTO;k++)
	{	
		for(p=0;p<3;p++)
		{
			tt = 0;
			sz = 0;
			isec_novac=0;
			if(p==0) //T
			{
				tipodato = GdataTable::Tstring;
				sz = OLV_SHP_SZ_CAMP_CHAR;

				strcpy_s(nombia,"T_");

				//rellena la info de h
				for(i=0;i<olv_limp->nsec;i++)
				{
					if(olv_limp->sec[i].namb==0)
						continue;
					tt=olv_limp->plan[i].t[k];
					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++;
				}
			}
			else if(p==1) //M/M2/UDS
			{
				sz = 0;
				
				if ((k == OLV_TTO) && (olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h || olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h_eje))
				{
					strcpy_s(nombia, "M2_");
					for (i = 0; i < olv_limp->nsec; i++)
					{
						if (olv_limp->sec[i].namb == 0)
							continue;
						tt = olv_limp->plan[i].m[OLV_TTO_2];
						//para guardar en número
						((double*)info)[isec_novac] = tt;
						tipodato = GdataTable::Tdouble;
						isec_novac++;

					}
				}					
				else if ((k == OLV_TTO) && (olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoMin))
				{
					strcpy_s(nombia, "UDS_");
					for (i = 0; i < olv_limp->nsec; i++)
					{
						if (olv_limp->sec[i].namb == 0)
							continue;
						tt = olv_limp->sec[i].namb;
						//para guardar en número
						((int*)info)[isec_novac] = tt;
						tipodato = GdataTable::Tint;
						isec_novac++;
					}
				}
				else
				{					
					strcpy_s(nombia, "M_");
					for (i = 0; i < olv_limp->nsec; i++)
					{
						if (olv_limp->sec[i].namb == 0)
							continue;
						tt = olv_limp->plan[i].m[k];
						//para guardar en número
						((double*)info)[isec_novac] = tt;
						tipodato = GdataTable::Tdouble;
						isec_novac++;

					}
				}				
					
			}
			else if(p==2) //VELO
			{
				if(k==OLV_TTO)
				{
					tt=olv_limp->t_tto;
					if(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoM2h || olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoM2h_eje)
						strcpy_s(nombia,"M2_H_");
					else if(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMh || olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMh_eje)
						strcpy_s(nombia,"M_H_");
					else if(olv_limp->uds_tto==OliviaDef::GeneralDef::OlvTipTtoMin)
					{
						strcpy_s(nombia,"MIN_");
						tt=tt/60;//para pasarlo a minutos
					}

				}
				else
				{
					strcpy_s(nombia,"KM_H_");
					tt=olv_limp->v_despl* OLV_MS2KMH;
				}
				for(i=0;i<olv_limp->nsec;i++)
				{	
					if(olv_limp->sec[i].namb==0)
						continue;
					
					if (!tt)
					{
						tipodato = GdataTable::Tstring;
						sz = OLV_SHP_SZ_CAMP_CHAR;
						sprintf_s(&info[isec_novac * OLV_SHP_SZ_CAMP_CHAR], OLV_SHP_SZ_CAMP_CHAR, "Def. Vias");
					}
					else
					{
						//sprintf_s(&info[isec_novac * OLV_SHP_SZ_CAMP_CHAR], OLV_SHP_SZ_CAMP_CHAR, "%.1f", tt);
						((double*)info)[isec_novac] = tt;
						tipodato = GdataTable::Tdouble;
						sz = 0;
					}

					isec_novac++;
				}
			}
			if(k==OLV_TTO)
			{
				strcat_s(nombia,"TRAT");
			}
			else if(k==OLV_DESP)
			{
				strcat_s(nombia,"DESP");
			}			

			if(!dbfmgr.AddCol(NULL,nombia,tipodato,&dataDbf,sz))
			{
				free(info);
				return FALSE;
			}
			memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
		}
	}	

	free(info);

	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Añade las columnas de información a los puntos de control
 */
BOOL Colv_limp_thr::guarda_cols_ctrl(char *path_shp)
{
	char path_dbf[MAX_PATH];
	int h,m,s,k;
	double tt;
	char *info;
	int nsec, i, isec_novac;
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	//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++;
	}

	//añade una columna a los puntos de control de secuencia
	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_limp->npts_ctrl* OLV_SHP_SZ_CAMP_SZ);
	if(!info)
	{
		return FALSE;
	}
	memset(info,0,nsec*olv_limp->npts_ctrl* OLV_SHP_SZ_CAMP_SZ);
	AddColsDbf dataDbf(info);
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//rellena el nombre del tto
	k=0;
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;

		sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,olv_limp->nomb_tto);
		k++;
		for(k;k<(isec_novac+1)*olv_limp->npts_ctrl-1;k++)		
			sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,olv_limp->nomb_tto);
		sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,olv_limp->nomb_tto);
		isec_novac++;
		k++;
	}
	if(!dbfmgr.AddCol(NULL,"TTO",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec*olv_limp->npts_ctrl* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info
	k=0;
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"Inicio");
		k++;
		for(k;k<(isec_novac+1)*olv_limp->npts_ctrl-1;k++)		
			sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"Medio");
		sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"Fin");
		isec_novac++;
		k++;
	}
	if(!dbfmgr.AddCol(NULL,"SECUENCIA",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec*olv_limp->npts_ctrl* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de tiempo
	k=0;
	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].t_despl[0];
		dame_h_m_s(tt, &h, &m, &s);
		sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		k++;
		for(k;k<(isec_novac+1)*olv_limp->npts_ctrl-1;k++)		
		{
			tt= olv_limp->plan[i].pts_ctrl[k-(isec_novac*olv_limp->npts_ctrl+1)].cost;				
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		}
		tt= olv_limp->plan[i].pts_ctrl[olv_limp->npts_ctrl-2].cost;
		dame_h_m_s(tt, &h, &m, &s);
		sprintf_s(&info[k*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);	
		k++;
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"HORA",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}

	free(info);
	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Añade las columnas de información a las rutas de viajes a la instalación
 */
BOOL Colv_limp_thr::guarda_cols_insta(char *path_shp)
{
	char path_dbf[MAX_PATH];
	char *info;
	double tt,ttt;
	int h,m,s,insta,i,ninsta,ninsta_parc,ninsta_novac;
	char tray[OLV_SHP_SZ_CAMP_CHAR];
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	//añade una columna
	strcpy_s(path_dbf,MAX_PATH,path_shp);
	//cambiaext(path_dbf,".shp",".dbf");
	char bufAux[256];
	strcpy(path_dbf, Cdir_manager::cambia_extension_archivo(path_dbf,bufAux,".dbf"));
	//cuenta el número de instalaciones
	ninsta=0;
	for(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++;
		}
	}

	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);
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//rellena el nombre del tto
	ninsta_parc=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		ttt=0;
		ninsta_novac=0;
		for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
		{
			if(olv_limp->plan[i].planif_insta[insta].nelem==0)
				continue;

			sprintf_s(&info[(insta+ninsta_parc)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%s",olv_limp->nomb_tto);
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"TTO",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de tipo de trayecto
	ninsta_parc=0;
	for(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;
			
			switch(olv_limp->plan[i].planif_insta[insta].ninsta)
			{
			case OLV_IDA_INST:
				strcpy_s(tray,"Ida desde instalacion"); //quitado acento para evitar que salga mal
				break;
			case OLV_VUELTA_INST:
				strcpy_s(tray,"Vuelta a instalacion");
				break;
			case OLV_IDA_PLANT_ULT:
				strcpy_s(tray,"Ultima ida a descargar");
				break;
			case OLV_IDA_PLANT:
				strcpy_s(tray,"Ida a descargar");
				break;
			case OLV_VUELTA_PLANT:
				strcpy_s(tray,"Vuelta de descargar");
				break;
			}
			sprintf_s(&info[(insta+ninsta_parc)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%s",tray);
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"TRAYECTO",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de tipo de hora
	ninsta_parc=0;
	for(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;

			switch(olv_limp->plan[i].planif_insta[insta].ninsta)
			{
			case OLV_IDA_INST:
				tt=olv_limp->t_ini;
				break;
			case OLV_VUELTA_INST:
				tt=olv_limp->t_ini+olv_limp->sec[i].cost_ac-olv_limp->sec[i].t_despl[1]+olv_limp->t_desc;
				olv_limp->plan[i].planif_insta[insta].t[OLV_TTO]=tt;
				break;
			case OLV_IDA_PLANT:
			case OLV_IDA_PLANT_ULT:
				tt=olv_limp->plan[i].planif_insta[insta].t[OLV_TTO];
				break;
			case OLV_VUELTA_PLANT:
				tt=olv_limp->plan[i].planif_insta[insta].t[OLV_TTO];
				break;
			}
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[(insta+ninsta_parc)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"H_INI",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de duración
	ninsta_parc=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		ttt=0;
		ninsta_novac=0;
		for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
		{
			if(olv_limp->plan[i].planif_insta[insta].nelem==0)
				continue;

			tt=olv_limp->plan[i].planif_insta[insta].elem[olv_limp->plan[i].planif_insta[insta].nelem-1].coste;
			if((olv_limp->plan[i].planif_insta[insta].ninsta== OLV_IDA_INST) || (olv_limp->plan[i].planif_insta[insta].ninsta == OLV_VUELTA_INST)
				|| (olv_limp->plan[i].planif_insta[insta].ninsta == OLV_IDA_PLANT && (insta< olv_limp->plan[i].ninsta-1) && olv_limp->plan[i].planif_insta[insta+1].nelem==0))
				tt+= olv_limp->t_sal;			
			ttt+=tt;
			dame_h_m_s(tt, &h, &m, &s);
			sprintf_s(&info[(insta+ninsta_parc)*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"T_TOTAL",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de longitud
	ninsta_parc=0;
	for(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;

			tt=olv_limp->plan[i].planif_insta[insta].m[OLV_DESP];
			((double*)info)[insta + ninsta_parc] = tt;
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"M_TOTAL",GdataTable::Tdouble,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	free(info);

	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Recorre la ruta y genera un listado en csv donde guarda las calles por las que va pasando la ruta
 * El archivo se llama como el shape, concatenando el número de sector y L, en formato csv
 */
BOOL Colv_limp_thr::genera_list_rut_ctrl()
{	
	Info_planif *pp;
	Colv_csv cc;
	char tto_desp[32],observ[32],calle[1024],path_csv[MAX_PATH],fila[256],fila0[256];
	int i,j,h,m,seg,ii,dt;
	double ltot,ltot0,tt,t0,linst[2];
	BOOL mal;

	double lttt;
		
	linst[0] = linst[1] = 0;

	mal=FALSE;
	strcpy_s(path_csv,MAX_PATH,olv_limp->olv->paths.path_data);
	//cambiaext(path_csv,".shp","_L.csv");
	strcpy((Cdir_manager::extension_archivo(path_csv)-1),"_L.csv");
	////////////
	if(!cc.inicia(path_csv))
	{
		sprintf_s(err_str, "Error al iniciar archivo %s",path_csv);
		return FALSE;
	}
	//Inicia el archivo csv donde va a guardar las calles del itinerario
	if (olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h || olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h_eje)
		sprintf_s(fila0, 256, "Ruta; Secuencia; Calle; Observaciones; Tratamiento / Desplazamiento; Longitud(m); Tiempo acumulado(h); Tratamiento(m2);\r\n");
	else
		sprintf_s(fila0, 256, "Ruta; Secuencia; Calle; Observaciones; Tratamiento / Desplazamiento; Longitud(m); Tiempo acumulado(h); \r\n");

	if(!cc.escribe(fila0))
		mal=TRUE;

	olvlog(LOG_TODO,"olv_limp_t","Escribiendo listados de las rutas en csv");

	//graba los listados de la ruta de los sectores
	for(int s=0; s<olv_limp->nsec && !mal;s++)
	{			
		lttt=0;
		ltot0=0;
		pp=&olv_limp->plan[s];
		if(pp->nelem==0)
			continue;
		ii=1;
		i=0;
		t0=olv_limp->t_ini + olv_limp->sec[s].t_despl[0];

		if ((olv_limp->nod_instal != -1) && (pp->ninsta>0))
		{
			linst[0] = pp->planif_insta[0].m[OLV_DESP];
			linst[1] = pp->planif_insta[pp->ninsta-1].m[OLV_DESP];
			pp->planif_insta[0].t[OLV_TTO] = olv_limp->t_ini + olv_limp->t_sal;
			pp->planif_insta[pp->ninsta - 1].t[OLV_TTO] = olv_limp->t_ini + olv_limp->sec[s].cost_ac + olv_limp->t_desc - olv_limp->sec[s].t_despl[1];
		}

		//////////////////////////////////////////////
		//primer punto de control e instalación
		if(i==0)
		{
			dame_h_m_s(olv_limp->t_ini, &h, &m, &seg);
			sprintf_s(fila0, 256, "%02d;%04d;%s;%s;%s;%s;%02d:%02d:%02d;\r\n", s + 1, ii, "", "", "Inicio", "", h, m, seg);
			if (!cc.escribe(fila0))
			{
				mal = TRUE;
				continue;;
			}

			if (linst[0] != 0)
			{
				dame_h_m_s(olv_limp->t_ini + olv_limp->t_sal, &h, &m, &seg);
				sprintf_s(fila0, 256, "%02d;%04d;%s;%s;%s;%.1f;%02d:%02d:%02d;\r\n", s + 1, ii, "", "", "Ida desde instalaciÃ³n", linst[0], h, m, seg);
				if (!cc.escribe(fila0))
				{
					mal = TRUE;
					continue;;
				}
			}
			dame_h_m_s(t0, &h, &m, &seg);
			sprintf_s(fila0,256,"%02d;%04d;%s;%s;%s;%s;%02d:%02d:%02d;\r\n",s+1,ii,"","","Control - Inicio","",h,m,seg);
			if(!cc.escribe(fila0))
			{
				mal=TRUE;
				continue;;
			}
		}
		//////////////////////////////////////////////

		for(i=0;i<pp->nelem;i++)
		{
			if(pp->elem[i].tp==OLV_PLAN_TIP_SEG_LIN)
				goto ctrl;

			if((pp->elem[i].ltot ==0) && (i>1) && (pp->elem[i].coste==pp->elem[i-1].coste))
				continue;

			if(i<(pp->nelem-1))
			{
				if(((pp->elem[i].ref_nw == pp->elem[i+1].ref_nw) || 
					(((olv_limp->iaso[pp->elem[i].ref_nw].flgs & OLV_LIMP_FLG_NW) && (olv_limp->iaso[pp->elem[i+1].ref_nw].flgs & OLV_LIMP_FLG_NW))&& 
					(strcmp(olv_limp->iaso[pp->elem[i].ref_nw].inf_n.nomb,olv_limp->iaso[pp->elem[i+1].ref_nw].inf_n.nomb)==0)))
					&& (pp->elem[i].tp == pp->elem[i+1].tp) )
				{
					ltot0+=pp->elem[i].ltot;
					lttt+=pp->elem[i].ltot;
					goto ctrl;
				}
			}
					
			strcpy_s(observ,32,"");
			strcpy_s(tto_desp,32,"");
			switch(pp->elem[i].tp)
			{
			case OLV_PLAN_TIP_NW:
				strcpy_s(tto_desp,32,"Desplazamiento");
				dt=OLV_DESP;
				break;
			case OLV_PLAN_TIP_AMB_PEAT_DESP:
				strcpy_s(tto_desp,32,"Despl. por peatonal");
				dt=OLV_DESP;
				break;			
			case OLV_PLAN_TIP_AMB_PEAT:
				strcpy_s(observ,32,"Peatonal");//pasa al siguiente para poner tto también
				case OLV_PLAN_TIP_AMB:
			case OLV_PLAN_TIP_SEG_PUN:
				strcpy_s(tto_desp,32,"Tratamiento");
				dt=OLV_TTO;
				break;
			case OLV_PLAN_TIP_SEG_LIN:
				goto ctrl;
			}

			if(pp->elem[i].ref_nw>0 && (olv_limp->iaso[pp->elem[i].ref_nw].flgs & OLV_LIMP_FLG_NW) && 
				olv_limp->iaso[pp->elem[i].ref_nw].inf_n.nomb)
				strcpy_s(calle,1024,olv_limp->iaso[pp->elem[i].ref_nw].inf_n.nomb);
			else if((pp->elem[i].ref_nw>0) && (!(olv_limp->iaso[pp->elem[i].ref_nw].flgs & OLV_LIMP_FLG_NW)) && 
				(pp->elem[i].tp == OLV_PLAN_TIP_AMB_PEAT))
				strcpy_s(calle,1024,"Parque---");
			else
				calle[0]=0;

			tt=pp->elem[i].coste+t0; //a todos los costes de la ruta se añade el tiempo de desplazamiento
			ltot=ltot0+pp->elem[i].ltot;	
			ltot0=0;
			lttt+=pp->elem[i].ltot;

			//////////////////////////////////////////////
			//mira si tiene que poner observaciones por si fuera contendor
			if(((olv_limp->iaso[pp->elem[i].refe].flgs & OLV_LIMP_FLG_SEG_PUN)) &&  (pp->elem[i].tp==OLV_PLAN_TIP_AMB))
				dame_observ_cont(pp->elem[i].refe, observ);		
			//////////////////////////////////////////////

			dame_h_m_s(tt, &h, &m, &seg);
			if((olv_limp->tipo_ambit==OLV_AMB_PUN) && (pp->elem[i].tp==OLV_PLAN_TIP_AMB))
				sprintf_s(fila,256,"%02d;%04d;%s;%s;%s;%s;%02d:%02d:%02d;\r\n",s+1,ii,calle,observ,tto_desp,"",h,m,seg);
			else if(((pp->elem[i].tp == OLV_PLAN_TIP_AMB) || (pp->elem[i].tp == OLV_PLAN_TIP_AMB_PEAT)) && 
				(olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h || olv_limp->uds_tto == OliviaDef::GeneralDef::OlvTipTtoM2h_eje))
				sprintf_s(fila,256,"%02d;%04d;%s;%s;%s;%.1f;%02d:%02d:%02d;%.1f;\r\n",s+1,ii,calle,observ,tto_desp,ltot,h,m,seg,ltot* olv_limp->iaso[pp->elem[i].refe].inf_l.ancho);
			else
				sprintf_s(fila, 256, "%02d;%04d;%s;%s;%s;%.1f;%02d:%02d:%02d;\r\n", s + 1, ii, calle, observ, tto_desp, ltot, h, m, seg);
						
			//////////////////////////////////////////////
			//escribe fila de paso
			if(!cc.escribe(fila))
			{
				mal=TRUE;
				continue;
			}
		
ctrl:
			//////////////////////////////////////////////
			//puntos de control intermedios
			for(j=0;j<olv_limp->npts_ctrl-2 && !mal;j++)
			{
				if(pp->pts_ctrl[j].ipt==i)
				{				
					t0+=olv_limp->t_desc/(olv_limp->npts_ctrl-2);
					tt+=olv_limp->t_desc/(olv_limp->npts_ctrl-2);
					pp->pts_ctrl[j].cost = tt;
					dame_h_m_s(tt, &h, &m, &seg);
					sprintf_s(fila0,256,"%02d;%04d;%s;%s;%s;%s;%02d:%02d:%02d;\r\n",s+1,ii,"","","Control - Medio","",h,m,seg);
					if(!cc.escribe(fila0))
					{
						mal=TRUE;
						continue;
					}
				}
			}
			//////////////////////////////////////////////
			//viajes a vaciar intermedios
			if((olv_limp->iaso[pp->elem[i].refe].flgs & OLV_LIMP_FLG_SEG_PUN)&&  (pp->elem[i].tp==OLV_PLAN_TIP_AMB))
			{			
				if(!genera_list_fila_vaci(&cc, fila0,pp->elem[i].refe, s,ii,tt, &t0,FALSE))
				{
					mal=TRUE;
					break;
				}			
			}
			//////////////////////////////////////////////
			
			ii++;
		}
		//////////////////////////////////////////////
		//último punto de control e instalación
		if((i==(pp->nelem))&& !mal)
		{		
			//quita_t_ult_desc(s,&tt);
			dame_h_m_s(tt, &h, &m, &seg);
			sprintf_s(fila0,256,"%02d;%04d;%s;%s;%s;%s;%02d:%02d:%02d;\r\n",s+1,ii,calle,"","Control - Fin","",h,m,seg);
			if(!cc.escribe(fila0))
			{
				mal=TRUE;
				continue;
			}
			pp->pts_ctrl[olv_limp->npts_ctrl-2].cost = tt;

			//////////////////////////////////////////////
			//último viaje a vaciar
			if(olv_limp->iaso[pp->elem[i-1].refe].flgs & OLV_LIMP_FLG_SEG_PUN)
			{
				if(!genera_list_fila_vaci(&cc, fila0,pp->elem[i-1].refe, s,ii,tt, &t0,TRUE))
				{
					mal=TRUE;
					break;
				}
				tt = t0;
			}

			//final
			//////////////////////////////////////////////				
			if (linst[1] != 0)
			{
				dame_h_m_s(tt, &h, &m, &seg);
				sprintf_s(fila0, 256, "%02d;%04d;%s;%s;%s;%.1f;%02d:%02d:%02d;\r\n", s + 1, ii, "", "", "Vuelta a instalaciÃ³n", linst[1], h, m, seg);
				if (!cc.escribe(fila0))
				{
					mal = TRUE;
					continue;
				}
			}
			tt = olv_limp->t_ini + olv_limp->sec[s].cost_ac + olv_limp->t_desc;			
			//////////////////////////////////////////////			
			dame_h_m_s(tt, &h, &m, &seg);
			sprintf_s(fila0, 256, "%02d;%04d;%s;%s;%s;%s;%02d:%02d:%02d;\r\n", s + 1, ii, "", "", "Fin", "", h, m, seg);			
			if(!cc.escribe(fila0))
			{
				mal=TRUE;
				continue;
			}
		}
		
	}
	
	cc.cierra();

	if(mal)
	{
		sprintf_s(err_str, "Error al escribir fila en archivo %s",path_csv);
		return FALSE;
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Quita al tiempo total el del último desplazamiento y la última descarga, solo para reco
 */
void Colv_limp_thr::quita_t_ult_desc(int s, double *t)
{

}
//*************************************************************************************
/**
 * Añade una línea al listado csv con el viaje a vaciar y vuelta
 */
void Colv_limp_thr::dame_h_m_s(double tt, int *h_, int *m_, int *s_)
{
	int h,m,s;

	h=(int)(tt/3600);
	m=(int)((tt-h*3600)/60);
	s=(int)(tt-m*60-h*3600);
	h=h%24;

	*h_=h;
	*m_=m;
	*s_=s;
}
//*************************************************************************************
/**
 * Añade una línea al listado csv con el viaje a vaciar y vuelta
 */
BOOL Colv_limp_thr::genera_list_fila_vaci(Colv_csv *cc, char *fila0,int ielem, int s, int ii, double tt, double *t0,BOOL is_fin)
{
	return TRUE;
}
//*************************************************************************************
/**
 * Añade una columna de observación al listado si es contenedores
 */
void Colv_limp_thr::dame_observ_cont(int iamb,char *observ)
{
}
//*************************************************************************************
/**
 * Modifica el dbf del shp original para poner la sectorización, 
 * que es el mismo que de entrada con una columna más, 
 * SECTOR (modo 0) o SECUENCIA VACÍA (modo 1) o SECUENCIA BUENA (modo 2) o TRAMO al que pertenece (modo 3)
 */
BOOL Colv_limp_thr::guarda_dbf_sector(int modo)
{
	char path_dbf[MAX_PATH];
	char nom_ia[16];

	class AddColS : public IAddColDbf
	{
	public:
		Colv_limp *olv_limp;
		int mod; 
		int dt;
		AddColS(Colv_limp *ll, int mod)
		{
			this->olv_limp=ll;
			this->mod=mod;			
		}
		virtual void setData(int i, void *data)
		{
			if(data)
			{
				switch(mod)
				{
				case 0://sector
					dt= olv_limp->sec[olv_limp->amb_sec[i].sec].sec_def;
					break;
				case 1://secuencia vacía
					dt=0;
					break;
				case 2://secuencia buena
					dt=olv_limp->amb_sec[i].iseq+1;
					break;
				case 3:
					dt=olv_limp->amb_sec[i].res+1;
					break;
				}				
				memcpy(data,(void*)&dt,sizeof(int));
			}

		};
	};
	AddColS dataDbf(olv_limp,modo);
	ManagerDbfGdataTable dbfmgr;

	//primero graba los archivos de la ruta de los sectores
	//graba todos los sectores en un único path
	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");
	//pone el nombre de la columna
	if(modo==0)//sector
		strcpy_s(nom_ia,16,"SECTOR");
	else if((modo==1)|| (modo==2))//secuencia
		strcpy_s(nom_ia,16,"SECUENCIA");
	else if(modo==3)
		strcpy_s(nom_ia,16,"VIAJE");

	if(!dbfmgr.AddCol(path_dbf,nom_ia,GdataTable::Tint,&dataDbf))
	{
		return FALSE;
	}

	return TRUE;
}
//*************************************************************************************
/**
 * Planifica o calcula el orden en el que hay que recorrer los ambitos del sector s
 * la idea es partir de una solucion factible (la cual se consigue por distancias minimas)
 * una vez que se tenga se realizan pequeños cambios en dicho orden para ver si mejora, si es asi se deja dicho cambio como permanente
 * si no se quita y se intenta otro cambio
 */
Secu_amb * Colv_limp_thr::planifica_sect(Info_sec *s, Djkt_ang_ady *ang_conj, int npermu)
{
	int i,k, j,  nsec;
	BOOL res=FALSE;
	BOOL camb;
	th_param_planif thp;
	int nth=Colv_geom::dame_n_nucleos();
	int obset=0;
	double ca, cold;
	Secu_amb *sec;
	BOOL nocalc=FALSE;

	sec=(Secu_amb*)malloc(s->namb*sizeof(Secu_amb));
	if(!sec)
		goto sal;
	memset(sec,0,s->namb*sizeof(Secu_amb));

	//prepara arrays----------------------
	memset(&thp,0,sizeof(thp));	

	//copia la info del sector

	for (i=0; i<s->namb && !pirate; i++)
	{
		for(k=0;k<2;k++)
		{
			sec[i].ctnod[k]=NULL;
		}
	}
	if(pirate)
		goto sal;

	//consigue solucion factible------------------------------
	nsec=0;
	sec[nsec].iamb=dame_planif_iamb_ini(s,olv_limp->cost_amb,&sec[nsec].entrada );
	//sec[nsec].entrada=-1;
	sec[sec[nsec].iamb].flags=1;
	if(sec[nsec].iamb<0)
		goto sal;
	nsec++;
	while(nsec<s->namb)
	{
		if(!busca_cercano(s,sec, nsec-1, TRUE))//se pilla el minimo local
			break;
		nsec++;
	}
	
	if(nsec<s->namb)
		goto sal;
	//mejora solucion---------------------
	//prepara thread------------
	thp.dth=(th_data_planif*)malloc(sizeof(th_data_planif)*nth);
	thp.sec=sec;
	thp.tl=this;

	thp.namb=s->namb;
	thp.namb_t=s->namb;
	thp.s=s;
	thp.abs=TRUE;//cambio ger
	if(!thp.dth)
		goto sigue;
	thp.dth[0].sec=(Secu_amb *)malloc(s->namb*nth*sizeof(Secu_amb));
	if(!thp.dth[0].sec)
		goto sigue;
	for (i=1; i<nth; i++)
		thp.dth[i].sec=&thp.dth[0].sec[s->namb*i];
	//lanza--------------------
	for (i=0; i<nth; i++)
	{
		thp.id_th=i;
		thp.dth[i].activo=TRUE;
		lck_sum_atm(&thp.nth,1);
		AfxBeginThread(th_planificacion, (LPVOID)&thp, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
		while(thp.id_th>=0)
			Sleep(1);

	}
	ca=dame_coste(sec,0,s->namb-1,s,TRUE);
	do 
	{
		thp.modo=2;
		cold=ca;
		camb=FALSE;

		//bucle hasta recorrer todos los elementos de sec
		//movimientos de elementos puntuales (cambio de posicion)
		for (i=1; i<s->namb; i++)
		{
			thp.param[0]=i;
			thp.a_currar();
			//espera thread
			while(!thp.terminado())
				Sleep(thp.milis_sleep);
			//elije la mejor permuta
			j=thp.dame_min();
			
			if(j<0 || ca <=thp.dth[j].coste)
				continue;
			cambia_elem(sec, i, thp.dth[j].pos[0], thp.dth[j].pos[1]);
			ca=thp.dth[j].coste;
			
			cold=ca;
			camb=TRUE;
		}
		//permutaciones de npermu elementos
		/*thp.modo=1;
		cold=ca;
		//camb=FALSE;
		for (i=npermu+obset; i<s->namb; i++)
		{
			thp.param[0]=max(i-npermu, obset);
			thp.param[1]=i;
			thp.a_currar();
			while(!thp.terminado())
				Sleep(1);
			j=thp.dame_min();
			if(j<0 || ca <=thp.dth[j].coste || thp.dth[j].pos[0]<0)
				continue;
			ca =thp.dth[j].coste;
			memcpy(sec, thp.dth[j].sec, s->namb*sizeof(Secu_amb));
			olvlog(LOG_TODO,"olv_limp_t","Permu Mejora coste de %lf a %lf actu: %lf",
				 cold, ca, dame_coste(sec,0,s->namb-1,ias, s));
			cold=ca;
			camb=TRUE;
		}*/
	} while (camb);
	thp.milis_sleep=1;

	//fuera thread
	thp.pirate=TRUE;
	while(thp.nth>0)
		Sleep(1);
	
	//----------------------------------------------------------
sigue:
	if (thp.dth)
	{
		if(thp.dth[0].sec)
			free(thp.dth[0].sec);
		free(thp.dth);
	}


	pon_t_desp(s, sec);
	

	res=TRUE;
sal:
	if(!res)
	{
		if(sec)
			free(sec);
		sec=NULL;
	}
	
	return sec;
}
//*************************************************************************************
/** 
 * Rellena los tiempos de desplazamiento
 */
void Colv_limp_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[0].ctnod[0][olv_limp->iaso[olv_limp->carto.get(s->iamb[sec[s->namb-1].iamb]).entity()->ref].inod[(sec[s->namb-1].entrada+1)%2]].dis;
	}	
}
//*************************************************************************************
/** 
 * Rellena el siguiente nodo en la secuencia
 */
BOOL Colv_limp_thr::busca_cercano(Info_sec *s, Secu_amb *sec, int isec, BOOL ind_abs)
{
	double d=MAYUSCULO;
	int nam, nsal, nent;
	int k, kk, i, j;
	int ic, ind_cost;
	ic=sec[isec].entrada;
	if(isec==0)
		isec=isec;
	if(ic<0)
		kk=olv_limp->tipo_ambit;
	else
		kk=1;

	for (k=0; k<kk; k++)
	{
		ic=(ic+1)%2;
		for (i=0; i<s->namb; i++)
		{
			if(sec[i].flags &1)
				continue;///ya esta en la secuencia
			if (ind_abs)
				ind_cost=s->iamb[i];
			else
				ind_cost=i;
			for (j=0; j<olv_limp->tipo_ambit; j++)
			{				
				if(d>olv_limp->arch_dj.dame_dis(s->iamb[sec[isec].iamb],ic,s->iamb[i],j))
				{
					d=olv_limp->arch_dj.dame_dis(s->iamb[sec[isec].iamb],ic,s->iamb[i],j);
					nent=j;
					nsal=ic;
					nam=i;	
				}
						
			}
		}
	}
	if(d>=MAYUSCULO)
		return FALSE;

	sec[isec++].entrada=(nsal+1)%2;
	sec[isec].entrada=nent;	
	sec[isec].iamb=nam;
	sec[nam].flags=1;
	return TRUE;
}
//*************************************************************************************
/**
 * Da el ámbito inicial por el que empezar la planificación, en función del modo
 */
short Colv_limp_thr::dame_planif_iamb_ini(Info_sec *s, Matrix2d<float> &cost_amb, short *ent/*=NULL*/)
{
	int i,j,iaux,ient,nn, ref_i, ref_j,k;
	float aux, dist, dist1;
	int modo;
	double a, b,c,d,e;
	int KK=olv_limp->tipo_ambit;

	//cost_amb=olv_limp->cost_amb;
	iaux=-1;
	modo=3;
	////////////////////////////////////////////////////
	//Coge el ámbito por defecto que se le hubiera dado en la columna secuencia
	//Si no, busca el ámbito más cercano a la instalación, si la hubiera configurada,
	//Si no, coge el de mayor coste (modo 1)
	//O el de 'y+x' menor (modo 2)
	//O el más alejado del centro (modo 3)
	if(s->iamb_ini_def!=-1)
	{		
		ient=0;
		for(i=0;i<s->namb;i++)
		{
			if(s->iamb[i]==s->iamb_ini_def)
				break;
		}
		iaux=i;
		//busca el nodo más cercano a la instalación, si tiene 2 nodos y hay instalación
		if(olv_limp->tipo_ambit==OLV_AMB_LIN && olv_limp->nod_instal>=0)
		{
			//comprueba los dos nodos				
			dist=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0,s->iamb[iaux],ient);
			dist1=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0,s->iamb[iaux],1);
			if(dist1<dist)
			{
				ient=1;
			}
		}
		if(ent)
			*ent=ient;		
	}
	else if(olv_limp->nod_instal>=0)
	{
		aux=(float)MAYUSCULO;
		//se coge de punto inicial el más cercano a la instalación
		for(i=0;i<s->namb;i++)
		{
			ref_i=olv_limp->carto.get(s->iamb[i]).entity()->ref;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			//calcula la distancia de la instalación al inicio del ámbito
			ient=0;			
			dist=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0,s->iamb[i],ient);
			if(olv_limp->tipo_ambit==OLV_AMB_LIN)
			{
				//comprueba los dos nodos			
				
				dist1=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0,s->iamb[i],1);				
				
				if(dist1<dist)
				{
					dist=dist1;
					ient=1;
				}
			}
			
			//calcula la distancia de la instalación al final del ámbito, y se queda con la menor
			//en caso de los puntuales, va a ser igual
			
			//busca el menor
			if(dist<aux)
			{
				aux=dist;
				iaux=i;
				if(ent)
					*ent=ient;
			}
		}

	}
	else if(modo==1)
	{
		aux=(float)MINUSCULO;
		//se coge de punto inicial el de mayor coste
		for(i=0;i<s->namb;i++)
		{
			ref_i=olv_limp->carto.get(s->iamb[i]).entity()->ref;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			//calcula la distancia de mayor entre dos ámbitos
			for(j=0;j<s->namb;j++)
			{
				if(i==j)
					continue;

				ref_j=olv_limp->carto.get(s->iamb[j]).entity()->ref;
				if(olv_limp->iaso[ref_j].flgs & OLV_LIMP_FLG_AMB_NO)
					continue;

				dist=cost_amb[s->iamb[i]][s->iamb[j]];
				//busca el mayor
				if(dist>aux)
				{
					aux=dist;
					iaux=i;
				}
			}				
		}
	}
	else if(modo==2)
	{
		/////////////////////////////////////
		//////////////////////
		//Como primer ámbito coge el más extremo
		//el de menor 'y+x'
		aux=(float)MAYUSCULO;
		for(i=0;i<s->namb;i++)
		{
			ref_i=olv_limp->carto.get(s->iamb[i]).entity()->ref;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			if((olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[0]][1]+olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[0]][0])<aux)
			{
				aux=(float)(olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[0]][1]+
					olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[0]][0]);
				iaux=i;
			}
		}
	}
	else if(modo==3)
	{
		//////////////////////
		a=0;
		b=0;
		c=0;
		d=0;
		e=-1;
		nn=0;
		//Como primer ámbito coge el más alejado del centro
		//coge la x y la y media, el centro
		for(i=0;i<s->namb;i++)
		{
			ref_i=olv_limp->carto.get(s->iamb[i]).entity()->ref;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			for(k=0;k<KK;k++)
			{
				a+=olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[k]][1]/1000;//divide para que no haga overflow
				b+=olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[k]][0]/1000;
				nn++;
			}
		}
		a=a/nn;
		b=b/nn;
		//busca el más alejado de la x e y media
		for(i=0;i<s->namb;i++)
		{
			ref_i=olv_limp->carto.get(s->iamb[i]).entity()->ref;
			if(olv_limp->iaso[ref_i].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			for(k=0;k<KK;k++)
			{
				c=olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[k]][1]/1000-a;
				c=fabs(c);
				d=olv_limp->conjs.coor[olv_limp->iaso[ref_i].inod[k]][0]/1000-b;
				d=fabs(d);
				if((c+d)>e)
				{
					e=(c+d);
					iaux=i;
					if(ent)
						*ent=k;
				}
			}
		}
	}
	return (short)iaux;
}
//*************************************************************************************
/**
 * Permuta los elementos de sec en sec_out, desde el indice ini hasta fin aplicando la permutacion p-esima
 */
BOOL Colv_limp_thr::permuta(Secu_amb * sec, int ini, int fin, int p, Secu_amb * sec_out)
{
	int n=fin-ini-1;//numero de elementos a permutar
	int nn, i, j, k;
	
	nn=Colv_geom::fact(n);
	for (i=ini; i<fin; i++)
		sec_out[i].flags=0;
	for(i=ini; i<fin; i++)
	{
		k=p/nn;
		p-=k*nn;
		nn=nn/n;
		n=max(n-1,1);
		for (j=ini; j<fin; j++)
		{
			if (!sec_out[j].flags)
			{
				k--;
				if(k<0)
					break;
			}
		}
		if (k>=0)
			return FALSE;//Error al permutar
		sec_out[j].flags=1;
		sec_out[i].entrada=sec[j].entrada;
		sec_out[i].iamb=sec[j].iamb;
	}
	return TRUE;
	
}
//*************************************************************************************
/**
 * Cambia de lugar el elemento de la pos_old a la pos_new en la secuencia de elementos sec
 */
void Colv_limp_thr::cambia_elem( Secu_amb * sec,int pos_old, int pos_new, int entr )
{
	int i;
	Secu_amb s;
	s.entrada=entr;
	s.iamb=sec[pos_old].iamb;
	if(pos_old>pos_new)
	{
		for (i=pos_old; i>pos_new; i--)
		{
			sec[i].entrada=sec[i-1].entrada;
			sec[i].iamb=sec[i-1].iamb;
		}
	}
	else
	{
		for (i=pos_old; i<pos_new; i++)
		{
			sec[i].entrada=sec[i+1].entrada;
			sec[i].iamb=sec[i+1].iamb;
		}
	}
	sec[pos_new].entrada=s.entrada;
	sec[pos_new].iamb=s.iamb;
}
//*************************************************************************************
BOOL Colv_limp_thr::calcula_coste_1sec( Secu_amb * ord_sec, Info_sec *ss, th_param_planif *thp, BOOL loguear )
{
	int nsecuencia;
	int obset=0;
	int i, k;
	double ca, cold;
	BOOL permu=FALSE;
	BOOL camb;

	if(!thp)
		goto npermu;

	thp->sec=ord_sec;
	thp->tl=this;
	thp->abs=TRUE;

	if(!thp->dth[0].sec)
		thp->dth[0].sec=(Secu_amb *)malloc(thp->namb_t*thp->nth*sizeof(Secu_amb));
	if(!thp->dth[0].sec)
		goto npermu;
		
	for (i=1; i<thp->nth; i++)
	{
		thp->dth[i].sec=&thp->dth[0].sec[thp->namb_t*i];
	}
	
	permu=TRUE;
npermu:
	
	for (nsecuencia=0; nsecuencia<ss->namb; nsecuencia++)
		ord_sec[nsecuencia].flags =0;
		nsecuencia=0;
	
	if(ss->namb<=0)
	{
		ss->cost_ac=0;
		return TRUE;
	}
	//calcula ambito inicial------------
	ord_sec[nsecuencia].iamb=dame_planif_iamb_ini(ss,olv_limp->cost_amb, &ord_sec[nsecuencia].entrada);
	if(ord_sec[nsecuencia].iamb<0)
		return FALSE;
	ord_sec[ord_sec[nsecuencia].iamb].flags=1;
	nsecuencia++;
	while(nsecuencia<ss->namb)
	{
		if(!busca_cercano(ss,ord_sec, nsecuencia-1,TRUE))//se pilla el minimo local
			break;
		nsecuencia++;
	}
	if (nsecuencia>=ss->namb)
	{
		ss->cost_ac=(float)dame_coste(ord_sec, 0, ss->namb-1, ss, TRUE);
	}
	else
		return FALSE;
	
	//mira a ver si tiene que pertmutar o no. Si un sector tiene casi todos los ámbitos, no se permuta
	int namb_m, nsec;
	if(olv_limp->n_amb>=OLV_DESV_MAX_NAMB_MIN)
	{			
		if(olv_limp->calc_nsec)
		{
			if(olv_limp->nsec_act>1)
				namb_m = olv_limp->n_amb/(olv_limp->nsec_act-1);
			else
				namb_m= olv_limp->n_amb;
		}
		else
			namb_m= olv_limp->n_amb/olv_limp->nsec;
		namb_m+=(int)(namb_m*OLV_DESV_MAX_NAMB);
		nsec=olv_limp->nsec;
		if(olv_limp->calc_nsec>0)
			nsec--;
		for(int p=0;p<nsec;p++)
		{
			if(olv_limp->sec[p].namb>namb_m)
			{
				permu=FALSE;
				break;
			}
		}		
	}
	
	if(!permu)
		return TRUE;
	
	//mejora solucion---------------------
	//prepara thread------------
	thp->namb=ss->namb;
	thp->s=ss;
	ca=dame_coste(ord_sec, 0, ss->namb-1, ss, TRUE);
	if(loguear)
		olvlog(LOG_TODO,"olv_limp_t","coste de partida %lf",ca);
	do 
	{
		thp->modo=2;
		cold=ca;
		camb=FALSE;

		//bucle hasta recorrer todos los elementos de sec
		//movimientos de elementos puntuales (cambio de posicion)
		for (i=1; i<ss->namb; i++)
		{
			thp->param[0]=i;
			thp->a_currar();
			//espera thread
			while(!thp->terminado())
				Sleep(thp->milis_sleep);
			//elije la mejor permuta
			k=thp->dame_min();
			if(loguear && k>=0)
				olvlog(LOG_TODO,"olv_limp_t","Candidato cal_costes cambia %ld, a %ld, costes: %lf ",
				i, thp->dth[k].pos[0], thp->dth[k].coste);
			if(k<0 || ca <=thp->dth[k].coste)
				continue;
			
			cambia_elem(ord_sec, i, thp->dth[k].pos[0], thp->dth[k].pos[1]);
			ca=thp->dth[k].coste;
			if(loguear)
				olvlog(LOG_TODO,"olv_limp_t","Mejora coste cambia %ld, a %ld, costes: %lf a %lf",
					i, thp->dth[k].pos[0], cold, ca);
			cold=ca;
			camb=TRUE;
		}
		//permutaciones de npermu elementos
		/*thp.modo=1;
		cold=ca;
		//camb=FALSE;
		for (i=npermu+obset; i<s->namb; i++)
		{
			thp.param[0]=max(i-npermu, obset);
			thp.param[1]=i;
			thp.a_currar();
			while(!thp.terminado())
				Sleep(1);
			j=thp.dame_min();
			if(j<0 || ca <=thp.dth[j].coste || thp.dth[j].pos[0]<0)
				continue;
			ca =thp.dth[j].coste;
			memcpy(sec, thp.dth[j].sec, s->namb*sizeof(Secu_amb));
			olvlog(LOG_TODO,"olv_limp_t","Permu Mejora coste de %lf a %lf actu: %lf",
				 cold, ca, dame_coste(sec,0,s->namb-1,ias, s));
			cold=ca;
			camb=TRUE;
		}*/
	} while (camb && !pirate);

	pon_t_desp(ss, ord_sec);
		
	ss->cost_ac=(float)ca;
	if(loguear)
	{
		olvlog(LOG_TODO,"olv_limp_t","Coste %lf",ss->cost_ac);
		if(esta_repe(thp->sec, thp->namb, FALSE))
			olvlog(LOG_TODO,"olv_limp_t","Esta repe en calcula costes");
	}

	return TRUE;	
	
	//fuera thread
	/*if(permu)
	{
		thp->pirate=TRUE;
		while(thp->nth>0)
			Sleep(1);
	}*/
}
//*************************************************************************************
/**
 * Calcula el coste de los sectores mediante planificación de sus ámbitos
 */
BOOL Colv_limp_thr::calcula_coste_sectores( Secu_amb * ord_sec,Info_sec *ss,int n_sec, th_param_planif *thp, BOOL loguear )
{
	int obset=0;
	int i;
	BOOL res=FALSE;
	int j;

	if(!thp)
		goto npermu;
	
	thp->sec=ord_sec;
	thp->tl=this;
	thp->abs=TRUE;
	thp->milis_sleep=0;
	
	if(!thp->dth[0].sec)
		thp->dth[0].sec=(Secu_amb *)malloc(thp->namb_t*thp->nth*sizeof(Secu_amb));
	if(!thp->dth[0].sec)
		goto npermu;
		
	for (i=1; i<thp->nth; i++)
	{
		thp->dth[i].sec=&thp->dth[0].sec[thp->namb_t*i];
	}
	
npermu:

	for (j=0; j<n_sec; j++)
	{
		if(loguear)
		{
			olvlog(LOG_TODO,"olv_limp_t","Calcula costes Sector %ld----------------------------------", j);
		}
		if(!calcula_coste_1sec( ord_sec, &ss[j], thp, loguear ))
			break;
		if(loguear)
		{
			olvlog(LOG_TODO,"olv_limp_t","Ruta Sector %ld----------------------------------", j);
			for (int i=0; i<ss[j].namb; i++)
			{
				olvlog(LOG_TODO,"olv_limp_t","pos %ld, ida %ld, ent:%ld",i,ss[j].iamb[ord_sec[i].iamb], ord_sec[i].entrada);
			}
			olvlog(LOG_TODO,"olv_limp_t","Fin Ruta Sector %ld----------------------------------", j);
		}
	}
	if(j>=n_sec)
		res=TRUE;


	thp->milis_sleep=1;

	return res;
}
//*************************************************************************************
/**
 * Comprueba si hay elementos repetidos en las permutaciones
 */
BOOL Colv_limp_thr::esta_repe( Secu_amb *sec, int nsec, BOOL log )
{
	BOOL res=FALSE;
	int i;
	for (i=0; i<nsec; i++)
		sec[i].flags=-1;
	for (i=0; i<nsec; i++)
	{
		if(log)
		{
			olvlog(LOG_TODO,"olv_limp_t","secu: %ld, amb: %ld",i,sec[i].iamb);

		}
		if(sec[sec[i].iamb].flags>=0)
		{
			olvlog(LOG_TODO,"olv_limp_t","Esta repe la secuencia %ld, en posiciones %ld, %ld ",sec[i].iamb, i, sec[sec[i].iamb].flags);
			res=TRUE;
		}
		sec[sec[i].iamb].flags=i;
	}
	return res;
}
//*************************************************************************************
/**
 * Escribe la info resultado de la planificación
 */
void Colv_limp_thr::pon_info_resul()
{
	char msg_[OLV_MAX_MSG_PROCE];
	char msg_aux[64];
	int i,h,m,s;
	double tt;
	int nsec=0;

	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb!=0)
			nsec++;
	}

	if(olv_limp->olv->modo_ejec==OLV_EJEC_SECT)
	{
		//si se ha ejecutado en modo cálculo de sectorización
		if(olv_limp->calc_nsec>0)
		{
			//se ha pedido proponer número de sectores óptimo
			sprintf_s(msg_,OLV_MAX_MSG_PROCE,
				"Se ha calculado la sectorización para el número de sectores óptimo\ndada la conf. elegida, que es de %ld, de tiempos:\n",
				nsec);
		}
		else
		{
			//se ha impuesto el número de sectores
			sprintf_s(msg_,OLV_MAX_MSG_PROCE,"Se ha calculado la sectorización para %ld sectores, de tiempos:\n",
				nsec);
		}
	}
	else if(olv_limp->olv->modo_ejec==OLV_EJEC_PLAN)
	{
		sprintf_s(msg_,OLV_MAX_MSG_PROCE,"Se ha calculado la planificación para %ld sectores, de tiempos:\n",
			nsec);
	}
	else if(olv_limp->olv->modo_ejec==OLV_EJEC_TODO)
	{
		sprintf_s(msg_,OLV_MAX_MSG_PROCE,"Resultados de todo el proceso para %ld sectores, de tiempos:\n",
			nsec);
	}
	else
		msg_[0]=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=olv_limp->sec[i].cost_ac+olv_limp->t_desc;
		dame_h_m_s(tt, &h, &m, &s);
		sprintf_s(msg_aux,64,"Sector %ld: %02d:%02d:%02d h, %03d elementos\n",i+1,h,m,s,olv_limp->sec[i].namb);
		strcat_s(msg_,OLV_MAX_MSG_PROCE,msg_aux);
	}
	pon_mi_msg(msg_);
	pon_mi_progre(tarea,100);
}
//*************************************************************************************
/*
 * Lanza los multi procesos para el cálculo de cost_amb
 */
BOOL Colv_limp_thr::lanza_tasks(int nthr_def/*=-1*/)
{	
	int nn;
	char comline[256];
	char app_path[MAX_PATH];
	char app_path_aux[MAX_PATH];
	BOOL ret=TRUE;

	if(nthr_def>0)
		nn=nthr_def;
	else
		nn=n_subthr;

	comline[0]=0;
	app_path[0]=0;
	app_path_aux[0]=0;

	olv_limp->olv_tasks->get_dll_dir(app_path_aux);
	if(!app_path_aux[0])
		return FALSE;

	char *pch=strrchr(app_path_aux,'\\');
	if(!pch)
		return FALSE;

	*pch=0;

	sprintf(app_path,"%s\\%s\\%s",app_path_aux,TASKS_FOLDER_NAME,TASKS_APP_NAME);

	//Arranca los tasks
	for(int i=0;i<nn && ret;i++)
	{
		//lanza el ejecutable y le manda como comandos la tarea y el task que es
		sprintf_s(comline, "%s %s %ld %ld", 
			"params",
		olv_limp->olv->olv_sock->ip,
			TASKS_PORT,
			i);

		if(!olv_limp->olv_tasks->lanza_app(app_path, comline))
			ret=FALSE;
	}

	for(int i=nthr_def;i<n_subthr;i++)
		subthrs[i]->prog_subthr = 0;

	for(int i=0;i<n_subthr-nthr_def;i++)
		encola(OLV_LIMP_EV_TASK_FIN,NULL,FALSE); //fuerza fin para que avance olivia
	
	return ret;
}
//*************************************************************************************
/*
 * Guarda a disco la matriz de dist entre conjunciones y de ángulos
 */
BOOL Colv_limp_thr::guarda_mats()
{
	pon_mi_progre(OLV_TAREA_GUARD_MAT, 0);
	olv_limp->olv_tasks->inidirs(olv_limp->olv->paths.path_temp);	

	olvlog(LOG_TODO,"olv_limp_t","Guardando matrices");

	//lanza los threads
	lanza_subthrs(OLV_LIMP_EV_GUARD_MATS_SUB);

	return TRUE;
}
//*************************************************************************************
/*
 * Cada thread de los que guardan a disco la matriz de dist entre conjunciones y de ángulos
 */
void Colv_limp_thr::guarda_mats_sub(int ithr)
{
	int nconj,ic;
	int n_ini, n_desp, n_fin, seg;
	BOOL mal=FALSE;
	Param_olv_limp_thr pp;
	HeadCostConj hd;
	HeadCostAng hda;
	
	////////////////
	pp.id_e=OLV_TAREA_GUARD_MAT;//manda de parámetro la tarea de la que es el progreso
	nconj=olv_limp->conjs.n;
	//las conjunciones que va a hacer
	n_desp = (int)ceil(1.0*nconj/n_subthr);	
	n_ini=ithr*n_desp;
	n_fin = min((ithr+1)*n_desp,nconj);	

	memset(&hd,0,sizeof(HeadCostConj));
	memset(&hda,0,sizeof(HeadCostAng));
	////////////////

	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Guardando filas de matrices %04d a %04d", ithr,n_ini, n_fin);	

	seg = GetTickCount();
	/////////////////////////////////////
	//bucle por cada conjunción de la carto
	Cgarray<MapDataFloat> bufer;
	for(ic=n_ini; ic<n_fin && !mal && !pirate; ic++)
	{				
		if(!olv_limp->cost_conj[ic].guarda(hd,ic,olv_limp->olv_tasks->path_cconj,TASKS_EXT_MAT,&bufer))
		{
			mal=TRUE;
			continue;
		}

		if(olv_limp->ang_conj)
		{		
			if(!olv_limp->ang_conj[ic].guarda(hda,ic,olv_limp->olv_tasks->path_ang, TASKS_EXT_MAT))
			{
				mal=TRUE;
				continue;
			}		
		}

		//avisa de progreso
		if(((ic-n_ini)%500==0) || ((ic-n_ini)==(n_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Guardando matrices, %ld de %ld", ithr,
				(ic-n_ini+1),n_desp);
			//avisa de progreso	
			prog_subthr=(1.0*(ic-n_ini+1)/n_desp);///
			thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
		}
	}	
	if(mal)
		goto va_mal;

va_mal:
	if(mal)
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en guardado de matrices", ithr);
		prog_subthr=-1;//para avisar al padre de que ha habido un error
	}
	else
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin guardado matriz, %.3f seg", ithr, 1.0*(GetTickCount()-seg)/1000);
	}

	thr_padre->encola(OLV_LIMP_EV_GUARD_MATS_FIN,NULL,FALSE);

}
//*************************************************************************************
/*
 * Cada thread de los que guardan a disco la matriz de dist entre conjunciones y de ángulos
 */
BOOL Colv_limp_thr::guarda_mats_fin()
{
	////////////////	
	//para los threads
	para_subthrs();

	//guarda matriz de info aso
	guarda_iaso();
	olvlog(LOG_TODO,"olv_limp_t","Guardada matriz de info aso");

	//libera esta memoria que ya no le hace falta
	olv_limp->tip_conj.clear();				

	olvlog(LOG_TODO,"olv_limp_t","FIN Guardado Matrices");
	return TRUE;
}
//*************************************************************************************
/*
 * Guarda los ic de la info aso del ámbito ia
 */
BOOL Colv_limp_thr::guarda_iaso()
{
	HANDLE hfile = INVALID_HANDLE_VALUE;
	int nb, i, ref_i;
	HeadInfoAso hd;

	//crea archivo-----------------------------------
	hfile = CreateFile(olv_limp->olv_tasks->file_iaso,  GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		i=GetLastError();
		return FALSE;
	}
	memset(&hd,0,sizeof(HeadInfoAso));
	hd.nint=olv_limp->n_amb*3;
	//graba cabecera------------		
	nb = sizeof(hd);
	//calcula el nb
	if (nb != _lwrite((int)hfile, (LPCCH)&hd, nb))
	{
		goto va_mal;
	}

	nb=sizeof(int);
	//se embucla en los ámbitos guardando sus flags ic[0] e ic[1]
	for(i=0;i<olv_limp->n_amb;i++)
	{
		ref_i=olv_limp->carto.get(i).entity()->ref;
		if (nb != _lwrite((int)hfile, (LPCCH)&olv_limp->iaso[ref_i].inod[0], nb))
			break;
		if (nb != _lwrite((int)hfile, (LPCCH)&olv_limp->iaso[ref_i].inod[1], nb))
			break;
		if (nb != _lwrite((int)hfile, (LPCCH)&olv_limp->iaso[ref_i].flgs, nb))
			break;
	}
	if(i<olv_limp->n_amb)
		goto va_mal;	

	CloseHandle(hfile);
	return TRUE;

va_mal:
	CloseHandle(hfile);
	return FALSE;
}
//*************************************************************************************
void Colv_limp_thr::ini_infotask(int ntasks)
{
	InfoIniTask ii;
	memset(&ii,0,sizeof(InfoIniTask));
	ii.KK = olv_limp->tipo_ambit;
	ii.n = olv_limp->conjs.n;
	ii.namb = olv_limp->n_amb;
	ii.nthr=n_subthr;
	ii.ntsks=ntasks;
	ii.usa_angs = (olv_limp->ang_conj!=NULL);
	ii.id_instal = olv_limp->nod_instal;
	ii.id_planta = olv_limp->nod_plant;
	strcpy_s(ii.path_temp,MAX_PATH,olv_limp->olv_tasks->path_temp);
	strcpy_s(ii.path_cconj,MAX_PATH,olv_limp->olv_tasks->path_cconj);
	strcpy_s(ii.path_costamb,MAX_PATH,olv_limp->olv_tasks->path_costamb);
	strcpy_s(ii.path_ang,MAX_PATH,olv_limp->olv_tasks->path_ang);
	strcpy_s(ii.file_iaso,MAX_PATH,olv_limp->olv_tasks->file_iaso);
	strcpy_s(ii.ext,8,TASKS_EXT_MAT);
	memcpy(&olv_limp->olv->infotask,&ii,sizeof(InfoIniTask));
}
//*************************************************************************************
BOOL Colv_limp_thr::task_dj_escucha()
{
	////////////////////////////////////////////////
	//lanza las tasks
	//ejecuta n veces OliviaTasks, cada una va a calcular una parte de la matriz de costes entre ambitos
	//con sus correspondientes dijkstras y lo va a escribir en disco
	//antes de eso, se han guardado en disco la matriz (o maps) de costes entre conjunciones y de ángulos entre conjunciones
	////////////////////////////////////////////////

	int ntasks=1;
	pon_mi_progre(OLV_TAREA_MULTITASK, 0);
	olvlog(LOG_TODO,"olv_limp_t","Comienza ejecución Multitask");
	ini_infotask(ntasks);

	//lanza la escucha
	olv_limp->soc = new Csock_svThread();
	olv_limp->soc->escucha=olv_limp->olv_tasks;

	if(!olv_limp->soc->liseningThread(TASKS_PORT,olv_limp->olv->olv_sock->ip))
	{
		goto mal;
	}

	//////////////////////////////////////
	if(!lanza_tasks(ntasks))
	{
		pon_mi_msg("Error al lanzar multitask para el cálculo de costes entre ámbitos");
		return FALSE;
	}		


	return TRUE;

mal:
	olv_limp->soc->close();
	delete olv_limp->soc;
	olv_limp->soc=NULL;
	return FALSE;
}
//*************************************************************************************
BOOL Colv_limp_thr::task_dj_fin()
{
	//debe iniciar la matriz cost_amb y leerla lo que han rellenado los tasks, y combinarla

	return TRUE;
}
//*************************************************************************************
void Colv_limp_thr::borra_temp_files(BOOL todo/*=TRUE*/)
{
	Cdir_manager dm;
	if(todo)
	{
		//borra los archivos de dijkstra
		dm.borra_archivos(olv_limp->olv->paths.path_temp,EXT_ARCH_DIJ_DEFAULT);
	}
	//borra los archivos asociados al multitask
	dm.borra_archivos(olv_limp->olv->paths.path_temp,TASKS_EXT_MAT,TRUE);
	dm.borra_archivos(olv_limp->olv->paths.path_temp,TASKS_EXT_DIS,TRUE);
}
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
/**
 * Thread para cálculo multiproceso de la planificación
 */
UINT th_planificacion(LPVOID pp)
{
	th_param_planif *p=(th_param_planif*)pp;
	int id_th=p->id_th;
	int id_curro=p->id_curro;
	int ini, fin, i, j, entr, entr_m;
	int mm[2];
	double d, dm;
	p->id_th=-1;
	while(!p->pirate)
	{
		if(id_curro==p->id_curro)
		{
			//no curro
			Sleep(p->milis_sleep);
			continue;
		}
		id_curro=p->id_curro;
		//ha currar
		switch(p->modo)
		{
		case (0)://cambio de un elemento en la ruta
			i=p->namb/p->nth;
			ini=max(i*id_th, 1);
			if(id_th+1==p->nth)
				fin=p->namb;
			else
				fin=ini+i;
			i=-1;
			dm=MAYUSCULO;
			entr=0;
			while(ini<fin)
			{
				if(ini==p->param[0])
				{
					
					d=p->tl->dame_coste(p->sec, 0,p->namb-1, p->s, p->abs);
					
				}
				else
					d=p->tl->dame_coste_ex(p->sec,0,p->namb-1,p->s,p->param[0],ini, entr);
				if(d<dm)
				{
					dm=d;
					i=ini;
					entr_m=entr;
				}
				if (entr>=1 || (ini==p->param[0]))
				{
					ini++;
					entr=0;
				}
				else
					entr=1;

			}
			p->dth[id_th].coste=dm;
			p->dth[id_th].pos[0]=i;
			p->dth[id_th].pos[1]=entr_m;

			break;
		case (1)://permutaciones de elementos
			i=Colv_geom::fact(p->param[1]-p->param[0]);
			j=i/p->nth;
			ini=max(i*id_th, 1);
			if(id_th+1==p->nth)
				fin=i;
			else
				fin=ini+j;
			i=-1;
			dm=MAYUSCULO;
			while(ini<fin)
			{
				if(!p->tl->permuta(p->sec, p->param[0], p->param[1], ini, p->dth[id_th].sec))
				{
					ini++;
					continue;
				}
				d=p->tl->dame_coste(p->dth[id_th].sec, 0,p->namb-1, p->s, p->abs);
				if(d<dm)
				{
					dm=d;
					i=ini;
				}
				ini++;
			}
			if(i<0 || !p->tl->permuta(p->sec, p->param[0], p->param[1], i, p->dth[id_th].sec))
			{
				p->dth[id_th].coste=MAYUSCULO;
			}
			else
				p->dth[id_th].coste=dm;
			p->dth[id_th].pos[0]=i;
			break;
		case (2)://cambio de un elemento en la ruta (cambiandolo de verdad)
			//pilla un entorno de como mucho +-100 ambitos para las permu
			//-----------------------------------------------
			/*i=p->namb/p->nth;
			ini=max(i*id_th, 1);
			if(id_th+1==p->nth)
				fin=p->namb;
			else
				fin=ini+i;*/
			mm[0]=max(p->param[0]-50,0);
			mm[1]=min(mm[0]+101,p->namb);
			i=(mm[1]-mm[0])/p->nth;
			ini=mm[0]+max(i*id_th, 1);
			if(id_th+1==p->nth)
				fin=mm[1];
			else
				fin=ini+i;
			//-----------------------------------------------

			i=-1;
			dm=MAYUSCULO;
			entr=entr_m=0;
			while(ini<fin)
			{
				if(ini==p->param[0])
				{
					d=p->tl->dame_coste(p->sec, 0,p->namb-1, p->s, p->abs);

				}
				else
				{
					memcpy(p->dth[id_th].sec,p->sec, p->namb_t*sizeof(Secu_amb));
					p->tl->cambia_elem(p->dth[id_th].sec, p->param[0],ini, entr);
					d=p->tl->dame_coste(p->dth[id_th].sec, 0,p->namb-1, p->s, p->abs);
				}
				if(d<dm)
				{
					dm=d;
					i=ini;
					entr_m=entr;
				}
				if (entr>=1 || (ini==p->param[0]))
				{
					ini++;
					entr=0;
				}
				else
					entr=1;

			}
			p->dth[id_th].coste=dm;
			p->dth[id_th].pos[0]=i;
			p->dth[id_th].pos[1]=entr_m;

			break;
		default:
			break;
		}
		p->dth[id_th].currando=FALSE;
	}
	//salida de thread-------------------------
	p->dth[id_th].activo=FALSE;
	lck_sum_atm(&p->nth,-1);

	return 0;
}
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
#endif