From de42d1f3ae5e1697a7d244dadf402442e8fe4f25 Mon Sep 17 00:00:00 2001 From: dmatetelki Date: Mon, 4 Aug 2014 12:14:05 +0200 Subject: [PATCH] qtgraph loads/saves state to graph --- lib/qtgraph/CMakeLists.txt | 30 +++- lib/qtgraph/floats.hpp | 293 ++++++++++++++++++++++++++++++++++ lib/qtgraph/graph_example.xml | 19 +++ lib/qtgraph/graphwidget.cpp | 209 +++++++++--------------- lib/qtgraph/graphwidget.hpp | 13 +- lib/qtgraph/main.cpp | 61 ++++++- lib/qtgraph/node.cpp | 63 +------- lib/qtgraph/node.hpp | 3 - 8 files changed, 489 insertions(+), 202 deletions(-) create mode 100644 lib/qtgraph/floats.hpp create mode 100644 lib/qtgraph/graph_example.xml diff --git a/lib/qtgraph/CMakeLists.txt b/lib/qtgraph/CMakeLists.txt index 2e89a80..0b516a1 100644 --- a/lib/qtgraph/CMakeLists.txt +++ b/lib/qtgraph/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required (VERSION 2.6) project (PROJECT_QGRAPH) +set ( CMAKE_CXX_COMPILER "/usr/bin/g++-4.9.0") + set (CXX_FLAGS "-Wall -Wextra -pedantic -Wshadow " "-Wpointer-arith -Wcast-qual " "-ggdb " @@ -10,7 +12,29 @@ add_definitions( ${CXX_FLAGS} ) FIND_PACKAGE(Qt4 REQUIRED) INCLUDE(${QT_USE_FILE}) -QT4_WRAP_CPP(qtgraph_HEADERS_MOC node.hpp edge.hpp graphwidget.hpp) +QT4_WRAP_CPP(qtgraph_HEADERS_MOC +# node.hpp +# edge.hpp +graphwidget.hpp) + +include_directories( +../ +/usr/include/libxml2 +) + +add_executable (qtgraph +main.cpp +edge.cpp +node.cpp +graphwidget.cpp +${qtgraph_HEADERS_MOC} ) + +target_link_libraries ( qtgraph ${QT_LIBRARIES} xml2 ) -add_executable ( qtgraph main.cpp edge.cpp node.cpp graphwidget.cpp ${qtgraph_HEADERS_MOC} ) -target_link_libraries ( qtgraph ${QT_LIBRARIES} ) +add_custom_target (clean2 +COMMAND +make clean && +find -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} \\+ && +rm Makefile && +rm moc_* +) \ No newline at end of file diff --git a/lib/qtgraph/floats.hpp b/lib/qtgraph/floats.hpp new file mode 100644 index 0000000..365e346 --- /dev/null +++ b/lib/qtgraph/floats.hpp @@ -0,0 +1,293 @@ +#ifndef FLOATS_HPP +#define FLOATS_HPP + +#include + +inline float clamp(float f, float min, float max) { return (f < min) ? min : ((f > max) ? max : f); } +inline float saturate(float f) { return clamp(f, 0.0f, 1.0f); } +inline float lerp(float f1, float f2, float f) { return f1 + (f2 - f1) * f; } +inline float min(float f1, float f2) { return f1 < f2 ? f1 : f2; } +inline float max(float f1, float f2) { return f1 > f2 ? f1 : f2; } +inline float sign(float f) { return (f == 0.0f) ? 0.0f : ((f > 0.0f) ? 1.0f : -1.0f); } + +// Vectors -------------------------------------------------------------------- + +// 2-dimensional vector ------------------------------------------------------- + +struct float2 { + float x, y; + + inline float2() : x(0.0), y(0.0) {} + inline float2(float f) : x(f), y(f) {} + inline float2(float x_, float y_) : x(x_), y(y_) {} + float2(const struct float3& v); + float2(const struct float4& v); + + inline float2 operator +() const { return *this; } + inline float2 operator -() const { return float2(-x, -y); } +}; + +inline bool operator ==(const float2& v1, const float2& v2) { return v1.x == v2.x && v1.y == v2.y; } + +inline float2 operator +(const float2& v1, const float2& v2) { return float2(v1.x + v2.x, v1.y + v2.y); } +inline float2 operator -(const float2& v1, const float2& v2) { return float2(v1.x - v2.x, v1.y - v2.y); } +inline float2 operator *(const float2& v1, const float2& v2) { return float2(v1.x * v2.x, v1.y * v2.y); } +inline float2 operator /(const float2& v1, const float2& v2) { return float2(v1.x / v2.x, v1.y / v2.y); } + +inline float2 operator +(const float2& v, float f) { return float2(v.x + f, v.y + f); } +inline float2 operator +(float f, const float2& v) { return float2(v.x + f, v.y + f); } +inline float2 operator -(const float2& v, float f) { return float2(v.x - f, v.y - f); } +inline float2 operator -(float f, const float2& v) { return float2(f - v.x, f - v.y); } +inline float2 operator *(const float2& v, float f) { return float2(v.x * f, v.y * f); } +inline float2 operator *(float f, const float2& v) { return float2(v.x * f, v.y * f); } +inline float2 operator /(const float2& v, float f) { float inv = 1.0f / f; return float2(v.x * inv, v.y * inv); } +inline float2 operator /(float f, const float2& v) { return float2(f / v.x, f / v.y); } + +inline float dot(const float2& v1, const float2& v2) { return v1.x * v2.x + v1.y * v2.y; } +inline float lengthsq(const float2& v) { return dot(v, v); } +inline float length(const float2& v) { return sqrt(lengthsq(v)); } +inline float2 lerp(const float2& v1, const float2& v2, float f) { return v1 + (v2 - v1) * f; } +inline float2 normalize(const float2& v) { return v * (1.0f / length(v)); } +inline float2 min(const float2& v1, const float2& v2) { return float2(min(v1.x, v2.x), min(v1.y, v2.y)); } +inline float2 max(const float2& v1, const float2& v2) { return float2(max(v1.x, v2.x), max(v1.y, v2.y)); } +inline float2 abs(const float2& v) { return float2(fabs(v.x), fabs(v.y)); } + +inline float dist(const float2& v1, const float2& v2) { return sqrt(pow((v2.x - v1.x),2) + pow((v2.y - v1.y),2)); } + + +// 3-dimensional vector ------------------------------------------------------- + +struct float3 { + float x, y, z; + + inline float3() {} + inline float3(float f) : x(f), y(f), z(f) {} + inline float3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {} + inline float3(const float2& v, float z_) : x(v.x), y(v.y), z(z_) {} + float3(const struct float4& v); + + inline float3 operator +() const { return *this; } + inline float3 operator -() const { return float3(-x, -y, -z); } +}; + +inline float3 operator +(const float3& v1, const float3& v2) { return float3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); } +inline float3 operator -(const float3& v1, const float3& v2) { return float3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); } +inline float3 operator *(const float3& v1, const float3& v2) { return float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); } +inline float3 operator /(const float3& v1, const float3& v2) { return float3(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z); } + +inline float3 operator +(const float3& v, float f) { return float3(v.x + f, v.y + f, v.z + f); } +inline float3 operator +(float f, const float3& v) { return float3(v.x + f, v.y + f, v.z + f); } +inline float3 operator -(const float3& v, float f) { return float3(v.x - f, v.y - f, v.z - f); } +inline float3 operator -(float f, const float3& v) { return float3(f - v.x, f - v.y, f - v.z); } +inline float3 operator *(const float3& v, float f) { return float3(v.x * f, v.y * f, v.z * f); } +inline float3 operator *(float f, const float3& v) { return float3(v.x * f, v.y * f, v.z * f); } +inline float3 operator /(const float3& v, float f) { float inv = 1.0f / f; return float3(v.x * inv, v.y * inv, v.z * inv); } +inline float3 operator /(float f, const float3& v) { return float3(f / v.x, f / v.y, f / v.z); } + +inline float3 cross(const float3& v1, const float3& v2) { return float3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x); } +inline float dot(const float3& v1, const float3& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } +inline float lengthsq(const float3& v) { return dot(v, v); } +inline float length(const float3& v) { return sqrt(lengthsq(v)); } +inline float3 lerp(const float3& v1, const float3& v2, float f) { return v1 + (v2 - v1) * f; } +inline float3 normalize(const float3& v) { return v * (1.0f / length(v)); } +inline float3 min(const float3& v1, const float3& v2) { return float3(min(v1.x, v2.x), min(v1.y, v2.y), min(v1.z, v2.z)); } +inline float3 max(const float3& v1, const float3& v2) { return float3(max(v1.x, v2.x), max(v1.y, v2.y), max(v1.z, v2.z)); } +inline float3 abs(const float3& v) { return float3(fabs(v.x), fabs(v.y), fabs(v.z)); } + +inline float dist(const float3& v1, const float3& v2) { return sqrt(pow((v2.x - v1.x),2) + pow((v2.y - v1.y),2) + pow((v2.z - v1.z),2)); } + + +// 4-dimensional vector ------------------------------------------------------- + +struct float4 { + float x, y, z, w; + + inline float4() {} + inline float4(float f) : x(f), y(f), z(f), w(f) {} + inline float4(float x_, float y_, float z_, float w_) : x(x_), y(y_), z(z_), w(w_) {} + inline float4(const float2& v, float z_, float w_) : x(v.x), y(v.y), z(z_), w(w_) {} + inline float4(const float3& v, float w_) : x(v.x), y(v.y), z(v.z), w(w_) {} + + inline float4 operator +() const { return *this; } + inline float4 operator -() const { return float4(-x, -y, -z, -w); } +}; + +inline float4 operator +(const float4& v1, const float4& v2) { return float4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w); } +inline float4 operator -(const float4& v1, const float4& v2) { return float4(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.w - v2.w); } +inline float4 operator *(const float4& v1, const float4& v2) { return float4(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.w * v2.w); } +inline float4 operator /(const float4& v1, const float4& v2) { return float4(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.w / v2.w); } + +inline float4 operator +(const float4& v, float f) { return float4(v.x + f, v.y + f, v.z + f, v.w + f); } +inline float4 operator +(float f, const float4& v) { return float4(v.x + f, v.y + f, v.z + f, v.w + f); } +inline float4 operator -(const float4& v, float f) { return float4(v.x - f, v.y - f, v.z - f, v.w - f); } +inline float4 operator -(float f, const float4& v) { return float4(f - v.x, f - v.y, f - v.z, f - v.w); } +inline float4 operator *(const float4& v, float f) { return float4(v.x * f, v.y * f, v.z * f, v.w * f); } +inline float4 operator *(float f, const float4& v) { return float4(v.x * f, v.y * f, v.z * f, v.w * f); } +inline float4 operator /(const float4& v, float f) { float inv = 1.0f / f; return float4(v.x * inv, v.y * inv, v.z * inv, v.w * inv); } +inline float4 operator /(float f, const float4& v) { return float4(f / v.x, f / v.y, f / v.z, f / v.w); } + +inline float dot(const float4& v1, const float4& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w; } +inline float lengthsq(const float4& v) { return dot(v, v); } +inline float length(const float4& v) { return sqrt(lengthsq(v)); } +inline float4 lerp(const float4& v1, const float4& v2, float f) { return v1 + (v2 - v1) * f; } +inline float4 normalize(const float4& v) { return v * (1.0f / length(v)); } +inline float4 min(const float4& v1, const float4& v2) { return float4(min(v1.x, v2.x), min(v1.y, v2.y), min(v1.z, v2.z), min(v1.w, v2.w)); } +inline float4 max(const float4& v1, const float4& v2) { return float4(max(v1.x, v2.x), max(v1.y, v2.y), max(v1.z, v2.z), max(v1.w, v2.w)); } +inline float4 abs(const float4& v) { return float4(fabs(v.x), fabs(v.y), fabs(v.z), fabs(v.w)); } + +inline float dist(const float4& v1, const float4& v2) { return sqrt(pow((v2.x - v1.x),2) + pow((v2.y - v1.y),2) + pow((v2.z - v1.z),2) + pow((v2.w - v1.w),2)); } + + +// ---------------------------------------------------------------------------- + +inline float2::float2(const struct float3& v) : x(v.x), y(v.y) { } +inline float2::float2(const struct float4& v) : x(v.x), y(v.y) { } + +inline float3::float3(const struct float4& v) : x(v.x), y(v.y), z(v.z) { } + +// Matrices ------------------------------------------------------------------- + +// 2x2-matrix ----------------------------------------------------------------- + +struct float2x2 { + float2 s, t; // rows + + inline float2x2() {} + inline float2x2(const float2& s_, const float2& t_) : s(s_), t(t_) {} + inline float2x2(float sx, float sy, + float tx, float ty) : s(sx, sy), t(tx, ty) {} +}; + +inline float2x2 transpose(const float2x2& m) { return float2x2(float2(m.s.x, m.t.x), float2(m.s.y, m.t.y)); } + +inline float2x2 operator *(const float2x2& m1, const float2x2& m2) { + const float2x2 m3 = transpose(m2); + return float2x2(float2(dot(m1.s, m3.s), dot(m1.s, m3.t)), + float2(dot(m1.t, m3.s), dot(m1.t, m3.t))); +} + +inline float2 operator *(const float2x2& m, const float2& v) { return float2(dot(m.s, v), dot(m.t, v)); } +inline float2x2 operator *(const float2x2& m, float f) { return float2x2(m.s * f, m.t * f); } +inline float2x2 operator *(float f, const float2x2& m) { return float2x2(m.s * f, m.t * f); } + +inline float determinant(const float2x2& m) { return m.s.x * m.t.y - m.s.y * m.t.x; } +inline float2x2 inverse(const float2x2& m) { return float2x2(float2(m.t.y, -m.s.y), float2(-m.t.x, m.s.x)) * (1.0f / determinant(m)); } + +// 3x3-matrix ----------------------------------------------------------------- + +struct float3x3 { + float3 s, t, u; // rows + + inline float3x3() {} + inline float3x3(const float3& s_, const float3& t_, const float3& u_) : s(s_), t(t_), u(u_) {} + inline float3x3(float sx, float sy, float sz, + float tx, float ty, float tz, + float ux, float uy, float uz) : s(sx, sy, sz), t(tx, ty, tz), u(ux, uy, uz) {} +}; + +inline float3x3 transpose(const float3x3& m) { + return float3x3(float3(m.s.x, m.t.x, m.u.x), + float3(m.s.y, m.t.y, m.u.y), + float3(m.s.z, m.t.z, m.u.z)); +} + +inline float3x3 operator *(const float3x3& m1, const float3x3& m2) { + const float3x3 m3 = transpose(m2); + return float3x3(float3(dot(m1.s, m3.s), dot(m1.s, m3.t), dot(m1.s, m3.u)), + float3(dot(m1.t, m3.s), dot(m1.t, m3.t), dot(m1.t, m3.u)), + float3(dot(m1.u, m3.s), dot(m1.u, m3.t), dot(m1.u, m3.u))); +} + +inline float3 operator *(const float3x3& m, const float3& v) { return float3(dot(m.s, v), dot(m.t, v), dot(m.u, v)); } +inline float3x3 operator *(const float3x3& m, float f) { return float3x3(m.s * f, m.t * f, m.u * f); } +inline float3x3 operator *(float f, const float3x3& m) { return float3x3(m.s * f, m.t * f, m.u * f); } + +inline float determinant(const float3x3& m) { + return m.s.x * determinant(float2x2(m.t.y, m.t.z, m.u.y, m.u.z)) + - m.s.y * determinant(float2x2(m.t.x, m.t.z, m.u.x, m.u.z)) + + m.s.z * determinant(float2x2(m.t.x, m.t.y, m.u.x, m.u.y)); +} + +inline float3x3 inverse(const float3x3& m) { + return float3x3( + determinant(float2x2(m.t.y, m.t.z, m.u.y, m.u.z)), + determinant(float2x2(m.s.z, m.s.y, m.u.z, m.u.y)), + determinant(float2x2(m.s.y, m.s.z, m.t.y, m.t.z)), + + determinant(float2x2(m.t.z, m.t.x, m.u.z, m.u.x)), + determinant(float2x2(m.s.x, m.s.z, m.u.x, m.u.z)), + determinant(float2x2(m.s.z, m.s.x, m.t.z, m.t.x)), + + determinant(float2x2(m.t.x, m.t.y, m.u.x, m.u.y)), + determinant(float2x2(m.s.y, m.s.x, m.u.y, m.u.x)), + determinant(float2x2(m.s.x, m.s.y, m.t.x, m.t.y))) + + * (1.0f / determinant(m)); +} + +// 4x4-matrix ----------------------------------------------------------------- + +struct float4x4 { + float4 s, t, u, v; // rows + + inline float4x4() {} + inline float4x4(const float4& s_, const float4& t_, const float4& u_, const float4& v_) : s(s_), t(t_), u(u_), v(v_) {} + inline float4x4(float sx, float sy, float sz, float sw, + float tx, float ty, float tz, float tw, + float ux, float uy, float uz, float uw, + float vx, float vy, float vz, float vw) : s(sx, sy, sz, sw), t(tx, ty, tz, tw), u(ux, uy, uz, uw), v(vx, vy, vz, vw) {} +}; + +inline float4x4 transpose(const float4x4& m) { + return float4x4(float4(m.s.x, m.t.x, m.u.x, m.v.x), + float4(m.s.y, m.t.y, m.u.y, m.v.y), + float4(m.s.z, m.t.z, m.u.z, m.v.z), + float4(m.s.w, m.t.w, m.u.w, m.v.w)); +} + +inline float4x4 operator *(const float4x4& m1, const float4x4& m2) { + const float4x4 m3 = transpose(m2); + return float4x4(float4(dot(m1.s, m3.s), dot(m1.s, m3.t), dot(m1.s, m3.u), dot(m1.s, m3.v)), + float4(dot(m1.t, m3.s), dot(m1.t, m3.t), dot(m1.t, m3.u), dot(m1.t, m3.v)), + float4(dot(m1.u, m3.s), dot(m1.u, m3.t), dot(m1.u, m3.u), dot(m1.u, m3.v)), + float4(dot(m1.v, m3.s), dot(m1.v, m3.t), dot(m1.v, m3.u), dot(m1.v, m3.v))); +} + +inline float4 operator *(const float4x4& m, const float4& v) { return float4(dot(m.s, v), dot(m.t, v), dot(m.u, v), dot(m.v, v)); } +inline float4x4 operator *(const float4x4& m, float f) { return float4x4(m.s * f, m.t * f, m.u * f, m.v * f); } +inline float4x4 operator *(float f, const float4x4& m) { return float4x4(m.s * f, m.t * f, m.u * f, m.v * f); } + +inline float determinant(const float4x4& m) { + return m.s.x * determinant(float3x3(m.t.y, m.u.y, m.v.y, m.t.z, m.u.z, m.v.z, m.t.w, m.u.w, m.v.w)) + - m.s.y * determinant(float3x3(m.t.x, m.u.x, m.v.x, m.t.z, m.u.z, m.v.z, m.t.w, m.u.w, m.v.w)) + + m.s.z * determinant(float3x3(m.t.x, m.u.x, m.v.x, m.t.y, m.u.y, m.v.y, m.t.w, m.u.w, m.v.w)) + - m.s.w * determinant(float3x3(m.t.x, m.u.x, m.v.x, m.t.y, m.u.y, m.v.y, m.t.z, m.u.z, m.v.z)); +} + +inline float4x4 inverse(const float4x4& m) { + return float4x4( + determinant(float3x3(m.t.y, m.u.y, m.v.y, m.t.z, m.u.z, m.v.z, m.t.w, m.u.w, m.v.w)), + -determinant(float3x3(m.s.y, m.u.y, m.v.y, m.s.z, m.u.z, m.v.z, m.s.w, m.u.w, m.v.w)), + determinant(float3x3(m.s.y, m.t.y, m.v.y, m.s.z, m.t.z, m.v.z, m.s.w, m.t.w, m.v.w)), + -determinant(float3x3(m.s.y, m.t.y, m.u.y, m.s.z, m.t.z, m.u.z, m.s.w, m.t.w, m.u.w)), + + -determinant(float3x3(m.t.x, m.u.x, m.v.x, m.t.z, m.u.z, m.v.z, m.t.w, m.u.w, m.v.w)), + determinant(float3x3(m.s.x, m.u.x, m.v.x, m.s.z, m.u.z, m.v.z, m.s.w, m.u.w, m.v.w)), + -determinant(float3x3(m.s.x, m.t.x, m.v.x, m.s.z, m.t.z, m.v.z, m.s.w, m.t.w, m.v.w)), + determinant(float3x3(m.s.x, m.t.x, m.u.x, m.s.z, m.t.z, m.u.z, m.s.w, m.t.w, m.u.w)), + + determinant(float3x3(m.t.x, m.u.x, m.v.x, m.t.y, m.u.y, m.v.y, m.t.w, m.u.w, m.v.w)), + -determinant(float3x3(m.s.x, m.u.x, m.v.x, m.s.y, m.u.y, m.v.y, m.s.w, m.u.w, m.v.w)), + determinant(float3x3(m.s.x, m.t.x, m.v.x, m.s.y, m.t.y, m.v.y, m.s.w, m.t.w, m.v.w)), + -determinant(float3x3(m.s.x, m.t.x, m.u.x, m.s.y, m.t.y, m.u.y, m.s.w, m.t.w, m.u.w)), + + -determinant(float3x3(m.t.x, m.u.x, m.v.x, m.t.y, m.u.y, m.v.y, m.t.z, m.u.z, m.v.z)), + determinant(float3x3(m.s.x, m.u.x, m.v.x, m.s.y, m.u.y, m.v.y, m.s.z, m.u.z, m.v.z)), + -determinant(float3x3(m.s.x, m.t.x, m.v.x, m.s.y, m.t.y, m.v.y, m.s.z, m.t.z, m.v.z)), + determinant(float3x3(m.s.x, m.t.x, m.u.x, m.s.y, m.t.y, m.u.y, m.s.z, m.t.z, m.u.z))) + + * (1.0f / determinant(m)); +} + +#endif // FLOATS_HPP + diff --git a/lib/qtgraph/graph_example.xml b/lib/qtgraph/graph_example.xml new file mode 100644 index 0000000..ec54db6 --- /dev/null +++ b/lib/qtgraph/graph_example.xml @@ -0,0 +1,19 @@ + + + + 53.873 90.123 + -161.127 -18.627 + -29.877 -102.377 + + + 53.873 90.123 + 140.123 -109.877 + + + -29.877 -102.377 + 140.123 -109.877 + + + 140.123 -109.877 + + diff --git a/lib/qtgraph/graphwidget.cpp b/lib/qtgraph/graphwidget.cpp index 7ffe947..16c2495 100644 --- a/lib/qtgraph/graphwidget.cpp +++ b/lib/qtgraph/graphwidget.cpp @@ -3,17 +3,41 @@ #include "edge.hpp" #include "node.hpp" -#include +#include +#include "floats.hpp" + +#include +#include +#include + +#include + +#include #include -GraphWidget::GraphWidget(QWidget *parent) - : QGraphicsView(parent), timerId(0) +namespace std { + template <> + struct hash + { + std::size_t operator()(const float2& f2) const { + std::size_t h1 = std::hash()(f2.x); + std::size_t h2 = std::hash()(f2.y); + return h1 ^ (h2 << 1); + } + }; +} + + +GraphWidget::GraphWidget(Graph* graph, QWidget *p) + : QGraphicsView(p) + , m_graph(graph) { - QGraphicsScene *scene = new QGraphicsScene(this); - scene->setItemIndexMethod(QGraphicsScene::NoIndex); - scene->setSceneRect(-200, -200, 400, 400); - setScene(scene); + QGraphicsScene *s = new QGraphicsScene(this); + s->setItemIndexMethod(QGraphicsScene::NoIndex); + s->setSceneRect(-200, -200, 400, 400); + setScene(s); + setCacheMode(CacheBackground); setViewportUpdateMode(BoundingRectViewportUpdate); setRenderHint(QPainter::Antialiasing); @@ -21,150 +45,78 @@ GraphWidget::GraphWidget(QWidget *parent) scale(qreal(0.8), qreal(0.8)); setMinimumSize(400, 400); setWindowTitle(tr("Elastic Nodes")); +} - Node *node1 = new Node(this); - Node *node2 = new Node(this); - Node *node3 = new Node(this); - Node *node4 = new Node(this); - centerNode = new Node(this); - Node *node6 = new Node(this); - Node *node7 = new Node(this); - Node *node8 = new Node(this); - Node *node9 = new Node(this); - scene->addItem(node1); - scene->addItem(node2); - scene->addItem(node3); - scene->addItem(node4); - scene->addItem(centerNode); - scene->addItem(node6); - scene->addItem(node7); - scene->addItem(node8); - scene->addItem(node9); - scene->addItem(new Edge(node1, node2)); - scene->addItem(new Edge(node2, node3)); - scene->addItem(new Edge(node2, centerNode)); - scene->addItem(new Edge(node3, node6)); - scene->addItem(new Edge(node4, node1)); - scene->addItem(new Edge(node4, centerNode)); - scene->addItem(new Edge(centerNode, node6)); - scene->addItem(new Edge(centerNode, node8)); - scene->addItem(new Edge(node6, node9)); - scene->addItem(new Edge(node7, node4)); - scene->addItem(new Edge(node8, node7)); - scene->addItem(new Edge(node9, node8)); - - node1->setPos(-50, -50); - node2->setPos(0, -50); - node3->setPos(50, -50); - node4->setPos(-50, 0); - centerNode->setPos(0, 0); - node6->setPos(50, 0); - node7->setPos(-50, 50); - node8->setPos(0, 50); - node9->setPos(50, 50); +void GraphWidget::itemMoved(const QPointF oldPos, const QPointF newPos) +{ + float2 old_v = float2(oldPos.x(), oldPos.y()); + float2 new_v = float2(newPos.x(), newPos.y()); + m_graph->modifyVertex(old_v, new_v); } -void GraphWidget::itemMoved() +void GraphWidget::updateFromGraph() { - if (!timerId) - timerId = startTimer(1000 / 25); +// for (const auto cit : m_graph) { + for (Graph::iterator cit = m_graph->begin(); cit != m_graph->end(); ++cit) { + Node *node = new Node(this); + scene()->addItem(node); + node->setPos(cit->x, cit->y); + } + +// for (const auto cit : g) { + for (Graph::iterator cit = m_graph->begin(); cit != m_graph->end(); ++cit) { + for (const auto cit2 : m_graph->neighboursOf(*cit)) { + + float2 v = *cit; + Node* node1 = dynamic_cast(scene()->itemAt(v.x, v.y)); /// @bug itemAt sometimes doesn't work + Q_CHECK_PTR(node1); + + float2 v2 = cit2; + Node* node2 = dynamic_cast(scene()->itemAt(v2.x, v2.y)); /// @bug itemAt sometimes doesn't work + Q_CHECK_PTR(node2); + + scene()->addItem(new Edge(node1, node2)); + } + } } -void GraphWidget::keyPressEvent(QKeyEvent *event) +void GraphWidget::keyPressEvent(QKeyEvent *e) { - switch (event->key()) { - case Qt::Key_Up: - centerNode->moveBy(0, -20); - break; - case Qt::Key_Down: - centerNode->moveBy(0, 20); - break; - case Qt::Key_Left: - centerNode->moveBy(-20, 0); - break; - case Qt::Key_Right: - centerNode->moveBy(20, 0); - break; + switch (e->key()) { case Qt::Key_Plus: zoomIn(); break; case Qt::Key_Minus: zoomOut(); break; - case Qt::Key_Space: - case Qt::Key_Enter: - shuffle(); - break; default: - QGraphicsView::keyPressEvent(event); - } -} - -void GraphWidget::timerEvent(QTimerEvent *event) -{ - Q_UNUSED(event); - - QList nodes; - foreach (QGraphicsItem *item, scene()->items()) { - if (Node *node = qgraphicsitem_cast(item)) - nodes << node; - } - - foreach (Node *node, nodes) - node->calculateForces(); - - bool itemsMoved = false; - foreach (Node *node, nodes) { - if (node->advance()) - itemsMoved = true; - } - - if (!itemsMoved) { - killTimer(timerId); - timerId = 0; + QGraphicsView::keyPressEvent(e); } } -void GraphWidget::wheelEvent(QWheelEvent *event) +void GraphWidget::wheelEvent(QWheelEvent *e) { - scaleView(pow((double)2, -event->delta() / 240.0)); + scaleView(pow((double)2, -e->delta() / 240.0)); } -void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect) +void GraphWidget::drawBackground(QPainter *painter, const QRectF &r) { - Q_UNUSED(rect); - // Shadow - QRectF sceneRect = this->sceneRect(); - QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height()); - QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5); - if (rightShadow.intersects(rect) || rightShadow.contains(rect)) + QRectF scene_rect = this->sceneRect(); + QRectF rightShadow(scene_rect.right(), scene_rect.top() + 5, 5, scene_rect.height()); + QRectF bottomShadow(scene_rect.left() + 5, scene_rect.bottom(), scene_rect.width(), 5); + if (rightShadow.intersects(r) || rightShadow.contains(r)) painter->fillRect(rightShadow, Qt::darkGray); - if (bottomShadow.intersects(rect) || bottomShadow.contains(rect)) + if (bottomShadow.intersects(r) || bottomShadow.contains(r)) painter->fillRect(bottomShadow, Qt::darkGray); // Fill - QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight()); + QLinearGradient gradient(scene_rect.topLeft(), scene_rect.bottomRight()); gradient.setColorAt(0, Qt::white); gradient.setColorAt(1, Qt::lightGray); - painter->fillRect(rect.intersect(sceneRect), gradient); + painter->fillRect(r.intersect(scene_rect), gradient); painter->setBrush(Qt::NoBrush); - painter->drawRect(sceneRect); - - // Text - QRectF textRect(sceneRect.left() + 4, sceneRect.top() + 4, - sceneRect.width() - 4, sceneRect.height() - 4); - QString message(tr("Click and drag the nodes around, and zoom with the mouse " - "wheel or the '+' and '-' keys")); - - QFont font = painter->font(); - font.setBold(true); - font.setPointSize(14); - painter->setFont(font); - painter->setPen(Qt::lightGray); - painter->drawText(textRect.translated(2, 2), message); - painter->setPen(Qt::black); - painter->drawText(textRect, message); + painter->drawRect(scene_rect); } void GraphWidget::scaleView(qreal scaleFactor) @@ -176,14 +128,6 @@ void GraphWidget::scaleView(qreal scaleFactor) scale(scaleFactor, scaleFactor); } -void GraphWidget::shuffle() -{ - foreach (QGraphicsItem *item, scene()->items()) { - if (qgraphicsitem_cast(item)) - item->setPos(-150 + qrand() % 300, -150 + qrand() % 300); - } -} - void GraphWidget::zoomIn() { scaleView(qreal(1.2)); @@ -193,3 +137,8 @@ void GraphWidget::zoomOut() { scaleView(1 / qreal(1.2)); } + +void GraphWidget::quit() +{ + QApplication::quit(); +} diff --git a/lib/qtgraph/graphwidget.hpp b/lib/qtgraph/graphwidget.hpp index 2f1a79f..24e2bc1 100644 --- a/lib/qtgraph/graphwidget.hpp +++ b/lib/qtgraph/graphwidget.hpp @@ -3,6 +3,8 @@ #include +class float2; +template class Graph; class Node; class GraphWidget : public QGraphicsView @@ -10,26 +12,25 @@ class GraphWidget : public QGraphicsView Q_OBJECT public: - GraphWidget(QWidget *parent = 0); + GraphWidget(Graph* graph, QWidget *parent = 0); - void itemMoved(); + void itemMoved(const QPointF oldPos, const QPointF newPos); + void updateFromGraph(); public slots: - void shuffle(); void zoomIn(); void zoomOut(); + void quit(); protected: void keyPressEvent(QKeyEvent *event); - void timerEvent(QTimerEvent *event); void wheelEvent(QWheelEvent *event); void drawBackground(QPainter *painter, const QRectF &rect); void scaleView(qreal scaleFactor); private: - int timerId; - Node *centerNode; + Graph* m_graph; }; #endif diff --git a/lib/qtgraph/main.cpp b/lib/qtgraph/main.cpp index 7746d3c..107bdcf 100644 --- a/lib/qtgraph/main.cpp +++ b/lib/qtgraph/main.cpp @@ -4,24 +4,79 @@ #include +#include +#include + +#include "floats.hpp" + +#include +#include +#include #include "graphwidget.hpp" +namespace std { + template <> + struct hash + { + std::size_t operator()(const float2& f2) const { + std::size_t h1 = std::hash()(f2.x); + std::size_t h2 = std::hash()(f2.y); + return h1 ^ (h2 << 1); + } + }; + + template + std::string to_string_with_precision(const T a_value, const int n = 6) + { + std::ostringstream out; + out << std::fixed << std::setprecision(n) << a_value; + return out.str(); + } +} + +// inline std::ostream& operator<< (std::ostream& os, const float2& f2) +// { +// os << f2.x << "," << f2.y; +// return os; +// } + +float2 float2creator(const std::string& line) +{ + std::stringstream ss(line); + float f1, f2; + ss >> f1 >> f2; + return float2(f1, f2); +} + +inline std::string float2serializer(const float2& f2) +{ + return std::to_string_with_precision(f2.x, 3) + " " + std::to_string_with_precision(f2.y, 3); +} + + int main(int argc, char **argv) { QApplication app(argc, argv); qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); - GraphWidget *widget = new GraphWidget; + + Graph g = readGraphFromXML("graph_example.xml", float2creator); + + GraphWidget *widget = new GraphWidget(&g); + widget->updateFromGraph(); QMainWindow mainWindow; mainWindow.setCentralWidget(widget); - mainWindow.menuBar()->addAction("Shuffle", widget, SLOT(shuffle())); mainWindow.menuBar()->addAction("Zoom In", widget, SLOT(zoomIn())); mainWindow.menuBar()->addAction("Zoom Out", widget, SLOT(zoomOut())); + mainWindow.menuBar()->addAction("Quit", widget, SLOT(quit())); mainWindow.show(); - return app.exec(); + const int app_retval = app.exec(); + + writeGraphToXML(g, "graph_example.xml", float2serializer); + return app_retval; } diff --git a/lib/qtgraph/node.cpp b/lib/qtgraph/node.cpp index e06452e..bc3db07 100644 --- a/lib/qtgraph/node.cpp +++ b/lib/qtgraph/node.cpp @@ -28,61 +28,6 @@ QList Node::edges() const return edgeList; } -void Node::calculateForces() -{ - if (!scene() || scene()->mouseGrabberItem() == this) { - newPos = pos(); - return; - } - - // Sum up all forces pushing this item away - qreal xvel = 0; - qreal yvel = 0; - foreach (QGraphicsItem *item, scene()->items()) { - Node *node = qgraphicsitem_cast(item); - if (!node) - continue; - - QPointF vec = mapToItem(node, 0, 0); - qreal dx = vec.x(); - qreal dy = vec.y(); - double l = 2.0 * (dx * dx + dy * dy); - if (l > 0) { - xvel += (dx * 150.0) / l; - yvel += (dy * 150.0) / l; - } - } - - // Now subtract all forces pulling items together - double weight = (edgeList.size() + 1) * 10; - foreach (Edge *edge, edgeList) { - QPointF vec; - if (edge->sourceNode() == this) - vec = mapToItem(edge->destNode(), 0, 0); - else - vec = mapToItem(edge->sourceNode(), 0, 0); - xvel -= vec.x() / weight; - yvel -= vec.y() / weight; - } - - if (qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1) - xvel = yvel = 0; - - QRectF sceneRect = scene()->sceneRect(); - newPos = pos() + QPointF(xvel, yvel); - newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)); - newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)); -} - -bool Node::advance() -{ - if (newPos == pos()) - return false; - - setPos(newPos); - return true; -} - QRectF Node::boundingRect() const { qreal adjust = 2; @@ -122,11 +67,15 @@ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) { switch (change) { - case ItemPositionHasChanged: + case ItemPositionChange: { foreach (Edge *edge, edgeList) edge->adjust(); - graph->itemMoved(); + + const QPointF old_pos = pos(); + const QPointF new_pos = value.toPointF(); + graph->itemMoved(old_pos, new_pos); break; + } default: break; }; diff --git a/lib/qtgraph/node.hpp b/lib/qtgraph/node.hpp index 3ebfb5f..93d8f76 100644 --- a/lib/qtgraph/node.hpp +++ b/lib/qtgraph/node.hpp @@ -19,9 +19,6 @@ public: enum { Type = UserType + 1 }; int type() const { return Type; } - void calculateForces(); - bool advance(); - QRectF boundingRect() const; QPainterPath shape() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);