rotate(0),
pitch(0)
{
- cout<<"blah?\n";
catalogue.load("tracks.dat");
- cout<<catalogue.get_tracks().size()<<'\n';
cat_layout=new Layout(catalogue);
cat_layout_3d=new Layout3D(*cat_layout);
glEnable(GL_CULL_FACE);
font=new GL::Font();
- Parser::load(*font, "dejavu.font");
+ Parser::load(*font, "dejavu-20.font");
mode=SELECT;
#include <GL/gl.h>
#include <msp/core/error.h>
#include <msp/core/getopt.h>
+#include <msp/gl/matrix.h>
+#include <msp/gl/transform.h>
+#include <msp/strings/formatter.h>
#include <msp/strings/lexicalcast.h>
#include <msp/strings/regex.h>
#include "engineer.h"
layout(catalogue),
layout_3d(layout),
no_lighting(false),
- placing_train(0)
+ placing_train(0),
+ placing_block(0),
+ placing_entry(0),
+ simulate(false)
{
string res;
bool debug=false;
getopt.add_option('g', "debug", debug, GetOpt::NO_ARG);
getopt.add_option('d', "device", device, GetOpt::REQUIRED_ARG);
getopt.add_option('q', "quality", quality, GetOpt::REQUIRED_ARG);
+ getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG);
getopt.add_option( "no-lighting", no_lighting, GetOpt::NO_ARG);
getopt(argc, argv);
throw UsageError("No layout given");
layout.load(args.front());
+ control.signal_sensor_event.connect(sigc::mem_fun(this, &Engineer::sensor_event));
+
trfc_mgr=new TrafficManager(control, layout);
+ trfc_mgr->signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved));
view_all();
-
- /*const TrackSeq &tracks=layout.get_tracks();
-
- for(TrackSeq::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
- {
- if(unsigned trnt_id=(*i)->get_turnout_id())
- {
- Turnout *trnt=new Turnout(control, trnt_id);
- trnt->signal_route_changed.connect(sigc::mem_fun(this, &Engineer::turnout_route_changed));
- }
- if(unsigned sens_id=(*i)->get_sensor_id())
- {
- Sensor *sens=new Sensor(control, sens_id);
- sens->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Engineer::sensor_state_changed), sens_id));
- }
- }*/
}
Engineer::~Engineer()
{
+ delete trfc_mgr;
}
void Engineer::add_train(unsigned addr)
Locomotive *loco=new Locomotive(control, addr);
Train *train=new Train(*trfc_mgr, *loco);
+ train->set_name(format("Train %d", trfc_mgr->get_trains().size()));
TrainPanel *tpanel=new TrainPanel(*this, ui_res, *train);
int y=main_panel->get_geometry().y;
train_panels.push_back(tpanel);
placing_train=train;
+ placing_block=0;
+ status_text="Select train location";
}
int Engineer::main()
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- font=new GL::Font();
- if(screen_w>=1024)
- {
- font_size=20;
- Parser::load(*font, "dejavu-20.font");
- }
- else
- {
- font_size=12;
- Parser::load(*font, "dejavu-12.font");
- }
-
Parser::load(ui_res, "engineer.res");
main_panel=new MainPanel(*this, ui_res);
main_panel->set_position(0, screen_h-main_panel->get_geometry().h);
Application::main();
- delete font;
delete main_panel;
+ for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
+ delete *i;
SDL_Quit();
(*i)->render_route(-1);
}
+ if(placing_train && placing_block)
+ {
+ float rot=placing_entry->track->get_rotation()+placing_entry->track_ep->rot;
+ Point pos=placing_entry->track->get_endpoint_position(*placing_entry->track_ep);
+ GL::push_matrix();
+ GL::translate(pos.x, pos.y, pos.z+0.03);
+ GL::rotate(rot*180/M_PI+180, 0, 0, 1);
+ GL::Texture::unbind();
+ glColor4f(1, 1, 1, 1);
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(0.08, 0);
+ glVertex2f(0.05, 0.03);
+ glVertex2f(0.05, 0.01);
+ glVertex2f(0, 0.01);
+ glVertex2f(0, -0.01);
+ glVertex2f(0.05, -0.01);
+ glVertex2f(0.05, -0.03);
+ glEnd();
+ GL::pop_matrix();
+ }
+
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, screen_w, 0, screen_h, 0, 1);
for(TrainPanelSeq::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
(*i)->render();
- glLoadIdentity();
- glTranslatef(340, 10, 0);
- glScalef(20, 20, 20);
+ const GL::Font &font=ui_res.get_font("dejavu-12");
+ GL::load_identity();
+ GL::translate(340, 10, 0);
+ GL::scale_uniform(font.get_default_size());
glColor4f(1, 1, 1, 1);
- font->draw_string(status_text);
+ font.draw_string(status_text);
SDL_GL_SwapBuffers();
}
return;
}
- Track3D *track=pick_track(x, y);
- if(track)
+ if(placing_train)
{
- if(placing_train)
+ if(btn==1 && placing_block)
{
- Block *block=trfc_man->get_block_by_track(&track->get_track());
+ set_block_color(*placing_block, Color(1, 1, 1));
+
+ placing_train->place(placing_block, placing_entry);
+ placing_train=0;
}
- else
+ else if(btn==3)
+ {
+ const Block::EndpointSeq &endpoints=placing_block->get_endpoints();
+ Block::EndpointSeq::const_iterator i;
+ for(i=endpoints.begin(); i!=endpoints.end(); ++i)
+ if(&*i==placing_entry)
+ break;
+ ++i;
+ if(i==endpoints.end())
+ i=endpoints.begin();
+ placing_entry=&*i;
+ }
+ }
+ else
+ {
+ Track3D *track=pick_track(x, y);
+ if(track)
{
Turnout *turnout=control.get_turnout(track->get_track().get_turnout_id());
if(turnout)
turnout->set_route(1-turnout->get_route());
+ else if(simulate)
+ {
+ Sensor *sensor=control.get_sensor(track->get_track().get_sensor_id());
+ if(sensor)
+ control.signal_sensor_event.emit(track->get_track().get_sensor_id(), !sensor->get_state());
+ }
}
}
}
}
Track3D *track=pick_track(x, y);
- if(track && track->get_track().get_turnout_id())
+ if(track && placing_train)
+ {
+ Block *block=trfc_mgr->get_block_by_track(&track->get_track());
+ if(block!=placing_block)
+ {
+ if(placing_block)
+ set_block_color(*placing_block, Color(1, 1, 1));
+ placing_block=block;
+ placing_entry=&block->get_endpoints().front();
+ set_block_color(*placing_block, Color(0.5, 1, 0.7));
+ }
+ }
+ else if(track && track->get_track().get_turnout_id())
{
ostringstream ss;
ss<<"Turnout "<<track->get_track().get_turnout_id();
status_text=ss.str();
}
- else
+ else if(!placing_train)
status_text="";
}
cam_pos.z=max(best_height*1.05/0.82843, 0.15);
}
-void Engineer::turnout_route_changed(unsigned)
+void Engineer::set_block_color(const Block &block, const Color &color)
{
+ const TrackSet &tracks=block.get_tracks();
+ for(TrackSet::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
+ layout_3d.get_track(*i)->set_color(color);
}
-void Engineer::sensor_state_changed(bool state, unsigned addr)
+void Engineer::sensor_event(unsigned addr, bool state)
{
+ cout<<"sensor_event "<<state<<" @ "<<addr<<'\n';
const Track3DSeq <racks=layout_3d.get_tracks();
for(Track3DSeq::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
if((*i)->get_track().get_sensor_id()==addr)
{
if(state)
- (*i)->set_color(Color(1, 0, 0));
+ (*i)->set_color(Color(1, 0.5, 0.3));
else
(*i)->set_color(Color(1, 1, 1));
}
}
+void Engineer::block_reserved(const Block &block, const Train *train)
+{
+ if(Sensor *sensor=control.get_sensor(block.get_sensor_id()))
+ if(sensor->get_state())
+ return;
+
+ if(train)
+ set_block_color(block, Color(1, 1, 0.3));
+ else
+ set_block_color(block, Color(1, 1, 1));
+}
+
void Engineer::project_3d()
{
glMatrixMode(GL_PROJECTION);
glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
return layout_3d.pick_track(xx, yy, size);
-
- /*unsigned select_buf[1024];
- glSelectBuffer(1024, select_buf);
- glRenderMode(GL_SELECT);
-
- //XXX Hardcoded values
- float xn=((float)(x-800)/960)*0.082843;
- float yn=((float)(y-480)/960)*0.082843;
- float size=(float)4/960*0.082843;
-
- project_3d();
- glLoadIdentity();
-
- double clip[4];
- clip[0]=0.1;
- clip[1]=0;
- clip[2]=xn-size;
- clip[3]=0;
- glClipPlane(GL_CLIP_PLANE0, clip);
- glEnable(GL_CLIP_PLANE0);
-
- clip[0]=-0.1;
- clip[2]=-(xn+size);
- glClipPlane(GL_CLIP_PLANE1, clip);
- glEnable(GL_CLIP_PLANE1);
-
- clip[0]=0;
- clip[1]=0.1;
- clip[2]=yn-size;
- glClipPlane(GL_CLIP_PLANE2, clip);
- glEnable(GL_CLIP_PLANE2);
-
- clip[1]=-0.1;
- clip[2]=-(yn+size);
- glClipPlane(GL_CLIP_PLANE3, clip);
- glEnable(GL_CLIP_PLANE3);
-
- glRotatef(-cam_rot*180/M_PI, 0, 0, 1);
- glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z);
-
- layout_3d.render();
-
- glDisable(GL_CLIP_PLANE0);
- glDisable(GL_CLIP_PLANE1);
- glDisable(GL_CLIP_PLANE2);
- glDisable(GL_CLIP_PLANE3);
-
- unsigned n_records=glRenderMode(GL_RENDER);
- if(n_records)
- {
- Track *track=0;
- unsigned i=0;
- unsigned track_depth=numeric_limits<unsigned>::max();
- for(unsigned j=0; j<n_records; ++j)
- {
- unsigned ns_size=select_buf[i++];
- unsigned min_depth=select_buf[i++];
- ++i; // Skip max_depth
- if(min_depth<track_depth)
- {
- track=(Track *)select_buf[i+ns_size-1];
- track_depth=min_depth;
- }
- i+=ns_size;
- }
-
- return track;
- }
-
- return 0;*/
}
Application::RegApp<Engineer> Engineer::reg;
#include "libmarklin/catalogue.h"
#include "libmarklin/control.h"
#include "libmarklin/trafficmanager.h"
+#include "libmarklin/train.h"
#include "3d/layout.h"
class MainPanel;
~Engineer();
Marklin::Control &get_control() { return control; }
- unsigned get_screen_width() const { return screen_w; }
- unsigned get_screen_height() const { return screen_h; }
- unsigned get_font_size() const { return font_size; }
- Msp::GL::Font &get_font() { return *font; }
void add_train(unsigned);
int main();
void quit() { exit(0); }
unsigned screen_w;
unsigned screen_h;
- unsigned font_size;
bool fullscreen;
- Msp::GL::Font *font;
Marklin::Catalogue catalogue;
Marklin::Layout layout;
Marklin::Layout3D layout_3d;
std::string status_text;
bool no_lighting;
Marklin::TrafficManager *trfc_mgr;
- Train *placing_train;
+ Marklin::Train *placing_train;
+ Marklin::Block *placing_block;
+ const Marklin::Block::Endpoint *placing_entry;
+ bool simulate;
void tick();
void key_press(unsigned, unsigned);
void button_release(int, int, unsigned);
void pointer_motion(int, int);
void view_all();
- void turnout_route_changed(unsigned);
- void sensor_state_changed(bool, unsigned);
+ void set_block_color(const Marklin::Block &, const Marklin::Color &);
+ void sensor_event(unsigned, bool);
+ void block_reserved(const Marklin::Block &, const Marklin::Train *);
void project_3d();
Marklin::Track3D *pick_track(int, int);
GLtk::Button *btn;
add(*(btn=new GLtk::Button(res, "Off")));
- btn->set_geometry(GLtk::Geometry(10, 50, 40, 25));
+ btn->set_geometry(GLtk::Geometry(10, 53, 40, 25));
btn->set_style("red");
btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::power_off));
ind_off->set_style("red");
add(*(btn=new GLtk::Button(res, "On")));
- btn->set_geometry(GLtk::Geometry(50, 50, 40, 25));
+ btn->set_geometry(GLtk::Geometry(50, 53, 40, 25));
btn->set_style("green");
btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::power_on));
ind_on->set_style("green");
add(*(btn=new GLtk::Button(res, "Quit")));
- btn->set_geometry(GLtk::Geometry(150, 50, 40, 25));
+ btn->set_geometry(GLtk::Geometry(150, 53, 40, 25));
btn->set_style("red");
btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::quit));
#include <msp/gltk/button.h>
+#include <msp/strings/formatter.h>
+#include "libmarklin/locomotive.h"
#include "trainpanel.h"
using namespace Msp;
{
set_size(200, 100);
- add(*(lbl_name=new GLtk::Label(res, "Train 1")));
+ add(*(lbl_name=new GLtk::Label(res, train.get_name())));
lbl_name->set_style("digital");
lbl_name->set_geometry(GLtk::Geometry(10, geom.h-34, 140, 24));
+ train.signal_name_changed.connect(sigc::mem_fun(lbl_name, &GLtk::Label::set_text));
GLtk::Button *btn;
sld_speed->set_step(1);
sld_speed->signal_value_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_slider_changed));
- add(*(btn=new GLtk::Button(res, "Place")));
- btn->set_geometry(GLtk::Geometry(150, geom.h-75, 40, 24));
+ add(*(lbl_speed=new GLtk::Label(res, " 0")));
+ lbl_speed->set_style("digital");
+ lbl_speed->set_geometry(GLtk::Geometry(10, geom.h-75, 36, 24));
+ train.get_locomotive().signal_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::loco_speed_changed));
}
void TrainPanel::speed_slider_changed(double v)
{
train.set_speed(static_cast<unsigned>(v));
}
+
+void TrainPanel::loco_speed_changed(unsigned speed)
+{
+ lbl_speed->set_text(format("%2d", speed));
+}
Msp::GLtk::Label *lbl_name;
Msp::GLtk::HSlider *sld_speed;
Marklin::Locomotive *loco;
+ Msp::GLtk::Label *lbl_speed;
void speed_slider_changed(double);
+ void loco_speed_changed(unsigned);
};
#endif
if(i->track==track && i->track_ep==other_ep)
return &*i;
- track_ep=track->get_endpoint_by_link(other_ep->link);
+ track_ep=other_ep->link->get_endpoint_by_link(track);
track=other_ep->link;
if(tracks.count(track)==0)
if(!t || !train)
{
train=t;
+ cout<<"Block "<<this<<" reserved for train "<<train<<'\n';
+ trfc_mgr.signal_block_reserved.emit(*this, train);
return true;
}
else
-#ifndef MARKLIN_3D_SECTION_H_
-#define MARKLIN_3D_SECTION_H_
+#ifndef MARKLIN_3D_BLOCK_H_
+#define MARKLIN_3D_BLOCK_H_
#include <list>
#include <set>
Block(TrafficManager &, Track *);
unsigned get_sensor_id() const { return sensor_id; }
const TrackSet &get_tracks() const { return tracks; }
+ const EndpointSeq &get_endpoints() const { return endpoints; }
const Endpoint *get_endpoint_by_link(const Block *) const;
const Endpoint *traverse(const Endpoint *) const;
void check_link(Block &);
Control::~Control()
{
+ for(SensorMap::iterator i=sensors.begin(); i!=sensors.end(); ++i)
+ delete i->second;
+ for(TurnoutMap::iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
+ delete i->second;
+ for(LocomotiveSeq::iterator i=locomotives.begin(); i!=locomotives.end(); ++i)
+ delete *i;
close(serial_fd);
}
speed=min(spd, 14U);
send_command(false);
+
+ signal_speed_changed.emit(speed);
}
void Locomotive::set_reverse(bool rev)
cmd[0]=CMD_LOK_STATUS;
cmd[1]=addr&0xFF;
cmd[2]=(addr>>8)&0xFF;
- control.command(string(cmd,3)).signal_done.connect(sigc::mem_fun(this,&Locomotive::status_reply));
+ control.command(string(cmd, 3)).signal_done.connect(sigc::mem_fun(this, &Locomotive::status_reply));
}
void Locomotive::send_command(bool setf)
#include <list>
#include <string>
+#include <sigc++/signal.h>
#include "constants.h"
namespace Marklin {
class Locomotive
{
public:
+ sigc::signal<void, unsigned> signal_speed_changed;
+
Locomotive(Control &, unsigned);
void set_speed(unsigned);
void set_reverse(bool);
return 0;
}
+Point Track::get_endpoint_position(const Endpoint &ep) const
+{
+ float c=cos(rot);
+ float s=sin(rot);
+ return Point(pos.x+c*ep.pos.x-s*ep.pos.y, pos.y+s*ep.pos.x+c*ep.pos.y, pos.z+ep.pos.z);
+}
+
float Track::get_length() const
{
float len=parts.front().length;
float limit=(link && !flex) ? 1e-6 : 1e-4;
for(EndpointSeq::iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
{
- float x=pos.x+i->pos.x*cos(rot)-i->pos.y*sin(rot);
- float y=pos.y+i->pos.y*cos(rot)+i->pos.x*sin(rot);
+ Point epp=get_endpoint_position(*i);
for(EndpointSeq::iterator j=other.endpoints.begin(); j!=other.endpoints.end(); ++j)
{
if(j->link)
continue;
- float x2=other.pos.x+j->pos.x*cos(other.rot)-j->pos.y*sin(other.rot);
- float y2=other.pos.y+j->pos.y*cos(other.rot)+j->pos.x*sin(other.rot);
- float dx=x2-x;
- float dy=y2-y;
+ Point epp2=other.get_endpoint_position(*j);
+ float dx=epp2.x-epp.x;
+ float dy=epp2.y-epp.y;
if(dx*dx+dy*dy<limit)
{
set_rotation(other.rot+j->rot-i->rot+M_PI);
- set_position(Point(x2-(i->pos.x*cos(rot)-i->pos.y*sin(rot)), y2-(i->pos.y*cos(rot)+i->pos.x*sin(rot)), other.pos.z+j->pos.z-i->pos.z));
+ set_position(Point(epp2.x-(i->pos.x*cos(rot)-i->pos.y*sin(rot)), epp2.y-(i->pos.y*cos(rot)+i->pos.x*sin(rot)), other.pos.z+j->pos.z-i->pos.z));
if(link)
{
if(i->link)
{
for(EndpointSeq::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
{
- float x=pos.x+i->pos.x*cos(rot)-i->pos.y*sin(rot);
- float y=pos.y+i->pos.y*cos(rot)+i->pos.x*sin(rot);
- float dx=pt.x-x;
- float dy=pt.y-y;
+ Point epp=get_endpoint_position(*i);
+ float dx=pt.x-epp.x;
+ float dy=pt.y-epp.y;
if(dx*dx+dy*dy<1e-4)
{
- pt.x=x;
- pt.y=y;
+ pt=epp;
d=rot+i->rot;
return true;
}
const PartSeq &get_parts() const { return parts; }
const EndpointSeq &get_endpoints() const { return endpoints; }
const Endpoint *get_endpoint_by_link(Track *) const;
+ Point get_endpoint_position(const Endpoint &) const;
const std::string &get_description() const { return description; }
float get_slope() const { return slope; }
bool get_flex() const { return flex; }
}
}
+TrafficManager::~TrafficManager()
+{
+ for(BlockSeq::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ delete *i;
+ for(TrainSeq::iterator i=trains.begin(); i!=trains.end(); ++i)
+ delete *i;
+}
+
Block *TrafficManager::get_block_by_track(const Track *t) const
{
for(BlockSeq::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
class TrafficManager
{
public:
+ sigc::signal<void, const Block &, const Train *> signal_block_reserved;
+
TrafficManager(Control &, Layout &);
+ ~TrafficManager();
+
Control &get_control() const { return control; }
Block *get_block_by_track(const Track *) const;
+ const TrainSeq &get_trains() const { return trains; }
void add_train(Train *);
private:
Control &control;
#include "trafficmanager.h"
#include "train.h"
+#include <iostream>
+using namespace std;
+
namespace Marklin {
Train::Train(TrafficManager &tm, Locomotive &l):
trfc_mgr.get_control().signal_sensor_event.connect(sigc::mem_fun(this, &Train::sensor_event));
}
+void Train::set_name(const string &n)
+{
+ name=n;
+
+ signal_name_changed.emit(name);
+}
+
void Train::set_speed(unsigned speed)
{
target_speed=speed;
void Train::sensor_event(unsigned addr, bool state)
{
+ if(!loco.get_speed())
+ return;
+
if(state)
{
BlockRefSeq::iterator i;
for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
if(i->block->get_sensor_id() && i->block->get_sensor_id()!=addr)
break;
- cur_blocks.splice(cur_blocks.begin(), rsv_blocks, rsv_blocks.begin(), i);
+ cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
+
+ cout<<"Train advanced, "<<cur_blocks.size()<<" cur_blocks, "<<rsv_blocks.size()<<" rsv_blocks\n";
reserve_more();
if(rsv_blocks.empty())
}
else
{
+ cout<<"Finding blocks to free\n";
BlockRefSeq::iterator i;
for(i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
if(i->block->get_sensor_id()==addr)
break;
if(i!=cur_blocks.end())
{
+ cout<<"found\n";
++i;
for(BlockRefSeq::iterator j=cur_blocks.begin(); j!=i; ++j)
j->block->reserve(0);
cur_blocks.erase(cur_blocks.begin(), i);
+ cout<<cur_blocks.size()<<" cur_blocks\n";
}
reserve_more();
while(size<5)
{
const Block::Endpoint *exit=last->block->traverse(last->entry);
- if(exit->link->reserve(this))
+ if(exit && exit->link->reserve(this))
{
rsv_blocks.push_back(BlockRef(exit->link, exit->link->get_endpoint_by_link(last->block)));
last=&rsv_blocks.back();
#ifndef LIBMARKLIN_TRAIN_H_
#define LIBMARKLIN_TRAIN_H_
+#include <sigc++/signal.h>
#include <sigc++/trackable.h>
#include "block.h"
class Train: public sigc::trackable
{
public:
+ sigc::signal<void, const std::string &> signal_name_changed;
+
Train(TrafficManager &, Locomotive &);
- const std::string &get_name() const { return name; }
+ void set_name(const std::string &);
void set_speed(unsigned);
+ const std::string &get_name() const { return name; }
+ Locomotive &get_locomotive() const { return loco; }
void place(Block *, const Block::Endpoint *);
bool free_block(Block *);
void tick();