private int BuscaPosibleExtremosDesconectados(
            Vía laVía,
            Vía laVíaDestino)
        {
            int númeroDeProblemasDetectados = 0;

            // Necesitamos al menos dos nodos.
            Coordenadas[] losNodos      = laVía.Coordenadas;
            int           númeroDeNodos = losNodos.Length;

            if (númeroDeNodos >= 2)
            {
                #region Crea los nodos extremos.
                int        índiceUltimoNodo     = númeroDeNodos - 1;
                List <int> índicesNodosExtremos = new List <int>();

                // Nos saltamos el nodo si éste tiene el atributo de índice desconectado.
                string atributoNodoDesconectado = AtributoNodoDesconectado
                                                  + ",0";
                if (!laVía.TieneAtributo(atributoNodoDesconectado))
                {
                    índicesNodosExtremos.Add(0);
                }
                atributoNodoDesconectado = AtributoNodoDesconectado
                                           + ',' + índiceUltimoNodo.ToString(CultureInfo.InvariantCulture);
                if (!laVía.TieneAtributo(atributoNodoDesconectado))
                {
                    índicesNodosExtremos.Add(índiceUltimoNodo);
                }
                #endregion

                // Busca la distancia mínima a los nodos de la vía.
                foreach (int índiceNodo in índicesNodosExtremos)
                {
                    Coordenadas nodo = laVía.Coordenadas[índiceNodo];
                    double      distanciaNodoMasCercano = double.MaxValue;
                    int         índiceNodoMasCercano    = 0;
                    int         númeroDeNodosDestino    = laVíaDestino.Coordenadas.Length;
                    for (int índiceNodoDestino = 0; índiceNodoDestino < númeroDeNodosDestino; ++índiceNodoDestino)
                    {
                        Coordenadas nodoDestino = laVíaDestino.Coordenadas[índiceNodoDestino];

                        // Nos saltamos este nodo si tiene las mismas coordenadas.
                        bool tienenLasMismasCoordenadas = (nodo == nodoDestino);
                        if (tienenLasMismasCoordenadas)
                        {
                            distanciaNodoMasCercano = 0;
                            continue;
                        }

                        // Busca el nodo mas cercano.
                        double distancia = Coordenadas.DistanciaEnMetros(nodo, nodoDestino);
                        if (distancia < distanciaNodoMasCercano)
                        {
                            distanciaNodoMasCercano = distancia;
                            índiceNodoMasCercano    = índiceNodoDestino;
                        }
                    }

                    // Si la distancia al nodo mas cercano es cero quiere decir que tiene las mismas
                    // coordenadas.  En este caso nos saltamos este nodo extremo porque
                    // nodos con las mismas coordenadas son procesados en otro ciclo.
                    if (distanciaNodoMasCercano == 0)
                    {
                        continue;
                    }

                    // Los nodos son posibles nodos desconectados si la distancia entre
                    // ellos es menor que la distancia máxima de búsqueda.
                    if (distanciaNodoMasCercano < DistanciaMáxima)
                    {
                        // Si la vía tiene algun otro nodo conectado al nodo destino
                        // entonces nos saltamos este nodo.
                        bool laVíaTieneOtroNodoConectadoAlNodoDestino = false;
                        foreach (Coordenadas nodoDeLaVía in laVía.Coordenadas)
                        {
                            Coordenadas nodoMasCercano = laVíaDestino.Coordenadas[índiceNodoMasCercano];
                            if (nodoDeLaVía == nodoMasCercano)
                            {
                                laVíaTieneOtroNodoConectadoAlNodoDestino = true;
                                break;
                            }
                        }
                        if (!laVíaTieneOtroNodoConectadoAlNodoDestino)
                        {
                            string error = string.Format("E107: La distancia es menor que {0:0.0} m: {1:0.0} m.", DistanciaMáxima,
                                                         distanciaNodoMasCercano);
                            InformaciónNodoDesconectado posibleNodoDesconectado = new InformaciónNodoDesconectado(
                                new Nodo(laVía, índiceNodo),
                                new Nodo(laVíaDestino, índiceNodoMasCercano),
                                distanciaNodoMasCercano,
                                error);

                            PosibleNodosDesconectados.Add(posibleNodoDesconectado);
                            ++númeroDeProblemasDetectados;
                        }
                    }
                }
            }

            return(númeroDeProblemasDetectados);
        }
        /// <summary>
        /// Procesa una Vía.
        /// </summary>
        /// <param name="laVía">La Vía.</param>
        /// <returns>El número de problemas detectados al procesar el elemento.</returns>
        protected override int ProcesaElemento(Vía laVía)
        {
            int númeroDeProblemasDetectados = 0;

            Coordenadas[] nodos         = laVía.Coordenadas;
            int           númeroDeNodos = nodos.Length;

            // Crea mapa de nodos desconectados por adelantado para hacerlo
            // afuera del loop.
            bool[] mapaNodoDesconectado = new bool[númeroDeNodos];
            for (int i = 0; i < númeroDeNodos; ++i)
            {
                string atributoNodoDesconectado = AtributoNodoDesconectado
                                                  + ',' + i;
                if (laVía.TieneAtributo(atributoNodoDesconectado))
                {
                    mapaNodoDesconectado[i] = true;
                }
            }

            // Busca en todos los nodos de todas las vías (comenzando desde la siguiente
            // para no repetir búsquedas.)
            for (int índiceVíaDestino = IndiceDeElementoProcesándose + 1; índiceVíaDestino < NúmeroDeElementos; ++índiceVíaDestino)
            {
                Vía víaDestino = this[índiceVíaDestino];

                #region Busca todos los nodos con las mismas coordenadas.
                foreach (Nodo nodo in laVía.Nodos)
                {
                    // Nos saltamos el nodo si éste tiene el atributo de nodo desconectado.
                    if (mapaNodoDesconectado[nodo.Indice])
                    {
                        continue;
                    }

                    bool esNodoRuteable = nodo.EsRuteable;

                    // Buscamos en todos los nodos destino.
                    Coordenadas coordenadasNodo = nodo.Coordenadas;
                    foreach (Nodo nodoDestino in víaDestino.Nodos)
                    {
                        #region Analizamos los nodos si tiene las mismas coordenadas.
                        Coordenadas coordenadasNodoDestino     = nodoDestino.Coordenadas;
                        bool        tienenLasMismasCoordenadas = (coordenadasNodo == coordenadasNodoDestino);
                        if (tienenLasMismasCoordenadas)
                        {
                            string       error                 = null;
                            const double distancia             = 0;
                            bool         esNodoDestinoRuteable = nodoDestino.EsRuteable;
                            if (esNodoRuteable && esNodoDestinoRuteable)
                            {
                                // Si los identificadores de nodo no son el mismo entonces es un
                                // posible nodo desconectado.
                                if (nodo.IdentificadorGlobal != nodoDestino.IdentificadorGlobal)
                                {
                                    error = string.Format("E104: Los nodos tienen Identificadores Globales distintos: {0} != {1}.",
                                                          nodo.IdentificadorGlobal,
                                                          nodoDestino.IdentificadorGlobal);
                                }
                            }
                            else if (!esNodoRuteable & !esNodoDestinoRuteable)
                            {
                                error = "E105: Ambos nodos tienen las mismas coordenadas pero ninguno es ruteable.";
                            }
                            else
                            {
                                error = "E106: Ambos nodos tienen las mismas coordenadas pero solo uno es ruteable.";
                            }

                            if (error != null)
                            {
                                InformaciónNodoDesconectado posibleNodoDesconectado = new InformaciónNodoDesconectado(
                                    nodo,
                                    nodoDestino,
                                    distancia,
                                    error);

                                PosibleNodosDesconectados.Add(posibleNodoDesconectado);
                                ++númeroDeProblemasDetectados;

                                // Añade las vías involucradas al filtro.
                                FiltroDeVíasConPosiblesNodosDesconectados[IndiceDeElementoProcesándose] = true;
                                FiltroDeVíasConPosiblesNodosDesconectados[índiceVíaDestino]             = true;
                            }

                            // Nos salimos del ciclo porque si los nodos tienen las mismas
                            // coordenadas entonces ya no pueden estar conectados en otro nodo.
                            break;
                        }
                        #endregion
                    }
                }
                #endregion

                // Busca nodos desconectados extremos.
                int númeroDeNodosDetectados = BuscaPosibleExtremosDesconectados(laVía, víaDestino);
                númeroDeNodosDetectados += BuscaPosibleExtremosDesconectados(víaDestino, laVía);
                if (númeroDeNodosDetectados > 0)
                {
                    // Añade las vías involucradas al filtro.
                    FiltroDeVíasConPosiblesNodosDesconectados[IndiceDeElementoProcesándose] = true;
                    FiltroDeVíasConPosiblesNodosDesconectados[índiceVíaDestino]             = true;
                }

                númeroDeProblemasDetectados += númeroDeNodosDetectados;
            }

            return(númeroDeProblemasDetectados);
        }