9 #include <QErrorMessage> 10 #include <QMessageBox> 11 #include <QStandardPaths> 12 #include <QDesktopServices> 15 #include <QJsonDocument> 16 #include <QJsonObject> 19 #include "ui_mainwindow.h" 25 using namespace input;
27 FrechetViewApplication* FrechetViewApplication::frechetViewApp =
nullptr;
29 FrechetViewApplication::FrechetViewApplication(QString exec_path,
bool withGui)
30 : history(), currentId(0),
43 _currentAlgorithm(ALGORITHM_CURVE)
64 Q_ASSERT(
P.empty() &&
Q.empty());
95 connect(
fileWatch, SIGNAL(fileChanged(QString)),
96 this, SLOT(
open(QString)),
97 Qt::QueuedConnection);
102 presentation_mode =
true;
103 if (!presentation_mode) {
104 window->
ui->menuExperimental->setEnabled(
false);
105 window->
ui->menuView->removeAction(
window->
ui->menuExperimental->menuAction());
106 window->
ui->actionShow_Animation->setEnabled(
false);
107 window->
ui->actionShow_XAnimation->setEnabled(
false);
108 window->
ui->actionStart_Animation->setEnabled(
false);
109 window->
ui->actionStart_FSAnimation->setEnabled(
false);
110 window->
ui->actionStart_CVAnimation->setEnabled(
false);
111 window->
ui->actionStart_ProjectionAnimation->setEnabled(
false);
116 settings.beginGroup(
"desktop");
119 QString installPath = settings.value(
"exec.path").toString();
120 bool iconsInstalled = settings.value(
"icons.installed").toBool();
124 settings.setValue(
"exec.path",
execPath);
126 if (!iconsInstalled) {
128 settings.setValue(
"icons.installed",
true);
181 fdlg.restoreState(settings.value(
"filedialog.open").toByteArray());
182 fdlg.setAcceptMode(QFileDialog::AcceptOpen);
183 fdlg.setFileMode(QFileDialog::ExistingFile);
190 dir = settings.value(
"filedialog.open.dir").toString();
191 fdlg.setDirectory(dir);
194 QStringList fileNames;
196 fileNames = fdlg.selectedFiles();
197 if (!fileNames.isEmpty())
198 open(fileNames.first());
201 settings.setValue(
"filedialog.open",fdlg.saveState());
202 settings.setValue(
"filedialog.open.dir",fdlg.directory().absolutePath());
211 QString oldPath =
path.
getFile().absoluteFilePath();
213 QString newPath =
path.
getFile().absoluteFilePath();
216 if (!oldPath.isEmpty())
227 if (!filePath.isEmpty()) {
232 QErrorMessage* msg =
new QErrorMessage();
247 P = paths[0].toCurve(precision);
248 Q = paths[1].toCurve(precision);
253 grid->hor().setLineStyles(
254 paths[p_is_primary?0:1].getLineStyles(),
255 paths[p_is_primary?0:1].getDefaultLineStyle());
256 grid->vert().setLineStyles(
257 paths[p_is_primary?1:0].getLineStyles(),
258 paths[p_is_primary?1:0].getDefaultLineStyle());
287 connect(
polyAlgorithm.get(), SIGNAL(optimisationResult(
double)),
289 connect(
polyAlgorithm.get(), SIGNAL(optimisationResult(
double)),
300 connect(
kAlgorithm.get(), SIGNAL(greedyFinished()),
303 connect(
kAlgorithm.get(), SIGNAL(bruteForceFinished()),
305 connect(
kAlgorithm.get(), SIGNAL(bruteForceIteration(
int)),
325 if (!filePath.isEmpty()) {
327 window->
ui->actionEdit_Curve->setEnabled(
true);
331 window->
ui->actionEdit_Curve->setEnabled(
false);
359 msg.setText(qApp->applicationDisplayName()+
" " 360 + qApp->applicationVersion()+
"\n\n" 361 +
"Build: "+__DATE__+
" "+__TIME__);
362 msg.setIconPixmap(
window->windowIcon().pixmap(64,64));
368 QDir desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
369 QDir appDir = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
372 QString target = desktopDir.filePath(
"frechet-view.desktop");
376 QFile::setPermissions(target,
377 QFile::ReadUser|QFile::ReadGroup|QFile::ReadOther|
379 QFile::ExeGroup|QFile::ExeUser|QFile::ExeOther);
384 QDir dir = QFileInfo(this->
execPath).dir();
387 bool created = QFile::link( dir.absolutePath(),
388 desktopDir.absoluteFilePath(
"Fréchet View"));
393 bool created = QFile::link( this->
execPath, desktopDir.absoluteFilePath(
"Fréchet View.lnk"));
396 created = QFile::link( this->
execPath, appDir.absoluteFilePath(
"Fréchet View.lnk"));
403 QDesktopServices::openUrl(
436 double approx =
epsMax * 1e-5;
458 double approx =
epsMax * 1e-5;
490 QString iconDir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
491 if (iconDir==
nullptr || iconDir.isEmpty())
return;
493 iconDir +=
"/.local/share/icons";
495 QStringList themes = {
"default",
"hicolor" };
496 QStringList sizes = {
"16",
"32",
"48",
"64",
"96",
"128",
"256"};
498 foreach(QString theme, themes)
501 iconDir+
"/"+theme+
"/scalable/apps/frechet-view.svg");
503 foreach(QString size, sizes)
504 copyFile(
":/frechet-view-"+size+
".png",
505 iconDir+
"/"+theme+
"/"+size+
"x"+size+
"/apps/frechet-view.png");
512 QString applDir = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
513 if (applDir.isEmpty())
return;
516 if (desktop.isEmpty())
return;
519 applDir+
"/frechet-view.desktop");
526 QByteArray execName =
"frechet-view.sh";
527 QString iconPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
528 if (iconPath.isEmpty())
return "";
530 iconPath +=
"/.local/share/icons/hicolor/scalable/apps/frechet-view.svg";
531 QString iconEntry =
"Icon="+iconPath;
533 QFile desktopFile (
":/frechet-view.desktop");
534 if (!desktopFile.open(QFile::ReadOnly))
return "";
536 QByteArray desktopContentsArray = desktopFile.readAll();
537 if (desktopContentsArray.isEmpty())
return "";
539 QString desktopContents = desktopContentsArray;
541 int i1 = desktopContents.indexOf(
"Exec=");
542 i1 = desktopContents.indexOf(execName,i1);
544 desktopContents.replace(
545 i1, execName.length(),
548 desktopContents.replace(
551 return desktopContents;
559 QString bookmarkPath = QStandardPaths::locate(
560 QStandardPaths::AppConfigLocation,
561 "bookmarks.json",QStandardPaths::LocateFile);
563 if (bookmarkPath==
nullptr || bookmarkPath.isEmpty())
567 QFile bookmarkFile(bookmarkPath);
568 if (!bookmarkFile.open(QFile::ReadOnly))
571 QByteArray jsonData = bookmarkFile.readAll();
572 QJsonParseError parseError;
573 QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData,&parseError);
574 if (parseError.error != QJsonParseError::NoError) {
575 std::cerr << parseError.errorString().toStdString() << std::endl;
579 QToolBar* toolBar =
window->
ui->mainToolBar;
581 QIcon fileIcon(
":awesome/file-regular.svg");
583 QJsonObject root = jsonDoc.object();
584 QString baseDirectory = root[
"base-directory"].toString();
586 QJsonArray bookmarks = root[
"bookmarks"].toArray();
587 foreach(QJsonValue bookmark, bookmarks) {
588 QString file = bookmark[
"file"].toString();
589 QString label = bookmark[
"label"].toString();
590 QString shortCut = bookmark[
"short-cut"].toString();
592 if (!any) toolBar->addSeparator();
595 QAction* action = toolBar->addAction(fileIcon, label, [=]{ this->
open(baseDirectory+QDir::separator()+file); });
596 action->setShortcut(QKeySequence::fromString(shortCut));
597 action->setToolTip(file+
" "+shortCut);
600 toolBar->setIconSize(QSize(14,14));
606 QFileInfo dinfo(dst);
607 QDir(
"/").mkpath(dinfo.absolutePath());
609 dfile.open(QFile::WriteOnly);
610 dfile.write(contents.constData());
615 QFileInfo dinfo(dst);
616 QDir(
"/").mkpath(dinfo.absolutePath());
617 QFile::copy(src,dst);
651 if (stat <= frechet::poly::Algorithm::Status::RUNNING) {
657 case frechet::poly::Algorithm::Status::SET_UP:
660 case frechet::poly::Algorithm::Status::RUNNING:
661 case frechet::poly::Algorithm::Status::YES:
662 case frechet::poly::Algorithm::Status::NO:
663 case frechet::poly::Algorithm::Status::NOT_SET_UP:
667 case frechet::poly::Algorithm::Status::P_EMPTY:
668 case frechet::poly::Algorithm::Status::Q_EMPTY:
670 case frechet::poly::Algorithm::Status::P_NOT_SIMPLE:
671 case frechet::poly::Algorithm::Status::Q_NOT_SIMPLE:
675 case frechet::poly::Algorithm::Status::P_NOT_CLOSED:
676 case frechet::poly::Algorithm::Status::Q_NOT_CLOSED:
687 case frechet::poly::Algorithm::Status::P_NOT_COUNTER_CLOCKWISE:
688 case frechet::poly::Algorithm::Status::Q_NOT_COUNTER_CLOCKWISE:
696 case frechet::poly::Algorithm::Status::P_NOT_COUNTER_CLOCKWISE:
697 case frechet::poly::Algorithm::Status::Q_NOT_COUNTER_CLOCKWISE:
702 case frechet::poly::Algorithm::Status::P_CONVEX:
703 case frechet::poly::Algorithm::Status::Q_CONVEX:
735 QString message =
"Please open an input file. \n" 736 "Accepted files are:\n\n" 737 "- Vector graphics (SVG, IPE)\n\t containing two paths\n" 738 "- Script files (*.js); see examples";
740 return QMessageBox::information(
window,
"Welcome", message,
741 QMessageBox::Open | QMessageBox::Cancel,
742 QMessageBox::Open) == QMessageBox::Open;
worker job for executing the optimisation variant, or approximation variant, on curves (not on simple...
void installLinuxDesktopEntries(QSettings &)
create a desktop file on a Linux system (or try at least..)
void swap(gpuword **A, gpuword **B)
size_t currentId
reference to current File
QString linuxDesktopFile()
find location of desktpo file
bool setupCurves(bool topo=false)
set up geometric data structures, like triangulations etc.
void startStopApproximateCurve()
starts, or stops the approximation algorithm for curves
void fileOpened(QString file)
raised when a new file is opened. Triggers changes in all parts of the GUI.
InputReader reader
reads files from disk
void startStopOptimiseCurve()
starts, or stops the optimisation algorithm for curves
void restore(QSettings &settings)
read settings from application preferences
void setCurrentAlgorithm(Algorithm alg)
change current algorithm
void showAboutDialog()
opens the "About" dialog
bool separateCurves() const
void installLinuxDesktopIcons(QSettings &)
create a desktop icon on a Linux system (or try at least..)
QString execPath
path to executable file
void attachMenu(QAction *recent)
attach sub-menu
QAction * actionOpenRecent()
global definitions for all algorithms.
Algorithm::ptr newPolyAlgorithm(bool topo)
factory method for creating a new algorithm object. Choose the appropriate implementation based on av...
Status
indicates the current status of the algorithm. Negative values indicate that the algorithm is current...
The single application window.
CurveView * getCurveView()
Ui::MainWindow * ui
widgets (auto-generated by Qt)
ControlPanel * getControlPanel()
std::vector< LineStyle > LineStyleVector
void restoreSettings(QSettings &settings)
load settings from application preferences
void populateScene(const Curve &P, const Curve &Q, frechet::poly::Algorithm::ptr alg)
set up the graphics scene with polygonal curves
double epsMax
maximum value for epsilon
Grid::ptr grid
manages the free-space grid
void cancelJob()
request the job to be cancelled
poly::Algorithm::ptr polyAlgorithm
the algorithm for simple polygons and curves (if available)
void populateScene()
create the grid lines and an array of CellView objects
virtual void restoreSettings(QSettings &settings, QString group)
load settings from application preferences
void createDesktopEntry()
creates an application icon on the users desktop
Algorithm
we have three Fréchet Distance algorithms
Abstract base class for executing the algorithm for simple polygons in a background thread....
compute Fréchet distance between simple polygons
QFileSystemWatcher * fileWatch
void algorithmChanged(int algo)
raised when another algorithm is selected. Triggers changes in all parts of the GUI.
bool showFirstTimeHint()
show a short hint when the application is opened for the very first time
void beginFile(QSettings &settings, size_t id, bool forWrite=false)
begin reading or updating file specific settings
FSPath::ptr fspath
the feasible path (if available)
void editInputFile()
opens the input file in an editor
FileHistory history
Open Recent file history.
void restoreFileSettings(QSettings &settings, size_t histId)
read file specific settings from preferences
void cancelBackgroundJob()
stops long-running algorithm (if necessary)
virtual void saveSettings(QSettings &settings, QString group)
store settings to application preferences
MainWindow * window
the main window
void flipVertical(bool flip)
flip graphics scene vertically
void startKBruteForce()
starts the brute-force k-Frechet algorithm
performs mappings to and from the free-space grid
void saveSettings(QSettings &settings, QString group)
store settings to application preferences
void startStopOptimisePolygon()
starts, or stops the optimisation algorithm for simple polygons
QPolygonF Curve
a polygonal curve in the plane; with double floating point precision. This type is heavily used throu...
void shutDown()
cancel all remaining tasks and shut down the global QThreaPool
void startStopApproximatePolygon()
starts, or stops the approximation algorithm for simple polygons
worker job for executing the decision variant of the algorithm for simple polygons.
static FrechetViewApplication * frechetViewApp
singleton instance
void restoreSettings(QSettings &settings, QString group)
load settings from application preferences
void startJob(WorkerJob *new_job)
start a new job
virtual void restoreSettings(QSettings &settings, QString group)
load settings from application preferences
static void copyContents(QByteArray contents, QString path)
copy data to a file on disk
void clearResults()
reset the k-Frechet panel
void endFile(QSettings &settings)
end updating file specific settings
boost::shared_ptr< Grid > ptr
smart pointer to a Grid object
worker job for executing the optimisation variant, or approximation variant, of the algorithm for sim...
void open(bool firstTime=false)
initialises the GUI
virtual void saveSettings(QSettings &settings, QString group)
store settings to application preferences
void saveFileSettings(QSettings &settings, size_t histId)
save file specific settings to preferences
void init(QString file)
initialise the GUI application and open a file (optional)
void setSeparateCurves(bool separate)
called when the user clicks the "Separate Curves" button
The FreeSpace class models the Free-Space Diagram calculated from two curves.
background worker job for running the k-Frechet brute-force algorithm.
void setShowBounds(bool show)
called when the user clicks the "Show Bounds" button
~FrechetViewApplication()
desctructor; closes all resources and windows
static void copyFile(QString src, QString dest)
copy files on disk
a feasible-path for simple polygons.
void quit()
quit the application, closing all resources and windows
void resetAlgorithms()
stops running algorithm(s)
FreeSpace::ptr freeSpace
the free-space diagram
size_t insert(QString path, QDateTime date=QDateTime::currentDateTime())
insert a new file into the list
DataPath path
pointer to input data within an xml file
FreeSpaceView * getFreeSpaceView()
boost::shared_ptr< kAlgorithm > ptr
smart pointer to an kAlgorithm object
double max_euclidean_distance(const Curve &P, const Curve &Q)
compute the maximum distance between two polygons This value serves as an upper bound for the Frechet...
bool populateBookmarks()
for presentation mode only
void init(QString agroup)
initialize file list and menu
boost::shared_ptr< FreeSpace > ptr
smart pointer to FreeSpace object
void startStopDecidePolygon()
starts, or stops the decision algorithm for simple polygons
void updateResults()
update the k-Frechet panel to show the latest results of the k-Frechet algorithm
void setEpsilonMax(double eps_max)
update the maximum value of epsilon; adjusts the slider control
Calculates a feasible path in the Free-Space given a start point (0,0) and an end point (n-1,...
compute k-Fréchet distance between two curves
Algorithm _currentAlgorithm
selects current Algorithm
void calculateFreeSpace(double epsilon)
update free-space diagram when epsilon changes. If the curve algorithm is selected,...