조성현

add comment, minor revision

......@@ -13,13 +13,13 @@ void NodeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
}
NodeItem::NodeItem(int x, int y)
NodeItem::NodeItem(int x, int y, QString label)
{
this->x = x;
this->y = y;
//this->color = QColor(Qt::green); //R, G, B
this->color = QColor(Qt::green);
setZValue((x+y)%2);
this->label = label;
setZValue(1);
setFlags(ItemIsSelectable | ItemIsMovable);
setAcceptHoverEvents(true);
......@@ -42,100 +42,23 @@ void NodeItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option
{
Q_UNUSED(widget);
//QColor fillColor = (option->state & QStyle::State_Selected) ? color.dark(150) : color;
//if (option->state & QStyle::State_MouseOver)
// fillColor = fillColor.light(125);
//label
QFont font("Gulim", 10);
font.setStyleStrategy(QFont::ForceOutline);
painter->setFont(font);
painter->save();
painter->scale(0.3, 0.3);
painter->drawText(0, 0, label);
painter->restore();
//const qreal& lod = option->levelOfDetailFromTransform(painter->worldTransform());
//if (lod < 0.2) {
// if (lod < 0.125) {
// painter->fillRect(QRectF(0, 0, 110, 70), fillColor);
// return;
// }
// QBrush b = painter->brush();
// painter->setBrush(fillColor);
// painter->drawRect(13, 13, 97, 57);
// painter->setBrush(b);
// return;
//}
//QPen oldPen = painter->pen();
//QPen pen = oldPen;
//int width = 0;
//if (option->state & QStyle::State_Selected)
// width += 2;
//pen.setWidth(width);
//QBrush b = painter->brush();
//painter->setBrush(QBrush(fillColor.dark(option->state & QStyle::State_Sunken ? 120 : 100)));
//painter->drawRect(QRect(14, 14, 79, 39));
//painter->setBrush(b);
//if (lod >= 1) {
// painter->setPen(QPen(Qt::gray, 1));
// painter->drawLine(15, 54, 94, 54);
// painter->drawLine(94, 53, 94, 15);
// painter->setPen(QPen(Qt::black, 0));
//}
//Rectangle
QColor fillColor = (option->state & QStyle::State_Selected) ? color.dark(150) : color;
if (option->state & QStyle::State_MouseOver) fillColor = fillColor.light(125);
painter->setPen(QPen(Qt::black));
QPen pen = painter->pen();
pen.setWidth(0);
pen.setColor(QColor(Qt::black));
painter->setPen(pen);
painter->setBrush(QBrush(fillColor));
painter->drawRect(0, 0, NODE_SIZE, NODE_SIZE);
//painter->fillRect(QRectF(0, 0, NODE_SIZE, NODE_SIZE), fillColor);
//painter->drawRect(0, 0, NODE_SIZE, NODE_SIZE);
// Draw text
//if (lod >= 2) {
// QFont font("Times", 10);
// font.setStyleStrategy(QFont::ForceOutline);
// painter->setFont(font);
// painter->save();
// painter->scale(0.1, 0.1);
// painter->drawText(170, 180, QString("Model: VSC-2000 (Very Small Chip) at %1x%2").arg(x).arg(y));
// painter->drawText(170, 200, QString("Serial number: DLWR-WEER-123L-ZZ33-SDSJ"));
// painter->drawText(170, 220, QString("Manufacturer: Chip Manufacturer"));
// painter->restore();
//}
// Draw lines
//QVarLengthArray<QLineF, 36> lines;
//if (lod >= 0.5) {
// for (int i = 0; i <= 10; i += (lod > 0.5 ? 1 : 2)) {
// lines.append(QLineF(18 + 7 * i, 13, 18 + 7 * i, 5));
// lines.append(QLineF(18 + 7 * i, 54, 18 + 7 * i, 62));
// }
// for (int i = 0; i <= 6; i += (lod > 0.5 ? 1 : 2)) {
// lines.append(QLineF(5, 18 + i * 5, 13, 18 + i * 5));
// lines.append(QLineF(94, 18 + i * 5, 102, 18 + i * 5));
// }
//}
//if (lod >= 0.4) {
// const QLineF lineData[] = {
// QLineF(25, 35, 35, 35),
// QLineF(35, 30, 35, 40),
// QLineF(35, 30, 45, 35),
// QLineF(35, 40, 45, 35),
// QLineF(45, 30, 45, 40),
// QLineF(45, 35, 55, 35)
// };
// lines.append(lineData, 6);
//}
//painter->drawLines(lines.data(), lines.size());
// Draw red ink
//if (stuff.size() > 1) {
// QPen p = painter->pen();
// painter->setPen(QPen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
// painter->setBrush(Qt::NoBrush);
// QPainterPath path;
// path.moveTo(stuff.first());
// for (int i = 1; i < stuff.size(); ++i)
// path.lineTo(stuff.at(i));
// painter->drawPath(path);
// painter->setPen(p);
//}
}
......
......@@ -14,6 +14,7 @@ private:
int x;
int y;
QColor color;
QString label;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
......@@ -21,7 +22,7 @@ protected:
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
public:
NodeItem(int x, int y);
NodeItem(int x, int y, QString label);
QRectF boundingRect() const override;
QPainterPath shape() const override;
......
......@@ -145,6 +145,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="EdgeItem.cpp" />
<ClCompile Include="GeneratedFiles\Debug\moc_GraphicsView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
......@@ -217,6 +218,7 @@
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClInclude Include="EdgeItem.h" />
<ClInclude Include="GeneratedFiles\ui_PaperGraphWidget.h" />
<CustomBuild Include="GraphicsView.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
......
......@@ -62,6 +62,9 @@
<ClCompile Include="GeneratedFiles\Release\moc_GraphicsView.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="EdgeItem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="PaperGraphWidget.h">
......@@ -84,5 +87,8 @@
<ClInclude Include="NodeItem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EdgeItem.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
......
#include "PaperGraphWidget.h"
#include "NodeItem.h"
#include "EdgeItem.h"
#include "GraphicsView.h"
#include <string>
PaperGraphWidget::PaperGraphWidget(QWidget *parent)
: QWidget(parent)
{
......@@ -20,6 +23,52 @@ PaperGraphWidget::PaperGraphWidget(QWidget *parent)
void PaperGraphWidget::print_graph(const Graph & graph)
{
//print graph
typedef square_topology<> Topology;
typedef typename Topology::point_type Point;
const int rect_sz = 4;
auto position = get(vertex_position, graph);
auto label = get(vertex_name, graph);
//print edges
typename graph_traits<Graph>::edge_iterator ei, ei_end;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
VertexDescriptor u, v;
for (boost::tie(ei, ei_end)=edges(graph); ei!=ei_end; ++ei) {
u = source(*ei, graph);
v = target(*ei, graph);
Point p1 = position[u];
Point p2 = position[v];
/*line = scene->addLine(
p1[0], p1[1],
p2[0], p2[1],
QPen(Qt::black)
);*/
//QGraphicsItem *edge =
// new EdgeItem(p1[0], p1[1], p2[0], p2[1]);
//edge->setPos(QPointF(p1[0], p1[1]));
//scene->addItem(edge);
scene->addLine(p1[0], p1[1], p2[0], p2[1], QPen(Qt::black, 0));
}
//print nodes
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end)=vertices(graph); vi!=vi_end; ++vi) {
//Point p = position[*vi];
//rectangle = scene->addRect(
// p[0], p[1], rect_sz, rect_sz,
// QPen(Qt::black),
// QBrush(Qt::green));
Point p = position[*vi];
std::string name = label[*vi];
QGraphicsItem *node = new NodeItem(p[0], p[1], QString(name.c_str()));
node->setPos(QPointF(p[0], p[1]));
scene->addItem(node);
}
}
void PaperGraphWidget::initscene()
......
......@@ -5,8 +5,8 @@
#include <QGraphicsScene>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/kamada_kawai_spring_layout.hpp>
#include <boost/graph/random_layout.hpp>
#include <boost/graph/topology.hpp>
#include <boost/graph/graph_traits.hpp>
#include "ui_PaperGraphWidget.h"
......@@ -33,7 +33,6 @@ typedef adjacency_list<
listS, //VertexList
undirectedS,
//vertex properties
//VertexProperties,
VertexProperties,
//edge properties
boost::property<edge_weight_t, double>
......
......@@ -10,14 +10,29 @@
#include <map>
#include <vector>
#include <boost/graph/fruchterman_reingold.hpp>
//#include <boost/graph/kamada_kawai_spring_layout.hpp>
#include <boost/graph/random_layout.hpp>
#include <boost/graph/circle_layout.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/algorithm/string.hpp> //boost::split
//#include <boost/bind.hpp>
#include <boost/bimap.hpp>
using namespace std;
const string PAPER_FILENAME = "dblp-paper.txt";
/**
* Constants
*/
const char* PAPER_FILENAME = "dblp-paper.txt";
enum GRAPH_LAYOUT {
RANDOM_LAYOUT,
CIRCLE_LAYOUT,
//KAMADA_KAWAI_LAYOUT,
FRUCHTERMAN_REINGOLD_LAYOUT //slow
};
const int LAYOUT_MODE = GRAPH_LAYOUT::RANDOM_LAYOUT;
const int SCREEN_SIZE = 500;
const int NODE_LIMIT = 100;
Graph read_graph(ifstream& in) {
/**
......@@ -31,82 +46,160 @@ Graph read_graph(ifstream& in) {
vector<std::string> authors;
vector<pair<string, string>> edges;
//String <--> int 양방향 변환을 위해 bidirectional map 상숑
typedef boost::bimap<string, int> bm_type;
bm_type node_ids;
vector<simple_edge> edges_indexes;
vector<simple_edge> edges_indexes; //int로 변환된 edge
int node_cnt = 0;
qDebug() << "* graph reading start" << endl;
qDebug() << "* graph reading start";
//한 줄씩 읽어서 Parse
while (std::getline(in, line) && !line.empty()) {
//boost::split 이용해 문자열 분리
//tokens[0]: Paper-key. ex) conf/iastedCSN/KeimS06
//tokens[1]: Authors. ex) Werner Keim&&Arpad L. Scholtz
//tokens[2]: Published year.
boost::split(tokens, line, boost::is_any_of("||"), boost::token_compress_on);
boost::split(authors, tokens[1], boost::is_any_of("&&"), boost::token_compress_on);
const string& paper_key = tokens[0];
if (node_ids.left.find(paper_key) == node_ids.left.end()) {
//node_ids[paper_key] = node_cnt++;
node_ids.insert(bm_type::value_type(paper_key, node_cnt++));
//qDebug() << paper_key.c_str() << " ";
}
for (auto author : authors) {
edges.push_back(pair<string, string>(paper_key, author));
if (node_ids.left.find(author) == node_ids.left.end()) {
//node_ids[author] = node_cnt++;
node_ids.insert(bm_type::value_type(author, node_cnt++));
//qDebug() << author.c_str() << " ";
}
}
//debug
if (node_cnt > 100) break;
if (node_cnt > NODE_LIMIT) break;
}
qDebug() << "* graph reading complete" << endl;
//std::sort(node_names.begin(), node_names.end());
qDebug() << "* graph reading complete";
qDebug() << "* # of nodes: " << node_cnt;
qDebug() << "* # of edges: " << edges.size();
//Make graph
//Graph --> defined in "PaperGraphWidget.h"
//edge conversion
//<string, string> to <int, int>
//using boost::bimap (bidirectional map)
for (auto edge : edges) {
edges_indexes.push_back({
node_ids.left.find(edge.first)->get_right(),
node_ids.left.find(edge.second)->get_right()
});
}
//Graph --> defined in "PaperGraphWidget.h"
Graph graph(edges_indexes.begin(), edges_indexes.end(), node_ids.size());
//print map
//for (auto it=node_ids.left.begin(), itend=node_ids.left.end();
// it!=itend; ++it) {
// qDebug() << it->first.c_str() << " " << it->second << endl;
//}
//set index property
qDebug() << "* set vertex property start";
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
vertex_iterator vi, vi_end;
int i = 0;
for (boost::tie(vi, vi_end)=vertices(graph); vi!=vi_end; ++vi) {
//Vertex Property 설정
//index: 0 ~ ...
//name : map의 value(i) 기준으로 찾은 Key
// map --> map<string, int> (boost bidirectional map)
boost::put(vertex_index, graph, *vi, i);
boost::put(vertex_name, graph, *vi,
node_ids.right.find(i)->get_left());
//VertexProperties prop = VertexProperties(i,
// boost::property<vertex_name_t, std::string,
// boost::property<vertex_position_t, point>>());
++i;
}
qDebug() << "* set vertex property end";
//for (auto edge : edges) {
// //add edge
// //VertexProperties prop = VertexProperties()
// //add_edge(node_ids[edge.first], node_ids[edge.second],);
//}
//모든 edge weight 1로 만들기
edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end)=boost::edges(graph); ei!=ei_end; ++ei) {
boost::put(edge_weight, graph, *ei, 1);
}
//make graph layout
//path finding between two vertices
//using dijkstra algorithm
//ex) "Werner Keim" ---> "Arpad L. Scholtz" (in dataset 2nd line)
qDebug() << "* path finding start";
typedef graph_traits<Graph>::vertex_descriptor vertex_descriptor;
std::vector<vertex_descriptor> parent(num_vertices(graph));
std::vector<int> distance(num_vertices(graph));
int start_idx = node_ids.left.find("Werner Keim")->get_right();
vertex_descriptor start_v = vertex(start_idx, graph);
dijkstra_shortest_paths(
graph,
start_v,
predecessor_map(
boost::make_iterator_property_map(parent.begin(), get(boost::vertex_index, graph))
).distance_map(boost::make_iterator_property_map(distance.begin(), get(boost::vertex_index, graph)))
);
qDebug() << "* path finding end";
int aaaa = 3;
//graph layout calculation
//using boost::random_graph_layout and boost::kamada_kawai_spring_layout
//vertex마다 계산된 좌표를 property에 적용
//예제 코드: http://www.boost.org/doc/libs/1_63_0/libs/graph/test/layout_test.cpp
//(-> 콘솔 기반)
qDebug() << "* make graph layout start";
typedef square_topology<> Topology;
minstd_rand gen;
Topology topology(gen, (double)SCREEN_SIZE);
Topology::point_type origin;
origin[0] = origin[1] = (double)SCREEN_SIZE;
Topology::point_difference_type extent;
extent[0] = extent[1] = (double)SCREEN_SIZE;
rectangle_topology<> rect_top(gen,
-SCREEN_SIZE/2, -SCREEN_SIZE/2,
SCREEN_SIZE/2, SCREEN_SIZE/2);
std::vector<Topology::point_difference_type> displacements(num_vertices(graph));
switch (LAYOUT_MODE) {
case GRAPH_LAYOUT::RANDOM_LAYOUT:
random_graph_layout(graph, get(vertex_position, graph), rect_top);
break;
case GRAPH_LAYOUT::CIRCLE_LAYOUT:
circle_graph_layout(graph, get(vertex_position, graph), SCREEN_SIZE/2);
break;
//case GRAPH_LAYOUT::KAMADA_KAWAI_LAYOUT:
// kamada_kawai_spring_layout(graph,
// get(vertex_position, graph),
// get(edge_weight, graph),
// topology,
// side_length((double)SCREEN_SIZE)
// );
// break;
case GRAPH_LAYOUT::FRUCHTERMAN_REINGOLD_LAYOUT:
//fruchterman_reingold_force_directed_layout(graph,
// get(vertex_position, graph),
// topology,
// square_distance_attractive_force(),
// square_distance_repulsive_force(),
// all_force_pairs(),
// linear_cooling<double>(SCREEN_SIZE/2),
// make_iterator_property_map(displacements.begin(),
// get(vertex_index, graph),
// Topology::point_difference_type())
//);
fruchterman_reingold_force_directed_layout(graph,
get(vertex_position, graph),
topology,
attractive_force(square_distance_attractive_force())
.cooling(linear_cooling<double>(50))
);
break;
}
qDebug() << "* make graph layout end";
return graph;
}
......@@ -114,7 +207,7 @@ Graph read_graph(ifstream& in) {
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
//app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
PaperGraphWidget w;
......