@ -14,74 +14,167 @@
*/
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <float.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
* @ param point_ts Los puntos a calcular
* @ param n La cantidad de puntos en el array point_ts
* @ param minimum_dist La distancia minimo encontrado
* @ return Retorna los 2 puntos mas cercanos
* Comparar 2 double para ver cual es mayor o si son iguales
* @ param a El primer double a comparar
* @ param b El segundo double a comparar
* @ return Retorna 1 si a es mayor de b , - 1 si a es menor de b ó 0 si son igual
*/
int compareX ( const void * a , const void * b ) { //ordena el arreglo de puntos de acuerdo a X
point_t * p1 = ( point_t * ) a , * p2 = ( point_t * ) b ;
return ( p1 - > x - p2 - > x ) ;
int compare_double ( double a , double b ) {
if ( a > b ) {
return 1 ;
}
else if ( a < b ) {
return - 1 ;
}
else {
return 0 ;
}
}
int compareY ( const void * a , const void * b ) { //ordena el arreglo de puntos de acuerdo a Y
point_t * p1 = ( point_t * ) a , * p2 = ( point_t * ) b ;
return ( p1 - > y - p2 - > y ) ;
/**
* Comparar los el eje x de 2 puntos
* @ param a El primer punto a comparar
* @ param b El segundo punto a comparar
* @ return Retorna la comparaci ó n entre los 2 puntos
*/
int compare_x ( const void * a , const void * b ) {
return compare_double ( ( * ( point_t * ) a ) . x , ( * ( point_t * ) b ) . x ) ;
}
double min ( double x , double y ) { // Función para encontrar el mayor entre dos valores flotantes
return ( x < y ) ? x : y ;
/**
* Comparar los el eje y de 2 puntos
* @ param a El primer punto a comparar
* @ param b El segundo punto a comparar
* @ return Retorna la comparaci ó n entre los 2 puntos
*/
int compare_y ( const void * a , const void * b ) {
return compare_double ( ( * ( point_t * ) a ) . y , ( * ( point_t * ) b ) . y ) ;
}
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
{
double dist ;
qsort ( strip , n , sizeof ( point_t ) , compareY ) ;
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 ] ;
}
}
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
int mid = n / 2 ;
point_t midpoint_t = P [ mid ] ;
// 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
double dl = closestUtil ( P , mid , minimum_dist , closest_pair ) ;
double dr = closestUtil ( P + mid , n - mid , minimum_dist , closest_pair ) ;
double d = min ( dl , dr ) ; // Encontrar la distancia minima de dos puntos
/* 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 [ ] */
* minimum_dist = min ( d , stripClosest ( strip , j , minimum_dist , closest_pair ) ) ;
return * minimum_dist ;
}
/**
* El algoritmo de encontrar 2 puntos recursivo usando divide and conquer
* @ param points_x Los puntos ordenado en el eje x
* @ param nx La cantidad de puntos en el array points_y
* @ param points_y Los puntos ordenado en el eje y
* @ param ny La cantidad de puntos en el array points_y
* @ param closest_pair Las 2 pares de puntos mas cercano
* @ return Retorna la distance entre los dos puntos mas cercano
*/
double divide_and_conquer_run ( point_t * points_x , unsigned int nx , point_t * points_y , unsigned int ny , point_t * closest_pair ) {
int left ;
int right ;
int i ;
double mid ;
double d = DBL_MAX ;
double min_d = DBL_MAX ;
double x0 ;
double x1 ;
double x ;
point_t * closest_pair2 ;
point_t * points_y2 ;
if ( nx < = 4 ) {
closest_pair2 = brute_force ( points_x , nx , & d ) ;
closest_pair [ 0 ] = closest_pair2 [ 0 ] ;
closest_pair [ 1 ] = closest_pair2 [ 1 ] ;
return d ;
}
closest_pair2 = malloc ( sizeof ( point_t ) * 2 ) ;
points_y2 = malloc ( sizeof ( point_t ) * ny ) ;
mid = points_x [ nx / 2 ] . x ;
left = - 1 ;
right = ny ;
for ( i = 0 ; i < ny ; i + + ) {
if ( points_y [ i ] . x < mid ) {
points_y2 [ + + left ] = points_y [ i ] ;
}
else {
points_y2 [ - - right ] = points_y [ i ] ;
}
}
for ( i = ny - 1 ; right < i ; right + + , i - - ) {
closest_pair2 [ 0 ] = points_y2 [ right ] ;
points_y2 [ right ] = points_y2 [ i ] ;
points_y2 [ i ] = closest_pair2 [ 0 ] ;
}
min_d = divide_and_conquer_run ( points_x , nx / 2 , points_y2 , left + 1 , closest_pair ) ;
d = divide_and_conquer_run ( points_x + nx / 2 , nx - nx / 2 , points_y2 + left + 1 , ny - left - 1 , closest_pair2 ) ;
if ( d < min_d ) {
min_d = d ;
closest_pair [ 0 ] = closest_pair2 [ 0 ] ;
closest_pair [ 1 ] = closest_pair2 [ 1 ] ;
}
d = sqrt ( min_d ) ;
free ( closest_pair2 ) ;
left = - 1 ; right = ny ;
for ( i = 0 ; i < ny ; i + + ) {
x = points_y [ i ] . x - mid ;
if ( x < = - d | | x > = d ) {
continue ;
}
if ( x < 0 ) {
points_y2 [ + + left ] = points_y [ i ] ;
}
else {
points_y2 [ - - right ] = points_y [ i ] ;
}
}
while ( left > = 0 ) {
x0 = points_y2 [ left ] . y + d ;
while ( right < ny & & points_y2 [ right ] . y > x0 ) {
right + + ;
}
if ( right > = ny ) {
break ;
}
x1 = points_y2 [ left ] . y - d ;
for ( i = right ; i < ny & & points_y2 [ i ] . y > x1 ; i + + )
if ( ( x = distance ( points_y2 [ left ] , points_y2 [ i ] ) ) < min_d ) {
min_d = x ;
closest_pair [ 0 ] = points_y2 [ left ] ;
closest_pair [ 1 ] = points_y2 [ i ] ;
}
left - - ;
}
free ( points_y2 ) ;
return min_d ;
}
/**
* Encontrar los 2 puntos m á s cercano usando el metodo de dividir para conquistar
* @ param point_t Los puntos a calcular
* @ param n La cantidad de puntos en el array point_ts
* @ param minimum_dist La distancia minimo encontrado
* @ return Retorna los 2 puntos mas cercanos
*/
point_t * divide_and_conquer ( point_t * points , unsigned int n , double * minimum_dist ) {
point_t * closest_pair = malloc ( sizeof ( point_t ) * 2 ) ;
qsort ( points , n , sizeof ( point_t ) , compareX ) ;
closestUtil ( points , n , minimum_dist , closest_pair ) ; //Usa la funcion recursiva closestUtil para encontrar la distancia minima
point_t * points_x = malloc ( sizeof ( point_t ) * n ) ;
point_t * points_y = malloc ( sizeof ( point_t ) * n ) ;
memcpy ( points_x , points , sizeof ( point_t ) * n ) ;
memcpy ( points_y , points , sizeof ( point_t ) * n ) ;
qsort ( points_x , n , sizeof ( point_t ) , compare_x ) ;
qsort ( points_y , n , sizeof ( point_t ) , compare_y ) ;
* minimum_dist = divide_and_conquer_run ( points_x , n , points_y , n , closest_pair ) ;
free ( points_x ) ;
free ( points_y ) ;
return closest_pair ;
}