////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Leo Tenenbaum
// This file is part of GraphColoring.
//
// GraphColoring is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GraphColoring is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GraphColoring. If not, see .
////////////////////////////////////////////////////////////////////////////////
#include "path.hpp"
#include
#include
namespace graphcoloring {
constexpr gui::Color Path::ANY_COLOR;
Path::Path(gui::Window* window_,
Graph& graph_, const RuleLoader& rule_loader_,
const ColorLoader& color_loader_)
: window(window_), graph(graph_), rule_loader(rule_loader_),
color_loader(color_loader_)
{
window->SetMouseupCallback([this] (gui::Window*,int,int) {
RightClick();
}, GDK_BUTTON_SECONDARY);
window->SetKeyupCallback([this] (gui::Window*) {
ResetPath();
}, GDK_KEY_q);
}
void Path::LoadFromNode(pugi::xml_node node)
{
std::string name = node.name();
if (name == "cycle")
type = Type::CYCLE;
else
type = Type::PATH;
points_starting_value = node.attribute("points").as_int(0);
for (pugi::xml_node point_node : node.children())
{
std::string name = point_node.name();
if (name != "edge") continue;
std::string color_str = point_node.attribute("color").value();
gui::Color color;
if (color_str == "any")
color = ANY_COLOR;
else
color =
color_loader.GetColorFromAttribute(
point_node.attribute("color"));
color_operations[color] = LoadOperation(point_node);
}
}
void Path::LoadFromDocument(const pugi::xml_document& document)
{
for (pugi::xml_node node : document.children())
{
std::string name = node.name();
if (name != "cycle" && name != "path") continue;
LoadFromNode(node);
break;
}
}
Path::operation_t Path::LoadOperation(pugi::xml_node node)
{
int val = node.attribute("val").as_int(0);
std::map operations = {
{"+", [val] (int a) { return a + val; }},
{"-", [val] (int a) { return a - val; }},
{"*", [val] (int a) { return a * val; }},
{"/", [val] (int a) { return a / val; }},
{"%", [val] (int a) { return a % val; }}
};
std::string op = node.attribute("op").value();
return operations[op];
}
void Path::RightClick()
{
if (!IsPath()) return;
if (!rule_loader.IsValid(graph)) return;
int vertex_id = graph.GetHoveringVertex();
if (vertex_id == -1) return;
graph.Lock();
if (last_vertex == -1)
{
last_vertex = vertex_id;
if (first_vertex == -1)
first_vertex = vertex_id;
return;
}
if (last_vertex == vertex_id) // Remove end of path
{
if (path.size() == 0)
{
ResetPath();
return;
}
int edge_id = path.at(path.size()-1);
path.pop_back();
last_vertex =
graph.GetEdgeByIDConst(edge_id).OtherEndpoint(last_vertex);
return;
}
if (!graph.HasEdge(last_vertex, vertex_id))
{
return;
}
int edge_id = graph.GetEdgeByEndpointsConst(last_vertex, vertex_id).id;
if (std::find(path.begin(), path.end(), edge_id) != path.end()) // Duplicate edge
return;
path.push_back(edge_id);
last_vertex = vertex_id;
}
void Path::ResetPath()
{
if (!IsPath()) return;
graph.Unlock();
path = std::vector();
is_making_path = false;
first_vertex = -1;
last_vertex = -1;
}
std::vector Path::GetPath() const
{
return path;
}
std::set Path::PathEdgeSet() const
{
return std::set(path.begin(), path.end());
}
std::set Path::PathVertexSet() const
{
std::set vertices;
if (last_vertex != -1)
vertices.insert(last_vertex);
for (int e : path)
{
const Edge& edge = graph.GetEdgeByIDConst(e);
vertices.insert(edge.from.id);
vertices.insert(edge.to.id);
}
return vertices;
}
int Path::LastVertex() const
{
return last_vertex;
}
bool Path::IsMakingPath() const
{
return is_making_path;
}
bool Path::IsPath() const
{
return type != Type::NO_PATH;
}
int Path::Points() const
{
if (!IsPath()) return 0;
if (type == Type::CYCLE)
{
if (path.size() < 2)
return 0;
if (first_vertex != last_vertex)
return 0;
}
int points = points_starting_value;
for (int e : path)
{
const Edge& edge = graph.GetEdgeByIDConst(e);
if (color_operations.count(edge.Color())
&& color_operations.at(edge.Color()))
points = color_operations.at(edge.Color())(points);
if (color_operations.count(ANY_COLOR)
&& color_operations.at(ANY_COLOR))
points = color_operations.at(ANY_COLOR)(points);
}
return points;
}
} // namespace graphcoloring