Commit 39b3ede4 authored by Yann Boucher's avatar Yann Boucher
Browse files

Support for loading images, performance optimisations for GridView

parent f9b544e5
Pipeline #78781 passed with stages
in 18 seconds
...@@ -618,6 +618,7 @@ pattern recorded :</string> ...@@ -618,6 +618,7 @@ pattern recorded :</string>
<property name="title"> <property name="title">
<string>Éditer</string> <string>Éditer</string>
</property> </property>
<addaction name="actionCharger_depuis_une_image"/>
<addaction name="action_save_struct"/> <addaction name="action_save_struct"/>
</widget> </widget>
<widget class="QMenu" name="menuA_propos"> <widget class="QMenu" name="menuA_propos">
...@@ -650,6 +651,11 @@ pattern recorded :</string> ...@@ -650,6 +651,11 @@ pattern recorded :</string>
<string>À propos de Qt</string> <string>À propos de Qt</string>
</property> </property>
</action> </action>
<action name="actionCharger_depuis_une_image">
<property name="text">
<string>Charger depuis une image...</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
......
...@@ -141,6 +141,7 @@ private: ...@@ -141,6 +141,7 @@ private:
GridGraphicsView* m_view; GridGraphicsView* m_view;
QGraphicsScene* m_scene; QGraphicsScene* m_scene;
detail::Graphics_view_zoom* m_zoom; detail::Graphics_view_zoom* m_zoom;
std::vector<GridItem*> m_item_cache; // cache pour pouvoir accéder efficacement à un Item selon une coordonnée
History m_undo_history; History m_undo_history;
unsigned m_width; unsigned m_width;
unsigned m_height; unsigned m_height;
......
...@@ -95,6 +95,9 @@ private: ...@@ -95,6 +95,9 @@ private:
//! \brief Déclenche la confirmation et la sauvegarde du modèle édité actuel //! \brief Déclenche la confirmation et la sauvegarde du modèle édité actuel
void save_model(); void save_model();
//! \brief Charge la grille depuis une image.
void load_from_image();
//! \brief Retourne le modèle par défaut à charger //! \brief Retourne le modèle par défaut à charger
QJsonObject default_model() const; QJsonObject default_model() const;
private: private:
......
...@@ -443,13 +443,15 @@ void GridView::undo() ...@@ -443,13 +443,15 @@ void GridView::undo()
GridItem *GridView::item_at(Coord pos) GridItem *GridView::item_at(Coord pos)
{ {
QGraphicsItem* gitem_ptr = m_scene->itemAt(QPointF(pos.x*GridItem::width(), pos.y*GridItem::height()), QTransform()); return m_item_cache[pos.y*m_width + pos.x];
return dynamic_cast<GridItem*>(gitem_ptr); //QGraphicsItem* gitem_ptr = m_scene->itemAt(QPointF(pos.x*GridItem::width(), pos.y*GridItem::height()), QTransform());
//return dynamic_cast<GridItem*>(gitem_ptr);
} }
const GridItem *GridView::item_at(Coord pos) const const GridItem *GridView::item_at(Coord pos) const
{ {
QGraphicsItem* gitem_ptr = m_scene->itemAt(QPointF(pos.x*GridItem::width(), pos.y*GridItem::height()), QTransform()); return m_item_cache[pos.y*m_width + pos.x];
return dynamic_cast<GridItem*>(gitem_ptr); //QGraphicsItem* gitem_ptr = m_scene->itemAt(QPointF(pos.x*GridItem::width(), pos.y*GridItem::height()), QTransform());
//return dynamic_cast<GridItem*>(gitem_ptr);
} }
void GridView::load_grid(const Grid &grid) void GridView::load_grid(const Grid &grid)
...@@ -457,6 +459,8 @@ void GridView::load_grid(const Grid &grid) ...@@ -457,6 +459,8 @@ void GridView::load_grid(const Grid &grid)
m_scene->clear(); m_scene->clear();
m_height = grid.get_rows(); m_height = grid.get_rows();
m_width = grid.get_col(); m_width = grid.get_col();
m_item_cache.clear();
m_item_cache.resize(m_width*m_height);
// Populate scene; // Populate scene;
for (unsigned i = 0; i < m_width; ++i) for (unsigned i = 0; i < m_width; ++i)
{ {
...@@ -466,8 +470,8 @@ void GridView::load_grid(const Grid &grid) ...@@ -466,8 +470,8 @@ void GridView::load_grid(const Grid &grid)
unsigned state = grid.get_state(pos); unsigned state = grid.get_state(pos);
GridItem *item = new GridItem(*this, state); GridItem *item = new GridItem(*this, state);
item->set_grid_pos(Coord{(int)i, (int)j}); item->set_grid_pos(pos);
m_item_cache[pos.y*m_width + pos.x] = item;
m_scene->addItem(item); m_scene->addItem(item);
} }
} }
......
...@@ -43,6 +43,10 @@ MainWindow::MainWindow(QWidget *parent) ...@@ -43,6 +43,10 @@ MainWindow::MainWindow(QWidget *parent)
{ {
QMessageBox::aboutQt(this, "À propos de Qt"); QMessageBox::aboutQt(this, "À propos de Qt");
}); });
connect(ui->actionCharger_depuis_une_image, &QAction::triggered, this, [this](bool)
{
load_from_image();
});
ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_pixel_size()); ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_pixel_size());
...@@ -52,10 +56,7 @@ MainWindow::MainWindow(QWidget *parent) ...@@ -52,10 +56,7 @@ MainWindow::MainWindow(QWidget *parent)
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete ui; delete ui;
if (m_transition_rule) // FIXME : il y a un risque de fuite de mémoire avec la gestion de pointeurs de m_transition_rule et m_neighborhood_rule, si l'application est quitée alors que ils pointent vers de la mémoire non transférée vers Simulation
delete m_transition_rule;
if (m_neighborhood_rule)
delete m_neighborhood_rule;
} }
/// Connections /// Connections
...@@ -355,6 +356,7 @@ void MainWindow::load_model(const QJsonObject &obj) ...@@ -355,6 +356,7 @@ void MainWindow::load_model(const QJsonObject &obj)
// On transfère la propriété de ces pointeurs vers Simulation, qui en est désormais propriétaire pour l'exécution de l'automate // On transfère la propriété de ces pointeurs vers Simulation, qui en est désormais propriétaire pour l'exécution de l'automate
simulation.setNeighborhoodRule(m_neighborhood_rule); simulation.setNeighborhoodRule(m_neighborhood_rule);
simulation.setTransitionRule(m_transition_rule); simulation.setTransitionRule(m_transition_rule);
simulation.setAlphabet(ui->grid_view->alphabet());
} }
void MainWindow::save_model() void MainWindow::save_model()
...@@ -402,6 +404,48 @@ void MainWindow::save_model() ...@@ -402,6 +404,48 @@ void MainWindow::save_model()
load_model(root); load_model(root);
} }
static unsigned closest_state(const Alphabet& alph, const QColor& color)
{
unsigned best_distance = std::numeric_limits<unsigned>::max();
unsigned best_match = 0;
for (unsigned i = 0; i < alph.taille(); ++i)
{
state s = alph.getState(i);
unsigned r_diff = qAbs(color.red() - s.getColor().getRed());
unsigned g_diff = qAbs(color.green() - s.getColor().getGreen());
unsigned b_diff = qAbs(color.blue() - s.getColor().getBlue());
unsigned distance = r_diff*r_diff + g_diff*g_diff + b_diff*b_diff;
if (distance < best_distance)
{
best_distance = distance;
best_match = i;
}
}
return best_match;
}
void MainWindow::load_from_image()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"",tr("Image (*.png *.jpg *.jpeg *.bmp *.gif"));
QImage img(fileName);
if (img.isNull())
return;
Grid grid = ui->grid_view->get_grid();
img = img.scaled(grid.get_col(),
grid.get_rows());
for (int x = 0; x < img.width(); ++x)
for (int y = 0; y < img.height(); ++y)
{
unsigned closest = closest_state(ui->grid_view->alphabet(), img.pixelColor(x, y));
grid.set_cell(Coord{x, y}, closest);
}
ui->grid_view->copy_grid(grid);
}
QJsonObject MainWindow::default_model() const QJsonObject MainWindow::default_model() const
{ {
QJsonObject obj; QJsonObject obj;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment