2018-12-12 11:43:12 -03:00
/*
* Copyright 2018 Christopher Cromer
* Copyright 2018 Rodolfo Cuevas
*
* Redistribution and use in source and binary forms , with or without modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice , this list of conditions and the following disclaimer in the documentation and / or other materials provided with the distribution .
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include <stdlib.h>
# include "points.h"
# include "brute_force.h"
# include "distance.h"
/**
* Encontrar los 2 puntos más cercano usando el metodo de dividir para conquistar
2018-12-12 12:26:33 -03:00
* @ param point_ts Los puntos a calcular
* @ param n La cantidad de puntos en el array point_ts
2018-12-12 11:43:12 -03:00
* @ param minimum_dist La distancia minimo encontrado
* @ return Retorna los 2 puntos mas cercanos
*/
2018-12-12 12:09:56 -03:00
int compareX ( const void * a , const void * b ) { //ordena el arreglo de puntos de acuerdo a X
2018-12-12 12:26:33 -03:00
point_t * p1 = ( point_t * ) a , * p2 = ( point_t * ) b ;
2018-12-12 11:43:12 -03:00
return ( p1 - > x - p2 - > x ) ;
2018-12-12 12:09:56 -03:00
}
2018-12-12 11:43:12 -03:00
2018-12-12 12:09:56 -03:00
int compareY ( const void * a , const void * b ) { //ordena el arreglo de puntos de acuerdo a Y
2018-12-12 12:26:33 -03:00
point_t * p1 = ( point_t * ) a , * p2 = ( point_t * ) b ;
2018-12-12 11:43:12 -03:00
return ( p1 - > y - p2 - > y ) ;
2018-12-12 12:09:56 -03:00
}
2018-12-12 11:43:12 -03:00
2018-12-12 13:30:38 -03:00
double min ( double x , double y ) { // Función para encontrar el mayor entre dos valores flotantes
2018-12-12 12:09:56 -03:00
return ( x < y ) ? x : y ;
}
2018-12-12 13:30:38 -03:00
void stripClosest ( point_t * strip , int n , double * minimum_dist , point_t * closest_pair ) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado
2018-12-12 12:33:06 -03:00
{
2018-12-12 13:30:38 -03:00
double dist ;
qsort ( strip , n , sizeof ( point_t ) , compareY ) ;
2018-12-12 12:33:06 -03:00
2018-12-12 13:30:38 -03:00
for ( int i = 0 ; i < n ; + + i )
for ( int j = i + 1 ; j < n & & ( strip [ j ] . y - strip [ i ] . y ) < * minimum_dist ; + + j )
if ( ( dist = distance ( strip [ i ] , strip [ j ] ) ) < * minimum_dist ) {
* minimum_dist = dist ;
closest_pair [ 0 ] = strip [ i ] ;
closest_pair [ 1 ] = strip [ j ] ;
}
2018-12-12 12:33:06 -03:00
}
2018-12-12 13:30:38 -03:00
double closestUtil ( point_t * P , int n , double * minimum_dist , point_t * closest_pair ) { // Función para encontrar la distancia más corta entre puntos
2018-12-12 12:26:33 -03:00
int mid = n / 2 ;
point_t midpoint_t = P [ mid ] ;
2018-12-12 13:30:38 -03:00
2018-12-12 12:26:33 -03:00
// Consider the vertical line passing through the middle point_t
// calculate the smallest distance dl on left of middle point_t and
// dr on right side
2018-12-12 13:30:38 -03:00
double dl = closestUtil ( P , mid , minimum_dist , closest_pair ) ;
double dr = closestUtil ( P + mid , n - mid , minimum_dist , closest_pair ) ;
2018-12-12 12:26:33 -03:00
2018-12-12 13:30:38 -03:00
double d = min ( dl , dr ) ; // Encontrar la distancia minima de dos puntos
2018-12-12 12:26:33 -03:00
/* Crea un arreglo que contiene los puntos cercanos, mas cerca que d*/
point_t strip [ n ] ;
int j = 0 ;
for ( int i = 0 ; i < n ; i + + )
if ( abs ( P [ i ] . x - midpoint_t . x ) < d )
strip [ j ] = P [ i ] , j + + ;
/*Encontrar el punto más cercano en la cinta, retornando el minimo de d y el más cercano
distance es strip [ ] */
2018-12-12 13:30:38 -03:00
* minimum_dist = min ( d , stripClosest ( strip , j , minimum_dist , closest_pair ) ) ;
return * minimum_dist ;
2018-12-12 12:26:33 -03:00
}
2018-12-12 12:09:56 -03:00
point_t * divide_and_conquer ( point_t * points , unsigned int n , double * minimum_dist ) {
2018-12-12 12:26:33 -03:00
point_t * closest_pair = malloc ( sizeof ( point_t ) * 2 ) ;
2018-12-12 13:30:38 -03:00
qsort ( points , n , sizeof ( point_t ) , compareX ) ;
closestUtil ( points , n , minimum_dist , closest_pair ) ; //Usa la funcion recursiva closestUtil para encontrar la distancia minima
return closest_pair ;
2018-12-12 12:33:06 -03:00
}
2018-12-12 12:09:56 -03:00