qtgraph loads/saves state to graph

for/release
dmatetelki 11 years ago
parent 738b6ce345
commit de42d1f3ae

@ -1,6 +1,8 @@
cmake_minimum_required (VERSION 2.6) cmake_minimum_required (VERSION 2.6)
project (PROJECT_QGRAPH) project (PROJECT_QGRAPH)
set ( CMAKE_CXX_COMPILER "/usr/bin/g++-4.9.0")
set (CXX_FLAGS "-Wall -Wextra -pedantic -Wshadow " set (CXX_FLAGS "-Wall -Wextra -pedantic -Wshadow "
"-Wpointer-arith -Wcast-qual " "-Wpointer-arith -Wcast-qual "
"-ggdb " "-ggdb "
@ -10,7 +12,29 @@ add_definitions( ${CXX_FLAGS} )
FIND_PACKAGE(Qt4 REQUIRED) FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE(${QT_USE_FILE}) 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} ) add_custom_target (clean2
target_link_libraries ( qtgraph ${QT_LIBRARIES} ) COMMAND
make clean &&
find -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} \\+ &&
rm Makefile &&
rm moc_*
)

@ -0,0 +1,293 @@
#ifndef FLOATS_HPP
#define FLOATS_HPP
#include <cmath>
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

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<graph>
<vertex pos="140.123 -109.877">
<edge>53.873 90.123</edge>
<edge>-161.127 -18.627</edge>
<edge>-29.877 -102.377</edge>
</vertex>
<vertex pos="-29.877 -102.377">
<edge>53.873 90.123</edge>
<edge>140.123 -109.877</edge>
</vertex>
<vertex pos="53.873 90.123">
<edge>-29.877 -102.377</edge>
<edge>140.123 -109.877</edge>
</vertex>
<vertex pos="-161.127 -18.627">
<edge>140.123 -109.877</edge>
</vertex>
</graph>

@ -3,17 +3,41 @@
#include "edge.hpp" #include "edge.hpp"
#include "node.hpp" #include "node.hpp"
#include <QtGui> #include <graph/graph.hpp>
#include "floats.hpp"
#include <QtGui/QKeyEvent>
#include <QtGui/QWheelEvent>
#include <QtGui/QGraphicsScene>
#include <QtGui/QApplication>
#include <QtCore/QtGlobal>
#include <math.h> #include <math.h>
GraphWidget::GraphWidget(QWidget *parent) namespace std {
: QGraphicsView(parent), timerId(0) template <>
struct hash<float2>
{
std::size_t operator()(const float2& f2) const {
std::size_t h1 = std::hash<float>()(f2.x);
std::size_t h2 = std::hash<float>()(f2.y);
return h1 ^ (h2 << 1);
}
};
}
GraphWidget::GraphWidget(Graph<float2>* graph, QWidget *p)
: QGraphicsView(p)
, m_graph(graph)
{ {
QGraphicsScene *scene = new QGraphicsScene(this); QGraphicsScene *s = new QGraphicsScene(this);
scene->setItemIndexMethod(QGraphicsScene::NoIndex); s->setItemIndexMethod(QGraphicsScene::NoIndex);
scene->setSceneRect(-200, -200, 400, 400); s->setSceneRect(-200, -200, 400, 400);
setScene(scene); setScene(s);
setCacheMode(CacheBackground); setCacheMode(CacheBackground);
setViewportUpdateMode(BoundingRectViewportUpdate); setViewportUpdateMode(BoundingRectViewportUpdate);
setRenderHint(QPainter::Antialiasing); setRenderHint(QPainter::Antialiasing);
@ -21,150 +45,78 @@ GraphWidget::GraphWidget(QWidget *parent)
scale(qreal(0.8), qreal(0.8)); scale(qreal(0.8), qreal(0.8));
setMinimumSize(400, 400); setMinimumSize(400, 400);
setWindowTitle(tr("Elastic Nodes")); setWindowTitle(tr("Elastic Nodes"));
}
Node *node1 = new Node(this); void GraphWidget::itemMoved(const QPointF oldPos, const QPointF newPos)
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()
{ {
if (!timerId) float2 old_v = float2(oldPos.x(), oldPos.y());
timerId = startTimer(1000 / 25); float2 new_v = float2(newPos.x(), newPos.y());
m_graph->modifyVertex(old_v, new_v);
} }
void GraphWidget::keyPressEvent(QKeyEvent *event) void GraphWidget::updateFromGraph()
{ {
switch (event->key()) { // for (const auto cit : m_graph) {
case Qt::Key_Up: for (Graph<float2>::iterator cit = m_graph->begin(); cit != m_graph->end(); ++cit) {
centerNode->moveBy(0, -20); Node *node = new Node(this);
break; scene()->addItem(node);
case Qt::Key_Down: node->setPos(cit->x, cit->y);
centerNode->moveBy(0, 20);
break;
case Qt::Key_Left:
centerNode->moveBy(-20, 0);
break;
case Qt::Key_Right:
centerNode->moveBy(20, 0);
break;
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) // for (const auto cit : g) {
{ for (Graph<float2>::iterator cit = m_graph->begin(); cit != m_graph->end(); ++cit) {
Q_UNUSED(event); for (const auto cit2 : m_graph->neighboursOf(*cit)) {
QList<Node *> nodes; float2 v = *cit;
foreach (QGraphicsItem *item, scene()->items()) { Node* node1 = dynamic_cast<Node*>(scene()->itemAt(v.x, v.y)); /// @bug itemAt sometimes doesn't work
if (Node *node = qgraphicsitem_cast<Node *>(item)) Q_CHECK_PTR(node1);
nodes << node;
}
foreach (Node *node, nodes) float2 v2 = cit2;
node->calculateForces(); Node* node2 = dynamic_cast<Node*>(scene()->itemAt(v2.x, v2.y)); /// @bug itemAt sometimes doesn't work
Q_CHECK_PTR(node2);
bool itemsMoved = false; scene()->addItem(new Edge(node1, node2));
foreach (Node *node, nodes) {
if (node->advance())
itemsMoved = true;
} }
if (!itemsMoved) {
killTimer(timerId);
timerId = 0;
} }
} }
void GraphWidget::wheelEvent(QWheelEvent *event) void GraphWidget::keyPressEvent(QKeyEvent *e)
{ {
scaleView(pow((double)2, -event->delta() / 240.0)); switch (e->key()) {
case Qt::Key_Plus:
zoomIn();
break;
case Qt::Key_Minus:
zoomOut();
break;
default:
QGraphicsView::keyPressEvent(e);
}
} }
void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect) void GraphWidget::wheelEvent(QWheelEvent *e)
{ {
Q_UNUSED(rect); scaleView(pow((double)2, -e->delta() / 240.0));
}
void GraphWidget::drawBackground(QPainter *painter, const QRectF &r)
{
// Shadow // Shadow
QRectF sceneRect = this->sceneRect(); QRectF scene_rect = this->sceneRect();
QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height()); QRectF rightShadow(scene_rect.right(), scene_rect.top() + 5, 5, scene_rect.height());
QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5); QRectF bottomShadow(scene_rect.left() + 5, scene_rect.bottom(), scene_rect.width(), 5);
if (rightShadow.intersects(rect) || rightShadow.contains(rect)) if (rightShadow.intersects(r) || rightShadow.contains(r))
painter->fillRect(rightShadow, Qt::darkGray); painter->fillRect(rightShadow, Qt::darkGray);
if (bottomShadow.intersects(rect) || bottomShadow.contains(rect)) if (bottomShadow.intersects(r) || bottomShadow.contains(r))
painter->fillRect(bottomShadow, Qt::darkGray); painter->fillRect(bottomShadow, Qt::darkGray);
// Fill // Fill
QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight()); QLinearGradient gradient(scene_rect.topLeft(), scene_rect.bottomRight());
gradient.setColorAt(0, Qt::white); gradient.setColorAt(0, Qt::white);
gradient.setColorAt(1, Qt::lightGray); gradient.setColorAt(1, Qt::lightGray);
painter->fillRect(rect.intersect(sceneRect), gradient); painter->fillRect(r.intersect(scene_rect), gradient);
painter->setBrush(Qt::NoBrush); painter->setBrush(Qt::NoBrush);
painter->drawRect(sceneRect); painter->drawRect(scene_rect);
// 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);
} }
void GraphWidget::scaleView(qreal scaleFactor) void GraphWidget::scaleView(qreal scaleFactor)
@ -176,14 +128,6 @@ void GraphWidget::scaleView(qreal scaleFactor)
scale(scaleFactor, scaleFactor); scale(scaleFactor, scaleFactor);
} }
void GraphWidget::shuffle()
{
foreach (QGraphicsItem *item, scene()->items()) {
if (qgraphicsitem_cast<Node *>(item))
item->setPos(-150 + qrand() % 300, -150 + qrand() % 300);
}
}
void GraphWidget::zoomIn() void GraphWidget::zoomIn()
{ {
scaleView(qreal(1.2)); scaleView(qreal(1.2));
@ -193,3 +137,8 @@ void GraphWidget::zoomOut()
{ {
scaleView(1 / qreal(1.2)); scaleView(1 / qreal(1.2));
} }
void GraphWidget::quit()
{
QApplication::quit();
}

@ -3,6 +3,8 @@
#include <QtGui/QGraphicsView> #include <QtGui/QGraphicsView>
class float2;
template<class T> class Graph;
class Node; class Node;
class GraphWidget : public QGraphicsView class GraphWidget : public QGraphicsView
@ -10,26 +12,25 @@ class GraphWidget : public QGraphicsView
Q_OBJECT Q_OBJECT
public: public:
GraphWidget(QWidget *parent = 0); GraphWidget(Graph<float2>* graph, QWidget *parent = 0);
void itemMoved(); void itemMoved(const QPointF oldPos, const QPointF newPos);
void updateFromGraph();
public slots: public slots:
void shuffle();
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();
void quit();
protected: protected:
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event);
void timerEvent(QTimerEvent *event);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);
void drawBackground(QPainter *painter, const QRectF &rect); void drawBackground(QPainter *painter, const QRectF &rect);
void scaleView(qreal scaleFactor); void scaleView(qreal scaleFactor);
private: private:
int timerId; Graph<float2>* m_graph;
Node *centerNode;
}; };
#endif #endif

@ -4,24 +4,79 @@
#include <QtCore/QTime> #include <QtCore/QTime>
#include <graph/graph.hpp>
#include <graph/graph_xml.hpp>
#include "floats.hpp"
#include <iostream>
#include <iomanip>
#include <sstream>
#include "graphwidget.hpp" #include "graphwidget.hpp"
namespace std {
template <>
struct hash<float2>
{
std::size_t operator()(const float2& f2) const {
std::size_t h1 = std::hash<float>()(f2.x);
std::size_t h2 = std::hash<float>()(f2.y);
return h1 ^ (h2 << 1);
}
};
template <typename T>
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) int main(int argc, char **argv)
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
GraphWidget *widget = new GraphWidget;
Graph<float2> g = readGraphFromXML<float2>("graph_example.xml", float2creator);
GraphWidget *widget = new GraphWidget(&g);
widget->updateFromGraph();
QMainWindow mainWindow; QMainWindow mainWindow;
mainWindow.setCentralWidget(widget); mainWindow.setCentralWidget(widget);
mainWindow.menuBar()->addAction("Shuffle", widget, SLOT(shuffle()));
mainWindow.menuBar()->addAction("Zoom In", widget, SLOT(zoomIn())); mainWindow.menuBar()->addAction("Zoom In", widget, SLOT(zoomIn()));
mainWindow.menuBar()->addAction("Zoom Out", widget, SLOT(zoomOut())); mainWindow.menuBar()->addAction("Zoom Out", widget, SLOT(zoomOut()));
mainWindow.menuBar()->addAction("Quit", widget, SLOT(quit()));
mainWindow.show(); mainWindow.show();
return app.exec(); const int app_retval = app.exec();
writeGraphToXML<float2>(g, "graph_example.xml", float2serializer);
return app_retval;
} }

@ -28,61 +28,6 @@ QList<Edge *> Node::edges() const
return edgeList; 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<Node *>(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 QRectF Node::boundingRect() const
{ {
qreal adjust = 2; qreal adjust = 2;
@ -122,11 +67,15 @@ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid
QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value)
{ {
switch (change) { switch (change) {
case ItemPositionHasChanged: case ItemPositionChange: {
foreach (Edge *edge, edgeList) foreach (Edge *edge, edgeList)
edge->adjust(); edge->adjust();
graph->itemMoved();
const QPointF old_pos = pos();
const QPointF new_pos = value.toPointF();
graph->itemMoved(old_pos, new_pos);
break; break;
}
default: default:
break; break;
}; };

@ -19,9 +19,6 @@ public:
enum { Type = UserType + 1 }; enum { Type = UserType + 1 };
int type() const { return Type; } int type() const { return Type; }
void calculateForces();
bool advance();
QRectF boundingRect() const; QRectF boundingRect() const;
QPainterPath shape() const; QPainterPath shape() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

Loading…
Cancel
Save