From c7db1870e709da2a963be08a7f71211fcfc6b357 Mon Sep 17 00:00:00 2001 From: Petros Koutsolampros Date: Wed, 30 Dec 2020 00:30:22 +0200 Subject: [PATCH 1/5] Parallel VGA first commit --- depthmapX/mainwindowmoduleregistry.cpp | 2 + depthmapXcli/modeparserregistry.cpp | 2 + modules/vgaparallel/CMakeLists.txt | 34 ++ .../RegressionTest/regressionconfig.json | 14 + modules/vgaparallel/cli/CMakeLists.txt | 24 ++ modules/vgaparallel/cli/vgaparallelparser.cpp | 138 ++++++++ modules/vgaparallel/cli/vgaparallelparser.h | 51 +++ modules/vgaparallel/cliTest/CMakeLists.txt | 24 ++ .../cliTest/vgaparallelparsertest.cpp | 94 ++++++ modules/vgaparallel/core/CMakeLists.txt | 34 ++ modules/vgaparallel/core/CMakeOpenMP.txt | 62 ++++ modules/vgaparallel/core/vgaangularopenmp.cpp | 187 +++++++++++ modules/vgaparallel/core/vgaangularopenmp.h | 46 +++ modules/vgaparallel/core/vgametricopenmp.cpp | 195 ++++++++++++ modules/vgaparallel/core/vgametricopenmp.h | 47 +++ .../core/vgavisualglobalopenmp.cpp | 259 +++++++++++++++ .../vgaparallel/core/vgavisualglobalopenmp.h | 46 +++ .../core/vgavisuallocaladjmatrix.cpp | 167 ++++++++++ .../core/vgavisuallocaladjmatrix.h | 40 +++ .../vgaparallel/core/vgavisuallocalopenmp.cpp | 159 ++++++++++ .../vgaparallel/core/vgavisuallocalopenmp.h | 39 +++ modules/vgaparallel/coreTest/CMakeLists.txt | 24 ++ .../coreTest/vgaparallelcoretest.cpp | 118 +++++++ modules/vgaparallel/gui/CMakeLists.txt | 50 +++ .../gui/UI/vgaparalleloptionsdlg.ui | 297 ++++++++++++++++++ modules/vgaparallel/gui/uictrigger.cpp | 5 + .../vgaparallel/gui/vgaparallelmainwindow.cpp | 109 +++++++ .../vgaparallel/gui/vgaparallelmainwindow.h | 28 ++ .../vgaparallel/gui/vgaparalleloptionsdlg.cpp | 186 +++++++++++ .../vgaparallel/gui/vgaparalleloptionsdlg.h | 54 ++++ 30 files changed, 2535 insertions(+) create mode 100644 modules/vgaparallel/CMakeLists.txt create mode 100644 modules/vgaparallel/RegressionTest/regressionconfig.json create mode 100644 modules/vgaparallel/cli/CMakeLists.txt create mode 100644 modules/vgaparallel/cli/vgaparallelparser.cpp create mode 100644 modules/vgaparallel/cli/vgaparallelparser.h create mode 100644 modules/vgaparallel/cliTest/CMakeLists.txt create mode 100644 modules/vgaparallel/cliTest/vgaparallelparsertest.cpp create mode 100644 modules/vgaparallel/core/CMakeLists.txt create mode 100644 modules/vgaparallel/core/CMakeOpenMP.txt create mode 100644 modules/vgaparallel/core/vgaangularopenmp.cpp create mode 100644 modules/vgaparallel/core/vgaangularopenmp.h create mode 100644 modules/vgaparallel/core/vgametricopenmp.cpp create mode 100644 modules/vgaparallel/core/vgametricopenmp.h create mode 100644 modules/vgaparallel/core/vgavisualglobalopenmp.cpp create mode 100644 modules/vgaparallel/core/vgavisualglobalopenmp.h create mode 100644 modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp create mode 100644 modules/vgaparallel/core/vgavisuallocaladjmatrix.h create mode 100644 modules/vgaparallel/core/vgavisuallocalopenmp.cpp create mode 100644 modules/vgaparallel/core/vgavisuallocalopenmp.h create mode 100644 modules/vgaparallel/coreTest/CMakeLists.txt create mode 100644 modules/vgaparallel/coreTest/vgaparallelcoretest.cpp create mode 100644 modules/vgaparallel/gui/CMakeLists.txt create mode 100644 modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui create mode 100644 modules/vgaparallel/gui/uictrigger.cpp create mode 100644 modules/vgaparallel/gui/vgaparallelmainwindow.cpp create mode 100644 modules/vgaparallel/gui/vgaparallelmainwindow.h create mode 100644 modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp create mode 100644 modules/vgaparallel/gui/vgaparalleloptionsdlg.h diff --git a/depthmapX/mainwindowmoduleregistry.cpp b/depthmapX/mainwindowmoduleregistry.cpp index 5238510f..4a038551 100644 --- a/depthmapX/mainwindowmoduleregistry.cpp +++ b/depthmapX/mainwindowmoduleregistry.cpp @@ -16,9 +16,11 @@ #include "mainwindowmoduleregistry.hpp" #include "modules/segmentshortestpaths/gui/segmentpathsmainwindow.h" +#include "modules/vgaparallel/gui/vgaparallelmainwindow.h" void MainWindowModuleRegistry::populateModules() { // Register any main window modules here REGISTER_MAIN_WINDOW_MODULE(SegmentPathsMainWindow); + REGISTER_MAIN_WINDOW_MODULE(VGAParallelMainWindow) // ********* } diff --git a/depthmapXcli/modeparserregistry.cpp b/depthmapXcli/modeparserregistry.cpp index e54a3d4f..93623cab 100644 --- a/depthmapXcli/modeparserregistry.cpp +++ b/depthmapXcli/modeparserregistry.cpp @@ -26,6 +26,7 @@ #include "stepdepthparser.h" #include "mapconvertparser.h" #include "modules/segmentshortestpaths/cli/segmentshortestpathparser.h" +#include "modules/vgaparallel/cli/vgaparallelparser.h" void ModeParserRegistry::populateParsers() @@ -43,5 +44,6 @@ void ModeParserRegistry::populateParsers() REGISTER_PARSER(StepDepthParser); REGISTER_PARSER(MapConvertParser); REGISTER_PARSER(SegmentShortestPathParser); + REGISTER_PARSER(VGAParallelParser) // ********* } diff --git a/modules/vgaparallel/CMakeLists.txt b/modules/vgaparallel/CMakeLists.txt new file mode 100644 index 00000000..70b4dd7b --- /dev/null +++ b/modules/vgaparallel/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +if(MODULES_CORE) +add_subdirectory(core) +endif() + +if(MODULES_GUI) + add_subdirectory(gui) +endif() + +if(MODULES_CLI) + add_subdirectory(cli) +endif() + +if(MODULES_CORE_TEST) + add_subdirectory(coreTest) +endif() + +if(MODULES_CLI_TEST) + add_subdirectory(cliTest) +endif() diff --git a/modules/vgaparallel/RegressionTest/regressionconfig.json b/modules/vgaparallel/RegressionTest/regressionconfig.json new file mode 100644 index 00000000..582fd805 --- /dev/null +++ b/modules/vgaparallel/RegressionTest/regressionconfig.json @@ -0,0 +1,14 @@ +{ + "rundir": "rundir", + "basebinlocation": "../../BaselineBinaries", + "testbinlocation": "../../../build", + "testcases": { + "shortest_segment_metric_path": [{ + "infile": "../../../testdata/barnsbury_extended1_segment.graph", + "outfile": "out.graph", + "mode": "VGAPARALLEL", + "extraArgs": { + } + }] + } +} diff --git a/modules/vgaparallel/cli/CMakeLists.txt b/modules/vgaparallel/cli/CMakeLists.txt new file mode 100644 index 00000000..578bec46 --- /dev/null +++ b/modules/vgaparallel/cli/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +set(vgaparallelcli vgaparallelcli) +set(vgaparallelcli_SRCS + vgaparallelparser.cpp) + +set(modules_cli "${modules_cli}" "vgaparallelcli" CACHE INTERNAL "modules_cli" FORCE) + +add_compile_definitions(VGAPARALLEL_CLI_LIBRARY) + +add_library(${vgaparallelcli} OBJECT ${vgaparallelcli_SRCS}) diff --git a/modules/vgaparallel/cli/vgaparallelparser.cpp b/modules/vgaparallel/cli/vgaparallelparser.cpp new file mode 100644 index 00000000..631d6862 --- /dev/null +++ b/modules/vgaparallel/cli/vgaparallelparser.cpp @@ -0,0 +1,138 @@ +// Copyright (C) 2020 Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgaparallelparser.h" +#include "depthmapXcli/exceptions.h" +#include "depthmapXcli/parsingutils.h" +#include "depthmapXcli/runmethods.h" +#include "depthmapXcli/simpletimer.h" +#include "modules/segmentshortestpaths/core/segmmetricshortestpath.h" +#include "modules/segmentshortestpaths/core/segmtopologicalshortestpath.h" +#include "modules/segmentshortestpaths/core/segmtulipshortestpath.h" +#include "salalib/entityparsing.h" +#include +#include + +using namespace depthmapX; + +void VGAParallelParser::parse(int argc, char **argv) { + + std::string originPoint; + std::string destinationPoint; + for (int i = 1; i < argc; ++i) { + if (std::strcmp("-sspo", argv[i]) == 0) { + if (!originPoint.empty()) { + throw CommandLineException("-sspo can only be provided once"); + } + ENFORCE_ARGUMENT("-sspo", i) + if (!has_only_digits_dots_commas(argv[i])) { + std::stringstream message; + message << "Invalid origin point provided (" << argv[i] + << "). Should only contain digits dots and commas" << std::flush; + throw CommandLineException(message.str().c_str()); + } + originPoint = argv[i]; + } + if (std::strcmp("-sspd", argv[i]) == 0) { + if (!destinationPoint.empty()) { + throw CommandLineException("-sspd can only be provided once"); + } + ENFORCE_ARGUMENT("-sspd", i) + if (!has_only_digits_dots_commas(argv[i])) { + std::stringstream message; + message << "Invalid destination point provided (" << argv[i] + << "). Should only contain digits dots and commas" << std::flush; + throw CommandLineException(message.str().c_str()); + } + destinationPoint = argv[i]; + } else if (std::strcmp("-sspt", argv[i]) == 0) { + ENFORCE_ARGUMENT("-sspt", i) + if (std::strcmp(argv[i], "tulip") == 0) { + m_stepType = StepType::TULIP; + } else if (std::strcmp(argv[i], "metric") == 0) { + m_stepType = StepType::METRIC; + } else if (std::strcmp(argv[i], "topological") == 0) { + m_stepType = StepType::TOPOLOGICAL; + } else { + throw CommandLineException(std::string("Invalid step type: ") + argv[i]); + } + } + } + + if (originPoint.empty() || destinationPoint.empty()) { + throw CommandLineException("Both -sspo and -sspd must be provided"); + } + + std::stringstream pointsStream; + pointsStream << "x,y"; + pointsStream << "\n" << originPoint; + pointsStream << "\n" << destinationPoint; + std::vector parsed = EntityParsing::parsePoints(pointsStream, ','); + m_originPoint = parsed[0]; + m_destinationPoint = parsed[1]; + + if (m_stepType == StepType::NONE) { + throw CommandLineException("Step depth type (-sspt) must be provided"); + } +} + +void VGAParallelParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const { + auto mGraph = dm_runmethods::loadGraph(clp.getFileName().c_str(), perfWriter); + + std::cout << "ok\nSelecting cells... " << std::flush; + + auto graphRegion = mGraph->getRegion(); + + if (!graphRegion.contains(m_originPoint)) { + throw depthmapX::RuntimeException("Origin point outside of target region"); + } + if (!graphRegion.contains(m_destinationPoint)) { + throw depthmapX::RuntimeException("Destination point outside of target region"); + } + QtRegion r(m_originPoint, m_originPoint); + mGraph->setCurSel(r, false); + + r = QtRegion(m_destinationPoint, m_destinationPoint); + mGraph->setCurSel(r, true); + + std::cout << "ok\nCalculating shortest path... " << std::flush; + + std::unique_ptr comm(new ICommunicator()); + + switch (m_stepType) { + case VGAParallelParser::StepType::TULIP: { + DO_TIMED("Calculating tulip shortest path", + SegmentTulipShortestPath(mGraph->getDisplayedShapeGraph()).run(comm.get())) + break; + } + case VGAParallelParser::StepType::METRIC: { + DO_TIMED("Calculating metric shortest path", + SegmentMetricShortestPath(mGraph->getDisplayedShapeGraph()).run(comm.get())) + break; + } + case VGAParallelParser::StepType::TOPOLOGICAL: { + DO_TIMED("Calculating topological shortest path", + SegmentTopologicalShortestPath(mGraph->getDisplayedShapeGraph()).run(comm.get())) + break; + } + default: { + throw depthmapX::SetupCheckException("Error, unsupported step type"); + } + } + + std::cout << " ok\nWriting out result..." << std::flush; + DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(), METAGRAPH_VERSION, false)) + std::cout << " ok" << std::endl; +} diff --git a/modules/vgaparallel/cli/vgaparallelparser.h b/modules/vgaparallel/cli/vgaparallelparser.h new file mode 100644 index 00000000..0256a447 --- /dev/null +++ b/modules/vgaparallel/cli/vgaparallelparser.h @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "depthmapXcli/imodeparser.h" +#include "genlib/p2dpoly.h" +#include + +class VGAParallelParser : public IModeParser { + public: + VGAParallelParser() : m_stepType(StepType::NONE) {} + + virtual std::string getModeName() const { return "SEGMENTSHORTESTPATH"; } + + virtual std::string getHelp() const { + return "Mode options for pointmap SEGMENTSHORTESTPATH are:\n" + " -sspo point where to calculate shortest path between.\n" + " -sspd point where to calculate shortest path between.\n" + " -sspt step type. One of metric, tulip or topological.\n"; + } + + enum class StepType { NONE, TULIP, METRIC, TOPOLOGICAL }; + + virtual void parse(int argc, char **argv); + + virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; + + Point2f getShortestPathOrigin() const { return m_originPoint; } + Point2f getShortestPathDestination() const { return m_destinationPoint; } + + StepType getStepType() const { return m_stepType; } + + private: + Point2f m_originPoint; + Point2f m_destinationPoint; + + StepType m_stepType; +}; diff --git a/modules/vgaparallel/cliTest/CMakeLists.txt b/modules/vgaparallel/cliTest/CMakeLists.txt new file mode 100644 index 00000000..18d5ebc6 --- /dev/null +++ b/modules/vgaparallel/cliTest/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +set(vgaparallelclitest vgaparallelclitest) +set(vgaparallelclitest_SRCS + vgaparallelparsertest.cpp) + +set(modules_cliTest "${modules_cliTest}" "vgaparallelclitest" CACHE INTERNAL "modules_cliTest" FORCE) + +add_compile_definitions(VGAPARALLEL_CLI_TEST_LIBRARY) + +add_library(${vgaparallelclitest} OBJECT ${vgaparallelclitest_SRCS}) diff --git a/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp b/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp new file mode 100644 index 00000000..a6039329 --- /dev/null +++ b/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2020 Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "cliTest/argumentholder.h" +#include "cliTest/selfcleaningfile.h" +#include "modules/segmentshortestpaths/cli/segmentshortestpathparser.h" +#include + +TEST_CASE("SegmentShortestPathParser", "Error cases") { + SECTION("Missing argument to -sspo") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog", "-sspd", "0,0", "-sspo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sspo requires an argument")); + } + + SECTION("Missing argument to -sspd") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sspd requires an argument")); + } + + SECTION("Missing argument to -sspt") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd", "0,0", "-sspt"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sspt requires an argument")); + } + + SECTION("rubbish input to -sspo") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog", "-sspd", "0,0", "-sspo", "foo"}; + REQUIRE_THROWS_WITH( + parser.parse(ah.argc(), ah.argv()), + Catch::Contains("Invalid origin point provided (foo). Should only contain digits dots and commas")); + } + + SECTION("rubbish input to -sspd") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd", "foo"}; + REQUIRE_THROWS_WITH( + parser.parse(ah.argc(), ah.argv()), + Catch::Contains("Invalid destination point provided (foo). Should only contain digits dots and commas")); + } + + SECTION("rubbish input to -sspt") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd", "0,0", "-sspt", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid step type: foo")); + } + + SECTION("Neiter points nor point file provided") { + SegmentShortestPathParser parser; + ArgumentHolder ah{"prog"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), + Catch::Contains("Both -sspo and -sspd must be provided")); + } +} + +TEST_CASE("Successful SegmentShortestPathParser", "Read successfully") { + SegmentShortestPathParser parser; + double originX = 1.0; + double originY = 2.0; + double destinationX = 1.1; + double destinationY = 1.2; + + SECTION("Read from commandline") { + std::stringstream originStream; + originStream << originX << "," << originY << std::flush; + std::stringstream destinationStream; + destinationStream << destinationX << "," << destinationY << std::flush; + + ArgumentHolder ah{"prog", "-sspo", originStream.str(), "-sspd", destinationStream.str(), + "-sspt", "topological"}; + parser.parse(ah.argc(), ah.argv()); + } + + auto originPoint = parser.getShortestPathOrigin(); + auto destinationPoint = parser.getShortestPathDestination(); + REQUIRE(originPoint.x == Approx(originX)); + REQUIRE(originPoint.y == Approx(originY)); + REQUIRE(destinationPoint.x == Approx(destinationX)); + REQUIRE(destinationPoint.y == Approx(destinationY)); +} diff --git a/modules/vgaparallel/core/CMakeLists.txt b/modules/vgaparallel/core/CMakeLists.txt new file mode 100644 index 00000000..6e370c6c --- /dev/null +++ b/modules/vgaparallel/core/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +set(vgaparallelcore vgaparallelcore) +set(vgaparallelcore_SRCS + vgavisuallocalopenmp.cpp + vgavisuallocaladjmatrix.cpp + vgavisualglobalopenmp.cpp + vgametricopenmp.cpp + vgaangularopenmp.cpp) + +include(CMakeOpenMP.txt) + +set(modules_core "${modules_core}" "vgaparallelcore" CACHE INTERNAL "modules_core" FORCE) + +add_compile_definitions(VGAPARALLEL_CORE_LIBRARY) + +add_library(${vgaparallelcore} OBJECT ${vgaparallelcore_SRCS}) + +find_package(OpenMP REQUIRED) + +target_link_libraries(${vgaparallelcore} OpenMP::OpenMP_CXX) diff --git a/modules/vgaparallel/core/CMakeOpenMP.txt b/modules/vgaparallel/core/CMakeOpenMP.txt new file mode 100644 index 00000000..3be307a5 --- /dev/null +++ b/modules/vgaparallel/core/CMakeOpenMP.txt @@ -0,0 +1,62 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +option(USE_OPENMP "Enable OpenMP" ON) + +if(USE_OPENMP) + find_package(OpenMP) + + # If OpenMP wasn't found, try if we can find it in the default Macports location + if((NOT OPENMP_FOUND) AND (NOT OPENMP_CXX_FOUND) AND EXISTS "/opt/local/lib/libomp/libomp.dylib") + set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I/opt/local/include/libomp/") + set(OpenMP_C_LIB_NAMES omp) + set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I/opt/local/include/libomp/") + set(OpenMP_CXX_LIB_NAMES omp) + set(OpenMP_omp_LIBRARY "/opt/local/lib/libomp/libomp.dylib") + + find_package(OpenMP) + if (OPENMP_FOUND OR OPENMP_CXX_FOUND) + message(STATUS "Found libomp in macports default location.") + else() + message(FATAL_ERROR "Didn't find libomp. Tried macports default location but also didn't find it.") + endif() + endif() + + # If OpenMP wasn't found, try if we can find it in the default Homebrew location + if((NOT OPENMP_FOUND) AND (NOT OPENMP_CXX_FOUND) AND EXISTS "/usr/local/opt/libomp/lib/libomp.dylib") + set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I/usr/local/opt/libomp/include") + set(OpenMP_C_LIB_NAMES omp) + set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I/usr/local/opt/libomp/include") + set(OpenMP_CXX_LIB_NAMES omp) + set(OpenMP_omp_LIBRARY "/usr/local/opt/libomp/lib/libomp.dylib") + + find_package(OpenMP) + if (OPENMP_FOUND OR OPENMP_CXX_FOUND) + message(STATUS "Found libomp in homebrew default location.") + else() + message(FATAL_ERROR "Didn't find libomp. Tried homebrew default location but also didn't find it.") + endif() + endif() + + if((NOT OPENMP_FOUND) AND (NOT OPENMP_CXX_FOUND)) + message(FATAL_ERROR "Did not find OpenMP.") + endif() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +else() + if( (CMAKE_CXX_COMPILER_ID MATCHES "[cC][lL][aA][nN][gG]") + OR (CMAKE_CXX_COMPILER_ID MATCHES "[gG][nN][uU]")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") + endif() +endif(USE_OPENMP) \ No newline at end of file diff --git a/modules/vgaparallel/core/vgaangularopenmp.cpp b/modules/vgaparallel/core/vgaangularopenmp.cpp new file mode 100644 index 00000000..ac9d6ba3 --- /dev/null +++ b/modules/vgaparallel/core/vgaangularopenmp.cpp @@ -0,0 +1,187 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgaangularopenmp.h" + +#include "genlib/stringutils.h" + +#include + +bool VGAAngularOpenMP::run(Communicator *comm) { + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, m_map.getFilledPointCount()); + } + + AttributeTable &attributes = m_map.getAttributeTable(); + + std::vector filled; + std::vector rows; + + for (int i = 0; i < m_map.getCols(); i++) { + for (int j = 0; j < m_map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + if (m_map.getPoint(curs).filled()) { + filled.push_back(curs); + rows.push_back(attributes.getRowPtr(AttributeKey(curs))); + } + } + } + + int count = 0; + + std::vector col_data(filled.size()); + + int i, N = int(filled.size()); +#pragma omp parallel for default(shared) private(i) schedule(dynamic) + for (i = 0; i < N; i++) { + if (m_gates_only) { + count++; + continue; + } + + DataPoint &dp = col_data[i]; + + depthmapX::RowMatrix miscs(m_map.getRows(), m_map.getCols()); + depthmapX::RowMatrix cumangles(m_map.getRows(), m_map.getCols()); + + miscs.initialiseValues(0); + cumangles.initialiseValues(-1.0f); + + float total_angle = 0.0f; + int total_nodes = 0; + + // note that m_misc is used in a different manner to analyseGraph / PointDepth + // here it marks the node as used in calculation only + + std::set search_list; + search_list.insert(AngularTriple(0.0f, filled[size_t(i)], NoPixel)); + cumangles(filled[size_t(i)].y, filled[size_t(i)].x) = 0.0f; + + while (search_list.size()) { + std::set::iterator it = search_list.begin(); + AngularTriple here = *it; + search_list.erase(it); + if (int(m_radius) != -1 && double(here.angle) > m_radius) { + break; + } + Point &p = m_map.getPoint(here.pixel); + int &p1misc = miscs(here.pixel.y, here.pixel.x); + float &p1cumangle = cumangles(here.pixel.y, here.pixel.x); + // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in + if (p.filled() && p1misc != ~0) { + extractAngular(p.getNode(), search_list, &m_map, here, miscs, cumangles); + p1misc = ~0; + if (!p.getMergePixel().empty()) { + Point &p2 = m_map.getPoint(p.getMergePixel()); + int &p2misc = miscs(p.getMergePixel().y, p.getMergePixel().x); + float &p2cumangle = cumangles(p.getMergePixel().y, p.getMergePixel().x); + if (p2misc != ~0) { + p2cumangle = p1cumangle; + extractAngular(p2.getNode(), search_list, &m_map, + AngularTriple(here.angle, p.getMergePixel(), NoPixel), miscs, cumangles); + p2misc = ~0; + } + } + total_angle += p1cumangle; + total_nodes += 1; + } + } + + if (total_nodes > 0) { + dp.mean_depth = float(double(total_angle) / double(total_nodes)); + } + dp.total_depth = total_angle; + dp.count = float(total_nodes); + + count++; // <- increment count + + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + + // kept to achieve parity in binary comparison with old versions + // TODO: Remove at next version of .graph file + m_map.getPoint(filled[size_t(i)]).m_misc = miscs(filled[size_t(i)].y, filled[size_t(i)].x); + m_map.getPoint(filled[size_t(i)]).m_cumangle = cumangles(filled[size_t(i)].y, filled[size_t(i)].x); + } + + std::string radius_text; + if (int(m_radius) != -1) { + if (m_map.getRegion().width() > 100.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.f"); + } else if (m_map.getRegion().width() < 1.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.4f"); + } else { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.2f"); + } + } + // n.b. these must be entered in alphabetical order to preserve col indexing: + std::string mean_depth_col_text = std::string("Angular Mean Depth") + radius_text; + int mean_depth_col = attributes.getOrInsertColumn(mean_depth_col_text.c_str()); + std::string total_detph_col_text = std::string("Angular Total Depth") + radius_text; + int total_depth_col = attributes.getOrInsertColumn(total_detph_col_text.c_str()); + std::string count_col_text = std::string("Angular Node Count") + radius_text; + int count_col = attributes.getOrInsertColumn(count_col_text.c_str()); + + auto dataIter = col_data.begin(); + for (auto row : rows) { + row->setValue(total_depth_col, dataIter->mean_depth); + row->setValue(total_depth_col, dataIter->total_depth); + row->setValue(count_col, dataIter->count); + dataIter++; + } + + m_map.overrideDisplayedAttribute(-2); + m_map.setDisplayedAttribute(mean_depth_col); + + return true; +} + +void VGAAngularOpenMP::extractAngular(Node &node, std::set &pixels, PointMap *pointdata, + const AngularTriple &curs, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &cumangles) { + if (curs.angle == 0.0f || pointdata->getPoint(curs.pixel).blocked() || pointdata->blockedAdjacent(curs.pixel)) { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + if (miscs(pix.y, pix.x) == 0) { + // n.b. dmap v4.06r now sets angle in range 0 to 4 (1 = 90 degrees) + float ang = (curs.lastpixel == NoPixel) + ? 0.0f + : (float)(angle(pix, curs.pixel, curs.lastpixel) / (M_PI * 0.5)); + float &cumangle = cumangles(pix.y, pix.x); + if (cumangle == -1.0 || curs.angle + ang < cumangle) { + cumangle = cumangles(curs.pixel.y, curs.pixel.x) + ang; + pixels.insert(AngularTriple(cumangle, pix, curs.pixel)); + } + } + pix.move(bin.m_dir); + } + } + } + } +} diff --git a/modules/vgaparallel/core/vgaangularopenmp.h b/modules/vgaparallel/core/vgaangularopenmp.h new file mode 100644 index 00000000..1ad3cf9d --- /dev/null +++ b/modules/vgaparallel/core/vgaangularopenmp.h @@ -0,0 +1,46 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "salalib/ianalysis.h" +#include "salalib/options.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +#include "genlib/simplematrix.h" + +class VGAAngularOpenMP : public IAnalysis { + private: + PointMap &m_map; + double m_radius; + bool m_gates_only; + + struct DataPoint { + float total_depth, mean_depth, count; + }; + + void extractAngular(Node &node, std::set &pixels, PointMap *pointdata, const AngularTriple &curs, + depthmapX::RowMatrix &miscs, depthmapX::RowMatrix &cumangles); + + public: + VGAAngularOpenMP(PointMap &map, double radius, bool gates_only) + : m_map(map), m_radius(radius), m_gates_only(gates_only) {} + std::string getAnalysisName() const override { return "Angular Analysis (OpenMP)"; } + bool run(Communicator *comm) override; +}; diff --git a/modules/vgaparallel/core/vgametricopenmp.cpp b/modules/vgaparallel/core/vgametricopenmp.cpp new file mode 100644 index 00000000..db9df19d --- /dev/null +++ b/modules/vgaparallel/core/vgametricopenmp.cpp @@ -0,0 +1,195 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgametricopenmp.h" + +#include "genlib/stringutils.h" + +#include + +bool VGAMetricOpenMP::run(Communicator *comm) { + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, m_map.getFilledPointCount()); + } + + AttributeTable &attributes = m_map.getAttributeTable(); + + std::vector filled; + std::vector rows; + + for (int i = 0; i < m_map.getCols(); i++) { + for (int j = 0; j < m_map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + if (m_map.getPoint(curs).filled()) { + filled.push_back(curs); + rows.push_back(attributes.getRowPtr(AttributeKey(curs))); + } + } + } + + int count = 0; + + std::vector col_data(filled.size()); + + int i, N = int(filled.size()); +#pragma omp parallel for default(shared) private(i) schedule(dynamic) + for (i = 0; i < N; i++) { + if (m_gates_only) { + count++; + continue; + } + + DataPoint &dp = col_data[i]; + + depthmapX::RowMatrix miscs(m_map.getRows(), m_map.getCols()); + depthmapX::RowMatrix dists(m_map.getRows(), m_map.getCols()); + depthmapX::RowMatrix cumangles(m_map.getRows(), m_map.getCols()); + + miscs.initialiseValues(0); + dists.initialiseValues(-1.0f); + cumangles.initialiseValues(0.0f); + + float euclid_depth = 0.0f; + float total_depth = 0.0f; + float total_angle = 0.0f; + int total_nodes = 0; + + // note that m_misc is used in a different manner to analyseGraph / PointDepth + // here it marks the node as used in calculation only + + std::set search_list; + search_list.insert(MetricTriple(0.0f, filled[size_t(i)], NoPixel)); + while (search_list.size()) { + std::set::iterator it = search_list.begin(); + MetricTriple here = *it; + search_list.erase(it); + if (int(m_radius) != -1 && double(here.dist) * m_map.getSpacing() > m_radius) { + break; + } + Point &p = m_map.getPoint(here.pixel); + int &p1misc = miscs(here.pixel.y, here.pixel.x); + float &p1cumangle = cumangles(here.pixel.y, here.pixel.x); + // nb, the filled check is necessary as diagonals seem to be stored with 'gaps' left in + if (p.filled() && p1misc != ~0) { + extractMetric(p.getNode(), search_list, &m_map, here, miscs, dists, cumangles); + p1misc = ~0; + if (!p.getMergePixel().empty()) { + Point &p2 = m_map.getPoint(p.getMergePixel()); + int &p2misc = miscs(p.getMergePixel().y, p.getMergePixel().x); + float &p2cumangle = cumangles(p.getMergePixel().y, p.getMergePixel().x); + if (p2misc != ~0) { + p2cumangle = p1cumangle; + extractMetric(p2.getNode(), search_list, &m_map, + MetricTriple(here.dist, p.getMergePixel(), NoPixel), miscs, dists, cumangles); + p2misc = ~0; + } + } + total_depth += here.dist * float(m_map.getSpacing()); + total_angle += p1cumangle; + euclid_depth += float(m_map.getSpacing() * dist(here.pixel, filled[size_t(i)])); + total_nodes += 1; + } + } + + // kept to achieve parity in binary comparison with old versions + // TODO: Remove at next version of .graph file + m_map.getPoint(filled[size_t(i)]).m_misc = miscs(filled[size_t(i)].y, filled[size_t(i)].x); + m_map.getPoint(filled[size_t(i)]).m_dist = dists(filled[size_t(i)].y, filled[size_t(i)].x); + m_map.getPoint(filled[size_t(i)]).m_cumangle = cumangles(filled[size_t(i)].y, filled[size_t(i)].x); + + dp.mspa = float(double(total_angle) / double(total_nodes)); + dp.mspl = float(double(total_depth) / double(total_nodes)); + dp.dist = float(double(euclid_depth) / double(total_nodes)); + dp.count = float(total_nodes); + + count++; // <- increment count + + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + + std::string radius_text; + if (int(m_radius) != -1) { + if (m_radius > 100.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.f"); + } else if (m_map.getRegion().width() < 1.0) { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.4f"); + } else { + radius_text = std::string(" R") + dXstring::formatString(m_radius, "%.2f"); + } + } + // n.b. these must be entered in alphabetical order to preserve col indexing: + std::string mspa_col_text = std::string("Metric Mean Shortest-Path Angle") + radius_text; + int mspa_col = attributes.insertOrResetColumn(mspa_col_text.c_str()); + std::string mspl_col_text = std::string("Metric Mean Shortest-Path Distance") + radius_text; + int mspl_col = attributes.insertOrResetColumn(mspl_col_text.c_str()); + std::string dist_col_text = std::string("Metric Mean Straight-Line Distance") + radius_text; + int dist_col = attributes.insertOrResetColumn(dist_col_text.c_str()); + std::string count_col_text = std::string("Metric Node Count") + radius_text; + int count_col = attributes.insertOrResetColumn(count_col_text.c_str()); + + auto dataIter = col_data.begin(); + for (auto row : rows) { + row->setValue(mspa_col, dataIter->mspa); + row->setValue(mspl_col, dataIter->mspl); + row->setValue(dist_col, dataIter->dist); + row->setValue(count_col, dataIter->count); + dataIter++; + } + + m_map.overrideDisplayedAttribute(-2); + m_map.setDisplayedAttribute(mspl_col); + + return true; +} + +void VGAMetricOpenMP::extractMetric(Node &node, std::set &pixels, PointMap *pointdata, + const MetricTriple &curs, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &dists, depthmapX::RowMatrix &cumangles) { + if (curs.dist == 0.0f || pointdata->getPoint(curs.pixel).blocked() || pointdata->blockedAdjacent(curs.pixel)) { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + float &pixdist = dists(pix.y, pix.x); + if (miscs(pix.y, pix.x) == 0 && + (pixdist == -1.0 || (curs.dist + dist(pix, curs.pixel) < pixdist))) { + pixdist = curs.dist + (float)dist(pix, curs.pixel); + // n.b. dmap v4.06r now sets angle in range 0 to 4 (1 = 90 degrees) + cumangles(pix.y, pix.x) = + cumangles(curs.pixel.y, curs.pixel.x) + + (curs.lastpixel == NoPixel + ? 0.0f + : (float)(angle(pix, curs.pixel, curs.lastpixel) / (M_PI * 0.5))); + pixels.insert(MetricTriple(pixdist, pix, curs.pixel)); + } + pix.move(bin.m_dir); + } + } + } + } +} diff --git a/modules/vgaparallel/core/vgametricopenmp.h b/modules/vgaparallel/core/vgametricopenmp.h new file mode 100644 index 00000000..11a8b786 --- /dev/null +++ b/modules/vgaparallel/core/vgametricopenmp.h @@ -0,0 +1,47 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "salalib/ianalysis.h" +#include "salalib/options.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +#include "genlib/simplematrix.h" + +class VGAMetricOpenMP : public IAnalysis { + private: + PointMap &m_map; + double m_radius; + bool m_gates_only; + + struct DataPoint { + float mspa, mspl, dist, count; + }; + + void extractMetric(Node &node, std::set &pixels, PointMap *pointdata, const MetricTriple &curs, + depthmapX::RowMatrix &miscs, depthmapX::RowMatrix &dists, + depthmapX::RowMatrix &cumangles); + + public: + VGAMetricOpenMP(PointMap &map, double radius, bool gates_only) + : m_map(map), m_radius(radius), m_gates_only(gates_only) {} + std::string getAnalysisName() const override { return "Metric Analysis (OpenMP)"; } + bool run(Communicator *comm) override; +}; diff --git a/modules/vgaparallel/core/vgavisualglobalopenmp.cpp b/modules/vgaparallel/core/vgavisualglobalopenmp.cpp new file mode 100644 index 00000000..fa0b4675 --- /dev/null +++ b/modules/vgaparallel/core/vgavisualglobalopenmp.cpp @@ -0,0 +1,259 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgavisualglobalopenmp.h" + +#include "genlib/stringutils.h" + +#include + +bool VGAVisualGlobalOpenMP::run(Communicator *comm) { + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, m_map.getFilledPointCount()); + } + + AttributeTable &attributes = m_map.getAttributeTable(); + + std::vector filled; + std::vector rows; + + for (int i = 0; i < m_map.getCols(); i++) { + for (int j = 0; j < m_map.getRows(); j++) { + PixelRef curs = PixelRef(i, j); + if (m_map.getPoint(curs).filled()) { + filled.push_back(curs); + rows.push_back(attributes.getRowPtr(AttributeKey(curs))); + } + } + } + + int count = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_STEPS, 1); + comm->CommPostMessage(Communicator::CURRENT_STEP, 1); + comm->CommPostMessage(Communicator::NUM_RECORDS, filled.size()); + } + std::vector col_data(filled.size()); + +#pragma omp parallel for + for (int i = 0; i < filled.size(); i++) { + + if ((m_map.getPoint(filled[i]).contextfilled() && !filled[i].iseven()) || (m_gatesOnly)) { + count++; + continue; + } + DataPoint &dp = col_data[i]; + + depthmapX::RowMatrix miscs(m_map.getRows(), m_map.getCols()); + depthmapX::RowMatrix extents(m_map.getRows(), m_map.getCols()); + + for (int ii = 0; ii < m_map.getCols(); ii++) { + for (int jj = 0; jj < m_map.getRows(); jj++) { + miscs(jj, ii) = 0; + extents(jj, ii) = PixelRef(ii, jj); + } + } + + int total_depth = 0; + int total_nodes = 0; + + std::vector distribution; + std::vector search_tree; + search_tree.push_back(PixelRefVector()); + search_tree.back().push_back(filled[i]); + + int level = 0; + while (search_tree[level].size()) { + search_tree.push_back(PixelRefVector()); + distribution.push_back(0); + for (size_t n = search_tree[level].size() - 1; n != -1; n--) { + PixelRef curr = search_tree[level][n]; + Point &p = m_map.getPoint(curr); + int &p1misc = miscs(curr.y, curr.x); + if (p.filled() && p1misc != ~0) { + total_depth += level; + total_nodes += 1; + distribution.back() += 1; + if ((int)m_radius == -1 || + (level < (int)m_radius && (!p.contextfilled() || search_tree[level][n].iseven()))) { + extractUnseen(p.getNode(), search_tree[level + 1], miscs, extents); + p1misc = ~0; + if (!p.getMergePixel().empty()) { + Point &p2 = m_map.getPoint(p.getMergePixel()); + int &p2misc = miscs(p.getMergePixel().y, p.getMergePixel().x); + if (p2misc != ~0) { + extractUnseen(p2.getNode(), search_tree[level + 1], miscs, extents); + p2misc = ~0; + } + } + } else { + p1misc = ~0; + } + } + search_tree[level].pop_back(); + } + level++; + } + + // only set to single float precision after divide + // note -- total_nodes includes this one -- mean depth as per p.108 Social Logic of Space + + dp.count = float(total_nodes); // note: total nodes includes this one; + + // ERROR !!!!!! + if (total_nodes > 1) { + double mean_depth = double(total_depth) / double(total_nodes - 1); + dp.depth = float(mean_depth); + // total nodes > 2 to avoid divide by 0 (was > 3) + if (total_nodes > 2 && mean_depth > 1.0) { + double ra = 2.0 * (mean_depth - 1.0) / double(total_nodes - 2); + // d-value / p-values from Depthmap 4 manual, note: node_count includes this one + double rra_d = ra / dvalue(total_nodes); + double rra_p = ra / pvalue(total_nodes); + double integ_tk = teklinteg(total_nodes, total_depth); + dp.integ_dv = float(1.0 / rra_d); + dp.integ_pv = float(1.0 / rra_p); + + if (total_depth - total_nodes + 1 > 1) { + dp.integ_tk = float(integ_tk); + } else { + dp.integ_tk = -1.0f; + } + } else { + dp.integ_dv = -1.0f; + dp.integ_pv = -1.0f; + dp.integ_tk = -1.0f; + } + double entropy = 0.0, rel_entropy = 0.0, factorial = 1.0; + // n.b., this distribution contains the root node itself in distribution[0] + // -> chopped from entropy to avoid divide by zero if only one node + for (size_t k = 1; k < distribution.size(); k++) { + if (distribution[k] > 0) { + double prob = double(distribution[k]) / double(total_nodes - 1); + entropy -= prob * log2(prob); + // Formula from Turner 2001, "Depthmap" + factorial *= double(k + 1); + double q = (pow(mean_depth, double(k)) / double(factorial)) * exp(-mean_depth); + rel_entropy += (float)prob * log2(prob / q); + } + } + dp.entropy = float(entropy); + dp.rel_entropy = float(rel_entropy); + } else { + dp.depth = -1.0f; + dp.entropy = -1.0f; + dp.rel_entropy = -1.0f; + } + count++; // <- increment count + + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + + // kept to achieve parity in binary comparison with old versions + // TODO: Remove at next version of .graph file + size_t filledIdx = size_t(filled[i].y * m_map.getCols() + filled[i].x); + m_map.getPoint(filled[i]).m_misc = miscs(filled[i].y, filled[i].x); + m_map.getPoint(filled[i]).m_extent = extents(filled[i].y, filled[i].x); + } + + int entropy_col, rel_entropy_col, integ_dv_col, integ_pv_col, integ_tk_col, depth_col, count_col; + + std::string radius_text; + if (m_radius != -1) { + radius_text = std::string(" R") + dXstring::formatString(int(m_radius), "%d"); + } + + // n.b. these must be entered in alphabetical order to preserve col indexing: + // dX simple version test // TV + std::string entropy_col_text = std::string("Visual Entropy") + radius_text; + std::string integ_dv_col_text = std::string("Visual Integration [HH]") + radius_text; + std::string integ_pv_col_text = std::string("Visual Integration [P-value]") + radius_text; + std::string integ_tk_col_text = std::string("Visual Integration [Tekl]") + radius_text; + std::string depth_col_text = std::string("Visual Mean Depth") + radius_text; + std::string count_col_text = std::string("Visual Node Count") + radius_text; + std::string rel_entropy_col_text = std::string("Visual Relativised Entropy") + radius_text; + + attributes.insertOrResetColumn(integ_dv_col_text.c_str()); + + attributes.insertOrResetColumn(entropy_col_text.c_str()); + attributes.insertOrResetColumn(integ_pv_col_text.c_str()); + attributes.insertOrResetColumn(integ_tk_col_text.c_str()); + attributes.insertOrResetColumn(depth_col_text.c_str()); + attributes.insertOrResetColumn(count_col_text.c_str()); + attributes.insertOrResetColumn(rel_entropy_col_text.c_str()); + + integ_dv_col = attributes.getOrInsertColumn(integ_dv_col_text.c_str()); + + entropy_col = attributes.getOrInsertColumn(entropy_col_text.c_str()); + integ_pv_col = attributes.getOrInsertColumn(integ_pv_col_text.c_str()); + integ_tk_col = attributes.getOrInsertColumn(integ_tk_col_text.c_str()); + depth_col = attributes.getOrInsertColumn(depth_col_text.c_str()); + count_col = attributes.getOrInsertColumn(count_col_text.c_str()); + rel_entropy_col = attributes.getOrInsertColumn(rel_entropy_col_text.c_str()); + + auto dataIter = col_data.begin(); + for (auto row : rows) { + row->setValue(integ_dv_col, dataIter->integ_dv); + row->setValue(integ_pv_col, dataIter->integ_pv); + row->setValue(integ_tk_col, dataIter->integ_tk); + row->setValue(count_col, dataIter->count); + row->setValue(depth_col, dataIter->depth); + row->setValue(entropy_col, dataIter->entropy); + row->setValue(rel_entropy_col, dataIter->rel_entropy); + dataIter++; + } + + m_map.setDisplayedAttribute(integ_dv_col); + + return true; +} + +void VGAVisualGlobalOpenMP::extractUnseen(Node &node, PixelRefVector &pixels, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &extents) { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + int &misc = miscs(pix.y, pix.x); + PixelRef &extent = extents(pix.y, pix.x); + if (misc == 0) { + pixels.push_back(pix); + misc |= (1 << i); + } + // 10.2.02 revised --- diagonal was breaking this as it was extent in diagonal or horizontal + if (!(bin.m_dir & PixelRef::DIAGONAL)) { + if (extent.col(bin.m_dir) >= pixVec.end().col(bin.m_dir)) + break; + extent.col(bin.m_dir) = pixVec.end().col(bin.m_dir); + } + pix.move(bin.m_dir); + } + } + } +} diff --git a/modules/vgaparallel/core/vgavisualglobalopenmp.h b/modules/vgaparallel/core/vgavisualglobalopenmp.h new file mode 100644 index 00000000..2a584dd2 --- /dev/null +++ b/modules/vgaparallel/core/vgavisualglobalopenmp.h @@ -0,0 +1,46 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "salalib/ianalysis.h" +#include "salalib/options.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +#include "genlib/simplematrix.h" + +class VGAVisualGlobalOpenMP : public IAnalysis { + private: + PointMap &m_map; + double m_radius; + bool m_gatesOnly; + + struct DataPoint { + float count, depth, integ_dv, integ_pv; + float integ_tk, entropy, rel_entropy; + }; + void extractUnseen(Node &node, PixelRefVector &pixels, depthmapX::RowMatrix &miscs, + depthmapX::RowMatrix &extents); + + public: + VGAVisualGlobalOpenMP(PointMap &map, double radius, bool gatesOnly) + : m_map(map), m_radius(radius), m_gatesOnly(gatesOnly) {} + std::string getAnalysisName() const override { return "Global Visibility Analysis (OpenMP)"; } + bool run(Communicator *) override; +}; diff --git a/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp b/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp new file mode 100644 index 00000000..79003ed3 --- /dev/null +++ b/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp @@ -0,0 +1,167 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgavisuallocaladjmatrix.h" + +#include "genlib/stringutils.h" + +#include + +bool VGAVisualLocalAdjMatrix::run(Communicator *comm) { + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, m_map.getFilledPointCount()); + } + + AttributeTable &attributes = m_map.getAttributeTable(); + + std::vector filled; + std::vector rows; + + for (int i = 0; i < m_map.getCols(); i++) { + for (int j = 0; j < m_map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + if (m_map.getPoint(curs).filled()) { + filled.push_back(curs); + rows.push_back(attributes.getRowPtr(AttributeKey(curs))); + } + } + } + + int count = 0; + + count = 0; + + std::vector col_data(filled.size()); + + int i; + const long N = long(filled.size()); + + std::map refToFilled; + for (i = 0; i < N; ++i) { + refToFilled.insert(std::make_pair(filled[size_t(i)], i)); + } + + std::vector hoods(N * N); + +#pragma omp parallel for default(shared) private(i) schedule(dynamic) + for (i = 0; i < N; ++i) { + Point &p = m_map.getPoint(filled[size_t(i)]); + std::set neighbourhood; +#pragma omp critical(dumpNeighbourhood) + { dumpNeighbourhood(p.getNode(), neighbourhood); } + for (auto &neighbour : neighbourhood) { + if (m_map.getPoint(neighbour).hasNode()) { + hoods[long(i * N + refToFilled[neighbour])] = true; + } + } + } + +#pragma omp parallel for default(shared) private(i) schedule(dynamic) + for (i = 0; i < N; ++i) { + + DataPoint &dp = col_data[i]; + + Point &p = m_map.getPoint(filled[size_t(i)]); + if ((p.contextfilled() && !filled[size_t(i)].iseven()) || (m_gates_only)) { + count++; + continue; + } + + std::vector totalHood(N); + + int cluster = 0; + float control = 0.0f; + + int hoodSize = 0; + for (int j = 0; j < N; j++) { + if (hoods[i * N + j]) { + hoodSize++; + int retHood = 0; + for (int k = 0; k < N; k++) { + if (hoods[j * N + k]) { + totalHood[k] = true; + retHood++; + if (hoods[i * N + k]) + cluster++; + } + } + control += 1.0f / float(retHood); + } + } + int totalReach = 0; + for (int j = 0; j < N; j++) { + if (totalHood[j]) + totalReach++; + } +#pragma omp critical(add_to_col) + { + if (hoodSize > 1) { + dp.cluster = float(cluster / double(hoodSize * (hoodSize - 1.0))); + dp.control = float(control); + dp.controllability = float(double(hoodSize) / double(totalReach)); + } else { + dp.cluster = -1.0f; + dp.control = -1.0f; + dp.controllability = -1; + } + } + +#pragma omp critical(count) + { + count++; // <- increment count + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + + int cluster_col = attributes.insertOrResetColumn("Visual Clustering Coefficient"); + int control_col = attributes.insertOrResetColumn("Visual Control"); + int controllability_col = attributes.insertOrResetColumn("Visual Controllability"); + + auto dataIter = col_data.begin(); + for (auto row : rows) { + row->setValue(cluster_col, dataIter->cluster); + row->setValue(control_col, dataIter->control); + row->setValue(controllability_col, dataIter->controllability); + dataIter++; + } + m_map.setDisplayedAttribute(cluster_col); + + return true; +} + +void VGAVisualLocalAdjMatrix::dumpNeighbourhood(Node &node, std::set &hood) const { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + hood.insert(pix); + pix.move(bin.m_dir); + } + } + } +} diff --git a/modules/vgaparallel/core/vgavisuallocaladjmatrix.h b/modules/vgaparallel/core/vgavisuallocaladjmatrix.h new file mode 100644 index 00000000..9fad889f --- /dev/null +++ b/modules/vgaparallel/core/vgavisuallocaladjmatrix.h @@ -0,0 +1,40 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "salalib/ianalysis.h" +#include "salalib/options.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAVisualLocalAdjMatrix : public IAnalysis { + private: + PointMap &m_map; + bool m_gates_only; + + struct DataPoint { + float cluster, control, controllability; + }; + void dumpNeighbourhood(Node &node, std::set &hood) const; + + public: + VGAVisualLocalAdjMatrix(PointMap &map, bool gates_only) : m_map(map), m_gates_only(gates_only) {} + std::string getAnalysisName() const override { return "Local Visibility Analysis (OpenMP)"; } + bool run(Communicator *comm) override; +}; diff --git a/modules/vgaparallel/core/vgavisuallocalopenmp.cpp b/modules/vgaparallel/core/vgavisuallocalopenmp.cpp new file mode 100644 index 00000000..8a03e72b --- /dev/null +++ b/modules/vgaparallel/core/vgavisuallocalopenmp.cpp @@ -0,0 +1,159 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgavisuallocalopenmp.h" + +#include "genlib/stringutils.h" + +#include + +bool VGAVisualLocalOpenMP::run(Communicator *comm) { + time_t atime = 0; + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_RECORDS, m_map.getFilledPointCount()); + } + + AttributeTable &attributes = m_map.getAttributeTable(); + + std::vector filled; + std::vector rows; + + for (int i = 0; i < m_map.getCols(); i++) { + for (int j = 0; j < m_map.getRows(); j++) { + PixelRef curs = PixelRef(static_cast(i), static_cast(j)); + if (m_map.getPoint(curs).filled()) { + filled.push_back(curs); + rows.push_back(attributes.getRowPtr(AttributeKey(curs))); + } + } + } + + int count = 0; + + count = 0; + + std::vector col_data(filled.size()); + + if (comm) { + qtimer(atime, 0); + comm->CommPostMessage(Communicator::NUM_STEPS, 1); + comm->CommPostMessage(Communicator::CURRENT_STEP, 1); + comm->CommPostMessage(Communicator::NUM_RECORDS, filled.size()); + } + std::vector> hoods(filled.size()); + + int i, N = int(filled.size()); + std::map refToFilled; + for (i = 0; i < N; ++i) { + refToFilled.insert(std::make_pair(filled[size_t(i)], i)); + } +#pragma omp parallel for default(shared) private(i) schedule(dynamic) + for (i = 0; i < N; ++i) { + Point &p = m_map.getPoint(filled[size_t(i)]); + std::set neighbourhood; +#pragma omp critical(dumpNeighbourhood) + { dumpNeighbourhood(p.getNode(), neighbourhood); } + for (auto &neighbour : neighbourhood) { + if (m_map.getPoint(neighbour).hasNode()) { + hoods[size_t(i)].insert(refToFilled[neighbour]); + } + } + } + +#pragma omp parallel for default(shared) private(i) schedule(dynamic) + for (i = 0; i < N; ++i) { + + DataPoint &dp = col_data[i]; + + Point &p = m_map.getPoint(filled[size_t(i)]); + if ((p.contextfilled() && !filled[size_t(i)].iseven())) { + count++; + continue; + } + + // This is much easier to do with a straight forward list: + std::set &neighbourhood = hoods[size_t(i)]; + std::set totalneighbourhood; + int cluster = 0; + float control = 0.0f; + + for (auto &neighbour : neighbourhood) { + std::set &retneighbourhood = hoods[size_t(neighbour)]; + std::set intersect; + std::set_intersection(neighbourhood.begin(), neighbourhood.end(), retneighbourhood.begin(), + retneighbourhood.end(), std::inserter(intersect, intersect.begin())); + totalneighbourhood.insert(retneighbourhood.begin(), retneighbourhood.end()); + control += 1.0f / float(retneighbourhood.size()); + cluster += intersect.size(); + } +#pragma omp critical(add_to_col) + { + if (neighbourhood.size() > 1) { + dp.cluster = float(cluster / double(neighbourhood.size() * (neighbourhood.size() - 1.0))); + dp.control = float(control); + dp.controllability = float(double(neighbourhood.size()) / double(totalneighbourhood.size())); + } else { + dp.cluster = -1.0f; + dp.control = -1.0f; + dp.controllability = -1.0f; + } + } + +#pragma omp critical(count) + { + count++; // <- increment count + if (comm) { + if (qtimer(atime, 500)) { + if (comm->IsCancelled()) { + throw Communicator::CancelledException(); + } + comm->CommPostMessage(Communicator::CURRENT_RECORD, count); + } + } + } + } + + int cluster_col = attributes.insertOrResetColumn("Visual Clustering Coefficient"); + int control_col = attributes.insertOrResetColumn("Visual Control"); + int controllability_col = attributes.insertOrResetColumn("Visual Controllability"); + + auto dataIter = col_data.begin(); + for (auto row : rows) { + row->setValue(cluster_col, dataIter->cluster); + row->setValue(control_col, dataIter->control); + row->setValue(controllability_col, dataIter->controllability); + dataIter++; + } + m_map.setDisplayedAttribute(cluster_col); + + return true; +} + +void VGAVisualLocalOpenMP::dumpNeighbourhood(Node &node, std::set &hood) const { + for (int i = 0; i < 32; i++) { + Bin &bin = node.bin(i); + for (auto pixVec : bin.m_pixel_vecs) { + for (PixelRef pix = pixVec.start(); pix.col(bin.m_dir) <= pixVec.end().col(bin.m_dir);) { + hood.insert(pix); + pix.move(bin.m_dir); + } + } + } +} diff --git a/modules/vgaparallel/core/vgavisuallocalopenmp.h b/modules/vgaparallel/core/vgavisuallocalopenmp.h new file mode 100644 index 00000000..8cd217cc --- /dev/null +++ b/modules/vgaparallel/core/vgavisuallocalopenmp.h @@ -0,0 +1,39 @@ +// sala - a component of the depthmapX - spatial network analysis platform +// Copyright (C) 2000-2010, University College London, Alasdair Turner +// Copyright (C) 2011-2012, Tasos Varoudis +// Copyright (C) 2017-2018, Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "salalib/ianalysis.h" +#include "salalib/options.h" +#include "salalib/pixelref.h" +#include "salalib/pointdata.h" + +class VGAVisualLocalOpenMP : public IAnalysis { + private: + PointMap &m_map; + struct DataPoint { + float cluster, control, controllability; + }; + + void dumpNeighbourhood(Node &node, std::set &hood) const; + + public: + VGAVisualLocalOpenMP(PointMap &map) : m_map(map) {} + std::string getAnalysisName() const override { return "Local Visibility Analysis (OpenMP)"; } + bool run(Communicator *comm) override; +}; diff --git a/modules/vgaparallel/coreTest/CMakeLists.txt b/modules/vgaparallel/coreTest/CMakeLists.txt new file mode 100644 index 00000000..2aee88b0 --- /dev/null +++ b/modules/vgaparallel/coreTest/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +set(vgaparallelcoretest vgaparallelcoretest) +set(vgaparallelcoretest_SRCS + vgaparallelcoretest.cpp) + +set(modules_coreTest "${modules_coreTest}" "vgaparallelcoretest" CACHE INTERNAL "modules_coreTest" FORCE) + +add_compile_definitions(VGAPARALLEL_CORE_TEST_LIBRARY) + +add_library(${vgaparallelcoretest} OBJECT ${vgaparallelcoretest_SRCS}) diff --git a/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp b/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp new file mode 100644 index 00000000..d8a547be --- /dev/null +++ b/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp @@ -0,0 +1,118 @@ +// Copyright (C) 2020 Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "catch.hpp" +#include "modules/segmentshortestpaths/core/segmmetricshortestpath.h" +#include "modules/segmentshortestpaths/core/segmtopologicalshortestpath.h" +#include "modules/segmentshortestpaths/core/segmtulipshortestpath.h" +#include "salalib/axialmap.h" +#include "salalib/mapconverter.h" + +TEST_CASE("Shortest paths working examples", "") { + const float EPSILON = 0.001; + + // construct an axial map which will result in three different paths for the three types + ShapeGraph axialMap("Dummy drawing map", ShapeMap::AXIALMAP); + axialMap.initialiseAttributesAxial(); + std::vector lines; + lines.push_back(Line(Point2f(1.05000000, 1.00000000), Point2f(3.60000000, 1.00000000))); + lines.push_back(Line(Point2f(3.43455142, 2.92439257), Point2f(4.15448579, 3.75607430))); + lines.push_back(Line(Point2f(2.40000000, 3.00000000), Point2f(3.60000000, 3.00000000))); + lines.push_back(Line(Point2f(1.15022677, 0.90136061), Point2f(1.34977323, 2.09863939))); + lines.push_back(Line(Point2f(3.50000000, 3.10000000), Point2f(3.50000000, 0.90000000))); + lines.push_back(Line(Point2f(1.24560093, 1.95201016), Point2f(2.11199711, 2.42593102))); + lines.push_back(Line(Point2f(1.96351621, 2.29850806), Point2f(2.56074850, 3.07943312))); + + lines.push_back(Line(Point2f(1.28848772, 1.91061952), Point2f(1.75546653, 2.84134127))); + lines.push_back(Line(Point2f(1.61521977, 2.72198377), Point2f(2.59540115, 3.02997701))); + lines.push_back(Line(Point2f(1.23737734, 1.07071068), Point2f(0.45955989, 0.29289322))); + for (Line line : lines) { + axialMap.makeLineShape(line); + } + axialMap.makeConnections(); + + REQUIRE(axialMap.getShapeCount() == 10); + + std::unique_ptr segmentMap = + MapConverter::convertAxialToSegment(nullptr, axialMap, "Dummy segment map", true, true, 0.4); + + REQUIRE(segmentMap->getShapeCount() == 10); + + // select the two edges + QtRegion selRegion(lines[1].midpoint(), lines[1].midpoint()); + segmentMap->setCurSel(selRegion, false); + selRegion.bottom_left = lines[9].midpoint(); + selRegion.top_right = lines[9].midpoint(); + segmentMap->setCurSel(selRegion, true); + REQUIRE(segmentMap->getSelCount() == 2); + + { + REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Angle")); + REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Order")); + SegmentTulipShortestPath(*segmentMap.get()).run(nullptr); + REQUIRE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Angle")); + REQUIRE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Order")); + int angleColIdx = segmentMap->getAttributeTable().getColumnIndex("Angular Shortest Path Angle"); + int orderColIdx = segmentMap->getAttributeTable().getColumnIndex("Angular Shortest Path Order"); + std::vector expectedAngles = {-1, 0, 0.54297, 1.42969, -1, -1, -1, 1.24219, 0.734375, 1.82422}; + std::vector expectedOrder = {-1, 0, 1, 4, -1, -1, -1, 3, 2, 5}; + for (int i = 0; i < lines.size(); i++) { + QtRegion selRegion(lines[i].midpoint(), lines[i].midpoint()); + AttributeRow &shapeRow = + segmentMap->getAttributeRowFromShapeIndex(segmentMap->getShapesInRegion(selRegion).begin()->first); + + REQUIRE(shapeRow.getValue(angleColIdx) == Approx(expectedAngles[i]).epsilon(EPSILON)); + REQUIRE(shapeRow.getValue(orderColIdx) == expectedOrder[i]); + } + } + + { + REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Distance")); + REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Order")); + SegmentMetricShortestPath(*segmentMap.get()).run(nullptr); + REQUIRE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Distance")); + REQUIRE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Order")); + int distanceColIdx = segmentMap->getAttributeTable().getColumnIndex("Metric Shortest Path Distance"); + int orderColIdx = segmentMap->getAttributeTable().getColumnIndex("Metric Shortest Path Order"); + std::vector expectedDistances = {-1, 0, 1, 3.57756, -1, 2.67689, 1.89156, -1, -1, 4.58446}; + std::vector expectedOrder = {-1, 0, 1, 4, -1, 3, 2, -1, -1, 5}; + for (int i = 0; i < lines.size(); i++) { + QtRegion selRegion(lines[i].midpoint(), lines[i].midpoint()); + AttributeRow &shapeRow = + segmentMap->getAttributeRowFromShapeIndex(segmentMap->getShapesInRegion(selRegion).begin()->first); + REQUIRE(shapeRow.getValue(distanceColIdx) == Approx(expectedDistances[i]).epsilon(EPSILON)); + REQUIRE(shapeRow.getValue(orderColIdx) == expectedOrder[i]); + } + } + + { + REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Depth")); + REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Order")); + SegmentTopologicalShortestPath(*segmentMap.get()).run(nullptr); + REQUIRE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Depth")); + REQUIRE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Order")); + int depthColIdx = segmentMap->getAttributeTable().getColumnIndex("Topological Shortest Path Depth"); + int orderColIdx = segmentMap->getAttributeTable().getColumnIndex("Topological Shortest Path Order"); + std::vector expectedDepths = {2, 0, -1, -1, 1, -1, -1, -1, -1, 3}; + std::vector expectedOrder = {2, 0, -1, -1, 1, -1, -1, -1, -1, 3}; + for (int i = 0; i < lines.size(); i++) { + QtRegion selRegion(lines[i].midpoint(), lines[i].midpoint()); + AttributeRow &shapeRow = + segmentMap->getAttributeRowFromShapeIndex(segmentMap->getShapesInRegion(selRegion).begin()->first); + REQUIRE(shapeRow.getValue(depthColIdx) == Approx(expectedDepths[i]).epsilon(EPSILON)); + REQUIRE(shapeRow.getValue(orderColIdx) == expectedOrder[i]); + } + } +} diff --git a/modules/vgaparallel/gui/CMakeLists.txt b/modules/vgaparallel/gui/CMakeLists.txt new file mode 100644 index 00000000..8e3fb8b8 --- /dev/null +++ b/modules/vgaparallel/gui/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (C) 2020 Petros Koutsolampros + +# This program 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. + +# This program 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 this program. If not, see . + +set(vgaparallelgui vgaparallelgui) + +set(CMAKE_AUTOMOC ON) +# AUTOUIC is required to trigger the equivalent function in depthmapX +# the .ui files in this target are however generated using qt5_wrap_ui +set(CMAKE_AUTOUIC_SEARCH_PATHS UI ../../../depthmapX/UI) +set(CMAKE_AUTOUIC ON) +find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED) + +set(vgaparallelgui_SRCS + uictrigger.cpp + vgaparallelmainwindow.cpp + vgaparalleloptionsdlg.cpp +) + +set(modules_gui "${modules_gui}" "vgaparallelgui" CACHE INTERNAL "modules_gui" FORCE) + +qt5_wrap_ui(vgaparallelgui_UIS + UI/vgaparalleloptionsdlg.ui +) + + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${Qt5Core_INCLUDE_DIRS}) +include_directories(${Qt5Widgets_INCLUDE_DIRS}) +include_directories(${Qt5Gui_INCLUDE_DIRS}) + +add_definitions(${Qt5Core_DEFINITIONS}) +add_definitions(${Qt5Widgets_DEFINITIONS}) +add_definitions(${Qt5Gui_DEFINITIONS}) + +add_compile_definitions(VGAPARALLEL_GUI_LIBRARY) + +add_library(${vgaparallelgui} OBJECT ${vgaparallelgui_SRCS} ${vgaparallelgui_UIS}) diff --git a/modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui b/modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui new file mode 100644 index 00000000..4bbbc654 --- /dev/null +++ b/modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui @@ -0,0 +1,297 @@ + + + VGAParallelOptionsDlg + + + + 0 + 0 + 577 + 338 + + + + Analysis Options + + + + + + Analysis Type + + + + + + Calculate isovist properties + + + + + + + Calculate visibility relationships + + + + + + + + + Include &global measures | Select radius (n or number)-> + + + + + + + + + + + + Include &local measures + + + + + + + Calculate metric relationships + + + + + + + + + Radius + + + + + + + + + + + + Calculate angular relationships + + + + + + + Calculate through vision + + + + + + + + + Record gate counts in data map + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + c_output_type + clicked(bool) + VGAParallelOptionsDlg + OnOutputType(bool) + + + 92 + 35 + + + 246 + 1 + + + + + c_radio1 + clicked(bool) + VGAParallelOptionsDlg + OnOutputType(bool) + + + 148 + 72 + + + 330 + 52 + + + + + c_radio2 + clicked(bool) + VGAParallelOptionsDlg + OnOutputType(bool) + + + 141 + 156 + + + 329 + 164 + + + + + c_radio3 + clicked(bool) + VGAParallelOptionsDlg + OnOutputType(bool) + + + 132 + 231 + + + 328 + 231 + + + + + c_radio4 + clicked(bool) + VGAParallelOptionsDlg + OnOutputType(bool) + + + 122 + 256 + + + 324 + 315 + + + + + c_radius + textChanged(QString) + VGAParallelOptionsDlg + OnUpdateRadius(QString) + + + 248 + 106 + + + 331 + 93 + + + + + c_radius2 + textChanged(QString) + VGAParallelOptionsDlg + OnUpdateRadius2(QString) + + + 110 + 188 + + + 331 + 192 + + + + + c_ok + clicked() + VGAParallelOptionsDlg + OnOK() + + + 115 + 337 + + + 29 + 324 + + + + + c_cancel + clicked() + VGAParallelOptionsDlg + OnCancel() + + + 249 + 330 + + + 301 + 328 + + + + + + OnOutputType(bool) + OnUpdateRadius(QString) + OnUpdateRadius2(QString) + OnOK() + OnCancel() + + diff --git a/modules/vgaparallel/gui/uictrigger.cpp b/modules/vgaparallel/gui/uictrigger.cpp new file mode 100644 index 00000000..3d79019a --- /dev/null +++ b/modules/vgaparallel/gui/uictrigger.cpp @@ -0,0 +1,5 @@ +// This file is required to trigger cmake's AUTOUIC in the depthmapX directory +// if it is not included then the ui_*.h files in that directory are not generated +// and then not found by the module which is built first because it is a dependency +// of depthmapX. +#include "depthmapX/ui_ColourScaleDlg.h" diff --git a/modules/vgaparallel/gui/vgaparallelmainwindow.cpp b/modules/vgaparallel/gui/vgaparallelmainwindow.cpp new file mode 100644 index 00000000..52e1292c --- /dev/null +++ b/modules/vgaparallel/gui/vgaparallelmainwindow.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2020 Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgaparallelmainwindow.h" + +#include "modules/vgaparallel/core/vgaangularopenmp.h" +#include "modules/vgaparallel/core/vgametricopenmp.h" +#include "modules/vgaparallel/core/vgavisualglobalopenmp.h" +#include "modules/vgaparallel/core/vgavisuallocaladjmatrix.h" +#include "modules/vgaparallel/core/vgavisuallocalopenmp.h" +#include "vgaparalleloptionsdlg.h" + +#include "depthmapX/mainwindowhelpers.h" + +#include +#include + +bool VGAParallelMainWindow::createMenus(MainWindow *mainWindow) { + QMenu *toolsMenu = MainWindowHelpers::getOrAddRootMenu(mainWindow, tr("&Tools")); + QMenu *visibilityMenu = MainWindowHelpers::getOrAddMenu(toolsMenu, tr("&Visibility")); + + QAction *vgaParallelAct = new QAction(tr("Parallel Visibility Graph Analysis..."), mainWindow); + connect(vgaParallelAct, &QAction::triggered, this, [this, mainWindow] { OnVGAParallel(mainWindow); }); + visibilityMenu->addAction(vgaParallelAct); + + return true; +} + +void VGAParallelMainWindow::OnVGAParallel(MainWindow *mainWindow) { + QGraphDoc *graphDoc = mainWindow->activeMapDoc(); + if (graphDoc == nullptr) + return; + + if (graphDoc->m_communicator) { + QMessageBox::warning(mainWindow, tr("Warning"), tr("Please wait, another process is running"), QMessageBox::Ok, + QMessageBox::Ok); + return; + } + if (graphDoc->m_meta_graph->getDisplayedMapType() != ShapeMap::POINTMAP) { + QMessageBox::warning(mainWindow, tr("Warning"), tr("Please make sure the displayed map is a vga map"), + QMessageBox::Ok, QMessageBox::Ok); + return; + } + + VGAParallelOptionsDlg dlg; + + dlg.m_layer_names.push_back(""); + for (auto &dataMap : graphDoc->m_meta_graph->getDataMaps()) { + dlg.m_layer_names.push_back(dataMap.getName()); + } + + if (QDialog::Accepted != dlg.exec()) { + return; + } + + graphDoc->m_communicator = new CMSCommunicator(); + + switch (dlg.m_output_type) { + case VGAParallelOptionsDlg::AnalysisType::ISOVIST_OPENMP: + // analysisCompleted = VGAIsovist().run(communicator, getDisplayedPointMap(), simple_version); + break; + case VGAParallelOptionsDlg::AnalysisType::VISUAL_GLOBAL_OPENMP: + graphDoc->m_communicator->setAnalysis(std::unique_ptr(new VGAVisualGlobalOpenMP( + graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_radius, dlg.m_gates_only))); + break; + case VGAParallelOptionsDlg::AnalysisType::VISUAL_LOCAL_OPENMP: + graphDoc->m_communicator->setAnalysis( + std::unique_ptr(new VGAVisualLocalOpenMP(graphDoc->m_meta_graph->getDisplayedPointMap()))); + break; + case VGAParallelOptionsDlg::AnalysisType::VISUAL_LOCAL_ADJMATRIX: + graphDoc->m_communicator->setAnalysis(std::unique_ptr( + new VGAVisualLocalAdjMatrix(graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_gates_only))); + break; + case VGAParallelOptionsDlg::AnalysisType::METRIC_OPENMP: + graphDoc->m_communicator->setAnalysis(std::unique_ptr( + new VGAMetricOpenMP(graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_radius, dlg.m_gates_only))); + break; + case VGAParallelOptionsDlg::AnalysisType::ANGULAR_OPENMP: + graphDoc->m_communicator->setAnalysis(std::unique_ptr( + new VGAAngularOpenMP(graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_radius, dlg.m_gates_only))); + break; + case VGAParallelOptionsDlg::AnalysisType::THROUGH_VISION_OPENMP: + // analysisCompleted = VGAThroughVision().run(communicator, getDisplayedPointMap(), simple_version); + break; + case VGAParallelOptionsDlg::AnalysisType::NONE: + QMessageBox::warning(mainWindow, tr("Warning"), tr("Please select an analysis type"), QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + graphDoc->m_communicator->SetFunction(CMSCommunicator::FROMCONNECTOR); + graphDoc->m_communicator->setSuccessUpdateFlags(QGraphDoc::NEW_DATA); + graphDoc->m_communicator->setSuccessRedrawFlags(QGraphDoc::VIEW_ALL, QGraphDoc::REDRAW_GRAPH, QGraphDoc::NEW_DATA); + + graphDoc->CreateWaitDialog(tr("Calculating shortest path...")); + graphDoc->m_thread.render(graphDoc); +} diff --git a/modules/vgaparallel/gui/vgaparallelmainwindow.h b/modules/vgaparallel/gui/vgaparallelmainwindow.h new file mode 100644 index 00000000..7dc7fa05 --- /dev/null +++ b/modules/vgaparallel/gui/vgaparallelmainwindow.h @@ -0,0 +1,28 @@ +// Copyright (C) 2020 Petros Koutsolampros + +// This program 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. + +// This program 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 this program. If not, see . + +#pragma once + +#include "depthmapX/imainwindowmodule.h" + +class VGAParallelMainWindow : public IMainWindowModule { + + private slots: + void OnVGAParallel(MainWindow *mainWindow); + + public: + VGAParallelMainWindow() : IMainWindowModule() {} + bool createMenus(MainWindow *mainWindow); +}; diff --git a/modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp b/modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp new file mode 100644 index 00000000..c31d0b9f --- /dev/null +++ b/modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp @@ -0,0 +1,186 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program 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. + +// This program 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 this program. If not, see . + +#include "vgaparalleloptionsdlg.h" +#include "depthmapX/mainwindow.h" +#include + +VGAParallelOptionsDlg::VGAParallelOptionsDlg(QWidget *parent) : QDialog(parent) { + setupUi(this); + m_global = false; + m_local = false; + m_radiusString = tr(""); + m_radius = -1; + m_gates_only = false; + m_output_type = AnalysisType::NONE; + m_radiusString2 = tr(""); + m_gatelayer = -1; +} + +void VGAParallelOptionsDlg::OnOutputType(bool value) { + UpdateData(true); + + if (m_output_type == AnalysisType::VISUAL_GLOBAL_OPENMP) { + c_local->setEnabled(true); + c_global->setEnabled(true); + c_radius->setEnabled(true); + } else { + c_local->setEnabled(false); + c_global->setEnabled(false); + c_radius->setEnabled(false); + c_radius->setText(tr("n")); // <- essentially, undo changes + } + + if (m_output_type == AnalysisType::METRIC_OPENMP) { + c_radius2->setEnabled(true); + } else { + c_radius2->setText(tr("n")); // <- essentially, undo changes + c_radius2->setEnabled(false); + } +} + +void VGAParallelOptionsDlg::OnUpdateRadius(QString text) { + if (text.length()) { + if (!text.toInt() && text != tr("n")) { + QMessageBox::warning(this, tr("Warning"), tr("The radius must either be n or number in range 1-99"), + QMessageBox::Ok, QMessageBox::Ok); + c_radius->setText(tr("n")); + } + } +} + +void VGAParallelOptionsDlg::OnUpdateRadius2(QString text) { + if (text.length()) { + if (text.toDouble() == 0.0 && text != tr("n")) { + QMessageBox::warning(this, tr("Warning"), tr("The radius must either be n or a positive number"), + QMessageBox::Ok, QMessageBox::Ok); + c_radius2->setText(tr("n")); + } + } +} + +void VGAParallelOptionsDlg::OnOK() { + UpdateData(true); + + m_gatelayer = c_layer_selector->currentIndex() - 1; + + if (m_output_type == AnalysisType::VISUAL_GLOBAL_OPENMP) { + if (m_radiusString.compare(tr("n")) == 0) { // 0 means identical + m_radius = -1.0; + } else { + m_radius = (double)m_radiusString.toInt(); + if (m_radius <= 0.0) { + QMessageBox::warning(this, tr("Warning"), + tr("The radius must either be n or a number in the range 1-99"), QMessageBox::Ok, + QMessageBox::Ok); + return; + } + } + } else { + if (m_radiusString2.compare(tr("n")) == 0) { // 0 means identical + m_radius = -1.0; + } else { + m_radius = m_radiusString2.toDouble(); + if (m_radius <= 0.0) { + QMessageBox::warning(this, tr("Warning"), tr("The radius must either be n or a positive number"), + QMessageBox::Ok, QMessageBox::Ok); + return; + } + } + } + accept(); +} + +void VGAParallelOptionsDlg::OnCancel() { reject(); } + +void VGAParallelOptionsDlg::UpdateData(bool value) { + if (value) { + if (c_global->checkState()) + m_global = true; + else + m_global = false; + + if (c_local->checkState()) + m_local = true; + else + m_local = false; + + m_radiusString = c_radius->text(); + + if (c_output_type->isChecked()) + m_output_type = AnalysisType::ISOVIST_OPENMP; + else if (c_radio1->isChecked()) + m_output_type = AnalysisType::VISUAL_GLOBAL_OPENMP; + else if (c_radio2->isChecked()) + m_output_type = AnalysisType::METRIC_OPENMP; + else if (c_radio3->isChecked()) + m_output_type = AnalysisType::ANGULAR_OPENMP; + else if (c_radio4->isChecked()) + m_output_type = AnalysisType::THROUGH_VISION_OPENMP; + else + m_output_type = AnalysisType::NONE; + m_radiusString2 = c_radius2->text(); + } else { + if (m_global) + c_global->setCheckState(Qt::Checked); + else + c_global->setCheckState(Qt::Unchecked); + + if (m_local) + c_local->setCheckState(Qt::Checked); + else + c_local->setCheckState(Qt::Unchecked); + + c_radius->setText(m_radiusString); + + switch (m_output_type) { + case AnalysisType::ISOVIST_OPENMP: + c_output_type->setChecked(true); + break; + case AnalysisType::VISUAL_GLOBAL_OPENMP: + c_radio1->setChecked(true); + break; + case AnalysisType::METRIC_OPENMP: + c_radio2->setChecked(true); + break; + case AnalysisType::ANGULAR_OPENMP: + c_radio3->setChecked(true); + break; + case AnalysisType::THROUGH_VISION_OPENMP: + c_radio4->setChecked(true); + break; + default: + break; + } + c_radius2->setText(m_radiusString2); + } +} + +void VGAParallelOptionsDlg::showEvent(QShowEvent *event) { + for (size_t i = 0; i < m_layer_names.size(); i++) { + c_layer_selector->addItem(QString(m_layer_names[i].c_str())); + } + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + MainWindow *mainWin = qobject_cast(widget); + if (mainWin) { + c_layer_selector->setCurrentIndex(m_gatelayer + 1); + break; + } + } + + OnOutputType(false); + + UpdateData(false); +} diff --git a/modules/vgaparallel/gui/vgaparalleloptionsdlg.h b/modules/vgaparallel/gui/vgaparalleloptionsdlg.h new file mode 100644 index 00000000..a27736fe --- /dev/null +++ b/modules/vgaparallel/gui/vgaparalleloptionsdlg.h @@ -0,0 +1,54 @@ +// Copyright (C) 2011-2012, Tasos Varoudis + +// This program 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. + +// This program 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 this program. If not, see . + +#include "ui_vgaparalleloptionsdlg.h" +#include +#include +#include + +class VGAParallelOptionsDlg : public QDialog, public Ui::VGAParallelOptionsDlg { + Q_OBJECT + public: + enum class AnalysisType { + NONE, + ISOVIST_OPENMP, + VISUAL_LOCAL_OPENMP, + VISUAL_LOCAL_ADJMATRIX, + VISUAL_GLOBAL_OPENMP, + METRIC_OPENMP, + ANGULAR_OPENMP, + THROUGH_VISION_OPENMP + }; + VGAParallelOptionsDlg(QWidget *parent = 0); + bool m_global; + bool m_local; + QString m_radiusString; + QString m_radiusString2; + double m_radius; + bool m_gates_only; + int m_gatelayer; + AnalysisType m_output_type; + void UpdateData(bool value); + void showEvent(QShowEvent *event); + + std::vector m_layer_names; + + private slots: + void OnOutputType(bool); + void OnUpdateRadius(QString); + void OnUpdateRadius2(QString); + void OnOK(); + void OnCancel(); +}; From dc812013c9d4e0cd2b8d9d617706435a10ad9e1d Mon Sep 17 00:00:00 2001 From: Petros Koutsolampros Date: Thu, 31 Dec 2020 01:10:36 +0200 Subject: [PATCH 2/5] Copy the VGA parser --- modules/vgaparallel/cli/vgaparallelparser.cpp | 162 ++++++++---------- modules/vgaparallel/cli/vgaparallelparser.h | 47 ++--- 2 files changed, 97 insertions(+), 112 deletions(-) diff --git a/modules/vgaparallel/cli/vgaparallelparser.cpp b/modules/vgaparallel/cli/vgaparallelparser.cpp index 631d6862..2c11addc 100644 --- a/modules/vgaparallel/cli/vgaparallelparser.cpp +++ b/modules/vgaparallel/cli/vgaparallelparser.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Petros Koutsolampros +// Copyright (C) 2017 Christian Sailer // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,121 +18,103 @@ #include "depthmapXcli/parsingutils.h" #include "depthmapXcli/runmethods.h" #include "depthmapXcli/simpletimer.h" -#include "modules/segmentshortestpaths/core/segmmetricshortestpath.h" -#include "modules/segmentshortestpaths/core/segmtopologicalshortestpath.h" -#include "modules/segmentshortestpaths/core/segmtulipshortestpath.h" -#include "salalib/entityparsing.h" +#include "salalib/options.h" #include -#include +#include using namespace depthmapX; -void VGAParallelParser::parse(int argc, char **argv) { +VgaParallelParser::VgaParallelParser() : m_vgaMode(VgaMode::NONE), m_localMeasures(false), m_globalMeasures(false) {} - std::string originPoint; - std::string destinationPoint; - for (int i = 1; i < argc; ++i) { - if (std::strcmp("-sspo", argv[i]) == 0) { - if (!originPoint.empty()) { - throw CommandLineException("-sspo can only be provided once"); - } - ENFORCE_ARGUMENT("-sspo", i) - if (!has_only_digits_dots_commas(argv[i])) { - std::stringstream message; - message << "Invalid origin point provided (" << argv[i] - << "). Should only contain digits dots and commas" << std::flush; - throw CommandLineException(message.str().c_str()); - } - originPoint = argv[i]; - } - if (std::strcmp("-sspd", argv[i]) == 0) { - if (!destinationPoint.empty()) { - throw CommandLineException("-sspd can only be provided once"); - } - ENFORCE_ARGUMENT("-sspd", i) - if (!has_only_digits_dots_commas(argv[i])) { - std::stringstream message; - message << "Invalid destination point provided (" << argv[i] - << "). Should only contain digits dots and commas" << std::flush; - throw CommandLineException(message.str().c_str()); +void VgaParallelParser::parse(int argc, char *argv[]) { + for (int i = 1; i < argc;) { + + if (std::strcmp("-vm", argv[i]) == 0) { + if (m_vgaMode != VgaMode::NONE) { + throw CommandLineException("-vm can only be used once, modes are mutually exclusive"); } - destinationPoint = argv[i]; - } else if (std::strcmp("-sspt", argv[i]) == 0) { - ENFORCE_ARGUMENT("-sspt", i) - if (std::strcmp(argv[i], "tulip") == 0) { - m_stepType = StepType::TULIP; + ENFORCE_ARGUMENT("-vm", i) + if (std::strcmp(argv[i], "isovist") == 0) { + m_vgaMode = VgaMode::ISOVIST; + } else if (std::strcmp(argv[i], "visibility") == 0) { + m_vgaMode = VgaMode::VISBILITY; } else if (std::strcmp(argv[i], "metric") == 0) { - m_stepType = StepType::METRIC; - } else if (std::strcmp(argv[i], "topological") == 0) { - m_stepType = StepType::TOPOLOGICAL; + m_vgaMode = VgaMode::METRIC; + } else if (std::strcmp(argv[i], "angular") == 0) { + m_vgaMode = VgaMode::ANGULAR; + } else if (std::strcmp(argv[i], "thruvision") == 0) { + m_vgaMode = VgaMode::THRU_VISION; } else { - throw CommandLineException(std::string("Invalid step type: ") + argv[i]); + throw CommandLineException(std::string("Invalid VGA mode: ") + argv[i]); } + } else if (std::strcmp(argv[i], "-vg") == 0) { + m_globalMeasures = true; + } else if (std::strcmp(argv[i], "-vl") == 0) { + m_localMeasures = true; + } else if (std::strcmp(argv[i], "-vr") == 0) { + ENFORCE_ARGUMENT("-vr", i) + m_radius = argv[i]; } + ++i; } - if (originPoint.empty() || destinationPoint.empty()) { - throw CommandLineException("Both -sspo and -sspd must be provided"); + if (m_vgaMode == VgaMode::NONE) { + m_vgaMode = VgaMode::ISOVIST; } - std::stringstream pointsStream; - pointsStream << "x,y"; - pointsStream << "\n" << originPoint; - pointsStream << "\n" << destinationPoint; - std::vector parsed = EntityParsing::parsePoints(pointsStream, ','); - m_originPoint = parsed[0]; - m_destinationPoint = parsed[1]; + if (m_vgaMode == VgaMode::VISBILITY && m_globalMeasures) { + if (m_radius.empty()) { + throw CommandLineException( + "Global measures in VGA/visibility analysis require a radius, use -vr "); + } + if (m_radius != "n" && !has_only_digits(m_radius)) { + throw CommandLineException(std::string("Radius must be a positive integer number or n, got ") + m_radius); + } - if (m_stepType == StepType::NONE) { - throw CommandLineException("Step depth type (-sspt) must be provided"); + } else if (m_vgaMode == VgaMode::METRIC) { + if (m_radius.empty()) { + throw CommandLineException("Metric vga requires a radius, use -vr "); + } } } -void VGAParallelParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const { - auto mGraph = dm_runmethods::loadGraph(clp.getFileName().c_str(), perfWriter); - - std::cout << "ok\nSelecting cells... " << std::flush; +void VgaParallelParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const { + RadiusConverter radiusConverter; - auto graphRegion = mGraph->getRegion(); + auto mgraph = dm_runmethods::loadGraph(clp.getFileName().c_str(), perfWriter); - if (!graphRegion.contains(m_originPoint)) { - throw depthmapX::RuntimeException("Origin point outside of target region"); - } - if (!graphRegion.contains(m_destinationPoint)) { - throw depthmapX::RuntimeException("Destination point outside of target region"); - } - QtRegion r(m_originPoint, m_originPoint); - mGraph->setCurSel(r, false); + std::unique_ptr options(new Options()); - r = QtRegion(m_destinationPoint, m_destinationPoint); - mGraph->setCurSel(r, true); - - std::cout << "ok\nCalculating shortest path... " << std::flush; - - std::unique_ptr comm(new ICommunicator()); - - switch (m_stepType) { - case VGAParallelParser::StepType::TULIP: { - DO_TIMED("Calculating tulip shortest path", - SegmentTulipShortestPath(mGraph->getDisplayedShapeGraph()).run(comm.get())) + std::cout << "Getting options..." << std::flush; + switch (getVgaMode()) { + case VgaParser::VgaMode::VISBILITY: + options->output_type = Options::OUTPUT_VISUAL; + options->local = localMeasures(); + options->global = globalMeasures(); + if (options->global) { + options->radius = radiusConverter.ConvertForVisibility(getRadius()); + } break; - } - case VGAParallelParser::StepType::METRIC: { - DO_TIMED("Calculating metric shortest path", - SegmentMetricShortestPath(mGraph->getDisplayedShapeGraph()).run(comm.get())) + case VgaParser::VgaMode::METRIC: + options->output_type = Options::OUTPUT_METRIC; + options->radius = radiusConverter.ConvertForMetric(getRadius()); break; - } - case VGAParallelParser::StepType::TOPOLOGICAL: { - DO_TIMED("Calculating topological shortest path", - SegmentTopologicalShortestPath(mGraph->getDisplayedShapeGraph()).run(comm.get())) + case VgaParser::VgaMode::ANGULAR: + options->output_type = Options::OUTPUT_ANGULAR; break; + case VgaParser::VgaMode::ISOVIST: + options->output_type = Options::OUTPUT_ISOVIST; + break; + case VgaParser::VgaMode::THRU_VISION: + options->output_type = Options::OUTPUT_THRU_VISION; + break; + default: + throw depthmapX::SetupCheckException("Unsupported VGA mode"); } - default: { - throw depthmapX::SetupCheckException("Error, unsupported step type"); - } - } + std::cout << " ok\nAnalysing graph..." << std::flush; + DO_TIMED("Run VGA", mgraph->analyseGraph(dm_runmethods::getCommunicator(clp).get(), *options, clp.simpleMode())) std::cout << " ok\nWriting out result..." << std::flush; - DO_TIMED("Writing graph", mGraph->write(clp.getOuputFile().c_str(), METAGRAPH_VERSION, false)) + DO_TIMED("Writing graph", mgraph->write(clp.getOuputFile().c_str(), METAGRAPH_VERSION, false)) std::cout << " ok" << std::endl; } diff --git a/modules/vgaparallel/cli/vgaparallelparser.h b/modules/vgaparallel/cli/vgaparallelparser.h index 0256a447..cec6e2a0 100644 --- a/modules/vgaparallel/cli/vgaparallelparser.h +++ b/modules/vgaparallel/cli/vgaparallelparser.h @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Petros Koutsolampros +// Copyright (C) 2017 Christian Sailer // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,37 +15,40 @@ #pragma once +#include "depthmapXcli/commandlineparser.h" #include "depthmapXcli/imodeparser.h" -#include "genlib/p2dpoly.h" -#include +#include "depthmapXcli/radiusconverter.h" +#include -class VGAParallelParser : public IModeParser { +class VgaParallelParser : public IModeParser { public: - VGAParallelParser() : m_stepType(StepType::NONE) {} - - virtual std::string getModeName() const { return "SEGMENTSHORTESTPATH"; } + virtual std::string getModeName() const { return "VGA"; } virtual std::string getHelp() const { - return "Mode options for pointmap SEGMENTSHORTESTPATH are:\n" - " -sspo point where to calculate shortest path between.\n" - " -sspd point where to calculate shortest path between.\n" - " -sspt step type. One of metric, tulip or topological.\n"; + return "Mode options for VGAPARALLEL:\n" + "-vm one of isovist, visiblity, metric, angular, thruvision\n" + "-vg turn on global measures for visibility, requires radius between 1 and 99 or n\n" + "-vl turn on local measures for visibility\n" + "-vr set visibility radius\n"; } - enum class StepType { NONE, TULIP, METRIC, TOPOLOGICAL }; - - virtual void parse(int argc, char **argv); - + public: + VgaParallelParser(); + virtual void parse(int argc, char *argv[]); virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; - Point2f getShortestPathOrigin() const { return m_originPoint; } - Point2f getShortestPathDestination() const { return m_destinationPoint; } + enum VgaMode { NONE, ISOVIST, VISBILITY, METRIC, ANGULAR, THRU_VISION }; - StepType getStepType() const { return m_stepType; } + // vga options + VgaMode getVgaMode() const { return m_vgaMode; } + bool localMeasures() const { return m_localMeasures; } + bool globalMeasures() const { return m_globalMeasures; } + const std::string &getRadius() const { return m_radius; } private: - Point2f m_originPoint; - Point2f m_destinationPoint; - - StepType m_stepType; + // vga options + VgaMode m_vgaMode; + bool m_localMeasures; + bool m_globalMeasures; + std::string m_radius; }; From 357722a969f7662390a11b67938bc629dec7f0a5 Mon Sep 17 00:00:00 2001 From: Petros Koutsolampros Date: Sun, 3 Jan 2021 02:10:40 +0200 Subject: [PATCH 3/5] Replace the VGA common dialog with different menu items --- modules/vgaparallel/gui/CMakeLists.txt | 5 - .../gui/UI/vgaparalleloptionsdlg.ui | 297 ------------------ .../vgaparallel/gui/vgaparallelmainwindow.cpp | 143 ++++++--- .../vgaparallel/gui/vgaparallelmainwindow.h | 13 +- .../vgaparallel/gui/vgaparalleloptionsdlg.cpp | 186 ----------- .../vgaparallel/gui/vgaparalleloptionsdlg.h | 54 ---- 6 files changed, 119 insertions(+), 579 deletions(-) delete mode 100644 modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui delete mode 100644 modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp delete mode 100644 modules/vgaparallel/gui/vgaparalleloptionsdlg.h diff --git a/modules/vgaparallel/gui/CMakeLists.txt b/modules/vgaparallel/gui/CMakeLists.txt index 8e3fb8b8..8f67521a 100644 --- a/modules/vgaparallel/gui/CMakeLists.txt +++ b/modules/vgaparallel/gui/CMakeLists.txt @@ -25,15 +25,10 @@ find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED) set(vgaparallelgui_SRCS uictrigger.cpp vgaparallelmainwindow.cpp - vgaparalleloptionsdlg.cpp ) set(modules_gui "${modules_gui}" "vgaparallelgui" CACHE INTERNAL "modules_gui" FORCE) -qt5_wrap_ui(vgaparallelgui_UIS - UI/vgaparalleloptionsdlg.ui -) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui b/modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui deleted file mode 100644 index 4bbbc654..00000000 --- a/modules/vgaparallel/gui/UI/vgaparalleloptionsdlg.ui +++ /dev/null @@ -1,297 +0,0 @@ - - - VGAParallelOptionsDlg - - - - 0 - 0 - 577 - 338 - - - - Analysis Options - - - - - - Analysis Type - - - - - - Calculate isovist properties - - - - - - - Calculate visibility relationships - - - - - - - - - Include &global measures | Select radius (n or number)-> - - - - - - - - - - - - Include &local measures - - - - - - - Calculate metric relationships - - - - - - - - - Radius - - - - - - - - - - - - Calculate angular relationships - - - - - - - Calculate through vision - - - - - - - - - Record gate counts in data map - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - OK - - - - - - - Cancel - - - - - - - - - - - c_output_type - clicked(bool) - VGAParallelOptionsDlg - OnOutputType(bool) - - - 92 - 35 - - - 246 - 1 - - - - - c_radio1 - clicked(bool) - VGAParallelOptionsDlg - OnOutputType(bool) - - - 148 - 72 - - - 330 - 52 - - - - - c_radio2 - clicked(bool) - VGAParallelOptionsDlg - OnOutputType(bool) - - - 141 - 156 - - - 329 - 164 - - - - - c_radio3 - clicked(bool) - VGAParallelOptionsDlg - OnOutputType(bool) - - - 132 - 231 - - - 328 - 231 - - - - - c_radio4 - clicked(bool) - VGAParallelOptionsDlg - OnOutputType(bool) - - - 122 - 256 - - - 324 - 315 - - - - - c_radius - textChanged(QString) - VGAParallelOptionsDlg - OnUpdateRadius(QString) - - - 248 - 106 - - - 331 - 93 - - - - - c_radius2 - textChanged(QString) - VGAParallelOptionsDlg - OnUpdateRadius2(QString) - - - 110 - 188 - - - 331 - 192 - - - - - c_ok - clicked() - VGAParallelOptionsDlg - OnOK() - - - 115 - 337 - - - 29 - 324 - - - - - c_cancel - clicked() - VGAParallelOptionsDlg - OnCancel() - - - 249 - 330 - - - 301 - 328 - - - - - - OnOutputType(bool) - OnUpdateRadius(QString) - OnUpdateRadius2(QString) - OnOK() - OnCancel() - - diff --git a/modules/vgaparallel/gui/vgaparallelmainwindow.cpp b/modules/vgaparallel/gui/vgaparallelmainwindow.cpp index 52e1292c..25326086 100644 --- a/modules/vgaparallel/gui/vgaparallelmainwindow.cpp +++ b/modules/vgaparallel/gui/vgaparallelmainwindow.cpp @@ -20,25 +20,44 @@ #include "modules/vgaparallel/core/vgavisualglobalopenmp.h" #include "modules/vgaparallel/core/vgavisuallocaladjmatrix.h" #include "modules/vgaparallel/core/vgavisuallocalopenmp.h" -#include "vgaparalleloptionsdlg.h" #include "depthmapX/mainwindowhelpers.h" +#include "genlib/exceptions.h" +#include #include #include bool VGAParallelMainWindow::createMenus(MainWindow *mainWindow) { QMenu *toolsMenu = MainWindowHelpers::getOrAddRootMenu(mainWindow, tr("&Tools")); QMenu *visibilityMenu = MainWindowHelpers::getOrAddMenu(toolsMenu, tr("&Visibility")); - - QAction *vgaParallelAct = new QAction(tr("Parallel Visibility Graph Analysis..."), mainWindow); - connect(vgaParallelAct, &QAction::triggered, this, [this, mainWindow] { OnVGAParallel(mainWindow); }); - visibilityMenu->addAction(vgaParallelAct); + QMenu *vgaParallelMenu = MainWindowHelpers::getOrAddMenu(visibilityMenu, tr("Parallel Visibility Graph Analysis")); + + QAction *visualGlobalAct = new QAction(tr("Global Visibility"), mainWindow); + connect(visualGlobalAct, &QAction::triggered, this, + [this, mainWindow] { OnVGAParallel(mainWindow, AnalysisType::VISUAL_GLOBAL_OPENMP); }); + vgaParallelMenu->addAction(visualGlobalAct); + QAction *visualLocalAct = new QAction(tr("Local Visibility"), mainWindow); + connect(visualLocalAct, &QAction::triggered, this, + [this, mainWindow] { OnVGAParallel(mainWindow, AnalysisType::VISUAL_LOCAL_OPENMP); }); + vgaParallelMenu->addAction(visualLocalAct); + QAction *visualLocalAdjMatrixAct = new QAction(tr("Local Visibility (Adjacency Matrix)"), mainWindow); + connect(visualLocalAdjMatrixAct, &QAction::triggered, this, + [this, mainWindow] { OnVGAParallel(mainWindow, AnalysisType::VISUAL_LOCAL_ADJMATRIX); }); + vgaParallelMenu->addAction(visualLocalAdjMatrixAct); + QAction *metricAct = new QAction(tr("Global Metric"), mainWindow); + connect(metricAct, &QAction::triggered, this, + [this, mainWindow] { OnVGAParallel(mainWindow, AnalysisType::METRIC_OPENMP); }); + vgaParallelMenu->addAction(metricAct); + QAction *angularAct = new QAction(tr("Global Angular"), mainWindow); + connect(angularAct, &QAction::triggered, this, + [this, mainWindow] { OnVGAParallel(mainWindow, AnalysisType::ANGULAR_OPENMP); }); + vgaParallelMenu->addAction(angularAct); return true; } -void VGAParallelMainWindow::OnVGAParallel(MainWindow *mainWindow) { +void VGAParallelMainWindow::OnVGAParallel(MainWindow *mainWindow, AnalysisType analysisType) { QGraphDoc *graphDoc = mainWindow->activeMapDoc(); if (graphDoc == nullptr) return; @@ -54,51 +73,65 @@ void VGAParallelMainWindow::OnVGAParallel(MainWindow *mainWindow) { return; } - VGAParallelOptionsDlg dlg; - - dlg.m_layer_names.push_back(""); - for (auto &dataMap : graphDoc->m_meta_graph->getDataMaps()) { - dlg.m_layer_names.push_back(dataMap.getName()); - } - - if (QDialog::Accepted != dlg.exec()) { - return; - } - graphDoc->m_communicator = new CMSCommunicator(); - switch (dlg.m_output_type) { - case VGAParallelOptionsDlg::AnalysisType::ISOVIST_OPENMP: - // analysisCompleted = VGAIsovist().run(communicator, getDisplayedPointMap(), simple_version); - break; - case VGAParallelOptionsDlg::AnalysisType::VISUAL_GLOBAL_OPENMP: + switch (analysisType) { + case AnalysisType::VISUAL_GLOBAL_OPENMP: { + + bool ok; + QString radiusText = QInputDialog::getText(mainWindow, tr("Visibility radius"), + tr("This is the standard global-visibility analysis, parallelised " + "with OpenMP.\nRadius can be from 1 to 99 or n"), + QLineEdit::Normal, "n", &ok); + if (!ok) + return; graphDoc->m_communicator->setAnalysis(std::unique_ptr(new VGAVisualGlobalOpenMP( - graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_radius, dlg.m_gates_only))); + graphDoc->m_meta_graph->getDisplayedPointMap(), ConvertForVisibility(radiusText.toStdString()), false))); break; - case VGAParallelOptionsDlg::AnalysisType::VISUAL_LOCAL_OPENMP: + } + case AnalysisType::VISUAL_LOCAL_OPENMP: { graphDoc->m_communicator->setAnalysis( std::unique_ptr(new VGAVisualLocalOpenMP(graphDoc->m_meta_graph->getDisplayedPointMap()))); break; - case VGAParallelOptionsDlg::AnalysisType::VISUAL_LOCAL_ADJMATRIX: - graphDoc->m_communicator->setAnalysis(std::unique_ptr( - new VGAVisualLocalAdjMatrix(graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_gates_only))); - break; - case VGAParallelOptionsDlg::AnalysisType::METRIC_OPENMP: + } + case AnalysisType::VISUAL_LOCAL_ADJMATRIX: { graphDoc->m_communicator->setAnalysis(std::unique_ptr( - new VGAMetricOpenMP(graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_radius, dlg.m_gates_only))); + new VGAVisualLocalAdjMatrix(graphDoc->m_meta_graph->getDisplayedPointMap(), false))); break; - case VGAParallelOptionsDlg::AnalysisType::ANGULAR_OPENMP: - graphDoc->m_communicator->setAnalysis(std::unique_ptr( - new VGAAngularOpenMP(graphDoc->m_meta_graph->getDisplayedPointMap(), dlg.m_radius, dlg.m_gates_only))); + } + case AnalysisType::METRIC_OPENMP: { + bool ok; + QString radiusText = + QInputDialog::getText(mainWindow, tr("Metric radius"), + tr("This is the standard global-metric analysis, parallelised " + "with OpenMP.\nRadius can be any positive number or n for unlimited radius"), + QLineEdit::Normal, "n", &ok); + if (!ok) + return; + graphDoc->m_communicator->setAnalysis(std::unique_ptr(new VGAMetricOpenMP( + graphDoc->m_meta_graph->getDisplayedPointMap(), ConvertForMetric(radiusText.toStdString()), false))); break; - case VGAParallelOptionsDlg::AnalysisType::THROUGH_VISION_OPENMP: - // analysisCompleted = VGAThroughVision().run(communicator, getDisplayedPointMap(), simple_version); + } + case AnalysisType::ANGULAR_OPENMP: { + + bool ok; + QString radiusText = + QInputDialog::getText(mainWindow, tr("Angular radius"), + tr("This is the standard global-angular analysis, parallelised " + "with OpenMP.\nRadius can be any positive number or n for unlimited radius"), + QLineEdit::Normal, "n", &ok); + if (!ok) + return; + graphDoc->m_communicator->setAnalysis(std::unique_ptr(new VGAAngularOpenMP( + graphDoc->m_meta_graph->getDisplayedPointMap(), ConvertForMetric(radiusText.toStdString()), false))); break; - case VGAParallelOptionsDlg::AnalysisType::NONE: + } + case AnalysisType::NONE: { QMessageBox::warning(mainWindow, tr("Warning"), tr("Please select an analysis type"), QMessageBox::Ok, QMessageBox::Ok); return; } + } graphDoc->m_communicator->SetFunction(CMSCommunicator::FROMCONNECTOR); graphDoc->m_communicator->setSuccessUpdateFlags(QGraphDoc::NEW_DATA); @@ -107,3 +140,41 @@ void VGAParallelMainWindow::OnVGAParallel(MainWindow *mainWindow) { graphDoc->CreateWaitDialog(tr("Calculating shortest path...")); graphDoc->m_thread.render(graphDoc); } + +// Duplicating the radius converters here to keep the module self contained +// TODO: Transfer them to sala + +double VGAParallelMainWindow::ConvertForVisibility(const std::string &radius) const { + if (radius == "n") { + return -1.0; + } + char *end; + long rad = std::strtol(radius.c_str(), &end, 10); + if (rad < 1 || rad > 99) { + throw depthmapX::RuntimeException( + std::string("Radius for visibility analysis must be n for the whole range or an " + "integer between 1 and 99 inclusive. Got ") + + radius); + } + return static_cast(rad); +} + +double VGAParallelMainWindow::ConvertForMetric(const std::string &radius) const { + if (radius == "n") { + return -1.0; + } + char *end; + double rad = strtod(radius.c_str(), &end); + if (rad <= 0) { + throw depthmapX::RuntimeException( + std::string("Radius for metric vga must be n for the whole range or a positive number. Got ") + radius); + } + if (std::isnan(rad)) { + throw depthmapX::RuntimeException("Radius NaN?! Really?"); + } + if (std::isinf(rad)) { + throw depthmapX::RuntimeException("Radius inf?! Who are you kidding?"); + } + + return rad; +} diff --git a/modules/vgaparallel/gui/vgaparallelmainwindow.h b/modules/vgaparallel/gui/vgaparallelmainwindow.h index 7dc7fa05..427ef7e7 100644 --- a/modules/vgaparallel/gui/vgaparallelmainwindow.h +++ b/modules/vgaparallel/gui/vgaparallelmainwindow.h @@ -18,9 +18,20 @@ #include "depthmapX/imainwindowmodule.h" class VGAParallelMainWindow : public IMainWindowModule { + private: + enum class AnalysisType { + NONE, + VISUAL_LOCAL_OPENMP, + VISUAL_LOCAL_ADJMATRIX, + VISUAL_GLOBAL_OPENMP, + METRIC_OPENMP, + ANGULAR_OPENMP + }; + double ConvertForVisibility(const std::string &radius) const; + double ConvertForMetric(const std::string &radius) const; private slots: - void OnVGAParallel(MainWindow *mainWindow); + void OnVGAParallel(MainWindow *mainWindow, AnalysisType analysisType); public: VGAParallelMainWindow() : IMainWindowModule() {} diff --git a/modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp b/modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp deleted file mode 100644 index c31d0b9f..00000000 --- a/modules/vgaparallel/gui/vgaparalleloptionsdlg.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program 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. - -// This program 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 this program. If not, see . - -#include "vgaparalleloptionsdlg.h" -#include "depthmapX/mainwindow.h" -#include - -VGAParallelOptionsDlg::VGAParallelOptionsDlg(QWidget *parent) : QDialog(parent) { - setupUi(this); - m_global = false; - m_local = false; - m_radiusString = tr(""); - m_radius = -1; - m_gates_only = false; - m_output_type = AnalysisType::NONE; - m_radiusString2 = tr(""); - m_gatelayer = -1; -} - -void VGAParallelOptionsDlg::OnOutputType(bool value) { - UpdateData(true); - - if (m_output_type == AnalysisType::VISUAL_GLOBAL_OPENMP) { - c_local->setEnabled(true); - c_global->setEnabled(true); - c_radius->setEnabled(true); - } else { - c_local->setEnabled(false); - c_global->setEnabled(false); - c_radius->setEnabled(false); - c_radius->setText(tr("n")); // <- essentially, undo changes - } - - if (m_output_type == AnalysisType::METRIC_OPENMP) { - c_radius2->setEnabled(true); - } else { - c_radius2->setText(tr("n")); // <- essentially, undo changes - c_radius2->setEnabled(false); - } -} - -void VGAParallelOptionsDlg::OnUpdateRadius(QString text) { - if (text.length()) { - if (!text.toInt() && text != tr("n")) { - QMessageBox::warning(this, tr("Warning"), tr("The radius must either be n or number in range 1-99"), - QMessageBox::Ok, QMessageBox::Ok); - c_radius->setText(tr("n")); - } - } -} - -void VGAParallelOptionsDlg::OnUpdateRadius2(QString text) { - if (text.length()) { - if (text.toDouble() == 0.0 && text != tr("n")) { - QMessageBox::warning(this, tr("Warning"), tr("The radius must either be n or a positive number"), - QMessageBox::Ok, QMessageBox::Ok); - c_radius2->setText(tr("n")); - } - } -} - -void VGAParallelOptionsDlg::OnOK() { - UpdateData(true); - - m_gatelayer = c_layer_selector->currentIndex() - 1; - - if (m_output_type == AnalysisType::VISUAL_GLOBAL_OPENMP) { - if (m_radiusString.compare(tr("n")) == 0) { // 0 means identical - m_radius = -1.0; - } else { - m_radius = (double)m_radiusString.toInt(); - if (m_radius <= 0.0) { - QMessageBox::warning(this, tr("Warning"), - tr("The radius must either be n or a number in the range 1-99"), QMessageBox::Ok, - QMessageBox::Ok); - return; - } - } - } else { - if (m_radiusString2.compare(tr("n")) == 0) { // 0 means identical - m_radius = -1.0; - } else { - m_radius = m_radiusString2.toDouble(); - if (m_radius <= 0.0) { - QMessageBox::warning(this, tr("Warning"), tr("The radius must either be n or a positive number"), - QMessageBox::Ok, QMessageBox::Ok); - return; - } - } - } - accept(); -} - -void VGAParallelOptionsDlg::OnCancel() { reject(); } - -void VGAParallelOptionsDlg::UpdateData(bool value) { - if (value) { - if (c_global->checkState()) - m_global = true; - else - m_global = false; - - if (c_local->checkState()) - m_local = true; - else - m_local = false; - - m_radiusString = c_radius->text(); - - if (c_output_type->isChecked()) - m_output_type = AnalysisType::ISOVIST_OPENMP; - else if (c_radio1->isChecked()) - m_output_type = AnalysisType::VISUAL_GLOBAL_OPENMP; - else if (c_radio2->isChecked()) - m_output_type = AnalysisType::METRIC_OPENMP; - else if (c_radio3->isChecked()) - m_output_type = AnalysisType::ANGULAR_OPENMP; - else if (c_radio4->isChecked()) - m_output_type = AnalysisType::THROUGH_VISION_OPENMP; - else - m_output_type = AnalysisType::NONE; - m_radiusString2 = c_radius2->text(); - } else { - if (m_global) - c_global->setCheckState(Qt::Checked); - else - c_global->setCheckState(Qt::Unchecked); - - if (m_local) - c_local->setCheckState(Qt::Checked); - else - c_local->setCheckState(Qt::Unchecked); - - c_radius->setText(m_radiusString); - - switch (m_output_type) { - case AnalysisType::ISOVIST_OPENMP: - c_output_type->setChecked(true); - break; - case AnalysisType::VISUAL_GLOBAL_OPENMP: - c_radio1->setChecked(true); - break; - case AnalysisType::METRIC_OPENMP: - c_radio2->setChecked(true); - break; - case AnalysisType::ANGULAR_OPENMP: - c_radio3->setChecked(true); - break; - case AnalysisType::THROUGH_VISION_OPENMP: - c_radio4->setChecked(true); - break; - default: - break; - } - c_radius2->setText(m_radiusString2); - } -} - -void VGAParallelOptionsDlg::showEvent(QShowEvent *event) { - for (size_t i = 0; i < m_layer_names.size(); i++) { - c_layer_selector->addItem(QString(m_layer_names[i].c_str())); - } - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - MainWindow *mainWin = qobject_cast(widget); - if (mainWin) { - c_layer_selector->setCurrentIndex(m_gatelayer + 1); - break; - } - } - - OnOutputType(false); - - UpdateData(false); -} diff --git a/modules/vgaparallel/gui/vgaparalleloptionsdlg.h b/modules/vgaparallel/gui/vgaparalleloptionsdlg.h deleted file mode 100644 index a27736fe..00000000 --- a/modules/vgaparallel/gui/vgaparalleloptionsdlg.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2011-2012, Tasos Varoudis - -// This program 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. - -// This program 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 this program. If not, see . - -#include "ui_vgaparalleloptionsdlg.h" -#include -#include -#include - -class VGAParallelOptionsDlg : public QDialog, public Ui::VGAParallelOptionsDlg { - Q_OBJECT - public: - enum class AnalysisType { - NONE, - ISOVIST_OPENMP, - VISUAL_LOCAL_OPENMP, - VISUAL_LOCAL_ADJMATRIX, - VISUAL_GLOBAL_OPENMP, - METRIC_OPENMP, - ANGULAR_OPENMP, - THROUGH_VISION_OPENMP - }; - VGAParallelOptionsDlg(QWidget *parent = 0); - bool m_global; - bool m_local; - QString m_radiusString; - QString m_radiusString2; - double m_radius; - bool m_gates_only; - int m_gatelayer; - AnalysisType m_output_type; - void UpdateData(bool value); - void showEvent(QShowEvent *event); - - std::vector m_layer_names; - - private slots: - void OnOutputType(bool); - void OnUpdateRadius(QString); - void OnUpdateRadius2(QString); - void OnOK(); - void OnCancel(); -}; From 12f4166727db47a2ff3eea976fbfe712f9235f19 Mon Sep 17 00:00:00 2001 From: Petros Koutsolampros Date: Sun, 3 Jan 2021 02:12:27 +0200 Subject: [PATCH 4/5] Revert to the default VGA cli parser, modified for the Parallel VGA --- depthmapXcli/modeparserregistry.cpp | 2 +- depthmapXcli/runmethods.h | 1 + modules/vgaparallel/cli/vgaparallelparser.cpp | 69 +++++++++---------- modules/vgaparallel/cli/vgaparallelparser.h | 16 ++--- .../core/vgavisuallocaladjmatrix.cpp | 2 - 5 files changed, 41 insertions(+), 49 deletions(-) diff --git a/depthmapXcli/modeparserregistry.cpp b/depthmapXcli/modeparserregistry.cpp index 93623cab..9802c9ee 100644 --- a/depthmapXcli/modeparserregistry.cpp +++ b/depthmapXcli/modeparserregistry.cpp @@ -44,6 +44,6 @@ void ModeParserRegistry::populateParsers() REGISTER_PARSER(StepDepthParser); REGISTER_PARSER(MapConvertParser); REGISTER_PARSER(SegmentShortestPathParser); - REGISTER_PARSER(VGAParallelParser) + REGISTER_PARSER(VgaParallelParser) // ********* } diff --git a/depthmapXcli/runmethods.h b/depthmapXcli/runmethods.h index 5aa57538..12777697 100644 --- a/depthmapXcli/runmethods.h +++ b/depthmapXcli/runmethods.h @@ -44,6 +44,7 @@ class Point2f; namespace dm_runmethods{ std::unique_ptr loadGraph(const std::string& filename, IPerformanceSink &perfWriter); + std::unique_ptr getCommunicator(const CommandLineParser &clp); void importFiles(const CommandLineParser &cmdP, const ImportParser &parser, IPerformanceSink &perfWriter); void linkGraph(const CommandLineParser &cmdP, const LinkParser &parser, IPerformanceSink &perfWriter ); void runVga(const CommandLineParser &cmdP, const VgaParser &vgaP, const IRadiusConverter &converter, IPerformanceSink &perfWriter ); diff --git a/modules/vgaparallel/cli/vgaparallelparser.cpp b/modules/vgaparallel/cli/vgaparallelparser.cpp index 2c11addc..b9707be7 100644 --- a/modules/vgaparallel/cli/vgaparallelparser.cpp +++ b/modules/vgaparallel/cli/vgaparallelparser.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2017 Christian Sailer +// Copyright (C) 2020 Petros Koutsolampros // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,13 +19,18 @@ #include "depthmapXcli/parsingutils.h" #include "depthmapXcli/runmethods.h" #include "depthmapXcli/simpletimer.h" +#include "modules/vgaparallel/core/vgaangularopenmp.h" +#include "modules/vgaparallel/core/vgametricopenmp.h" +#include "modules/vgaparallel/core/vgavisualglobalopenmp.h" +#include "modules/vgaparallel/core/vgavisuallocaladjmatrix.h" +#include "modules/vgaparallel/core/vgavisuallocalopenmp.h" #include "salalib/options.h" #include #include using namespace depthmapX; -VgaParallelParser::VgaParallelParser() : m_vgaMode(VgaMode::NONE), m_localMeasures(false), m_globalMeasures(false) {} +VgaParallelParser::VgaParallelParser() : m_vgaMode(VgaMode::NONE) {} void VgaParallelParser::parse(int argc, char *argv[]) { for (int i = 1; i < argc;) { @@ -34,23 +40,19 @@ void VgaParallelParser::parse(int argc, char *argv[]) { throw CommandLineException("-vm can only be used once, modes are mutually exclusive"); } ENFORCE_ARGUMENT("-vm", i) - if (std::strcmp(argv[i], "isovist") == 0) { - m_vgaMode = VgaMode::ISOVIST; - } else if (std::strcmp(argv[i], "visibility") == 0) { - m_vgaMode = VgaMode::VISBILITY; + if (std::strcmp(argv[i], "visiblity-global") == 0) { + m_vgaMode = VgaMode::VISBILITY_GLOBAL; + } else if (std::strcmp(argv[i], "visibility-local") == 0) { + m_vgaMode = VgaMode::VISBILITY_LOCAL; + } else if (std::strcmp(argv[i], "visibility-local-adjmatrix") == 0) { + m_vgaMode = VgaMode::VISBILITY_LOCAL_ADJMATRIX; } else if (std::strcmp(argv[i], "metric") == 0) { m_vgaMode = VgaMode::METRIC; } else if (std::strcmp(argv[i], "angular") == 0) { m_vgaMode = VgaMode::ANGULAR; - } else if (std::strcmp(argv[i], "thruvision") == 0) { - m_vgaMode = VgaMode::THRU_VISION; } else { - throw CommandLineException(std::string("Invalid VGA mode: ") + argv[i]); + throw CommandLineException(std::string("Invalid VGAPARALLEL mode: ") + argv[i]); } - } else if (std::strcmp(argv[i], "-vg") == 0) { - m_globalMeasures = true; - } else if (std::strcmp(argv[i], "-vl") == 0) { - m_localMeasures = true; } else if (std::strcmp(argv[i], "-vr") == 0) { ENFORCE_ARGUMENT("-vr", i) m_radius = argv[i]; @@ -58,11 +60,7 @@ void VgaParallelParser::parse(int argc, char *argv[]) { ++i; } - if (m_vgaMode == VgaMode::NONE) { - m_vgaMode = VgaMode::ISOVIST; - } - - if (m_vgaMode == VgaMode::VISBILITY && m_globalMeasures) { + if (m_vgaMode == VgaMode::VISBILITY_GLOBAL) { if (m_radius.empty()) { throw CommandLineException( "Global measures in VGA/visibility analysis require a radius, use -vr "); @@ -79,41 +77,38 @@ void VgaParallelParser::parse(int argc, char *argv[]) { } void VgaParallelParser::run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const { - RadiusConverter radiusConverter; auto mgraph = dm_runmethods::loadGraph(clp.getFileName().c_str(), perfWriter); - std::unique_ptr options(new Options()); + std::unique_ptr analysis = nullptr; - std::cout << "Getting options..." << std::flush; + RadiusConverter radiusConverter; switch (getVgaMode()) { - case VgaParser::VgaMode::VISBILITY: - options->output_type = Options::OUTPUT_VISUAL; - options->local = localMeasures(); - options->global = globalMeasures(); - if (options->global) { - options->radius = radiusConverter.ConvertForVisibility(getRadius()); - } + case VgaMode::VISBILITY_GLOBAL: + analysis = std::unique_ptr(new VGAVisualGlobalOpenMP( + mgraph->getDisplayedPointMap(), radiusConverter.ConvertForVisibility(getRadius()), false)); break; - case VgaParser::VgaMode::METRIC: - options->output_type = Options::OUTPUT_METRIC; - options->radius = radiusConverter.ConvertForMetric(getRadius()); + case VgaMode::VISBILITY_LOCAL: + analysis = std::unique_ptr(new VGAVisualLocalOpenMP(mgraph->getDisplayedPointMap())); break; - case VgaParser::VgaMode::ANGULAR: - options->output_type = Options::OUTPUT_ANGULAR; + case VgaMode::VISBILITY_LOCAL_ADJMATRIX: + analysis = std::unique_ptr(new VGAVisualLocalAdjMatrix(mgraph->getDisplayedPointMap(), false)); break; - case VgaParser::VgaMode::ISOVIST: - options->output_type = Options::OUTPUT_ISOVIST; + case VgaMode::METRIC: + analysis = std::unique_ptr( + new VGAMetricOpenMP(mgraph->getDisplayedPointMap(), radiusConverter.ConvertForMetric(getRadius()), false)); break; - case VgaParser::VgaMode::THRU_VISION: - options->output_type = Options::OUTPUT_THRU_VISION; + case VgaMode::ANGULAR: + analysis = std::unique_ptr(new VGAAngularOpenMP( + mgraph->getDisplayedPointMap(), radiusConverter.ConvertForMetric(getRadius()), false)); break; default: throw depthmapX::SetupCheckException("Unsupported VGA mode"); } + std::cout << " ok\nAnalysing graph..." << std::flush; - DO_TIMED("Run VGA", mgraph->analyseGraph(dm_runmethods::getCommunicator(clp).get(), *options, clp.simpleMode())) + DO_TIMED("Run VGA", analysis->run(dm_runmethods::getCommunicator(clp).get())) std::cout << " ok\nWriting out result..." << std::flush; DO_TIMED("Writing graph", mgraph->write(clp.getOuputFile().c_str(), METAGRAPH_VERSION, false)) std::cout << " ok" << std::endl; diff --git a/modules/vgaparallel/cli/vgaparallelparser.h b/modules/vgaparallel/cli/vgaparallelparser.h index cec6e2a0..bae97ef5 100644 --- a/modules/vgaparallel/cli/vgaparallelparser.h +++ b/modules/vgaparallel/cli/vgaparallelparser.h @@ -26,10 +26,12 @@ class VgaParallelParser : public IModeParser { virtual std::string getHelp() const { return "Mode options for VGAPARALLEL:\n" - "-vm one of isovist, visiblity, metric, angular, thruvision\n" - "-vg turn on global measures for visibility, requires radius between 1 and 99 or n\n" - "-vl turn on local measures for visibility\n" - "-vr set visibility radius\n"; + "-vm one of visiblity-global (default algorithm)" + " visibility-local (default algorithm)" + " visibility-local-adjmatrix (alternative algorithm)" + " metric (default algorithm)" + " angular (default algorithm)\n" + "-vr radius between 1 and 99 or n, to limit visibility\n"; } public: @@ -37,18 +39,14 @@ class VgaParallelParser : public IModeParser { virtual void parse(int argc, char *argv[]); virtual void run(const CommandLineParser &clp, IPerformanceSink &perfWriter) const; - enum VgaMode { NONE, ISOVIST, VISBILITY, METRIC, ANGULAR, THRU_VISION }; + enum VgaMode { NONE, VISBILITY_GLOBAL, VISBILITY_LOCAL, VISBILITY_LOCAL_ADJMATRIX, METRIC, ANGULAR }; // vga options VgaMode getVgaMode() const { return m_vgaMode; } - bool localMeasures() const { return m_localMeasures; } - bool globalMeasures() const { return m_globalMeasures; } const std::string &getRadius() const { return m_radius; } private: // vga options VgaMode m_vgaMode; - bool m_localMeasures; - bool m_globalMeasures; std::string m_radius; }; diff --git a/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp b/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp index 79003ed3..b2952755 100644 --- a/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp +++ b/modules/vgaparallel/core/vgavisuallocaladjmatrix.cpp @@ -47,8 +47,6 @@ bool VGAVisualLocalAdjMatrix::run(Communicator *comm) { int count = 0; - count = 0; - std::vector col_data(filled.size()); int i; From b15563b12a89d31411a53d7e5bba06421bbb32a9 Mon Sep 17 00:00:00 2001 From: Petros Koutsolampros Date: Mon, 4 Jan 2021 01:57:05 +0200 Subject: [PATCH 5/5] Provide unit tests related to the VGA parallel module --- modules/vgaparallel/cli/vgaparallelparser.cpp | 3 + .../cliTest/vgaparallelparsertest.cpp | 95 ++++++++--------- .../coreTest/vgaparallelcoretest.cpp | 100 +----------------- 3 files changed, 46 insertions(+), 152 deletions(-) diff --git a/modules/vgaparallel/cli/vgaparallelparser.cpp b/modules/vgaparallel/cli/vgaparallelparser.cpp index b9707be7..eda3dff0 100644 --- a/modules/vgaparallel/cli/vgaparallelparser.cpp +++ b/modules/vgaparallel/cli/vgaparallelparser.cpp @@ -73,6 +73,9 @@ void VgaParallelParser::parse(int argc, char *argv[]) { if (m_radius.empty()) { throw CommandLineException("Metric vga requires a radius, use -vr "); } + if (m_radius != "n" && !has_only_digits(m_radius)) { + throw CommandLineException(std::string("Radius must be a positive integer number or n, got ") + m_radius); + } } } diff --git a/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp b/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp index a6039329..d0c62217 100644 --- a/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp +++ b/modules/vgaparallel/cliTest/vgaparallelparsertest.cpp @@ -13,82 +13,71 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "modules/vgaparallel/cli/vgaparallelparser.h" #include "cliTest/argumentholder.h" #include "cliTest/selfcleaningfile.h" -#include "modules/segmentshortestpaths/cli/segmentshortestpathparser.h" #include -TEST_CASE("SegmentShortestPathParser", "Error cases") { - SECTION("Missing argument to -sspo") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog", "-sspd", "0,0", "-sspo"}; - REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sspo requires an argument")); +TEST_CASE("VgaParallelParser", "Error cases") { + SECTION("Missing argument to -vr") { + VgaParallelParser parser; + ArgumentHolder ah{ + "prog", + "-vr", + }; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-vr requires an argument")); } - SECTION("Missing argument to -sspd") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd"}; - REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sspd requires an argument")); + SECTION("Missing argument to -vm") { + VgaParallelParser parser; + ArgumentHolder ah{"prog", "-vm"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-vm requires an argument")); } - SECTION("Missing argument to -sspt") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd", "0,0", "-sspt"}; - REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("-sspt requires an argument")); + SECTION("rubbish input to -vm") { + VgaParallelParser parser; + ArgumentHolder ah{"prog", "-vm", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid VGAPARALLEL mode: foo")); } - SECTION("rubbish input to -sspo") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog", "-sspd", "0,0", "-sspo", "foo"}; - REQUIRE_THROWS_WITH( - parser.parse(ah.argc(), ah.argv()), - Catch::Contains("Invalid origin point provided (foo). Should only contain digits dots and commas")); + SECTION("no input to -vr in metric analysis") { + VgaParallelParser parser; + ArgumentHolder ah{"prog", "-vm", "metric"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), + Catch::Contains("Metric vga requires a radius, use -vr ")); } - SECTION("rubbish input to -sspd") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd", "foo"}; - REQUIRE_THROWS_WITH( - parser.parse(ah.argc(), ah.argv()), - Catch::Contains("Invalid destination point provided (foo). Should only contain digits dots and commas")); + SECTION("rubbish input to -vr in metric analysis") { + VgaParallelParser parser; + ArgumentHolder ah{"prog", "-vm", "metric", "-vr", "foo"}; + REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), + Catch::Contains("Radius must be a positive integer number or n, got foo")); } - SECTION("rubbish input to -sspt") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog", "-sspo", "0,0", "-sspd", "0,0", "-sspt", "foo"}; - REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), Catch::Contains("Invalid step type: foo")); + SECTION("no input to -vr in visual global analysis") { + VgaParallelParser parser; + ArgumentHolder ah{"prog", "-vm", "visiblity-global"}; + REQUIRE_THROWS_WITH( + parser.parse(ah.argc(), ah.argv()), + Catch::Contains("Global measures in VGA/visibility analysis require a radius, use -vr ")); } - SECTION("Neiter points nor point file provided") { - SegmentShortestPathParser parser; - ArgumentHolder ah{"prog"}; + SECTION("rubbish input to -vr in visual global analysis") { + VgaParallelParser parser; + ArgumentHolder ah{"prog", "-vm", "visiblity-global", "-vr", "foo"}; REQUIRE_THROWS_WITH(parser.parse(ah.argc(), ah.argv()), - Catch::Contains("Both -sspo and -sspd must be provided")); + Catch::Contains("Radius must be a positive integer number or n, got foo")); } } -TEST_CASE("Successful SegmentShortestPathParser", "Read successfully") { - SegmentShortestPathParser parser; - double originX = 1.0; - double originY = 2.0; - double destinationX = 1.1; - double destinationY = 1.2; +TEST_CASE("Successful VgaParallelParser", "Read successfully") { + VgaParallelParser parser; SECTION("Read from commandline") { - std::stringstream originStream; - originStream << originX << "," << originY << std::flush; - std::stringstream destinationStream; - destinationStream << destinationX << "," << destinationY << std::flush; - - ArgumentHolder ah{"prog", "-sspo", originStream.str(), "-sspd", destinationStream.str(), - "-sspt", "topological"}; + ArgumentHolder ah{"prog", "-vm", "metric", "-vr", "5"}; parser.parse(ah.argc(), ah.argv()); } - auto originPoint = parser.getShortestPathOrigin(); - auto destinationPoint = parser.getShortestPathDestination(); - REQUIRE(originPoint.x == Approx(originX)); - REQUIRE(originPoint.y == Approx(originY)); - REQUIRE(destinationPoint.x == Approx(destinationX)); - REQUIRE(destinationPoint.y == Approx(destinationY)); + REQUIRE(parser.getVgaMode() == VgaParallelParser::VgaMode::METRIC); + REQUIRE(parser.getRadius() == "5"); } diff --git a/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp b/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp index d8a547be..bb89174f 100644 --- a/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp +++ b/modules/vgaparallel/coreTest/vgaparallelcoretest.cpp @@ -14,105 +14,7 @@ // along with this program. If not, see . #include "catch.hpp" -#include "modules/segmentshortestpaths/core/segmmetricshortestpath.h" -#include "modules/segmentshortestpaths/core/segmtopologicalshortestpath.h" -#include "modules/segmentshortestpaths/core/segmtulipshortestpath.h" #include "salalib/axialmap.h" #include "salalib/mapconverter.h" -TEST_CASE("Shortest paths working examples", "") { - const float EPSILON = 0.001; - - // construct an axial map which will result in three different paths for the three types - ShapeGraph axialMap("Dummy drawing map", ShapeMap::AXIALMAP); - axialMap.initialiseAttributesAxial(); - std::vector lines; - lines.push_back(Line(Point2f(1.05000000, 1.00000000), Point2f(3.60000000, 1.00000000))); - lines.push_back(Line(Point2f(3.43455142, 2.92439257), Point2f(4.15448579, 3.75607430))); - lines.push_back(Line(Point2f(2.40000000, 3.00000000), Point2f(3.60000000, 3.00000000))); - lines.push_back(Line(Point2f(1.15022677, 0.90136061), Point2f(1.34977323, 2.09863939))); - lines.push_back(Line(Point2f(3.50000000, 3.10000000), Point2f(3.50000000, 0.90000000))); - lines.push_back(Line(Point2f(1.24560093, 1.95201016), Point2f(2.11199711, 2.42593102))); - lines.push_back(Line(Point2f(1.96351621, 2.29850806), Point2f(2.56074850, 3.07943312))); - - lines.push_back(Line(Point2f(1.28848772, 1.91061952), Point2f(1.75546653, 2.84134127))); - lines.push_back(Line(Point2f(1.61521977, 2.72198377), Point2f(2.59540115, 3.02997701))); - lines.push_back(Line(Point2f(1.23737734, 1.07071068), Point2f(0.45955989, 0.29289322))); - for (Line line : lines) { - axialMap.makeLineShape(line); - } - axialMap.makeConnections(); - - REQUIRE(axialMap.getShapeCount() == 10); - - std::unique_ptr segmentMap = - MapConverter::convertAxialToSegment(nullptr, axialMap, "Dummy segment map", true, true, 0.4); - - REQUIRE(segmentMap->getShapeCount() == 10); - - // select the two edges - QtRegion selRegion(lines[1].midpoint(), lines[1].midpoint()); - segmentMap->setCurSel(selRegion, false); - selRegion.bottom_left = lines[9].midpoint(); - selRegion.top_right = lines[9].midpoint(); - segmentMap->setCurSel(selRegion, true); - REQUIRE(segmentMap->getSelCount() == 2); - - { - REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Angle")); - REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Order")); - SegmentTulipShortestPath(*segmentMap.get()).run(nullptr); - REQUIRE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Angle")); - REQUIRE(segmentMap->getAttributeTable().hasColumn("Angular Shortest Path Order")); - int angleColIdx = segmentMap->getAttributeTable().getColumnIndex("Angular Shortest Path Angle"); - int orderColIdx = segmentMap->getAttributeTable().getColumnIndex("Angular Shortest Path Order"); - std::vector expectedAngles = {-1, 0, 0.54297, 1.42969, -1, -1, -1, 1.24219, 0.734375, 1.82422}; - std::vector expectedOrder = {-1, 0, 1, 4, -1, -1, -1, 3, 2, 5}; - for (int i = 0; i < lines.size(); i++) { - QtRegion selRegion(lines[i].midpoint(), lines[i].midpoint()); - AttributeRow &shapeRow = - segmentMap->getAttributeRowFromShapeIndex(segmentMap->getShapesInRegion(selRegion).begin()->first); - - REQUIRE(shapeRow.getValue(angleColIdx) == Approx(expectedAngles[i]).epsilon(EPSILON)); - REQUIRE(shapeRow.getValue(orderColIdx) == expectedOrder[i]); - } - } - - { - REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Distance")); - REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Order")); - SegmentMetricShortestPath(*segmentMap.get()).run(nullptr); - REQUIRE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Distance")); - REQUIRE(segmentMap->getAttributeTable().hasColumn("Metric Shortest Path Order")); - int distanceColIdx = segmentMap->getAttributeTable().getColumnIndex("Metric Shortest Path Distance"); - int orderColIdx = segmentMap->getAttributeTable().getColumnIndex("Metric Shortest Path Order"); - std::vector expectedDistances = {-1, 0, 1, 3.57756, -1, 2.67689, 1.89156, -1, -1, 4.58446}; - std::vector expectedOrder = {-1, 0, 1, 4, -1, 3, 2, -1, -1, 5}; - for (int i = 0; i < lines.size(); i++) { - QtRegion selRegion(lines[i].midpoint(), lines[i].midpoint()); - AttributeRow &shapeRow = - segmentMap->getAttributeRowFromShapeIndex(segmentMap->getShapesInRegion(selRegion).begin()->first); - REQUIRE(shapeRow.getValue(distanceColIdx) == Approx(expectedDistances[i]).epsilon(EPSILON)); - REQUIRE(shapeRow.getValue(orderColIdx) == expectedOrder[i]); - } - } - - { - REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Depth")); - REQUIRE_FALSE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Order")); - SegmentTopologicalShortestPath(*segmentMap.get()).run(nullptr); - REQUIRE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Depth")); - REQUIRE(segmentMap->getAttributeTable().hasColumn("Topological Shortest Path Order")); - int depthColIdx = segmentMap->getAttributeTable().getColumnIndex("Topological Shortest Path Depth"); - int orderColIdx = segmentMap->getAttributeTable().getColumnIndex("Topological Shortest Path Order"); - std::vector expectedDepths = {2, 0, -1, -1, 1, -1, -1, -1, -1, 3}; - std::vector expectedOrder = {2, 0, -1, -1, 1, -1, -1, -1, -1, 3}; - for (int i = 0; i < lines.size(); i++) { - QtRegion selRegion(lines[i].midpoint(), lines[i].midpoint()); - AttributeRow &shapeRow = - segmentMap->getAttributeRowFromShapeIndex(segmentMap->getShapesInRegion(selRegion).begin()->first); - REQUIRE(shapeRow.getValue(depthColIdx) == Approx(expectedDepths[i]).epsilon(EPSILON)); - REQUIRE(shapeRow.getValue(orderColIdx) == expectedOrder[i]); - } - } -} +TEST_CASE("Dummy VGA Parallel test", "") {}