////////////////////////////////////////////////////////////////////////// // Fundamentos de Programación // ETS Informática y Telecomunicaciones // Universidad de Granada // Departamento de Ciencias de la Computación e Inteligencia Artificial // Autor: Juan Carlos Cubero ////////////////////////////////////////////////////////////////////////// // Clases Segmento Dirigido, Punto2D y Recta #include #include using namespace std; bool SonIguales (double un_real, double otro_real){ return (abs(un_real-otro_real) <= 1e-5); } class Punto2D{ private: double abscisa; double ordenada; public: Punto2D(double abscisaPunto, double ordenadaPunto) { SetCoordenadas(abscisaPunto, ordenadaPunto); } double Abscisa(){ return abscisa; } double Ordenada(){ return ordenada; } void SetCoordenadas(double abscisaPunto, double ordenadaPunto){ abscisa = abscisaPunto; ordenada = ordenadaPunto; } bool EsIgual_a (Punto2D otro_punto){ return (SonIguales(abscisa, otro_punto.abscisa) && SonIguales(ordenada, otro_punto.ordenada)); } string ToString(){ return "(" + to_string(abscisa) + " , " + to_string(ordenada) + ")"; } }; class SegmentoDirigido{ private: double x_1, y_1, x_2, y_2; bool SonCorrectos(double origen_abscisa, double origen_ordenada, double final_abscisa, double final_ordenada){ return !(origen_abscisa == final_abscisa && origen_ordenada == final_ordenada); } public: // Prec: Parámetros correctos (punto origen distinto de punto final) SegmentoDirigido(double origen_abscisa, double origen_ordenada, double final_abscisa, double final_ordenada){ SetCoordenadas(origen_abscisa, origen_ordenada, final_abscisa, final_ordenada); } void SetCoordenadas(double origen_abscisa, double origen_ordenada, double final_abscisa, double final_ordenada){ if (SonCorrectos(origen_abscisa, origen_ordenada, final_abscisa, final_ordenada)){ x_1 = origen_abscisa; y_1 = origen_ordenada; x_2 = final_abscisa; y_2 = final_ordenada; } } double OrigenAbscisa(){ return x_1; } double OrigenOrdenada(){ return y_1; } double FinalAbscisa(){ return x_2; } double FinalOrdenada(){ return y_2; } double Longitud(){ double diferencia_abscisas, diferencia_ordenadas; diferencia_abscisas = x_2 - x_1; diferencia_ordenadas = y_2 - y_1; return sqrt(diferencia_abscisas * diferencia_abscisas + diferencia_ordenadas * diferencia_ordenadas); } void TrasladaHorizontal(double unidades){ x_1 = x_1 + unidades; x_2 = x_2 + unidades; } void TrasladaVertical(double unidades){ y_1 = y_1 + unidades; y_2 = y_2 + unidades; } void Traslada(double und_horizontal, double und_vertical){ TrasladaHorizontal(und_horizontal); TrasladaVertical(und_vertical); } }; class Recta{ // Ax + By + C = 0 private: double A; double B; double C; bool SonCorrectos (double coef_x, double coef_y){ return !(coef_x == 0 && coef_y == 0); } public: // Prec: Parámetros correctos (coef_x, coef_y distintos de 0) Recta(double coef_x, double coef_y, double coef_indep){ SetCoeficientes(coef_x, coef_y, coef_indep); } /* AMPLIACIÓN: Sobre la precondición del constructor Si los parámetros pasados al constructor no son correctos, los datos miembro se quedan con valores indeterminados. Para paliar este problema, se podrían inicializar los datos miembro a un valor concreto, como por ejemplo NAN. El objeto seguiría estando en un estado inválido, pero al menos "reconocible" Esta inicialización por defecto es posible desde C++11. Bastaría poner: private: double A = NAN; double B = NAN; double C = NAN; */ // Si los datos no son correctos, no hace ninguna modificación void SetCoeficientes(double coef_x, double coef_y, double coef_indep){ if (SonCorrectos(coef_x, coef_y)){ A = coef_x; B = coef_y; C = coef_indep; } } double Coef_X(){ return A; } double Coef_Y(){ return B; } double Coef_indep(){ return C; } double Ordenada_en(double x){ return (-C - x*A ) / B; } double Abscisa_en (double y){ return (-C - y*B ) / A; } double Pendiente(){ return -A/B; } string ToString(){ return to_string(A) + " x + " + to_string(B) + " y + " + to_string(C) + " = 0"; } Punto2D PuntoContenido(double x){ Punto2D contenido(x, Ordenada_en(x)); return contenido; } bool Contiene(Punto2D punto){ double ordenada_recta = Ordenada_en(punto.Abscisa()); return SonIguales(ordenada_recta , punto.Ordenada()); // O también: // return SonIguales(A * punto.Abscisa() + // B * punto.Ordenada() + C , 0.0); } SegmentoDirigido Segmento(double abscisa_origen, double abscisa_final){ double ordenada_origen = Ordenada_en(abscisa_origen); double ordenada_final = Ordenada_en(abscisa_final); SegmentoDirigido segmento(abscisa_origen, ordenada_origen, abscisa_final, ordenada_final); return segmento; } Recta Perpendicular (Punto2D pto){ double coef_y = 1; double pendiente_perp = B/A; double coef_x = -pendiente_perp; double coef_ind = pto.Abscisa() * pendiente_perp - pto.Ordenada(); Recta perp(coef_x, coef_y, coef_ind); return perp; } }; int main(){ double A, B, C; double abscisa, ordenada; int numero_de_puntos; bool contenido; cin >> A, cin >> B; cin >> C; Recta recta(A, B, C); /* Importante: En el siguiente bucle creamos un objeto Punto2D en cada iteración. En situaciones en las que esto puede suponer una recarga computacional importante, tendríamos que proporcional un constructor sin parámetros para Punto2D, crear un sólo punto antes del bucle y cambiar las coordenadas en cada iteración con el correspondiente método SetCoordenadas */ cin >> numero_de_puntos; for (int i = 0; i < numero_de_puntos; i++){ cin >> abscisa; cin >> ordenada; Punto2D punto(abscisa, ordenada); contenido = recta.Contiene(punto); if (contenido) cout << "\nLa recta contiene al punto " << punto.ToString(); else cout << "\nLa recta no contiene al punto " << punto.ToString(); } // 2 -5 -3 2 4 1 4 2 // Contiene al primero pero no al segundo }