U
Ulkiorra199218. Dezember 2017 09:46

QGraphicsScene

Добрый день, собственно задачка такая, есть 36 частей панорамы, необходимо подгружать части, которые влезают на Scene в данный момент и выгружать в момент скроллинга части не отображающиеся на Scene

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

23
Evgenii Legotckoi
  • 18. Dezember 2017 09:55

День добрый.
А вы эти части панорамы уже разбили на какой-нибудь вектор, наподобие QVector<Image>?
Чтобы мне было понятно, с какими исходными данными вы работаете.

А ещё посмотрите вот этот топик про игру жизнь , там мы обсуждали проблемы производительности и отрисовки большого числа объектов на графической сцене. А также глянуть проект, который есть конкретно в этом посте . Не я его писал, но я его глянул. Кажется там как раз нужныя вам логика отрисовки, ну или схожая. Во всяком случае у меня в памяти осталось, что там не перерисовывались объекты, которые не видны на графической сцене (но могу и ошибаться).

    U
    • 18. Dezember 2017 09:59

    в данный момент, я разрезал панораму 64000 точек на 12000, и сохранил 36 изображений в формате png  в папке, логика, на данный момент подгружать из папки тайлы отображающиеся на Scene  для экономии памяти

      Evgenii Legotckoi
      • 18. Dezember 2017 10:04

      Я понял вашу идею. Я сейчас как раз сходной задачей по тайлам занят, но только делаю это для QML. Однако кое-какие наработки и мысли уже есть.

      У меня такой вопрос, что именно подразумеваете под экономией памяти?
      Сами тайлы для быстродействия я загружал бы все в некоторый пул объектов, как никак чтение и запись в файл тоже не быстрая операция, но вот на графической сцене держал бы только видимые.
        U
        • 18. Dezember 2017 10:11

        экономия оперативной памяти, что бы не грузить к примеру 18 тайлов, которые 2 гб съедят, а грузить 3 к примеру, максимум 4 будут видны на экране, по предварительным расчетам

          Evgenii Legotckoi
          • 18. Dezember 2017 10:17

          Понятно. У меня есть кое-какие мысли, но нужно уточнить ещё пару моментов.
          Для такого требуется следующая информация:

          • количество тайлов
          • количество тайлов в строке
          • количество тайлов в колонке
          • размер тайла
          • информация о именах тайлов, чтобы получить правильный порядок загрузки тайла из каталога
          Уточните это, а я сегодня/завтра накидаю свои мысли об этом
            U
            • 18. Dezember 2017 10:37
            возможно я немного не так понял, но на данный момент:
            панорама 360 градусов, я ее режу по вертикали на 36 тайлов, по 10 градусов получается.
            при максимальном отдалении на эране будет максимально отображаться 4 тайла
            размер тайла примерно 20 мб. (1 800х11 692 точек)
            имена тайлов просто от 0.png до 35.png
              Evgenii Legotckoi
              • 18. Dezember 2017 10:41
              • (bearbeitet)

              Ага. вот оно что. Для меня (и конкретно в моей задаче) тайлы составляют карту, в виде матрицы, то есть может быть сетка 40 на 40 тайлов и т.д. А у вас получается 1 на 36.

              Ну понятно в общем. Я всё равно над этим работаю. Вечером постараюсь глянуть и в сторону вашей задачи.
                U
                • 18. Dezember 2017 10:43

                спасибо большое, хотя бы, направление, как это реализовать, я пока не представляю как реализовать алгоритм

                  Evgenii Legotckoi
                  • 20. Dezember 2017 16:30
                  • (bearbeitet)

                  В общем смысл программы будет следующий. Вы открываете через диалоговое окно с файлами панорамы. Тайлы при этом должны иметь все одинаковые размеры (это искусственное ограничение, чтобы показать основной алгоритм, необходимые проверки потом сами реализуете, если будут тайлы разных размеров).

                   
                  Записываете нужную информацию во вьюшку, то есть пути ко всем тайлам.
                  #include "widget.h"
                  #include "ui_widget.h"
                  
                  Widget::Widget(QWidget *parent) :
                      QWidget(parent),
                      ui(new Ui::Widget)
                  {
                      ui->setupUi(this);
                      m_scene = new QGraphicsScene(this);
                      ui->graphicsView->setScene(m_scene);
                  }
                  
                  Widget::~Widget()
                  {
                      delete ui;
                  }
                  
                  void Widget::on_pushButton_clicked()
                  {
                      // Открыть все необходимые тайлы
                      ui->graphicsView->setTilePaths(QFileDialog::getOpenFileNames(this, tr("Open Tiles")));
                  }
                  

                  В самой графической вьюшке будут вектора на тайлы, а также и на пути к тайлам, которые можно будет подгружать.
                  #ifndef TILEDGRAPHICSVIEW_H
                  #define TILEDGRAPHICSVIEW_H
                  
                  #include <QGraphicsView>
                  #include <QGraphicsPixmapItem>
                  
                  class TiledGraphicsView : public QGraphicsView
                  {
                      Q_OBJECT
                  public:
                      explicit TiledGraphicsView(QWidget *parent = nullptr);
                  
                      void setTilePaths(QStringList tilePaths);
                  
                  protected:
                      virtual void paintEvent(QPaintEvent* e) override;
                  
                  private:
                      QStringList m_tilePaths;    // Пути к тайлам
                      int m_tileHeight;           // Высота тайла
                      int m_tileWidth;            // Ширина тайла
                      int m_tileSetWidth;         // Ширина графической сцены под тайлы
                      int m_tileSetHeight;        // Высота графической сцены под тайлы
                  
                      std::vector<QGraphicsPixmapItem*> m_tileItems;  // Указатели на загруженные тайлы
                  };
                  
                  #endif // TILEDGRAPHICSVIEW_H

                  Далее сам процесс отрисовки с установкой тайлов во вьюшку
                  #include "TiledGraphicsView.h"
                  
                  #include <QPainter>
                  #include <QFile>
                  #include <QGLWidget>
                  #include <QScrollBar>
                  
                  #include <QDebug>
                  
                  TiledGraphicsView::TiledGraphicsView(QWidget *parent) : QGraphicsView(parent)
                  {
                      setViewport(new QGLWidget(this));
                  }
                  
                  void TiledGraphicsView::setTilePaths(QStringList tilePaths)
                  {
                      // При загрузке нового сета тайлов очистим всё.
                      scene()->clear();
                      m_tilePaths.clear();
                      m_tileItems.clear();
                  
                      m_tilePaths = tilePaths;
                  
                      // С помощью первого тайла найдём параметры графической сцены и тайла
                      QImage firstTile(m_tilePaths.first());
                      m_tileHeight = firstTile.height();
                      m_tileWidth = firstTile.width();
                      m_tileSetWidth = m_tileWidth * m_tilePaths.length();
                      m_tileSetHeight = m_tileHeight;
                      setSceneRect(0, 0, m_tileSetWidth, m_tileSetHeight);
                  }
                  
                  void TiledGraphicsView::paintEvent(QPaintEvent *e)
                  {
                      QRect drawRect(horizontalScrollBar()->value(),
                                      verticalScrollBar()->value(),
                                      viewport()->width(),
                                      viewport()->height());
                  
                      // При каждом событии перерисовки проверяем, какие из тайлов нужно отрисовать
                      for (int i = 0; i < m_tilePaths.length(); ++i)
                      {
                          int coordX1 = i * m_tileWidth;
                          int coordX2 = coordX1 + m_tileWidth;
                          // Если тайл попадает в область отрисовки
                          if ((coordX1 >= drawRect.x() && coordX1 <= drawRect.x() + drawRect.width()) || (coordX2 >= drawRect.x() && coordX2 <= drawRect.x() + drawRect.width()))
                          {
                              // то пытаемся его отрисовать при условии, что он ещё не был отрисован
                              auto it = std::find_if(m_tileItems.begin(), m_tileItems.end(), [&coordX1](const QGraphicsPixmapItem* pixmap) { return coordX1 == pixmap->pos().x(); } );
                              if (it == m_tileItems.end())
                              {
                                  QGraphicsPixmapItem* pixmapItem = scene()->addPixmap(QPixmap(m_tilePaths.at(i)));
                                  m_tileItems.push_back(pixmapItem);
                                  pixmapItem->setPos(coordX1, 0);
                              }
                          }
                          else
                          {
                              // В противном случае удаляем его со сцены и из пула отрисованных тайлов с очисткой памяти
                              auto it = std::find_if(m_tileItems.begin(), m_tileItems.end(), [&coordX1](const QGraphicsPixmapItem* pixmap) { return coordX1 == pixmap->pos().x(); } );
                              if (it != m_tileItems.end())
                              {
                                  scene()->removeItem(*it);
                                  delete *it;
                                  m_tileItems.erase(it);
                              }
                          }
                      }
                  
                      QGraphicsView::paintEvent(e);
                  }
                    U
                    • 20. Dezember 2017 19:21

                    Спасибо большое, за помощь, и с наступающим Новым Годом!!!

                      Evgenii Legotckoi
                      • 21. Dezember 2017 05:53

                      Пожалуйста. Вас также с Наступающим Новым Годом!!!

                        U
                        • 12. Januar 2018 08:07
                        хочу еще поблагодарить за помощь, я в свой проект это все внедрил, но вот строчка, что ниже, мне совсем не понятно как это работает:
                        // то пытаемся его отрисовать при условии, что он ещё не был отрисован
                                    auto it = std::find_if(m_tileItems.begin(), m_tileItems.end(), [&coordX1](const QGraphicsPixmapItem* pixmap) { return coordX1 == pixmap->pos().x(); } );
                        и еще, возникла проблема, когда я приближаю или отдаляю изображение, программа перестает работать (тайлы не грузятся)
                            QMatrix matrix;
                            matrix.scale(1.5,1.5);
                            ui->graphicsView->setMatrix(matrix);
                        возможно вы подскажите, как сделать что бы программа работала и при зуме.
                          Evgenii Legotckoi
                          • 15. Januar 2018 13:02

                          Добрый день. Что-то я совсем забыл про ваш вопрос.

                          Чтобы сделать зум, нужно правильно пересчитывать ширину и тайлов.
                          Возможно матрица преобразования попадает в неправильные пропорции и идёт обращение к неинициализированным тайлам. Пройдитесь для начала дебагером, куда там уходит зум в не ту область памяти.

                          Что касается той строчки
                          auto it = std::find_if(m_tileItems.begin(), m_tileItems.end(), [&coordX1](const QGraphicsPixmapItem* pixmap) { return coordX1 == pixmap->pos().x(); } );
                          auto - это оператор с автоматическим выводом типа, здесь я получаю итератор, auto позволяет особо не нагружать голову с огромным названием класса итератора.

                          std::find_if - это функция стандартной библиотеки, которая осуществляет поиск по контейнеру с условием, в качестве которого выступает лямбда.

                          m_tileItems.begin() и m_tileItems.end() возвращают итераторы с указанием на начало и конец контейнера.

                          [&coordX1](const QGraphicsPixmapItem* pixmap) { return coordX1 == pixmap->pos().x(); } 
                          Это функция-условие, по которому необходимо найти нужный элемент.
                          coordX1 - это захват переменной, с помощью которой пытаемся найти нужный элемент. Лямбды могут захватывать внешние переменные, очень удобно в таких ситуациях, как здесь.

                          const QGraphicsPixmapItem* pixmap - это то, что содержится в контейнере тайлов. Там внутри цикл, в котором в функцию условия передаются все элементы в итераторе поочерёдно. Этот pixmap и есть эта проверяемая переменная. Дальше возвращается результат проверки. Если true , то объект найден. И возвращается итератор на этот объект. В противном случае false , пока все элементы в контейнере не закончатся. Если объект не найден, то будет возвращён пустой итератор, равный m_tileItems.end()
                            U
                            • 15. Januar 2018 13:06

                            спасибо, за подробное объяснение строчки, а с зумом я разобрался, все работает

                              U
                              • 18. Januar 2018 10:12

                              Добрый вечер, а можно как то "зациклить" панораму, чтобы если вправо просматривать изображение, то  после последнего тайла, грузился 1-ый  потом 2-ой и так далее, а при просмотре влево, после 1-ого грузился последний и так по кругу изображение просматривать?

                                Evgenii Legotckoi
                                • 18. Januar 2018 15:46

                                Как вариант умножать ключевые координаты, от которых вы строите весь панораму, на общую ширину панорамы и при прокрутке отталкиваться от этих кратных координат.

                                  U
                                  • 4. Februar 2018 10:51

                                  не получилось зациклить прокрутку панорамы, все что хотел реализовал, а с зацикливанием уже неделю не могу справиться, не понимаю как умножая ключевые координаты на общую ширину панорамы, можно ее по кругу прокручивать

                                    Evgenii Legotckoi
                                    • 5. Februar 2018 01:51

                                    Как появится свободное время, гляну, что там можно сделать.

                                      U
                                      • 5. Februar 2018 08:34

                                      я реализовал загрузку тайлов в отдельном потоке, чтобы скроллинг плавный был, может из за того что я его не правильно реализовал не получается зациклить панораму

                                        Evgenii Legotckoi
                                        • 11. Februar 2018 09:43

                                        Насчёт зацикливания... смотрите, Вы знаете количество тайлов и значете их ширину. Допустим будет 10 тайлов с шириной 300 пикселей. Так вот крайняя точка будет равна 3000. если вычесть из этой координаты 3000, то получится, что нужно отрисовать тайл с координатой X равной 0. То есть при прокрутке влево или вправо нужно только прибавлять или вычитать общую ширину изображения, чтобы получить корректную координату тайла, а отрисовывать тайл с координатой 3000, 6000, -3000, -6000 и т.д.

                                          U
                                          • 11. Februar 2018 09:47

                                          спасибо, завтра попробую, реализовать

                                            t
                                            • 5. November 2020 07:01

                                            Скажите есть вменяемое решение для отображения 360 панорамы в QML или как-то самому можно реализовать? Спасибо!

                                              Evgenii Legotckoi
                                              • 28. Januar 2021 08:14

                                              Да по сути тоже самое нужно делать, что и с виджетами, только кастомное расположение объектов QQuickItem.
                                              Я бы наследовался от QQuickItem и рисовал бы вручную каждый тайл.
                                              Также саму графическую сцену сделал бы из другого QQuickItem, внутри которого бы уже отображал все тайлы.

                                                Kommentare

                                                Nur autorisierte Benutzer können Kommentare posten.
                                                Bitte Anmelden oder Registrieren
                                                Letzte Kommentare
                                                ИМ
                                                Игорь Максимов5. Oktober 2024 07:51
                                                Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                                                d
                                                dblas55. Juli 2024 11:02
                                                QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                                k
                                                kmssr8. Februar 2024 18:43
                                                Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                                Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                                EVA
                                                EVA25. Dezember 2023 10:30
                                                Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                                Jetzt im Forum diskutieren
                                                J
                                                JacobFib17. Oktober 2024 03:27
                                                добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
                                                JW
                                                Jhon Wick1. Oktober 2024 15:52
                                                Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
                                                КГ
                                                Кирилл Гусарев27. September 2024 09:09
                                                Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
                                                F
                                                Fynjy22. Juli 2024 04:15
                                                при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

                                                Folgen Sie uns in sozialen Netzwerken