From b88d3630a0e3fdd763db018bbe5dbfe3180a95f2 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 12 May 2013 19:08:30 +0300 Subject: [PATCH] Add a generic snapping interface in Object --- source/3d/endpoint.cpp | 7 +- source/designer/manipulator.cpp | 44 ++++++------ source/designer/measure.cpp | 35 +++++----- source/designer/measure.h | 5 +- source/designer/svgexporter.cpp | 2 +- source/engineer/engineer.cpp | 7 +- source/libr2c2/object.cpp | 60 ++++++++++++++++ source/libr2c2/object.h | 10 +++ source/libr2c2/signal.cpp | 37 ++++++++-- source/libr2c2/signal.h | 6 ++ source/libr2c2/snap.h | 25 +++++++ source/libr2c2/track.cpp | 120 ++++++++++++++++---------------- source/libr2c2/track.h | 11 +-- 13 files changed, 246 insertions(+), 123 deletions(-) create mode 100644 source/libr2c2/object.cpp create mode 100644 source/libr2c2/snap.h diff --git a/source/3d/endpoint.cpp b/source/3d/endpoint.cpp index e851007..5d7ebb5 100644 --- a/source/3d/endpoint.cpp +++ b/source/3d/endpoint.cpp @@ -27,13 +27,12 @@ void Endpoint3D::render(GL::Renderer &renderer, const GL::Tag &tag) const { if(tag=="unlit") { - Vector p = track.get_track().get_endpoint_position(index); - float a = track.get_track().get_endpoint_direction(index)+M_PI; + Snap sn = track.get_track().get_snap_node(index); GL::MatrixStack::Push push_mtx(renderer.matrix_stack()); GL::Matrix matrix; - matrix.translate(p.x, p.y, p.z); - matrix.rotate(a, 0, 0, 1); + matrix.translate(sn.position.x, sn.position.y, sn.position.z); + matrix.rotate(sn.rotation+M_PI, 0, 0, 1); renderer.matrix_stack() *= matrix; if(track.get_track().get_link(index)) diff --git a/source/designer/manipulator.cpp b/source/designer/manipulator.cpp index 5b95d5c..6aca114 100644 --- a/source/designer/manipulator.cpp +++ b/source/designer/manipulator.cpp @@ -174,10 +174,10 @@ void Manipulator::even_slope(bool smooth) set::iterator nb = neighbors.begin(); int epi = (*nb)->get_endpoint_by_link(*order.front().track); - float start_z = (*nb)->get_endpoint_position(epi).z; + float start_z = (*nb)->get_snap_node(epi).position.z; ++nb; epi = (*nb)->get_endpoint_by_link(*order.back().track); - float end_z = (*nb)->get_endpoint_position(epi).z; + float end_z = (*nb)->get_snap_node(epi).position.z; if(smooth) { @@ -233,8 +233,7 @@ void Manipulator::connect() float limit = designer.get_layout().get_catalogue().get_gauge()/10; - Vector pos1; - float dir1; + Snap sn1; bool ok = false; float gap = 0; for(unsigned i=0; iget_type().get_endpoints().size(); ++i) @@ -242,22 +241,20 @@ void Manipulator::connect() if(track1->get_link(i)) continue; - pos1 = track1->get_endpoint_position(i); - dir1 = track1->get_endpoint_direction(i); + sn1 = track1->get_snap_node(i); for(unsigned j=0; jget_type().get_endpoints().size(); ++j) { if(track2->get_link(j)) continue; - Vector pos2 = track2->get_endpoint_position(j); - float dir2 = track2->get_endpoint_direction(j); + Snap sn2 = track2->get_snap_node(j); - float dz = pos2.z-pos1.z; + float dz = sn2.position.z-sn1.position.z; if(abs(dz)>0.02) continue; - float adiff = dir1+M_PI-dir2; + float adiff = sn1.rotation+M_PI-sn2.rotation; while(adiff<-M_PI) adiff += M_PI*2; while(adiff>M_PI) @@ -265,10 +262,10 @@ void Manipulator::connect() if(abs(adiff)>0.01) continue; - float c = cos(dir1); - float s = sin(dir1); - float dx = pos2.x-pos1.x; - float dy = pos2.y-pos1.y; + float c = cos(sn1.rotation); + float s = sin(sn1.rotation); + float dx = sn2.position.x-sn1.position.x; + float dy = sn2.position.y-sn1.position.y; if(abs(dx*s-dy*c)>limit) continue; @@ -289,7 +286,7 @@ void Manipulator::connect() return; } - vector trks = create_straight(pos1, dir1, gap, limit); + vector trks = create_straight(sn1.position, sn1.rotation, gap, limit); if(trks.empty()) { @@ -472,19 +469,18 @@ void Manipulator::axis_motion(unsigned axis, float value, float) if(track->get_link(j)) continue; - Vector ep_pos = track->get_endpoint_position(j); - float ep_dir = track->get_endpoint_direction(j); - float c = cos(ep_dir); - float s = sin(ep_dir); - float dx = gpointer.x-ep_pos.x; - float dy = gpointer.y-ep_pos.y; + Snap sn = track->get_snap_node(j); + float c = cos(sn.rotation); + float s = sin(sn.rotation); + float dx = gpointer.x-sn.position.x; + float dy = gpointer.y-sn.position.y; float len = dx*c+dy*s; if(lenget_type().get_endpoints().size(); for(unsigned j=0; jget_endpoint_position(j); + Vector p = track->get_snap_node(j).position; if(i==objects.begin() && j==0) minp = maxp = p; else diff --git a/source/designer/measure.cpp b/source/designer/measure.cpp index f115f9d..69ada81 100644 --- a/source/designer/measure.cpp +++ b/source/designer/measure.cpp @@ -28,9 +28,9 @@ void Measure::button_press(float gx, float gy, unsigned btn) if(btn==1) { - spoint = Vector(gx, gy, 0); - sdir = 0; - snap_to_tracks(spoint, sdir); + ssnap.position = Vector(gx, gy, 0); + ssnap.rotation = 0; + snap_to_tracks(ssnap); state = ACTIVE; } @@ -54,20 +54,21 @@ void Measure::pointer_motion(float gx, float gy) if(!state) return; - pointer = Vector(gx, gy, 0); - float dir = sdir; - snap_to_tracks(pointer, dir); + Snap sn = ssnap; + sn.position = Vector(gx, gy, 0); + snap_to_tracks(sn); + pointer = sn.position; if(state!=STARTING) { - Vector delta(pointer.x-spoint.x, pointer.y-spoint.y, 0); - float c = cos(sdir); - float s = sin(sdir); + Vector delta(pointer.x-ssnap.position.x, pointer.y-ssnap.position.y, 0); + float c = cos(ssnap.rotation); + float s = sin(ssnap.rotation); par_dist = delta.x*c+delta.y*s; perp_dist = delta.x*s-delta.y*c; - adiff = dir-sdir+M_PI; + adiff = sn.rotation-ssnap.rotation+M_PI; while(adiff<-M_PI) adiff += M_PI*2; while(adiff>M_PI) @@ -85,7 +86,7 @@ void Measure::render(GL::Renderer &renderer, const GL::Tag &) const return; GL::Renderer::Push push(renderer); - const Vector &pos = (state==ACTIVE ? spoint : pointer); + const Vector &pos = (state==ACTIVE ? ssnap.position : pointer); renderer.matrix_stack() *= GL::Matrix::translation(pos.x, pos.y, pos.z); mesh.draw(renderer); @@ -108,25 +109,25 @@ void Measure::update_mesh() if(state==ACTIVE) { - float c = cos(sdir); - float s = sin(sdir); + float c = cos(ssnap.rotation); + float s = sin(ssnap.rotation); bld.begin(GL::QUAD_STRIP); bld.vertex(0, 0, 0); bld.vertex(0, 0, 0.01); bld.vertex(c*par_dist, s*par_dist, 0); bld.vertex(c*par_dist, s*par_dist, 0.01); - bld.vertex(pointer.x-spoint.x, pointer.y-spoint.y, 0); - bld.vertex(pointer.x-spoint.x, pointer.y-spoint.y, 0.01); + bld.vertex(pointer.x-ssnap.position.x, pointer.y-ssnap.position.y, 0); + bld.vertex(pointer.x-ssnap.position.x, pointer.y-ssnap.position.y, 0.01); bld.vertex(0, 0, 0); bld.vertex(0, 0, 0.01); bld.end(); } } -void Measure::snap_to_tracks(Vector &pt, float &dir) +void Measure::snap_to_tracks(Snap &sn) { const set <racks = designer.get_layout().get_tracks(); for(set::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i) - if((*i)->snap(pt, dir)) + if((*i)->snap(sn, 0.01, SNAP_NODE)) return; } diff --git a/source/designer/measure.h b/source/designer/measure.h index 84b1c83..022c314 100644 --- a/source/designer/measure.h +++ b/source/designer/measure.h @@ -23,8 +23,7 @@ public: private: Designer &designer; R2C2::Vector pointer; - R2C2::Vector spoint; - float sdir; + R2C2::Snap ssnap; float par_dist; float perp_dist; float adiff; @@ -42,7 +41,7 @@ public: virtual void render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; private: void update_mesh(); - void snap_to_tracks(R2C2::Vector &, float &); + void snap_to_tracks(R2C2::Snap &); }; #endif diff --git a/source/designer/svgexporter.cpp b/source/designer/svgexporter.cpp index 11edf64..62e869c 100644 --- a/source/designer/svgexporter.cpp +++ b/source/designer/svgexporter.cpp @@ -45,7 +45,7 @@ void SvgExporter::save(const string &fn) unsigned n_endpoints = (*i)->get_type().get_endpoints().size(); for(unsigned j=0; jget_endpoint_position(j); + Vector pos = (*i)->get_snap_node(j).position; if(i==tracks.begin() && j==0) minp = maxp = pos; else diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index e19c11e..b0296a1 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -230,11 +230,10 @@ void Engineer::tick() camera.apply(); GL::MatrixStack::Push push_mat(GL::MatrixStack::modelview()); - float rot = picking_track->get_endpoint_direction(picking_entry); - Vector pos = picking_track->get_endpoint_position(picking_entry); + Snap sn = picking_track->get_snap_node(picking_entry); - GL::MatrixStack::modelview() *= GL::Matrix::translation(pos.x, pos.y, pos.z+0.03); - GL::MatrixStack::modelview() *= GL::Matrix::rotation(rot+M_PI, 0, 0, 1); + GL::MatrixStack::modelview() *= GL::Matrix::translation(sn.position.x, sn.position.y, sn.position.z+0.03); + GL::MatrixStack::modelview() *= GL::Matrix::rotation(sn.rotation+M_PI, 0, 0, 1); arrow_mesh.draw(); } diff --git a/source/libr2c2/object.cpp b/source/libr2c2/object.cpp new file mode 100644 index 0000000..1b48a86 --- /dev/null +++ b/source/libr2c2/object.cpp @@ -0,0 +1,60 @@ +#include +#include "object.h" + +using namespace std; + +namespace R2C2 { + +Snap Object::get_snap_node(unsigned) const +{ + throw out_of_range("Object::get_snap_node"); +} + +bool Object::snap(Snap &sn, float limit, SnapType what) const +{ + if(what&SNAP_NODE) + { + unsigned nsn = get_n_snap_nodes(); + for(unsigned i=0; i::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) if(!(*i)->get_type().is_turnout()) { - TrackPoint n = (*i)->get_nearest_point(p); - float d = distance(p, n.pos); + Snap sn; + sn.position = p; + sn.rotation = rotation; + (*i)->snap(sn, 1000, SNAP_SEGMENT); + float d = distance(p, sn.position); if(dget_type().get_endpoints().size(); for(unsigned j=0; jget_endpoint_direction(j)-rotation; + float a = track->get_snap_node(j).rotation-rotation; while(a<-M_PI/2) a += M_PI*2; while(a>M_PI*3/2) @@ -107,6 +110,30 @@ void Signal::set_rotation(float r) normalize_location(); } +unsigned Signal::get_n_snap_nodes() const +{ + return 1; +} + +Snap Signal::get_snap_node(unsigned i) const +{ + if(i>=1) + throw out_of_range("Signal::get_snap_node"); + + Snap sn; + sn.position = position; + sn.rotation = rotation; + return sn; +} + +SnapType Signal::get_default_snap_type_to(const Object &other) const +{ + if(dynamic_cast(&other)) + return SNAP_SEGMENT; + + return NO_SNAP; +} + bool Signal::collide_ray(const Vector &start, const Vector &ray) const { // XXX Totally hardcoded stuff, should be replaced with a geometry system diff --git a/source/libr2c2/signal.h b/source/libr2c2/signal.h index 92e1977..b604951 100644 --- a/source/libr2c2/signal.h +++ b/source/libr2c2/signal.h @@ -54,6 +54,12 @@ private: public: virtual Track *get_parent() const { return track; } + virtual unsigned get_n_snap_nodes() const; + virtual Snap get_snap_node(unsigned) const; +private: + virtual SnapType get_default_snap_type_to(const Object &) const; + +public: virtual bool collide_ray(const Vector &, const Vector &) const; void tick(const Msp::Time::TimeDelta &); diff --git a/source/libr2c2/snap.h b/source/libr2c2/snap.h new file mode 100644 index 0000000..844af3d --- /dev/null +++ b/source/libr2c2/snap.h @@ -0,0 +1,25 @@ +#ifndef LIBR2C2_SNAP_H_ +#define LIBR2C2_SNAP_H_ + +namespace R2C2 { + +enum SnapType +{ + SNAP_DEFAULT = 0, + NO_SNAP = 0, + SNAP_NODE = 1, + SNAP_SEGMENT = 2 +}; + +struct Snap +{ + Vector position; + float rotation; +}; + +inline SnapType operator|(SnapType s1, SnapType s2) +{ return static_cast(static_cast(s1)|static_cast(s2)); } + +} // namespace R2C2 + +#endif diff --git a/source/libr2c2/track.cpp b/source/libr2c2/track.cpp index b679af7..e4d7bad 100644 --- a/source/libr2c2/track.cpp +++ b/source/libr2c2/track.cpp @@ -100,8 +100,8 @@ void Track::check_slope() if(links[0] && links[1]) { - Vector epp0 = links[0]->get_endpoint_position(links[0]->get_endpoint_by_link(*this)); - Vector epp1 = links[1]->get_endpoint_position(links[1]->get_endpoint_by_link(*this)); + Vector epp0 = links[0]->get_snap_node(links[0]->get_endpoint_by_link(*this)).position; + Vector epp1 = links[1]->get_snap_node(links[1]->get_endpoint_by_link(*this)).position; position.z = epp0.z; slope = epp1.z-position.z; } @@ -110,12 +110,12 @@ void Track::check_slope() slope = 0; if(links[0]) { - Vector epp = links[0]->get_endpoint_position(links[0]->get_endpoint_by_link(*this)); + Vector epp = links[0]->get_snap_node(links[0]->get_endpoint_by_link(*this)).position; position.z = epp.z; } else if(links[1]) { - Vector epp = links[1]->get_endpoint_position(links[1]->get_endpoint_by_link(*this)); + Vector epp = links[1]->get_snap_node(links[1]->get_endpoint_by_link(*this)).position; position.z = epp.z; } } @@ -164,34 +164,6 @@ int Track::get_endpoint_by_link(Track &other) const return -1; } -Vector Track::get_endpoint_position(unsigned epi) const -{ - const vector &eps = type.get_endpoints(); - if(epi>=eps.size()) - throw out_of_range("Track::get_endpoint_position"); - - const TrackType::Endpoint &ep = eps[epi]; - - float c = cos(rotation); - float s = sin(rotation); - - Vector p(position.x+c*ep.pos.x-s*ep.pos.y, position.y+s*ep.pos.x+c*ep.pos.y, position.z); - if(eps.size()==2 && epi==1) - p.z += slope; - return p; -} - -float Track::get_endpoint_direction(unsigned epi) const -{ - const vector &eps = type.get_endpoints(); - if(epi>=eps.size()) - throw out_of_range("Track::get_endpoint_direction"); - - const TrackType::Endpoint &ep = eps[epi]; - - return rotation+ep.dir; -} - bool Track::snap_to(Track &other, bool link, float limit) { if(!limit || link) @@ -207,14 +179,14 @@ bool Track::snap_to(Track &other, bool link, float limit) for(unsigned i=0; i &eps = type.get_endpoints(); - - for(unsigned i=0; i::iterator i=links.begin(); i!=links.end(); ++i) @@ -335,17 +287,63 @@ TrackPoint Track::get_point(unsigned epi, float d) const return get_point(epi, active_path, d); } -TrackPoint Track::get_nearest_point(const Vector &p) const +unsigned Track::get_n_snap_nodes() const { - Vector local(p.x-position.x, p.y-position.y, p.z-position.z); + return type.get_endpoints().size(); +} + +Snap Track::get_snap_node(unsigned i) const +{ + const vector &eps = type.get_endpoints(); + if(i>=eps.size()) + throw out_of_range("Track::get_snap_node"); + + Snap result; + const TrackType::Endpoint &ep = eps[i]; + float c = cos(rotation); float s = sin(rotation); - local = Vector(c*local.x+s*local.y, c*local.y-s*local.x, local.z); - TrackPoint tp = type.get_nearest_point(local); - tp.pos = Vector(position.x+tp.pos.x*c-tp.pos.y*s, position.y+tp.pos.y*c+tp.pos.x*s, position.z+tp.pos.z); - tp.dir += rotation; - return tp; + result.position = Vector(position.x+c*ep.pos.x-s*ep.pos.y, position.y+s*ep.pos.x+c*ep.pos.y, position.z); + if(eps.size()==2 && i==1) + result.position.z += slope; + + result.rotation = rotation+ep.dir; + + return result; +} + +bool Track::snap(Snap &sn, float limit, SnapType what) const +{ + if(Object::snap(sn, limit, what)) + return true; + + if(what&SNAP_SEGMENT) + { + Vector local(sn.position.x-position.x, sn.position.y-position.y, sn.position.z-position.z); + float c = cos(rotation); + float s = sin(rotation); + local = Vector(c*local.x+s*local.y, c*local.y-s*local.x, local.z); + + TrackPoint tp = type.get_nearest_point(local); + Vector d(local.x-tp.pos.x, local.y-tp.pos.y, local.z-tp.pos.z); + if(d.x*d.x+d.y*d.y+d.z*d.z<=limit*limit) + { + sn.position = Vector(position.x+tp.pos.x*c-tp.pos.y*s, position.y+tp.pos.y*c+tp.pos.x*s, position.z+tp.pos.z); + sn.rotation = tp.dir+rotation; + return true; + } + } + + return false; +} + +SnapType Track::get_default_snap_type_to(const Object &other) const +{ + if(dynamic_cast(&other)) + return SNAP_NODE; + + return NO_SNAP; } bool Track::collide_ray(const Vector &start, const Vector &ray) const diff --git a/source/libr2c2/track.h b/source/libr2c2/track.h index 883fb5e..b8a9a3d 100644 --- a/source/libr2c2/track.h +++ b/source/libr2c2/track.h @@ -70,18 +70,21 @@ public: bool is_path_changing() const { return path_changing; } int get_endpoint_by_link(Track &) const; - Vector get_endpoint_position(unsigned) const; - float get_endpoint_direction(unsigned) const; bool snap_to(Track &, bool, float = 0); - bool snap(Vector &, float &) const; void break_link(Track &); void break_links(); const std::vector &get_links() const { return links; } Track *get_link(unsigned) const; TrackPoint get_point(unsigned, unsigned, float) const; TrackPoint get_point(unsigned, float) const; - TrackPoint get_nearest_point(const Vector &) const; + virtual unsigned get_n_snap_nodes() const; + virtual Snap get_snap_node(unsigned) const; + virtual bool snap(Snap &, float, SnapType = SNAP_DEFAULT) const; +private: + virtual SnapType get_default_snap_type_to(const Object &) const; + +public: virtual bool collide_ray(const Vector &, const Vector &) const; void save(std::list &) const; -- 2.45.2