namespace Model {
+/** Bomba hidráulica
+ *
+ * La bomba es un elemento que toma líquido de alguna fuente
+ * misteriosa y lo envía por su salida. La cantidad de fluido que
+ * envía va a depender exclusivamente del sistema al cual está conectado.
+ * La bomba es "inteligente", y es capaz de reducir el flujo que envía
+ * dependiendo de las condiciones que le ponga el sistema, reduciendo
+ * así el flujo de manera automática para evitar sobrecargas.
+ *
+ * La bomba tiene 2 interruptores, uno manual y otro automático.
+ * Si el manual está apagado, la bomba se considera apagada e ignora
+ * todo mensage del interruptor automático. En esta condición envía
+ * 0 cuando se le consulta por su flojo máximo.
+ *
+ */
class Bomb:public Source {
public:
+ /// Constructor
Bomb(const std::string &_name);
- ~Bomb();
+ /// Destructor
+ virtual ~Bomb();
virtual void update();
virtual void simulate();
virtual void recieve_msg(int msg, IConector *who, void *data);
+ /// Activa la bomba
void activate() { active = true; }
+ /// Desactiva la bomba
void deactivate() { active = false; }
protected:
/** Define si la bomba esta abierta o no. Esto lo maneja la logica de
namespace PlaQui {
namespace Model {
-
+
+/** Conducto de transporte de fluido
+ *
+ * Un conducto puede modelar tanto a un caño recto como a un
+ * codo. Su principal objetivo es saber que flujo puede pasar por
+ * el y consultar que flujo pasará en cada iteración
+ */
class Conduct:public Transport {
public:
+ /// Constructor
Conduct(const std::string &_name);
+ /// Destructor
virtual ~Conduct();
virtual void recieve_msg(int msg, IConector *who, void *data);
- /// Hace que los elementos de la plata actualicen su flujo en esta etapa
virtual void update();
- /// Hace la simulación de esta iteración
virtual void simulate();
protected:
/** Elementos que pueden ser automatizados */
class Control:public PlantItem {
public:
+ /// Constructor
Control(const std::string &_name);
+ /// Destructor
virtual ~Control();
+ /// Retorna un estado booleano dependiendo de su estado actual
virtual bool get_output() = 0;
protected:
/*
}
#endif // _CONTROL_H_
+
*/
class IConector {
public:
- /// Constructor
+ /** Constructor
+ *
+ * \param in Cantidad de entradas
+ * \param out Cantidad de salidas
+ */
IConector(unsigned in, unsigned out);
/// Destructor
virtual ~IConector();
/** Envía un mensage a los elementos conectados
*
- * Esvía un mensage a los elementos conectados a la entrada o
+ * Envía un mensage a los elementos conectados a la entrada o
* a la salida.
* \param where Donde enviar el mensage, IConector::IN o IConector::OUT
* \param msg Mensage a enviar
namespace PlaQui {
namespace Model {
-
+
+/** Elementos simulables en una planta
+ *
+ * Todo elemento que pueda ser simulado en la planta debe
+ * descender de esta clase.
+ */
class PlantItem:public IConector {
public:
- /// Constructor
+ /** Constructor
+ *
+ * \param _name Nombre único que identifica el objeto
+ */
PlantItem(const std::string &_name);
+ /// FIXME : agregar el nombre!
PlantItem(unsigned ins, unsigned outs);
+ /// Destructor
virtual ~PlantItem();
// FIXME: ver que parametros seran necesarios
+ // TODO : ver si no son inutiles!!!
virtual void send_fluid() {}
virtual void receive_fluid() {}
- /// Hace que los elementos de la plata actualicen su flujo en esta etapa
+ /** Ejecuta la fase de actualización.
+ *
+ * Durante la fase de actualización los objetos se comunican entre
+ * sí para determinar cual es el flujo que manejan en una iteración.
+ */
virtual void update() = 0;
- /// Hace la simulación de esta iteración
+ /** Hace la simulación de esta iteración
+ *
+ * Por simulacion se entiende que el modelo debe avisar a las vistas
+ * que ya está actualizado para que el usuario vea los resultados.
+ */
virtual void simulate() = 0;
/// Setea el nuevo color del fluido
/// Retorna el actual color del fluido
const RGB &getColor() { return fluid_color; }
+ /** Recive un mensage y lo procesa
+ *
+ * \see IConector::recieve_msg
+ */
virtual void recieve_msg(int msg, IConector *who, void *data);
/// Mensages manejados por los elementos de la planta
enum {
- MSG_QUERY_MAX_FLOW = IConector::MSG_LAST, ///< pregunta por el maximo flujo
+ MSG_QUERY_MAX_FLOW = IConector::MSG_LAST, ///< preguntar por el máximo flujo
MSG_RESPONSE_MAX_FLOW, ///< responde al mensage QUERY_MAX_FLOW. data == float
MSG_LAST
};
/** Modela objetos desde donde fluye liquido */
class Source:public Control {
public:
+ /// Constructor
Source(const std::string &_name);
+ /// Destructor
virtual ~Source();
virtual bool get_output();
virtual void simulate();
+ /// Retorna el flujo que entrega actualmente
float get_actual_flow() { return actual_flow; }
+ /// Retorna el flujo máximo capaz de entregar
float get_max_flow() { return max_flow; }
+ /// Asigna el flojo máximo capaz de entregar
void set_max_flow(float _f) { max_flow = _f; }
protected:
float max_flow;
namespace Model {
+/** Elementos que permiten transportar fluidos
+ *
+ * Estos objetos son capaces de transportar fluidos solamente.
+ */
class Transport:public PlantItem {
public:
+ /// Constructor
Transport(const std::string &_name);
+ /// Destructor
virtual ~Transport();
+ /// Retorna el flujo actual que maneja el objeto.
float get_actual_flow() { return actual_flow; }
+ /// Retorna el flujo máximo soportado por el objeto
float get_max_flow() { return max_flow; }
+ /// Asigna el flujo máximo a manejar
void set_max_flow(float _f) { max_flow = _f; }
protected:
// Es de solo lectura, no hay set
--- /dev/null
+
+#ifndef _UNION_H_
+#define _UNION_H_
+
+#include "transport.h"
+
+namespace PlaQui {
+
+namespace Model {
+
+class Union:public Transport {
+public:
+ Union(const std::string &_name);
+ virtual ~Union();
+
+ virtual void recieve_msg(int msg, IConector *who, void *data);
+ virtual void update();
+ virtual void simulate();
+protected:
+private:
+ Union(const Union &):Transport("null") {}
+ Union &operator = (const Union &) { return *this; }
+};
+
+}
+}
+
+#endif //_UNION_H_
std::cout << name << "::Flujo actual = " << ((active && open)?actual_flow:0) \
<< " de " << max_flow;
std::cout << ((active && open)?" (funcionando)":" (apagada)") << std::endl;
+ updated = false;
}
bool Bomb::get_output()
// Seteo mi actualizar en true para evitar entrar de nuevo
actual_flow = 99999;
updated = true;
- send_msg(IN, MSG_QUERY_MAX_FLOW);
send_msg(OUT, MSG_QUERY_MAX_FLOW);
+ send_msg(IN, MSG_QUERY_MAX_FLOW);
}
void Conduct::simulate()
} else {
return false; // no se pudo conectar!
}
+ break;
case OUT:
if (out_list.size() <= out_slots) {
out_list.push_back(obj);
/* Compilar : g++ -Wall -o test -I../include *.cpp */
#include "bomb.h"
#include "conduct.h"
+#include "union.h"
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[])
{
- Bomb *bomba;
+ Bomb *bomba1, *bomba2;
Conduct *canio1;
Conduct *canio2;
+ Conduct *salida;
+ Union *union1;
+
- bomba = new Bomb("bomba");
- bomba->set_max_flow(3);
+ bomba1 = new Bomb("bomba1");
+ bomba1->set_max_flow(3);
+ bomba2 = new Bomb("bomba2");
+ bomba2->set_max_flow(5);
canio1 = new Conduct("cond_1");
- canio1->set_max_flow(10);
+ canio1->set_max_flow(5);
canio2 = new Conduct("cond_2");
canio2->set_max_flow(5);
- bomba->connect(canio1, IConector::OUT);
- canio1->connect(bomba, IConector::IN);
- canio1->connect(canio2, IConector::OUT);
- canio2->connect(canio1, IConector::IN);
+ union1 = new Union("union");
+ union1->set_max_flow(5);
+ salida = new Conduct("salida");
+ salida->set_max_flow(10);
+
+ bomba1->connect(canio1, IConector::OUT);
+ canio1->connect(bomba1, IConector::IN);
+ canio1->connect(union1, IConector::OUT);
+
+ bomba2->connect(canio2, IConector::OUT);
+ canio2->connect(bomba2, IConector::IN);
+ canio2->connect(union1, IConector::OUT);
+
+ union1->connect(canio1, IConector::IN);
+ union1->connect(canio2, IConector::IN);
+ union1->connect(salida, IConector::OUT);
+
+ salida->connect(union1, IConector::IN);
int i = 0;
while (i<10) {
- bomba->update();
+ bomba1->update();
+ bomba2->update();
canio1->update();
canio2->update();
+ salida->update();
+ union1->update();
- bomba->simulate();
+ bomba1->simulate();
+ bomba2->simulate();
canio1->simulate();
canio2->simulate();
+ salida->simulate();
+ union1->simulate();
sleep(1);
if (i == 5) {
- bomba->deactivate();
+ bomba1->deactivate();
}
i++;
}
- delete bomba;
+ delete bomba1;
+ delete bomba2;
delete canio1;
delete canio2;
+ delete salida;
+ delete union1;
return 1;
}
--- /dev/null
+
+#include "union.h"
+#include <iostream>
+
+using namespace PlaQui::Model;
+
+Union::Union(const std::string &_name):Transport(_name)
+{
+ in_slots = 2;
+ out_slots = 1;
+ max_flow = actual_flow = 0.0f;
+}
+
+Union::~Union()
+{
+}
+
+void Union::recieve_msg(int msg, IConector *who, void *data)
+{
+ int pos = OUT;
+
+ // Verifico si esta conectado a mi entrada
+ std::list<IConector *>::iterator i;
+ for(i=in_list.begin(); i!=in_list.end(); i++) {
+ if ((*i) == who) pos = IN;
+ }
+
+ switch (msg) {
+ case MSG_QUERY_MAX_FLOW: {
+ // Me preguntan por el flujo máximo.
+ // Primero me actualizo, y luego respondo
+ update();
+ float tmp;
+
+ tmp = (actual_flow<max_flow)?actual_flow:max_flow;
+ if (pos == IN) {
+ // Si esta conectado a mi entrada, le puedo aceptar
+ // solo la mitad del flujo maximo
+ tmp /= 2;
+ }
+ who->recieve_msg(MSG_RESPONSE_MAX_FLOW, this, &tmp);
+ }
+ break;
+ case MSG_RESPONSE_MAX_FLOW: {
+ float max = *((float *)data);
+ if (pos == OUT) {
+ if (max < actual_flow) actual_flow = max;
+ } else {
+ if ((2*max) < actual_flow) actual_flow = 2*max;
+ }
+ }
+ break;
+ default:
+ Transport::recieve_msg(msg, who, data);
+ }
+}
+
+void Union::update()
+{
+ // Si ya me actualice, no lo tengo que hacer de nuevo
+ if (updated) return;
+ // Seteo mi actualizar en true para evitar entrar de nuevo
+ actual_flow = 99999;
+ updated = true;
+ send_msg(OUT, MSG_QUERY_MAX_FLOW);
+ send_msg(IN, MSG_QUERY_MAX_FLOW);
+}
+
+void Union::simulate()
+{
+ if (!updated) {
+ return;
+ }
+
+ std::cout << name << "::Flujo actual = " << actual_flow << std::endl;
+ updated = false;
+}
+