diff --git a/c++/perspective/src/SConstruct b/c++/perspective/src/SConstruct index 2b21240..5951876 100644 --- a/c++/perspective/src/SConstruct +++ b/c++/perspective/src/SConstruct @@ -20,7 +20,8 @@ sources = [ 'generator.cpp', 'main.cpp', 'matrix.cpp', - 'surface.cpp' ] + 'surface.cpp', + 'view.cpp' ] # build diff --git a/c++/perspective/src/common.h b/c++/perspective/src/common.h index 2c5e843..b4c1580 100644 --- a/c++/perspective/src/common.h +++ b/c++/perspective/src/common.h @@ -1,9 +1,12 @@ #ifndef COMMON_H #define COMMON_H + #include #include +#include + typedef float ColorReal; typedef double Real; @@ -12,21 +15,28 @@ typedef unsigned int UInt; typedef long long int LongInt; typedef unsigned long long int ULongInt; +using Glib::RefPtr; + -const Real realRrecision = 1e-10; +const Real real_precision = 1e-10; class Shared { private: int ref_count; public: - Shared(): ref_count() { } - Shared(const Shared&): ref_count() { } + Shared(): ref_count(1) { } + Shared(const Shared&): ref_count(1) { } virtual ~Shared() { }; inline Shared& operator=(const Shared&) { return *this; } - inline void reference() { ++ref_count; } - inline void unreference() { if (--ref_count <= 0) delete this; } + inline void reference() { + ++ref_count; + } + inline void unreference() { + if (--ref_count <= 0) + delete this; + } }; diff --git a/c++/perspective/src/main.cpp b/c++/perspective/src/main.cpp index 58eb40d..88102e2 100644 --- a/c++/perspective/src/main.cpp +++ b/c++/perspective/src/main.cpp @@ -3,6 +3,7 @@ #include #include +#include "view.h" #include "surface.h" #include "generator.h" @@ -35,8 +36,25 @@ int main(int argc, char **argv) { std::cout << "create window" << std::endl; Gtk::Window window; window.set_default_size(200, 200); + Gtk::HBox hbox; + hbox.set_homogeneous(true); + + View a; + a.own_points.push_back( View::PointPtr( new View::Point() ) ); + a.own_points.push_back( View::PointPtr( new View::Point() ) ); + a.own_points.push_back( View::PointPtr( new View::Point() ) ); + hbox.add(a); + + View b; + b.own_points.push_back( View::PointPtr( new View::Point() ) ); + b.own_points.push_back( View::PointPtr( new View::Point() ) ); + b.own_points.push_back( View::PointPtr( new View::Point() ) ); + hbox.add(b); + Gtk::Image image(pixbuf); - window.add(image); + hbox.add(image); + + window.add(hbox); window.show_all(); std::cout << "run" << std::endl; diff --git a/c++/perspective/src/matrix.cpp b/c++/perspective/src/matrix.cpp index da4b1ff..45e9f5b 100644 --- a/c++/perspective/src/matrix.cpp +++ b/c++/perspective/src/matrix.cpp @@ -13,15 +13,27 @@ // so result for index0(1, 2) is 0 // and for index1(1, 2) is 2 // -// r1\r0 : 0 1 2 3 -// ------------------- -// 0 : 23 23 13 12 -// 1 : 13 03 03 02 -// 2 : 12 02 01 01 +// r1\r0 : 0 1 2 3 +// --------------------------- +// -- : _123 0_23 01_3 012_ +// 0 : _.23 ._23 .1_3 .12_ +// 1 : _1.3 0_.3 0._3 0.2_ +// 2 : _12. 0_2. 01_. 01._ +// --------------------------- +// 0 : 23 23 13 12 +// 1 : 13 03 03 02 +// 2 : 12 02 01 01 + static inline int index0(int r0, int r1) - { return r1 ? (r0 ? 1 : 0) : (r0 > 1 ? 1 : 2); } + { return r1 ? (r0 ? 0 : 1) : (r0 > 1 ? 1 : 2); } static inline int index1(int r0, int r1) { return r1 < 2 ? (r0 < 3 ? 3 : 2) : (r0 > 1 ? 1 : 2); } +static inline int index0(int r) + { return r ? 1 : 0; } +static inline int index1(int r) + { return r > 0 ? 1 : 2; } +static inline int index2(int r) + { return r > 1 ? 2 : 3; } static inline Real det2(const Matrix4 &m, int r, int c, int rr, int cc) { const int r0 = index0(r, rr); @@ -30,13 +42,18 @@ static inline Real det2(const Matrix4 &m, int r, int c, int rr, int cc) { const int c1 = index1(c, cc); return m[r0][c0]*m[r1][c1] - m[r0][c1]*m[r1][c0]; } -static inline Real det3(const Matrix4 &m, int r, int c) - { return det2(m, r, c, 0, 0) - det2(m, r, c, 0, 1) + det2(m, r, c, 0, 2); } + +static inline Real det3(const Matrix4 &m, int r, int c) { + const int r0 = index0(r); + return m[r0][index0(c)] * det2(m, r, c, 0, 0) + - m[r0][index1(c)] * det2(m, r, c, 0, 1) + + m[r0][index2(c)] * det2(m, r, c, 0, 2); +} Real Matrix4::det() const - { return det3(*this, 0, 0) - det3(*this, 0, 1) + det3(*this, 0, 2) - det3(*this, 0, 3); } + { return m00*det3(*this, 0, 0) - m01*det3(*this, 0, 1) + m02*det3(*this, 0, 2) - m03*det3(*this, 0, 3); } Matrix4 Matrix4::invert() const { @@ -46,7 +63,7 @@ Matrix4::invert() const { det3(*this, 0, 2), -det3(*this, 0, 3) ); Real d = dv.x + dv.y + dv.z + dv.w; - if (fabs(d) <= realRrecision) + if (fabs(d) <= real_precision) return zero(); d = 1.0/d; diff --git a/c++/perspective/src/vector.h b/c++/perspective/src/vector.h index ee790d2..61c2ea0 100644 --- a/c++/perspective/src/vector.h +++ b/c++/perspective/src/vector.h @@ -10,6 +10,7 @@ template class VectorBase2T { public: + typedef VectorBase2T SelfTypeArg; typedef ST SelfType; typedef LT LowerType; @@ -36,6 +37,7 @@ public: template class VectorBase3T { public: + typedef VectorBase3T SelfTypeArg; typedef ST SelfType; typedef LT LowerType; @@ -55,7 +57,7 @@ public: inline VectorBase3T(const Vector2 &v, const Coord &z): x(v.x), y(v.y), z(z) { } - inline SelfType cross(const SelfType &other) const + inline SelfType cross(const SelfTypeArg &other) const { return SelfType(y*other.z - z*other.y, z*other.x - x*other.z, x*other.y - y*other.x); } inline Vector2& vec2() @@ -79,6 +81,7 @@ public: template class VectorBase4T { public: + typedef VectorBase4T SelfTypeArg; typedef ST SelfType; typedef LT LowerType; @@ -111,7 +114,7 @@ public: inline const Vector2& vec2() const { return *(const Vector2*)this; }; - inline SelfType cross(const SelfType &other) const + inline SelfType cross(const SelfTypeArg &other) const { return SelfType(y*other.z - z*other.y, z*other.x - x*other.z, x*other.y - y*other.x, w); } }; @@ -119,6 +122,7 @@ public: template class VectorT: public T { public: + typedef VectorT SelfTypeArg; typedef T ParentType; using ParentType::Count; using typename ParentType::Coord; @@ -135,7 +139,7 @@ public: template inline explicit VectorT(const VectorT &v) { - const int cnt = TT::Count < Count ? TT::Count : Count; + const int cnt = (int)TT::Count < (int)Count ? (int)TT::Count : (int)Count; for(int i = 0; i < cnt; ++i) coords[i] = Coord(v.coords[i]); for(int i = cnt; i < Count; ++i) coords[i] = Coord(); } @@ -145,27 +149,27 @@ public: const Coord& operator[] (int i) const { assert(i >= 0 && i < Count); return coords[i]; } - inline bool operator< (const SelfType &other) const { + inline bool operator< (const SelfTypeArg &other) const { for(int i = 0; i < Count; ++i) if (coords[i] < other.coords[i]) return true; else if (other.coords[i] < coords[i]) return false; return false; } - inline bool operator== (const SelfType &other) const { + inline bool operator== (const SelfTypeArg &other) const { for(int i = 0; i < Count; ++i) if (coords[i] != other.coords[i]) return false; return true; } - inline bool operator!= (const SelfType &other) const + inline bool operator!= (const SelfTypeArg &other) const { return !(*(const SelfType*)this == other); } - inline SelfType& operator+= (const SelfType &other) { + inline SelfType& operator+= (const SelfTypeArg &other) { for(int i = 0; i < Count; ++i) coords[i] += other.coords[i]; return *(SelfType*)this; } - inline SelfType& operator-= (const SelfType &other) { + inline SelfType& operator-= (const SelfTypeArg &other) { for(int i = 0; i < Count; ++i) coords[i] -= other.coords[i]; return *(SelfType*)this; } @@ -178,15 +182,15 @@ public: for(int i = 0; i < Count; ++i) v.coords[i] = -coords[i]; return v; } - inline Coord operator* (const SelfType &other) const { + inline Coord operator* (const SelfTypeArg &other) const { Coord r = Coord(); for(int i = 0; i < Count; ++i) r += coords[i]*other.coords[i]; return r; } - inline SelfType operator+ (const SelfType &other) const + inline SelfType operator+ (const SelfTypeArg &other) const { return SelfType(*this) += other; } - inline SelfType operator- (const SelfType &other) const + inline SelfType operator- (const SelfTypeArg &other) const { return SelfType(*this) -= other; } inline SelfType operator* (const Coord &c) const { return SelfType(*this) *= c; } @@ -203,6 +207,7 @@ public: template class VectorFT: public VectorT { public: + typedef VectorFT SelfTypeArg; typedef VectorT ParentType; using ParentType::Count; using typename ParentType::Coord; @@ -218,21 +223,21 @@ public: inline Coord length() const { return Coord(sqrt(ParentType::square())); } - inline bool operator< (const SelfType &other) const { + inline bool operator< (const SelfTypeArg &other) const { for(int i = 0; i < Count; ++i) - if (coords[i] < other.coords[i] - realRrecision) return true; - else if (other.coords[i] < coords[i] - realRrecision) return false; + if (coords[i] < other.coords[i] - real_precision) return true; + else if (other.coords[i] < coords[i] - real_precision) return false; return false; } - inline bool operator== (const SelfType &other) const { + inline bool operator== (const SelfTypeArg &other) const { for(int i = 0; i < Count; ++i) - if ( coords[i] < other.coords[i] - realRrecision - || other.coords[i] < coords[i] - realRrecision ) return false; + if ( coords[i] < other.coords[i] - real_precision + || other.coords[i] < coords[i] - real_precision ) return false; return true; } - inline bool operator!= (const SelfType &other) const + inline bool operator!= (const SelfTypeArg &other) const { return !(*(const SelfType*)this == other); } }; diff --git a/c++/perspective/src/view.cpp b/c++/perspective/src/view.cpp new file mode 100644 index 0000000..d2d3127 --- /dev/null +++ b/c++/perspective/src/view.cpp @@ -0,0 +1,113 @@ +#include "view.h" + +#include + + +void +View::Point::draw( + const Cairo::RefPtr& context, + View &view ) +{ + const Real scale = 1.0/sqrt(fabs(view.transform.m00*view.transform.m11)); + context->save(); + context->arc(position.x, position.y, radius*scale, 0.0, 2.0*M_PI); + context->set_source_rgba(color.r, color.g, color.b, color.a); + context->fill_preserve(); + context->set_source_rgba(0.0, 0.0, 0.0, color.a); + context->set_line_width(selected ? 2.0*scale : scale); + context->stroke(); + context->restore(); +} + + +void +View::Layer::draw(const Cairo::RefPtr&, View&) + { } + + +View::View(): + dragging() +{ + set_events( + Gdk::POINTER_MOTION_MASK + | Gdk::BUTTON_PRESS_MASK + | Gdk::BUTTON_RELEASE_MASK ); +} + +View::~View() { } + +bool +View::on_draw(const Cairo::RefPtr& context) { + context->save(); + + const Real border_size = 1.0; + const Real border_margin = 2.0; + + context->save(); + context->rectangle(0, 0, get_width(), get_height()); + context->set_source_rgba(0, 0, 0, 1); + context->fill(); + context->rectangle( + border_margin, border_margin, + get_width() - 2*border_margin, + get_height() - 2*border_margin ); + context->set_line_width(border_size); + context->set_source_rgba(1, 1, 0, 1); + context->stroke(); + context->restore(); + + context->translate(0.5*get_width(), 0.5*get_height()); + context->transform(Cairo::Matrix(transform.m00, transform.m10, transform.m01, transform.m11, transform.m30, transform.m31)); + for(LayerList::const_iterator i = layers.begin(); i != layers.end(); ++i) + (*i)->draw(context, *this); + for(PointList::const_iterator i = foreign_points.begin(); i != foreign_points.end(); ++i) + (*i)->draw(context, *this); + for(PointList::const_iterator i = own_points.begin(); i != own_points.end(); ++i) + (*i)->draw(context, *this); + context->restore(); + return true; +} + +bool +View::on_motion_notify_event(GdkEventMotion *event) { + Vector2 position = Vector2(event->x - 0.5*get_width(), event->y - 0.5*get_height()); + if (dragging) { + if (selected_point) { + selected_point->position = Vector2(transform.invert()*Vector4(position + selected_point_offset)); + selected_point->motion(); + queue_draw(); + } + } else { + PointPtr point; + for(PointList::iterator i = own_points.begin(); i != own_points.end(); ++i) { + (*i)->selected = false; + Vector2 point_position = Vector2(transform * Vector4((*i)->position)); + Vector2 offset = point_position - position; + if (offset.square() <= (*i)->radius * (*i)->radius) + point = *i; + } + if (point) + point->selected = true; + if (selected_point != point) { + selected_point = point; + queue_draw(); + } + } + return true; +} + +bool +View::on_button_press_event(GdkEventButton *event) { + if (event->button == 1) + dragging = true; + return true; +} + +bool +View::on_button_release_event(GdkEventButton *event) { + if (event->button == 1) { + dragging = false; + if (selected_point) selected_point->changed(); + } + return true; +} diff --git a/c++/perspective/src/view.h b/c++/perspective/src/view.h new file mode 100644 index 0000000..f529475 --- /dev/null +++ b/c++/perspective/src/view.h @@ -0,0 +1,72 @@ +#ifndef VIEW_H +#define VIEW_H + + +#include + +#include + +#include "common.h" +#include "surface.h" +#include "matrix.h" + + +class View: public Gtk::DrawingArea { +public: + class Point: public Shared { + public: + Vector2 position; + Real radius; + Color color; + bool selected; + + Point(): radius(5.0), color(1, 1, 0, 1), selected() { } + + sigc::signal signal_motion; + sigc::signal signal_changed; + + void motion() { signal_motion(); } + void changed() { motion(); signal_changed(); } + + virtual void draw( + const Cairo::RefPtr& context, + View &view ); + }; + + class Layer: public Shared { + public: + virtual void draw( + const Cairo::RefPtr& context, + View &view ); + }; + + typedef RefPtr PointPtr; + typedef RefPtr LayerPtr; + typedef std::vector PointList; + typedef std::vector LayerList; + +public: + Matrix transform; + + LayerList layers; + PointList own_points; + PointList foreign_points; + +private: + bool dragging; + PointPtr selected_point; + Vector2 selected_point_offset; + +public: + View(); + virtual ~View(); + +protected: + bool on_draw(const Cairo::RefPtr& context) override; + bool on_motion_notify_event(GdkEventMotion *event) override; + bool on_button_press_event(GdkEventButton *event) override; + bool on_button_release_event(GdkEventButton *event) override; +}; + + +#endif