#include <signal.h>
#include <cmath>
-#include <iostream>
#include <GL/gl.h>
+#include <msp/gl/matrix.h>
+#include <msp/gl/misc.h>
+#include <msp/gl/projection.h>
#include <msp/gl/rendermode.h>
#include <msp/gl/select.h>
+#include <msp/gl/tests.h>
#include <msp/gl/texture2d.h>
#include <msp/input/keys.h>
+#include <msp/io/print.h>
#include <msp/strings/codec.h>
#include <msp/strings/lexicalcast.h>
#include <msp/strings/utf8.h>
#include "manipulator.h"
#include "measure.h"
#include "selection.h"
+#include "toolbar.h"
using namespace std;
using namespace Marklin;
screen_w(1280),
screen_h(960),
base_mesh(0),
+ cur_route(0),
mode(SELECT),
input(0),
cam_yaw(M_PI/2),
if(argc>1)
{
+ filename = argv[1];
DataFile::load(*layout, argv[1]);
const list<Track3D *> <racks = layout_3d->get_tracks();
for(list<Track3D *>::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i)
- {
- if((*i)->get_track().get_sensor_id())
- (*i)->set_color(GL::Color(1, 1, 0.5));
- else if((*i)->get_track().get_turnout_id())
- (*i)->set_color(GL::Color(0.5, 1, 1));
- else if((*i)->get_track().get_flex())
- (*i)->set_color(GL::Color(1, 0.5, 1));
- }
+ update_track_color(**i);
if(!layout->get_base().empty())
{
dpy = new Graphics::Display;
wnd = new Graphics::Window(*dpy, screen_w, screen_h);
glc = new Graphics::GLContext(*wnd);
+ wnd->set_title("Railway Designer");
wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &Designer::exit), 0));
- wnd->signal_key_press.connect(sigc::mem_fun(this, &Designer::key_press));
- wnd->signal_key_release.connect(sigc::mem_fun(this, &Designer::key_release));
- wnd->signal_button_press.connect(sigc::mem_fun(this, &Designer::button_press));
- wnd->signal_pointer_motion.connect(sigc::mem_fun(this, &Designer::pointer_motion));
-
wnd->show();
glEnableClientState(GL_VERTEX_ARRAY);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
- GL::Texture2D *font_tex = new GL::Texture2D;
- font_tex->set_min_filter(GL::LINEAR);
- font_tex->load_image("dejavu-20.png");
- font = new GL::Font();
- font->set_texture(*font_tex);
- DataFile::load(*font, "dejavu-20.font");
+ DataFile::load(ui_res, "marklin.res");
+ root = new GLtk::Root(ui_res, *wnd);
+
+ lbl_tooltip = new GLtk::Label(ui_res);
+ lbl_tooltip->set_style("tooltip");
+ root->add(*lbl_tooltip);
+ lbl_tooltip->set_visible(false);
+
+ toolbar = new Toolbar(*this);
+ root->add(*toolbar);
+ toolbar->set_position(0, screen_h-toolbar->get_geometry().h);
+ toolbar->set_visible(true);
+
+
+ wnd->signal_key_press.connect(sigc::mem_fun(this, &Designer::key_press));
+ wnd->signal_key_release.connect(sigc::mem_fun(this, &Designer::key_release));
+ wnd->signal_button_press.connect(sigc::mem_fun(this, &Designer::button_press));
+ wnd->signal_pointer_motion.connect(sigc::mem_fun(this, &Designer::pointer_motion));
mode = SELECT;
Application::main();
- delete font;
- delete font_tex;
- delete input;
+ delete root;
delete glc;
delete wnd;
return exit_code;
}
+void Designer::save()
+{
+ input = new ::Input(*this, "Save layout", filename);
+ input->signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss));
+ input->signal_accept.connect(sigc::mem_fun(this, &Designer::save_accept));
+ mode = INPUT;
+}
+
+void Designer::quit()
+{
+ exit(0);
+}
+
+void Designer::edit_route(Route &r)
+{
+ cur_route = &r;
+}
+
+void Designer::add_selection_to_route()
+{
+ if(!cur_route)
+ return;
+
+ try
+ {
+ const set<Track *> &stracks = selection->get_tracks();
+ set<const Track *> tracks(stracks.begin(), stracks.end());
+ cur_route->add_tracks(tracks);
+ }
+ catch(const Exception &e)
+ {
+ IO::print("%s\n", e.what());
+ }
+}
+
void Designer::map_pointer_coords(int x, int y, float &gx, float &gy)
{
float cos_pitch = cos(cam_pitch);
{
const Track &track = t3d->get_track();
const TrackType &ttype = track.get_type();
- ostringstream ss;
- ss.precision(2);
- ss<<ttype.get_article_number()<<' '<<ttype.get_description();
- if(mode!=CATALOGUE)
- ss<<" (slope "<<track.get_slope()/ttype.get_total_length()*100<<"%)";
+ string info = format("%d %s", ttype.get_article_number(), ttype.get_description());
+ if(mode!=CATALOGUE && abs(track.get_slope())>1e-4)
+ info += format(" (slope %.1f%%)", abs(track.get_slope()/ttype.get_total_length()*100));
if(track.get_turnout_id())
- ss<<" (turnout "<<track.get_turnout_id()<<')';
+ info += format(" (turnout %d)", track.get_turnout_id());
else if(track.get_sensor_id())
- ss<<" (sensor "<<track.get_sensor_id()<<')';
- tooltip = ss.str();
+ info += format(" (sensor %d)", track.get_sensor_id());
- move_tooltip(pointer_x, pointer_y);
+ set_tooltip(pointer_x, pointer_y, info);
}
else
- tooltip.clear();
+ clear_tooltip();
tooltip_timeout = Msp::Time::TimeStamp();
}
glc->swap_buffers();
}
-/*** private ***/
-
-void Designer::key_press(unsigned code, unsigned mod, wchar_t ch)
+void Designer::key_press(unsigned code, unsigned mod, wchar_t)
{
unsigned key = Msp::Input::key_from_sys(code);
if(mode==INPUT)
- {
- input->key_press(key, mod, ch);
return;
- }
if(key==Msp::Input::KEY_SHIFT_L || key==Msp::Input::KEY_SHIFT_R)
shift = true;
mode = MANIPULATE;
}
else if(key==Msp::Input::KEY_W)
- {
- input = new ::Input(*this, "Filename");
- input->signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss));
- input->signal_accept.connect(sigc::mem_fun(this, &Designer::save_accept));
- mode = INPUT;
- }
+ save();
else if(key==Msp::Input::KEY_PLUS)
selection->select_more();
else if(key==Msp::Input::KEY_L && (mod&1))
float len = 0;
for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
len += (*i)->get_type().get_total_length();
- cout<<"Total length: "<<len<<"m\n";
+ IO::print("Total length: %.1fm\n", len);
}
else if(key==Msp::Input::KEY_L)
selection->select_linked();
if(*j!=*i)
(*i)->snap_to(**j, true);
- Track3D &t3d = layout_3d->get_track(**i);
- if((*i)->get_flex())
- t3d.set_color(GL::Color(1, 0.5, 1));
- else
- t3d.set_color(GL::Color(1, 1, 1));
+ update_track_color(layout_3d->get_track(**i));
}
}
else if(key==Msp::Input::KEY_F)
else if(key==Msp::Input::KEY_T)
{
Track *track = selection->get_track();
- if(selection->size()==1 && track->get_type().get_n_routes()>1)
+ if(selection->size()==1 && track->get_type().get_n_paths()>1)
{
- ostringstream ss;
- ss<<track->get_turnout_id();
- input = new ::Input(*this, "Turnout ID", ss.str());
+ input = new ::Input(*this, "Turnout ID", lexical_cast(track->get_turnout_id()));
input->signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss));
input->signal_accept.connect(sigc::mem_fun(this, &Designer::turnout_id_accept));
mode = INPUT;
int id = -1;
for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
{
- if((*i)->get_type().get_n_routes()==1)
+ if((*i)->get_type().get_n_paths()==1)
ok = true;
if(static_cast<int>((*i)->get_sensor_id())!=id)
{
}
if(ok)
{
- ostringstream ss;
- if(id>=0)
- ss<<id;
- input = new ::Input(*this, "Sensor ID", ss.str());
+ input = new ::Input(*this, "Sensor ID", (id>=0 ? lexical_cast(id) : string()));
input->signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss));
input->signal_accept.connect(sigc::mem_fun(this, &Designer::sensor_id_accept));
mode = INPUT;
}
}
+ else if(key==Msp::Input::KEY_A)
+ add_selection_to_route();
else if(key==Msp::Input::KEY_RIGHT)
rotate = -1;
else if(key==Msp::Input::KEY_LEFT)
{
y = screen_h-y-1;
- float gx, gy;
- map_pointer_coords(x, y, gx, gy);
+ pointer_x = x;
+ pointer_y = y;
if(mode==SELECT || mode==CATALOGUE)
- {
- pointer_x = x;
- pointer_y = y;
tooltip_timeout = Msp::Time::now()+100*Msp::Time::msec;
- }
+
+ clear_tooltip();
if(mode!=INPUT)
{
+ float gx, gy;
+ map_pointer_coords(x, y, gx, gy);
manipulator->pointer_motion(x, y, gx, gy);
measure->pointer_motion(x, y, gx, gy);
}
-
- if(mode==MEASURE || mode==MANIPULATE)
- move_tooltip(x, y);
}
void Designer::project_3d()
void Designer::render()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
+ GL::enable(GL::DEPTH_TEST);
project_3d();
apply_camera();
base_mesh->draw();
}
layout_3d->render(true);
+ if(cur_route)
+ {
+ glColor4f(0.5, 0.8, 1.0, 1.0);
+ const set<const Track *> &rtracks = cur_route->get_tracks();
+ const map<unsigned, int> &turnouts = cur_route->get_turnouts();
+ for(set<const Track *>::const_iterator i=rtracks.begin(); i!=rtracks.end(); ++i)
+ {
+ unsigned path = 0;
+ if(unsigned tid=(*i)->get_turnout_id())
+ {
+ map<unsigned, int>::const_iterator j = turnouts.find(tid);
+ if(j!=turnouts.end())
+ path = j->second;
+ }
+ layout_3d->get_track(**i).render_path(path);
+ }
+ }
manipulator->render();
if(mode==MEASURE)
measure->render();
}
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, screen_w, 0, screen_h, 0, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ GL::matrix_mode(GL::PROJECTION);
+ GL::load_identity();
+ GL::ortho_bottomleft(screen_w, screen_h);
+ GL::matrix_mode(GL::MODELVIEW);
+ GL::load_identity();
- glDisable(GL_DEPTH_TEST);
+ GL::disable(GL::DEPTH_TEST);
- if(!tooltip.empty())
- {
- glTranslatef(tooltip_x, tooltip_y, 0);
- glScalef(20, 20, 20);
- float width = font->get_string_width(tooltip);
- glColor4f(0, 0, 0, 0.5);
- glBegin(GL_QUADS);
- glVertex2f(0, 0);
- glVertex2f(width, 0);
- glVertex2f(width, 1);
- glVertex2f(0, 1);
- glEnd();
- glColor4f(1, 1, 1, 1);
- font->draw_string(tooltip);
- }
-
- if(mode==INPUT)
- input->render();
+ root->render();
}
Track3D *Designer::pick_track(int x, int y)
return l->pick_track(xx, yy, size);
}
+void Designer::update_track_color(Track3D &track)
+{
+ if(track.get_track().get_sensor_id())
+ {
+ if(track.get_track().get_flex())
+ track.set_color(GL::Color(1, 0.6, 1));
+ else
+ track.set_color(GL::Color(0.7, 0.7, 1));
+ }
+ else if(track.get_track().get_turnout_id())
+ track.set_color(GL::Color(0.8, 1, 0.8));
+ else if(track.get_track().get_flex())
+ track.set_color(GL::Color(1, 0.8, 0.8));
+ else
+ track.set_color(GL::Color(1, 1, 1));
+}
+
void Designer::manipulation_status(const string &status)
{
- tooltip = status;
+ set_tooltip(pointer_x, pointer_y, status);
}
void Designer::manipulation_done(bool)
float perpd = measure->get_perpendicular_distance()*1000;
float d = sqrt(pard*pard+perpd*perpd);
float adiff = measure->get_angle_difference()*180/M_PI;
- ostringstream ss;
- ss.precision(3);
- ss<<"Par "<<pard<<"mm - Perp "<<perpd<<"mm - Total "<<d<<"mm - Angle "<<adiff<<"°";
- tooltip = ss.str();
+ string info = format("Par %.1fmm - Perp %.1fmm - Total %.1fmm - Angle %.1f°", pard, perpd, d, adiff);
+ set_tooltip(pointer_x, pointer_y, info);
}
void Designer::measure_done()
mode = SELECT;
}
-void Designer::move_tooltip(int x, int y)
+void Designer::set_tooltip(int x, int y, const std::string &text)
+{
+ int fontsize = ui_res.get_default_font().get_default_size();
+ int h = fontsize+6;
+ int w = static_cast<int>(ui_res.get_default_font().get_string_width(text)*fontsize)+6;
+ x = max(min(static_cast<int>(screen_w)-w, x), 0);
+ y = max(min(static_cast<int>(screen_h)-h, y), 0);
+ lbl_tooltip->set_text(text);
+ lbl_tooltip->set_geometry(GLtk::Geometry(x, y, w, h));
+ lbl_tooltip->set_visible(true);
+}
+
+void Designer::clear_tooltip()
{
- int w = static_cast<int>(font->get_string_width(tooltip)*20);
- tooltip_x = max(min(static_cast<int>(screen_w)-w, x), 0);
- tooltip_y = max(min(static_cast<int>(screen_h)-20, y), 0);
+ lbl_tooltip->set_visible(false);
}
void Designer::save_accept()
unsigned id = lexical_cast<unsigned>(input->get_text());
track->set_turnout_id(id);
- Track3D &t3d = layout_3d->get_track(*track);
- if(id)
- t3d.set_color(GL::Color(0.5, 1, 1));
- else
- t3d.set_color(GL::Color(1, 1, 1));
+ update_track_color(layout_3d->get_track(*track));
input_dismiss();
}
{
(*i)->set_sensor_id(id);
- Track3D &t3d = layout_3d->get_track(**i);
- if(id)
- t3d.set_color(GL::Color(1, 1, 0.5));
- else
- t3d.set_color(GL::Color(1, 1, 1));
+ update_track_color(layout_3d->get_track(**i));
}
input_dismiss();